فهرست منبع

Added GameInstance class

- available as global GAME
- integrates LOCPLINT (CPlayerInterface)
- integrates CGI->mh (CMapHandler)
- integrates CSH (CServerHandler)
Ivan Savenko 8 ماه پیش
والد
کامیت
156de5b17e
98فایلهای تغییر یافته به همراه1284 افزوده شده و 1127 حذف شده
  1. 11 10
      client/ArtifactsUIController.cpp
  2. 2 0
      client/CMakeLists.txt
  3. 28 29
      client/CPlayerInterface.cpp
  4. 1 4
      client/CPlayerInterface.h
  5. 0 2
      client/CServerHandler.cpp
  6. 0 2
      client/CServerHandler.h
  7. 19 19
      client/Client.cpp
  8. 29 28
      client/ClientCommandManager.cpp
  9. 9 8
      client/GameChatHandler.cpp
  10. 2 1
      client/GameEngine.cpp
  11. 60 0
      client/GameInstance.cpp
  12. 38 0
      client/GameInstance.h
  13. 32 31
      client/HeroMovementController.cpp
  14. 52 75
      client/NetPacksClient.cpp
  15. 3 2
      client/NetPacksLobbyClient.cpp
  16. 69 68
      client/adventureMap/AdventureMapInterface.cpp
  17. 81 80
      client/adventureMap/AdventureMapShortcuts.cpp
  18. 3 2
      client/adventureMap/AdventureMapWidget.cpp
  19. 7 6
      client/adventureMap/AdventureOptions.cpp
  20. 6 5
      client/adventureMap/CInGameConsole.cpp
  21. 28 27
      client/adventureMap/CInfoBar.cpp
  22. 1 1
      client/adventureMap/CInfoBar.h
  23. 39 38
      client/adventureMap/CList.cpp
  24. 9 8
      client/adventureMap/CMinimap.cpp
  25. 6 5
      client/adventureMap/CResDataBar.cpp
  26. 13 12
      client/adventureMap/MapAudioPlayer.cpp
  27. 11 10
      client/adventureMap/TurnTimerWidget.cpp
  28. 3 2
      client/battle/BattleActionsController.cpp
  29. 2 1
      client/battle/BattleFieldController.cpp
  30. 2 1
      client/battle/BattleInterface.cpp
  31. 2 1
      client/battle/BattleInterfaceClasses.cpp
  32. 10 9
      client/battle/BattleWindow.cpp
  33. 2 1
      client/eventsSDL/InputSourceKeyboard.cpp
  34. 2 1
      client/eventsSDL/InputSourceTouch.cpp
  35. 3 2
      client/globalLobby/GlobalLobbyAddChannelWindow.cpp
  36. 10 9
      client/globalLobby/GlobalLobbyClient.cpp
  37. 6 5
      client/globalLobby/GlobalLobbyInviteWindow.cpp
  38. 9 8
      client/globalLobby/GlobalLobbyLoginWindow.cpp
  39. 4 3
      client/globalLobby/GlobalLobbyRoomWindow.cpp
  40. 5 4
      client/globalLobby/GlobalLobbyServerSetup.cpp
  41. 10 9
      client/globalLobby/GlobalLobbyWidget.cpp
  42. 8 7
      client/globalLobby/GlobalLobbyWindow.cpp
  43. 11 9
      client/gui/CursorHandler.cpp
  44. 2 0
      client/gui/CursorHandler.h
  45. 3 2
      client/gui/InterfaceObjectConfigurable.cpp
  46. 40 39
      client/lobby/CBonusSelection.cpp
  47. 3 2
      client/lobby/CCampaignInfoScreen.cpp
  48. 37 36
      client/lobby/CLobbyScreen.cpp
  49. 7 6
      client/lobby/CSavingScreen.cpp
  50. 3 2
      client/lobby/CScenarioInfoScreen.cpp
  51. 13 12
      client/lobby/CSelectionBase.cpp
  52. 24 23
      client/lobby/OptionsTab.cpp
  53. 19 18
      client/lobby/OptionsTabBase.cpp
  54. 2 1
      client/lobby/RandomMapTab.cpp
  55. 10 9
      client/lobby/SelectionTab.cpp
  56. 12 11
      client/mainmenu/CMainMenu.cpp
  57. 18 17
      client/mapView/MapRendererContext.cpp
  58. 9 8
      client/mapView/MapRendererContextState.cpp
  59. 2 1
      client/mapView/MapView.cpp
  60. 13 12
      client/mapView/MapViewController.cpp
  61. 4 3
      client/mapView/mapHandler.cpp
  62. 0 2
      client/mapView/mapHandler.h
  63. 3 2
      client/widgets/Buttons.cpp
  64. 3 2
      client/widgets/CArtifactsOfHeroBackpack.cpp
  65. 4 3
      client/widgets/CArtifactsOfHeroBase.cpp
  66. 3 2
      client/widgets/CArtifactsOfHeroMain.cpp
  67. 4 3
      client/widgets/CComponentHolder.cpp
  68. 12 11
      client/widgets/CExchangeController.cpp
  69. 22 21
      client/widgets/CGarrisonInt.cpp
  70. 25 24
      client/widgets/MiscWidgets.cpp
  71. 4 3
      client/widgets/TextControls.cpp
  72. 9 8
      client/widgets/markets/CAltarArtifacts.cpp
  73. 4 3
      client/widgets/markets/CAltarCreatures.cpp
  74. 4 3
      client/widgets/markets/CArtifactsBuying.cpp
  75. 4 3
      client/widgets/markets/CArtifactsSelling.cpp
  76. 3 2
      client/widgets/markets/CFreelancerGuild.cpp
  77. 2 1
      client/widgets/markets/CMarketBase.cpp
  78. 4 3
      client/widgets/markets/CMarketResources.cpp
  79. 4 3
      client/widgets/markets/CTransferResources.cpp
  80. 2 1
      client/widgets/markets/TradePanels.cpp
  81. 102 101
      client/windows/CCastleInterface.cpp
  82. 10 9
      client/windows/CCreatureWindow.cpp
  83. 8 7
      client/windows/CExchangeWindow.cpp
  84. 6 5
      client/windows/CHeroBackpackWindow.cpp
  85. 13 12
      client/windows/CHeroWindow.cpp
  86. 18 17
      client/windows/CKingdomInterface.cpp
  87. 6 5
      client/windows/CMarketWindow.cpp
  88. 2 1
      client/windows/CPuzzleWindow.cpp
  89. 9 8
      client/windows/CSpellWindow.cpp
  90. 5 4
      client/windows/CTutorialWindow.cpp
  91. 3 2
      client/windows/CWindowObject.cpp
  92. 17 16
      client/windows/CWindowWithArtifacts.cpp
  93. 36 35
      client/windows/GUIClasses.cpp
  94. 29 28
      client/windows/InfoWindows.cpp
  95. 1 1
      client/windows/InfoWindows.h
  96. 7 6
      client/windows/QuickRecruitmentWindow.cpp
  97. 14 13
      client/windows/settings/SettingsMainWindow.cpp
  98. 13 10
      clientapp/EntryPoint.cpp

+ 11 - 10
client/ArtifactsUIController.cpp

@@ -18,6 +18,7 @@
 #include "../lib/mapObjects/CGHeroInstance.h"
 
 #include "GameEngine.h"
+#include "GameInstance.h"
 #include "gui/WindowHandler.h"
 #include "widgets/CComponent.h"
 #include "windows/CWindowWithArtifacts.h"
@@ -30,7 +31,7 @@ ArtifactsUIController::ArtifactsUIController()
 
 bool ArtifactsUIController::askToAssemble(const ArtifactLocation & al, const bool onlyEquipped, const bool checkIgnored)
 {
-	if(auto hero = LOCPLINT->cb->getHero(al.artHolder))
+	if(auto hero = GAME->interface()->cb->getHero(al.artHolder))
 	{
 		if(hero->getArt(al.slot) == nullptr)
 		{
@@ -49,7 +50,7 @@ bool ArtifactsUIController::askToAssemble(const CGHeroInstance * hero, const Art
 	const auto art = hero->getArt(slot);
 	assert(art);
 
-	if(hero->tempOwner != LOCPLINT->playerID)
+	if(hero->tempOwner != GAME->interface()->playerID)
 		return false;
 
 	if(numOfArtsAskAssembleSession != 0)
@@ -79,13 +80,13 @@ bool ArtifactsUIController::askToAssemble(const CGHeroInstance * hero, const Art
 					else
 						message.appendRawString(VLC->generaltexth->allTexts[732]); // You possess all of the components needed to assemble the
 					message.replaceName(ArtifactID(combinedArt->getId()));
-					LOCPLINT->showYesNoDialog(message.toString(), [&assembleConfirmed, hero, slot, combinedArt]()
+					GAME->interface()->showYesNoDialog(message.toString(), [&assembleConfirmed, hero, slot, combinedArt]()
 						{
 							assembleConfirmed = true;
-							LOCPLINT->cb.get()->assembleArtifacts(hero->id, slot, true, combinedArt->getId());
+							GAME->interface()->cb->assembleArtifacts(hero->id, slot, true, combinedArt->getId());
 						}, nullptr, {std::make_shared<CComponent>(ComponentType::ARTIFACT, combinedArt->getId())});
 
-					LOCPLINT->waitWhileDialog();
+					GAME->interface()->waitWhileDialog();
 					if(assembleConfirmed)
 						break;
 				}
@@ -102,7 +103,7 @@ bool ArtifactsUIController::askToDisassemble(const CGHeroInstance * hero, const
 	const auto art = hero->getArt(slot);
 	assert(art);
 
-	if(hero->tempOwner != LOCPLINT->playerID)
+	if(hero->tempOwner != GAME->interface()->playerID)
 		return false;
 
 	if(art->hasParts())
@@ -114,9 +115,9 @@ bool ArtifactsUIController::askToDisassemble(const CGHeroInstance * hero, const
 		message.appendEOL();
 		message.appendEOL();
 		message.appendRawString(VLC->generaltexth->allTexts[733]); // Do you wish to disassemble this artifact?
-		LOCPLINT->showYesNoDialog(message.toString(), [hero, slot]()
+		GAME->interface()->showYesNoDialog(message.toString(), [hero, slot]()
 			{
-				LOCPLINT->cb->assembleArtifacts(hero->id, slot, false, ArtifactID());
+				GAME->interface()->cb->assembleArtifacts(hero->id, slot, false, ArtifactID());
 			}, nullptr);
 		return true;
 	}
@@ -127,7 +128,7 @@ void ArtifactsUIController::artifactRemoved()
 {
 	for(const auto & artWin : ENGINE->windows().findWindows<CWindowWithArtifacts>())
 		artWin->update();
-	LOCPLINT->waitWhileDialog();
+	GAME->interface()->waitWhileDialog();
 }
 
 void ArtifactsUIController::artifactMoved()
@@ -141,7 +142,7 @@ void ArtifactsUIController::artifactMoved()
 		{
 			artWin->update();
 		}
-	LOCPLINT->waitWhileDialog();
+	GAME->interface()->waitWhileDialog();
 }
 
 void ArtifactsUIController::bulkArtMovementStart(size_t totalNumOfArts, size_t possibleAssemblyNumOfArts)

+ 2 - 0
client/CMakeLists.txt

@@ -180,6 +180,7 @@ set(vcmiclientcommon_SRCS
 
 	ArtifactsUIController.cpp
 	GameEngine.cpp
+	GameInstance.cpp
 	CPlayerInterface.cpp
 	PlayerLocalState.cpp
 	CServerHandler.cpp
@@ -397,6 +398,7 @@ set(vcmiclientcommon_HEADERS
 	CMT.h
 	CPlayerInterface.h
 	GameEngine.h
+	GameInstance.h
 	PlayerLocalState.h
 	CServerHandler.h
 	Client.h

+ 28 - 29
client/CPlayerInterface.cpp

@@ -30,6 +30,7 @@
 #include "eventsSDL/NotificationHandler.h"
 
 #include "GameEngine.h"
+#include "GameInstance.h"
 #include "gui/CursorHandler.h"
 #include "gui/WindowHandler.h"
 
@@ -111,9 +112,7 @@
 // They all assume that interface mutex is locked.
 #define EVENT_HANDLER_CALLED_BY_CLIENT
 
-#define BATTLE_EVENT_POSSIBLE_RETURN	if (LOCPLINT != this) return; if (isAutoFightOn && !battleInt) return
-
-CPlayerInterface * LOCPLINT;
+#define BATTLE_EVENT_POSSIBLE_RETURN	if (GAME->interface() != this) return; if (isAutoFightOn && !battleInt) return
 
 std::shared_ptr<BattleInterface> CPlayerInterface::battleInt;
 
@@ -136,7 +135,7 @@ CPlayerInterface::CPlayerInterface(PlayerColor Player):
 	
 {
 	logGlobal->trace("\tHuman player interface for player %s being constructed", Player.toString());
-	LOCPLINT = this;
+	GAME->setInterfaceInstance(this);
 	playerID=Player;
 	human=true;
 	battleInt.reset();
@@ -155,8 +154,8 @@ CPlayerInterface::~CPlayerInterface()
 	logGlobal->trace("\tHuman player interface for player %s being destructed", playerID.toString());
 	delete showingDialog;
 	delete cingconsole;
-	if (LOCPLINT == this)
-		LOCPLINT = nullptr;
+	if (GAME->interface() == this)
+		GAME->setInterfaceInstance(nullptr);
 }
 
 void CPlayerInterface::initGameInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CCallback> CB)
@@ -235,7 +234,7 @@ void CPlayerInterface::playerStartsTurn(PlayerColor player)
 	}
 
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if (player != playerID && LOCPLINT == this)
+	if (player != playerID && GAME->interface() == this)
 	{
 		waitWhileDialog();
 
@@ -315,7 +314,7 @@ void CPlayerInterface::yourTurn(QueryID queryID)
 
 	bool hotseatWait = humanPlayersCount > 1;
 
-		LOCPLINT = this;
+		GAME->setInterfaceInstance(this);
 		ENGINE->curInt = this;
 
 		NotificationHandler::notify("Your turn");
@@ -399,7 +398,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	waitWhileDialog();
-	if(LOCPLINT != this)
+	if(GAME->interface() != this)
 		return;
 
 	//FIXME: read once and store
@@ -905,7 +904,7 @@ void CPlayerInterface::battleTriggerEffect(const BattleID & battleID, const Batt
 
 	if(bte.effect == vstd::to_underlying(BonusType::MANA_DRAIN))
 	{
-		const CGHeroInstance * manaDrainedHero = LOCPLINT->cb->getHero(ObjectInstanceID(bte.additionalInfo));
+		const CGHeroInstance * manaDrainedHero = GAME->interface()->cb->getHero(ObjectInstanceID(bte.additionalInfo));
 		battleInt->windowObject->heroManaPointsChanged(manaDrainedHero);
 	}
 }
@@ -1006,7 +1005,7 @@ void CPlayerInterface::showInfoDialog(EInfoWindowMode type, const std::string &t
 		// abort movement, if any. Strictly speaking unnecessary, but prevents some edge cases, like movement sound on visiting Magi Hut with "show messages in status window" on
 		movementController->requestMovementAbort();
 
-		if (makingTurn && ENGINE->windows().count() > 0 && LOCPLINT == this)
+		if (makingTurn && ENGINE->windows().count() > 0 && GAME->interface() == this)
 			ENGINE->sound().playSound(static_cast<soundBase::soundID>(soundID));
 		return;
 	}
@@ -1038,7 +1037,7 @@ void CPlayerInterface::showInfoDialog(const std::string & text, std::shared_ptr<
 
 void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector<std::shared_ptr<CComponent>> & components, int soundID)
 {
-	LOG_TRACE_PARAMS(logGlobal, "player=%s, text=%s, is LOCPLINT=%d", playerID % text % (this==LOCPLINT));
+	LOG_TRACE_PARAMS(logGlobal, "player=%s, text=%s, is GAME->interface()=%d", playerID % text % (this==GAME->interface()));
 	waitWhileDialog();
 
 	if (settings["session"]["autoSkip"].Bool() && !ENGINE->isKeyboardShiftDown())
@@ -1047,7 +1046,7 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector
 	}
 	std::shared_ptr<CInfoWindow> temp = CInfoWindow::create(text, playerID, components);
 
-	if ((makingTurn || (battleInt && battleInt->curInt && battleInt->curInt.get() == this)) && ENGINE->windows().count() > 0 && LOCPLINT == this)
+	if ((makingTurn || (battleInt && battleInt->curInt && battleInt->curInt.get() == this)) && ENGINE->windows().count() > 0 && GAME->interface() == this)
 	{
 		ENGINE->sound().playSound(static_cast<soundBase::soundID>(soundID));
 		showingDialog->setBusy();
@@ -1073,7 +1072,7 @@ void CPlayerInterface::showInfoDialogAndWait(std::vector<Component> & components
 void CPlayerInterface::showYesNoDialog(const std::string &text, CFunctionList<void()> onYes, CFunctionList<void()> onNo, const std::vector<std::shared_ptr<CComponent>> & components)
 {
 	movementController->requestMovementAbort();
-	LOCPLINT->showingDialog->setBusy();
+	GAME->interface()->showingDialog->setBusy();
 	CInfoWindow::showYesNoDialog(text, components, onYes, onNo, playerID);
 }
 
@@ -1251,7 +1250,7 @@ void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const Bonus
 void CPlayerInterface::moveHero( const CGHeroInstance *h, const CGPath& path )
 {
 	LOG_TRACE(logGlobal);
-	if (!LOCPLINT->makingTurn)
+	if (!GAME->interface()->makingTurn)
 		return;
 
 	assert(h);
@@ -1420,10 +1419,10 @@ void CPlayerInterface::newObject( const CGObjectInstance * obj )
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	//we might have built a boat in shipyard in opened town screen
 	if (obj->ID == Obj::BOAT
-		&& LOCPLINT->castleInt
-		&&  obj->visitablePos() == LOCPLINT->castleInt->town->bestLocation())
+		&& GAME->interface()->castleInt
+		&&  obj->visitablePos() == GAME->interface()->castleInt->town->bestLocation())
 	{
-		LOCPLINT->castleInt->addBuilding(BuildingID::SHIP);
+		GAME->interface()->castleInt->addBuilding(BuildingID::SHIP);
 	}
 }
 
@@ -1457,7 +1456,7 @@ void CPlayerInterface::objectRemoved(const CGObjectInstance * obj, const PlayerC
 			ENGINE->sound().playSound(removalSound.value());
 		}
 	}
-	MAPHANDLER->waitForOngoingAnimations();
+	GAME->map().waitForOngoingAnimations();
 
 	if(obj->ID == Obj::HERO && obj->tempOwner == playerID)
 	{
@@ -1490,10 +1489,10 @@ void CPlayerInterface::playerBlocked(int reason, bool start)
 {
 	if(reason == PlayerBlocked::EReason::UPCOMING_BATTLE)
 	{
-		if(CSH->howManyPlayerInterfaces() > 1 && LOCPLINT != this && LOCPLINT->makingTurn == false)
+		if(GAME->server().howManyPlayerInterfaces() > 1 && GAME->interface() != this && GAME->interface()->makingTurn == false)
 		{
 			//one of our players who isn't last in order got attacked not by our another player (happens for example in hotseat mode)
-			LOCPLINT = this;
+			GAME->setInterfaceInstance(this);
 			ENGINE->curInt = this;
 			adventureInt->onCurrentPlayerChanged(playerID);
 			std::string msg = VLC->generaltexth->translate("vcmi.adventureMap.playerAttacked");
@@ -1514,7 +1513,7 @@ void CPlayerInterface::update()
 	boost::shared_lock gsLock(CGameState::mutex);
 
 	// While mutexes were locked away we may be have stopped being the active interface
-	if (LOCPLINT != this)
+	if (GAME->interface() != this)
 		return;
 
 	//if there are any waiting dialogs, show them
@@ -1577,10 +1576,10 @@ void CPlayerInterface::gameOver(PlayerColor player, const EVictoryLossCheckResul
 		if (victoryLossCheckResult.loss())
 			showInfoDialog(VLC->generaltexth->allTexts[95]);
 
-		assert(ENGINE->curInt == LOCPLINT);
-		auto previousInterface = LOCPLINT; //without multiple player interfaces some of lines below are useless, but for hotseat we wanna swap player interface temporarily
+		assert(ENGINE->curInt == GAME->interface());
+		auto previousInterface = GAME->interface(); //without multiple player interfaces some of lines below are useless, but for hotseat we wanna swap player interface temporarily
 
-		LOCPLINT = this; //this is needed for dialog to show and avoid freeze, dialog showing logic should be reworked someday
+		GAME->setInterfaceInstance(this); //this is needed for dialog to show and avoid freeze, dialog showing logic should be reworked someday
 		ENGINE->curInt = this; //waiting for dialogs requires this to get events
 
 		if(!makingTurn)
@@ -1593,7 +1592,7 @@ void CPlayerInterface::gameOver(PlayerColor player, const EVictoryLossCheckResul
 			waitForAllDialogs();
 
 		ENGINE->curInt = previousInterface;
-		LOCPLINT = previousInterface;
+		GAME->setInterfaceInstance(previousInterface);
 	}
 }
 
@@ -1741,7 +1740,7 @@ void CPlayerInterface::showThievesGuildWindow (const CGObjectInstance * obj)
 void CPlayerInterface::showQuestLog()
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	ENGINE->windows().createAndPushWindow<CQuestLog>(LOCPLINT->cb->getMyQuests());
+	ENGINE->windows().createAndPushWindow<CQuestLog>(GAME->interface()->cb->getMyQuests());
 }
 
 void CPlayerInterface::showShipyardDialogOrProblemPopup(const IShipyard *obj)
@@ -1819,7 +1818,7 @@ void CPlayerInterface::proposeLoadingGame()
 		VLC->generaltexth->allTexts[68],
 		[]()
 		{
-			CSH->endGameplay();
+			GAME->server().endGameplay();
 			CMM->menu->switchToTab("load");
 		},
 		nullptr
@@ -1834,7 +1833,7 @@ bool CPlayerInterface::capturedAllEvents()
 		return true;
 	}
 
-	bool needToLockAdventureMap = adventureInt && adventureInt->isActive() && MAPHANDLER->hasOngoingAnimations();
+	bool needToLockAdventureMap = adventureInt && adventureInt->isActive() && GAME->map().hasOngoingAnimations();
 	bool quickCombatOngoing = isAutoFightOn && !battleInt;
 
 	if (ignoreEvents || needToLockAdventureMap || quickCombatOngoing )

+ 1 - 4
client/CPlayerInterface.h

@@ -170,7 +170,7 @@ protected: // Call-ins from server, should not be called directly, but only via
 	void yourTacticPhase(const BattleID & battleID, int distance) override;
 	std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override;
 
-public: // public interface for use by client via LOCPLINT access
+public: // public interface for use by client via GAME->interface() access
 
 	// part of GameInterface that is also used by client code
 	void showPuzzleMap() override;
@@ -231,6 +231,3 @@ private:
 	void initializeHeroTownList();
 	int getLastIndex(std::string namePrefix);
 };
-
-/// Provides global access to instance of interface of currently active player
-extern CPlayerInterface * LOCPLINT;

+ 0 - 2
client/CServerHandler.cpp

@@ -58,8 +58,6 @@
 
 #include <vcmi/events/EventBus.h>
 
-CServerHandler * CSH = nullptr;
-
 CServerHandler::~CServerHandler()
 {
 	if (serverRunner)

+ 0 - 2
client/CServerHandler.h

@@ -215,5 +215,3 @@ public:
 	void visitForLobby(CPackForLobby & lobbyPack);
 	void visitForClient(CPackForClient & clientPack);
 };
-
-extern CServerHandler * CSH;

+ 19 - 19
client/Client.cpp

@@ -18,6 +18,7 @@
 #include "adventureMap/AdventureMapInterface.h"
 #include "battle/BattleInterface.h"
 #include "GameEngine.h"
+#include "GameInstance.h"
 #include "gui/WindowHandler.h"
 #include "mapView/mapHandler.h"
 
@@ -115,18 +116,18 @@ events::EventBus * CClient::eventBus() const
 
 void CClient::newGame(CGameState * initializedGameState)
 {
-	CSH->th->update();
+	GAME->server().th->update();
 	CMapService mapService;
 	assert(initializedGameState);
 	gs = initializedGameState;
 	gs->preInit(VLC, this);
-	logNetwork->trace("\tCreating gamestate: %i", CSH->th->getDiff());
+	logNetwork->trace("\tCreating gamestate: %i", GAME->server().th->getDiff());
 	if(!initializedGameState)
 	{
 		Load::ProgressAccumulator progressTracking;
-		gs->init(&mapService, CSH->si.get(), progressTracking, settings["general"]["saveRandomMaps"].Bool());
+		gs->init(&mapService, GAME->server().si.get(), progressTracking, settings["general"]["saveRandomMaps"].Bool());
 	}
-	logNetwork->trace("Initializing GameState (together): %d ms", CSH->th->getDiff());
+	logNetwork->trace("Initializing GameState (together): %d ms", GAME->server().th->getDiff());
 
 	initMapHandler();
 	reinitScripting();
@@ -142,7 +143,7 @@ void CClient::loadGame(CGameState * initializedGameState)
 	gs = initializedGameState;
 
 	gs->preInit(VLC, this);
-	gs->updateOnLoad(CSH->si.get());
+	gs->updateOnLoad(GAME->server().si.get());
 	logNetwork->info("Game loaded, initialize interfaces.");
 
 	initMapHandler();
@@ -167,8 +168,7 @@ void CClient::save(const std::string & fname)
 
 void CClient::endNetwork()
 {
-	if (MAPHANDLER)
-		MAPHANDLER->endNetwork();
+	GAME->map().endNetwork();
 
 	if (CPlayerInterface::battleInt)
 		CPlayerInterface::battleInt->endNetwork();
@@ -196,7 +196,7 @@ void CClient::endGame()
 		logNetwork->info("Ending current game!");
 		removeGUI();
 
-		MAPHANDLER.reset();
+		GAME->setMapInstance(nullptr);
 		vstd::clear_pointer(gs);
 
 		logNetwork->info("Deleted mapHandler and gameState.");
@@ -218,8 +218,8 @@ void CClient::initMapHandler()
 	// During loading CPlayerInterface from serialized state it's depend on MH
 	if(!settings["session"]["headless"].Bool())
 	{
-		MAPHANDLER = std::make_unique<CMapHandler>(gs->map);
-		logNetwork->trace("Creating mapHandler: %d ms", CSH->th->getDiff());
+		GAME->setMapInstance(std::make_unique<CMapHandler>(gs->map));
+		logNetwork->trace("Creating mapHandler: %d ms", GAME->server().th->getDiff());
 	}
 }
 
@@ -227,7 +227,7 @@ void CClient::initPlayerEnvironments()
 {
 	playerEnvironments.clear();
 
-	auto allPlayers = CSH->getAllClientPlayers(CSH->logicConnection->connectionID);
+	auto allPlayers = GAME->server().getAllClientPlayers(GAME->server().logicConnection->connectionID);
 	bool hasHumanPlayer = false;
 	for(auto & color : allPlayers)
 	{
@@ -257,7 +257,7 @@ void CClient::initPlayerInterfaces()
 	for(auto & playerInfo : gs->scenarioOps->playerInfos)
 	{
 		PlayerColor color = playerInfo.first;
-		if(!vstd::contains(CSH->getAllClientPlayers(CSH->logicConnection->connectionID), color))
+		if(!vstd::contains(GAME->server().getAllClientPlayers(GAME->server().logicConnection->connectionID), color))
 			continue;
 
 		if(!vstd::contains(playerint, color))
@@ -287,10 +287,10 @@ void CClient::initPlayerInterfaces()
 		installNewPlayerInterface(std::make_shared<CPlayerInterface>(PlayerColor::SPECTATOR), PlayerColor::SPECTATOR, true);
 	}
 
-	if(CSH->getAllClientPlayers(CSH->logicConnection->connectionID).count(PlayerColor::NEUTRAL))
+	if(GAME->server().getAllClientPlayers(GAME->server().logicConnection->connectionID).count(PlayerColor::NEUTRAL))
 		installNewBattleInterface(CDynLibHandler::getNewBattleAI(settings["server"]["neutralAI"].String()), PlayerColor::NEUTRAL);
 
-	logNetwork->trace("Initialized player interfaces %d ms", CSH->th->getDiff());
+	logNetwork->trace("Initialized player interfaces %d ms", GAME->server().th->getDiff());
 }
 
 std::string CClient::aiNameForPlayer(const PlayerSettings & ps, bool battleAI, bool alliedToHuman) const
@@ -371,7 +371,7 @@ int CClient::sendRequest(const CPackForServer & request, PlayerColor player)
 	waitingRequest.pushBack(requestID);
 	request.requestID = requestID;
 	request.player = player;
-	CSH->logicConnection->sendPack(request);
+	GAME->server().logicConnection->sendPack(request);
 	if(vstd::contains(playerint, player))
 		playerint[player]->requestSent(&request, requestID);
 
@@ -523,7 +523,7 @@ void CClient::removeGUI() const
 	adventureInt.reset();
 	logGlobal->info("Removed GUI.");
 
-	LOCPLINT = nullptr;
+	GAME->setInterfaceInstance(nullptr);
 }
 
 #ifdef VCMI_ANDROID
@@ -532,19 +532,19 @@ extern "C" JNIEXPORT jboolean JNICALL Java_eu_vcmi_vcmi_NativeMethods_tryToSaveT
 	boost::mutex::scoped_lock interfaceLock(ENGINE->interfaceMutex);
 
 	logGlobal->info("Received emergency save game request");
-	if(!LOCPLINT || !LOCPLINT->cb)
+	if(!GAME->interface() || !GAME->interface()->cb)
 	{
 		logGlobal->info("... but no active player interface found!");
 		return false;
 	}
 
-	if (!CSH || !CSH->logicConnection)
+	if (!GAME->server().logicConnection)
 	{
 		logGlobal->info("... but no active connection found!");
 		return false;
 	}
 
-	LOCPLINT->cb->save("Saves/_Android_Autosave");
+	GAME->interface()->cb->save("Saves/_Android_Autosave");
 	return true;
 }
 #endif

+ 29 - 28
client/ClientCommandManager.cpp

@@ -16,6 +16,7 @@
 #include "PlayerLocalState.h"
 #include "CServerHandler.h"
 #include "GameEngine.h"
+#include "GameInstance.h"
 #include "gui/WindowHandler.h"
 #include "render/IRenderHandler.h"
 #include "ClientNetPackVisitors.h"
@@ -50,7 +51,7 @@ void ClientCommandManager::handleQuitCommand()
 
 void ClientCommandManager::handleSaveCommand(std::istringstream & singleWordBuffer)
 {
-	if(!CSH->client)
+	if(!GAME->server().client)
 	{
 		printCommandMessage("Game is not in playing state");
 		return;
@@ -58,7 +59,7 @@ void ClientCommandManager::handleSaveCommand(std::istringstream & singleWordBuff
 
 	std::string saveFilename;
 	singleWordBuffer >> saveFilename;
-	CSH->client->save(saveFilename);
+	GAME->server().client->save(saveFilename);
 	printCommandMessage("Game saved as: " + saveFilename);
 }
 
@@ -67,7 +68,7 @@ void ClientCommandManager::handleLoadCommand(std::istringstream& singleWordBuffe
 	// TODO: this code should end the running game and manage to call startGame instead
 	//std::string fname;
 	//singleWordBuffer >> fname;
-	//CSH->client->loadGame(fname);
+	//GAME->server().client->loadGame(fname);
 }
 
 void ClientCommandManager::handleGoSoloCommand()
@@ -76,7 +77,7 @@ void ClientCommandManager::handleGoSoloCommand()
 
 	boost::mutex::scoped_lock interfaceLock(ENGINE->interfaceMutex);
 
-	if(!CSH->client)
+	if(!GAME->server().client)
 	{
 		printCommandMessage("Game is not in playing state");
 		return;
@@ -85,26 +86,26 @@ void ClientCommandManager::handleGoSoloCommand()
 	if(session["aiSolo"].Bool())
 	{
 		// unlikely it will work but just in case to be consistent
-		for(auto & color : CSH->getAllClientPlayers(CSH->logicConnection->connectionID))
+		for(auto & color : GAME->server().getAllClientPlayers(GAME->server().logicConnection->connectionID))
 		{
-			if(color.isValidPlayer() && CSH->client->getStartInfo()->playerInfos.at(color).isControlledByHuman())
+			if(color.isValidPlayer() && GAME->server().client->getStartInfo()->playerInfos.at(color).isControlledByHuman())
 			{
-				CSH->client->installNewPlayerInterface(std::make_shared<CPlayerInterface>(color), color);
+				GAME->server().client->installNewPlayerInterface(std::make_shared<CPlayerInterface>(color), color);
 			}
 		}
 	}
 	else
 	{
-		PlayerColor currentColor = LOCPLINT->playerID;
-		CSH->client->removeGUI();
+		PlayerColor currentColor = GAME->interface()->playerID;
+		GAME->server().client->removeGUI();
 		
-		for(auto & color : CSH->getAllClientPlayers(CSH->logicConnection->connectionID))
+		for(auto & color : GAME->server().getAllClientPlayers(GAME->server().logicConnection->connectionID))
 		{
-			if(color.isValidPlayer() && CSH->client->getStartInfo()->playerInfos.at(color).isControlledByHuman())
+			if(color.isValidPlayer() && GAME->server().client->getStartInfo()->playerInfos.at(color).isControlledByHuman())
 			{
-				auto AiToGive = CSH->client->aiNameForPlayer(*CSH->client->getPlayerSettings(color), false, false);
+				auto AiToGive = GAME->server().client->aiNameForPlayer(*GAME->server().client->getPlayerSettings(color), false, false);
 				printCommandMessage("Player " + color.toString() + " will be lead by " + AiToGive, ELogLevel::INFO);
-				CSH->client->installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), color);
+				GAME->server().client->installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), color);
 			}
 		}
 
@@ -129,17 +130,17 @@ void ClientCommandManager::handleControlaiCommand(std::istringstream& singleWord
 
 	boost::mutex::scoped_lock interfaceLock(ENGINE->interfaceMutex);
 
-	if(!CSH->client)
+	if(!GAME->server().client)
 	{
 		printCommandMessage("Game is not in playing state");
 		return;
 	}
 
 	PlayerColor color;
-	if(LOCPLINT)
-		color = LOCPLINT->playerID;
+	if(GAME->interface())
+		color = GAME->interface()->playerID;
 
-	for(auto & elem : CSH->client->gameState()->players)
+	for(auto & elem : GAME->server().client->gameState()->players)
 	{
 		if(!elem.first.isValidPlayer()
 			|| elem.second.human
@@ -148,8 +149,8 @@ void ClientCommandManager::handleControlaiCommand(std::istringstream& singleWord
 			continue;
 		}
 
-		CSH->client->removeGUI();
-		CSH->client->installNewPlayerInterface(std::make_shared<CPlayerInterface>(elem.first), elem.first);
+		GAME->server().client->removeGUI();
+		GAME->server().client->installNewPlayerInterface(std::make_shared<CPlayerInterface>(elem.first), elem.first);
 	}
 
 	ENGINE->windows().totalRedraw();
@@ -436,12 +437,12 @@ void ClientCommandManager::handleBonusesCommand(std::istringstream & singleWordB
 		ss << b;
 		return ss.str();
 	};
-		printCommandMessage("Bonuses of " + LOCPLINT->localState->getCurrentArmy()->getObjectName() + "\n");
-		printCommandMessage(format(*LOCPLINT->localState->getCurrentArmy()->getAllBonuses(Selector::all, Selector::all)) + "\n");
+		printCommandMessage("Bonuses of " + GAME->interface()->localState->getCurrentArmy()->getObjectName() + "\n");
+		printCommandMessage(format(*GAME->interface()->localState->getCurrentArmy()->getAllBonuses(Selector::all, Selector::all)) + "\n");
 
 	printCommandMessage("\nInherited bonuses:\n");
 	TCNodes parents;
-		LOCPLINT->localState->getCurrentArmy()->getParents(parents);
+		GAME->interface()->localState->getCurrentArmy()->getParents(parents);
 	for(const CBonusSystemNode *parent : parents)
 	{
 		printCommandMessage(std::string("\nBonuses from ") + typeid(*parent).name() + "\n" + format(*parent->getAllBonuses(Selector::all, Selector::all)) + "\n");
@@ -457,7 +458,7 @@ void ClientCommandManager::handleTellCommand(std::istringstream& singleWordBuffe
 
 	if(what == "hs")
 	{
-		for(const CGHeroInstance* h : LOCPLINT->cb->getHeroesInfo())
+		for(const CGHeroInstance* h : GAME->interface()->cb->getHeroesInfo())
 			if(h->getHeroTypeID().getNum() == id1)
 				if(const CArtifactInstance* a = h->getArt(ArtifactPosition(id2)))
 					printCommandMessage(a->nodeName());
@@ -466,7 +467,7 @@ void ClientCommandManager::handleTellCommand(std::istringstream& singleWordBuffe
 
 void ClientCommandManager::handleMpCommand()
 {
-	if(const CGHeroInstance* h = LOCPLINT->localState->getCurrentHero())
+	if(const CGHeroInstance* h = GAME->interface()->localState->getCurrentHero())
 		printCommandMessage(std::to_string(h->movementPointsRemaining()) + "; max: " + std::to_string(h->movementPointsLimit(true)) + "/" + std::to_string(h->movementPointsLimit(false)) + "\n");
 }
 
@@ -543,9 +544,9 @@ void ClientCommandManager::printCommandMessage(const std::string &commandMessage
 	if(currentCallFromIngameConsole)
 	{
 		boost::mutex::scoped_lock interfaceLock(ENGINE->interfaceMutex);
-		if(LOCPLINT && LOCPLINT->cingconsole)
+		if(GAME->interface() && GAME->interface()->cingconsole)
 		{
-			LOCPLINT->cingconsole->addMessage("", "System", commandMessage);
+			GAME->interface()->cingconsole->addMessage("", "System", commandMessage);
 		}
 	}
 }
@@ -556,7 +557,7 @@ void ClientCommandManager::giveTurn(const PlayerColor &colorIdentifier)
 	yt.player = colorIdentifier;
 	yt.queryID = QueryID::NONE;
 
-	ApplyClientNetPackVisitor visitor(*CSH->client, *CSH->client->gameState());
+	ApplyClientNetPackVisitor visitor(*GAME->server().client, *GAME->server().client->gameState());
 	yt.visit(visitor);
 }
 
@@ -626,7 +627,7 @@ void ClientCommandManager::processCommand(const std::string & message, bool call
 	else if(commandName == "tell")
 		handleTellCommand(singleWordBuffer);
 
-	else if(commandName == "mp" && LOCPLINT)
+	else if(commandName == "mp" && GAME->interface())
 		handleMpCommand();
 
 	else if (commandName == "set")

+ 9 - 8
client/GameChatHandler.cpp

@@ -10,6 +10,7 @@
 #include "StdInc.h"
 
 #include "GameChatHandler.h"
+#include "GameInstance.h"
 #include "CServerHandler.h"
 #include "CPlayerInterface.h"
 #include "PlayerLocalState.h"
@@ -39,8 +40,8 @@ void GameChatHandler::resetMatchState()
 
 void GameChatHandler::sendMessageGameplay(const std::string & messageText)
 {
-	LOCPLINT->cb->sendMessage(messageText, LOCPLINT->localState->getCurrentArmy());
-	CSH->getGlobalLobby().sendMatchChatMessage(messageText);
+	GAME->interface()->cb->sendMessage(messageText, GAME->interface()->localState->getCurrentArmy());
+	GAME->server().getGlobalLobby().sendMatchChatMessage(messageText);
 }
 
 void GameChatHandler::sendMessageLobby(const std::string & senderName, const std::string & messageText)
@@ -50,8 +51,8 @@ void GameChatHandler::sendMessageLobby(const std::string & senderName, const std
 	txt.appendRawString(messageText);
 	lcm.message = txt;
 	lcm.playerName = senderName;
-	CSH->sendLobbyPack(lcm);
-	CSH->getGlobalLobby().sendMatchChatMessage(messageText);
+	GAME->server().sendLobbyPack(lcm);
+	GAME->server().getGlobalLobby().sendMatchChatMessage(messageText);
 }
 
 void GameChatHandler::onNewLobbyMessageReceived(const std::string & senderName, const std::string & messageText)
@@ -90,20 +91,20 @@ void GameChatHandler::onNewGameMessageReceived(PlayerColor sender, const std::st
 	std::string playerName = "<UNKNOWN>";
 
 	if (sender.isValidPlayer())
-		playerName = LOCPLINT->cb->getStartInfo()->playerInfos.at(sender).name;
+		playerName = GAME->interface()->cb->getStartInfo()->playerInfos.at(sender).name;
 
 	if (sender.isSpectator())
 		playerName = VLC->generaltexth->translate("vcmi.lobby.login.spectator");
 
 	chatHistory.push_back({playerName, messageText, timeFormatted});
 
-	LOCPLINT->cingconsole->addMessage(timeFormatted, playerName, messageText);
+	GAME->interface()->cingconsole->addMessage(timeFormatted, playerName, messageText);
 }
 
 void GameChatHandler::onNewSystemMessageReceived(const std::string & messageText)
 {
 	chatHistory.push_back({"System", messageText, TextOperations::getCurrentFormattedTimeLocal()});
 
-	if(LOCPLINT && !settings["session"]["hideSystemMessages"].Bool())
-		LOCPLINT->cingconsole->addMessage(TextOperations::getCurrentFormattedTimeLocal(), "System", messageText);
+	if(GAME->interface() && !settings["session"]["hideSystemMessages"].Bool())
+		GAME->interface()->cingconsole->addMessage(TextOperations::getCurrentFormattedTimeLocal(), "System", messageText);
 }

+ 2 - 1
client/GameEngine.cpp

@@ -33,6 +33,7 @@
 #include "renderSDL/ScreenHandler.h"
 #include "renderSDL/RenderHandler.h"
 #include "CMT.h"
+#include "GameInstance.h"
 #include "battle/BattleInterface.h"
 
 #include "../lib/CThreadHelper.h"
@@ -90,7 +91,7 @@ void GameEngine::handleEvents()
 	events().dispatchTimer(framerate().getElapsedMilliseconds());
 
 	//player interface may want special event handling
-	if(nullptr != LOCPLINT && LOCPLINT->capturedAllEvents())
+	if(GAME->interface() && GAME->interface()->capturedAllEvents())
 		return;
 
 	input().processEvents();

+ 60 - 0
client/GameInstance.cpp

@@ -0,0 +1,60 @@
+/*
+ * GameInstance.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#include "StdInc.h"
+#include "GameInstance.h"
+
+#include "CServerHandler.h"
+#include "mapView/mapHandler.h"
+
+std::unique_ptr<GameInstance> GAME = nullptr;
+
+GameInstance::GameInstance()
+	: serverInstance(std::make_unique<CServerHandler>())
+	, interfaceInstance(nullptr)
+{
+}
+
+GameInstance::~GameInstance() = default;
+
+CServerHandler & GameInstance::server()
+{
+	if (!serverInstance)
+		throw std::runtime_error("Invalid access to GameInstance::server");
+
+	return *serverInstance;
+}
+
+CMapHandler & GameInstance::map()
+{
+	if (!mapInstance)
+		throw std::runtime_error("Invalid access to GameInstance::map");
+
+	return *mapInstance;
+}
+
+CPlayerInterface * GameInstance::interface()
+{
+	return interfaceInstance;
+}
+
+void GameInstance::setServerInstance(std::unique_ptr<CServerHandler> ptr)
+{
+	serverInstance = std::move(ptr);
+}
+
+void GameInstance::setMapInstance(std::unique_ptr<CMapHandler> ptr)
+{
+	mapInstance = std::move(ptr);
+}
+
+void GameInstance::setInterfaceInstance(CPlayerInterface * ptr)
+{
+	interfaceInstance = std::move(ptr);
+}

+ 38 - 0
client/GameInstance.h

@@ -0,0 +1,38 @@
+/*
+ * GameInstance.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+class CServerHandler;
+class GlobalLobbyClient;
+class INetworkHandler;
+class CPlayerInterface;
+class CMapHandler;
+
+class GameInstance : boost::noncopyable
+{
+	std::unique_ptr<CServerHandler> serverInstance;
+	std::unique_ptr<CMapHandler> mapInstance;
+	CPlayerInterface * interfaceInstance;
+
+public:
+	GameInstance();
+	~GameInstance();
+
+	CServerHandler & server();
+	CMapHandler & map();
+
+	CPlayerInterface * interface();
+
+	void setServerInstance(std::unique_ptr<CServerHandler> ptr);
+	void setMapInstance(std::unique_ptr<CMapHandler> ptr);
+	void setInterfaceInstance(CPlayerInterface * ptr);
+};
+
+extern std::unique_ptr<GameInstance> GAME;

+ 32 - 31
client/HeroMovementController.cpp

@@ -15,6 +15,7 @@
 #include "adventureMap/AdventureMapInterface.h"
 #include "eventsSDL/InputHandler.h"
 #include "GameEngine.h"
+#include "GameInstance.h"
 #include "gui/CursorHandler.h"
 #include "mapView/mapHandler.h"
 #include "media/ISoundPlayer.h"
@@ -35,10 +36,10 @@ bool HeroMovementController::isHeroMovingThroughGarrison(const CGHeroInstance *
 	if(!duringMovement)
 		return false;
 
-	if(!LOCPLINT->localState->hasPath(hero))
+	if(!GAME->interface()->localState->hasPath(hero))
 		return false;
 
-	if(garrison->visitableAt(LOCPLINT->localState->getPath(hero).lastNode().coord))
+	if(garrison->visitableAt(GAME->interface()->localState->getPath(hero).lastNode().coord))
 		return false; // hero want to enter garrison, not pass through it
 
 	return true;
@@ -69,7 +70,7 @@ void HeroMovementController::showTeleportDialog(const CGHeroInstance * hero, Tel
 {
 	if (impassable || exits.empty()) //FIXME: why we even have this dialog in such case?
 	{
-		LOCPLINT->cb->selectionMade(-1, askID);
+		GAME->interface()->cb->selectionMade(-1, askID);
 		return;
 	}
 
@@ -79,14 +80,14 @@ void HeroMovementController::showTeleportDialog(const CGHeroInstance * hero, Tel
 	assert(waitingForQueryApplyReply == false);
 	waitingForQueryApplyReply = true;
 
-	if(!LOCPLINT->localState->hasPath(hero))
+	if(!GAME->interface()->localState->hasPath(hero))
 	{
 		// Hero enters teleporter without specifying exit - select it randomly
-		LOCPLINT->cb->selectionMade(-1, askID);
+		GAME->interface()->cb->selectionMade(-1, askID);
 		return;
 	}
 
-	const auto & heroPath = LOCPLINT->localState->getPath(hero);
+	const auto & heroPath = GAME->interface()->localState->getPath(hero);
 	const auto & nextNode = heroPath.nextNode();
 
 	for(size_t i = 0; i < exits.size(); ++i)
@@ -94,15 +95,15 @@ void HeroMovementController::showTeleportDialog(const CGHeroInstance * hero, Tel
 		if(exits[i].second == nextNode.coord)
 		{
 			// Remove this node from path - it will be covered by teleportation
-			//LOCPLINT->localState->removeLastNode(hero);
-			LOCPLINT->cb->selectionMade(i, askID);
+			//GAME->interface()->localState->removeLastNode(hero);
+			GAME->interface()->cb->selectionMade(i, askID);
 			return;
 		}
 	}
 
 	// may happen when hero has path but does not moves alongside it
 	// for example, while standing on teleporter set path that does not leads throught teleporter and press space
-	LOCPLINT->cb->selectionMade(-1, askID);
+	GAME->interface()->cb->selectionMade(-1, askID);
 	return;
 }
 
@@ -111,17 +112,17 @@ void HeroMovementController::updatePath(const CGHeroInstance * hero, const TryMo
 	// Once hero moved (or attempted to move) we need to update path
 	// to make sure that it is still valid or remove it completely if destination has been reached
 
-	if(hero->tempOwner != LOCPLINT->playerID)
+	if(hero->tempOwner != GAME->interface()->playerID)
 		return;
 
-	if(!LOCPLINT->localState->hasPath(hero))
+	if(!GAME->interface()->localState->hasPath(hero))
 		return; // may happen when hero teleports
 
-	assert(LOCPLINT->makingTurn);
+	assert(GAME->interface()->makingTurn);
 
-	bool directlyAttackingCreature = details.attackedFrom.has_value() && LOCPLINT->localState->getPath(hero).lastNode().coord == details.attackedFrom;
+	bool directlyAttackingCreature = details.attackedFrom.has_value() && GAME->interface()->localState->getPath(hero).lastNode().coord == details.attackedFrom;
 
-	int3 desiredTarget = LOCPLINT->localState->getPath(hero).nextNode().coord;
+	int3 desiredTarget = GAME->interface()->localState->getPath(hero).nextNode().coord;
 	int3 actualTarget = hero->convertToVisitablePos(details.end);
 
 	//don't erase path when revisiting with spacebar
@@ -133,16 +134,16 @@ void HeroMovementController::updatePath(const CGHeroInstance * hero, const TryMo
 		{
 			//invalidate path - movement was not along current path
 			//possible reasons: teleport, visit of object with "blocking visit" property
-			LOCPLINT->localState->erasePath(hero);
+			GAME->interface()->localState->erasePath(hero);
 		}
 		else
 		{
 			//movement along desired path - remove one node and keep rest of path
-			LOCPLINT->localState->removeLastNode(hero);
+			GAME->interface()->localState->removeLastNode(hero);
 		}
 
 		if(directlyAttackingCreature)
-			LOCPLINT->localState->erasePath(hero);
+			GAME->interface()->localState->erasePath(hero);
 	}
 }
 
@@ -153,7 +154,7 @@ void HeroMovementController::onTryMoveHero(const CGHeroInstance * hero, const Tr
 
 	if(details.result == TryMoveHero::EMBARK || details.result == TryMoveHero::DISEMBARK)
 	{
-		if (hero->tempOwner == LOCPLINT->playerID)
+		if (hero->tempOwner == GAME->interface()->playerID)
 		{
 			auto removalSound = hero->getRemovalSound(CRandomGenerator::getDefault());
 			if (removalSound)
@@ -163,8 +164,8 @@ void HeroMovementController::onTryMoveHero(const CGHeroInstance * hero, const Tr
 
 	bool directlyAttackingCreature =
 		details.attackedFrom.has_value() &&
-		LOCPLINT->localState->hasPath(hero) &&
-		LOCPLINT->localState->getPath(hero).lastNode().coord == details.attackedFrom;
+		GAME->interface()->localState->hasPath(hero) &&
+		GAME->interface()->localState->getPath(hero).lastNode().coord == details.attackedFrom;
 
 	std::unordered_set<int3> changedTiles {
 		hero->convertToVisitablePos(details.start),
@@ -184,7 +185,7 @@ void HeroMovementController::onTryMoveHero(const CGHeroInstance * hero, const Tr
 
 	// We are in network thread
 	// Block netpack processing until movement animation is over
-	MAPHANDLER->waitForOngoingAnimations();
+	GAME->map().waitForOngoingAnimations();
 
 	//move finished
 	adventureInt->onHeroChanged(hero);
@@ -240,9 +241,9 @@ void HeroMovementController::onMoveHeroApplied()
 	assert(currentlyMovingHero);
 	const auto * hero = currentlyMovingHero;
 
-	bool canMove = LOCPLINT->localState->hasPath(hero) && LOCPLINT->localState->getPath(hero).nextNode().turns == 0 && !LOCPLINT->showingDialog->isBusy();
+	bool canMove = GAME->interface()->localState->hasPath(hero) && GAME->interface()->localState->getPath(hero).nextNode().turns == 0 && !GAME->interface()->showingDialog->isBusy();
 	bool wantStop = stoppingMovement;
-	bool canStop = !canMove || canHeroStopAtNode(LOCPLINT->localState->getPath(hero).currNode());
+	bool canStop = !canMove || canHeroStopAtNode(GAME->interface()->localState->getPath(hero).currNode());
 
 	if(!canMove || (wantStop && canStop))
 	{
@@ -250,7 +251,7 @@ void HeroMovementController::onMoveHeroApplied()
 	}
 	else
 	{
-		sendMovementRequest(hero, LOCPLINT->localState->getPath(hero));
+		sendMovementRequest(hero, GAME->interface()->localState->getPath(hero));
 	}
 }
 
@@ -287,8 +288,8 @@ AudioPath HeroMovementController::getMovementSoundFor(const CGHeroInstance * her
 	if(hero->hasBonusOfType(BonusType::FLYING_MOVEMENT))
 		return AudioPath::builtin("HORSE10.wav");
 
-	auto prevTile = LOCPLINT->cb->getTile(posPrev);
-	auto nextTile = LOCPLINT->cb->getTile(posNext);
+	auto prevTile = GAME->interface()->cb->getTile(posPrev);
+	auto nextTile = GAME->interface()->cb->getTile(posNext);
 
 	bool movingOnRoad = prevTile->hasRoad() && nextTile->hasRoad();
 
@@ -364,7 +365,7 @@ void HeroMovementController::sendMovementRequest(const CGHeroInstance * h, const
 	{
 		stopMovementSound();
 		logGlobal->trace("Requesting hero teleportation to %s", nextNode.coord.toString());
-		LOCPLINT->cb->moveHero(h, h->pos, false);
+		GAME->interface()->cb->moveHero(h, h->pos, false);
 		return;
 	}
 
@@ -379,7 +380,7 @@ void HeroMovementController::sendMovementRequest(const CGHeroInstance * h, const
 		bool useTransit = nextNode.layer == EPathfindingLayer::AIR || nextNode.layer == EPathfindingLayer::WATER;
 		int3 nextCoord = h->convertFromVisitablePos(nextNode.coord);
 
-		LOCPLINT->cb->moveHero(h, nextCoord, useTransit);
+		GAME->interface()->cb->moveHero(h, nextCoord, useTransit);
 		return;
 	}
 
@@ -404,10 +405,10 @@ void HeroMovementController::sendMovementRequest(const CGHeroInstance * h, const
 		int3 coord = h->convertFromVisitablePos(node.coord);
 		pathToMove.push_back(coord);
 
-		if (LOCPLINT->cb->guardingCreaturePosition(node.coord) != int3(-1, -1, -1))
+		if (GAME->interface()->cb->guardingCreaturePosition(node.coord) != int3(-1, -1, -1))
 			break; // we reached zone-of-control of wandering monster
 
-		if (!LOCPLINT->cb->getVisitableObjs(node.coord).empty())
+		if (!GAME->interface()->cb->getVisitableObjs(node.coord).empty())
 			break; // we reached event, garrison or some other visitable object - end this movement batch
 	}
 
@@ -415,6 +416,6 @@ void HeroMovementController::sendMovementRequest(const CGHeroInstance * h, const
 	if (!pathToMove.empty())
 	{
 		updateMovementSound(h, currNode.coord, nextNode.coord, nextNode.action);
-		LOCPLINT->cb->moveHero(h, pathToMove, useTransitAtStart);
+		GAME->interface()->cb->moveHero(h, pathToMove, useTransitAtStart);
 	}
 }

+ 52 - 75
client/NetPacksClient.cpp

@@ -20,6 +20,7 @@
 #include "battle/BattleInterface.h"
 #include "battle/BattleWindow.h"
 #include "GameEngine.h"
+#include "GameInstance.h"
 #include "gui/WindowHandler.h"
 #include "widgets/MiscWidgets.h"
 #include "CMT.h"
@@ -108,7 +109,7 @@ void callBattleInterfaceIfPresentForBothSides(CClient & cl, const BattleID & bat
 
 	callOnlyThatBattleInterface(cl, cl.gameState()->getBattle(battleID)->getSide(BattleSide::ATTACKER).color, ptr, std::forward<Args2>(args)...);
 	callOnlyThatBattleInterface(cl, cl.gameState()->getBattle(battleID)->getSide(BattleSide::DEFENDER).color, ptr, std::forward<Args2>(args)...);
-	if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool() && LOCPLINT->battleInt)
+	if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool() && GAME->interface()->battleInt)
 	{
 		callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, ptr, std::forward<Args2>(args)...);
 	}
@@ -180,9 +181,9 @@ void ApplyClientNetPackVisitor::visitFoWChange(FoWChange & pack)
 {
 	for(auto &i : cl.playerint)
 	{
-		if(cl.getPlayerRelations(i.first, pack.player) == PlayerRelations::SAME_PLAYER && pack.waitForDialogs && LOCPLINT == i.second.get())
+		if(cl.getPlayerRelations(i.first, pack.player) == PlayerRelations::SAME_PLAYER && pack.waitForDialogs && GAME->interface() == i.second.get())
 		{
-			LOCPLINT->waitWhileDialog();
+			GAME->interface()->waitWhileDialog();
 		}
 		if(cl.getPlayerRelations(i.first, pack.player) != PlayerRelations::ENEMIES)
 		{
@@ -381,21 +382,15 @@ void ApplyClientNetPackVisitor::visitGiveBonus(GiveBonus & pack)
 void ApplyFirstClientNetPackVisitor::visitChangeObjPos(ChangeObjPos & pack)
 {
 	CGObjectInstance *obj = gs.getObjInstance(pack.objid);
-	if(VLC && MAPHANDLER)
-	{
-		MAPHANDLER->onObjectFadeOut(obj, pack.initiator);
-		MAPHANDLER->waitForOngoingAnimations();
-	}
+	GAME->map().onObjectFadeOut(obj, pack.initiator);
+	GAME->map().waitForOngoingAnimations();
 }
 
 void ApplyClientNetPackVisitor::visitChangeObjPos(ChangeObjPos & pack)
 {
 	CGObjectInstance *obj = gs.getObjInstance(pack.objid);
-	if(VLC && MAPHANDLER)
-	{
-		MAPHANDLER->onObjectFadeIn(obj, pack.initiator);
-		MAPHANDLER->waitForOngoingAnimations();
-	}
+	GAME->map().onObjectFadeIn(obj, pack.initiator);
+	GAME->map().waitForOngoingAnimations();
 	callAllInterfaces(cl, &CGameInterface::invalidatePaths);
 }
 
@@ -404,7 +399,7 @@ void ApplyClientNetPackVisitor::visitPlayerEndsGame(PlayerEndsGame & pack)
 	callAllInterfaces(cl, &IGameEventsReceiver::gameOver, pack.player, pack.victoryLossCheckResult);
 
 	bool localHumanWinsGame = vstd::contains(cl.playerint, pack.player) && cl.getPlayerState(pack.player)->human && pack.victoryLossCheckResult.victory();
-	bool lastHumanEndsGame = CSH->howManyPlayerInterfaces() == 1 && vstd::contains(cl.playerint, pack.player) && cl.getPlayerState(pack.player)->human && !settings["session"]["spectate"].Bool();
+	bool lastHumanEndsGame = GAME->server().howManyPlayerInterfaces() == 1 && vstd::contains(cl.playerint, pack.player) && cl.getPlayerState(pack.player)->human && !settings["session"]["spectate"].Bool();
 
 	if(lastHumanEndsGame || localHumanWinsGame)
 	{
@@ -415,7 +410,7 @@ void ApplyClientNetPackVisitor::visitPlayerEndsGame(PlayerEndsGame & pack)
 			adventureInt.reset();
 		}
 
-		CSH->showHighScoresAndEndGameplay(pack.player, pack.victoryLossCheckResult.victory(), pack.statistic);
+		GAME->server().showHighScoresAndEndGameplay(pack.player, pack.victoryLossCheckResult.victory(), pack.statistic);
 	}
 
 	// In auto testing pack.mode we always close client if red pack.player won or lose
@@ -445,14 +440,14 @@ void ApplyClientNetPackVisitor::visitPlayerReinitInterface(PlayerReinitInterface
 	
 	for(auto player : pack.players)
 	{
-		auto & plSettings = CSH->si->getIthPlayersSettings(player);
+		auto & plSettings = GAME->server().si->getIthPlayersSettings(player);
 		if(pack.playerConnectionId == PlayerSettings::PLAYER_AI)
 		{
 			plSettings.connectedPlayerIDs.clear();
 			cl.initPlayerEnvironments();
 			initInterfaces();
 		}
-		else if(pack.playerConnectionId == CSH->logicConnection->connectionID)
+		else if(pack.playerConnectionId == GAME->server().logicConnection->connectionID)
 		{
 			plSettings.connectedPlayerIDs.insert(pack.playerConnectionId);
 			cl.playerint.clear();
@@ -485,8 +480,7 @@ void ApplyFirstClientNetPackVisitor::visitRemoveObject(RemoveObject & pack)
 {
 	const CGObjectInstance *o = cl.getObj(pack.objectID);
 
-	if(MAPHANDLER)
-		MAPHANDLER->onObjectFadeOut(o, pack.initiator);
+	GAME->map().onObjectFadeOut(o, pack.initiator);
 
 	//notify interfaces about removal
 	for(auto i=cl.playerint.begin(); i!=cl.playerint.end(); i++)
@@ -497,8 +491,7 @@ void ApplyFirstClientNetPackVisitor::visitRemoveObject(RemoveObject & pack)
 			i->second->objectRemoved(o, pack.initiator);
 	}
 
-	if(MAPHANDLER)
-		MAPHANDLER->waitForOngoingAnimations();
+	GAME->map().waitForOngoingAnimations();
 }
 
 void ApplyClientNetPackVisitor::visitRemoveObject(RemoveObject & pack)
@@ -513,21 +506,17 @@ void ApplyFirstClientNetPackVisitor::visitTryMoveHero(TryMoveHero & pack)
 {
 	CGHeroInstance *h = gs.getHero(pack.id);
 
-	if(MAPHANDLER)
+	switch (pack.result)
 	{
-		switch (pack.result)
-		{
-			case TryMoveHero::EMBARK:
-				MAPHANDLER->onBeforeHeroEmbark(h, pack.start, pack.end);
-				break;
-			case TryMoveHero::TELEPORTATION:
-				MAPHANDLER->onBeforeHeroTeleported(h, pack.start, pack.end);
-				break;
-			case TryMoveHero::DISEMBARK:
-				MAPHANDLER->onBeforeHeroDisembark(h, pack.start, pack.end);
-				break;
-		}
-		MAPHANDLER->waitForOngoingAnimations();
+		case TryMoveHero::EMBARK:
+			GAME->map().onBeforeHeroEmbark(h, pack.start, pack.end);
+			break;
+		case TryMoveHero::TELEPORTATION:
+			GAME->map().onBeforeHeroTeleported(h, pack.start, pack.end);
+			break;
+		case TryMoveHero::DISEMBARK:
+			GAME->map().onBeforeHeroDisembark(h, pack.start, pack.end);
+			break;
 	}
 }
 
@@ -536,23 +525,20 @@ void ApplyClientNetPackVisitor::visitTryMoveHero(TryMoveHero & pack)
 	const CGHeroInstance *h = cl.getHero(pack.id);
 	callAllInterfaces(cl, &CGameInterface::invalidatePaths);
 
-	if(MAPHANDLER)
+	switch(pack.result)
 	{
-		switch(pack.result)
-		{
-			case TryMoveHero::SUCCESS:
-				MAPHANDLER->onHeroMoved(h, pack.start, pack.end);
-				break;
-			case TryMoveHero::EMBARK:
-				MAPHANDLER->onAfterHeroEmbark(h, pack.start, pack.end);
-				break;
-			case TryMoveHero::TELEPORTATION:
-				MAPHANDLER->onAfterHeroTeleported(h, pack.start, pack.end);
-				break;
-			case TryMoveHero::DISEMBARK:
-				MAPHANDLER->onAfterHeroDisembark(h, pack.start, pack.end);
-				break;
-		}
+		case TryMoveHero::SUCCESS:
+			GAME->map().onHeroMoved(h, pack.start, pack.end);
+			break;
+		case TryMoveHero::EMBARK:
+			GAME->map().onAfterHeroEmbark(h, pack.start, pack.end);
+			break;
+		case TryMoveHero::TELEPORTATION:
+			GAME->map().onAfterHeroTeleported(h, pack.start, pack.end);
+			break;
+		case TryMoveHero::DISEMBARK:
+			GAME->map().onAfterHeroDisembark(h, pack.start, pack.end);
+			break;
 	}
 
 	PlayerColor player = h->tempOwner;
@@ -585,12 +571,10 @@ void ApplyClientNetPackVisitor::visitNewStructures(NewStructures & pack)
 	}
 
 	// invalidate section of map view with our object and force an update
-	if(MAPHANDLER)
-	{
-		MAPHANDLER->onObjectInstantRemove(town, town->getOwner());
-		MAPHANDLER->onObjectInstantAdd(town, town->getOwner());
-	}
+	GAME->map().onObjectInstantRemove(town, town->getOwner());
+	GAME->map().onObjectInstantAdd(town, town->getOwner());
 }
+
 void ApplyClientNetPackVisitor::visitRazeStructures(RazeStructures & pack)
 {
 	CGTownInstance * town = gs.getTown(pack.tid);
@@ -600,11 +584,8 @@ void ApplyClientNetPackVisitor::visitRazeStructures(RazeStructures & pack)
 	}
 
 	// invalidate section of map view with our object and force an update
-	if(MAPHANDLER)
-	{
-		MAPHANDLER->onObjectInstantRemove(town, town->getOwner());
-		MAPHANDLER->onObjectInstantAdd(town, town->getOwner());
-	}
+	GAME->map().onObjectInstantRemove(town, town->getOwner());
+	GAME->map().onObjectInstantAdd(town, town->getOwner());
 }
 
 void ApplyClientNetPackVisitor::visitSetAvailableCreatures(SetAvailableCreatures & pack)
@@ -654,15 +635,13 @@ void ApplyClientNetPackVisitor::visitHeroRecruited(HeroRecruited & pack)
 		if(const CGTownInstance *t = gs.getTown(pack.tid))
 			callInterfaceIfPresent(cl, h->getOwner(), &IGameEventsReceiver::heroInGarrisonChange, t);
 	}
-	if(MAPHANDLER)
-		MAPHANDLER->onObjectInstantAdd(h, h->getOwner());
+	GAME->map().onObjectInstantAdd(h, h->getOwner());
 }
 
 void ApplyClientNetPackVisitor::visitGiveHero(GiveHero & pack)
 {
 	CGHeroInstance *h = gs.getHero(pack.id);
-	if(MAPHANDLER)
-		MAPHANDLER->onObjectInstantAdd(h, h->getOwner());
+	GAME->map().onObjectInstantAdd(h, h->getOwner());
 	callInterfaceIfPresent(cl, h->tempOwner, &IGameEventsReceiver::heroCreated, h);
 }
 
@@ -688,10 +667,10 @@ void ApplyFirstClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty &
 	}
 
 	// invalidate section of map view with our object and force an update with new flag color
-	if(pack.what == ObjProperty::OWNER && MAPHANDLER)
+	if(pack.what == ObjProperty::OWNER)
 	{
 		auto object = gs.getObjInstance(pack.id);
-		MAPHANDLER->onObjectInstantRemove(object, object->getOwner());
+		GAME->map().onObjectInstantRemove(object, object->getOwner());
 	}
 }
 
@@ -705,10 +684,10 @@ void ApplyClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty & pack)
 	}
 
 	// invalidate section of map view with our object and force an update with new flag color
-	if(pack.what == ObjProperty::OWNER && MAPHANDLER)
+	if(pack.what == ObjProperty::OWNER)
 	{
 		auto object = gs.getObjInstance(pack.id);
-		MAPHANDLER->onObjectInstantAdd(object, object->getOwner());
+		GAME->map().onObjectInstantAdd(object, object->getOwner());
 	}
 }
 
@@ -912,7 +891,7 @@ void ApplyClientNetPackVisitor::visitSystemMessage(SystemMessage & pack)
 	// usually used to receive error messages from server
 	logNetwork->error("System message: %s", pack.text.toString());
 
-	CSH->getGameChat().onNewSystemMessageReceived(pack.text.toString());
+	GAME->server().getGameChat().onNewSystemMessageReceived(pack.text.toString());
 }
 
 void ApplyClientNetPackVisitor::visitPlayerBlocked(PlayerBlocked & pack)
@@ -944,7 +923,7 @@ void ApplyClientNetPackVisitor::visitPlayerMessageClient(PlayerMessageClient & p
 {
 	logNetwork->debug("pack.player %s sends a message: %s", pack.player.toString(), pack.text);
 
-	CSH->getGameChat().onNewGameMessageReceived(pack.player, pack.text);
+	GAME->server().getGameChat().onNewGameMessageReceived(pack.player, pack.text);
 }
 
 void ApplyClientNetPackVisitor::visitAdvmapSpellCast(AdvmapSpellCast & pack)
@@ -1045,8 +1024,7 @@ void ApplyClientNetPackVisitor::visitNewObject(NewObject & pack)
 	callAllInterfaces(cl, &CGameInterface::invalidatePaths);
 
 	const CGObjectInstance *obj = pack.newObject;
-	if(MAPHANDLER)
-		MAPHANDLER->onObjectFadeIn(obj, pack.initiator);
+	GAME->map().onObjectFadeIn(obj, pack.initiator);
 
 	for(auto i=cl.playerint.begin(); i!=cl.playerint.end(); i++)
 	{
@@ -1054,8 +1032,7 @@ void ApplyClientNetPackVisitor::visitNewObject(NewObject & pack)
 			i->second->newObject(obj);
 	}
 
-	if(MAPHANDLER)
-		MAPHANDLER->waitForOngoingAnimations();
+	GAME->map().waitForOngoingAnimations();
 }
 
 void ApplyClientNetPackVisitor::visitSetAvailableArtifacts(SetAvailableArtifacts & pack)

+ 3 - 2
client/NetPacksLobbyClient.cpp

@@ -27,6 +27,7 @@
 #include "GameChatHandler.h"
 #include "Client.h"
 #include "GameEngine.h"
+#include "GameInstance.h"
 #include "gui/WindowHandler.h"
 #include "widgets/Buttons.h"
 #include "widgets/TextControls.h"
@@ -212,8 +213,8 @@ void ApplyOnLobbyScreenNetPackVisitor::visitLobbyUpdateState(LobbyUpdateState &
 		{
 			ENGINE->music().stopMusic();
 			ENGINE->windows().createAndPushWindow<VideoWindow>(handler.si->campState->getIntroVideo(), handler.si->campState->getVideoRim().empty() ? ImagePath::builtin("INTRORIM") : handler.si->campState->getVideoRim(), false, 1, [bonusSel](bool skipped){
-				if(!CSH->si->campState->getMusic().empty())
-					ENGINE->music().playMusic(CSH->si->campState->getMusic(), true, false);
+				if(!GAME->server().si->campState->getMusic().empty())
+					ENGINE->music().playMusic(GAME->server().si->campState->getMusic(), true, false);
 				ENGINE->windows().pushWindow(bonusSel);
 			});
 		}

+ 69 - 68
client/adventureMap/AdventureMapInterface.cpp

@@ -27,6 +27,7 @@
 #include "../widgets/RadialMenu.h"
 #include "../gui/CursorHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../gui/WindowHandler.h"
 #include "../render/Canvas.h"
@@ -69,7 +70,7 @@ AdventureMapInterface::AdventureMapInterface():
 	shortcuts->setState(EAdventureState::MAKING_TURN);
 	widget->getMapView()->onViewMapActivated();
 
-	if(LOCPLINT->cb->getStartInfo()->turnTimerInfo.turnTimer != 0)
+	if(GAME->interface()->cb->getStartInfo()->turnTimerInfo.turnTimer != 0)
 		watches = std::make_shared<TurnTimerWidget>(Point(24, 24));
 	
 	addUsedEvents(KEYBOARD | TIME);
@@ -105,7 +106,7 @@ void AdventureMapInterface::onHeroChanged(const CGHeroInstance *h)
 {
 	widget->getHeroList()->updateElement(h);
 
-	if (h && h == LOCPLINT->localState->getCurrentHero() && !widget->getInfoBar()->showingComponents())
+	if (h && h == GAME->interface()->localState->getCurrentHero() && !widget->getInfoBar()->showingComponents())
 		widget->getInfoBar()->showSelection();
 
 	widget->updateActiveState();
@@ -115,7 +116,7 @@ void AdventureMapInterface::onTownChanged(const CGTownInstance * town)
 {
 	widget->getTownList()->updateElement(town);
 
-	if (town && town == LOCPLINT->localState->getCurrentTown() && !widget->getInfoBar()->showingComponents())
+	if (town && town == GAME->interface()->localState->getCurrentTown() && !widget->getInfoBar()->showingComponents())
 		widget->getInfoBar()->showSelection();
 }
 
@@ -130,10 +131,10 @@ void AdventureMapInterface::activate()
 
 	adjustActiveness();
 
-	if(LOCPLINT)
+	if(GAME->interface())
 	{
-		LOCPLINT->cingconsole->activate();
-		LOCPLINT->cingconsole->pos = this->pos;
+		GAME->interface()->cingconsole->activate();
+		GAME->interface()->cingconsole->pos = this->pos;
 	}
 
 	ENGINE->fakeMouseMove(); //to restore the cursor
@@ -141,8 +142,8 @@ void AdventureMapInterface::activate()
 	// workaround for an edge case:
 	// if player unequips Angel Wings / Boots of Levitation of currently active hero
 	// game will correctly invalidate paths but current route will not be updated since verifyPath() is not called for current hero
-	if (LOCPLINT->makingTurn && LOCPLINT->localState->getCurrentHero())
-		LOCPLINT->localState->verifyPath(LOCPLINT->localState->getCurrentHero());
+	if (GAME->interface()->makingTurn && GAME->interface()->localState->getCurrentHero())
+		GAME->interface()->localState->verifyPath(GAME->interface()->localState->getCurrentHero());
 }
 
 void AdventureMapInterface::deactivate()
@@ -150,22 +151,22 @@ void AdventureMapInterface::deactivate()
 	CIntObject::deactivate();
 	ENGINE->cursor().set(Cursor::Map::POINTER);
 
-	if(LOCPLINT)
-		LOCPLINT->cingconsole->deactivate();
+	if(GAME->interface())
+		GAME->interface()->cingconsole->deactivate();
 }
 
 void AdventureMapInterface::showAll(Canvas & to)
 {
 	CIntObject::showAll(to);
 	dim(to);
-	LOCPLINT->cingconsole->show(to);
+	GAME->interface()->cingconsole->show(to);
 }
 
 void AdventureMapInterface::show(Canvas & to)
 {
 	CIntObject::show(to);
 	dim(to);
-	LOCPLINT->cingconsole->show(to);
+	GAME->interface()->cingconsole->show(to);
 }
 
 void AdventureMapInterface::dim(Canvas & to)
@@ -330,7 +331,7 @@ void AdventureMapInterface::onSelectionChanged(const CArmedInstance *sel)
 		widget->getHeroList()->select(hero);
 		widget->getTownList()->select(nullptr);
 
-		LOCPLINT->localState->verifyPath(hero);
+		GAME->interface()->localState->verifyPath(hero);
 		onHeroChanged(hero);
 	}
 
@@ -408,7 +409,7 @@ void AdventureMapInterface::onPlayerTurnStarted(PlayerColor playerID)
 	onCurrentPlayerChanged(playerID);
 
 	setState(EAdventureState::MAKING_TURN);
-	if(playerID == LOCPLINT->playerID || settings["session"]["spectate"].Bool())
+	if(playerID == GAME->interface()->playerID || settings["session"]["spectate"].Bool())
 	{
 		widget->getMinimap()->setAIRadar(false);
 		widget->getInfoBar()->showSelection();
@@ -420,9 +421,9 @@ void AdventureMapInterface::onPlayerTurnStarted(PlayerColor playerID)
 	const CGHeroInstance * heroToSelect = nullptr;
 
 	// find first non-sleeping hero
-	for (auto hero : LOCPLINT->localState->getWanderingHeroes())
+	for (auto hero : GAME->interface()->localState->getWanderingHeroes())
 	{
-		if (!LOCPLINT->localState->isHeroSleeping(hero))
+		if (!GAME->interface()->localState->isHeroSleeping(hero))
 		{
 			heroToSelect = hero;
 			break;
@@ -432,21 +433,21 @@ void AdventureMapInterface::onPlayerTurnStarted(PlayerColor playerID)
 	//select first hero if available.
 	if (heroToSelect != nullptr)
 	{
-		LOCPLINT->localState->setSelection(heroToSelect);
+		GAME->interface()->localState->setSelection(heroToSelect);
 	}
-	else if (LOCPLINT->localState->getOwnedTowns().size())
+	else if (GAME->interface()->localState->getOwnedTowns().size())
 	{
-		LOCPLINT->localState->setSelection(LOCPLINT->localState->getOwnedTown(0));
+		GAME->interface()->localState->setSelection(GAME->interface()->localState->getOwnedTown(0));
 	}
 	else
 	{
-		LOCPLINT->localState->setSelection(LOCPLINT->localState->getWanderingHero(0));
+		GAME->interface()->localState->setSelection(GAME->interface()->localState->getWanderingHero(0));
 	}
 
-	onSelectionChanged(LOCPLINT->localState->getCurrentArmy());
+	onSelectionChanged(GAME->interface()->localState->getCurrentArmy());
 
 	//show new day animation and sound on infobar, except for 1st day of the game
-	if (LOCPLINT->cb->getDate(Date::DAY) != 1)
+	if (GAME->interface()->cb->getDate(Date::DAY) != 1)
 		widget->getInfoBar()->showDate();
 
 	onHeroChanged(nullptr);
@@ -472,11 +473,11 @@ void AdventureMapInterface::hotkeyEndingTurn()
 
 	if(!settings["general"]["startTurnAutosave"].Bool())
 	{
-		LOCPLINT->performAutosave();
+		GAME->interface()->performAutosave();
 	}
 
-	LOCPLINT->makingTurn = false;
-	LOCPLINT->cb->endTurn();
+	GAME->interface()->makingTurn = false;
+	GAME->interface()->cb->endTurn();
 
 	mapAudio->onPlayerTurnEnded();
 
@@ -485,9 +486,9 @@ void AdventureMapInterface::hotkeyEndingTurn()
 	// So find first player other than ours that is acting at the moment and update UI as if he had started turn
 	for (auto player = PlayerColor(0); player < PlayerColor::PLAYER_LIMIT; ++player)
 	{
-		if (player != LOCPLINT->playerID && LOCPLINT->cb->isPlayerMakingTurn(player))
+		if (player != GAME->interface()->playerID && GAME->interface()->cb->isPlayerMakingTurn(player))
 		{
-			onEnemyTurnStarted(player, LOCPLINT->cb->getStartInfo()->playerInfos.at(player).isControlledByHuman());
+			onEnemyTurnStarted(player, GAME->interface()->cb->getStartInfo()->playerInfos.at(player).isControlledByHuman());
 			break;
 		}
 	}
@@ -495,7 +496,7 @@ void AdventureMapInterface::hotkeyEndingTurn()
 
 const CGObjectInstance* AdventureMapInterface::getActiveObject(const int3 &mapPos)
 {
-	std::vector < const CGObjectInstance * > bobjs = LOCPLINT->cb->getBlockingObjs(mapPos);  //blocking objects at tile
+	std::vector < const CGObjectInstance * > bobjs = GAME->interface()->cb->getBlockingObjs(mapPos);  //blocking objects at tile
 
 	if (bobjs.empty())
 		return nullptr;
@@ -508,7 +509,7 @@ void AdventureMapInterface::onTileLeftClicked(const int3 &targetPosition)
 	if(!shortcuts->optionMapViewActive())
 		return;
 
-	const CGObjectInstance *topBlocking = LOCPLINT->cb->isVisible(targetPosition) ? getActiveObject(targetPosition) : nullptr;
+	const CGObjectInstance *topBlocking = GAME->interface()->cb->isVisible(targetPosition) ? getActiveObject(targetPosition) : nullptr;
 
 	if(spellBeingCasted)
 	{
@@ -520,39 +521,39 @@ void AdventureMapInterface::onTileLeftClicked(const int3 &targetPosition)
 		return;
 	}
 
-	if(!LOCPLINT->cb->isVisible(targetPosition))
+	if(!GAME->interface()->cb->isVisible(targetPosition))
 		return;
 
 	//check if we can select this object
-	bool canSelect = topBlocking && topBlocking->ID == Obj::HERO && topBlocking->tempOwner == LOCPLINT->playerID;
-	canSelect |= topBlocking && topBlocking->ID == Obj::TOWN && LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, topBlocking->tempOwner) != PlayerRelations::ENEMIES;
+	bool canSelect = topBlocking && topBlocking->ID == Obj::HERO && topBlocking->tempOwner == GAME->interface()->playerID;
+	canSelect |= topBlocking && topBlocking->ID == Obj::TOWN && GAME->interface()->cb->getPlayerRelations(GAME->interface()->playerID, topBlocking->tempOwner) != PlayerRelations::ENEMIES;
 
-	if(LOCPLINT->localState->getCurrentArmy()->ID != Obj::HERO) //hero is not selected (presumably town)
+	if(GAME->interface()->localState->getCurrentArmy()->ID != Obj::HERO) //hero is not selected (presumably town)
 	{
-		if(LOCPLINT->localState->getCurrentArmy() == topBlocking) //selected town clicked
-			LOCPLINT->openTownWindow(static_cast<const CGTownInstance*>(topBlocking));
+		if(GAME->interface()->localState->getCurrentArmy() == topBlocking) //selected town clicked
+			GAME->interface()->openTownWindow(static_cast<const CGTownInstance*>(topBlocking));
 		else if(canSelect)
-			LOCPLINT->localState->setSelection(static_cast<const CArmedInstance*>(topBlocking));
+			GAME->interface()->localState->setSelection(static_cast<const CArmedInstance*>(topBlocking));
 	}
-	else if(const CGHeroInstance * currentHero = LOCPLINT->localState->getCurrentHero()) //hero is selected
+	else if(const CGHeroInstance * currentHero = GAME->interface()->localState->getCurrentHero()) //hero is selected
 	{
-		const CGPathNode *pn = LOCPLINT->getPathsInfo(currentHero)->getPathInfo(targetPosition);
+		const CGPathNode *pn = GAME->interface()->getPathsInfo(currentHero)->getPathInfo(targetPosition);
 
 		const auto shipyard = dynamic_cast<const IShipyard *>(topBlocking);
 
 		if(currentHero == topBlocking) //clicked selected hero
 		{
-			LOCPLINT->openHeroWindow(currentHero);
+			GAME->interface()->openHeroWindow(currentHero);
 			return;
 		}
 		else if(canSelect && pn->turns == 255 ) //selectable object at inaccessible tile
 		{
-			LOCPLINT->localState->setSelection(static_cast<const CArmedInstance*>(topBlocking));
+			GAME->interface()->localState->setSelection(static_cast<const CArmedInstance*>(topBlocking));
 			return;
 		}
-		else if(shipyard != nullptr && pn->turns == 255 && LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, topBlocking->tempOwner) != PlayerRelations::ENEMIES)
+		else if(shipyard != nullptr && pn->turns == 255 && GAME->interface()->cb->getPlayerRelations(GAME->interface()->playerID, topBlocking->tempOwner) != PlayerRelations::ENEMIES)
 		{
-			LOCPLINT->showShipyardDialogOrProblemPopup(shipyard);
+			GAME->interface()->showShipyardDialogOrProblemPopup(shipyard);
 		}
 		else //still here? we need to move hero if we clicked end of already selected path or calculate a new path otherwise
 		{
@@ -561,13 +562,13 @@ void AdventureMapInterface::onTileLeftClicked(const int3 &targetPosition)
 			if(topBlocking && topBlocking->isVisitable() && !topBlocking->visitableAt(destinationTile) && settings["gameTweaks"]["simpleObjectSelection"].Bool())
 				destinationTile = topBlocking->visitablePos();
 
-			if(LOCPLINT->localState->hasPath(currentHero) &&
-			   LOCPLINT->localState->getPath(currentHero).endPos() == destinationTile &&
+			if(GAME->interface()->localState->hasPath(currentHero) &&
+			   GAME->interface()->localState->getPath(currentHero).endPos() == destinationTile &&
 			   !ENGINE->isKeyboardShiftDown())//we'll be moving
 			{
-				assert(!MAPHANDLER->hasOngoingAnimations());
-				if(!MAPHANDLER->hasOngoingAnimations() && LOCPLINT->localState->getPath(currentHero).nextNode().turns == 0)
-					LOCPLINT->moveHero(currentHero, LOCPLINT->localState->getPath(currentHero));
+				assert(!GAME->map().hasOngoingAnimations());
+				if(!GAME->map().hasOngoingAnimations() && GAME->interface()->localState->getPath(currentHero).nextNode().turns == 0)
+					GAME->interface()->moveHero(currentHero, GAME->interface()->localState->getPath(currentHero));
 				return;
 			}
 			else
@@ -575,11 +576,11 @@ void AdventureMapInterface::onTileLeftClicked(const int3 &targetPosition)
 				if(ENGINE->isKeyboardShiftDown()) //normal click behaviour (as no hero selected)
 				{
 					if(canSelect)
-						LOCPLINT->localState->setSelection(static_cast<const CArmedInstance*>(topBlocking));
+						GAME->interface()->localState->setSelection(static_cast<const CArmedInstance*>(topBlocking));
 				}
 				else //remove old path and find a new one if we clicked on accessible tile
 				{
-					LOCPLINT->localState->setPath(currentHero, destinationTile);
+					GAME->interface()->localState->setPath(currentHero, destinationTile);
 					onHeroChanged(currentHero);
 				}
 			}
@@ -597,10 +598,10 @@ void AdventureMapInterface::onTileHovered(const int3 &targetPosition)
 		return;
 
 	//may occur just at the start of game (fake move before full initialization)
-	if(!LOCPLINT->localState->getCurrentArmy())
+	if(!GAME->interface()->localState->getCurrentArmy())
 		return;
 
-	bool isTargetPositionVisible = LOCPLINT->cb->isVisible(targetPosition);
+	bool isTargetPositionVisible = GAME->interface()->cb->isVisible(targetPosition);
 	const CGObjectInstance *objAtTile = isTargetPositionVisible ? getActiveObject(targetPosition) : nullptr;
 
 	if(spellBeingCasted)
@@ -617,7 +618,7 @@ void AdventureMapInterface::onTileHovered(const int3 &targetPosition)
 		case SpellID::DIMENSION_DOOR:
 			if(isValidAdventureSpellTarget(targetPosition))
 			{
-				if(LOCPLINT->cb->getSettings().getBoolean(EGameSettings::DIMENSION_DOOR_TRIGGERS_GUARDS) && LOCPLINT->cb->isTileGuardedUnchecked(targetPosition))
+				if(GAME->interface()->cb->getSettings().getBoolean(EGameSettings::DIMENSION_DOOR_TRIGGERS_GUARDS) && GAME->interface()->cb->isTileGuardedUnchecked(targetPosition))
 					ENGINE->cursor().set(Cursor::Map::T1_ATTACK);
 				else
 					ENGINE->cursor().set(Cursor::Map::TELEPORT);
@@ -642,8 +643,8 @@ void AdventureMapInterface::onTileHovered(const int3 &targetPosition)
 
 	if(objAtTile)
 	{
-		objRelations = LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, objAtTile->tempOwner);
-		std::string text = LOCPLINT->localState->getCurrentHero() ? objAtTile->getHoverText(LOCPLINT->localState->getCurrentHero()) : objAtTile->getHoverText(LOCPLINT->playerID);
+		objRelations = GAME->interface()->cb->getPlayerRelations(GAME->interface()->playerID, objAtTile->tempOwner);
+		std::string text = GAME->interface()->localState->getCurrentHero() ? objAtTile->getHoverText(GAME->interface()->localState->getCurrentHero()) : objAtTile->getHoverText(GAME->interface()->playerID);
 		boost::replace_all(text,"\n"," ");
 		if (ENGINE->isKeyboardCmdDown())
 			text.append(" (" + std::to_string(targetPosition.x) + ", " + std::to_string(targetPosition.y) + ")");
@@ -651,13 +652,13 @@ void AdventureMapInterface::onTileHovered(const int3 &targetPosition)
 	}
 	else if(isTargetPositionVisible)
 	{
-		std::string tileTooltipText = MAPHANDLER->getTerrainDescr(targetPosition, false);
+		std::string tileTooltipText = GAME->map().getTerrainDescr(targetPosition, false);
 		if (ENGINE->isKeyboardCmdDown())
 			tileTooltipText.append(" (" + std::to_string(targetPosition.x) + ", " + std::to_string(targetPosition.y) + ")");
 		ENGINE->statusbar()->write(tileTooltipText);
 	}
 
-	if(LOCPLINT->localState->getCurrentArmy()->ID == Obj::TOWN || ENGINE->isKeyboardShiftDown())
+	if(GAME->interface()->localState->getCurrentArmy()->ID == Obj::TOWN || ENGINE->isKeyboardShiftDown())
 	{
 		if(objAtTile)
 		{
@@ -671,7 +672,7 @@ void AdventureMapInterface::onTileHovered(const int3 &targetPosition)
 		else
 			ENGINE->cursor().set(Cursor::Map::POINTER);
 	}
-	else if(const CGHeroInstance * hero = LOCPLINT->localState->getCurrentHero())
+	else if(const CGHeroInstance * hero = GAME->interface()->localState->getCurrentHero())
 	{
 		std::array<Cursor::Map, 4> cursorMove      = { Cursor::Map::T1_MOVE,       Cursor::Map::T2_MOVE,       Cursor::Map::T3_MOVE,       Cursor::Map::T4_MOVE,       };
 		std::array<Cursor::Map, 4> cursorAttack    = { Cursor::Map::T1_ATTACK,     Cursor::Map::T2_ATTACK,     Cursor::Map::T3_ATTACK,     Cursor::Map::T4_ATTACK,     };
@@ -681,7 +682,7 @@ void AdventureMapInterface::onTileHovered(const int3 &targetPosition)
 		std::array<Cursor::Map, 4> cursorVisit     = { Cursor::Map::T1_VISIT,      Cursor::Map::T2_VISIT,      Cursor::Map::T3_VISIT,      Cursor::Map::T4_VISIT,      };
 		std::array<Cursor::Map, 4> cursorSailVisit = { Cursor::Map::T1_SAIL_VISIT, Cursor::Map::T2_SAIL_VISIT, Cursor::Map::T3_SAIL_VISIT, Cursor::Map::T4_SAIL_VISIT, };
 
-		const CGPathNode * pathNode = LOCPLINT->getPathsInfo(hero)->getPathInfo(targetPosition);
+		const CGPathNode * pathNode = GAME->interface()->getPathsInfo(hero)->getPathInfo(targetPosition);
 		assert(pathNode);
 
 		if((ENGINE->isKeyboardAltDown() || settings["gameTweaks"]["forceMovementInfo"].Bool()) && pathNode->reachable()) //overwrite status bar text with movement info
@@ -708,7 +709,7 @@ void AdventureMapInterface::onTileHovered(const int3 &targetPosition)
 			}
 
 			if(objAtTile->isVisitable() && !objAtTile->visitableAt(targetPosition) && settings["gameTweaks"]["simpleObjectSelection"].Bool())
-				pathNode = LOCPLINT->getPathsInfo(hero)->getPathInfo(objAtTile->visitablePos());
+				pathNode = GAME->interface()->getPathsInfo(hero)->getPathInfo(objAtTile->visitablePos());
 		}
 
 		int turns = pathNode->turns;
@@ -728,7 +729,7 @@ void AdventureMapInterface::onTileHovered(const int3 &targetPosition)
 		case EPathNodeAction::TELEPORT_BLOCKING_VISIT:
 			if(objAtTile && objAtTile->ID == Obj::HERO)
 			{
-				if(LOCPLINT->localState->getCurrentArmy()  == objAtTile)
+				if(GAME->interface()->localState->getCurrentArmy()  == objAtTile)
 					ENGINE->cursor().set(Cursor::Map::HERO);
 				else
 					ENGINE->cursor().set(cursorExchange[turns]);
@@ -807,7 +808,7 @@ void AdventureMapInterface::onTileRightClicked(const int3 &mapPos)
 		return;
 	}
 
-	if(!LOCPLINT->cb->isVisible(mapPos))
+	if(!GAME->interface()->cb->isVisible(mapPos))
 	{
 		CRClickPopup::createAndPush(VLC->generaltexth->allTexts[61]); //Uncharted Territory
 		return;
@@ -817,10 +818,10 @@ void AdventureMapInterface::onTileRightClicked(const int3 &mapPos)
 	if(!obj)
 	{
 		// Bare or undiscovered terrain
-		const TerrainTile * tile = LOCPLINT->cb->getTile(mapPos);
+		const TerrainTile * tile = GAME->interface()->cb->getTile(mapPos);
 		if(tile)
 		{
-			std::string hlp = MAPHANDLER->getTerrainDescr(mapPos, true);
+			std::string hlp = GAME->map().getTerrainDescr(mapPos, true);
 			CRClickPopup::createAndPush(hlp);
 		}
 		return;
@@ -852,14 +853,14 @@ void AdventureMapInterface::exitCastingMode()
 void AdventureMapInterface::hotkeyAbortCastingMode()
 {
 	exitCastingMode();
-	LOCPLINT->showInfoDialog(VLC->generaltexth->allTexts[731]); //Spell cancelled
+	GAME->interface()->showInfoDialog(VLC->generaltexth->allTexts[731]); //Spell cancelled
 }
 
 void AdventureMapInterface::performSpellcasting(const int3 & dest)
 {
 	SpellID id = spellBeingCasted->id;
 	exitCastingMode();
-	LOCPLINT->cb->castSpell(LOCPLINT->localState->getCurrentHero(), id, dest);
+	GAME->interface()->cb->castSpell(GAME->interface()->localState->getCurrentHero(), id, dest);
 }
 
 Rect AdventureMapInterface::terrainAreaPixels() const
@@ -929,8 +930,8 @@ void AdventureMapInterface::onScreenResize()
 	widget->getMinimap()->update();
 	widget->getInfoBar()->showSelection();
 
-	if (LOCPLINT && LOCPLINT->localState->getCurrentArmy())
-		widget->getMapView()->onCenteredObject(LOCPLINT->localState->getCurrentArmy());
+	if (GAME->interface() && GAME->interface()->localState->getCurrentArmy())
+		widget->getMapView()->onCenteredObject(GAME->interface()->localState->getCurrentArmy());
 
 	adjustActiveness();
 
@@ -942,5 +943,5 @@ bool AdventureMapInterface::isValidAdventureSpellTarget(int3 targetPosition) con
 {
 	spells::detail::ProblemImpl problem;
 
-	return spellBeingCasted->getAdventureMechanics().canBeCastAt(problem, LOCPLINT->cb.get(), LOCPLINT->localState->getCurrentHero(), targetPosition);
+	return spellBeingCasted->getAdventureMechanics().canBeCastAt(problem, GAME->interface()->cb.get(), GAME->interface()->localState->getCurrentHero(), targetPosition);
 }

+ 81 - 80
client/adventureMap/AdventureMapShortcuts.cpp

@@ -16,6 +16,7 @@
 #include "../CServerHandler.h"
 #include "../PlayerLocalState.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../gui/WindowHandler.h"
 #include "../lobby/CSavingScreen.h"
@@ -128,7 +129,7 @@ void AdventureMapShortcuts::worldViewBack()
 {
 	owner.hotkeyExitWorldView();
 
-	auto hero = LOCPLINT->localState->getCurrentHero();
+	auto hero = GAME->interface()->localState->getCurrentHero();
 	if (hero)
 		owner.centerOnObject(hero);
 }
@@ -151,7 +152,7 @@ void AdventureMapShortcuts::worldViewScale4x()
 
 void AdventureMapShortcuts::switchMapLevel()
 {
-	int maxLevels = LOCPLINT->cb->getMapSize().z;
+	int maxLevels = GAME->interface()->cb->getMapSize().z;
 	if (maxLevels < 2)
 		return;
 
@@ -160,7 +161,7 @@ void AdventureMapShortcuts::switchMapLevel()
 
 void AdventureMapShortcuts::showQuestlog()
 {
-	LOCPLINT->showQuestLog();
+	GAME->interface()->showQuestLog();
 }
 
 void AdventureMapShortcuts::toggleTrackHero()
@@ -200,10 +201,10 @@ void AdventureMapShortcuts::toggleSleepWake()
 
 void AdventureMapShortcuts::setHeroSleeping()
 {
-	const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero();
+	const CGHeroInstance *h = GAME->interface()->localState->getCurrentHero();
 	if (h)
 	{
-		LOCPLINT->localState->setHeroAsleep(h);
+		GAME->interface()->localState->setHeroAsleep(h);
 		owner.onHeroChanged(h);
 		nextHero();
 	}
@@ -211,31 +212,31 @@ void AdventureMapShortcuts::setHeroSleeping()
 
 void AdventureMapShortcuts::setHeroAwake()
 {
-	const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero();
+	const CGHeroInstance *h = GAME->interface()->localState->getCurrentHero();
 	if (h)
 	{
-		LOCPLINT->localState->setHeroAwaken(h);
+		GAME->interface()->localState->setHeroAwaken(h);
 		owner.onHeroChanged(h);
 	}
 }
 
 void AdventureMapShortcuts::moveHeroAlongPath()
 {
-	const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero();
-	if (!h || !LOCPLINT->localState->hasPath(h))
+	const CGHeroInstance *h = GAME->interface()->localState->getCurrentHero();
+	if (!h || !GAME->interface()->localState->hasPath(h))
 		return;
 
-	LOCPLINT->moveHero(h, LOCPLINT->localState->getPath(h));
+	GAME->interface()->moveHero(h, GAME->interface()->localState->getPath(h));
 }
 
 void AdventureMapShortcuts::showSpellbook()
 {
-	if (!LOCPLINT->localState->getCurrentHero())
+	if (!GAME->interface()->localState->getCurrentHero())
 		return;
 
-	owner.centerOnObject(LOCPLINT->localState->getCurrentHero());
+	owner.centerOnObject(GAME->interface()->localState->getCurrentHero());
 
-	ENGINE->windows().createAndPushWindow<CSpellWindow>(LOCPLINT->localState->getCurrentHero(), LOCPLINT, false);
+	ENGINE->windows().createAndPushWindow<CSpellWindow>(GAME->interface()->localState->getCurrentHero(), GAME->interface(), false);
 }
 
 void AdventureMapShortcuts::adventureOptions()
@@ -250,52 +251,52 @@ void AdventureMapShortcuts::systemOptions()
 
 void AdventureMapShortcuts::firstHero()
 {
-	if (!LOCPLINT->localState->getWanderingHeroes().empty())
+	if (!GAME->interface()->localState->getWanderingHeroes().empty())
 	{
-		const auto * hero = LOCPLINT->localState->getWanderingHero(0);
-		LOCPLINT->localState->setSelection(hero);
+		const auto * hero = GAME->interface()->localState->getWanderingHero(0);
+		GAME->interface()->localState->setSelection(hero);
 		owner.centerOnObject(hero);
 	}
 }
 
 void AdventureMapShortcuts::nextHero()
 {
-	const auto * currHero = LOCPLINT->localState->getCurrentHero();
-	const auto * nextHero = LOCPLINT->localState->getNextWanderingHero(currHero);
+	const auto * currHero = GAME->interface()->localState->getCurrentHero();
+	const auto * nextHero = GAME->interface()->localState->getNextWanderingHero(currHero);
 
 	if (nextHero)
 	{
-		LOCPLINT->localState->setSelection(nextHero);
+		GAME->interface()->localState->setSelection(nextHero);
 		owner.centerOnObject(nextHero);
 	}
 }
 
 void AdventureMapShortcuts::endTurn()
 {
-	if(!LOCPLINT->makingTurn)
+	if(!GAME->interface()->makingTurn)
 		return;
 
 	if(settings["adventure"]["heroReminder"].Bool())
 	{
-		for(auto hero : LOCPLINT->localState->getWanderingHeroes())
+		for(auto hero : GAME->interface()->localState->getWanderingHeroes())
 		{
-			if(!LOCPLINT->localState->isHeroSleeping(hero) && hero->movementPointsRemaining() > 0)
+			if(!GAME->interface()->localState->isHeroSleeping(hero) && hero->movementPointsRemaining() > 0)
 			{
 				// Only show hero reminder if conditions met:
 				// - There still movement points
 				// - Hero don't have a path or there not points for first step on path
-				LOCPLINT->localState->verifyPath(hero);
+				GAME->interface()->localState->verifyPath(hero);
 
-				if(!LOCPLINT->localState->hasPath(hero))
+				if(!GAME->interface()->localState->hasPath(hero))
 				{
-					LOCPLINT->showYesNoDialog( VLC->generaltexth->allTexts[55], [this](){ owner.hotkeyEndingTurn(); }, nullptr);
+					GAME->interface()->showYesNoDialog( VLC->generaltexth->allTexts[55], [this](){ owner.hotkeyEndingTurn(); }, nullptr);
 					return;
 				}
 
-				auto path = LOCPLINT->localState->getPath(hero);
+				auto path = GAME->interface()->localState->getPath(hero);
 				if (path.nodes.size() < 2 || path.nodes[path.nodes.size() - 2].turns)
 				{
-					LOCPLINT->showYesNoDialog( VLC->generaltexth->allTexts[55], [this](){ owner.hotkeyEndingTurn(); }, nullptr);
+					GAME->interface()->showYesNoDialog( VLC->generaltexth->allTexts[55], [this](){ owner.hotkeyEndingTurn(); }, nullptr);
 					return;
 				}
 			}
@@ -307,15 +308,15 @@ void AdventureMapShortcuts::endTurn()
 void AdventureMapShortcuts::showThievesGuild()
 {
 	//find first town with tavern
-	auto itr = range::find_if(LOCPLINT->localState->getOwnedTowns(), [](const CGTownInstance * town)
+	auto itr = range::find_if(GAME->interface()->localState->getOwnedTowns(), [](const CGTownInstance * town)
 	{
 		return town->hasBuilt(BuildingID::TAVERN);
 	});
 
-	if(itr != LOCPLINT->localState->getOwnedTowns().end())
-		LOCPLINT->showThievesGuildWindow(*itr);
+	if(itr != GAME->interface()->localState->getOwnedTowns().end())
+		GAME->interface()->showThievesGuildWindow(*itr);
 	else
-		LOCPLINT->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.noTownWithTavern"));
+		GAME->interface()->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.noTownWithTavern"));
 }
 
 void AdventureMapShortcuts::showScenarioInfo()
@@ -325,11 +326,11 @@ void AdventureMapShortcuts::showScenarioInfo()
 
 void AdventureMapShortcuts::toMainMenu()
 {
-	LOCPLINT->showYesNoDialog(
+	GAME->interface()->showYesNoDialog(
 		VLC->generaltexth->allTexts[578],
 		[]()
 		{
-			CSH->endGameplay();
+			GAME->server().endGameplay();
 			CMM->menu->switchToTab("main");
 		},
 		0
@@ -338,11 +339,11 @@ void AdventureMapShortcuts::toMainMenu()
 
 void AdventureMapShortcuts::newGame()
 {
-	LOCPLINT->showYesNoDialog(
+	GAME->interface()->showYesNoDialog(
 		VLC->generaltexth->allTexts[578],
 		[]()
 		{
-			CSH->endGameplay();
+			GAME->server().endGameplay();
 			CMM->menu->switchToTab("new");
 		},
 		nullptr
@@ -351,7 +352,7 @@ void AdventureMapShortcuts::newGame()
 
 void AdventureMapShortcuts::quitGame()
 {
-	LOCPLINT->showYesNoDialog(
+	GAME->interface()->showYesNoDialog(
 		VLC->generaltexth->allTexts[578],
 		[]()
 		{
@@ -371,32 +372,32 @@ void AdventureMapShortcuts::saveGame()
 
 void AdventureMapShortcuts::loadGame()
 {
-	LOCPLINT->proposeLoadingGame();
+	GAME->interface()->proposeLoadingGame();
 }
 
 void AdventureMapShortcuts::digGrail()
 {
-	const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero();
+	const CGHeroInstance *h = GAME->interface()->localState->getCurrentHero();
 
-	if(h && LOCPLINT->makingTurn)
-		LOCPLINT->tryDigging(h);
+	if(h && GAME->interface()->makingTurn)
+		GAME->interface()->tryDigging(h);
 }
 
 void AdventureMapShortcuts::viewPuzzleMap()
 {
-	LOCPLINT->showPuzzleMap();
+	GAME->interface()->showPuzzleMap();
 }
 
 void AdventureMapShortcuts::restartGame()
 {
-	LOCPLINT->showYesNoDialog(
+	GAME->interface()->showYesNoDialog(
 		VLC->generaltexth->translate("vcmi.adventureMap.confirmRestartGame"),
 		[]()
 		{
 			ENGINE->dispatchMainThread(
 				[]()
 				{
-					CSH->sendRestartGame();
+					GAME->server().sendRestartGame();
 				}
 			);
 		},
@@ -406,28 +407,28 @@ void AdventureMapShortcuts::restartGame()
 
 void AdventureMapShortcuts::visitObject()
 {
-	const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero();
+	const CGHeroInstance *h = GAME->interface()->localState->getCurrentHero();
 
 	if(h)
-		LOCPLINT->cb->moveHero(h, h->pos, false);
+		GAME->interface()->cb->moveHero(h, h->pos, false);
 }
 
 void AdventureMapShortcuts::openObject()
 {
-	const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero();
-	const CGTownInstance *t = LOCPLINT->localState->getCurrentTown();
+	const CGHeroInstance *h = GAME->interface()->localState->getCurrentHero();
+	const CGTownInstance *t = GAME->interface()->localState->getCurrentTown();
 	if(h)
-		LOCPLINT->openHeroWindow(h);
+		GAME->interface()->openHeroWindow(h);
 
 	if(t)
-		LOCPLINT->openTownWindow(t);
+		GAME->interface()->openTownWindow(t);
 }
 
 void AdventureMapShortcuts::showMarketplace()
 {
 	//check if we have any marketplace
 	const CGTownInstance *townWithMarket = nullptr;
-	for(const CGTownInstance *t : LOCPLINT->cb->getTownsInfo())
+	for(const CGTownInstance *t : GAME->interface()->cb->getTownsInfo())
 	{
 		if(t->hasBuilt(BuildingID::MARKETPLACE))
 		{
@@ -439,15 +440,15 @@ void AdventureMapShortcuts::showMarketplace()
 	if(townWithMarket) //if any town has marketplace, open window
 		ENGINE->windows().createAndPushWindow<CMarketWindow>(townWithMarket, nullptr, nullptr, EMarketMode::RESOURCE_RESOURCE);
 	else //if not - complain
-		LOCPLINT->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.noTownWithMarket"));
+		GAME->interface()->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.noTownWithMarket"));
 }
 
 void AdventureMapShortcuts::firstTown()
 {
-	if (!LOCPLINT->localState->getOwnedTowns().empty())
+	if (!GAME->interface()->localState->getOwnedTowns().empty())
 	{
-		const auto * town = LOCPLINT->localState->getOwnedTown(0);
-		LOCPLINT->localState->setSelection(town);
+		const auto * town = GAME->interface()->localState->getOwnedTown(0);
+		GAME->interface()->localState->setSelection(town);
 		owner.centerOnObject(town);
 	}
 }
@@ -466,14 +467,14 @@ void AdventureMapShortcuts::search(bool next)
 {
 	// get all relevant objects
 	std::vector<ObjectInstanceID> visitableObjInstances;
-	for(auto & obj : LOCPLINT->cb->getAllVisitableObjs())
+	for(auto & obj : GAME->interface()->cb->getAllVisitableObjs())
 		if(obj->ID != MapObjectID::MONSTER && obj->ID != MapObjectID::HERO && obj->ID != MapObjectID::TOWN)
 			visitableObjInstances.push_back(obj->id);
 
 	// count of elements for each group (map is already sorted)
 	std::map<std::string, int> mapObjCount;
 	for(auto & obj : visitableObjInstances)
-		mapObjCount[{ LOCPLINT->cb->getObjInstance(obj)->getObjectName() }]++;
+		mapObjCount[{ GAME->interface()->cb->getObjInstance(obj)->getObjectName() }]++;
 
 	// convert to vector for indexed access
 	std::vector<std::pair<std::string, int>> textCountList;
@@ -499,7 +500,7 @@ void AdventureMapShortcuts::search(bool next)
 			// filter for matching objects
 			std::vector<ObjectInstanceID> selVisitableObjInstances;
 			for(auto & obj : visitableObjInstances)
-				if(selObj == LOCPLINT->cb->getObjInstance(obj)->getObjectName())
+				if(selObj == GAME->interface()->cb->getObjInstance(obj)->getObjectName())
 					selVisitableObjInstances.push_back(obj);
 			
 			if(searchPos + 1 < selVisitableObjInstances.size() && searchLast == selObj)
@@ -507,7 +508,7 @@ void AdventureMapShortcuts::search(bool next)
 			else
 				searchPos = 0;
 
-			auto objInst = LOCPLINT->cb->getObjInstance(selVisitableObjInstances[searchPos]);
+			auto objInst = GAME->interface()->cb->getObjInstance(selVisitableObjInstances[searchPos]);
 			owner.centerOnObject(objInst);
 			searchLast = objInst->getObjectName();
 		};
@@ -520,8 +521,8 @@ void AdventureMapShortcuts::search(bool next)
 
 void AdventureMapShortcuts::nextObject()
 {
-	const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero();
-	const CGTownInstance *t = LOCPLINT->localState->getCurrentTown();
+	const CGHeroInstance *h = GAME->interface()->localState->getCurrentHero();
+	const CGTownInstance *t = GAME->interface()->localState->getCurrentTown();
 	if(h)
 		nextHero();
 
@@ -531,39 +532,39 @@ void AdventureMapShortcuts::nextObject()
 
 void AdventureMapShortcuts::moveHeroDirectional(const Point & direction)
 {
-	const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero(); //selected hero
+	const CGHeroInstance *h = GAME->interface()->localState->getCurrentHero(); //selected hero
 
 	if(!h)
 		return;
 
-	if (MAPHANDLER->hasOngoingAnimations())
+	if (GAME->map().hasOngoingAnimations())
 		return;
 
 	int3 dst = h->visitablePos() + int3(direction.x, direction.y, 0);
 
-	if (!MAPHANDLER->isInMap((dst)))
+	if (!GAME->map().isInMap((dst)))
 		return;
 
-	if ( !LOCPLINT->localState->setPath(h, dst))
+	if ( !GAME->interface()->localState->setPath(h, dst))
 		return;
 
-	const CGPath & path = LOCPLINT->localState->getPath(h);
+	const CGPath & path = GAME->interface()->localState->getPath(h);
 
 	if (path.nodes.size() > 2)
 		owner.onHeroChanged(h);
 	else
 		if(path.nodes[0].turns == 0)
-			LOCPLINT->moveHero(h, path);
+			GAME->interface()->moveHero(h, path);
 }
 
 bool AdventureMapShortcuts::optionCanViewQuests()
 {
-	return optionInMapView() && !MAPHANDLER->getMap()->quests.empty();
+	return optionInMapView() && !GAME->map().getMap()->quests.empty();
 }
 
 bool AdventureMapShortcuts::optionCanToggleLevel()
 {
-	return optionSidePanelActive() && LOCPLINT->cb->getMapSize().z > 1;
+	return optionSidePanelActive() && GAME->interface()->cb->getMapSize().z > 1;
 }
 
 bool AdventureMapShortcuts::optionMapLevelSurface()
@@ -573,14 +574,14 @@ bool AdventureMapShortcuts::optionMapLevelSurface()
 
 bool AdventureMapShortcuts::optionHeroSleeping()
 {
-	const CGHeroInstance *hero = LOCPLINT->localState->getCurrentHero();
-	return optionInMapView() && hero && LOCPLINT->localState->isHeroSleeping(hero);
+	const CGHeroInstance *hero = GAME->interface()->localState->getCurrentHero();
+	return optionInMapView() && hero && GAME->interface()->localState->isHeroSleeping(hero);
 }
 
 bool AdventureMapShortcuts::optionHeroAwake()
 {
-	const CGHeroInstance *hero = LOCPLINT->localState->getCurrentHero();
-	return optionInMapView() && hero && !LOCPLINT->localState->isHeroSleeping(hero);
+	const CGHeroInstance *hero = GAME->interface()->localState->getCurrentHero();
+	return optionInMapView() && hero && !GAME->interface()->localState->isHeroSleeping(hero);
 }
 
 bool AdventureMapShortcuts::optionCanVisitObject()
@@ -588,34 +589,34 @@ bool AdventureMapShortcuts::optionCanVisitObject()
 	if (!optionHeroSelected())
 		return false;
 
-	auto * hero = LOCPLINT->localState->getCurrentHero();
-	auto objects = LOCPLINT->cb->getVisitableObjs(hero->visitablePos());
+	auto * hero = GAME->interface()->localState->getCurrentHero();
+	auto objects = GAME->interface()->cb->getVisitableObjs(hero->visitablePos());
 
 	return objects.size() > 1; // there is object other than our hero
 }
 
 bool AdventureMapShortcuts::optionHeroSelected()
 {
-	return optionInMapView() && LOCPLINT->localState->getCurrentHero() != nullptr;
+	return optionInMapView() && GAME->interface()->localState->getCurrentHero() != nullptr;
 }
 
 bool AdventureMapShortcuts::optionHeroCanMove()
 {
-	const auto * hero = LOCPLINT->localState->getCurrentHero();
-	return optionInMapView() && hero && LOCPLINT->localState->hasPath(hero) && LOCPLINT->localState->getPath(hero).nextNode().turns == 0;
+	const auto * hero = GAME->interface()->localState->getCurrentHero();
+	return optionInMapView() && hero && GAME->interface()->localState->hasPath(hero) && GAME->interface()->localState->getPath(hero).nextNode().turns == 0;
 }
 
 bool AdventureMapShortcuts::optionHasNextHero()
 {
-	const auto * hero = LOCPLINT->localState->getCurrentHero();
-	const auto * nextSuitableHero = LOCPLINT->localState->getNextWanderingHero(hero);
+	const auto * hero = GAME->interface()->localState->getCurrentHero();
+	const auto * nextSuitableHero = GAME->interface()->localState->getNextWanderingHero(hero);
 
 	return optionInMapView() && nextSuitableHero != nullptr;
 }
 
 bool AdventureMapShortcuts::optionCanEndTurn()
 {
-	return optionInMapView() && LOCPLINT->makingTurn;
+	return optionInMapView() && GAME->interface()->makingTurn;
 }
 
 bool AdventureMapShortcuts::optionSpellcasting()

+ 3 - 2
client/adventureMap/AdventureMapWidget.cpp

@@ -18,6 +18,7 @@
 #include "AdventureState.h"
 
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../mapView/MapView.h"
 #include "../render/IImage.h"
@@ -219,7 +220,7 @@ std::shared_ptr<CIntObject> AdventureMapWidget::buildMapHeroList(const JsonNode
 	Point itemOffset(input["itemsOffset"]["x"].Integer(), input["itemsOffset"]["y"].Integer());
 	int itemsCount = input["itemsCount"].Integer();
 
-	auto result = std::make_shared<CHeroList>(itemsCount, area, item.topLeft() - area.topLeft(), itemOffset, LOCPLINT->localState->getWanderingHeroes().size());
+	auto result = std::make_shared<CHeroList>(itemsCount, area, item.topLeft() - area.topLeft(), itemOffset, GAME->interface()->localState->getWanderingHeroes().size());
 
 
 	if(!input["scrollUp"].isNull())
@@ -252,7 +253,7 @@ std::shared_ptr<CIntObject> AdventureMapWidget::buildMapTownList(const JsonNode
 	Point itemOffset(input["itemsOffset"]["x"].Integer(), input["itemsOffset"]["y"].Integer());
 	int itemsCount = input["itemsCount"].Integer();
 
-	auto result = std::make_shared<CTownList>(itemsCount, area, item.topLeft() - area.topLeft(), itemOffset, LOCPLINT->localState->getOwnedTowns().size());
+	auto result = std::make_shared<CTownList>(itemsCount, area, item.topLeft() - area.topLeft(), itemOffset, GAME->interface()->localState->getOwnedTowns().size());
 
 
 	if(!input["scrollUp"].isNull())

+ 7 - 6
client/adventureMap/AdventureOptions.cpp

@@ -16,6 +16,7 @@
 #include "../lobby/CCampaignInfoScreen.h"
 #include "../lobby/CScenarioInfoScreen.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/WindowHandler.h"
 #include "../gui/Shortcut.h"
 #include "../widgets/Buttons.h"
@@ -31,14 +32,14 @@ AdventureOptions::AdventureOptions()
 	OBJECT_CONSTRUCTION;
 
 	viewWorld = std::make_shared<CButton>(Point(24, 23), AnimationPath::builtin("ADVVIEW.DEF"), CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_VIEW_WORLD);
-	viewWorld->addCallback([] { LOCPLINT->viewWorldMap(); });
+	viewWorld->addCallback([] { GAME->interface()->viewWorldMap(); });
 
 	puzzle = std::make_shared<CButton>(Point(24, 81), AnimationPath::builtin("ADVPUZ.DEF"), CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_VIEW_PUZZLE);
-	puzzle->addCallback(std::bind(&CPlayerInterface::showPuzzleMap, LOCPLINT));
+	puzzle->addCallback(std::bind(&CPlayerInterface::showPuzzleMap, GAME->interface()));
 
 	dig = std::make_shared<CButton>(Point(24, 139), AnimationPath::builtin("ADVDIG.DEF"), CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_DIG_GRAIL);
-	if(const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero())
-		dig->addCallback(std::bind(&CPlayerInterface::tryDigging, LOCPLINT, h));
+	if(const CGHeroInstance *h = GAME->interface()->localState->getCurrentHero())
+		dig->addCallback(std::bind(&CPlayerInterface::tryDigging, GAME->interface(), h));
 	else
 		dig->block(true);
 
@@ -46,14 +47,14 @@ AdventureOptions::AdventureOptions()
 	scenInfo->addCallback(AdventureOptions::showScenarioInfo);
 	
 	replay = std::make_shared<CButton>(Point(24, 257), AnimationPath::builtin("ADVTURN.DEF"), CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_REPLAY_TURN);
-	replay->addCallback([]{ LOCPLINT->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.replayOpponentTurnNotImplemented")); });
+	replay->addCallback([]{ GAME->interface()->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.replayOpponentTurnNotImplemented")); });
 
 	exit = std::make_shared<CButton>(Point(203, 313), AnimationPath::builtin("IOK6432.DEF"), CButton::tooltip(), std::bind(&AdventureOptions::close, this), EShortcut::GLOBAL_RETURN);
 }
 
 void AdventureOptions::showScenarioInfo()
 {
-	if(LOCPLINT->cb->getStartInfo()->campState)
+	if(GAME->interface()->cb->getStartInfo()->campState)
 	{
 		ENGINE->windows().createAndPushWindow<CCampaignInfoScreen>();
 	}

+ 6 - 5
client/adventureMap/CInGameConsole.cpp

@@ -16,6 +16,7 @@
 #include "../GameChatHandler.h"
 #include "../ClientCommandManager.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/WindowHandler.h"
 #include "../gui/Shortcut.h"
 #include "../gui/TextAlignment.h"
@@ -46,7 +47,7 @@ void CInGameConsole::showAll(Canvas & to)
 
 void CInGameConsole::show(Canvas & to)
 {
-	if (LOCPLINT->cingconsole != this)
+	if (GAME->interface()->cingconsole != this)
 		return;
 
 	int number = 0;
@@ -142,7 +143,7 @@ bool CInGameConsole::captureThisKey(EShortcut key)
 
 void CInGameConsole::keyPressed (EShortcut key)
 {
-	if (LOCPLINT->cingconsole != this)
+	if (GAME->interface()->cingconsole != this)
 		return;
 
 	if(!isEnteringText() && key != EShortcut::GAME_ACTIVATE_CONSOLE)
@@ -221,7 +222,7 @@ void CInGameConsole::keyPressed (EShortcut key)
 
 void CInGameConsole::textInputted(const std::string & inputtedText)
 {
-	if (LOCPLINT->cingconsole != this)
+	if (GAME->interface()->cingconsole != this)
 		return;
 
 	if(!isEnteringText())
@@ -242,7 +243,7 @@ void CInGameConsole::textEdited(const std::string & inputtedText)
 
 void CInGameConsole::showRecentChatHistory()
 {
-	auto const & history = CSH->getGameChat().getChatHistory();
+	auto const & history = GAME->server().getGameChat().getChatHistory();
 
 	texts.clear();
 
@@ -303,7 +304,7 @@ void CInGameConsole::endEnteringText(bool processEnteredText)
 			clientCommandThread.detach();
 		}
 		else
-			CSH->getGameChat().sendMessageGameplay(txt);
+			GAME->server().getGameChat().sendMessageGameplay(txt);
 	}
 	enteredText.clear();
 

+ 28 - 27
client/adventureMap/CInfoBar.cpp

@@ -22,6 +22,7 @@
 #include "../CPlayerInterface.h"
 #include "../PlayerLocalState.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/WindowHandler.h"
 #include "../media/ISoundPlayer.h"
 #include "../render/IScreenHandler.h"
@@ -78,10 +79,10 @@ CInfoBar::VisibleDateInfo::VisibleDateInfo()
 	animation->setDuration(1500);
 
 	std::string labelText;
-	if(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK) == 1 && LOCPLINT->cb->getDate(Date::DAY) != 1) // monday of any week but first - show new week info
-		labelText = VLC->generaltexth->allTexts[63] + " " + std::to_string(LOCPLINT->cb->getDate(Date::WEEK));
+	if(GAME->interface()->cb->getDate(Date::DAY_OF_WEEK) == 1 && GAME->interface()->cb->getDate(Date::DAY) != 1) // monday of any week but first - show new week info
+		labelText = VLC->generaltexth->allTexts[63] + " " + std::to_string(GAME->interface()->cb->getDate(Date::WEEK));
 	else
-		labelText = VLC->generaltexth->allTexts[64] + " " + std::to_string(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK));
+		labelText = VLC->generaltexth->allTexts[64] + " " + std::to_string(GAME->interface()->cb->getDate(Date::DAY_OF_WEEK));
 
 	label = std::make_shared<CLabel>(95, 31, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, labelText);
 
@@ -90,13 +91,13 @@ CInfoBar::VisibleDateInfo::VisibleDateInfo()
 
 AnimationPath CInfoBar::VisibleDateInfo::getNewDayName()
 {
-	if(LOCPLINT->cb->getDate(Date::DAY) == 1)
+	if(GAME->interface()->cb->getDate(Date::DAY) == 1)
 		return AnimationPath::builtin("NEWDAY");
 
-	if(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK) != 1)
+	if(GAME->interface()->cb->getDate(Date::DAY_OF_WEEK) != 1)
 		return AnimationPath::builtin("NEWDAY");
 
-	switch(LOCPLINT->cb->getDate(Date::WEEK))
+	switch(GAME->interface()->cb->getDate(Date::WEEK))
 	{
 	case 1:
 		return AnimationPath::builtin("NEWWEEK1");
@@ -125,7 +126,7 @@ CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo()
 	OBJECT_CONSTRUCTION;
 	//get amount of halls of each level
 	std::vector<int> halls(4, 0);
-	for(auto town : LOCPLINT->localState->getOwnedTowns())
+	for(auto town : GAME->interface()->localState->getOwnedTowns())
 	{
 		int hallLevel = town->hallLevel();
 		//negative value means no village hall, unlikely but possible
@@ -139,9 +140,9 @@ CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo()
 	//generate list of allies and enemies
 	for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; i++)
 	{
-		if(LOCPLINT->cb->getPlayerStatus(PlayerColor(i), false) == EPlayerStatus::INGAME)
+		if(GAME->interface()->cb->getPlayerStatus(PlayerColor(i), false) == EPlayerStatus::INGAME)
 		{
-			if(LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, PlayerColor(i)) != PlayerRelations::ENEMIES)
+			if(GAME->interface()->cb->getPlayerRelations(GAME->interface()->playerID, PlayerColor(i)) != PlayerRelations::ENEMIES)
 				allies.push_back(PlayerColor(i));
 			else
 				enemies.push_back(PlayerColor(i));
@@ -234,11 +235,11 @@ void CInfoBar::playNewDaySound()
 	if(volume == 0)
 		ENGINE->sound().setVolume(settings["general"]["sound"].Integer());
 
-	if(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK) != 1) // not first day of the week
+	if(GAME->interface()->cb->getDate(Date::DAY_OF_WEEK) != 1) // not first day of the week
 		handle = ENGINE->sound().playSound(soundBase::newDay);
-	else if(LOCPLINT->cb->getDate(Date::WEEK) != 1) // not first week in month
+	else if(GAME->interface()->cb->getDate(Date::WEEK) != 1) // not first week in month
 		handle = ENGINE->sound().playSound(soundBase::newWeek);
-	else if(LOCPLINT->cb->getDate(Date::MONTH) != 1) // not first month
+	else if(GAME->interface()->cb->getDate(Date::MONTH) != 1) // not first month
 		handle = ENGINE->sound().playSound(soundBase::newMonth);
 	else
 		handle = ENGINE->sound().playSound(soundBase::newDay);
@@ -250,22 +251,22 @@ void CInfoBar::playNewDaySound()
 void CInfoBar::reset()
 {
 	OBJECT_CONSTRUCTION;
-	state = EMPTY;
+	state = EState::EMPTY;
 	visibleInfo = std::make_shared<EmptyVisibleInfo>();
 }
 
 void CInfoBar::showSelection()
 {
 	OBJECT_CONSTRUCTION;
-	if(LOCPLINT->localState->getCurrentHero())
+	if(GAME->interface()->localState->getCurrentHero())
 	{
-		showHeroSelection(LOCPLINT->localState->getCurrentHero());
+		showHeroSelection(GAME->interface()->localState->getCurrentHero());
 		return;
 	}
 
-	if(LOCPLINT->localState->getCurrentTown())
+	if(GAME->interface()->localState->getCurrentTown())
 	{
-		showTownSelection(LOCPLINT->localState->getCurrentTown());
+		showTownSelection(GAME->interface()->localState->getCurrentTown());
 		return;
 	}
 
@@ -294,12 +295,12 @@ void CInfoBar::clickReleased(const Point & cursorPosition, bool lastActivated)
 	timerCounter = 0;
 	removeUsedEvents(TIME); //expiration trigger from just clicked element is not valid anymore
 
-	if(state == HERO || state == TOWN)
+	if(state == EState::HERO || state == EState::TOWN)
 	{
 		if(lastActivated)
 			showGameStatus();
 	}
-	else if(state == GAME)
+	else if(state == EState::GAME)
 		showDate();
 	else
 		popComponents(true);
@@ -321,7 +322,7 @@ void CInfoBar::hover(bool on)
 CInfoBar::CInfoBar(const Rect & position)
 	: CIntObject(LCLICK | SHOW_POPUP | HOVER, position.topLeft()),
 	timerCounter(0),
-	state(EMPTY),
+	state(EState::EMPTY),
 	listener(settings.listen["gameTweaks"]["infoBarCreatureManagement"])
 {
 	OBJECT_CONSTRUCTION;
@@ -350,7 +351,7 @@ void CInfoBar::showDate()
 {
 	OBJECT_CONSTRUCTION;
 	playNewDaySound();
-	state = DATE;
+	state = EState::DATE;
 	visibleInfo = std::make_shared<VisibleDateInfo>();
 	setTimer(3000); // confirmed to match H3
 	redraw();
@@ -479,7 +480,7 @@ void CInfoBar::popComponents(bool remove)
 		componentsQueue.pop();
 	if(!componentsQueue.empty())
 	{
-		state = COMPONENT;
+		state = EState::COMPONENT;
 		const auto & extracted = componentsQueue.front();
 		visibleInfo = std::make_shared<VisibleComponentInfo>(extracted.first);
 		setTimer(extracted.second);
@@ -497,13 +498,13 @@ void CInfoBar::pushComponents(const std::vector<Component> & comps, std::string
 
 bool CInfoBar::showingComponents()
 {
-	return state == COMPONENT;
+	return state == EState::COMPONENT;
 }
 
 void CInfoBar::startEnemyTurn(PlayerColor color)
 {
 	OBJECT_CONSTRUCTION;
-	state = AITURN;
+	state = EState::AITURN;
 	visibleInfo = std::make_shared<VisibleEnemyTurnInfo>(color);
 	redraw();
 }
@@ -517,7 +518,7 @@ void CInfoBar::showHeroSelection(const CGHeroInstance * hero)
 	}
 	else
 	{
-		state = HERO;
+		state = EState::HERO;
 		visibleInfo = std::make_shared<VisibleHeroInfo>(hero);
 	}
 	redraw();
@@ -532,7 +533,7 @@ void CInfoBar::showTownSelection(const CGTownInstance * town)
 	}
 	else
 	{
-		state = TOWN;
+		state = EState::TOWN;
 		visibleInfo = std::make_shared<VisibleTownInfo>(town);
 	}
 	redraw();
@@ -541,7 +542,7 @@ void CInfoBar::showTownSelection(const CGTownInstance * town)
 void CInfoBar::showGameStatus()
 {
 	OBJECT_CONSTRUCTION;
-	state = GAME;
+	state = EState::GAME;
 	visibleInfo = std::make_shared<VisibleGameStatusInfo>();
 	setTimer(3000);
 	redraw();

+ 1 - 1
client/adventureMap/CInfoBar.h

@@ -136,7 +136,7 @@ private:
 		VisibleComponentInfo(const std::vector<Component> & compsToDisplay, std::string message, int textH, bool tiny);
 	};
 
-	enum EState
+	enum class EState
 	{
 		EMPTY, HERO, TOWN, DATE, GAME, AITURN, COMPONENT
 	};

+ 39 - 38
client/adventureMap/CList.cpp

@@ -22,6 +22,7 @@
 #include "../CPlayerInterface.h"
 #include "../PlayerLocalState.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../gui/WindowHandler.h"
 #include "../render/Canvas.h"
@@ -249,12 +250,12 @@ std::shared_ptr<CIntObject> CHeroList::CHeroItem::genSelection()
 void CHeroList::CHeroItem::select(bool on)
 {
 	if(on)
-		LOCPLINT->localState->setSelection(hero);
+		GAME->interface()->localState->setSelection(hero);
 }
 
 void CHeroList::CHeroItem::open()
 {
-	LOCPLINT->openHeroWindow(hero);
+	GAME->interface()->openHeroWindow(hero);
 }
 
 void CHeroList::CHeroItem::showTooltip()
@@ -275,7 +276,7 @@ void CHeroList::CHeroItem::gesture(bool on, const Point & initialPosition, const
 	if(!hero)
 		return;
 
-	auto & heroes = LOCPLINT->localState->getWanderingHeroes();
+	auto & heroes = GAME->interface()->localState->getWanderingHeroes();
 
 	if(heroes.size() < 2)
 		return;
@@ -288,14 +289,14 @@ void CHeroList::CHeroItem::gesture(bool on, const Point & initialPosition, const
 		{ RadialMenuConfig::ITEM_ALT_NN, heroUpper != nullptr, "altUpTop", "vcmi.radialWheel.moveTop", [heroPos]()
 		{
 			for (size_t i = heroPos; i > 0; i--)
-				LOCPLINT->localState->swapWanderingHero(i, i - 1);
+				GAME->interface()->localState->swapWanderingHero(i, i - 1);
 		} },
-		{ RadialMenuConfig::ITEM_ALT_NW, heroUpper != nullptr, "altUp", "vcmi.radialWheel.moveUp", [heroPos](){LOCPLINT->localState->swapWanderingHero(heroPos, heroPos - 1); } },
-		{ RadialMenuConfig::ITEM_ALT_SW, heroLower != nullptr, "altDown", "vcmi.radialWheel.moveDown", [heroPos](){ LOCPLINT->localState->swapWanderingHero(heroPos, heroPos + 1); } },
+		{ RadialMenuConfig::ITEM_ALT_NW, heroUpper != nullptr, "altUp", "vcmi.radialWheel.moveUp", [heroPos](){GAME->interface()->localState->swapWanderingHero(heroPos, heroPos - 1); } },
+		{ RadialMenuConfig::ITEM_ALT_SW, heroLower != nullptr, "altDown", "vcmi.radialWheel.moveDown", [heroPos](){ GAME->interface()->localState->swapWanderingHero(heroPos, heroPos + 1); } },
 		{ RadialMenuConfig::ITEM_ALT_SS, heroLower != nullptr, "altDownBottom", "vcmi.radialWheel.moveBottom", [heroPos, heroes]()
 		{
 			for (int i = heroPos; i < heroes.size() - 1; i++)
-				LOCPLINT->localState->swapWanderingHero(i, i + 1);
+				GAME->interface()->localState->swapWanderingHero(i, i + 1);
 		} },
 	};
 
@@ -310,11 +311,11 @@ void CHeroList::CHeroItem::keyPressed(EShortcut key)
 	if(parent->selected != this->shared_from_this())
 		return;
 
-	auto & heroes = LOCPLINT->localState->getWanderingHeroes();
+	auto & heroes = GAME->interface()->localState->getWanderingHeroes();
 
 	if(key == EShortcut::LIST_HERO_DISMISS)
 	{
-		LOCPLINT->showYesNoDialog(VLC->generaltexth->allTexts[22], [=](){ LOCPLINT->cb->dismissHero(hero); }, nullptr);
+		GAME->interface()->showYesNoDialog(VLC->generaltexth->allTexts[22], [=](){ GAME->interface()->cb->dismissHero(hero); }, nullptr);
 		return;
 	}
 
@@ -329,32 +330,32 @@ void CHeroList::CHeroItem::keyPressed(EShortcut key)
 	{
 	case EShortcut::LIST_HERO_UP:
 		if(heroUpper)
-			LOCPLINT->localState->swapWanderingHero(heroPos, heroPos - 1);
+			GAME->interface()->localState->swapWanderingHero(heroPos, heroPos - 1);
 		break;
 
 	case EShortcut::LIST_HERO_DOWN:
 		if(heroLower)
-			LOCPLINT->localState->swapWanderingHero(heroPos, heroPos + 1);
+			GAME->interface()->localState->swapWanderingHero(heroPos, heroPos + 1);
 		break;
 
 	case EShortcut::LIST_HERO_TOP:
 		if(heroUpper)
 			for (size_t i = heroPos; i > 0; i--)
-				LOCPLINT->localState->swapWanderingHero(i, i - 1);
+				GAME->interface()->localState->swapWanderingHero(i, i - 1);
 		break;
 
 	case EShortcut::LIST_HERO_BOTTOM:
 		if(heroLower)
 			for (int i = heroPos; i < heroes.size() - 1; i++)
-				LOCPLINT->localState->swapWanderingHero(i, i + 1);
+				GAME->interface()->localState->swapWanderingHero(i, i + 1);
 		break;
 	}
 }
 
 std::shared_ptr<CIntObject> CHeroList::createItem(size_t index)
 {
-	if (LOCPLINT->localState->getWanderingHeroes().size() > index)
-		return std::make_shared<CHeroItem>(this, LOCPLINT->localState->getWanderingHero(index));
+	if (GAME->interface()->localState->getWanderingHeroes().size() > index)
+		return std::make_shared<CHeroItem>(this, GAME->interface()->localState->getWanderingHero(index));
 	return std::make_shared<CEmptyHeroItem>();
 }
 
@@ -366,7 +367,7 @@ CHeroList::CHeroList(int visibleItemsCount, Rect widgetPosition, Point firstItem
 
 void CHeroList::select(const CGHeroInstance * hero)
 {
-	selectIndex(vstd::find_pos(LOCPLINT->localState->getWanderingHeroes(), hero));
+	selectIndex(vstd::find_pos(GAME->interface()->localState->getWanderingHeroes(), hero));
 }
 
 void CHeroList::updateElement(const CGHeroInstance * hero)
@@ -376,7 +377,7 @@ void CHeroList::updateElement(const CGHeroInstance * hero)
 
 void CHeroList::updateWidget()
 {
-	const auto & heroes = LOCPLINT->localState->getWanderingHeroes();
+	const auto & heroes = GAME->interface()->localState->getWanderingHeroes();
 
 	listBox->resize(heroes.size());
 
@@ -398,16 +399,16 @@ void CHeroList::updateWidget()
 		}
 	}
 
-	if (LOCPLINT->localState->getCurrentHero())
-		select(LOCPLINT->localState->getCurrentHero());
+	if (GAME->interface()->localState->getCurrentHero())
+		select(GAME->interface()->localState->getCurrentHero());
 
 	CList::update();
 }
 
 std::shared_ptr<CIntObject> CTownList::createItem(size_t index)
 {
-	if (LOCPLINT->localState->getOwnedTowns().size() > index)
-		return std::make_shared<CTownItem>(this, LOCPLINT->localState->getOwnedTown(index));
+	if (GAME->interface()->localState->getOwnedTowns().size() > index)
+		return std::make_shared<CTownItem>(this, GAME->interface()->localState->getOwnedTown(index));
 	return std::make_shared<CAnimImage>(AnimationPath::builtin("ITPA"), 0);
 }
 
@@ -430,7 +431,7 @@ std::shared_ptr<CIntObject> CTownList::CTownItem::genSelection()
 
 void CTownList::CTownItem::update()
 {
-	size_t iconIndex = town->getTown()->clientInfo.icons[town->hasFort()][town->built >= LOCPLINT->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
+	size_t iconIndex = town->getTown()->clientInfo.icons[town->hasFort()][town->built >= GAME->interface()->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
 
 	picture->setFrame(iconIndex + 2);
 	redraw();
@@ -439,12 +440,12 @@ void CTownList::CTownItem::update()
 void CTownList::CTownItem::select(bool on)
 {
 	if(on)
-		LOCPLINT->localState->setSelection(town);
+		GAME->interface()->localState->setSelection(town);
 }
 
 void CTownList::CTownItem::open()
 {
-	LOCPLINT->openTownWindow(town);
+	GAME->interface()->openTownWindow(town);
 }
 
 void CTownList::CTownItem::showTooltip()
@@ -457,7 +458,7 @@ void CTownList::CTownItem::gesture(bool on, const Point & initialPosition, const
 	if(!on)
 		return;
 
-	const std::vector<const CGTownInstance *> towns = LOCPLINT->localState->getOwnedTowns();
+	const std::vector<const CGTownInstance *> towns = GAME->interface()->localState->getOwnedTowns();
 	size_t townIndex = vstd::find_pos(towns, town);
 
 	if(townIndex + 1 > towns.size() || !towns.at(townIndex))
@@ -481,15 +482,15 @@ void CTownList::CTownItem::gesture(bool on, const Point & initialPosition, const
 		{ RadialMenuConfig::ITEM_ALT_NN, townUpperPos > -1, "altUpTop", "vcmi.radialWheel.moveTop", [updateList, townIndex]()
 		{
 			for (int i = townIndex; i > 0; i--)
-				LOCPLINT->localState->swapOwnedTowns(i, i - 1);
+				GAME->interface()->localState->swapOwnedTowns(i, i - 1);
 			updateList();
 		} },
-		{ RadialMenuConfig::ITEM_ALT_NW, townUpperPos > -1, "altUp", "vcmi.radialWheel.moveUp", [updateList, townIndex, townUpperPos](){LOCPLINT->localState->swapOwnedTowns(townIndex, townUpperPos); updateList(); } },
-		{ RadialMenuConfig::ITEM_ALT_SW, townLowerPos > -1, "altDown", "vcmi.radialWheel.moveDown", [updateList, townIndex, townLowerPos](){ LOCPLINT->localState->swapOwnedTowns(townIndex, townLowerPos); updateList(); } },
+		{ RadialMenuConfig::ITEM_ALT_NW, townUpperPos > -1, "altUp", "vcmi.radialWheel.moveUp", [updateList, townIndex, townUpperPos](){GAME->interface()->localState->swapOwnedTowns(townIndex, townUpperPos); updateList(); } },
+		{ RadialMenuConfig::ITEM_ALT_SW, townLowerPos > -1, "altDown", "vcmi.radialWheel.moveDown", [updateList, townIndex, townLowerPos](){ GAME->interface()->localState->swapOwnedTowns(townIndex, townLowerPos); updateList(); } },
 		{ RadialMenuConfig::ITEM_ALT_SS, townLowerPos > -1, "altDownBottom", "vcmi.radialWheel.moveBottom", [updateList, townIndex, towns]()
 		{
 			for (int i = townIndex; i < towns.size() - 1; i++)
-				LOCPLINT->localState->swapOwnedTowns(i, i + 1);
+				GAME->interface()->localState->swapOwnedTowns(i, i + 1);
 			updateList();
 		} },
 	};
@@ -502,7 +503,7 @@ void CTownList::CTownItem::keyPressed(EShortcut key)
 	if(parent->selected != this->shared_from_this())
 		return;
 
-	const std::vector<const CGTownInstance *> towns = LOCPLINT->localState->getOwnedTowns();
+	const std::vector<const CGTownInstance *> towns = GAME->interface()->localState->getOwnedTowns();
 	size_t townIndex = vstd::find_pos(towns, town);
 
 	if(townIndex + 1 > towns.size() || !towns.at(townIndex))
@@ -518,24 +519,24 @@ void CTownList::CTownItem::keyPressed(EShortcut key)
 	{
 	case EShortcut::LIST_TOWN_UP:
 		if(townUpperPos > -1)
-			LOCPLINT->localState->swapOwnedTowns(townIndex, townUpperPos);
+			GAME->interface()->localState->swapOwnedTowns(townIndex, townUpperPos);
 		break;
 
 	case EShortcut::LIST_TOWN_DOWN:
 		if(townLowerPos > -1)
-			LOCPLINT->localState->swapOwnedTowns(townIndex, townLowerPos);
+			GAME->interface()->localState->swapOwnedTowns(townIndex, townLowerPos);
 		break;
 
 	case EShortcut::LIST_TOWN_TOP:
 		if(townUpperPos > -1)
 			for (int i = townIndex; i > 0; i--)
-				LOCPLINT->localState->swapOwnedTowns(i, i - 1);
+				GAME->interface()->localState->swapOwnedTowns(i, i - 1);
 		break;
 
 	case EShortcut::LIST_TOWN_BOTTOM:
 		if(townLowerPos > -1)
 			for (int i = townIndex; i < towns.size() - 1; i++)
-				LOCPLINT->localState->swapOwnedTowns(i, i + 1);
+				GAME->interface()->localState->swapOwnedTowns(i, i + 1);
 		break;
 	}
 
@@ -556,7 +557,7 @@ CTownList::CTownList(int visibleItemsCount, Rect widgetPosition, Point firstItem
 
 void CTownList::select(const CGTownInstance * town)
 {
-	selectIndex(vstd::find_pos(LOCPLINT->localState->getOwnedTowns(), town));
+	selectIndex(vstd::find_pos(GAME->interface()->localState->getOwnedTowns(), town));
 }
 
 void CTownList::updateElement(const CGTownInstance * town)
@@ -566,7 +567,7 @@ void CTownList::updateElement(const CGTownInstance * town)
 
 void CTownList::updateWidget()
 {
-	auto & towns = LOCPLINT->localState->getOwnedTowns();
+	auto & towns = GAME->interface()->localState->getOwnedTowns();
 
 	listBox->resize(towns.size());
 
@@ -588,8 +589,8 @@ void CTownList::updateWidget()
 		}
 	}
 
-	if (LOCPLINT->localState->getCurrentTown())
-		select(LOCPLINT->localState->getCurrentTown());
+	if (GAME->interface()->localState->getCurrentTown())
+		select(GAME->interface()->localState->getCurrentTown());
 
 	CList::update();
 }

+ 9 - 8
client/adventureMap/CMinimap.cpp

@@ -16,6 +16,7 @@
 #include "../widgets/Images.h"
 #include "../CPlayerInterface.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/MouseButton.h"
 #include "../gui/WindowHandler.h"
 #include "../render/Colors.h"
@@ -31,7 +32,7 @@
 
 ColorRGBA CMinimapInstance::getTileColor(const int3 & pos) const
 {
-	const TerrainTile * tile = LOCPLINT->cb->getTile(pos, false);
+	const TerrainTile * tile = GAME->interface()->cb->getTile(pos, false);
 
 	// if tile is not visible it will be black on minimap
 	if(!tile)
@@ -62,7 +63,7 @@ void CMinimapInstance::refreshTile(const int3 &tile)
 
 void CMinimapInstance::redrawMinimap()
 {
-	int3 mapSizes = LOCPLINT->cb->getMapSize();
+	int3 mapSizes = GAME->interface()->cb->getMapSize();
 
 	for (int y = 0; y < mapSizes.y; ++y)
 		for (int x = 0; x < mapSizes.x; ++x)
@@ -70,7 +71,7 @@ void CMinimapInstance::redrawMinimap()
 }
 
 CMinimapInstance::CMinimapInstance(const Point & position, const Point & dimensions, int Level):
-	minimap(new Canvas(Point(LOCPLINT->cb->getMapSize().x, LOCPLINT->cb->getMapSize().y), CanvasScalingPolicy::IGNORE)),
+	minimap(new Canvas(Point(GAME->interface()->cb->getMapSize().x, GAME->interface()->cb->getMapSize().y), CanvasScalingPolicy::IGNORE)),
 	level(Level)
 {
 	pos += position;
@@ -92,10 +93,10 @@ CMinimap::CMinimap(const Rect & position)
 {
 	OBJECT_CONSTRUCTION;
 
-	double maxSideLengthSrc = std::max(LOCPLINT->cb->getMapSize().x, LOCPLINT->cb->getMapSize().y);
+	double maxSideLengthSrc = std::max(GAME->interface()->cb->getMapSize().x, GAME->interface()->cb->getMapSize().y);
 	double maxSideLengthDst = std::max(position.w, position.h);
 	double resize = maxSideLengthSrc / maxSideLengthDst;
-	Point newMinimapSize(LOCPLINT->cb->getMapSize().x/ resize, LOCPLINT->cb->getMapSize().y / resize);
+	Point newMinimapSize(GAME->interface()->cb->getMapSize().x/ resize, LOCPLINT->cb->getMapSize().y / resize);
 	Point offset = Point((std::max(newMinimapSize.x, newMinimapSize.y) - newMinimapSize.x) / 2, (std::max(newMinimapSize.x, newMinimapSize.y) - newMinimapSize.y) / 2);
 
 	pos.x += offset.x;
@@ -113,7 +114,7 @@ int3 CMinimap::pixelToTile(const Point & cursorPos) const
 	double dx = static_cast<double>(cursorPos.x) / pos.w;
 	double dy = static_cast<double>(cursorPos.y) / pos.h;
 
-	int3 mapSizes = LOCPLINT->cb->getMapSize();
+	int3 mapSizes = GAME->interface()->cb->getMapSize();
 
 	int tileX(std::round(mapSizes.x * dx));
 	int tileY(std::round(mapSizes.y * dy));
@@ -123,7 +124,7 @@ int3 CMinimap::pixelToTile(const Point & cursorPos) const
 
 Point CMinimap::tileToPixels(const int3 &tile) const
 {
-	int3 mapSizes = LOCPLINT->cb->getMapSize();
+	int3 mapSizes = GAME->interface()->cb->getMapSize();
 
 	double stepX = static_cast<double>(pos.w) / mapSizes.x;
 	double stepY = static_cast<double>(pos.h) / mapSizes.y;
@@ -181,7 +182,7 @@ void CMinimap::showAll(Canvas & to)
 
 	if(minimap)
 	{
-		int3 mapSizes = LOCPLINT->cb->getMapSize();
+		int3 mapSizes = GAME->interface()->cb->getMapSize();
 
 		//draw radar
 		Rect radar =

+ 6 - 5
client/adventureMap/CResDataBar.cpp

@@ -15,6 +15,7 @@
 #include "../render/Colors.h"
 #include "../render/EFont.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/TextAlignment.h"
 #include "../widgets/Images.h"
 
@@ -31,7 +32,7 @@ CResDataBar::CResDataBar(const ImagePath & imageName, const Point & position)
 
 	OBJECT_CONSTRUCTION;
 	background = std::make_shared<CPicture>(imageName, 0, 0);
-	background->setPlayerColor(LOCPLINT->playerID);
+	background->setPlayerColor(GAME->interface()->playerID);
 
 	pos.w = background->pos.w;
 	pos.h = background->pos.h;
@@ -61,9 +62,9 @@ std::string CResDataBar::buildDateString()
 	std::string pattern = "%s: %d, %s: %d, %s: %d";
 
 	auto formatted = boost::format(pattern)
-		% VLC->generaltexth->translate("core.genrltxt.62") % LOCPLINT->cb->getDate(Date::MONTH)
-		% VLC->generaltexth->translate("core.genrltxt.63") % LOCPLINT->cb->getDate(Date::WEEK)
-		% VLC->generaltexth->translate("core.genrltxt.64") % LOCPLINT->cb->getDate(Date::DAY_OF_WEEK);
+		% VLC->generaltexth->translate("core.genrltxt.62") % GAME->interface()->cb->getDate(Date::MONTH)
+		% VLC->generaltexth->translate("core.genrltxt.63") % GAME->interface()->cb->getDate(Date::WEEK)
+		% VLC->generaltexth->translate("core.genrltxt.64") % GAME->interface()->cb->getDate(Date::DAY_OF_WEEK);
 
 	return boost::str(formatted);
 }
@@ -75,7 +76,7 @@ void CResDataBar::showAll(Canvas & to)
 	//TODO: all this should be labels, but they require proper text update on change
 	for (auto & entry : resourcePositions)
 	{
-		std::string text = std::to_string(LOCPLINT->cb->getResourceAmount(entry.first));
+		std::string text = std::to_string(GAME->interface()->cb->getResourceAmount(entry.first));
 
 		to.drawText(pos.topLeft() + entry.second, FONT_SMALL, Colors::WHITE, ETextAlignment::TOPLEFT, text);
 	}

+ 13 - 12
client/adventureMap/MapAudioPlayer.cpp

@@ -13,6 +13,7 @@
 #include "../CCallback.h"
 #include "../CPlayerInterface.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../mapView/mapHandler.h"
 #include "../media/IMusicPlayer.h"
 #include "../media/ISoundPlayer.h"
@@ -83,7 +84,7 @@ void MapAudioPlayer::addObject(const CGObjectInstance * obj)
 			{
 				int3 currTile(obj->anchorPos().x - fx, obj->anchorPos().y - fy, obj->anchorPos().z);
 
-				if(LOCPLINT->cb->isInTheMap(currTile) && obj->coveringAt(currTile))
+				if(GAME->interface()->cb->isInTheMap(currTile) && obj->coveringAt(currTile))
 					objects[currTile.z][currTile.x][currTile.y].push_back(obj->id);
 			}
 		}
@@ -95,7 +96,7 @@ void MapAudioPlayer::addObject(const CGObjectInstance * obj)
 		// visitable object - visitable tile acts as sound source
 		int3 currTile = obj->visitablePos();
 
-		if(LOCPLINT->cb->isInTheMap(currTile))
+		if(GAME->interface()->cb->isInTheMap(currTile))
 			objects[currTile.z][currTile.x][currTile.y].push_back(obj->id);
 
 		return;
@@ -110,7 +111,7 @@ void MapAudioPlayer::addObject(const CGObjectInstance * obj)
 		{
 			int3 currTile = obj->anchorPos() + tile;
 
-			if(LOCPLINT->cb->isInTheMap(currTile))
+			if(GAME->interface()->cb->isInTheMap(currTile))
 				objects[currTile.z][currTile.x][currTile.y].push_back(obj->id);
 		}
 		return;
@@ -119,9 +120,9 @@ void MapAudioPlayer::addObject(const CGObjectInstance * obj)
 
 void MapAudioPlayer::removeObject(const CGObjectInstance * obj)
 {
-	for(int z = 0; z < LOCPLINT->cb->getMapSize().z; z++)
-		for(int x = 0; x < LOCPLINT->cb->getMapSize().x; x++)
-			for(int y = 0; y < LOCPLINT->cb->getMapSize().y; y++)
+	for(int z = 0; z < GAME->interface()->cb->getMapSize().z; z++)
+		for(int x = 0; x < GAME->interface()->cb->getMapSize().x; x++)
+			for(int y = 0; y < GAME->interface()->cb->getMapSize().y; y++)
 				vstd::erase(objects[z][x][y], obj->id);
 }
 
@@ -131,7 +132,7 @@ std::vector<AudioPath> MapAudioPlayer::getAmbientSounds(const int3 & tile)
 
 	for(auto & objectID : objects[tile.z][tile.x][tile.y])
 	{
-		const auto & object = MAPHANDLER->getMap()->objects[objectID.getNum()];
+		const auto & object = GAME->map().getMap()->objects[objectID.getNum()];
 
 		assert(object);
 		if (!object)
@@ -145,7 +146,7 @@ std::vector<AudioPath> MapAudioPlayer::getAmbientSounds(const int3 & tile)
 		}
 	}
 
-	if(MAPHANDLER->getMap()->isCoastalTile(tile))
+	if(GAME->map().getMap()->isCoastalTile(tile))
 		result.emplace_back(AudioPath::builtin("LOOPOCEA"));
 
 	return result;
@@ -164,7 +165,7 @@ void MapAudioPlayer::updateAmbientSounds()
 
 	int3 pos = currentSelection->getSightCenter();
 	std::unordered_set<int3> tiles;
-	LOCPLINT->cb->getVisibleTilesInRange(tiles, pos, ENGINE->sound().ambientGetRange(), int3::DIST_CHEBYSHEV);
+	GAME->interface()->cb->getVisibleTilesInRange(tiles, pos, ENGINE->sound().ambientGetRange(), int3::DIST_CHEBYSHEV);
 	for(int3 tile : tiles)
 	{
 		int dist = pos.dist(tile, int3::DIST_CHEBYSHEV);
@@ -179,7 +180,7 @@ void MapAudioPlayer::updateMusic()
 {
 	if(audioPlaying && playerMakingTurn && currentSelection)
 	{
-		const auto * tile = LOCPLINT->cb->getTile(currentSelection->visitablePos());
+		const auto * tile = GAME->interface()->cb->getTile(currentSelection->visitablePos());
 
 		if (tile)
 			ENGINE->music().playMusicFromSet("terrain", tile->getTerrain()->getJsonKey(), true, false);
@@ -201,11 +202,11 @@ void MapAudioPlayer::update()
 
 MapAudioPlayer::MapAudioPlayer()
 {
-	auto mapSize = LOCPLINT->cb->getMapSize();
+	auto mapSize = GAME->interface()->cb->getMapSize();
 
 	objects.resize(boost::extents[mapSize.z][mapSize.x][mapSize.y]);
 
-	for(const auto & obj : MAPHANDLER->getMap()->objects)
+	for(const auto & obj : GAME->map().getMap()->objects)
 	{
 		if (obj)
 			addObject(obj);

+ 11 - 10
client/adventureMap/TurnTimerWidget.cpp

@@ -14,6 +14,7 @@
 #include "../battle/BattleInterface.h"
 #include "../battle/BattleStacksController.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../media/ISoundPlayer.h"
 #include "../render/Graphics.h"
 #include "../widgets/Images.h"
@@ -40,7 +41,7 @@ TurnTimerWidget::TurnTimerWidget(const Point & position, PlayerColor player)
 	pos.w = 0;
 	pos.h = 0;
 	recActions &= ~DEACTIVATE;
-	const auto & timers = LOCPLINT->cb->getStartInfo()->turnTimerInfo;
+	const auto & timers = GAME->interface()->cb->getStartInfo()->turnTimerInfo;
 
 	backgroundTexture = std::make_shared<CFilledTexture>(ImagePath::builtin("DiBoxBck"), pos); // 1 px smaller on all sides
 
@@ -68,7 +69,7 @@ TurnTimerWidget::TurnTimerWidget(const Point & position, PlayerColor player)
 			playerLabelsUnit[player] = std::make_shared<CLabel>(pos.w / 2, pos.h - 10, FONT_BIG, ETextAlignment::CENTER, graphics->playerColors[player], "");
 		}
 
-		updateTextLabel(player, LOCPLINT->cb->getPlayerTurnTime(player));
+		updateTextLabel(player, GAME->interface()->cb->getPlayerTurnTime(player));
 	}
 	else
 	{
@@ -79,16 +80,16 @@ TurnTimerWidget::TurnTimerWidget(const Point & position, PlayerColor player)
 
 		for(PlayerColor player(0); player < PlayerColor::PLAYER_LIMIT; ++player)
 		{
-			if (LOCPLINT->cb->getStartInfo()->playerInfos.count(player) == 0)
+			if (GAME->interface()->cb->getStartInfo()->playerInfos.count(player) == 0)
 				continue;
 
-			if (!LOCPLINT->cb->getStartInfo()->playerInfos.at(player).isControlledByHuman())
+			if (!GAME->interface()->cb->getStartInfo()->playerInfos.at(player).isControlledByHuman())
 				continue;
 
 			pos.h += 20;
 			playerLabelsMain[player] = std::make_shared<CLabel>(pos.w / 2, pos.h - 10, FONT_BIG, ETextAlignment::CENTER, graphics->playerColors[player], "");
 
-			updateTextLabel(player, LOCPLINT->cb->getPlayerTurnTime(player));
+			updateTextLabel(player, GAME->interface()->cb->getPlayerTurnTime(player));
 		}
 	}
 
@@ -103,7 +104,7 @@ void TurnTimerWidget::show(Canvas & to)
 
 void TurnTimerWidget::updateNotifications(PlayerColor player, int timeMs)
 {
-	if(player != LOCPLINT->playerID)
+	if(player != GAME->interface()->playerID)
 		return;
 
 	int newTimeSeconds = timeMs / 1000;
@@ -124,7 +125,7 @@ static std::string msToString(int timeMs)
 
 void TurnTimerWidget::updateTextLabel(PlayerColor player, const TurnTimerInfo & timer)
 {
-	const auto & timerSettings = LOCPLINT->cb->getStartInfo()->turnTimerInfo;
+	const auto & timerSettings = GAME->interface()->cb->getStartInfo()->turnTimerInfo;
 	auto mainLabel = playerLabelsMain[player];
 
 	if (isBattleMode)
@@ -165,7 +166,7 @@ void TurnTimerWidget::updateTextLabel(PlayerColor player, const TurnTimerInfo &
 
 void TurnTimerWidget::updateTimer(PlayerColor player, uint32_t msPassed)
 {
-	const auto & gamestateTimer = LOCPLINT->cb->getPlayerTurnTime(player);
+	const auto & gamestateTimer = GAME->interface()->cb->getPlayerTurnTime(player);
 	updateNotifications(player, gamestateTimer.valueMs());
 	updateTextLabel(player, gamestateTimer);
 }
@@ -174,9 +175,9 @@ void TurnTimerWidget::tick(uint32_t msPassed)
 {
 	for(const auto & player : playerLabelsMain)
 	{
-		if (LOCPLINT->battleInt)
+		if (GAME->interface()->battleInt)
 		{
-			const auto & battle = LOCPLINT->battleInt->getBattle();
+			const auto & battle = GAME->interface()->battleInt->getBattle();
 
 			bool isDefender = battle->sideToPlayer(BattleSide::DEFENDER) == player.first;
 			bool isAttacker = battle->sideToPlayer(BattleSide::ATTACKER) == player.first;

+ 3 - 2
client/battle/BattleActionsController.cpp

@@ -20,6 +20,7 @@
 #include "../CPlayerInterface.h"
 #include "../gui/CursorHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/CIntObject.h"
 #include "../gui/WindowHandler.h"
 #include "../windows/CCreatureWindow.h"
@@ -261,8 +262,8 @@ void BattleActionsController::reorderPossibleActionsPriority(const CStack * stac
 				if(!stack->hasBonusOfType(BonusType::NO_SPELLCAST_BY_DEFAULT) && targetStack != nullptr)
 				{
 					PlayerColor stackOwner = owner.getBattle()->battleGetOwner(targetStack);
-					bool enemyTargetingPositiveSpellcast = item.spell().toSpell()->isPositive() && stackOwner != LOCPLINT->playerID;
-					bool friendTargetingNegativeSpellcast = item.spell().toSpell()->isNegative() && stackOwner == LOCPLINT->playerID;
+					bool enemyTargetingPositiveSpellcast = item.spell().toSpell()->isPositive() && stackOwner != GAME->interface()->playerID;
+					bool friendTargetingNegativeSpellcast = item.spell().toSpell()->isNegative() && stackOwner == GAME->interface()->playerID;
 
 					if(!enemyTargetingPositiveSpellcast && !friendTargetingNegativeSpellcast)
 						return 1;

+ 2 - 1
client/battle/BattleFieldController.cpp

@@ -27,6 +27,7 @@
 #include "../render/IImage.h"
 #include "../render/IRenderHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/CursorHandler.h"
 #include "../adventureMap/CInGameConsole.h"
 #include "../client/render/CAnimation.h"
@@ -148,7 +149,7 @@ BattleFieldController::BattleFieldController(BattleInterface & owner):
 
 void BattleFieldController::activate()
 {
-	LOCPLINT->cingconsole->pos = this->pos;
+	GAME->interface()->cingconsole->pos = this->pos;
 	CIntObject::activate();
 }
 

+ 2 - 1
client/battle/BattleInterface.cpp

@@ -26,6 +26,7 @@
 #include "../CPlayerInterface.h"
 #include "../gui/CursorHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/WindowHandler.h"
 #include "../media/IMusicPlayer.h"
 #include "../media/ISoundPlayer.h"
@@ -108,7 +109,7 @@ void BattleInterface::playIntroSoundAndUnlockInterface()
 	auto onIntroPlayed = [this]()
 	{
 		// Make sure that battle have not ended while intro was playing AND that a different one has not started
-		if(LOCPLINT->battleInt.get() == this)
+		if(GAME->interface()->battleInt.get() == this)
 			onIntroSoundPlayed();
 	};
 

+ 2 - 1
client/battle/BattleInterfaceClasses.cpp

@@ -21,6 +21,7 @@
 #include "../CPlayerInterface.h"
 #include "../gui/CursorHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../gui/MouseButton.h"
 #include "../gui/WindowHandler.h"
@@ -170,7 +171,7 @@ BattleConsole::BattleConsole(const BattleInterface & owner, std::shared_ptr<CPic
 void BattleConsole::deactivate()
 {
 	if (enteringText)
-		LOCPLINT->cingconsole->endEnteringText(false);
+		GAME->interface()->cingconsole->endEnteringText(false);
 
 	CIntObject::deactivate();
 }

+ 10 - 9
client/battle/BattleWindow.cpp

@@ -19,6 +19,7 @@
 #include "../CPlayerInterface.h"
 #include "../gui/CursorHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../gui/WindowHandler.h"
 #include "../windows/CSpellWindow.h"
@@ -55,8 +56,8 @@ BattleWindow::BattleWindow(BattleInterface & Owner):
 
 	PlayerColor defenderColor = owner.getBattle()->getBattle()->getSidePlayer(BattleSide::DEFENDER);
 	PlayerColor attackerColor = owner.getBattle()->getBattle()->getSidePlayer(BattleSide::ATTACKER);
-	bool isDefenderHuman = defenderColor.isValidPlayer() && LOCPLINT->cb->getStartInfo()->playerInfos.at(defenderColor).isControlledByHuman();
-	bool isAttackerHuman = attackerColor.isValidPlayer() && LOCPLINT->cb->getStartInfo()->playerInfos.at(attackerColor).isControlledByHuman();
+	bool isDefenderHuman = defenderColor.isValidPlayer() && GAME->interface()->cb->getStartInfo()->playerInfos.at(defenderColor).isControlledByHuman();
+	bool isAttackerHuman = attackerColor.isValidPlayer() && GAME->interface()->cb->getStartInfo()->playerInfos.at(attackerColor).isControlledByHuman();
 	onlyOnePlayerHuman = isDefenderHuman != isAttackerHuman;
 
 	REGISTER_BUILDER("battleConsole", &BattleWindow::buildBattleConsole);
@@ -241,7 +242,7 @@ void BattleWindow::createTimerInfoWindows()
 
 	int xOffsetAttacker = quickSpellWindow->isEnabled ? -53 : 0;
 
-	if(LOCPLINT->cb->getStartInfo()->turnTimerInfo.battleTimer != 0 || LOCPLINT->cb->getStartInfo()->turnTimerInfo.unitTimer != 0)
+	if(GAME->interface()->cb->getStartInfo()->turnTimerInfo.battleTimer != 0 || GAME->interface()->cb->getStartInfo()->turnTimerInfo.unitTimer != 0)
 	{
 		PlayerColor attacker = owner.getBattle()->sideToPlayer(BattleSide::ATTACKER);
 		PlayerColor defender = owner.getBattle()->sideToPlayer(BattleSide::DEFENDER);
@@ -458,14 +459,14 @@ void BattleWindow::activate()
 {
 	ENGINE->setStatusbar(console);
 	CIntObject::activate();
-	LOCPLINT->cingconsole->activate();
+	GAME->interface()->cingconsole->activate();
 }
 
 void BattleWindow::deactivate()
 {
 	ENGINE->setStatusbar(nullptr);
 	CIntObject::deactivate();
-	LOCPLINT->cingconsole->deactivate();
+	GAME->interface()->cingconsole->deactivate();
 }
 
 bool BattleWindow::captureThisKey(EShortcut key)
@@ -745,13 +746,13 @@ void BattleWindow::bSpellf()
 			std::string heroName = myHero->hasArt(artID, true) ? myHero->getNameTranslated() : owner.enemyHero().name;
 
 			//%s wields the %s, an ancient artifact which creates a p dead to all magic.
-			LOCPLINT->showInfoDialog(boost::str(boost::format(VLC->generaltexth->allTexts[683])
+			GAME->interface()->showInfoDialog(boost::str(boost::format(VLC->generaltexth->allTexts[683])
 										% heroName % VLC->artifacts()->getByIndex(artID)->getNameTranslated()));
 		}
 		else if(blockingBonus->source == BonusSource::OBJECT_TYPE)
 		{
 			if(blockingBonus->sid.as<MapObjectID>() == Obj::GARRISON || blockingBonus->sid.as<MapObjectID>() == Obj::GARRISON2)
-				LOCPLINT->showInfoDialog(VLC->generaltexth->allTexts[684]);
+				GAME->interface()->showInfoDialog(VLC->generaltexth->allTexts[684]);
 		}
 	}
 	else
@@ -890,7 +891,7 @@ void BattleWindow::endWithAutocombat()
 	if(!owner.makingTurn() || owner.tacticsMode)
 		return;
 
-	LOCPLINT->showYesNoDialog(
+	GAME->interface()->showYesNoDialog(
 		VLC->generaltexth->translate("vcmi.battleWindow.endWithAutocombat"),
 		[this]()
 		{
@@ -929,7 +930,7 @@ void BattleWindow::showAll(Canvas & to)
 void BattleWindow::show(Canvas & to)
 {
 	CIntObject::show(to);
-	LOCPLINT->cingconsole->show(to);
+	GAME->interface()->cingconsole->show(to);
 }
 
 void BattleWindow::close()

+ 2 - 1
client/eventsSDL/InputSourceKeyboard.cpp

@@ -14,6 +14,7 @@
 #include "../../lib/CConfigHandler.h"
 #include "../CPlayerInterface.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/EventDispatcher.h"
 #include "../gui/Shortcut.h"
 #include "../gui/ShortcutHandler.h"
@@ -91,7 +92,7 @@ void InputSourceKeyboard::handleEventKeyDown(const SDL_KeyboardEvent & key)
 	auto shortcutsVector = ENGINE->shortcuts().translateKeycode(keyName);
 
 	if (vstd::contains(shortcutsVector, EShortcut::MAIN_MENU_LOBBY))
-		CSH->getGlobalLobby().activateInterface();
+		GAME->server().getGlobalLobby().activateInterface();
 
 	if (vstd::contains(shortcutsVector, EShortcut::GLOBAL_FULLSCREEN))
 	{

+ 2 - 1
client/eventsSDL/InputSourceTouch.cpp

@@ -16,6 +16,7 @@
 #include "../../lib/CConfigHandler.h"
 #include "../gui/CursorHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/EventDispatcher.h"
 #include "../gui/MouseButton.h"
 #include "../gui/WindowHandler.h"
@@ -157,7 +158,7 @@ void InputSourceTouch::handleEventFingerDown(const SDL_TouchFingerEvent & tfinge
 		}
 		case TouchState::TAP_DOWN_DOUBLE:
 		{
-			CSH->getGlobalLobby().activateInterface();
+			GAME->server().getGlobalLobby().activateInterface();
 			break;
 		}
 		case TouchState::TAP_DOWN_LONG_AWAIT:

+ 3 - 2
client/globalLobby/GlobalLobbyAddChannelWindow.cpp

@@ -15,6 +15,7 @@
 
 #include "../CServerHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../gui/WindowHandler.h"
 #include "../widgets/Buttons.h"
@@ -45,7 +46,7 @@ GlobalLobbyAddChannelWindowCard::GlobalLobbyAddChannelWindowCard(const std::stri
 
 void GlobalLobbyAddChannelWindowCard::clickPressed(const Point & cursorPosition)
 {
-	CSH->getGlobalLobby().addChannel(languageID);
+	GAME->server().getGlobalLobby().addChannel(languageID);
 	ENGINE->windows().popWindows(1);
 }
 
@@ -66,7 +67,7 @@ GlobalLobbyAddChannelWindow::GlobalLobbyAddChannelWindow()
 	const auto & allLanguages = Languages::getLanguageList();
 	std::vector<std::string> newLanguages;
 	for (const auto & language : allLanguages)
-		if (!vstd::contains(CSH->getGlobalLobby().getActiveChannels(), language.identifier))
+		if (!vstd::contains(GAME->server().getGlobalLobby().getActiveChannels(), language.identifier))
 			newLanguages.push_back(language.identifier);
 
 	const auto & createChannelCardCallback = [newLanguages](size_t index) -> std::shared_ptr<CIntObject>

+ 10 - 9
client/globalLobby/GlobalLobbyClient.cpp

@@ -18,6 +18,7 @@
 
 #include "../CServerHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/WindowHandler.h"
 #include "../mainmenu/CMainMenu.h"
 #include "../media/ISoundPlayer.h"
@@ -58,7 +59,7 @@ void GlobalLobbyClient::addChannel(const std::string & channel)
 	toSend["type"].String() = "requestChatHistory";
 	toSend["channelType"].String() = "global";
 	toSend["channelName"].String() = channel;
-	CSH->getGlobalLobby().sendMessage(toSend);
+	GAME->server().getGlobalLobby().sendMessage(toSend);
 
 	Settings languageRooms = settings.write["lobby"]["languageRooms"];
 
@@ -349,15 +350,15 @@ void GlobalLobbyClient::receiveJoinRoomSuccess(const JsonNode & json)
 {
 	if (json["proxyMode"].Bool())
 	{
-		CSH->resetStateForLobby(EStartMode::NEW_GAME, ESelectionScreen::newGame, EServerMode::LOBBY_GUEST, { CSH->getGlobalLobby().getAccountDisplayName() });
-		CSH->loadMode = ELoadMode::MULTI;
+		GAME->server().resetStateForLobby(EStartMode::NEW_GAME, ESelectionScreen::newGame, EServerMode::LOBBY_GUEST, { GAME->server().getGlobalLobby().getAccountDisplayName() });
+		GAME->server().loadMode = ELoadMode::MULTI;
 
 		std::string hostname = getServerHost();
 		uint16_t port = getServerPort();
-		CSH->connectToServer(hostname, port);
+		GAME->server().connectToServer(hostname, port);
 	}
 
-	// NOTE: must be set after CSH->resetStateForLobby call
+	// NOTE: must be set after GAME->server().resetStateForLobby call
 	currentGameRoomUUID = json["gameRoomID"].String();
 }
 
@@ -449,7 +450,7 @@ void GlobalLobbyClient::connect()
 {
 	std::string hostname = getServerHost();
 	uint16_t port = getServerPort();
-	CSH->getNetworkHandler().connectToRemote(*this, hostname, port);
+	GAME->server().getNetworkHandler().connectToRemote(*this, hostname, port);
 }
 
 bool GlobalLobbyClient::isLoggedIn() const
@@ -531,7 +532,7 @@ const std::vector<GlobalLobbyChannelMessage> & GlobalLobbyClient::getChannelHist
 			toSend["type"].String() = "requestChatHistory";
 			toSend["channelType"].String() = channelType;
 			toSend["channelName"].String() = channelName;
-			CSH->getGlobalLobby().sendMessage(toSend);
+			GAME->server().getGlobalLobby().sendMessage(toSend);
 		}
 		return emptyVector;
 	}
@@ -647,7 +648,7 @@ void GlobalLobbyClient::sendMatchChatMessage(const std::string & messageText)
 
 	assert(TextOperations::isValidUnicodeString(messageText));
 
-	CSH->getGlobalLobby().sendMessage(toSend);
+	GAME->server().getGlobalLobby().sendMessage(toSend);
 }
 
 bool GlobalLobbyClient::isInvitedToRoom(const std::string & gameRoomID)
@@ -655,7 +656,7 @@ bool GlobalLobbyClient::isInvitedToRoom(const std::string & gameRoomID)
 	if (activeInvites.count(gameRoomID) > 0)
 		return true;
 
-	const auto & gameRoom = CSH->getGlobalLobby().getActiveRoomByName(gameRoomID);
+	const auto & gameRoom = GAME->server().getGlobalLobby().getActiveRoomByName(gameRoomID);
 	for (auto const & invited : gameRoom.invited)
 	{
 		if (invited.accountID == getAccountID())

+ 6 - 5
client/globalLobby/GlobalLobbyInviteWindow.cpp

@@ -15,6 +15,7 @@
 
 #include "../CServerHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../widgets/Buttons.h"
 #include "../widgets/GraphicalPrimitiveCanvas.h"
@@ -33,10 +34,10 @@ GlobalLobbyInviteAccountCard::GlobalLobbyInviteAccountCard(const GlobalLobbyAcco
 	addUsedEvents(LCLICK);
 
 	bool thisAccountInvited = false;
-	const auto & myRoomID = CSH->getGlobalLobby().getCurrentGameRoomID();
+	const auto & myRoomID = GAME->server().getGlobalLobby().getCurrentGameRoomID();
 	if (!myRoomID.empty())
 	{
-		const auto & myRoom = CSH->getGlobalLobby().getActiveRoomByName(myRoomID);
+		const auto & myRoom = GAME->server().getGlobalLobby().getActiveRoomByName(myRoomID);
 		for (auto const & invited : myRoom.invited)
 		{
 			if (invited.accountID == accountID)
@@ -67,7 +68,7 @@ void GlobalLobbyInviteAccountCard::clickPressed(const Point & cursorPosition)
 	message["type"].String() = "sendInvite";
 	message["accountID"].String() = accountID;
 
-	CSH->getGlobalLobby().sendMessage(message);
+	GAME->server().getGlobalLobby().sendMessage(message);
 }
 
 GlobalLobbyInviteWindow::GlobalLobbyInviteWindow()
@@ -86,7 +87,7 @@ GlobalLobbyInviteWindow::GlobalLobbyInviteWindow()
 
 	const auto & createAccountCardCallback = [](size_t index) -> std::shared_ptr<CIntObject>
 	{
-		const auto & accounts = CSH->getGlobalLobby().getActiveAccounts();
+		const auto & accounts = GAME->server().getGlobalLobby().getActiveAccounts();
 
 		if(index < accounts.size())
 			return std::make_shared<GlobalLobbyInviteAccountCard>(accounts[index]);
@@ -94,7 +95,7 @@ GlobalLobbyInviteWindow::GlobalLobbyInviteWindow()
 	};
 
 	listBackground = std::make_shared<TransparentFilledRectangle>(Rect(8, 48, 220, 324), ColorRGBA(0, 0, 0, 64), ColorRGBA(64, 80, 128, 255), 1);
-	accountList = std::make_shared<CListBox>(createAccountCardCallback, Point(10, 50), Point(0, 40), 8, CSH->getGlobalLobby().getActiveAccounts().size(), 0, 1 | 4, Rect(200, 0, 320, 320));
+	accountList = std::make_shared<CListBox>(createAccountCardCallback, Point(10, 50), Point(0, 40), 8, GAME->server().getGlobalLobby().getActiveAccounts().size(), 0, 1 | 4, Rect(200, 0, 320, 320));
 
 	buttonClose = std::make_shared<CButton>(Point(86, 384), AnimationPath::builtin("MuBchck"), CButton::tooltip(), [this]() { close(); }, EShortcut::GLOBAL_RETURN );
 

+ 9 - 8
client/globalLobby/GlobalLobbyLoginWindow.cpp

@@ -15,6 +15,7 @@
 
 #include "../CServerHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../widgets/Buttons.h"
 #include "../widgets/CTextInput.h"
@@ -38,7 +39,7 @@ GlobalLobbyLoginWindow::GlobalLobbyLoginWindow()
 
 	MetaString loginAs;
 	loginAs.appendTextID("vcmi.lobby.login.as");
-	loginAs.replaceRawString(CSH->getGlobalLobby().getAccountDisplayName());
+	loginAs.replaceRawString(GAME->server().getGlobalLobby().getAccountDisplayName());
 
 	filledBackground = std::make_shared<FilledTexturePlayerColored>(Rect(0, 0, pos.w, pos.h));
 	labelTitle = std::make_shared<CLabel>( pos.w / 2, 20, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW, VLC->generaltexth->translate("vcmi.lobby.login.title"));
@@ -61,7 +62,7 @@ GlobalLobbyLoginWindow::GlobalLobbyLoginWindow()
 	toggleMode->setSelected(settings["lobby"]["roomType"].Integer());
 	toggleMode->addCallback([this](int index){onLoginModeChanged(index);});
 
-	if (CSH->getGlobalLobby().getAccountID().empty())
+	if (GAME->server().getGlobalLobby().getAccountID().empty())
 	{
 		buttonLogin->block(true);
 		toggleMode->setSelected(0);
@@ -110,8 +111,8 @@ void GlobalLobbyLoginWindow::onClose()
 void GlobalLobbyLoginWindow::onLogin()
 {
 	labelStatus->setText(VLC->generaltexth->translate("vcmi.lobby.login.connecting"));
-	if(!CSH->getGlobalLobby().isConnected())
-		CSH->getGlobalLobby().connect();
+	if(!GAME->server().getGlobalLobby().isConnected())
+		GAME->server().getGlobalLobby().connect();
 	else
 		onConnectionSuccess();
 
@@ -121,18 +122,18 @@ void GlobalLobbyLoginWindow::onLogin()
 
 void GlobalLobbyLoginWindow::onConnectionSuccess()
 {
-	std::string accountID = CSH->getGlobalLobby().getAccountID();
+	std::string accountID = GAME->server().getGlobalLobby().getAccountID();
 
 	if(toggleMode->getSelected() == 0)
-		CSH->getGlobalLobby().sendClientRegister(inputUsername->getText());
+		GAME->server().getGlobalLobby().sendClientRegister(inputUsername->getText());
 	else
-		CSH->getGlobalLobby().sendClientLogin();
+		GAME->server().getGlobalLobby().sendClientLogin();
 }
 
 void GlobalLobbyLoginWindow::onLoginSuccess()
 {
 	close();
-	CSH->getGlobalLobby().activateInterface();
+	GAME->server().getGlobalLobby().activateInterface();
 }
 
 void GlobalLobbyLoginWindow::onConnectionFailed(const std::string & reason)

+ 4 - 3
client/globalLobby/GlobalLobbyRoomWindow.cpp

@@ -17,6 +17,7 @@
 
 #include "../CServerHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../mainmenu/CMainMenu.h"
 #include "../widgets/Buttons.h"
@@ -71,8 +72,8 @@ static std::string getJoinRoomErrorMessage(const GlobalLobbyRoom & roomDescripti
 	bool publicRoom = roomDescription.statusID == "public";
 	bool privateRoom = roomDescription.statusID == "private";
 	bool gameStarted = !publicRoom && !privateRoom;
-	bool hasInvite = CSH->getGlobalLobby().isInvitedToRoom(roomDescription.gameRoomID);
-	bool alreadyInRoom = CSH->inGame();
+	bool hasInvite = GAME->server().getGlobalLobby().isInvitedToRoom(roomDescription.gameRoomID);
+	bool alreadyInRoom = GAME->server().inGame();
 
 	if (alreadyInRoom)
 		return "vcmi.lobby.preview.error.playing";
@@ -122,7 +123,7 @@ GlobalLobbyRoomWindow::GlobalLobbyRoomWindow(GlobalLobbyWindow * window, const s
 	pos.w = 400;
 	pos.h = 400;
 
-	GlobalLobbyRoom roomDescription = CSH->getGlobalLobby().getActiveRoomByName(roomUUID);
+	GlobalLobbyRoom roomDescription = GAME->server().getGlobalLobby().getActiveRoomByName(roomUUID);
 	for(const auto & modEntry : ModVerificationInfo::verifyListAgainstLocalMods(roomDescription.modList))
 	{
 		GlobalLobbyRoomModInfo modInfo;

+ 5 - 4
client/globalLobby/GlobalLobbyServerSetup.cpp

@@ -15,6 +15,7 @@
 
 #include "../CServerHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../mainmenu/CMainMenu.h"
 #include "../widgets/Buttons.h"
@@ -128,12 +129,12 @@ void GlobalLobbyServerSetup::onGameModeChanged(int value)
 void GlobalLobbyServerSetup::onCreate()
 {
 	if(toggleGameMode->getSelected() == 0)
-		CSH->resetStateForLobby(EStartMode::NEW_GAME, ESelectionScreen::newGame, EServerMode::LOBBY_HOST, { CSH->getGlobalLobby().getAccountDisplayName() });
+		GAME->server().resetStateForLobby(EStartMode::NEW_GAME, ESelectionScreen::newGame, EServerMode::LOBBY_HOST, { GAME->server().getGlobalLobby().getAccountDisplayName() });
 	else
-		CSH->resetStateForLobby(EStartMode::LOAD_GAME, ESelectionScreen::loadGame, EServerMode::LOBBY_HOST, { CSH->getGlobalLobby().getAccountDisplayName() });
+		GAME->server().resetStateForLobby(EStartMode::LOAD_GAME, ESelectionScreen::loadGame, EServerMode::LOBBY_HOST, { GAME->server().getGlobalLobby().getAccountDisplayName() });
 
-	CSH->loadMode = ELoadMode::MULTI;
-	CSH->startLocalServerAndConnect(true);
+	GAME->server().loadMode = ELoadMode::MULTI;
+	GAME->server().startLocalServerAndConnect(true);
 
 	buttonCreate->block(true);
 	buttonClose->block(true);

+ 10 - 9
client/globalLobby/GlobalLobbyWidget.cpp

@@ -18,6 +18,7 @@
 
 #include "../CServerHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/WindowHandler.h"
 #include "../media/ISoundPlayer.h"
 #include "../render/Colors.h"
@@ -39,7 +40,7 @@ GlobalLobbyWidget::GlobalLobbyWidget(GlobalLobbyWindow * window)
 {
 	addCallback("closeWindow", [](int) { ENGINE->windows().popWindows(1); });
 	addCallback("sendMessage", [this](int) { this->window->doSendChatMessage(); });
-	addCallback("createGameRoom", [this](int) { if (!CSH->inGame()) this->window->doCreateGameRoom(); });//TODO: button should be blocked instead
+	addCallback("createGameRoom", [this](int) { if (!GAME->server().inGame()) this->window->doCreateGameRoom(); });//TODO: button should be blocked instead
 
 	REGISTER_BUILDER("lobbyItemList", &GlobalLobbyWidget::buildItemList);
 
@@ -51,7 +52,7 @@ GlobalLobbyWidget::CreateFunc GlobalLobbyWidget::getItemListConstructorFunc(cons
 {
 	const auto & createAccountCardCallback = [this](size_t index) -> std::shared_ptr<CIntObject>
 	{
-		const auto & accounts = CSH->getGlobalLobby().getActiveAccounts();
+		const auto & accounts = GAME->server().getGlobalLobby().getActiveAccounts();
 
 		if(index < accounts.size())
 			return std::make_shared<GlobalLobbyAccountCard>(this->window, accounts[index]);
@@ -60,7 +61,7 @@ GlobalLobbyWidget::CreateFunc GlobalLobbyWidget::getItemListConstructorFunc(cons
 
 	const auto & createRoomCardCallback = [this](size_t index) -> std::shared_ptr<CIntObject>
 	{
-		const auto & rooms = CSH->getGlobalLobby().getActiveRooms();
+		const auto & rooms = GAME->server().getGlobalLobby().getActiveRooms();
 
 		if(index < rooms.size())
 			return std::make_shared<GlobalLobbyRoomCard>(this->window, rooms[index]);
@@ -69,7 +70,7 @@ GlobalLobbyWidget::CreateFunc GlobalLobbyWidget::getItemListConstructorFunc(cons
 
 	const auto & createChannelCardCallback = [this](size_t index) -> std::shared_ptr<CIntObject>
 	{
-		const auto & channels = CSH->getGlobalLobby().getActiveChannels();
+		const auto & channels = GAME->server().getGlobalLobby().getActiveChannels();
 
 		if(index < channels.size())
 			return std::make_shared<GlobalLobbyChannelCard>(this->window, channels[index]);
@@ -90,7 +91,7 @@ GlobalLobbyWidget::CreateFunc GlobalLobbyWidget::getItemListConstructorFunc(cons
 
 	const auto & createMatchCardCallback = [this](size_t index) -> std::shared_ptr<CIntObject>
 	{
-		const auto & matches = CSH->getGlobalLobby().getMatchesHistory();
+		const auto & matches = GAME->server().getGlobalLobby().getMatchesHistory();
 
 		if(index < matches.size())
 			return std::make_shared<GlobalLobbyMatchCard>(this->window, matches[index]);
@@ -240,7 +241,7 @@ GlobalLobbyRoomCard::GlobalLobbyRoomCard(GlobalLobbyWindow * window, const Globa
 	OBJECT_CONSTRUCTION;
 	addUsedEvents(LCLICK);
 
-	bool hasInvite = CSH->getGlobalLobby().isInvitedToRoom(roomDescription.gameRoomID);
+	bool hasInvite = GAME->server().getGlobalLobby().isInvitedToRoom(roomDescription.gameRoomID);
 
 	auto roomSizeText = MetaString::createFromRawString("%d/%d");
 	roomSizeText.replaceNumber(roomDescription.participants.size());
@@ -278,10 +279,10 @@ GlobalLobbyChannelCard::GlobalLobbyChannelCard(GlobalLobbyWindow * window, const
 	OBJECT_CONSTRUCTION;
 	labelName = std::make_shared<CLabel>(5, 20, FONT_SMALL, ETextAlignment::CENTERLEFT, Colors::WHITE, Languages::getLanguageOptions(channelName).nameNative);
 
-	if (CSH->getGlobalLobby().getActiveChannels().size() > 1)
+	if (GAME->server().getGlobalLobby().getActiveChannels().size() > 1)
 	{
 		pos.w = 110;
-		buttonClose = std::make_shared<CButton>(Point(113, 7), AnimationPath::builtin("lobbyCloseChannel"), CButton::tooltip(), [channelName](){CSH->getGlobalLobby().closeChannel(channelName);});
+		buttonClose = std::make_shared<CButton>(Point(113, 7), AnimationPath::builtin("lobbyCloseChannel"), CButton::tooltip(), [channelName](){GAME->server().getGlobalLobby().closeChannel(channelName);});
 		buttonClose->setOverlay(std::make_shared<CPicture>(ImagePath::builtin("lobby/closeChannel")));
 	}
 }
@@ -299,7 +300,7 @@ GlobalLobbyMatchCard::GlobalLobbyMatchCard(GlobalLobbyWindow * window, const Glo
 
 	if (matchDescription.participants.size() == 2)
 	{
-		std::string ourAccountID = CSH->getGlobalLobby().getAccountID();
+		std::string ourAccountID = GAME->server().getGlobalLobby().getAccountID();
 
 		opponentDescription.appendTextID("vcmi.lobby.match.duel");
 		// Find display name of our one and only opponent in this game

+ 8 - 7
client/globalLobby/GlobalLobbyWindow.cpp

@@ -17,6 +17,7 @@
 
 #include "../CServerHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/WindowHandler.h"
 #include "../widgets/CTextInput.h"
 #include "../widgets/Slider.h"
@@ -35,11 +36,11 @@ GlobalLobbyWindow::GlobalLobbyWindow()
 	pos = widget->pos;
 	center();
 
-	widget->getAccountNameLabel()->setText(CSH->getGlobalLobby().getAccountDisplayName());
+	widget->getAccountNameLabel()->setText(GAME->server().getGlobalLobby().getAccountDisplayName());
 	doOpenChannel("global", "english", Languages::getLanguageOptions("english").nameNative);
 
 	widget->getChannelListHeader()->setText(MetaString::createFromTextID("vcmi.lobby.header.channels").toString());
-	widget->getChannelList()->resize(CSH->getGlobalLobby().getActiveChannels().size()+1);
+	widget->getChannelList()->resize(GAME->server().getGlobalLobby().getActiveChannels().size()+1);
 }
 
 bool GlobalLobbyWindow::isChannelOpen(const std::string & testChannelType, const std::string & testChannelName) const
@@ -54,7 +55,7 @@ void GlobalLobbyWindow::doOpenChannel(const std::string & channelType, const std
 	chatHistory.clear();
 	unreadChannels.erase(channelType + "_" + channelName);
 
-	auto history = CSH->getGlobalLobby().getChannelHistory(channelType, channelName);
+	auto history = GAME->server().getGlobalLobby().getChannelHistory(channelType, channelName);
 
 	for(const auto & entry : history)
 		onGameChatMessage(entry.displayName, entry.messageText, entry.timeFormatted, channelType, channelName);
@@ -87,7 +88,7 @@ void GlobalLobbyWindow::doSendChatMessage()
 
 	assert(TextOperations::isValidUnicodeString(messageText));
 
-	CSH->getGlobalLobby().sendMessage(toSend);
+	GAME->server().getGlobalLobby().sendMessage(toSend);
 
 	widget->getMessageInput()->setText("");
 }
@@ -103,7 +104,7 @@ void GlobalLobbyWindow::doInviteAccount(const std::string & accountID)
 	toSend["type"].String() = "sendInvite";
 	toSend["accountID"].String() = accountID;
 
-	CSH->getGlobalLobby().sendMessage(toSend);
+	GAME->server().getGlobalLobby().sendMessage(toSend);
 }
 
 void GlobalLobbyWindow::doJoinRoom(const std::string & roomID)
@@ -112,7 +113,7 @@ void GlobalLobbyWindow::doJoinRoom(const std::string & roomID)
 	toSend["type"].String() = "joinGameRoom";
 	toSend["gameRoomID"].String() = roomID;
 
-	CSH->getGlobalLobby().sendMessage(toSend);
+	GAME->server().getGlobalLobby().sendMessage(toSend);
 }
 
 void GlobalLobbyWindow::onGameChatMessage(const std::string & sender, const std::string & message, const std::string & when, const std::string & channelType, const std::string & channelName)
@@ -185,7 +186,7 @@ void GlobalLobbyWindow::onMatchesHistory(const std::vector<GlobalLobbyRoom> & hi
 
 void GlobalLobbyWindow::refreshActiveChannels()
 {
-	const auto & activeChannels = CSH->getGlobalLobby().getActiveChannels();
+	const auto & activeChannels = GAME->server().getGlobalLobby().getActiveChannels();
 
 	if (activeChannels.size()+1 == widget->getChannelList()->size())
 		widget->getChannelList()->reset();

+ 11 - 9
client/gui/CursorHandler.cpp

@@ -41,25 +41,27 @@ CursorHandler::CursorHandler()
 	, frameTime(0.f)
 	, showing(false)
 	, pos(0,0)
+	, dndObject(nullptr)
+	, type(Cursor::Type::DEFAULT)
 {
+	showType = dynamic_cast<CursorSoftware *>(cursor.get()) ? Cursor::ShowType::SOFTWARE : Cursor::ShowType::HARDWARE;
+}
 
-	type = Cursor::Type::DEFAULT;
-	dndObject = nullptr;
+CursorHandler::~CursorHandler() = default;
 
+void CursorHandler::init()
+{
 	cursors =
 	{
-		ENGINE->renderHandler().loadAnimation(AnimationPath::builtin("CRADVNTR"), EImageBlitMode::COLORKEY),
-		ENGINE->renderHandler().loadAnimation(AnimationPath::builtin("CRCOMBAT"), EImageBlitMode::COLORKEY),
-		ENGINE->renderHandler().loadAnimation(AnimationPath::builtin("CRDEFLT"), EImageBlitMode::COLORKEY),
-		ENGINE->renderHandler().loadAnimation(AnimationPath::builtin("CRSPELL"), EImageBlitMode::COLORKEY)
+			ENGINE->renderHandler().loadAnimation(AnimationPath::builtin("CRADVNTR"), EImageBlitMode::COLORKEY),
+			ENGINE->renderHandler().loadAnimation(AnimationPath::builtin("CRCOMBAT"), EImageBlitMode::COLORKEY),
+			ENGINE->renderHandler().loadAnimation(AnimationPath::builtin("CRDEFLT"), EImageBlitMode::COLORKEY),
+			ENGINE->renderHandler().loadAnimation(AnimationPath::builtin("CRSPELL"), EImageBlitMode::COLORKEY)
 	};
 
 	set(Cursor::Map::POINTER);
-	showType = dynamic_cast<CursorSoftware *>(cursor.get()) ? Cursor::ShowType::SOFTWARE : Cursor::ShowType::HARDWARE;
 }
 
-CursorHandler::~CursorHandler() = default;
-
 void CursorHandler::changeGraphic(Cursor::Type type, size_t index)
 {
 	assert(dndObject == nullptr);

+ 2 - 0
client/gui/CursorHandler.h

@@ -145,6 +145,8 @@ public:
 	CursorHandler();
 	~CursorHandler();
 
+	void init();
+
 	/// Replaces the cursor with a custom image.
 	/// @param image Image to replace cursor with or nullptr to use the normal cursor.
 	void dragAndDropCursor(std::shared_ptr<IImage> image);

+ 3 - 2
client/gui/InterfaceObjectConfigurable.cpp

@@ -14,6 +14,7 @@
 
 #include "../CPlayerInterface.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/ShortcutHandler.h"
 #include "../gui/Shortcut.h"
 #include "../render/Graphics.h"
@@ -333,8 +334,8 @@ std::shared_ptr<CPicture> InterfaceObjectConfigurable::buildPicture(const JsonNo
 	auto position = readPosition(config["position"]);
 	auto pic = std::make_shared<CPicture>(image, position.x, position.y);
 
-	if ( config["playerColored"].Bool() && LOCPLINT)
-		pic->setPlayerColor(LOCPLINT->playerID);
+	if ( config["playerColored"].Bool() && GAME->interface())
+		pic->setPlayerColor(GAME->interface()->playerID);
 	return pic;
 }
 

+ 40 - 39
client/lobby/CBonusSelection.cpp

@@ -35,6 +35,7 @@
 #include "../render/CAnimation.h"
 #include "../render/Graphics.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../gui/WindowHandler.h"
 #include "../adventureMap/AdventureMapInterface.h"
@@ -61,7 +62,7 @@
 
 std::shared_ptr<CampaignState> CBonusSelection::getCampaign()
 {
-	return CSH->si->campState;
+	return GAME->server().si->campState;
 }
 
 CBonusSelection::CBonusSelection()
@@ -76,7 +77,7 @@ CBonusSelection::CBonusSelection()
 	const auto & playVideo = [this]()
 	{
 		ENGINE->windows().createAndPushWindow<CPrologEpilogVideo>(
-			getCampaign()->scenario(CSH->campaignMap).prolog,
+			getCampaign()->scenario(GAME->server().campaignMap).prolog,
 			[this]() { redraw(); } );
 	};
 
@@ -87,21 +88,21 @@ CBonusSelection::CBonusSelection()
 	buttonVideo = std::make_shared<CButton>(Point(705, 214), AnimationPath::builtin("CBVIDEB.DEF"), CButton::tooltip(), playVideo, EShortcut::LOBBY_REPLAY_VIDEO);
 	buttonBack = std::make_shared<CButton>(Point(624, 536), AnimationPath::builtin("CBCANCB.DEF"), CButton::tooltip(), std::bind(&CBonusSelection::goBack, this), EShortcut::GLOBAL_CANCEL);
 
-	campaignName = std::make_shared<CLabel>(481, 28, FONT_BIG, ETextAlignment::TOPLEFT, Colors::YELLOW, CSH->si->getCampaignName(), 250);
+	campaignName = std::make_shared<CLabel>(481, 28, FONT_BIG, ETextAlignment::TOPLEFT, Colors::YELLOW, GAME->server().si->getCampaignName(), 250);
 
 	iconsMapSizes = std::make_shared<CAnimImage>(AnimationPath::builtin("SCNRMPSZ"), 4, 0, 735, 26);
 
 	labelCampaignDescription = std::make_shared<CLabel>(481, 63, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::YELLOW, VLC->generaltexth->allTexts[38]);
 	campaignDescription = std::make_shared<CTextBox>(getCampaign()->getDescriptionTranslated(), Rect(480, 86, 286, 117), 1);
 
-	bool videoButtonActive = CSH->getState() == EClientState::GAMEPLAY;
+	bool videoButtonActive = GAME->server().getState() == EClientState::GAMEPLAY;
 	int availableSpace = videoButtonActive ? 225 : 285;
-	mapName = std::make_shared<CLabel>(481, 219, FONT_BIG, ETextAlignment::TOPLEFT, Colors::YELLOW, CSH->mi->getNameTranslated(), availableSpace );
+	mapName = std::make_shared<CLabel>(481, 219, FONT_BIG, ETextAlignment::TOPLEFT, Colors::YELLOW, GAME->server().mi->getNameTranslated(), availableSpace );
 	labelMapDescription = std::make_shared<CLabel>(481, 253, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::YELLOW, VLC->generaltexth->allTexts[496]);
 	mapDescription = std::make_shared<CTextBox>("", Rect(480, 278, 286, 108), 1);
 
 	labelChooseBonus = std::make_shared<CLabel>(475, 432, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, VLC->generaltexth->allTexts[71]);
-	groupBonuses = std::make_shared<CToggleGroup>(std::bind(&IServerAPI::setCampaignBonus, CSH, _1));
+	groupBonuses = std::make_shared<CToggleGroup>(std::bind(&IServerAPI::setCampaignBonus, &GAME->server(), _1));
 
 	flagbox = std::make_shared<CFlagBox>(Rect(486, 407, 335, 23));
 
@@ -138,7 +139,7 @@ CBonusSelection::CBonusSelection()
 	if (!getCampaign()->getMusic().empty())
 		ENGINE->music().playMusic( getCampaign()->getMusic(), true, false);
 
-	if(CSH->getState() != EClientState::GAMEPLAY && settings["general"]["enableUiEnhancements"].Bool())
+	if(GAME->server().getState() != EClientState::GAMEPLAY && settings["general"]["enableUiEnhancements"].Bool())
 	{
 		tabExtraOptions = std::make_shared<ExtraOptionsTab>();
 		tabExtraOptions->recActions = UPDATE | SHOWALL | LCLICK | RCLICK_POPUP;
@@ -152,9 +153,9 @@ CBonusSelection::CBonusSelection()
 void CBonusSelection::createBonusesIcons()
 {
 	OBJECT_CONSTRUCTION;
-	const CampaignScenario & scenario = getCampaign()->scenario(CSH->campaignMap);
+	const CampaignScenario & scenario = getCampaign()->scenario(GAME->server().campaignMap);
 	const std::vector<CampaignBonus> & bonDescs = scenario.travelOptions.bonusesToChoose;
-	groupBonuses = std::make_shared<CToggleGroup>(std::bind(&IServerAPI::setCampaignBonus, CSH, _1));
+	groupBonuses = std::make_shared<CToggleGroup>(std::bind(&IServerAPI::setCampaignBonus, &GAME->server(), _1));
 
 	constexpr std::array bonusPics =
 	{
@@ -193,7 +194,7 @@ void CBonusSelection::createBonusesIcons()
 		case CampaignBonusType::BUILDING:
 		{
 			FactionID faction;
-			for(auto & elem : CSH->si->playerInfos)
+			for(auto & elem : GAME->server().si->playerInfos)
 			{
 				if(elem.second.isControlledByHuman())
 				{
@@ -328,18 +329,18 @@ void CBonusSelection::createBonusesIcons()
 		else
 			bonusButton->setOverlay(std::make_shared<CPicture>(ImagePath::builtin(picName)));
 
-		if(CSH->campaignBonus == i)
+		if(GAME->server().campaignBonus == i)
 			bonusButton->setBorderColor(Colors::BRIGHT_YELLOW);
 		groupBonuses->addToggle(i, bonusButton);
 	}
 
-	if(getCampaign()->getBonusID(CSH->campaignMap))
-		groupBonuses->setSelected(*getCampaign()->getBonusID(CSH->campaignMap));
+	if(getCampaign()->getBonusID(GAME->server().campaignMap))
+		groupBonuses->setSelected(*getCampaign()->getBonusID(GAME->server().campaignMap));
 }
 
 void CBonusSelection::updateAfterStateChange()
 {
-	if(CSH->getState() != EClientState::GAMEPLAY)
+	if(GAME->server().getState() != EClientState::GAMEPLAY)
 	{
 		buttonRestart->disable();
 		buttonVideo->disable();
@@ -357,9 +358,9 @@ void CBonusSelection::updateAfterStateChange()
 		if(buttonDifficultyRight)
 			buttonDifficultyRight->disable();
 	}
-	if(CSH->campaignBonus == -1)
+	if(GAME->server().campaignBonus == -1)
 	{
-		buttonStart->block(getCampaign()->scenario(CSH->campaignMap).travelOptions.bonusesToChoose.size());
+		buttonStart->block(getCampaign()->scenario(GAME->server().campaignMap).travelOptions.bonusesToChoose.size());
 	}
 	else
 	{
@@ -369,14 +370,14 @@ void CBonusSelection::updateAfterStateChange()
 	for(auto region : regions)
 		region->updateState();
 
-	if(!CSH->mi)
+	if(!GAME->server().mi)
 		return;
-	iconsMapSizes->setFrame(CSH->mi->getMapSizeIconId());
-	mapName->setText(CSH->mi->getNameTranslated());
-	mapDescription->setText(CSH->mi->getDescriptionTranslated());
+	iconsMapSizes->setFrame(GAME->server().mi->getMapSizeIconId());
+	mapName->setText(GAME->server().mi->getNameTranslated());
+	mapDescription->setText(GAME->server().mi->getDescriptionTranslated());
 	for(size_t i = 0; i < difficultyIcons.size(); i++)
 	{
-		if(i == CSH->si->difficulty)
+		if(i == GAME->server().si->difficulty)
 		{
 			difficultyIcons[i]->enable();
 			difficultyIconAreas[i]->enable();
@@ -394,7 +395,7 @@ void CBonusSelection::updateAfterStateChange()
 
 void CBonusSelection::goBack()
 {
-	if(CSH->getState() != EClientState::GAMEPLAY)
+	if(GAME->server().getState() != EClientState::GAMEPLAY)
 	{
 		ENGINE->windows().popWindows(2);
 		CMM->playMusic();
@@ -411,25 +412,25 @@ void CBonusSelection::goBack()
 	else
 	{
 		close();
-		CSH->state = EClientState::LOBBY;
+		GAME->server().state = EClientState::LOBBY;
 	}
 */
 }
 
 void CBonusSelection::startMap()
 {
-	if (!CSH->validateGameStart())
+	if (!GAME->server().validateGameStart())
 		return;
 
 	auto showPrologVideo = [=]()
 	{
 		auto exitCb = [=]()
 		{
-			logGlobal->info("Starting scenario %d", static_cast<int>(CSH->campaignMap));
-			CSH->sendStartGame();
+			logGlobal->info("Starting scenario %d", static_cast<int>(GAME->server().campaignMap));
+			GAME->server().sendStartGame();
 		};
 
-		const CampaignScenario & scenario = getCampaign()->scenario(CSH->campaignMap);
+		const CampaignScenario & scenario = getCampaign()->scenario(GAME->server().campaignMap);
 		if(scenario.prolog.hasPrologEpilog)
 		{
 			ENGINE->windows().createAndPushWindow<CPrologEpilogVideo>(scenario.prolog, exitCb);
@@ -446,10 +447,10 @@ void CBonusSelection::startMap()
 	buttonVideo->block(true);
 	buttonBack->block(true);
 
-	if(LOCPLINT) // we're currently ingame, so ask for starting new map and end game
+	if(GAME->interface()) // we're currently ingame, so ask for starting new map and end game
 	{
 		close();
-		LOCPLINT->showYesNoDialog(VLC->generaltexth->allTexts[67], [=]()
+		GAME->interface()->showYesNoDialog(VLC->generaltexth->allTexts[67], [=]()
 		{
 			showPrologVideo();
 		}, 0);
@@ -463,14 +464,14 @@ void CBonusSelection::startMap()
 void CBonusSelection::restartMap()
 {
 	close();
-	LOCPLINT->showYesNoDialog(
+	GAME->interface()->showYesNoDialog(
 		VLC->generaltexth->allTexts[67],
 		[=]()
 		{
 			ENGINE->dispatchMainThread(
 				[]()
 				{
-					CSH->sendRestartGame();
+					GAME->server().sendRestartGame();
 				}
 			);
 		},
@@ -480,14 +481,14 @@ void CBonusSelection::restartMap()
 
 void CBonusSelection::increaseDifficulty()
 {
-	CSH->setDifficulty(CSH->si->difficulty + 1);
+	GAME->server().setDifficulty(GAME->server().si->difficulty + 1);
 }
 
 void CBonusSelection::decreaseDifficulty()
 {
 	// avoid negative overflow (0 - 1 = 255)
-	if (CSH->si->difficulty > 0)
-		CSH->setDifficulty(CSH->si->difficulty - 1);
+	if (GAME->server().si->difficulty > 0)
+		GAME->server().setDifficulty(GAME->server().si->difficulty - 1);
 }
 
 CBonusSelection::CRegion::CRegion(CampaignScenarioID id, bool accessible, bool selectable, bool labelOnly, const CampaignRegions & campDsc)
@@ -497,7 +498,7 @@ CBonusSelection::CRegion::CRegion(CampaignScenarioID id, bool accessible, bool s
 
 	pos += campDsc.getPosition(id);
 
-	auto color = CSH->si->campState->scenario(idOfMapAndRegion).regionColor;
+	auto color = GAME->server().si->campState->scenario(idOfMapAndRegion).regionColor;
 
 	graphicsNotSelected = std::make_shared<CPicture>(campDsc.getAvailableName(id, color));
 	graphicsNotSelected->disable();
@@ -511,7 +512,7 @@ CBonusSelection::CRegion::CRegion(CampaignScenarioID id, bool accessible, bool s
 	auto labelPos = campDsc.getLabelPosition(id);
 	if(labelPos)
 	{
-		auto mapHeader = CSH->si->campState->getMapHeader(idOfMapAndRegion);
+		auto mapHeader = GAME->server().si->campState->getMapHeader(idOfMapAndRegion);
 		label = std::make_shared<CLabel>((*labelPos).x, (*labelPos).y, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, mapHeader->name.toString());
 	}
 }
@@ -533,7 +534,7 @@ void CBonusSelection::CRegion::updateState(bool disableAll)
 		graphicsSelected->disable();
 		graphicsStriped->enable();
 	}
-	else if(CSH->campaignMap == idOfMapAndRegion)
+	else if(GAME->server().campaignMap == idOfMapAndRegion)
 	{
 		graphicsNotSelected->disable();
 		graphicsSelected->enable();
@@ -574,14 +575,14 @@ void CBonusSelection::CRegion::clickReleased(const Point & cursorPosition)
 {
 	if(!labelOnly && selectable && !graphicsNotSelected->getSurface()->isTransparent(cursorPosition - pos.topLeft()))
 	{
-		CSH->setCampaignMap(idOfMapAndRegion);
+		GAME->server().setCampaignMap(idOfMapAndRegion);
 	}
 }
 
 void CBonusSelection::CRegion::showPopupWindow(const Point & cursorPosition)
 {
 	// FIXME: For some reason "down" is only ever contain indeterminate_value
-	auto & text = CSH->si->campState->scenario(idOfMapAndRegion).regionText;
+	auto & text = GAME->server().si->campState->scenario(idOfMapAndRegion).regionText;
 	if(!labelOnly && !graphicsNotSelected->getSurface()->isTransparent(cursorPosition - pos.topLeft()) && !text.empty())
 	{
 		CRClickPopup::createAndPush(text.toString());

+ 3 - 2
client/lobby/CCampaignInfoScreen.cpp

@@ -17,14 +17,15 @@
 #include "../../lib/mapping/CMapInfo.h"
 #include "../../lib/mapping/CMapHeader.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../CPlayerInterface.h"
 
 CCampaignInfoScreen::CCampaignInfoScreen()
 {
 	OBJECT_CONSTRUCTION;
-	localSi = new StartInfo(*LOCPLINT->cb->getStartInfo());
+	localSi = new StartInfo(*GAME->interface()->cb->getStartInfo());
 	localMi = new CMapInfo();
-	localMi->mapHeader = std::unique_ptr<CMapHeader>(new CMapHeader(*LOCPLINT->cb->getMapHeader()));
+	localMi->mapHeader = std::unique_ptr<CMapHeader>(new CMapHeader(*GAME->interface()->cb->getMapHeader()));
 
 	screenType = ESelectionScreen::scenarioInfo;
 

+ 37 - 36
client/lobby/CLobbyScreen.cpp

@@ -19,6 +19,7 @@
 
 #include "../CServerHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../widgets/Buttons.h"
 #include "../widgets/GraphicalPrimitiveCanvas.h"
@@ -45,14 +46,14 @@ CLobbyScreen::CLobbyScreen(ESelectionScreen screenType, bool hideScreen)
 
 	auto initLobby = [&]()
 	{
-		tabSel->callOnSelect = std::bind(&IServerAPI::setMapInfo, CSH, _1, nullptr);
+		tabSel->callOnSelect = std::bind(&IServerAPI::setMapInfo, &GAME->server(), _1, nullptr);
 
 		buttonSelect = std::make_shared<CButton>(Point(411, 80), AnimationPath::builtin("GSPBUTT.DEF"), VLC->generaltexth->zelp[45], 0, EShortcut::LOBBY_SELECT_SCENARIO);
 		buttonSelect->addCallback([=]()
 		{
 			toggleTab(tabSel);
 			if (getMapInfo() && getMapInfo()->isRandomMap)
-				CSH->setMapInfo(tabSel->getSelectedMapInfo());
+				GAME->server().setMapInfo(tabSel->getSelectedMapInfo());
 		});
 
 		buttonOptions = std::make_shared<CButton>(Point(411, 510), AnimationPath::builtin("GSPBUTT.DEF"), VLC->generaltexth->zelp[46], std::bind(&CLobbyScreen::toggleTab, this, tabOpt), EShortcut::LOBBY_ADDITIONAL_OPTIONS);
@@ -74,7 +75,7 @@ CLobbyScreen::CLobbyScreen(ESelectionScreen screenType, bool hideScreen)
 		tabTurnOptions = std::make_shared<TurnOptionsTab>();
 		tabExtraOptions = std::make_shared<ExtraOptionsTab>();
 		tabRand = std::make_shared<RandomMapTab>();
-		tabRand->mapInfoChanged += std::bind(&IServerAPI::setMapInfo, CSH, _1, _2);
+		tabRand->mapInfoChanged += std::bind(&IServerAPI::setMapInfo, &GAME->server(), _1, _2);
 		buttonRMG = std::make_shared<CButton>(Point(411, 105), AnimationPath::builtin("GSPBUTT.DEF"), VLC->generaltexth->zelp[47], 0, EShortcut::LOBBY_RANDOM_MAP);
 		buttonRMG->addCallback([this]()
 		{
@@ -83,7 +84,7 @@ CLobbyScreen::CLobbyScreen(ESelectionScreen screenType, bool hideScreen)
 				tabRand->updateMapInfoByHost();
 		});
 
-		card->iconDifficulty->addCallback(std::bind(&IServerAPI::setDifficulty, CSH, _1));
+		card->iconDifficulty->addCallback(std::bind(&IServerAPI::setDifficulty, &GAME->server(), _1));
 
 		buttonStart = std::make_shared<CButton>(Point(411, 535), AnimationPath::builtin("SCNRBEG.DEF"), VLC->generaltexth->zelp[103], std::bind(&CLobbyScreen::startScenario, this, false), EShortcut::LOBBY_BEGIN_STANDARD_GAME);
 		initLobby();
@@ -99,7 +100,7 @@ CLobbyScreen::CLobbyScreen(ESelectionScreen screenType, bool hideScreen)
 		break;
 	}
 	case ESelectionScreen::campaignList:
-		tabSel->callOnSelect = std::bind(&IServerAPI::setMapInfo, CSH, _1, nullptr);
+		tabSel->callOnSelect = std::bind(&IServerAPI::setMapInfo, &GAME->server(), _1, nullptr);
 		buttonStart = std::make_shared<CButton>(Point(411, 535), AnimationPath::builtin("SCNRLOD.DEF"), CButton::tooltip(), std::bind(&CLobbyScreen::startCampaign, this), EShortcut::LOBBY_BEGIN_CAMPAIGN);
 		break;
 	}
@@ -108,12 +109,12 @@ CLobbyScreen::CLobbyScreen(ESelectionScreen screenType, bool hideScreen)
 
 	buttonBack = std::make_shared<CButton>(Point(581, 535), AnimationPath::builtin("SCNRBACK.DEF"), VLC->generaltexth->zelp[105], [&]()
 	{
-		bool wasInLobbyRoom = CSH->inLobbyRoom();
-		CSH->sendClientDisconnecting();
+		bool wasInLobbyRoom = GAME->server().inLobbyRoom();
+		GAME->server().sendClientDisconnecting();
 		close();
 
 		if (wasInLobbyRoom)
-			CSH->getGlobalLobby().activateInterface();
+			GAME->server().getGlobalLobby().activateInterface();
 	}, EShortcut::GLOBAL_CANCEL);
 
 	if(hideScreen) // workaround to avoid confusing players by custom campaign list displaying for a few ms -> instead of this draw a black screen while "loading"
@@ -126,35 +127,35 @@ CLobbyScreen::CLobbyScreen(ESelectionScreen screenType, bool hideScreen)
 CLobbyScreen::~CLobbyScreen()
 {
 	// TODO: For now we always destroy whole lobby when leaving bonus selection screen
-	if(CSH->getState() == EClientState::LOBBY_CAMPAIGN)
-		CSH->sendClientDisconnecting();
+	if(GAME->server().getState() == EClientState::LOBBY_CAMPAIGN)
+		GAME->server().sendClientDisconnecting();
 }
 
 void CLobbyScreen::toggleTab(std::shared_ptr<CIntObject> tab)
 {
 	if(tab == curTab)
-		CSH->sendGuiAction(LobbyGuiAction::NO_TAB);
+		GAME->server().sendGuiAction(LobbyGuiAction::NO_TAB);
 	else if(tab == tabOpt)
-		CSH->sendGuiAction(LobbyGuiAction::OPEN_OPTIONS);
+		GAME->server().sendGuiAction(LobbyGuiAction::OPEN_OPTIONS);
 	else if(tab == tabSel)
-		CSH->sendGuiAction(LobbyGuiAction::OPEN_SCENARIO_LIST);
+		GAME->server().sendGuiAction(LobbyGuiAction::OPEN_SCENARIO_LIST);
 	else if(tab == tabRand)
-		CSH->sendGuiAction(LobbyGuiAction::OPEN_RANDOM_MAP_OPTIONS);
+		GAME->server().sendGuiAction(LobbyGuiAction::OPEN_RANDOM_MAP_OPTIONS);
 	else if(tab == tabTurnOptions)
-		CSH->sendGuiAction(LobbyGuiAction::OPEN_TURN_OPTIONS);
+		GAME->server().sendGuiAction(LobbyGuiAction::OPEN_TURN_OPTIONS);
 	else if(tab == tabExtraOptions)
-		CSH->sendGuiAction(LobbyGuiAction::OPEN_EXTRA_OPTIONS);
+		GAME->server().sendGuiAction(LobbyGuiAction::OPEN_EXTRA_OPTIONS);
 	CSelectionBase::toggleTab(tab);
 }
 
 void CLobbyScreen::startCampaign()
 {
-	if(!CSH->mi)
+	if(!GAME->server().mi)
 		return;
 
 	try {
-		auto ourCampaign = CampaignHandler::getCampaign(CSH->mi->fileURI);
-		CSH->setCampaignState(ourCampaign);
+		auto ourCampaign = CampaignHandler::getCampaign(GAME->server().mi->fileURI);
+		GAME->server().setCampaignState(ourCampaign);
 	}
 	catch (const std::runtime_error &e)
 	{
@@ -170,19 +171,19 @@ void CLobbyScreen::startCampaign()
 
 void CLobbyScreen::startScenario(bool allowOnlyAI)
 {
-	if (tabRand && CSH->si->mapGenOptions)
+	if (tabRand && GAME->server().si->mapGenOptions)
 	{
 		// Save RMG settings at game start
-		tabRand->saveOptions(*CSH->si->mapGenOptions);
+		tabRand->saveOptions(*GAME->server().si->mapGenOptions);
 	}
 
 	// Save chosen difficulty
 	Settings lastDifficulty = settings.write["general"]["lastDifficulty"];
 	lastDifficulty->Integer() = getCurrentDifficulty();
 
-	if (CSH->validateGameStart(allowOnlyAI))
+	if (GAME->server().validateGameStart(allowOnlyAI))
 	{
-		CSH->sendStartGame(allowOnlyAI);
+		GAME->server().sendStartGame(allowOnlyAI);
 		buttonStart->block(true);
 	}
 }
@@ -218,7 +219,7 @@ void CLobbyScreen::toggleMode(bool host)
 	if (buttonExtraOptions)
 		buttonExtraOptions->block(!host);
 
-	if(CSH->mi)
+	if(GAME->server().mi)
 	{
 		tabOpt->recreate();
 		tabTurnOptions->recreate();
@@ -237,17 +238,17 @@ void CLobbyScreen::toggleChat()
 
 void CLobbyScreen::updateAfterStateChange()
 {
-	if(CSH->isHost() && screenType == ESelectionScreen::newGame)
+	if(GAME->server().isHost() && screenType == ESelectionScreen::newGame)
 	{
-		bool isMultiplayer = CSH->loadMode == ELoadMode::MULTI;
+		bool isMultiplayer = GAME->server().loadMode == ELoadMode::MULTI;
 		ExtraOptionsInfo info = SEL->getStartInfo()->extraOptionsInfo;
 		info.cheatsAllowed = isMultiplayer ? persistentStorage["startExtraOptions"]["multiPlayer"]["cheatsAllowed"].Bool() : !persistentStorage["startExtraOptions"]["singlePlayer"]["cheatsNotAllowed"].Bool();
 		info.unlimitedReplay = persistentStorage["startExtraOptions"][isMultiplayer ? "multiPlayer" : "singlePlayer"]["unlimitedReplay"].Bool();
-		if(info.cheatsAllowed != CSH->si->extraOptionsInfo.cheatsAllowed || info.unlimitedReplay != CSH->si->extraOptionsInfo.unlimitedReplay)
-			CSH->setExtraOptionsInfo(info);
+		if(info.cheatsAllowed != GAME->server().si->extraOptionsInfo.cheatsAllowed || info.unlimitedReplay != GAME->server().si->extraOptionsInfo.unlimitedReplay)
+			GAME->server().setExtraOptionsInfo(info);
 	}
 
-	if(CSH->mi)
+	if(GAME->server().mi)
 	{
 		if (tabOpt)
 			tabOpt->recreate();
@@ -257,7 +258,7 @@ void CLobbyScreen::updateAfterStateChange()
 			tabExtraOptions->recreate();
 	}
 
-	buttonStart->block(CSH->mi == nullptr || CSH->isGuest());
+	buttonStart->block(GAME->server().mi == nullptr || GAME->server().isGuest());
 
 	card->changeSelection();
 	if (card->iconDifficulty)
@@ -265,24 +266,24 @@ void CLobbyScreen::updateAfterStateChange()
 		if (screenType == ESelectionScreen::loadGame)
 		{
 			// When loading the game, only one button in the difficulty toggle group should be enabled, so here disable all other buttons first, then make selection
-			card->iconDifficulty->setSelectedOnly(CSH->si->difficulty);
+			card->iconDifficulty->setSelectedOnly(GAME->server().si->difficulty);
 		}
 		else
 		{
-			card->iconDifficulty->setSelected(CSH->si->difficulty);
+			card->iconDifficulty->setSelected(GAME->server().si->difficulty);
 		}
 	}
 	
-	if(curTab && curTab == tabRand && CSH->si->mapGenOptions)
-		tabRand->setMapGenOptions(CSH->si->mapGenOptions);
+	if(curTab && curTab == tabRand && GAME->server().si->mapGenOptions)
+		tabRand->setMapGenOptions(GAME->server().si->mapGenOptions);
 }
 
 const StartInfo * CLobbyScreen::getStartInfo()
 {
-	return CSH->si.get();
+	return GAME->server().si.get();
 }
 
 const CMapInfo * CLobbyScreen::getMapInfo()
 {
-	return CSH->mi.get();
+	return GAME->server().mi.get();
 }

+ 7 - 6
client/lobby/CSavingScreen.cpp

@@ -14,6 +14,7 @@
 
 #include "../CPlayerInterface.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../widgets/Buttons.h"
 #include "../widgets/CTextInput.h"
@@ -33,7 +34,7 @@ CSavingScreen::CSavingScreen()
 	OBJECT_CONSTRUCTION;
 	center(pos);
 	localMi = std::make_shared<CMapInfo>();
-	localMi->mapHeader = std::unique_ptr<CMapHeader>(new CMapHeader(*LOCPLINT->cb->getMapHeader()));
+	localMi->mapHeader = std::unique_ptr<CMapHeader>(new CMapHeader(*GAME->interface()->cb->getMapHeader()));
 
 	tabSel = std::make_shared<SelectionTab>(screenType);
 	tabSel->callOnSelect = std::bind(&CSavingScreen::changeSelection, this, _1);
@@ -42,7 +43,7 @@ CSavingScreen::CSavingScreen()
 		
 	buttonStart = std::make_shared<CButton>(Point(411, 535), AnimationPath::builtin("SCNRSAV.DEF"), VLC->generaltexth->zelp[103], std::bind(&CSavingScreen::saveGame, this), EShortcut::LOBBY_SAVE_GAME);
 	
-	LOCPLINT->gamePause(true);
+	GAME->interface()->gamePause(true);
 }
 
 const CMapInfo * CSavingScreen::getMapInfo()
@@ -54,7 +55,7 @@ const StartInfo * CSavingScreen::getStartInfo()
 {
 	if (localMi)
 		return localMi->scenarioOptionsOfSave;
-	return LOCPLINT->cb->getStartInfo();
+	return GAME->interface()->cb->getStartInfo();
 }
 
 void CSavingScreen::changeSelection(std::shared_ptr<CMapInfo> to)
@@ -69,7 +70,7 @@ void CSavingScreen::changeSelection(std::shared_ptr<CMapInfo> to)
 
 void CSavingScreen::close()
 {
-	LOCPLINT->gamePause(false);
+	GAME->interface()->gamePause(false);
 	CSelectionBase::close();
 }
 
@@ -84,7 +85,7 @@ void CSavingScreen::saveGame()
 	{
 		Settings lastSave = settings.write["general"]["lastSave"];
 		lastSave->String() = path;
-		LOCPLINT->cb->save(path);
+		GAME->interface()->cb->save(path);
 		close();
 	};
 
@@ -92,7 +93,7 @@ void CSavingScreen::saveGame()
 	{
 		std::string hlp = VLC->generaltexth->allTexts[493]; //%s exists. Overwrite?
 		boost::algorithm::replace_first(hlp, "%s", tabSel->inputName->getText());
-		LOCPLINT->showYesNoDialog(hlp, overWrite, nullptr);
+		GAME->interface()->showYesNoDialog(hlp, overWrite, nullptr);
 	}
 	else
 	{

+ 3 - 2
client/lobby/CScenarioInfoScreen.cpp

@@ -14,6 +14,7 @@
 
 #include "../CPlayerInterface.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../widgets/Buttons.h"
 
@@ -32,9 +33,9 @@ CScenarioInfoScreen::CScenarioInfoScreen()
 	pos.h = 600;
 	pos = center();
 
-	localSi = new StartInfo(*LOCPLINT->cb->getStartInfo());
+	localSi = new StartInfo(*GAME->interface()->cb->getStartInfo());
 	localMi = new CMapInfo();
-	localMi->mapHeader = std::unique_ptr<CMapHeader>(new CMapHeader(*LOCPLINT->cb->getMapHeader()));
+	localMi->mapHeader = std::unique_ptr<CMapHeader>(new CMapHeader(*GAME->interface()->cb->getMapHeader()));
 
 	screenType = ESelectionScreen::scenarioInfo;
 

+ 13 - 12
client/lobby/CSelectionBase.cpp

@@ -21,6 +21,7 @@
 #include "../CPlayerInterface.h"
 #include "../CServerHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../gui/WindowHandler.h"
 #include "../globalLobby/GlobalLobbyClient.h"
@@ -148,8 +149,8 @@ InfoCard::InfoCard()
 	chat = std::make_shared<CChatBox>(Rect(18, 126, 335, 143));
 	pvpBox = std::make_shared<PvPBox>(Rect(17, 396, 338, 105));
 
-	buttonInvitePlayers = std::make_shared<CButton>(Point(20, 365), AnimationPath::builtin("pregameInvitePlayers"), VLC->generaltexth->zelp[105], [](){ CSH->getGlobalLobby().activateRoomInviteInterface(); }, EShortcut::LOBBY_INVITE_PLAYERS );
-	buttonOpenGlobalLobby = std::make_shared<CButton>(Point(188, 365), AnimationPath::builtin("pregameReturnToLobby"), VLC->generaltexth->zelp[105], [](){ CSH->getGlobalLobby().activateInterface(); }, EShortcut::MAIN_MENU_LOBBY );
+	buttonInvitePlayers = std::make_shared<CButton>(Point(20, 365), AnimationPath::builtin("pregameInvitePlayers"), VLC->generaltexth->zelp[105], [](){ GAME->server().getGlobalLobby().activateRoomInviteInterface(); }, EShortcut::LOBBY_INVITE_PLAYERS );
+	buttonOpenGlobalLobby = std::make_shared<CButton>(Point(188, 365), AnimationPath::builtin("pregameReturnToLobby"), VLC->generaltexth->zelp[105], [](){ GAME->server().getGlobalLobby().activateInterface(); }, EShortcut::MAIN_MENU_LOBBY );
 
 	buttonInvitePlayers->setTextOverlay  (MetaString::createFromTextID("vcmi.lobby.invite.header").toString(), EFonts::FONT_SMALL, Colors::WHITE);
 	buttonOpenGlobalLobby->setTextOverlay(MetaString::createFromTextID("vcmi.lobby.backToLobby").toString(), EFonts::FONT_SMALL, Colors::WHITE);
@@ -204,7 +205,7 @@ InfoCard::InfoCard()
 		disableLabelRedraws();
 	}
 	setChat(false);
-	if (CSH->inLobbyRoom())
+	if (GAME->server().inLobbyRoom())
 		setChat(true); // FIXME: less ugly version?
 }
 
@@ -264,7 +265,7 @@ void InfoCard::changeSelection()
 
 	const auto & font = ENGINE->renderHandler().loadFont(FONT_SMALL);
 
-	for(const auto & p : CSH->playerNames)
+	for(const auto & p : GAME->server().playerNames)
 	{
 		int slotsUsed = labelGroupPlayers->currentSize();
 		Point labelPosition;
@@ -316,7 +317,7 @@ void InfoCard::setChat(bool activateChat)
 			pvpBox->enable();
 			playerListBg->enable();
 		}
-		if (CSH->inLobbyRoom())
+		if (GAME->server().inLobbyRoom())
 		{
 			buttonInvitePlayers->enable();
 			buttonOpenGlobalLobby->enable();
@@ -387,7 +388,7 @@ void CChatBox::keyPressed(EShortcut key)
 {
 	if(key == EShortcut::GLOBAL_ACCEPT && inputBox->getText().size())
 	{
-		CSH->sendMessage(inputBox->getText());
+		GAME->server().sendMessage(inputBox->getText());
 		inputBox->setText("");
 	}
 	else
@@ -425,7 +426,7 @@ PvPBox::PvPBox(const Rect & rect)
 	buttonFlipCoin = std::make_shared<CButton>(Point(190, 6), AnimationPath::builtin("GSPBUT2.DEF"), CButton::tooltip("", VLC->generaltexth->translate("vcmi.lobby.pvp.coin.help")), [](){
 		LobbyPvPAction lpa;
 		lpa.action = LobbyPvPAction::COIN;
-		CSH->sendLobbyPack(lpa);
+		GAME->server().sendLobbyPack(lpa);
 	}, EShortcut::LOBBY_FLIP_COIN);
 	buttonFlipCoin->setTextOverlay(VLC->generaltexth->translate("vcmi.lobby.pvp.coin.hover"), EFonts::FONT_SMALL, Colors::WHITE);
 
@@ -433,7 +434,7 @@ PvPBox::PvPBox(const Rect & rect)
 		LobbyPvPAction lpa;
 		lpa.action = LobbyPvPAction::RANDOM_TOWN;
 		lpa.bannedTowns = getBannedTowns();
-		CSH->sendLobbyPack(lpa);
+		GAME->server().sendLobbyPack(lpa);
 	}, EShortcut::LOBBY_RANDOM_TOWN);
 	buttonRandomTown->setTextOverlay(VLC->generaltexth->translate("vcmi.lobby.pvp.randomTown.hover"), EFonts::FONT_SMALL, Colors::WHITE);
 
@@ -441,12 +442,12 @@ PvPBox::PvPBox(const Rect & rect)
 		LobbyPvPAction lpa;
 		lpa.action = LobbyPvPAction::RANDOM_TOWN_VS;
 		lpa.bannedTowns = getBannedTowns();
-		CSH->sendLobbyPack(lpa);
+		GAME->server().sendLobbyPack(lpa);
 	}, EShortcut::LOBBY_RANDOM_TOWN_VS);
 	buttonRandomTownVs->setTextOverlay(VLC->generaltexth->translate("vcmi.lobby.pvp.randomTownVs.hover"), EFonts::FONT_SMALL, Colors::WHITE);
 
 	buttonHandicap = std::make_shared<CButton>(Point(190, 81), AnimationPath::builtin("GSPBUT2.DEF"), CButton::tooltip("", VLC->generaltexth->translate("vcmi.lobby.handicap")), [](){
-		if(!CSH->isHost())
+		if(!GAME->server().isHost())
 			return;
 		ENGINE->windows().createAndPushWindow<OptionsTab::HandicapWindow>();
 	}, EShortcut::LOBBY_HANDICAP);
@@ -539,10 +540,10 @@ void CFlagBox::recreate()
 	OBJECT_CONSTRUCTION;
 	const int alliesX = 5 + (int)labelAllies->getWidth();
 	const int enemiesX = 5 + 133 + (int)labelEnemies->getWidth();
-	for(auto i = CSH->si->playerInfos.cbegin(); i != CSH->si->playerInfos.cend(); i++)
+	for(auto i = GAME->server().si->playerInfos.cbegin(); i != GAME->server().si->playerInfos.cend(); i++)
 	{
 		auto flag = std::make_shared<CAnimImage>(AnimationPath::builtin("ITGFLAGS.DEF"), i->first.getNum(), 0);
-		if(i->first == CSH->myFirstColor() || CSH->getPlayerTeamId(i->first) == CSH->getPlayerTeamId(CSH->myFirstColor()))
+		if(i->first == GAME->server().myFirstColor() || GAME->server().getPlayerTeamId(i->first) == GAME->server().getPlayerTeamId(GAME->server().myFirstColor()))
 		{
 			flag->moveTo(Point(pos.x + alliesX + (int)flagsAllies.size()*flag->pos.w, pos.y));
 			flagsAllies.push_back(flag);

+ 24 - 23
client/lobby/OptionsTab.cpp

@@ -14,6 +14,7 @@
 
 #include "../CServerHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../gui/WindowHandler.h"
 #include "../render/Graphics.h"
@@ -493,13 +494,13 @@ void OptionsTab::SelectionWindow::apply()
 void OptionsTab::SelectionWindow::setSelection()
 {
 	if(selectedFaction != initialFaction)
-		CSH->setPlayerOption(LobbyChangePlayerOption::TOWN_ID, selectedFaction, color);
+		GAME->server().setPlayerOption(LobbyChangePlayerOption::TOWN_ID, selectedFaction, color);
 
 	if(selectedHero != initialHero)
-		CSH->setPlayerOption(LobbyChangePlayerOption::HERO_ID, selectedHero, color);
+		GAME->server().setPlayerOption(LobbyChangePlayerOption::HERO_ID, selectedHero, color);
 
 	if(selectedBonus != initialBonus)
-		CSH->setPlayerOption(LobbyChangePlayerOption::BONUS_ID, static_cast<int>(selectedBonus), color);
+		GAME->server().setPlayerOption(LobbyChangePlayerOption::BONUS_ID, static_cast<int>(selectedBonus), color);
 }
 
 void OptionsTab::SelectionWindow::reopen()
@@ -509,7 +510,7 @@ void OptionsTab::SelectionWindow::reopen()
 	else{
 		auto window = std::make_shared<SelectionWindow>(color, type, slider ? slider->getValue() : 0);
 		close();
-		if(CSH->isMyColor(color) || CSH->isHost())
+		if(GAME->server().isMyColor(color) || GAME->server().isHost())
 			ENGINE->windows().pushWindow(window);
 	}
 }
@@ -893,7 +894,7 @@ OptionsTab::HandicapWindow::HandicapWindow()
 				else
 					resources[resource.first] = std::stoi(resource.second->getText());
 			}
-			CSH->setPlayerHandicap(player.first, Handicap{resources, income, growth});
+			GAME->server().setPlayerHandicap(player.first, Handicap{resources, income, growth});
 		}
 	    		
 		close();
@@ -951,7 +952,7 @@ void OptionsTab::SelectedBox::clickReleased(const Point & cursorPosition)
 		return;
 	
 	PlayerInfo pi = SEL->getPlayerInfo(playerSettings.color);
-	const bool foreignPlayer = CSH->isGuest() && !CSH->isMyColor(playerSettings.color);
+	const bool foreignPlayer = GAME->server().isGuest() && !GAME->server().isMyColor(playerSettings.color);
 
 	if(selectionType == SelType::TOWN && ((pi.allowedFactions.size() < 2 && !pi.isFactionRandom) || foreignPlayer))
 		return;
@@ -976,13 +977,13 @@ void OptionsTab::SelectedBox::scrollBy(int distance)
 	switch(CPlayerSettingsHelper::selectionType)
 	{
 		case TOWN:
-			CSH->setPlayerOption(LobbyChangePlayerOption::TOWN, distance, playerSettings.color);
+			GAME->server().setPlayerOption(LobbyChangePlayerOption::TOWN, distance, playerSettings.color);
 			break;
 		case HERO:
-			CSH->setPlayerOption(LobbyChangePlayerOption::HERO, distance, playerSettings.color);
+			GAME->server().setPlayerOption(LobbyChangePlayerOption::HERO, distance, playerSettings.color);
 			break;
 		case BONUS:
-			CSH->setPlayerOption(LobbyChangePlayerOption::BONUS, distance, playerSettings.color);
+			GAME->server().setPlayerOption(LobbyChangePlayerOption::BONUS, distance, playerSettings.color);
 			break;
 	}
 
@@ -1009,7 +1010,7 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry(const PlayerSettings & S, con
 	pos.x += 54;
 	pos.y += 128 + serial * 50;
 
-	assert(CSH->mi && CSH->mi->mapHeader);
+	assert(GAME->server().mi && GAME->server().mi->mapHeader);
 	const PlayerInfo & p = SEL->getPlayerInfo(s->color);
 	assert(p.canComputerPlay || p.canHumanPlay); //someone must be able to control this player
 	if(p.canHumanPlay && p.canComputerPlay)
@@ -1031,7 +1032,7 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry(const PlayerSettings & S, con
 	}};
 
 	background = std::make_shared<CPicture>(ImagePath::builtin(bgs[s->color]), 0, 0);
-	if(s->isControlledByAI() || CSH->isGuest())
+	if(s->isControlledByAI() || GAME->server().isGuest())
 		labelPlayerName = std::make_shared<CLabel>(55, 10, EFonts::FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, name, 95);
 	else
 	{
@@ -1045,7 +1046,7 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry(const PlayerSettings & S, con
 	std::string labelHandicapText = hasHandicap() ? VLC->generaltexth->arraytxt[210] : MetaString::createFromTextID("vcmi.lobby.handicap").toString();
 	labelHandicap = std::make_shared<CMultiLineLabel>(Rect(55, 23, 46, 24), EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, labelHandicapText);
 	handicap = std::make_shared<LRClickableArea>(Rect(53, 23, 50, 24), [](){
-		if(!CSH->isHost())
+		if(!GAME->server().isHost())
 			return;
 		
 		ENGINE->windows().createAndPushWindow<HandicapWindow>();
@@ -1084,12 +1085,12 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry(const PlayerSettings & S, con
 
 	if(SEL->screenType == ESelectionScreen::newGame)
 	{
-		buttonTownLeft   = std::make_shared<CButton>(Point(107, 5), AnimationPath::builtin("ADOPLFA.DEF"), VLC->generaltexth->zelp[132], std::bind(&IServerAPI::setPlayerOption, CSH, LobbyChangePlayerOption::TOWN, -1, s->color));
-		buttonTownRight  = std::make_shared<CButton>(Point(168, 5), AnimationPath::builtin("ADOPRTA.DEF"), VLC->generaltexth->zelp[133], std::bind(&IServerAPI::setPlayerOption, CSH, LobbyChangePlayerOption::TOWN, +1, s->color));
-		buttonHeroLeft   = std::make_shared<CButton>(Point(183, 5), AnimationPath::builtin("ADOPLFA.DEF"), VLC->generaltexth->zelp[148], std::bind(&IServerAPI::setPlayerOption, CSH, LobbyChangePlayerOption::HERO, -1, s->color));
-		buttonHeroRight  = std::make_shared<CButton>(Point(244, 5), AnimationPath::builtin("ADOPRTA.DEF"), VLC->generaltexth->zelp[149], std::bind(&IServerAPI::setPlayerOption, CSH, LobbyChangePlayerOption::HERO, +1, s->color));
-		buttonBonusLeft  = std::make_shared<CButton>(Point(259, 5), AnimationPath::builtin("ADOPLFA.DEF"), VLC->generaltexth->zelp[164], std::bind(&IServerAPI::setPlayerOption, CSH, LobbyChangePlayerOption::BONUS, -1, s->color));
-		buttonBonusRight = std::make_shared<CButton>(Point(320, 5), AnimationPath::builtin("ADOPRTA.DEF"), VLC->generaltexth->zelp[165], std::bind(&IServerAPI::setPlayerOption, CSH, LobbyChangePlayerOption::BONUS, +1, s->color));
+		buttonTownLeft   = std::make_shared<CButton>(Point(107, 5), AnimationPath::builtin("ADOPLFA.DEF"), VLC->generaltexth->zelp[132], std::bind(&IServerAPI::setPlayerOption, &GAME->server(), LobbyChangePlayerOption::TOWN, -1, s->color));
+		buttonTownRight  = std::make_shared<CButton>(Point(168, 5), AnimationPath::builtin("ADOPRTA.DEF"), VLC->generaltexth->zelp[133], std::bind(&IServerAPI::setPlayerOption, &GAME->server(), LobbyChangePlayerOption::TOWN, +1, s->color));
+		buttonHeroLeft   = std::make_shared<CButton>(Point(183, 5), AnimationPath::builtin("ADOPLFA.DEF"), VLC->generaltexth->zelp[148], std::bind(&IServerAPI::setPlayerOption, &GAME->server(), LobbyChangePlayerOption::HERO, -1, s->color));
+		buttonHeroRight  = std::make_shared<CButton>(Point(244, 5), AnimationPath::builtin("ADOPRTA.DEF"), VLC->generaltexth->zelp[149], std::bind(&IServerAPI::setPlayerOption, &GAME->server(), LobbyChangePlayerOption::HERO, +1, s->color));
+		buttonBonusLeft  = std::make_shared<CButton>(Point(259, 5), AnimationPath::builtin("ADOPLFA.DEF"), VLC->generaltexth->zelp[164], std::bind(&IServerAPI::setPlayerOption, &GAME->server(), LobbyChangePlayerOption::BONUS, -1, s->color));
+		buttonBonusRight = std::make_shared<CButton>(Point(320, 5), AnimationPath::builtin("ADOPRTA.DEF"), VLC->generaltexth->zelp[165], std::bind(&IServerAPI::setPlayerOption, &GAME->server(), LobbyChangePlayerOption::BONUS, +1, s->color));
 	}
 
 	hideUnavailableButtons();
@@ -1103,7 +1104,7 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry(const PlayerSettings & S, con
 			std::bind(&OptionsTab::onSetPlayerClicked, &parentTab, *s)
 		);
 		flag->setHoverable(true);
-		flag->block(CSH->isGuest());
+		flag->block(GAME->server().isGuest());
 	}
 	else
 		flag = nullptr;
@@ -1138,8 +1139,8 @@ void OptionsTab::PlayerOptionsEntry::clickReleased(const Point & cursorPosition)
 void OptionsTab::PlayerOptionsEntry::updateName() {
 	if(labelPlayerNameEdit->getText() != name)
 	{
-		CSH->setPlayerName(s->color, labelPlayerNameEdit->getText());
-		if(CSH->isMyColor(s->color))
+		GAME->server().setPlayerName(s->color, labelPlayerNameEdit->getText());
+		if(GAME->server().isMyColor(s->color))
 		{
 			Settings set = settings.write["general"]["playerName"];
 			set->String() = labelPlayerNameEdit->getText();
@@ -1153,7 +1154,7 @@ void OptionsTab::PlayerOptionsEntry::updateName() {
 void OptionsTab::onSetPlayerClicked(const PlayerSettings & ps) const
 {
 	if(ps.isControlledByAI() || humanPlayers > 1)
-		CSH->setPlayer(ps.color);
+		GAME->server().setPlayer(ps.color);
 }
 
 void OptionsTab::PlayerOptionsEntry::hideUnavailableButtons()
@@ -1161,7 +1162,7 @@ void OptionsTab::PlayerOptionsEntry::hideUnavailableButtons()
 	if(!buttonTownLeft)
 		return;
 
-	const bool foreignPlayer = CSH->isGuest() && !CSH->isMyColor(s->color);
+	const bool foreignPlayer = GAME->server().isGuest() && !GAME->server().isMyColor(s->color);
 
 	if((pi->allowedFactions.size() < 2 && !pi->isFactionRandom) || foreignPlayer)
 	{

+ 19 - 18
client/lobby/OptionsTabBase.cpp

@@ -17,6 +17,7 @@
 #include "../widgets/Slider.h"
 #include "../widgets/TextControls.h"
 #include "../CServerHandler.h"
+#include "../GameInstance.h"
 
 #include "../../lib/StartInfo.h"
 #include "../../lib/texts/CGeneralTextHandler.h"
@@ -71,11 +72,11 @@ OptionsTabBase::OptionsTabBase(const JsonPath & configPath)
 	recActions = 0;
 
 	auto setTimerPresetCallback = [this](int index){
-		CSH->setTurnTimerInfo(getTimerPresets().at(index));
+		GAME->server().setTurnTimerInfo(getTimerPresets().at(index));
 	};
 
 	auto setSimturnsPresetCallback = [this](int index){
-		CSH->setSimturnsInfo(getSimturnsPresets().at(index));
+		GAME->server().setSimturnsInfo(getSimturnsPresets().at(index));
 	};
 
 	addCallback("setTimerPreset", setTimerPresetCallback);
@@ -85,50 +86,50 @@ OptionsTabBase::OptionsTabBase(const JsonPath & configPath)
 		SimturnsInfo info = SEL->getStartInfo()->simturnsInfo;
 		info.requiredTurns = index;
 		info.optionalTurns = std::max(info.optionalTurns, index);
-		CSH->setSimturnsInfo(info);
+		GAME->server().setSimturnsInfo(info);
 	});
 
 	addCallback("setSimturnDurationMax", [&](int index){
 		SimturnsInfo info = SEL->getStartInfo()->simturnsInfo;
 		info.optionalTurns = index;
 		info.requiredTurns = std::min(info.requiredTurns, index);
-		CSH->setSimturnsInfo(info);
+		GAME->server().setSimturnsInfo(info);
 	});
 
 	addCallback("setSimturnAI", [&](int index){
 		SimturnsInfo info = SEL->getStartInfo()->simturnsInfo;
 		info.allowHumanWithAI = index;
-		CSH->setSimturnsInfo(info);
+		GAME->server().setSimturnsInfo(info);
 	});
 
 	addCallback("setCheatAllowed", [&](int index){
-		bool isMultiplayer = CSH->loadMode == ELoadMode::MULTI;
+		bool isMultiplayer = GAME->server().loadMode == ELoadMode::MULTI;
 		Settings entry = persistentStorage.write["startExtraOptions"][isMultiplayer ? "multiPlayer" : "singlePlayer"][isMultiplayer ? "cheatsAllowed" : "cheatsNotAllowed"];
 		entry->Bool() = isMultiplayer ? index : !index;
 		ExtraOptionsInfo info = SEL->getStartInfo()->extraOptionsInfo;
 		info.cheatsAllowed = index;
-		CSH->setExtraOptionsInfo(info);
+		GAME->server().setExtraOptionsInfo(info);
 	});
 
 	addCallback("setUnlimitedReplay", [&](int index){
-		bool isMultiplayer = CSH->loadMode == ELoadMode::MULTI;
+		bool isMultiplayer = GAME->server().loadMode == ELoadMode::MULTI;
 		Settings entry = persistentStorage.write["startExtraOptions"][isMultiplayer ? "multiPlayer" : "singlePlayer"]["unlimitedReplay"];
 		entry->Bool() = index;
 		ExtraOptionsInfo info = SEL->getStartInfo()->extraOptionsInfo;
 		info.unlimitedReplay = index;
-		CSH->setExtraOptionsInfo(info);
+		GAME->server().setExtraOptionsInfo(info);
 	});
 
 	addCallback("setTurnTimerAccumulate", [&](int index){
 		TurnTimerInfo info = SEL->getStartInfo()->turnTimerInfo;
 		info.accumulatingTurnTimer = index;
-		CSH->setTurnTimerInfo(info);
+		GAME->server().setTurnTimerInfo(info);
 	});
 
 	addCallback("setUnitTimerAccumulate", [&](int index){
 		TurnTimerInfo info = SEL->getStartInfo()->turnTimerInfo;
 		info.accumulatingUnitTimer = index;
-		CSH->setTurnTimerInfo(info);
+		GAME->server().setTurnTimerInfo(info);
 	});
 
 	//helper function to parse string containing time to integer reflecting time in seconds
@@ -179,7 +180,7 @@ OptionsTabBase::OptionsTabBase(const JsonPath & configPath)
 		{
 			TurnTimerInfo tinfo = SEL->getStartInfo()->turnTimerInfo;
 			tinfo.baseTimer = time;
-			CSH->setTurnTimerInfo(tinfo);
+			GAME->server().setTurnTimerInfo(tinfo);
 			if(auto ww = widget<CTextInput>("chessFieldBase"))
 				ww->setText(timeToString(time));
 		}
@@ -190,7 +191,7 @@ OptionsTabBase::OptionsTabBase(const JsonPath & configPath)
 		{
 			TurnTimerInfo tinfo = SEL->getStartInfo()->turnTimerInfo;
 			tinfo.turnTimer = time;
-			CSH->setTurnTimerInfo(tinfo);
+			GAME->server().setTurnTimerInfo(tinfo);
 			if(auto ww = widget<CTextInput>("chessFieldTurn"))
 				ww->setText(timeToString(time));
 		}
@@ -201,7 +202,7 @@ OptionsTabBase::OptionsTabBase(const JsonPath & configPath)
 		{
 			TurnTimerInfo tinfo = SEL->getStartInfo()->turnTimerInfo;
 			tinfo.battleTimer = time;
-			CSH->setTurnTimerInfo(tinfo);
+			GAME->server().setTurnTimerInfo(tinfo);
 			if(auto ww = widget<CTextInput>("chessFieldBattle"))
 				ww->setText(timeToString(time));
 		}
@@ -212,7 +213,7 @@ OptionsTabBase::OptionsTabBase(const JsonPath & configPath)
 		{
 			TurnTimerInfo tinfo = SEL->getStartInfo()->turnTimerInfo;
 			tinfo.unitTimer = time;
-			CSH->setTurnTimerInfo(tinfo);
+			GAME->server().setTurnTimerInfo(tinfo);
 			if(auto ww = widget<CTextInput>("chessFieldUnit"))
 				ww->setText(timeToString(time));
 		}
@@ -256,7 +257,7 @@ OptionsTabBase::OptionsTabBase(const JsonPath & configPath)
 						tinfo.turnTimer = (*tObj)["default"].Vector().at(1).Integer() * 1000;
 						tinfo.battleTimer = (*tObj)["default"].Vector().at(2).Integer() * 1000;
 						tinfo.unitTimer = (*tObj)["default"].Vector().at(3).Integer() * 1000;
-						CSH->setTurnTimerInfo(tinfo);
+						GAME->server().setTurnTimerInfo(tinfo);
 					}
 				}
 				redraw();
@@ -418,13 +419,13 @@ void OptionsTabBase::recreate(bool campaign)
 	if(auto buttonCheatAllowed = widget<CToggleButton>("buttonCheatAllowed"))
 	{
 		buttonCheatAllowed->setSelectedSilent(SEL->getStartInfo()->extraOptionsInfo.cheatsAllowed);
-		buttonCheatAllowed->block(CSH->isGuest());
+		buttonCheatAllowed->block(GAME->server().isGuest());
 	}
 
 	if(auto buttonUnlimitedReplay = widget<CToggleButton>("buttonUnlimitedReplay"))
 	{
 		buttonUnlimitedReplay->setSelectedSilent(SEL->getStartInfo()->extraOptionsInfo.unlimitedReplay);
-		buttonUnlimitedReplay->block(CSH->isGuest());
+		buttonUnlimitedReplay->block(GAME->server().isGuest());
 	}
 
 	if(auto textureCampaignOverdraw = widget<CFilledTexture>("textureCampaignOverdraw"))

+ 2 - 1
client/lobby/RandomMapTab.cpp

@@ -16,6 +16,7 @@
 
 #include "../CServerHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/MouseButton.h"
 #include "../gui/WindowHandler.h"
 #include "../widgets/CComponent.h"
@@ -170,7 +171,7 @@ RandomMapTab::RandomMapTab():
 
 void RandomMapTab::updateMapInfoByHost()
 {
-	if(CSH->isGuest())
+	if(GAME->server().isGuest())
 		return;
 
 	// Generate header info

+ 10 - 9
client/lobby/SelectionTab.cpp

@@ -16,6 +16,7 @@
 #include "../CPlayerInterface.h"
 #include "../CServerHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../gui/WindowHandler.h"
 #include "../widgets/CComponent.h"
@@ -263,7 +264,7 @@ void SelectionTab::toggleMode()
 {
 	allItems.clear();
 	curItems.clear();
-	if(CSH->isGuest())
+	if(GAME->server().isGuest())
 	{
 		if(slider)
 			slider->block(true);
@@ -310,10 +311,10 @@ void SelectionTab::toggleMode()
 			filter(0);
 		}
 
-		if(CSH->campaignStateToSend)
+		if(GAME->server().campaignStateToSend)
 		{
-			CSH->setCampaignState(CSH->campaignStateToSend);
-			CSH->campaignStateToSend.reset();
+			GAME->server().setCampaignState(GAME->server().campaignStateToSend);
+			GAME->server().campaignStateToSend.reset();
 		}
 		else
 		{
@@ -350,14 +351,14 @@ void SelectionTab::clickReleased(const Point & cursorPosition)
 					LobbyDelete ld;
 					ld.type = tabType == ESelectionScreen::newGame ? LobbyDelete::EType::RANDOMMAP : LobbyDelete::EType::SAVEGAME;
 					ld.name = curItems[py]->fileURI;
-					CSH->sendLobbyPack(ld);
+					GAME->server().sendLobbyPack(ld);
 				}, nullptr);
 			else
 				CInfoWindow::showYesNoDialog(VLC->generaltexth->translate("vcmi.lobby.deleteFolder") + "\n\n" + curFolder + curItems[py]->folderName, std::vector<std::shared_ptr<CComponent>>(), [this, py](){
 					LobbyDelete ld;
 					ld.type = LobbyDelete::EType::SAVEGAME_FOLDER;
 					ld.name = curFolder + curItems[py]->folderName;
-					CSH->sendLobbyPack(ld);
+					GAME->server().sendLobbyPack(ld);
 				}, nullptr);
 		}
 	}
@@ -895,7 +896,7 @@ std::vector<ResourcePath> SelectionTab::parseSaves(const std::unordered_set<Reso
 			bool isCampaign = mapInfo->scenarioOptionsOfSave->mode == EStartMode::CAMPAIGN;
 			bool isMultiplayer = mapInfo->amountOfHumanPlayersInSave > 1;
 			bool isTutorial = boost::to_upper_copy(mapInfo->scenarioOptionsOfSave->mapname) == "MAPS/TUTORIAL";
-			switch(CSH->getLoadMode())
+			switch(GAME->server().getLoadMode())
 			{
 			case ELoadMode::SINGLE:
 				if(isCampaign || isTutorial)
@@ -937,7 +938,7 @@ std::vector<ResourcePath> SelectionTab::parseSaves(const std::unordered_set<Reso
 
 void SelectionTab::handleUnsupportedSavegames(const std::vector<ResourcePath> & files)
 {
-	if(CSH->isHost() && files.size())
+	if(GAME->server().isHost() && files.size())
 	{
 		MetaString text = MetaString::createFromTextID("vcmi.lobby.deleteUnsupportedSave");
 		text.replaceNumber(files.size());
@@ -947,7 +948,7 @@ void SelectionTab::handleUnsupportedSavegames(const std::vector<ResourcePath> &
 				LobbyDelete ld;
 				ld.type = LobbyDelete::EType::SAVEGAME;
 				ld.name = file.getName();
-				CSH->sendLobbyPack(ld);
+				GAME->server().sendLobbyPack(ld);
 			}
 		}, nullptr);
 	}

+ 12 - 11
client/mainmenu/CMainMenu.cpp

@@ -22,6 +22,7 @@
 #include "../gui/CursorHandler.h"
 #include "../windows/GUIClasses.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../eventsSDL/InputHandler.h"
 #include "../gui/ShortcutHandler.h"
 #include "../gui/Shortcut.h"
@@ -404,8 +405,8 @@ void CMainMenu::update()
 
 void CMainMenu::openLobby(ESelectionScreen screenType, bool host, const std::vector<std::string> & names, ELoadMode loadMode)
 {
-	CSH->resetStateForLobby(screenType == ESelectionScreen::newGame ? EStartMode::NEW_GAME : EStartMode::LOAD_GAME, screenType, EServerMode::LOCAL, names);
-	CSH->loadMode = loadMode;
+	GAME->server().resetStateForLobby(screenType == ESelectionScreen::newGame ? EStartMode::NEW_GAME : EStartMode::LOAD_GAME, screenType, EServerMode::LOCAL, names);
+	GAME->server().loadMode = loadMode;
 
 	ENGINE->windows().createAndPushWindow<CSimpleJoinScreen>(host);
 }
@@ -419,8 +420,8 @@ void CMainMenu::openCampaignLobby(const std::string & campaignFileName, std::str
 
 void CMainMenu::openCampaignLobby(std::shared_ptr<CampaignState> campaign)
 {
-	CSH->resetStateForLobby(EStartMode::CAMPAIGN, ESelectionScreen::campaignList, EServerMode::LOCAL, {});
-	CSH->campaignStateToSend = campaign;
+	GAME->server().resetStateForLobby(EStartMode::CAMPAIGN, ESelectionScreen::campaignList, EServerMode::LOCAL, {});
+	GAME->server().campaignStateToSend = campaign;
 	ENGINE->windows().createAndPushWindow<CSimpleJoinScreen>();
 }
 
@@ -465,7 +466,7 @@ void CMainMenu::startTutorial()
 	auto mapInfo = std::make_shared<CMapInfo>();
 	mapInfo->mapInit(tutorialMap.getName());
 	CMainMenu::openLobby(ESelectionScreen::newGame, true, {}, ELoadMode::NONE);
-	CSH->startMapAfterConnection(mapInfo);
+	GAME->server().startMapAfterConnection(mapInfo);
 }
 
 void CMainMenu::openHighScoreScreen()
@@ -528,7 +529,7 @@ CMultiMode::CMultiMode(ESelectionScreen ScreenType)
 void CMultiMode::openLobby()
 {
 	close();
-	CSH->getGlobalLobby().activateInterface();
+	GAME->server().getGlobalLobby().activateInterface();
 }
 
 void CMultiMode::hostTCP(EShortcut shortcut)
@@ -675,8 +676,8 @@ CSimpleJoinScreen::CSimpleJoinScreen(bool host)
 		inputPort->setFilterNumber(0, 65535);
 		inputAddress->giveFocus();
 	}
-	inputAddress->setText(host ? CSH->getLocalHostname() : CSH->getRemoteHostname());
-	inputPort->setText(std::to_string(host ? CSH->getLocalPort() : CSH->getRemotePort()));
+	inputAddress->setText(host ? GAME->server().getLocalHostname() : GAME->server().getRemoteHostname());
+	inputPort->setText(std::to_string(host ? GAME->server().getLocalPort() : GAME->server().getRemotePort()));
 	buttonOk->block(inputAddress->getText().empty() || inputPort->getText().empty());
 
 	buttonCancel = std::make_shared<CButton>(Point(142, 142), AnimationPath::builtin("MUBCANC.DEF"), VLC->generaltexth->zelp[561], std::bind(&CSimpleJoinScreen::leaveScreen, this), EShortcut::GLOBAL_CANCEL);
@@ -695,7 +696,7 @@ void CSimpleJoinScreen::connectToServer()
 void CSimpleJoinScreen::leaveScreen()
 {
 	textTitle->setText(VLC->generaltexth->translate("vcmi.mainMenu.serverClosing"));
-	CSH->setState(EClientState::CONNECTION_CANCELLED);
+	GAME->server().setState(EClientState::CONNECTION_CANCELLED);
 }
 
 void CSimpleJoinScreen::onChange(const std::string & newText)
@@ -706,9 +707,9 @@ void CSimpleJoinScreen::onChange(const std::string & newText)
 void CSimpleJoinScreen::startConnection(const std::string & addr, ui16 port)
 {
 	if(addr.empty())
-		CSH->startLocalServerAndConnect(false);
+		GAME->server().startLocalServerAndConnect(false);
 	else
-		CSH->connectToServer(addr, port);
+		GAME->server().connectToServer(addr, port);
 }
 
 CLoadingScreen::CLoadingScreen()

+ 18 - 17
client/mapView/MapRendererContext.cpp

@@ -17,6 +17,7 @@
 #include "../../CCallback.h"
 #include "../CPlayerInterface.h"
 #include "../PlayerLocalState.h"
+#include "../GameInstance.h"
 
 #include "../../lib/Point.h"
 #include "../../lib/mapObjects/CGHeroInstance.h"
@@ -53,20 +54,20 @@ uint32_t MapRendererBaseContext::getObjectRotation(ObjectInstanceID objectID) co
 
 int3 MapRendererBaseContext::getMapSize() const
 {
-	return LOCPLINT->cb->getMapSize();
+	return GAME->interface()->cb->getMapSize();
 }
 
 bool MapRendererBaseContext::isInMap(const int3 & coordinates) const
 {
-	return LOCPLINT->cb->isInTheMap(coordinates);
+	return GAME->interface()->cb->isInTheMap(coordinates);
 }
 
 bool MapRendererBaseContext::isVisible(const int3 & coordinates) const
 {
 	if(settingsSessionSpectate)
-		return LOCPLINT->cb->isInTheMap(coordinates);
+		return GAME->interface()->cb->isInTheMap(coordinates);
 	else
-		return LOCPLINT->cb->isVisible(coordinates);
+		return GAME->interface()->cb->isVisible(coordinates);
 }
 
 bool MapRendererBaseContext::isActiveHero(const CGObjectInstance * obj) const
@@ -74,9 +75,9 @@ bool MapRendererBaseContext::isActiveHero(const CGObjectInstance * obj) const
 	if(obj->ID == Obj::HERO)
 	{
 		assert(dynamic_cast<const CGHeroInstance *>(obj) != nullptr);
-		if(LOCPLINT->localState->getCurrentHero() != nullptr)
+		if(GAME->interface()->localState->getCurrentHero() != nullptr)
 		{
-			if(obj->id == LOCPLINT->localState->getCurrentHero()->id)
+			if(obj->id == GAME->interface()->localState->getCurrentHero()->id)
 				return true;
 		}
 	}
@@ -91,7 +92,7 @@ bool MapRendererBaseContext::tileAnimated(const int3 & coordinates) const
 
 const TerrainTile & MapRendererBaseContext::getMapTile(const int3 & coordinates) const
 {
-	return MAPHANDLER->getMap()->getTile(coordinates);
+	return GAME->map().getMap()->getTile(coordinates);
 }
 
 const MapRendererBaseContext::MapObjectsList & MapRendererBaseContext::getObjects(const int3 & coordinates) const
@@ -102,7 +103,7 @@ const MapRendererBaseContext::MapObjectsList & MapRendererBaseContext::getObject
 
 const CGObjectInstance * MapRendererBaseContext::getObject(ObjectInstanceID objectID) const
 {
-	return MAPHANDLER->getMap()->objects.at(objectID.getNum());
+	return GAME->map().getMap()->objects.at(objectID.getNum());
 }
 
 const CGPath * MapRendererBaseContext::currentPath() const
@@ -227,15 +228,15 @@ MapRendererAdventureContext::MapRendererAdventureContext(const MapRendererContex
 
 const CGPath * MapRendererAdventureContext::currentPath() const
 {
-	const auto * hero = LOCPLINT->localState->getCurrentHero();
+	const auto * hero = GAME->interface()->localState->getCurrentHero();
 
 	if(!hero)
 		return nullptr;
 
-	if(!LOCPLINT->localState->hasPath(hero))
+	if(!GAME->interface()->localState->hasPath(hero))
 		return nullptr;
 
-	return &LOCPLINT->localState->getPath(hero);
+	return &GAME->interface()->localState->getPath(hero);
 }
 
 size_t MapRendererAdventureContext::objectImageIndex(ObjectInstanceID objectID, size_t groupSize) const
@@ -295,10 +296,10 @@ ColorRGBA MapRendererAdventureContext::overlayTextColor(const int3 & coordinates
 
 	const auto * object = tile.visitableObjects.back();
 
-	if (object->getOwner() == LOCPLINT->playerID)
+	if (object->getOwner() == GAME->interface()->playerID)
 		return { 0, 192, 0};
 
-	if (LOCPLINT->cb->getPlayerRelations(object->getOwner(), LOCPLINT->playerID) == PlayerRelations::ALLIES)
+	if (GAME->interface()->cb->getPlayerRelations(object->getOwner(), GAME->interface()->playerID) == PlayerRelations::ALLIES)
 		return { 0, 128, 255};
 
 	if (object->getOwner().isValidPlayer())
@@ -307,7 +308,7 @@ ColorRGBA MapRendererAdventureContext::overlayTextColor(const int3 & coordinates
 	if (object->ID == MapObjectID::MONSTER)
 		return { 255, 0, 0};
 
-	auto hero = LOCPLINT->localState->getCurrentHero();
+	auto hero = GAME->interface()->localState->getCurrentHero();
 
 	if (hero)
 	{
@@ -316,7 +317,7 @@ ColorRGBA MapRendererAdventureContext::overlayTextColor(const int3 & coordinates
 	}
 	else
 	{
-		if (object->wasVisited(LOCPLINT->playerID))
+		if (object->wasVisited(GAME->interface()->playerID))
 			return { 160, 160, 160 };
 	}
 
@@ -353,7 +354,7 @@ bool MapRendererAdventureContext::showSpellRange(const int3 & position) const
 	if (!settingSpellRange)
 		return false;
 
-	auto hero = LOCPLINT->localState->getCurrentHero();
+	auto hero = GAME->interface()->localState->getCurrentHero();
 
 	if (!hero)
 		return false;
@@ -586,7 +587,7 @@ double MapRendererPuzzleMapContext::objectTransparency(ObjectInstanceID objectID
 
 bool MapRendererPuzzleMapContext::isVisible(const int3 & coordinates) const
 {
-	return LOCPLINT->cb->isInTheMap(coordinates);
+	return GAME->interface()->cb->isInTheMap(coordinates);
 }
 
 bool MapRendererPuzzleMapContext::filterGrayscale() const

+ 9 - 8
client/mapView/MapRendererContextState.cpp

@@ -16,6 +16,7 @@
 
 #include "../../CCallback.h"
 #include "../CPlayerInterface.h"
+#include "../GameInstance.h"
 #include "../adventureMap/AdventureMapInterface.h"
 
 #include "../../lib/mapObjects/CGHeroInstance.h"
@@ -24,17 +25,17 @@
 static bool compareObjectBlitOrder(ObjectInstanceID left, ObjectInstanceID right)
 {
 	//FIXME: remove mh access
-	return MAPHANDLER->compareObjectBlitOrder(MAPHANDLER->getMap()->objects[left.getNum()], MAPHANDLER->getMap()->objects[right.getNum()]);
+	return GAME->map().compareObjectBlitOrder(GAME->map().getMap()->objects[left.getNum()], GAME->map().getMap()->objects[right.getNum()]);
 }
 
 MapRendererContextState::MapRendererContextState()
 {
-	auto mapSize = LOCPLINT->cb->getMapSize();
+	auto mapSize = GAME->interface()->cb->getMapSize();
 
 	objects.resize(boost::extents[mapSize.z][mapSize.x][mapSize.y]);
 
 	logGlobal->debug("Loading map objects");
-	for(const auto & obj : MAPHANDLER->getMap()->objects)
+	for(const auto & obj : GAME->map().getMap()->objects)
 		addObject(obj);
 	logGlobal->debug("Done loading map objects");
 }
@@ -50,7 +51,7 @@ void MapRendererContextState::addObject(const CGObjectInstance * obj)
 		{
 			int3 currTile(obj->anchorPos().x - fx, obj->anchorPos().y - fy, obj->anchorPos().z);
 
-			if(LOCPLINT->cb->isInTheMap(currTile) && obj->coveringAt(currTile))
+			if(GAME->interface()->cb->isInTheMap(currTile) && obj->coveringAt(currTile))
 			{
 				auto & container = objects[currTile.z][currTile.x][currTile.y];
 				auto position = std::upper_bound(container.begin(), container.end(), obj->id, compareObjectBlitOrder);
@@ -73,7 +74,7 @@ void MapRendererContextState::addMovingObject(const CGObjectInstance * object, c
 		{
 			int3 currTile(x, y, object->anchorPos().z);
 
-			if(LOCPLINT->cb->isInTheMap(currTile))
+			if(GAME->interface()->cb->isInTheMap(currTile))
 			{
 				auto & container = objects[currTile.z][currTile.x][currTile.y];
 
@@ -86,8 +87,8 @@ void MapRendererContextState::addMovingObject(const CGObjectInstance * object, c
 
 void MapRendererContextState::removeObject(const CGObjectInstance * object)
 {
-	for(int z = 0; z < LOCPLINT->cb->getMapSize().z; z++)
-		for(int x = 0; x < LOCPLINT->cb->getMapSize().x; x++)
-			for(int y = 0; y < LOCPLINT->cb->getMapSize().y; y++)
+	for(int z = 0; z < GAME->interface()->cb->getMapSize().z; z++)
+		for(int x = 0; x < GAME->interface()->cb->getMapSize().x; x++)
+			for(int y = 0; y < GAME->interface()->cb->getMapSize().y; y++)
 				vstd::erase(objects[z][x][y], object->id);
 }

+ 2 - 1
client/mapView/MapView.cpp

@@ -20,6 +20,7 @@
 #include "../CPlayerInterface.h"
 #include "../adventureMap/AdventureMapInterface.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../render/CAnimation.h"
 #include "../render/Canvas.h"
 #include "../render/IImage.h"
@@ -113,7 +114,7 @@ MapView::MapView(const Point & offset, const Point & dimensions)
 
 void MapView::onMapLevelSwitched()
 {
-	if(LOCPLINT->cb->getMapSize().z > 1)
+	if(GAME->interface()->cb->getMapSize().z > 1)
 	{
 		if(model->getLevel() == 0)
 			controller->setViewCenter(model->getMapViewCenter(), 1);

+ 13 - 12
client/mapView/MapViewController.cpp

@@ -20,6 +20,7 @@
 #include "../CPlayerInterface.h"
 #include "../adventureMap/AdventureMapInterface.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/WindowHandler.h"
 #include "../eventsSDL/InputHandler.h"
 
@@ -174,7 +175,7 @@ void MapViewController::tick(uint32_t timeDelta)
 		if(!hero)
 			hero = boat->hero;
 
-		double heroMoveTime = LOCPLINT->playerID == hero->getOwner() ?
+		double heroMoveTime = GAME->interface()->playerID == hero->getOwner() ?
 			settings["adventure"]["heroMoveTime"].Float() :
 			settings["adventure"]["enemyMoveTime"].Float();
 
@@ -285,10 +286,10 @@ bool MapViewController::isEventInstant(const CGObjectInstance * obj, const Playe
 	if (!initiator.isValidPlayer())
 		return true; // skip effects such as new monsters on new month
 
-	if(initiator != LOCPLINT->playerID && settings["adventure"]["enemyMoveTime"].Float() <= 0)
+	if(initiator != GAME->interface()->playerID && settings["adventure"]["enemyMoveTime"].Float() <= 0)
 		return true; // instant movement speed
 
-	if(initiator == LOCPLINT->playerID && settings["adventure"]["heroMoveTime"].Float() <= 0)
+	if(initiator == GAME->interface()->playerID && settings["adventure"]["heroMoveTime"].Float() <= 0)
 		return true; // instant movement speed
 
 	return false;
@@ -299,18 +300,18 @@ bool MapViewController::isEventVisible(const CGObjectInstance * obj, const Playe
 	if(adventureContext == nullptr)
 		return false;
 
-	if(initiator != LOCPLINT->playerID && settings["adventure"]["enemyMoveTime"].Float() < 0)
+	if(initiator != GAME->interface()->playerID && settings["adventure"]["enemyMoveTime"].Float() < 0)
 		return false; // enemy move speed set to "hidden/none"
 
 	if(!ENGINE->windows().isTopWindow(adventureInt))
 		return false;
 
 	// do not focus on actions of other players except for AI with simturns off
-	if (initiator != LOCPLINT->playerID && initiator.isValidPlayer())
+	if (initiator != GAME->interface()->playerID && initiator.isValidPlayer())
 	{
-		if (LOCPLINT->makingTurn)
+		if (GAME->interface()->makingTurn)
 			return false;
-		if (LOCPLINT->cb->getStartInfo()->playerInfos.at(initiator).isControlledByHuman() && !settings["session"]["adventureTrackHero"].Bool())
+		if (GAME->interface()->cb->getStartInfo()->playerInfos.at(initiator).isControlledByHuman() && !settings["session"]["adventureTrackHero"].Bool())
 			return false;
 	}
 
@@ -325,18 +326,18 @@ bool MapViewController::isEventVisible(const CGHeroInstance * obj, const int3 &
 	if(adventureContext == nullptr)
 		return false;
 
-	if(obj->getOwner() != LOCPLINT->playerID && settings["adventure"]["enemyMoveTime"].Float() < 0)
+	if(obj->getOwner() != GAME->interface()->playerID && settings["adventure"]["enemyMoveTime"].Float() < 0)
 		return false; // enemy move speed set to "hidden/none"
 
 	if(!ENGINE->windows().isTopWindow(adventureInt))
 		return false;
 
 	// do not focus on actions of other players except for AI with simturns off
-	if (obj->getOwner() != LOCPLINT->playerID)
+	if (obj->getOwner() != GAME->interface()->playerID)
 	{
-		if (LOCPLINT->makingTurn)
+		if (GAME->interface()->makingTurn)
 			return false;
-		if (LOCPLINT->cb->getStartInfo()->playerInfos.at(obj->getOwner()).isControlledByHuman() && !settings["session"]["adventureTrackHero"].Bool())
+		if (GAME->interface()->cb->getStartInfo()->playerInfos.at(obj->getOwner()).isControlledByHuman() && !settings["session"]["adventureTrackHero"].Bool())
 			return false;
 	}
 
@@ -542,7 +543,7 @@ void MapViewController::onHeroMoved(const CGHeroInstance * obj, const int3 & fro
 		return;
 	}
 
-	double movementTime = LOCPLINT->playerID == obj->tempOwner ?
+	double movementTime = GAME->interface()->playerID == obj->tempOwner ?
 		settings["adventure"]["heroMoveTime"].Float() :
 		settings["adventure"]["enemyMoveTime"].Float();
 

+ 4 - 3
client/mapView/mapHandler.cpp

@@ -15,6 +15,7 @@
 #include "../CCallback.h"
 #include "../CPlayerInterface.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 
 #include "../../lib/texts/CGeneralTextHandler.h"
 #include "../../lib/TerrainHandler.h"
@@ -67,7 +68,7 @@ std::string CMapHandler::getTerrainDescr(const int3 & pos, bool rightClick) cons
 		}
 	}
 
-	if(LOCPLINT->cb->getTileDigStatus(pos, false) == EDiggingStatus::CAN_DIG)
+	if(GAME->interface()->cb->getTileDigStatus(pos, false) == EDiggingStatus::CAN_DIG)
 	{
 		return boost::str(
 			boost::format(rightClick ? "%s\r\n%s" : "%s %s") // New line for the Message Box, space for the Status Bar
@@ -236,11 +237,11 @@ void CMapHandler::removeMapObserver(IMapObjectObserver * object)
 
 IMapObjectObserver::IMapObjectObserver()
 {
-	MAPHANDLER->addMapObserver(this);
+	GAME->map().addMapObserver(this);
 }
 
 IMapObjectObserver::~IMapObjectObserver()
 {
 	if (VLC && MAPHANDLER)
-		MAPHANDLER->removeMapObserver(this);
+		GAME->map().removeMapObserver(this);
 }

+ 0 - 2
client/mapView/mapHandler.h

@@ -75,5 +75,3 @@ public:
 
 	static bool compareObjectBlitOrder(const CGObjectInstance * a, const CGObjectInstance * b);
 };
-
-extern std::unique_ptr<CMapHandler> MAPHANDLER;

+ 3 - 2
client/widgets/Buttons.cpp

@@ -18,6 +18,7 @@
 #include "../battle/BattleInterfaceClasses.h"
 #include "../eventsSDL/InputHandler.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/MouseButton.h"
 #include "../gui/Shortcut.h"
 #include "../gui/InterfaceObjectConfigurable.h"
@@ -100,7 +101,7 @@ void ButtonBase::setImage(const AnimationPath & defName, bool playerColoredButto
 	pos = image->pos;
 
 	if (playerColoredButton)
-		image->setPlayerColor(LOCPLINT->playerID);
+		image->setPlayerColor(GAME->interface()->playerID);
 }
 
 const JsonNode & ButtonBase::getCurrentConfig() const
@@ -135,7 +136,7 @@ void ButtonBase::setConfigurable(const JsonPath & jsonName, bool playerColoredBu
 	pos = configurable->pos;
 
 	if (playerColoredButton)
-		image->setPlayerColor(LOCPLINT->playerID);
+		image->setPlayerColor(GAME->interface()->playerID);
 }
 
 void CButton::addHoverText(EButtonState state, const std::string & text)

+ 3 - 2
client/widgets/CArtifactsOfHeroBackpack.cpp

@@ -11,6 +11,7 @@
 #include "CArtifactsOfHeroBackpack.h"
 
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 
 #include "Images.h"
 #include "IGameSettings.h"
@@ -34,7 +35,7 @@ CArtifactsOfHeroBackpack::CArtifactsOfHeroBackpack(size_t slotsColumnsMax, size_
 CArtifactsOfHeroBackpack::CArtifactsOfHeroBackpack()
 	: CArtifactsOfHeroBackpack(8, 8)
 {
-	const auto backpackCap = LOCPLINT->cb->getSettings().getInteger(EGameSettings::HEROES_BACKPACK_CAP);
+	const auto backpackCap = GAME->interface()->cb->getSettings().getInteger(EGameSettings::HEROES_BACKPACK_CAP);
 	auto visibleCapacityMax = slotsRowsMax * slotsColumnsMax;
 	if(backpackCap >= 0)
 		visibleCapacityMax = visibleCapacityMax > backpackCap ? backpackCap : visibleCapacityMax;
@@ -203,5 +204,5 @@ void CArtifactsOfHeroQuickBackpack::swapSelected()
 			break;
 		}
 	if(backpackLoc.slot != ArtifactPosition::PRE_FIRST && filterBySlot != ArtifactPosition::PRE_FIRST && curHero)
-		LOCPLINT->cb->swapArtifacts(backpackLoc, ArtifactLocation(curHero->id, filterBySlot));
+		GAME->interface()->cb->swapArtifacts(backpackLoc, ArtifactLocation(curHero->id, filterBySlot));
 }

+ 4 - 3
client/widgets/CArtifactsOfHeroBase.cpp

@@ -11,6 +11,7 @@
 #include "CArtifactsOfHeroBase.h"
 
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 
 #include "Buttons.h"
@@ -35,11 +36,11 @@ void CArtifactsOfHeroBase::putBackPickedArtifact()
 		auto slot = ArtifactUtils::getArtAnyPosition(curHero, art->getTypeId());
 		if(slot == ArtifactPosition::PRE_FIRST)
 		{
-			LOCPLINT->cb->eraseArtifactByClient(ArtifactLocation(curHero->id, ArtifactPosition::TRANSITION_POS));
+			GAME->interface()->cb->eraseArtifactByClient(ArtifactLocation(curHero->id, ArtifactPosition::TRANSITION_POS));
 		}
 		else
 		{
-			LOCPLINT->cb->swapArtifacts(ArtifactLocation(curHero->id, ArtifactPosition::TRANSITION_POS), ArtifactLocation(curHero->id, slot));
+			GAME->interface()->cb->swapArtifacts(ArtifactLocation(curHero->id, ArtifactPosition::TRANSITION_POS), ArtifactLocation(curHero->id, slot));
 		}
 	}
 }
@@ -155,7 +156,7 @@ const CGHeroInstance * CArtifactsOfHeroBase::getHero() const
 
 void CArtifactsOfHeroBase::scrollBackpack(bool left)
 {
-	LOCPLINT->cb->scrollBackpackArtifacts(curHero->id, left);
+	GAME->interface()->cb->scrollBackpackArtifacts(curHero->id, left);
 }
 
 void CArtifactsOfHeroBase::markPossibleSlots(const CArtifact * art, bool assumeDestRemoved)

+ 3 - 2
client/widgets/CArtifactsOfHeroMain.cpp

@@ -11,6 +11,7 @@
 #include "CArtifactsOfHeroMain.h"
 
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 
 #include "../CPlayerInterface.h"
 #include "../../lib/mapObjects/CGHeroInstance.h"
@@ -42,14 +43,14 @@ void CArtifactsOfHeroMain::keyPressed(EShortcut key)
 		if (saveIdx != -1)
 		{
 			shortcutPressed = true;
-			LOCPLINT->cb->manageHeroCostume(getHero()->id, saveIdx, true);
+			GAME->interface()->cb->manageHeroCostume(getHero()->id, saveIdx, true);
 			return;
 		}
 
 		if (loadIdx != -1)
 		{
 			shortcutPressed = true;
-			LOCPLINT->cb->manageHeroCostume(getHero()->id, loadIdx, false);
+			GAME->interface()->cb->manageHeroCostume(getHero()->id, loadIdx, false);
 			return;
 		}
 	}

+ 4 - 3
client/widgets/CComponentHolder.cpp

@@ -11,6 +11,7 @@
 #include "CComponentHolder.h"
 
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 
 #include "CComponent.h"
@@ -167,7 +168,7 @@ void CCommanderArtPlace::returnArtToHeroCallback()
 	ArtifactPosition freeSlot = ArtifactUtils::getArtBackpackPosition(commanderOwner, getArtifactId());
 	if(freeSlot == ArtifactPosition::PRE_FIRST)
 	{
-		LOCPLINT->showInfoDialog(VLC->generaltexth->translate("core.genrltxt.152"));
+		GAME->interface()->showInfoDialog(VLC->generaltexth->translate("core.genrltxt.152"));
 	}
 	else
 	{
@@ -177,7 +178,7 @@ void CCommanderArtPlace::returnArtToHeroCallback()
 
 		if(getArtifactId().toArtifact()->canBePutAt(commanderOwner, freeSlot, true))
 		{
-			LOCPLINT->cb->swapArtifacts(src, dst);
+			GAME->interface()->cb->swapArtifacts(src, dst);
 			setArtifact(ArtifactID(ArtifactID::NONE));
 			parent->redraw();
 		}
@@ -187,7 +188,7 @@ void CCommanderArtPlace::returnArtToHeroCallback()
 void CCommanderArtPlace::clickPressed(const Point & cursorPosition)
 {
 	if(getArtifactId() != ArtifactID::NONE && text.size())
-		LOCPLINT->showYesNoDialog(VLC->generaltexth->translate("vcmi.commanderWindow.artifactMessage"), [this]() { returnArtToHeroCallback(); }, []() {});
+		GAME->interface()->showYesNoDialog(VLC->generaltexth->translate("vcmi.commanderWindow.artifactMessage"), [this]() { returnArtToHeroCallback(); }, []() {});
 }
 
 void CCommanderArtPlace::showPopupWindow(const Point & cursorPosition)

+ 12 - 11
client/widgets/CExchangeController.cpp

@@ -11,6 +11,7 @@
 #include "CExchangeController.h"
 
 #include "../CPlayerInterface.h"
+#include "../GameInstance.h"
 
 #include "../widgets/CGarrisonInt.h"
 
@@ -19,8 +20,8 @@
 #include "../lib/mapObjects/CGHeroInstance.h"
 
 CExchangeController::CExchangeController(ObjectInstanceID hero1, ObjectInstanceID hero2)
-	: left(LOCPLINT->cb->getHero(hero1))
-	, right(LOCPLINT->cb->getHero(hero2))
+	: left(GAME->interface()->cb->getHero(hero1))
+	, right(GAME->interface()->cb->getHero(hero2))
 {
 }
 
@@ -40,7 +41,7 @@ void CExchangeController::swapArmy()
 
 	for(; i != leftSlots.end() && j != rightSlots.end(); i++, j++)
 	{
-		LOCPLINT->cb->swapCreatures(left, right, i->first, j->first);
+		GAME->interface()->cb->swapCreatures(left, right, i->first, j->first);
 	}
 
 	if(i != leftSlots.end())
@@ -50,7 +51,7 @@ void CExchangeController::swapArmy()
 
 		for(; i != leftSlots.end() && slot != freeSlots.end(); i++, slot++)
 		{
-			LOCPLINT->cb->swapCreatures(left, right, i->first, *slot);
+			GAME->interface()->cb->swapCreatures(left, right, i->first, *slot);
 		}
 	}
 	else if(j != rightSlots.end())
@@ -60,7 +61,7 @@ void CExchangeController::swapArmy()
 
 		for(; j != rightSlots.end() && slot != freeSlots.end(); j++, slot++)
 		{
-			LOCPLINT->cb->swapCreatures(left, right, *slot, j->first);
+			GAME->interface()->cb->swapCreatures(left, right, *slot, j->first);
 		}
 	}
 }
@@ -83,7 +84,7 @@ void CExchangeController::moveArmy(bool leftToRight, std::optional<SlotID> heldS
 	if (source->getCreature(heldSlot.value()) == nullptr)
 		return;
 
-	LOCPLINT->cb->bulkMoveArmy(source->id, target->id, heldSlot.value());
+	GAME->interface()->cb->bulkMoveArmy(source->id, target->id, heldSlot.value());
 }
 
 void CExchangeController::moveStack(bool leftToRight, SlotID sourceSlot)
@@ -100,12 +101,12 @@ void CExchangeController::moveStack(bool leftToRight, SlotID sourceSlot)
 	{
 		if(source->stacksCount() == 1 && source->needsLastStack())
 		{
-			LOCPLINT->cb->splitStack(source, target, sourceSlot, targetSlot,
+			GAME->interface()->cb->splitStack(source, target, sourceSlot, targetSlot,
 				target->getStackCount(targetSlot) + source->getStackCount(sourceSlot) - 1);
 		}
 		else
 		{
-			LOCPLINT->cb->mergeOrSwapStacks(source, target, sourceSlot, targetSlot);
+			GAME->interface()->cb->mergeOrSwapStacks(source, target, sourceSlot, targetSlot);
 		}
 	}
 }
@@ -122,13 +123,13 @@ void CExchangeController::moveSingleStackCreature(bool leftToRight, SlotID sourc
 	SlotID targetSlot = forceEmptySlotTarget ? target->getFreeSlot() : target->getSlotFor(creature);
 	if(targetSlot.validSlot())
 	{
-		LOCPLINT->cb->splitStack(source, target, sourceSlot, targetSlot, target->getStackCount(targetSlot) + 1);
+		GAME->interface()->cb->splitStack(source, target, sourceSlot, targetSlot, target->getStackCount(targetSlot) + 1);
 	}
 }
 
 void CExchangeController::swapArtifacts(bool equipped, bool baclpack)
 {
-	LOCPLINT->cb->bulkMoveArtifacts(left->id, right->id, true, equipped, baclpack);
+	GAME->interface()->cb->bulkMoveArtifacts(left->id, right->id, true, equipped, baclpack);
 }
 
 void CExchangeController::moveArtifacts(bool leftToRight, bool equipped, bool baclpack)
@@ -136,5 +137,5 @@ void CExchangeController::moveArtifacts(bool leftToRight, bool equipped, bool ba
 	const auto source = leftToRight ? left : right;
 	const auto target = leftToRight ? right : left;
 
-	LOCPLINT->cb->bulkMoveArtifacts(source->id, target->id, false, equipped, baclpack);
+	GAME->interface()->cb->bulkMoveArtifacts(source->id, target->id, false, equipped, baclpack);
 }

+ 22 - 21
client/widgets/CGarrisonInt.cpp

@@ -15,6 +15,7 @@
 #include "RadialMenu.h"
 
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/WindowHandler.h"
 #include "../render/IImage.h"
 #include "../windows/CCreatureWindow.h"
@@ -143,18 +144,18 @@ bool CGarrisonSlot::ally() const
 	if(!getObj())
 		return false;
 
-	return PlayerRelations::ALLIES == LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, getObj()->tempOwner);
+	return PlayerRelations::ALLIES == GAME->interface()->cb->getPlayerRelations(GAME->interface()->playerID, getObj()->tempOwner);
 }
 
 std::function<void()> CGarrisonSlot::getDismiss() const
 {
-	const bool canDismiss = getObj()->tempOwner == LOCPLINT->playerID
+	const bool canDismiss = getObj()->tempOwner == GAME->interface()->playerID
 		&& (getObj()->stacksCount() > 1 ||
 			!getObj()->needsLastStack());
 
 	return canDismiss ? [=]()
 	{
-		LOCPLINT->cb->dismissCreature(getObj(), ID);
+		GAME->interface()->cb->dismissCreature(getObj(), ID);
 	} : (std::function<void()>)nullptr;
 }
 
@@ -163,12 +164,12 @@ std::function<void()> CGarrisonSlot::getDismiss() const
 bool CGarrisonSlot::viewInfo()
 {
 	UpgradeInfo pom(ID.getNum());
-	LOCPLINT->cb->fillUpgradeInfo(getObj(), ID, pom);
+	GAME->interface()->cb->fillUpgradeInfo(getObj(), ID, pom);
 
-	bool canUpgrade = getObj()->tempOwner == LOCPLINT->playerID && pom.canUpgrade(); //upgrade is possible
+	bool canUpgrade = getObj()->tempOwner == GAME->interface()->playerID && pom.canUpgrade(); //upgrade is possible
 	std::function<void(CreatureID)> upgr = nullptr;
 	auto dism = getDismiss();
-	if(canUpgrade) upgr = [=] (CreatureID newID) { LOCPLINT->cb->upgradeCreature(getObj(), ID, newID); };
+	if(canUpgrade) upgr = [=] (CreatureID newID) { GAME->interface()->cb->upgradeCreature(getObj(), ID, newID); };
 
 	owner->selectSlot(nullptr);
 	owner->setSplittingMode(false);
@@ -206,10 +207,10 @@ bool CGarrisonSlot::highlightOrDropArtifact()
 					{
 						//creature can wear only one active artifact
 						//if we are placing a new one, the old one will be returned to the hero's backpack
-						LOCPLINT->cb->swapArtifacts(dst, ArtifactLocation(srcHero->id,
+						GAME->interface()->cb->swapArtifacts(dst, ArtifactLocation(srcHero->id,
 							ArtifactUtils::getArtBackpackPosition(srcHero, dstArt->getTypeId())));
 					}
-					LOCPLINT->cb->swapArtifacts(src, dst);
+					GAME->interface()->cb->swapArtifacts(src, dst);
 				}
 			}
 		}
@@ -271,7 +272,7 @@ bool CGarrisonSlot::mustForceReselection() const
 	bool withAlly = selection->our() ^ our();
 
 	// not our turn - actions are blocked
-	if (!LOCPLINT->makingTurn)
+	if (!GAME->interface()->makingTurn)
 		return true;
 
 	// Attempt to take creatures from ally (select theirs first)
@@ -343,13 +344,13 @@ void CGarrisonSlot::clickPressed(const Point & cursorPosition)
 				refr = split();
 			}
 			else if(!creature && lastHeroStackSelected) // split all except last creature
-				LOCPLINT->cb->splitStack(selectedObj, owner->army(upg), selection->ID, ID, selection->myStack->count - 1);
+				GAME->interface()->cb->splitStack(selectedObj, owner->army(upg), selection->ID, ID, selection->myStack->count - 1);
 			else if(creature != selection->creature) // swap
-				LOCPLINT->cb->swapCreatures(owner->army(upg), selectedObj, ID, selection->ID);
+				GAME->interface()->cb->swapCreatures(owner->army(upg), selectedObj, ID, selection->ID);
 			else if(lastHeroStackSelected) // merge last stack to other hero stack
 				refr = split();
 			else // merge
-				LOCPLINT->cb->mergeStacks(selectedObj, owner->army(upg), selection->ID, ID);
+				GAME->interface()->cb->mergeStacks(selectedObj, owner->army(upg), selection->ID, ID);
 		}
 		if(refr)
 		{
@@ -513,7 +514,7 @@ bool CGarrisonSlot::handleSplittingShortcuts()
 	{
 		auto dismiss = getDismiss();
 		if(dismiss)
-			LOCPLINT->showYesNoDialog(VLC->generaltexth->allTexts[12], dismiss, nullptr);
+			GAME->interface()->showYesNoDialog(VLC->generaltexth->allTexts[12], dismiss, nullptr);
 	}
 	else if(isAlt)
 	{
@@ -596,7 +597,7 @@ void CGarrisonInt::splitClick()
 
 void CGarrisonInt::splitStacks(const CGarrisonSlot * from, const CArmedInstance * armyDest, SlotID slotDest, int amount )
 {
-	LOCPLINT->cb->splitStack(armedObjs[from->upg], armyDest, from->ID, slotDest, amount);
+	GAME->interface()->cb->splitStack(armedObjs[from->upg], armyDest, from->ID, slotDest, amount);
 }
 
 bool CGarrisonInt::checkSelected(const CGarrisonSlot * selected, TQuantity min) const
@@ -640,11 +641,11 @@ void CGarrisonInt::moveStackToAnotherArmy(const CGarrisonSlot * selected)
 	if(!isDestSlotEmpty || isLastStack)
 	{
 		srcAmount += destArmy->getStackCount(destSlot); // Due to 'split' implementation in the 'CGameHandler::arrangeStacks'
-		LOCPLINT->cb->splitStack(srcArmy, destArmy, srcSlot, destSlot, srcAmount);
+		GAME->interface()->cb->splitStack(srcArmy, destArmy, srcSlot, destSlot, srcAmount);
 	}
 	else
 	{
-		LOCPLINT->cb->swapCreatures(srcArmy, destArmy, srcSlot, destSlot);
+		GAME->interface()->cb->swapCreatures(srcArmy, destArmy, srcSlot, destSlot);
 	}
 }
 
@@ -665,7 +666,7 @@ void CGarrisonInt::bulkMoveArmy(const CGarrisonSlot * selected)
 		return;
 
 	const auto srcSlot = selected->ID;
-	LOCPLINT->cb->bulkMoveArmy(srcArmy->id, destArmy->id, srcSlot);
+	GAME->interface()->cb->bulkMoveArmy(srcArmy->id, destArmy->id, srcSlot);
 }
 
 void CGarrisonInt::bulkMergeStacks(const CGarrisonSlot * selected)
@@ -678,7 +679,7 @@ void CGarrisonInt::bulkMergeStacks(const CGarrisonSlot * selected)
 	if(!armedObjs[type]->hasCreatureSlots(selected->creature, selected->ID))
 		return;
 
-	LOCPLINT->cb->bulkMergeStacks(armedObjs[type]->id, selected->ID);
+	GAME->interface()->cb->bulkMergeStacks(armedObjs[type]->id, selected->ID);
 }
 
 void CGarrisonInt::bulkSplitStack(const CGarrisonSlot * selected)
@@ -691,7 +692,7 @@ void CGarrisonInt::bulkSplitStack(const CGarrisonSlot * selected)
 	if(!hasEmptySlot(type))
 		return;
 
-	LOCPLINT->cb->bulkSplitStack(armedObjs[type]->id, selected->ID);
+	GAME->interface()->cb->bulkSplitStack(armedObjs[type]->id, selected->ID);
 }
 
 void CGarrisonInt::bulkSmartSplitStack(const CGarrisonSlot * selected)
@@ -705,7 +706,7 @@ void CGarrisonInt::bulkSmartSplitStack(const CGarrisonSlot * selected)
 	if(!hasEmptySlot(type) && armedObjs[type]->isCreatureBalanced(selected->creature))
 		return;
 
-	LOCPLINT->cb->bulkSmartSplitStack(armedObjs[type]->id, selected->ID);
+	GAME->interface()->cb->bulkSmartSplitStack(armedObjs[type]->id, selected->ID);
 }
 
 CGarrisonInt::CGarrisonInt(const Point & position, int inx, const Point & garsOffset, const CArmedInstance * s1, const CArmedInstance * s2, bool _removableUnits, bool smallImgs, ESlotsLayout _layout)
@@ -801,7 +802,7 @@ bool CGarrisonInt::isArmyOwned(EGarrisonType which) const
 	if (!object)
 		return false;
 
-	if (object->tempOwner == LOCPLINT->playerID)
+	if (object->tempOwner == GAME->interface()->playerID)
 		return true;
 
 	if (object->tempOwner == PlayerColor::UNFLAGGABLE)

+ 25 - 24
client/widgets/MiscWidgets.cpp

@@ -13,6 +13,7 @@
 #include "CComponent.h"
 
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/CursorHandler.h"
 
 #include "../CMT.h"
@@ -60,7 +61,7 @@ CHoverableArea::~CHoverableArea()
 void LRClickableAreaWText::clickPressed(const Point & cursorPosition)
 {
 	if(!text.empty())
-		LOCPLINT->showInfoDialog(text);
+		GAME->interface()->showInfoDialog(text);
 }
 void LRClickableAreaWText::showPopupWindow(const Point & cursorPosition)
 {
@@ -93,7 +94,7 @@ void LRClickableAreaWText::init()
 void LRClickableAreaWTextComp::clickPressed(const Point & cursorPosition)
 {
 	std::vector<std::shared_ptr<CComponent>> comp(1, createComponent());
-	LOCPLINT->showInfoDialog(text, comp);
+	GAME->interface()->showInfoDialog(text, comp);
 }
 
 LRClickableAreaWTextComp::LRClickableAreaWTextComp(const Rect &Pos, ComponentType BaseType)
@@ -139,7 +140,7 @@ CHeroArea::CHeroArea(int x, int y, const CGHeroInstance * hero)
 		portrait = std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsLarge"), hero->getIconIndex());
 		clickFunctor = [hero]() -> void
 		{
-			LOCPLINT->openHeroWindow(hero);
+			GAME->interface()->openHeroWindow(hero);
 		};
 	}
 }
@@ -177,7 +178,7 @@ void CHeroArea::hover(bool on)
 void LRClickableAreaOpenTown::clickPressed(const Point & cursorPosition)
 {
 	if(town)
-		LOCPLINT->openTownWindow(town);
+		GAME->interface()->openTownWindow(town);
 }
 
 LRClickableAreaOpenTown::LRClickableAreaOpenTown(const Rect & Pos, const CGTownInstance * Town)
@@ -215,9 +216,9 @@ std::string CMinorResDataBar::buildDateString()
 	std::string pattern = "%s: %d, %s: %d, %s: %d";
 
 	auto formatted = boost::format(pattern)
-		% VLC->generaltexth->translate("core.genrltxt.62") % LOCPLINT->cb->getDate(Date::MONTH)
-		% VLC->generaltexth->translate("core.genrltxt.63") % LOCPLINT->cb->getDate(Date::WEEK)
-		% VLC->generaltexth->translate("core.genrltxt.64") % LOCPLINT->cb->getDate(Date::DAY_OF_WEEK);
+		% VLC->generaltexth->translate("core.genrltxt.62") % GAME->interface()->cb->getDate(Date::MONTH)
+		% VLC->generaltexth->translate("core.genrltxt.63") % GAME->interface()->cb->getDate(Date::WEEK)
+		% VLC->generaltexth->translate("core.genrltxt.64") % GAME->interface()->cb->getDate(Date::DAY_OF_WEEK);
 
 	return boost::str(formatted);
 }
@@ -228,7 +229,7 @@ void CMinorResDataBar::showAll(Canvas & to)
 
 	for (GameResID i=EGameResID::WOOD; i<=EGameResID::GOLD; ++i)
 	{
-		std::string text = std::to_string(LOCPLINT->cb->getResourceAmount(i));
+		std::string text = std::to_string(GAME->interface()->cb->getResourceAmount(i));
 
 		Point target(pos.x + 50 + 76 * GameResID(i), pos.y + pos.h/2);
 
@@ -248,7 +249,7 @@ CMinorResDataBar::CMinorResDataBar()
 	pos.y = 575;
 
 	background = std::make_shared<CPicture>(ImagePath::builtin("KRESBAR.bmp"));
-	background->setPlayerColor(LOCPLINT->playerID);
+	background->setPlayerColor(GAME->interface()->playerID);
 
 	pos.w = background->pos.w;
 	pos.h = background->pos.h;
@@ -387,7 +388,7 @@ void CTownTooltip::init(const InfoAboutTown & town)
 
 	assert(town.tType);
 
-	size_t iconIndex = town.tType->clientInfo.icons[town.fortLevel > 0][town.built >= LOCPLINT->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
+	size_t iconIndex = town.tType->clientInfo.icons[town.fortLevel > 0][town.built >= GAME->interface()->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
 
 	build = std::make_shared<CAnimImage>(AnimationPath::builtin("itpt"), iconIndex, 0, 3, 2);
 
@@ -451,7 +452,7 @@ void CInteractableTownTooltip::init(const CGTownInstance * town)
 	fort = std::make_shared<CAnimImage>(AnimationPath::builtin("ITMCLS"), fortIndex, 0, 105, 31);
 	fastArmyPurchase = std::make_shared<LRClickableArea>(Rect(105, 31, 34, 34), [townId]()
 	{
-		std::vector<const CGTownInstance*> towns = LOCPLINT->cb->getTownsInfo(true);
+		std::vector<const CGTownInstance*> towns = GAME->interface()->cb->getTownsInfo(true);
 		for(auto & town : towns)
 		{
 			if(town->id == townId)
@@ -460,11 +461,11 @@ void CInteractableTownTooltip::init(const CGTownInstance * town)
 	});
 	fastTavern = std::make_shared<LRClickableArea>(Rect(3, 2, 58, 64), [townId]()
 	{
-		std::vector<const CGTownInstance*> towns = LOCPLINT->cb->getTownsInfo(true);
+		std::vector<const CGTownInstance*> towns = GAME->interface()->cb->getTownsInfo(true);
 		for(auto & town : towns)
 		{
 			if(town->id == townId && town->hasBuilt(BuildingID::TAVERN))
-				LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
+				GAME->interface()->showTavernWindow(town, nullptr, QueryID::NONE);
 		}
 	}, [town]{
 		if(!town->getFaction()->getDescriptionTranslated().empty())
@@ -472,7 +473,7 @@ void CInteractableTownTooltip::init(const CGTownInstance * town)
 	});
 	fastMarket = std::make_shared<LRClickableArea>(Rect(143, 31, 30, 34), []()
 	{
-		std::vector<const CGTownInstance*> towns = LOCPLINT->cb->getTownsInfo(true);
+		std::vector<const CGTownInstance*> towns = GAME->interface()->cb->getTownsInfo(true);
 		for(auto & town : towns)
 		{
 			if(town->hasBuilt(BuildingID::MARKETPLACE))
@@ -481,12 +482,12 @@ void CInteractableTownTooltip::init(const CGTownInstance * town)
 				return;
 			}
 		}
-		LOCPLINT->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.noTownWithMarket"));
+		GAME->interface()->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.noTownWithMarket"));
 	});
 
 	assert(townInfo.tType);
 
-	size_t iconIndex = townInfo.tType->clientInfo.icons[townInfo.fortLevel > 0][townInfo.built >= LOCPLINT->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
+	size_t iconIndex = townInfo.tType->clientInfo.icons[townInfo.fortLevel > 0][townInfo.built >= GAME->interface()->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
 
 	build = std::make_shared<CAnimImage>(AnimationPath::builtin("itpt"), iconIndex, 0, 3, 2);
 	title = std::make_shared<CLabel>(66, 2, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, townInfo.name);
@@ -496,7 +497,7 @@ void CInteractableTownTooltip::init(const CGTownInstance * town)
 		hall = std::make_shared<CAnimImage>(AnimationPath::builtin("ITMTLS"), townInfo.details->hallLevel, 0, 67, 31);
 		fastTownHall = std::make_shared<LRClickableArea>(Rect(67, 31, 34, 34), [townId]()
 		{
-			std::vector<const CGTownInstance*> towns = LOCPLINT->cb->getTownsInfo(true);
+			std::vector<const CGTownInstance*> towns = GAME->interface()->cb->getTownsInfo(true);
 			for(auto & town : towns)
 			{
 				if(town->id == townId)
@@ -536,15 +537,15 @@ CreatureTooltip::CreatureTooltip(Point pos, const CGCreature * creature)
 	creatureImage = std::make_shared<CAnimImage>(AnimationPath::builtin("TWCRPORT"), creatureIconIndex);
 	creatureImage->center(Point(parent->pos.x + parent->pos.w / 2, parent->pos.y + creatureImage->pos.h / 2 + 11));
 
-	bool isHeroSelected = LOCPLINT->localState->getCurrentHero() != nullptr;
+	bool isHeroSelected = GAME->interface()->localState->getCurrentHero() != nullptr;
 	std::string textContent = isHeroSelected
-			? creature->getPopupText(LOCPLINT->localState->getCurrentHero())
-			: creature->getPopupText(LOCPLINT->playerID);
+			? creature->getPopupText(GAME->interface()->localState->getCurrentHero())
+			: creature->getPopupText(GAME->interface()->playerID);
 
 	//TODO: window is bigger than OH3
 	//TODO: vertical alignment does not match H3. Commented below example that matches H3 for creatures count but supports only 1 line:
 	/*std::shared_ptr<CLabel> = std::make_shared<CLabel>(parent->pos.w / 2, 103,
-			FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, creature->getHoverText(LOCPLINT->playerID));*/
+			FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, creature->getHoverText(GAME->interface()->playerID));*/
 
 	tooltipTextbox = std::make_shared<CTextBox>(textContent, Rect(15, 95, 230, 150), 0, FONT_SMALL, ETextAlignment::TOPCENTER, Colors::WHITE);
 }
@@ -590,13 +591,13 @@ void MoraleLuckBox::set(const AFactionMember * node)
 	else if(morale && node && node->getBonusBearer()->hasBonusOfType(BonusType::NO_MORALE))
 	{
 		auto noMorale = node->getBonusBearer()->getBonus(Selector::type()(BonusType::NO_MORALE));
-		text += "\n" + noMorale->Description(LOCPLINT->cb.get());
+		text += "\n" + noMorale->Description(GAME->interface()->cb.get());
 		component.value = 0;
 	}
 	else if (!morale && node && node->getBonusBearer()->hasBonusOfType(BonusType::NO_LUCK))
 	{
 		auto noLuck = node->getBonusBearer()->getBonus(Selector::type()(BonusType::NO_LUCK));
-		text += "\n" + noLuck->Description(LOCPLINT->cb.get());
+		text += "\n" + noLuck->Description(GAME->interface()->cb.get());
 		component.value = 0;
 	}
 	else
@@ -605,7 +606,7 @@ void MoraleLuckBox::set(const AFactionMember * node)
 		for(auto & bonus : * modifierList)
 		{
 			if(bonus->val) {
-				const std::string& description = bonus->Description(LOCPLINT->cb.get());
+				const std::string& description = bonus->Description(GAME->interface()->cb.get());
 				//arraytxt already contains \n
 				if (description.size() && description[0] != '\n')
 					addInfo += '\n';

+ 4 - 3
client/widgets/TextControls.cpp

@@ -15,6 +15,7 @@
 
 #include "../CPlayerInterface.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../windows/CMessage.h"
 #include "../windows/InfoWindows.h"
 #include "../adventureMap/CInGameConsole.h"
@@ -546,8 +547,8 @@ void CGStatusBar::show(Canvas & to)
 
 void CGStatusBar::clickPressed(const Point & cursorPosition)
 {
-	if(LOCPLINT && LOCPLINT->cingconsole->isActive())
-		LOCPLINT->cingconsole->startEnteringText();
+	if(GAME->interface() && GAME->interface()->cingconsole->isActive())
+		GAME->interface()->cingconsole->startEnteringText();
 }
 
 void CGStatusBar::activate()
@@ -561,7 +562,7 @@ void CGStatusBar::deactivate()
 	ENGINE->setStatusbar(nullptr);
 
 	if (enteringText)
-		LOCPLINT->cingconsole->endEnteringText(false);
+		GAME->interface()->cingconsole->endEnteringText(false);
 
 	CIntObject::deactivate();
 }

+ 9 - 8
client/widgets/markets/CAltarArtifacts.cpp

@@ -12,6 +12,7 @@
 #include "CAltarArtifacts.h"
 
 #include "../../GameEngine.h"
+#include "../../GameInstance.h"
 #include "../../gui/Shortcut.h"
 #include "../../widgets/Buttons.h"
 #include "../../widgets/TextControls.h"
@@ -102,18 +103,18 @@ void CAltarArtifacts::makeDeal()
 	{
 		positions.push_back(artInst->getId());
 	}
-	LOCPLINT->cb->trade(market->getObjInstanceID(), EMarketMode::ARTIFACT_EXP, positions, std::vector<TradeItemBuy>(), std::vector<ui32>(), hero);
+	GAME->interface()->cb->trade(market->getObjInstanceID(), EMarketMode::ARTIFACT_EXP, positions, std::vector<TradeItemBuy>(), std::vector<ui32>(), hero);
 	deselect();
 }
 
 void CAltarArtifacts::sacrificeAll()
 {
-	LOCPLINT->cb->bulkMoveArtifacts(heroArts->getHero()->id, heroArts->altarId, false, true, true);
+	GAME->interface()->cb->bulkMoveArtifacts(heroArts->getHero()->id, heroArts->altarId, false, true, true);
 }
 
 void CAltarArtifacts::sacrificeBackpack()
 {
-	LOCPLINT->cb->bulkMoveArtifacts(heroArts->getHero()->id, heroArts->altarId, false, false, true);
+	GAME->interface()->cb->bulkMoveArtifacts(heroArts->getHero()->id, heroArts->altarId, false, false, true);
 }
 
 std::shared_ptr<CArtifactsOfHeroAltar> CAltarArtifacts::getAOHset() const
@@ -170,7 +171,7 @@ void CAltarArtifacts::updateAltarSlots()
 	}
 
 	calcExpAltarForHero();
-	deal->block(tradeSlotsMap.empty() || !LOCPLINT->makingTurn);
+	deal->block(tradeSlotsMap.empty() || !GAME->interface()->makingTurn);
 }
 
 void CAltarArtifacts::putBackArtifacts()
@@ -178,7 +179,7 @@ void CAltarArtifacts::putBackArtifacts()
 	// TODO: If the backpack capacity limit is enabled, artifacts may remain on the altar.
 	// Perhaps should be erased in CGameHandler::objectVisitEnded if id of visited object will be available
 	if(!altarArtifactsStorage->artifactsInBackpack.empty())
-		LOCPLINT->cb->bulkMoveArtifacts(heroArts->altarId, heroArts->getHero()->id, false, true, true);
+		GAME->interface()->cb->bulkMoveArtifacts(heroArts->altarId, heroArts->getHero()->id, false, true, true);
 }
 
 CMarketBase::MarketShowcasesParams CAltarArtifacts::getShowcasesParams() const
@@ -204,9 +205,9 @@ void CAltarArtifacts::onSlotClickPressed(const std::shared_ptr<CTradeableItem> &
 			{
 				if(altarSlot->id == -1)
 					tradeSlotsMap.try_emplace(altarSlot, pickedArtInst);
-				deal->block(!LOCPLINT->makingTurn);
+				deal->block(!GAME->interface()->makingTurn);
 
-				LOCPLINT->cb->swapArtifacts(ArtifactLocation(heroArts->getHero()->id, ArtifactPosition::TRANSITION_POS),
+				GAME->interface()->cb->swapArtifacts(ArtifactLocation(heroArts->getHero()->id, ArtifactPosition::TRANSITION_POS),
 					ArtifactLocation(heroArts->altarId, ArtifactPosition::ALTAR));
 			}
 			else
@@ -221,7 +222,7 @@ void CAltarArtifacts::onSlotClickPressed(const std::shared_ptr<CTradeableItem> &
 		assert(tradeSlotsMap.at(altarSlot));
 		const auto slot = altarArtifactsStorage->getArtPos(tradeSlotsMap.at(altarSlot));
 		assert(slot != ArtifactPosition::PRE_FIRST);
-		LOCPLINT->cb->swapArtifacts(ArtifactLocation(heroArts->altarId, slot),
+		GAME->interface()->cb->swapArtifacts(ArtifactLocation(heroArts->altarId, slot),
 			ArtifactLocation(hero->id, ENGINE->isKeyboardCtrlDown() ? ArtifactPosition::FIRST_AVAILABLE : ArtifactPosition::TRANSITION_POS));
 		tradeSlotsMap.erase(altarSlot);
 	}

+ 4 - 3
client/widgets/markets/CAltarCreatures.cpp

@@ -12,6 +12,7 @@
 #include "CAltarCreatures.h"
 
 #include "../../GameEngine.h"
+#include "../../GameInstance.h"
 #include "../../gui/Shortcut.h"
 #include "../../widgets/Buttons.h"
 #include "../../widgets/TextControls.h"
@@ -156,7 +157,7 @@ void CAltarCreatures::makeDeal()
 		}
 	}
 
-	LOCPLINT->cb->trade(market->getObjInstanceID(), EMarketMode::CREATURE_EXP, ids, {}, toSacrifice, hero);
+	GAME->interface()->cb->trade(market->getObjInstanceID(), EMarketMode::CREATURE_EXP, ids, {}, toSacrifice, hero);
 
 	for(int & units : unitsOnAltar)
 		units = 0;
@@ -204,7 +205,7 @@ void CAltarCreatures::sacrificeAll()
 	offerTradePanel->update();
 	updateShowcases();
 
-	deal->block(calcExpAltarForHero() == 0 || !LOCPLINT->makingTurn);
+	deal->block(calcExpAltarForHero() == 0 || !GAME->interface()->makingTurn);
 }
 
 void CAltarCreatures::updateAltarSlot(const std::shared_ptr<CTradeableItem> & slot)
@@ -222,7 +223,7 @@ void CAltarCreatures::onOfferSliderMoved(int newVal)
 		unitsOnAltar[bidTradePanel->highlightedSlot->serial] = newVal;
 	if(offerTradePanel->isHighlighted())
 		updateAltarSlot(offerTradePanel->highlightedSlot);
-	deal->block(calcExpAltarForHero() == 0 || !LOCPLINT->makingTurn);
+	deal->block(calcExpAltarForHero() == 0 || !GAME->interface()->makingTurn);
 	highlightingChanged();
 	redraw();
 }

+ 4 - 3
client/widgets/markets/CArtifactsBuying.cpp

@@ -16,6 +16,7 @@
 #include "../../widgets/TextControls.h"
 
 #include "../../CPlayerInterface.h"
+#include "../../GameInstance.h"
 
 #include "../../../CCallback.h"
 
@@ -67,14 +68,14 @@ void CArtifactsBuying::makeDeal()
 {
 	if(ArtifactID(offerTradePanel->getHighlightedItemId()).toArtifact()->canBePutAt(hero))
 	{
-		LOCPLINT->cb->trade(market->getObjInstanceID(), EMarketMode::RESOURCE_ARTIFACT, GameResID(bidTradePanel->getHighlightedItemId()),
+		GAME->interface()->cb->trade(market->getObjInstanceID(), EMarketMode::RESOURCE_ARTIFACT, GameResID(bidTradePanel->getHighlightedItemId()),
 			ArtifactID(offerTradePanel->getHighlightedItemId()), offerQty, hero);
 		CMarketTraderText::makeDeal();
 		deselect();
 	}
 	else
 	{
-		LOCPLINT->showInfoDialog(VLC->generaltexth->translate("core.genrltxt.326"));
+		GAME->interface()->showInfoDialog(VLC->generaltexth->translate("core.genrltxt.326"));
 	}
 }
 
@@ -95,7 +96,7 @@ void CArtifactsBuying::highlightingChanged()
 	if(bidTradePanel->isHighlighted() && offerTradePanel->isHighlighted())
 	{
 		market->getOffer(bidTradePanel->getHighlightedItemId(), offerTradePanel->getHighlightedItemId(), bidQty, offerQty, EMarketMode::RESOURCE_ARTIFACT);
-		deal->block(LOCPLINT->cb->getResourceAmount(GameResID(bidTradePanel->getHighlightedItemId())) < bidQty || !LOCPLINT->makingTurn);
+		deal->block(GAME->interface()->cb->getResourceAmount(GameResID(bidTradePanel->getHighlightedItemId())) < bidQty || !GAME->interface()->makingTurn);
 	}
 	CMarketBase::highlightingChanged();
 	CMarketTraderText::highlightingChanged();

+ 4 - 3
client/widgets/markets/CArtifactsSelling.cpp

@@ -12,6 +12,7 @@
 #include "CArtifactsSelling.h"
 
 #include "../../GameEngine.h"
+#include "../../GameInstance.h"
 #include "../../gui/Shortcut.h"
 #include "../../widgets/Buttons.h"
 #include "../../widgets/TextControls.h"
@@ -58,7 +59,7 @@ CArtifactsSelling::CArtifactsSelling(const IMarket * market, const CGHeroInstanc
 	heroArts->onClickNotTradableCallback = []()
 	{
 		// This item can't be traded
-		LOCPLINT->showInfoDialog(VLC->generaltexth->allTexts[21]);
+		GAME->interface()->showInfoDialog(VLC->generaltexth->allTexts[21]);
 	};
 	CArtifactsSelling::updateShowcases();
 	CArtifactsSelling::deselect();
@@ -77,7 +78,7 @@ void CArtifactsSelling::makeDeal()
 {
 	const auto art = hero->getArt(selectedHeroSlot);
 	assert(art);
-	LOCPLINT->cb->trade(market->getObjInstanceID(), EMarketMode::ARTIFACT_RESOURCE, art->getId(),
+	GAME->interface()->cb->trade(market->getObjInstanceID(), EMarketMode::ARTIFACT_RESOURCE, art->getId(),
 		GameResID(offerTradePanel->getHighlightedItemId()), offerQty, hero);
 	CMarketTraderText::makeDeal();
 }
@@ -147,7 +148,7 @@ void CArtifactsSelling::highlightingChanged()
 	if(art && offerTradePanel->isHighlighted())
 	{
 		market->getOffer(art->getTypeId(), offerTradePanel->getHighlightedItemId(), bidQty, offerQty, EMarketMode::ARTIFACT_RESOURCE);
-		deal->block(!LOCPLINT->makingTurn);
+		deal->block(!GAME->interface()->makingTurn);
 	}
 	CMarketBase::highlightingChanged();
 	CMarketTraderText::highlightingChanged();

+ 3 - 2
client/widgets/markets/CFreelancerGuild.cpp

@@ -12,6 +12,7 @@
 #include "CFreelancerGuild.h"
 
 #include "../../GameEngine.h"
+#include "../../GameInstance.h"
 #include "../../gui/Shortcut.h"
 #include "../../widgets/Buttons.h"
 #include "../../widgets/TextControls.h"
@@ -68,7 +69,7 @@ void CFreelancerGuild::makeDeal()
 {
 	if(auto toTrade = offerSlider->getValue(); toTrade != 0)
 	{
-		LOCPLINT->cb->trade(market->getObjInstanceID(), EMarketMode::CREATURE_RESOURCE, SlotID(bidTradePanel->highlightedSlot->serial), GameResID(offerTradePanel->getHighlightedItemId()), bidQty * toTrade, hero);
+		GAME->interface()->cb->trade(market->getObjInstanceID(), EMarketMode::CREATURE_RESOURCE, SlotID(bidTradePanel->highlightedSlot->serial), GameResID(offerTradePanel->getHighlightedItemId()), bidQty * toTrade, hero);
 		CMarketTraderText::makeDeal();
 		deselect();
 	}
@@ -95,7 +96,7 @@ void CFreelancerGuild::highlightingChanged()
 		offerSlider->scrollTo(0);
 		offerSlider->block(false);
 		maxAmount->block(false);
-		deal->block(!LOCPLINT->makingTurn);
+		deal->block(!GAME->interface()->makingTurn);
 	}
 	CMarketBase::highlightingChanged();
 	CMarketTraderText::highlightingChanged();

+ 2 - 1
client/widgets/markets/CMarketBase.cpp

@@ -14,6 +14,7 @@
 
 #include "../Images.h"
 #include "../../GameEngine.h"
+#include "../../GameInstance.h"
 #include "../../gui/Shortcut.h"
 #include "../../widgets/Buttons.h"
 #include "../../widgets/TextControls.h"
@@ -188,7 +189,7 @@ CResourcesSelling::CResourcesSelling(const CTradeableItem::ClickPressedFunctor &
 void CResourcesSelling::updateSubtitles() const
 {
 	for(const auto & slot : bidTradePanel->slots)
-		slot->subtitle->setText(std::to_string(LOCPLINT->cb->getResourceAmount(static_cast<EGameResID>(slot->serial))));
+		slot->subtitle->setText(std::to_string(GAME->interface()->cb->getResourceAmount(static_cast<EGameResID>(slot->serial))));
 }
 
 CMarketSlider::CMarketSlider(const CSlider::SliderMovingFunctor & movingCallback)

+ 4 - 3
client/widgets/markets/CMarketResources.cpp

@@ -12,6 +12,7 @@
 #include "CMarketResources.h"
 
 #include "../../GameEngine.h"
+#include "../../GameInstance.h"
 #include "../../gui/Shortcut.h"
 #include "../../widgets/Buttons.h"
 #include "../../widgets/TextControls.h"
@@ -60,7 +61,7 @@ void CMarketResources::makeDeal()
 {
 	if(auto toTrade = offerSlider->getValue(); toTrade != 0)
 	{
-		LOCPLINT->cb->trade(market->getObjInstanceID(), EMarketMode::RESOURCE_RESOURCE, GameResID(bidTradePanel->getHighlightedItemId()),
+		GAME->interface()->cb->trade(market->getObjInstanceID(), EMarketMode::RESOURCE_RESOURCE, GameResID(bidTradePanel->getHighlightedItemId()),
 			GameResID(offerTradePanel->highlightedSlot->id), bidQty * toTrade, hero);
 		CMarketTraderText::makeDeal();
 		deselect();
@@ -84,12 +85,12 @@ void CMarketResources::highlightingChanged()
 	if(bidTradePanel->isHighlighted() && offerTradePanel->isHighlighted())
 	{
 		market->getOffer(bidTradePanel->getHighlightedItemId(), offerTradePanel->getHighlightedItemId(), bidQty, offerQty, EMarketMode::RESOURCE_RESOURCE);
-		offerSlider->setAmount(LOCPLINT->cb->getResourceAmount(GameResID(bidTradePanel->getHighlightedItemId())) / bidQty);
+		offerSlider->setAmount(GAME->interface()->cb->getResourceAmount(GameResID(bidTradePanel->getHighlightedItemId())) / bidQty);
 		offerSlider->scrollTo(0);
 		const bool isControlsBlocked = bidTradePanel->getHighlightedItemId() != offerTradePanel->getHighlightedItemId() ? false : true;
 		offerSlider->block(isControlsBlocked);
 		maxAmount->block(isControlsBlocked);
-		deal->block(isControlsBlocked || !LOCPLINT->makingTurn);
+		deal->block(isControlsBlocked || !GAME->interface()->makingTurn);
 	}
 	CMarketBase::highlightingChanged();
 	CMarketTraderText::highlightingChanged();

+ 4 - 3
client/widgets/markets/CTransferResources.cpp

@@ -12,6 +12,7 @@
 #include "CTransferResources.h"
 
 #include "../../GameEngine.h"
+#include "../../GameInstance.h"
 #include "../../gui/Shortcut.h"
 #include "../../widgets/Buttons.h"
 #include "../../widgets/TextControls.h"
@@ -64,7 +65,7 @@ void CTransferResources::makeDeal()
 {
 	if(auto toTrade = offerSlider->getValue(); toTrade != 0)
 	{
-		LOCPLINT->cb->trade(market->getObjInstanceID(), EMarketMode::RESOURCE_PLAYER, GameResID(bidTradePanel->getHighlightedItemId()),
+		GAME->interface()->cb->trade(market->getObjInstanceID(), EMarketMode::RESOURCE_PLAYER, GameResID(bidTradePanel->getHighlightedItemId()),
 			PlayerColor(offerTradePanel->getHighlightedItemId()), toTrade, hero);
 		CMarketTraderText::makeDeal();
 		deselect();
@@ -87,11 +88,11 @@ void CTransferResources::highlightingChanged()
 {
 	if(bidTradePanel->isHighlighted() && offerTradePanel->isHighlighted())
 	{
-		offerSlider->setAmount(LOCPLINT->cb->getResourceAmount(GameResID(bidTradePanel->getHighlightedItemId())));
+		offerSlider->setAmount(GAME->interface()->cb->getResourceAmount(GameResID(bidTradePanel->getHighlightedItemId())));
 		offerSlider->scrollTo(0);
 		offerSlider->block(false);
 		maxAmount->block(false);
-		deal->block(!LOCPLINT->makingTurn);
+		deal->block(!GAME->interface()->makingTurn);
 	}
 	CMarketBase::highlightingChanged();
 	CMarketTraderText::highlightingChanged();

+ 2 - 1
client/widgets/markets/TradePanels.cpp

@@ -11,6 +11,7 @@
 #include "TradePanels.h"
 
 #include "../../GameEngine.h"
+#include "../../GameInstance.h"
 #include "../../render/Canvas.h"
 #include "../../widgets/TextControls.h"
 #include "../../windows/InfoWindows.h"
@@ -304,7 +305,7 @@ PlayersPanel::PlayersPanel(const CTradeableItem::ClickPressedFunctor & clickPres
 	std::vector<PlayerColor> players;
 	for(auto player = PlayerColor(0); player < PlayerColor::PLAYER_LIMIT_I; player++)
 	{
-		if(player != LOCPLINT->playerID && LOCPLINT->cb->getPlayerStatus(player) == EPlayerStatus::INGAME)
+		if(player != GAME->interface()->playerID && GAME->interface()->cb->getPlayerStatus(player) == EPlayerStatus::INGAME)
 			players.emplace_back(player);
 	}
 

+ 102 - 101
client/windows/CCastleInterface.cpp

@@ -19,6 +19,7 @@
 
 #include "../CPlayerInterface.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../PlayerLocalState.h"
 
 #include "../gui/Shortcut.h"
@@ -348,8 +349,8 @@ auto CHeroGSlot::getUpgradableSlots(const CArmedInstance *obj) const
 	for(const auto & slot : slots)
 	{
 		auto upgradeInfo = std::make_pair(slot.first, UpgradeInfo(slot.second->getCreatureID()));
-		LOCPLINT->cb->fillUpgradeInfo(slot.second->armyObj, slot.first, upgradeInfo.second);
-		bool canUpgrade = obj->tempOwner == LOCPLINT->playerID && upgradeInfo.second.canUpgrade();
+		GAME->interface()->cb->fillUpgradeInfo(slot.second->armyObj, slot.first, upgradeInfo.second);
+		bool canUpgrade = obj->tempOwner == GAME->interface()->playerID && upgradeInfo.second.canUpgrade();
 		if(canUpgrade)
 			upgradeInfos.push_back(upgradeInfo);
 	}
@@ -364,7 +365,7 @@ auto CHeroGSlot::getUpgradableSlots(const CArmedInstance *obj) const
 	for(const auto & upgradeInfo : upgradeInfos)
 	{
 		TResources upgradeCosts = upgradeInfo.second.getUpgradeCosts() * slots[upgradeInfo.first]->getCount();
-		if(LOCPLINT->cb->getResourceAmount().canAfford(costs + upgradeCosts))
+		if(GAME->interface()->cb->getResourceAmount().canAfford(costs + upgradeCosts))
 			costs += upgradeCosts;
 		else
 			slotInfosToDelete.push_back(upgradeInfo.first);
@@ -391,7 +392,7 @@ void CHeroGSlot::gesture(bool on, const Point & initialPosition, const Point & f
 	auto upgradeAll = [upgradableSlots, obj](){
 		if(!upgradableSlots.canAffordAny)
 		{
-			LOCPLINT->showInfoDialog(VLC->generaltexth->translate("vcmi.townWindow.upgradeAll.notUpgradable"));
+			GAME->interface()->showInfoDialog(VLC->generaltexth->translate("vcmi.townWindow.upgradeAll.notUpgradable"));
 			return;
 		}
 
@@ -404,9 +405,9 @@ void CHeroGSlot::gesture(bool on, const Point & initialPosition, const Point & f
 			
 		std::string textID = upgradableSlots.canAffordAll ? "core.genrltxt.207" : "vcmi.townWindow.upgradeAll.notAllUpgradable";
 
-		LOCPLINT->showYesNoDialog(VLC->generaltexth->translate(textID), [upgradableSlots, obj](){
+		GAME->interface()->showYesNoDialog(VLC->generaltexth->translate(textID), [upgradableSlots, obj](){
 			for(auto & upgradeInfo : upgradableSlots.upgradeInfos)
-				LOCPLINT->cb->upgradeCreature(obj, upgradeInfo.first, upgradeInfo.second.getUpgrade());
+				GAME->interface()->cb->upgradeCreature(obj, upgradeInfo.first, upgradeInfo.second.getUpgrade());
 		}, nullptr, resComps);
 	};
 
@@ -435,12 +436,12 @@ void CHeroGSlot::gesture(bool on, const Point & initialPosition, const Point & f
 	std::vector<RadialMenuConfig> menuElements = {
 		{ RadialMenuConfig::ITEM_NW, twoHeroes, "moveTroops", "vcmi.radialWheel.heroGetArmy", [heroId, heroOtherId](){CExchangeController(heroId, heroOtherId).moveArmy(false, std::nullopt);} },
 		{ RadialMenuConfig::ITEM_NE, twoHeroes, "stackSplitDialog", "vcmi.radialWheel.heroSwapArmy", [heroId, heroOtherId](){CExchangeController(heroId, heroOtherId).swapArmy();} },
-		{ RadialMenuConfig::ITEM_EE, twoHeroes, "tradeHeroes", "vcmi.radialWheel.heroExchange", [heroId, heroOtherId](){LOCPLINT->showHeroExchange(heroId, heroOtherId);} },
+		{ RadialMenuConfig::ITEM_EE, twoHeroes, "tradeHeroes", "vcmi.radialWheel.heroExchange", [heroId, heroOtherId](){GAME->interface()->showHeroExchange(heroId, heroOtherId);} },
 		{ RadialMenuConfig::ITEM_SW, twoHeroes, "moveArtifacts", "vcmi.radialWheel.heroGetArtifacts", [heroId, heroOtherId](){CExchangeController(heroId, heroOtherId).moveArtifacts(false, true, true);} },
 		{ RadialMenuConfig::ITEM_SE, twoHeroes, "swapArtifacts", "vcmi.radialWheel.heroSwapArtifacts", [heroId, heroOtherId](){CExchangeController(heroId, heroOtherId).swapArtifacts(true, true);} }
 	};
 	RadialMenuConfig upgradeSlot = { RadialMenuConfig::ITEM_WW, true, "upgradeCreatures", "vcmi.radialWheel.upgradeCreatures", [upgradeAll](){ upgradeAll(); } };
-	RadialMenuConfig dismissSlot = { RadialMenuConfig::ITEM_WW, true, "dismissHero", "vcmi.radialWheel.heroDismiss", [this](){ LOCPLINT->showYesNoDialog(VLC->generaltexth->allTexts[22], [=](){ LOCPLINT->cb->dismissHero(hero); }, nullptr); } };
+	RadialMenuConfig dismissSlot = { RadialMenuConfig::ITEM_WW, true, "dismissHero", "vcmi.radialWheel.heroDismiss", [this](){ GAME->interface()->showYesNoDialog(VLC->generaltexth->allTexts[22], [=](){ GAME->interface()->cb->dismissHero(hero); }, nullptr); } };
 
 	if(upgradableSlots.isCreatureUpgradePossible)
 		menuElements.push_back(upgradeSlot);
@@ -514,9 +515,9 @@ void CHeroGSlot::clickPressed(const Point & cursorPosition)
 		setHighlight(false);
 
 		if(other->hero && !ENGINE->isKeyboardShiftDown())
-			LOCPLINT->showHeroExchange(hero->id, other->hero->id);
+			GAME->interface()->showHeroExchange(hero->id, other->hero->id);
 		else
-			LOCPLINT->openHeroWindow(hero);
+			GAME->interface()->openHeroWindow(hero);
 	}
 	else if(other->hero && other->isSelected())
 	{
@@ -582,7 +583,7 @@ void CHeroGSlot::set(const CGHeroInstance * newHero)
 	else if(!upg && owner->showEmpty) //up garrison
 	{
 		flag->visible = true;
-		flag->setFrame(LOCPLINT->castleInt->town->getOwner().getNum());
+		flag->setFrame(GAME->interface()->castleInt->town->getOwner().getNum());
 	}
 }
 
@@ -611,18 +612,18 @@ void HeroSlots::swapArmies()
 	//moving hero out of town - check if it is allowed
 	if (town->garrisonHero)
 	{
-		if (!town->visitingHero && LOCPLINT->cb->howManyHeroes(false) >= LOCPLINT->cb->getSettings().getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP))
+		if (!town->visitingHero && GAME->interface()->cb->howManyHeroes(false) >= GAME->interface()->cb->getSettings().getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP))
 		{
 			std::string text = VLC->generaltexth->translate("core.genrltxt.18"); //You already have %d adventuring heroes under your command.
-			boost::algorithm::replace_first(text,"%d",std::to_string(LOCPLINT->cb->howManyHeroes(false)));
+			boost::algorithm::replace_first(text,"%d",std::to_string(GAME->interface()->cb->howManyHeroes(false)));
 
-			LOCPLINT->showInfoDialog(text, std::vector<std::shared_ptr<CComponent>>(), soundBase::sound_todo);
+			GAME->interface()->showInfoDialog(text, std::vector<std::shared_ptr<CComponent>>(), soundBase::sound_todo);
 			allow = false;
 		}
 		else if (town->garrisonHero->stacksCount() == 0)
 		{
 			//This hero has no creatures.  A hero must have creatures before he can brave the dangers of the countryside.
-			LOCPLINT->showInfoDialog(VLC->generaltexth->translate("core.genrltxt.19"), {}, soundBase::sound_todo);
+			GAME->interface()->showInfoDialog(VLC->generaltexth->translate("core.genrltxt.19"), {}, soundBase::sound_todo);
 			allow = false;
 		}
 	}
@@ -631,7 +632,7 @@ void HeroSlots::swapArmies()
 	{
 		if(!town->visitingHero->canBeMergedWith(*town))
 		{
-			LOCPLINT->showInfoDialog(VLC->generaltexth->allTexts[275], std::vector<std::shared_ptr<CComponent>>(), soundBase::sound_todo);
+			GAME->interface()->showInfoDialog(VLC->generaltexth->allTexts[275], std::vector<std::shared_ptr<CComponent>>(), soundBase::sound_todo);
 			allow = false;
 		}
 	}
@@ -640,7 +641,7 @@ void HeroSlots::swapArmies()
 	visitingHero->setHighlight(false);
 
 	if (allow)
-		LOCPLINT->cb->swapGarrisonHero(town);
+		GAME->interface()->cb->swapGarrisonHero(town);
 }
 
 CCastleBuildings::CCastleBuildings(const CGTownInstance* Town):
@@ -676,7 +677,7 @@ void CCastleBuildings::recreate()
 		auto bayPos = town->bestLocation();
 		if(!bayPos.valid())
 			logGlobal->warn("Shipyard in non-coastal town!");
-		std::vector <const CGObjectInstance *> vobjs = LOCPLINT->cb->getVisitableObjs(bayPos, false);
+		std::vector <const CGObjectInstance *> vobjs = GAME->interface()->cb->getVisitableObjs(bayPos, false);
 		//there is visitable obj at shipyard output tile and it's a boat or hero (on boat)
 		if(!vobjs.empty() && (vobjs.front()->ID == Obj::BOAT || vobjs.front()->ID == Obj::HERO))
 		{
@@ -858,7 +859,7 @@ bool CCastleBuildings::buildingTryActivateCustomUI(BuildingID buildingToTest, Bu
 
 			case EMarketMode::RESOURCE_RESOURCE:
 				// can't use allied marketplace
-				if (town->getOwner() == LOCPLINT->playerID)
+				if (town->getOwner() == GAME->interface()->playerID)
 				{
 					ENGINE->windows().createAndPushWindow<CMarketWindow>(town, getHero(), nullptr, *b->marketModes.begin());
 					return true;
@@ -869,7 +870,7 @@ bool CCastleBuildings::buildingTryActivateCustomUI(BuildingID buildingToTest, Bu
 				if(getHero())
 					ENGINE->windows().createAndPushWindow<CMarketWindow>(town, getHero(), nullptr, *b->marketModes.begin());
 				else
-					LOCPLINT->showInfoDialog(boost::str(boost::format(VLC->generaltexth->allTexts[273]) % b->getNameTranslated())); //Only visiting heroes may use the %s.
+					GAME->interface()->showInfoDialog(boost::str(boost::format(VLC->generaltexth->allTexts[273]) % b->getNameTranslated())); //Only visiting heroes may use the %s.
 				return true;
 		}
 	}
@@ -898,18 +899,18 @@ bool CCastleBuildings::buildingTryActivateCustomUI(BuildingID buildingToTest, Bu
 				return true;
 
 		case BuildingID::TAVERN:
-				LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
+				GAME->interface()->showTavernWindow(town, nullptr, QueryID::NONE);
 				return true;
 
 		case BuildingID::SHIPYARD:
 				if(town->shipyardStatus() == IBoatGenerator::GOOD)
 				{
-					LOCPLINT->showShipyardDialog(town);
+					GAME->interface()->showShipyardDialog(town);
 					return true;
 				}
 				else if(town->shipyardStatus() == IBoatGenerator::BOAT_ALREADY_BUILT)
 				{
-					LOCPLINT->showInfoDialog(VLC->generaltexth->allTexts[51]);
+					GAME->interface()->showInfoDialog(VLC->generaltexth->allTexts[51]);
 					return true;
 				}
 				return false;
@@ -928,7 +929,7 @@ bool CCastleBuildings::buildingTryActivateCustomUI(BuildingID buildingToTest, Bu
 				return true;
 
 		case BuildingID::SHIP:
-			LOCPLINT->showInfoDialog(VLC->generaltexth->allTexts[51]); //Cannot build another boat
+			GAME->interface()->showInfoDialog(VLC->generaltexth->allTexts[51]); //Cannot build another boat
 			return true;
 
 		case BuildingID::SPECIAL_1:
@@ -942,7 +943,7 @@ bool CCastleBuildings::buildingTryActivateCustomUI(BuildingID buildingToTest, Bu
 						return true;
 
 				case BuildingSubID::CASTLE_GATE:
-						if (LOCPLINT->makingTurn)
+						if (GAME->interface()->makingTurn)
 						{
 							enterCastleGate(buildingToTest);
 							return true;
@@ -951,7 +952,7 @@ bool CCastleBuildings::buildingTryActivateCustomUI(BuildingID buildingToTest, Bu
 
 				case BuildingSubID::PORTAL_OF_SUMMONING:
 						if (town->creatures[town->getTown()->creatures.size()].second.empty())//No creatures
-							LOCPLINT->showInfoDialog(VLC->generaltexth->tcommands[30]);
+							GAME->interface()->showInfoDialog(VLC->generaltexth->tcommands[30]);
 						else
 							enterDwelling(town->getTown()->creatures.size());
 						return true;
@@ -982,14 +983,14 @@ void CCastleBuildings::enterRewardable(BuildingID building)
 		message.appendTextID("core.genrltxt.273"); // only visiting heroes may visit %s
 		message.replaceTextID(town->getTown()->buildings.at(building)->getNameTextID());
 
-		LOCPLINT->showInfoDialog(message.toString());
+		GAME->interface()->showInfoDialog(message.toString());
 	}
 	else
 	{
 		if (town->rewardableBuildings.at(building)->wasVisited(town->visitingHero))
 			enterBuilding(building);
 		else
-			LOCPLINT->cb->visitTownBuilding(town, building);
+			GAME->interface()->cb->visitTownBuilding(town, building);
 	}
 }
 
@@ -998,13 +999,13 @@ void CCastleBuildings::enterBlacksmith(BuildingID building, ArtifactID artifactI
 	const CGHeroInstance *hero = town->visitingHero;
 	if(!hero)
 	{
-		LOCPLINT->showInfoDialog(boost::str(boost::format(VLC->generaltexth->allTexts[273]) % town->getTown()->buildings.find(building)->second->getNameTranslated()));
+		GAME->interface()->showInfoDialog(boost::str(boost::format(VLC->generaltexth->allTexts[273]) % town->getTown()->buildings.find(building)->second->getNameTranslated()));
 		return;
 	}
 	auto art = artifactID.toArtifact();
 
 	int price = art->getPrice();
-	bool possible = LOCPLINT->cb->getResourceAmount(EGameResID::GOLD) >= price;
+	bool possible = GAME->interface()->cb->getResourceAmount(EGameResID::GOLD) >= price;
 	if(possible)
 	{
 		for(auto slot : art->getPossibleSlots().at(ArtBearer::HERO))
@@ -1028,19 +1029,19 @@ void CCastleBuildings::enterBlacksmith(BuildingID building, ArtifactID artifactI
 void CCastleBuildings::enterBuilding(BuildingID building)
 {
 	std::vector<std::shared_ptr<CComponent>> comps(1, std::make_shared<CComponent>(ComponentType::BUILDING, BuildingTypeUniqueID(town->getFactionID(), building)));
-	LOCPLINT->showInfoDialog( town->getTown()->buildings.find(building)->second->getDescriptionTranslated(), comps);
+	GAME->interface()->showInfoDialog( town->getTown()->buildings.find(building)->second->getDescriptionTranslated(), comps);
 }
 
 void CCastleBuildings::enterCastleGate(BuildingID building)
 {
 	if (!town->visitingHero)
 	{
-		LOCPLINT->showInfoDialog(VLC->generaltexth->allTexts[126]);
+		GAME->interface()->showInfoDialog(VLC->generaltexth->allTexts[126]);
 		return;//only visiting hero can use castle gates
 	}
 	std::vector <int> availableTowns;
 	std::vector<std::shared_ptr<IImage>> images;
-	std::vector <const CGTownInstance*> Towns = LOCPLINT->localState->getOwnedTowns();
+	std::vector <const CGTownInstance*> Towns = GAME->interface()->localState->getOwnedTowns();
 	for(auto & Town : Towns)
 	{
 		const CGTownInstance *t = Town;
@@ -1060,8 +1061,8 @@ void CCastleBuildings::enterCastleGate(BuildingID building)
 
 	auto gateIcon = std::make_shared<CAnimImage>(town->getTown()->clientInfo.buildingsIcons, building);//will be deleted by selection window
 	auto wnd = std::make_shared<CObjectListWindow>(availableTowns, gateIcon, VLC->generaltexth->jktexts[40],
-		VLC->generaltexth->jktexts[41], std::bind (&CCastleInterface::castleTeleport, LOCPLINT->castleInt, _1), 0, images);
-	wnd->onPopup = [availableTowns](int index) { CRClickPopup::createAndPush(LOCPLINT->cb->getObjInstance(ObjectInstanceID(availableTowns[index])), ENGINE->getCursorPosition()); };
+		VLC->generaltexth->jktexts[41], std::bind (&CCastleInterface::castleTeleport, GAME->interface()->castleInt, _1), 0, images);
+	wnd->onPopup = [availableTowns](int index) { CRClickPopup::createAndPush(GAME->interface()->cb->getObjInstance(ObjectInstanceID(availableTowns[index])), ENGINE->getCursorPosition()); };
 	ENGINE->windows().pushWindow(wnd);
 }
 
@@ -1076,7 +1077,7 @@ void CCastleBuildings::enterDwelling(int level)
 
 	auto recruitCb = [=](CreatureID id, int count)
 	{
-		LOCPLINT->cb->recruitCreatures(town, town->getUpperArmy(), id, count, level);
+		GAME->interface()->cb->recruitCreatures(town, town->getUpperArmy(), id, count, level);
 	};
 	ENGINE->windows().createAndPushWindow<CRecruitmentWindow>(town, level, town->getUpperArmy(), recruitCb, nullptr, -87);
 }
@@ -1123,7 +1124,7 @@ void CCastleBuildings::enterFountain(const BuildingID & building, BuildingSubID:
 			boost::algorithm::replace_first(descr,"%d",std::to_string(town->bonusValue.second));
 		}
 	}
-	LOCPLINT->showInfoDialog(descr, comps);
+	GAME->interface()->showInfoDialog(descr, comps);
 }
 
 void CCastleBuildings::enterMagesGuild()
@@ -1132,26 +1133,26 @@ void CCastleBuildings::enterMagesGuild()
 
 	// hero doesn't have spellbok
 	// or it is not our turn and we can't make actions
-	if(hero && !hero->hasSpellbook() && LOCPLINT->makingTurn)
+	if(hero && !hero->hasSpellbook() && GAME->interface()->makingTurn)
 	{
 		if(hero->isCampaignYog())
 		{
 			// "Yog has given up magic in all its forms..."
-			LOCPLINT->showInfoDialog(VLC->generaltexth->allTexts[736]);
+			GAME->interface()->showInfoDialog(VLC->generaltexth->allTexts[736]);
 		}
-		else if(LOCPLINT->cb->getResourceAmount(EGameResID::GOLD) < 500) //not enough gold to buy spellbook
+		else if(GAME->interface()->cb->getResourceAmount(EGameResID::GOLD) < 500) //not enough gold to buy spellbook
 		{
 			openMagesGuild();
-			LOCPLINT->showInfoDialog(VLC->generaltexth->allTexts[213]);
+			GAME->interface()->showInfoDialog(VLC->generaltexth->allTexts[213]);
 		}
 		else
 		{
 			CFunctionList<void()> onYes = [this](){ openMagesGuild(); };
 			CFunctionList<void()> onNo = onYes;
-			onYes += [hero](){ LOCPLINT->cb->buyArtifact(hero, ArtifactID::SPELLBOOK); };
+			onYes += [hero](){ GAME->interface()->cb->buyArtifact(hero, ArtifactID::SPELLBOOK); };
 			std::vector<std::shared_ptr<CComponent>> components(1, std::make_shared<CComponent>(ComponentType::ARTIFACT, ArtifactID(ArtifactID::SPELLBOOK)));
 
-			LOCPLINT->showYesNoDialog(VLC->generaltexth->allTexts[214], onYes, onNo, components);
+			GAME->interface()->showYesNoDialog(VLC->generaltexth->allTexts[214], onYes, onNo, components);
 		}
 	}
 	else
@@ -1167,13 +1168,13 @@ void CCastleBuildings::enterTownHall()
 	{
 		if(!vstd::contains(town->forbiddenBuildings, BuildingID::GRAIL))
 		{
-			LOCPLINT->showYesNoDialog(VLC->generaltexth->allTexts[597], //Do you wish this to be the permanent home of the Grail?
-										[&](){ LOCPLINT->cb->buildBuilding(town, BuildingID::GRAIL); },
+			GAME->interface()->showYesNoDialog(VLC->generaltexth->allTexts[597], //Do you wish this to be the permanent home of the Grail?
+										[&](){ GAME->interface()->cb->buildBuilding(town, BuildingID::GRAIL); },
 										[&](){ openTownHall(); });
 		}
 		else
 		{
-			LOCPLINT->showInfoDialog(VLC->generaltexth->allTexts[673]);
+			GAME->interface()->showInfoDialog(VLC->generaltexth->allTexts[673]);
 			assert(ENGINE->windows().topWindow<CInfoWindow>() != nullptr);
 			ENGINE->windows().topWindow<CInfoWindow>()->buttons[0]->addCallback(std::bind(&CCastleBuildings::openTownHall, this));
 		}
@@ -1186,8 +1187,8 @@ void CCastleBuildings::enterTownHall()
 
 void CCastleBuildings::openMagesGuild()
 {
-	auto mageGuildBackground = LOCPLINT->castleInt->town->getTown()->clientInfo.guildBackground;
-	ENGINE->windows().createAndPushWindow<CMageGuildScreen>(LOCPLINT->castleInt, mageGuildBackground);
+	auto mageGuildBackground = GAME->interface()->castleInt->town->getTown()->clientInfo.guildBackground;
+	ENGINE->windows().createAndPushWindow<CMageGuildScreen>(GAME->interface()->castleInt, mageGuildBackground);
 }
 
 void CCastleBuildings::openTownHall()
@@ -1197,16 +1198,16 @@ void CCastleBuildings::openTownHall()
 
 void CCastleBuildings::enterAnyThievesGuild()
 {
-	std::vector<const CGTownInstance*> towns = LOCPLINT->cb->getTownsInfo(true);
+	std::vector<const CGTownInstance*> towns = GAME->interface()->cb->getTownsInfo(true);
 	for(auto & ownedTown : towns)
 	{
 		if(ownedTown->hasBuilt(BuildingID::TAVERN))
 		{
-			LOCPLINT->showThievesGuildWindow(ownedTown);
+			GAME->interface()->showThievesGuildWindow(ownedTown);
 			return;
 		}
 	}
-	LOCPLINT->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.noTownWithTavern"));
+	GAME->interface()->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.noTownWithTavern"));
 }
 
 void CCastleBuildings::enterBank(BuildingID building)
@@ -1215,12 +1216,12 @@ void CCastleBuildings::enterBank(BuildingID building)
 	if(town->bonusValue.second > 0)
 	{
 		components.push_back(std::make_shared<CComponent>(ComponentType::RESOURCE_PER_DAY, GameResID(GameResID::GOLD), -500));
-		LOCPLINT->showInfoDialog(VLC->generaltexth->translate("vcmi.townStructure.bank.payBack"), components);
+		GAME->interface()->showInfoDialog(VLC->generaltexth->translate("vcmi.townStructure.bank.payBack"), components);
 	}
 	else{
 	
 		components.push_back(std::make_shared<CComponent>(ComponentType::RESOURCE, GameResID(GameResID::GOLD), 2500));
-		LOCPLINT->showYesNoDialog(VLC->generaltexth->translate("vcmi.townStructure.bank.borrow"), [this, building](){ LOCPLINT->cb->visitTownBuilding(town, building); }, nullptr, components);
+		GAME->interface()->showYesNoDialog(VLC->generaltexth->translate("vcmi.townStructure.bank.borrow"), [this, building](){ GAME->interface()->cb->visitTownBuilding(town, building); }, nullptr, components);
 	}
 }
 
@@ -1232,7 +1233,7 @@ void CCastleBuildings::enterAnyMarket()
 		return;
 	}
 
-	std::vector<const CGTownInstance*> towns = LOCPLINT->cb->getTownsInfo(true);
+	std::vector<const CGTownInstance*> towns = GAME->interface()->cb->getTownsInfo(true);
 	for(auto & town : towns)
 	{
 		if(town->hasBuilt(BuildingID::MARKETPLACE))
@@ -1241,7 +1242,7 @@ void CCastleBuildings::enterAnyMarket()
 			return;
 		}
 	}
-	LOCPLINT->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.noTownWithMarket"));
+	GAME->interface()->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.noTownWithMarket"));
 }
 
 CCreaInfo::CCreaInfo(Point position, const CGTownInstance * Town, int Level, bool compact, bool _showAvailable):
@@ -1317,10 +1318,10 @@ void CCreaInfo::hover(bool on)
 
 void CCreaInfo::clickPressed(const Point & cursorPosition)
 {
-	int offset = LOCPLINT->castleInt? (-87) : 0;
+	int offset = GAME->interface()->castleInt? (-87) : 0;
 	auto recruitCb = [=](CreatureID id, int count)
 	{
-		LOCPLINT->cb->recruitCreatures(town, town->getUpperArmy(), id, count, level);
+		GAME->interface()->cb->recruitCreatures(town, town->getUpperArmy(), id, count, level);
 	};
 	ENGINE->windows().createAndPushWindow<CRecruitmentWindow>(town, level, town->getUpperArmy(), recruitCb, nullptr, offset);
 }
@@ -1409,12 +1410,12 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, const CGTownInst
 {
 	OBJECT_CONSTRUCTION;
 
-	LOCPLINT->castleInt = this;
+	GAME->interface()->castleInt = this;
 	addUsedEvents(KEYBOARD);
 
 	builds = std::make_shared<CCastleBuildings>(town);
 	panel = std::make_shared<CPicture>(ImagePath::builtin("TOWNSCRN"), 0, builds->pos.h);
-	panel->setPlayerColor(LOCPLINT->playerID);
+	panel->setPlayerColor(GAME->interface()->playerID);
 	pos.w = panel->pos.w;
 	pos.h = builds->pos.h + panel->pos.h;
 	center();
@@ -1439,7 +1440,7 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, const CGTownInst
 	statusbar = CGStatusBar::create(statusbarBackground);
 	resdatabar = std::make_shared<CResDataBar>(ImagePath::builtin("ARESBAR"), 3, 575, 37, 3, 84, 78);
 
-	townlist = std::make_shared<CTownList>(3, Rect(Point(743, 414), Point(48, 128)), Point(1,16), Point(0, 32), LOCPLINT->localState->getOwnedTowns().size() );
+	townlist = std::make_shared<CTownList>(3, Rect(Point(743, 414), Point(48, 128)), Point(1,16), Point(0, 32), GAME->interface()->localState->getOwnedTowns().size() );
 	townlist->setScrollUpButton( std::make_shared<CButton>( Point(744, 414), AnimationPath::builtin("IAM014"), CButton::tooltipLocalized("core.help.306"), 0));
 	townlist->setScrollDownButton( std::make_shared<CButton>( Point(744, 526), AnimationPath::builtin("IAM015"), CButton::tooltipLocalized("core.help.307"), 0));
 
@@ -1460,10 +1461,10 @@ CCastleInterface::~CCastleInterface()
 	// resume map audio if:
 	// adventureInt exists (may happen on exiting client with open castle interface)
 	// castleInt has not been replaced (happens on switching between towns inside castle interface)
-	if (adventureInt && LOCPLINT->castleInt == this)
+	if (adventureInt && GAME->interface()->castleInt == this)
 		adventureInt->onAudioResumed();
-	if(LOCPLINT->castleInt == this)
-		LOCPLINT->castleInt = nullptr;
+	if(GAME->interface()->castleInt == this)
+		GAME->interface()->castleInt = nullptr;
 }
 
 void CCastleInterface::updateGarrisons()
@@ -1483,28 +1484,28 @@ bool CCastleInterface::holdsGarrison(const CArmedInstance * army)
 
 void CCastleInterface::close()
 {
-	if(town->tempOwner == LOCPLINT->playerID) //we may have opened window for an allied town
+	if(town->tempOwner == GAME->interface()->playerID) //we may have opened window for an allied town
 	{
-		if(town->visitingHero && town->visitingHero->tempOwner == LOCPLINT->playerID)
-			LOCPLINT->localState->setSelection(town->visitingHero);
+		if(town->visitingHero && town->visitingHero->tempOwner == GAME->interface()->playerID)
+			GAME->interface()->localState->setSelection(town->visitingHero);
 		else
-			LOCPLINT->localState->setSelection(town);
+			GAME->interface()->localState->setSelection(town);
 	}
 	CWindowObject::close();
 }
 
 void CCastleInterface::castleTeleport(int where)
 {
-	const CGTownInstance * dest = LOCPLINT->cb->getTown(ObjectInstanceID(where));
-	LOCPLINT->localState->setSelection(town->visitingHero);//according to assert(ho == adventureInt->selection) in the eraseCurrentPathOf
-	LOCPLINT->cb->teleportHero(town->visitingHero, dest);
-	LOCPLINT->localState->erasePath(town->visitingHero);
+	const CGTownInstance * dest = GAME->interface()->cb->getTown(ObjectInstanceID(where));
+	GAME->interface()->localState->setSelection(town->visitingHero);//according to assert(ho == adventureInt->selection) in the eraseCurrentPathOf
+	GAME->interface()->cb->teleportHero(town->visitingHero, dest);
+	GAME->interface()->localState->erasePath(town->visitingHero);
 }
 
 void CCastleInterface::townChange()
 {
 	//TODO: do not recreate window
-	const CGTownInstance * dest = LOCPLINT->localState->getOwnedTown(townlist->getSelectedIndex());
+	const CGTownInstance * dest = GAME->interface()->localState->getOwnedTown(townlist->getSelectedIndex());
 	const CGTownInstance * town = this->town;// "this" is going to be deleted
 	if ( dest == town )
 		return;
@@ -1536,7 +1537,7 @@ void CCastleInterface::removeBuilding(BuildingID bid)
 void CCastleInterface::recreateIcons()
 {
 	OBJECT_CONSTRUCTION;
-	size_t iconIndex = town->getTown()->clientInfo.icons[town->hasFort()][town->built >= LOCPLINT->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
+	size_t iconIndex = town->getTown()->clientInfo.icons[town->hasFort()][town->built >= GAME->interface()->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
 
 	icon->setFrame(iconIndex);
 	TResources townIncome = town->dailyIncome();
@@ -1556,7 +1557,7 @@ void CCastleInterface::recreateIcons()
 	fastTavern = std::make_shared<LRClickableArea>(Rect(15, 387, 58, 64), [&]()
 	{
 		if(town->hasBuilt(BuildingID::TAVERN))
-			LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
+			GAME->interface()->showTavernWindow(town, nullptr, QueryID::NONE);
 	}, [this]{
 		if(!town->getFaction()->getDescriptionTranslated().empty())
 			CRClickPopup::createAndPush(town->getFaction()->getDescriptionTranslated());
@@ -1599,28 +1600,28 @@ void CCastleInterface::keyPressed(EShortcut key)
 		break;
 	case EShortcut::TOWN_OPEN_HERO_EXCHANGE:
 		if (town->visitingHero && town->garrisonHero)
-			LOCPLINT->showHeroExchange(town->visitingHero->id, town->garrisonHero->id);
+			GAME->interface()->showHeroExchange(town->visitingHero->id, town->garrisonHero->id);
 		break;
 	case EShortcut::TOWN_OPEN_HERO:
 		if (town->visitingHero)
-			LOCPLINT->openHeroWindow(town->visitingHero);
+			GAME->interface()->openHeroWindow(town->visitingHero);
 		else if (town->garrisonHero)
-			LOCPLINT->openHeroWindow(town->garrisonHero);
+			GAME->interface()->openHeroWindow(town->garrisonHero);
 		break;
 	case EShortcut::TOWN_OPEN_VISITING_HERO:
 		if (town->visitingHero)
-			LOCPLINT->openHeroWindow(town->visitingHero);
+			GAME->interface()->openHeroWindow(town->visitingHero);
 		break;
 	case EShortcut::TOWN_OPEN_GARRISONED_HERO:
 		if (town->garrisonHero)
-			LOCPLINT->openHeroWindow(town->garrisonHero);
+			GAME->interface()->openHeroWindow(town->garrisonHero);
 		break;
 	case EShortcut::TOWN_SWAP_ARMIES:
 		heroes->swapArmies();
 		break;
 	case EShortcut::TOWN_OPEN_TAVERN:
 		if(town->hasBuilt(BuildingID::TAVERN))
-			LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
+			GAME->interface()->showTavernWindow(town, nullptr, QueryID::NONE);
 		break;
 	default:
 		break;
@@ -1649,7 +1650,7 @@ CHallInterface::CBuildingBox::CBuildingBox(int x, int y, const CGTownInstance *
 	pos.w = 154;
 	pos.h = 92;
 
-	state = LOCPLINT->cb->canBuildStructure(town, building->bid);
+	state = GAME->interface()->cb->canBuildStructure(town, building->bid);
 
 	constexpr std::array panelIndex =
 	{
@@ -1782,7 +1783,7 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin
 		if(building->resources[i])
 		{
 			MetaString message;
-			int resourceAmount = LOCPLINT->cb->getResourceAmount(i);
+			int resourceAmount = GAME->interface()->cb->getResourceAmount(i);
 			bool canAfford = resourceAmount >= building->resources[i];
 
 			if(!canAfford && state != EBuildingState::ALREADY_PRESENT && settings["general"]["enableUiEnhancements"].Bool())
@@ -1813,7 +1814,7 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin
 
 		buy = std::make_shared<CButton>(Point(45, 446), AnimationPath::builtin("IBUY30"), CButton::tooltip(tooltipYes.toString()), [&](){ buyFunc(); }, EShortcut::GLOBAL_ACCEPT);
 		buy->setBorderColor(Colors::METALLIC_GOLD);
-		buy->block(state != EBuildingState::ALLOWED || LOCPLINT->playerID != town->tempOwner || !LOCPLINT->makingTurn);
+		buy->block(state != EBuildingState::ALLOWED || GAME->interface()->playerID != town->tempOwner || !GAME->interface()->makingTurn);
 
 		cancel = std::make_shared<CButton>(Point(290, 445), AnimationPath::builtin("ICANCEL"), CButton::tooltip(tooltipNo.toString()), [&](){ close();}, EShortcut::GLOBAL_CANCEL);
 		cancel->setBorderColor(Colors::METALLIC_GOLD);
@@ -1822,7 +1823,7 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin
 
 void CBuildWindow::buyFunc()
 {
-	LOCPLINT->cb->buildBuilding(town,building->bid);
+	GAME->interface()->cb->buildBuilding(town,building->bid);
 	ENGINE->windows().popWindows(2); //we - build window and hall screen
 }
 
@@ -1988,7 +1989,7 @@ void CFortScreen::creaturesChangedEventHandler()
 	for(auto & elem : recAreas)
 		elem->creaturesChangedEventHandler();
 
-	LOCPLINT->castleInt->creaturesChangedEventHandler();
+	GAME->interface()->castleInt->creaturesChangedEventHandler();
 }
 
 CFortScreen::RecruitArea::RecruitArea(int posX, int posY, const CGTownInstance * Town, int Level):
@@ -2092,7 +2093,7 @@ void CFortScreen::RecruitArea::creaturesChangedEventHandler()
 
 void CFortScreen::RecruitArea::clickPressed(const Point & cursorPosition)
 {
-	LOCPLINT->castleInt->builds->enterDwelling(level);
+	GAME->interface()->castleInt->builds->enterDwelling(level);
 }
 
 void CFortScreen::RecruitArea::showPopupWindow(const Point & cursorPosition)
@@ -2139,7 +2140,7 @@ void CMageGuildScreen::updateSpells(ObjectInstanceID tID)
 	spells.clear();
 	emptyScrolls.clear();
 
-	const CGTownInstance * town = LOCPLINT->cb->getTown(townId);
+	const CGTownInstance * town = GAME->interface()->cb->getTown(townId);
 
 	for(uint32_t i=0; i<town->getTown()->mageLevel; i++)
 	{
@@ -2169,22 +2170,22 @@ CMageGuildScreen::Scroll::Scroll(Point position, const CSpell *Spell, ObjectInst
 
 void CMageGuildScreen::Scroll::clickPressed(const Point & cursorPosition)
 {
-	const CGTownInstance * town = LOCPLINT->cb->getTown(townId);
-	if(LOCPLINT->cb->getSettings().getBoolean(EGameSettings::TOWNS_SPELL_RESEARCH) && town->spellResearchAllowed)
+	const CGTownInstance * town = GAME->interface()->cb->getTown(townId);
+	if(GAME->interface()->cb->getSettings().getBoolean(EGameSettings::TOWNS_SPELL_RESEARCH) && town->spellResearchAllowed)
 	{
 		int level = -1;
 		for(int i = 0; i < town->spells.size(); i++)
 			if(vstd::find_pos(town->spells[i], spell->id) != -1)
 				level = i;
 				
-		if(town->spellResearchCounterDay >= LOCPLINT->cb->getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_PER_DAY).Vector()[level].Float())
+		if(town->spellResearchCounterDay >= GAME->interface()->cb->getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_PER_DAY).Vector()[level].Float())
 		{
-			LOCPLINT->showInfoDialog(VLC->generaltexth->translate("vcmi.spellResearch.comeAgain"));
+			GAME->interface()->showInfoDialog(VLC->generaltexth->translate("vcmi.spellResearch.comeAgain"));
 			return;
 		}
 
-		auto costBase = TResources(LOCPLINT->cb->getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST).Vector()[level]);
-		auto costExponent = LOCPLINT->cb->getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST_EXPONENT_PER_RESEARCH).Vector()[level].Float();
+		auto costBase = TResources(GAME->interface()->cb->getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST).Vector()[level]);
+		auto costExponent = GAME->interface()->cb->getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST_EXPONENT_PER_RESEARCH).Vector()[level].Float();
 		auto cost = costBase * std::pow(town->spellResearchAcceptedCounter + 1, costExponent);
 
 		std::vector<std::shared_ptr<CComponent>> resComps;
@@ -2192,7 +2193,7 @@ void CMageGuildScreen::Scroll::clickPressed(const Point & cursorPosition)
 		int index = town->spellsAtLevel(level, false);
 		if (index >= town->spells[level].size())
 		{
-			LOCPLINT->showInfoDialog(VLC->generaltexth->translate("vcmi.spellResearch.noMoreSpells"));
+			GAME->interface()->showInfoDialog(VLC->generaltexth->translate("vcmi.spellResearch.noMoreSpells"));
 			return;
 		}
 		auto newSpell = town->spells[level].at(index);
@@ -2208,17 +2209,17 @@ void CMageGuildScreen::Scroll::clickPressed(const Point & cursorPosition)
 		for(int i = 0; i < 3; i++)
 			pom.emplace_back(AnimationPath::builtin("settingsWindow/button80"), nullptr);
 
-		auto text = VLC->generaltexth->translate(LOCPLINT->cb->getResourceAmount().canAfford(cost) ? "vcmi.spellResearch.pay" : "vcmi.spellResearch.canNotAfford");
+		auto text = VLC->generaltexth->translate(GAME->interface()->cb->getResourceAmount().canAfford(cost) ? "vcmi.spellResearch.pay" : "vcmi.spellResearch.canNotAfford");
 		boost::replace_first(text, "%SPELL1", spell->id.toSpell()->getNameTranslated());
 		boost::replace_first(text, "%SPELL2", newSpell.toSpell()->getNameTranslated());
-		auto temp = std::make_shared<CInfoWindow>(text, LOCPLINT->playerID, resComps, pom);
+		auto temp = std::make_shared<CInfoWindow>(text, GAME->interface()->playerID, resComps, pom);
 
 		temp->buttons[0]->setOverlay(std::make_shared<CPicture>(ImagePath::builtin("spellResearch/accept")));
-		temp->buttons[0]->addCallback([this, town](){ LOCPLINT->cb->spellResearch(town, spell->id, true); });
+		temp->buttons[0]->addCallback([this, town](){ GAME->interface()->cb->spellResearch(town, spell->id, true); });
 		temp->buttons[0]->addPopupCallback([](){ CRClickPopup::createAndPush(VLC->generaltexth->translate("vcmi.spellResearch.research")); });
-		temp->buttons[0]->setEnabled(LOCPLINT->cb->getResourceAmount().canAfford(cost));
+		temp->buttons[0]->setEnabled(GAME->interface()->cb->getResourceAmount().canAfford(cost));
 		temp->buttons[1]->setOverlay(std::make_shared<CPicture>(ImagePath::builtin("spellResearch/reroll")));
-		temp->buttons[1]->addCallback([this, town](){ LOCPLINT->cb->spellResearch(town, spell->id, false); });
+		temp->buttons[1]->addCallback([this, town](){ GAME->interface()->cb->spellResearch(town, spell->id, false); });
 		temp->buttons[1]->addPopupCallback([](){ CRClickPopup::createAndPush(VLC->generaltexth->translate("vcmi.spellResearch.skip")); });
 		temp->buttons[2]->setOverlay(std::make_shared<CPicture>(ImagePath::builtin("spellResearch/close")));
 		temp->buttons[2]->addPopupCallback([](){ CRClickPopup::createAndPush(VLC->generaltexth->translate("vcmi.spellResearch.abort")); });
@@ -2226,7 +2227,7 @@ void CMageGuildScreen::Scroll::clickPressed(const Point & cursorPosition)
 		ENGINE->windows().pushWindow(temp);
 	}
 	else
-		LOCPLINT->showInfoDialog(spell->getDescriptionTranslated(0), std::make_shared<CComponent>(ComponentType::SPELL, spell->id));
+		GAME->interface()->showInfoDialog(spell->getDescriptionTranslated(0), std::make_shared<CComponent>(ComponentType::SPELL, spell->id));
 }
 
 void CMageGuildScreen::Scroll::showPopupWindow(const Point & cursorPosition)
@@ -2281,7 +2282,7 @@ CBlacksmithDialog::CBlacksmithDialog(bool possible, CreatureID creMachineID, Art
 	cancel = std::make_shared<CButton>(Point(224, 312), AnimationPath::builtin("ICANCEL.DEF"), CButton::tooltip(cancelText.toString()), [&](){ close(); }, EShortcut::GLOBAL_CANCEL);
 
 	if(possible)
-		buy->addCallback([=](){ LOCPLINT->cb->buyArtifact(LOCPLINT->cb->getHero(hid),aid); });
+		buy->addCallback([=](){ GAME->interface()->cb->buyArtifact(GAME->interface()->cb->getHero(hid),aid); });
 	else
 		buy->block(true);
 

+ 10 - 9
client/windows/CCreatureWindow.cpp

@@ -24,6 +24,7 @@
 #include "../widgets/GraphicalPrimitiveCanvas.h"
 #include "../windows/InfoWindows.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../battle/BattleInterface.h"
 
@@ -353,7 +354,7 @@ CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset)
 		};
 		auto onClick = [=] ()
 		{
-			LOCPLINT->showYesNoDialog(VLC->generaltexth->allTexts[12], onDismiss, nullptr);
+			GAME->interface()->showYesNoDialog(VLC->generaltexth->allTexts[12], onDismiss, nullptr);
 		};
 		dismiss = std::make_shared<CButton>(Point(5, 5),AnimationPath::builtin("IVIEWCR2.DEF"), VLC->generaltexth->zelp[445], onClick, EShortcut::HERO_DISMISS);
 	}
@@ -383,13 +384,13 @@ CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset)
 					resComps.push_back(std::make_shared<CComponent>(ComponentType::RESOURCE, i->resType, i->resVal));
 				}
 
-				if(LOCPLINT->cb->getResourceAmount().canAfford(totalCost))
+				if(GAME->interface()->cb->getResourceAmount().canAfford(totalCost))
 				{
-					LOCPLINT->showYesNoDialog(VLC->generaltexth->allTexts[207], onUpgrade, nullptr, resComps);
+					GAME->interface()->showYesNoDialog(VLC->generaltexth->allTexts[207], onUpgrade, nullptr, resComps);
 				}
 				else
 				{
-					LOCPLINT->showInfoDialog(VLC->generaltexth->allTexts[314], resComps);
+					GAME->interface()->showInfoDialog(VLC->generaltexth->allTexts[314], resComps);
 				}
 			};
 			auto upgradeBtn = std::make_shared<CButton>(Point(221 + (int)buttonIndex * 40, 5), AnimationPath::builtin("stackWindow/upgradeButton"), VLC->generaltexth->zelp[446], onClick);
@@ -455,7 +456,7 @@ CStackWindow::CommanderMainSection::CommanderMainSection(CStackWindow * owner, i
 
 		auto icon = std::make_shared<CCommanderSkillIcon>(std::make_shared<CPicture>(getSkillImage(index), skillPos.x, skillPos.y), false, [=]()
 		{
-			LOCPLINT->showInfoDialog(getSkillDescription(index));
+			GAME->interface()->showInfoDialog(getSkillDescription(index));
 		});
 
 		icon->text = getSkillDescription(index); //used to handle right click description via LRClickableAreaWText::ClickRight()
@@ -590,7 +591,7 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
 
 	name = std::make_shared<CLabel>(215, 13, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, parent->info->getName());
 
-	const BattleInterface* battleInterface = LOCPLINT->battleInt.get();
+	const BattleInterface* battleInterface = GAME->interface()->battleInt.get();
 	const CStack* battleStack = parent->info->stack;
 
 	int dmgMultiply = 1;
@@ -887,8 +888,8 @@ void CStackWindow::initSections()
 {
 	OBJECT_CONSTRUCTION;
 
-	bool showArt = LOCPLINT->cb->getSettings().getBoolean(EGameSettings::MODULE_STACK_ARTIFACT) && info->commander == nullptr && info->stackNode;
-	bool showExp = (LOCPLINT->cb->getSettings().getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE) || info->commander != nullptr) && info->stackNode;
+	bool showArt = GAME->interface()->cb->getSettings().getBoolean(EGameSettings::MODULE_STACK_ARTIFACT) && info->commander == nullptr && info->stackNode;
+	bool showExp = (GAME->interface()->cb->getSettings().getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE) || info->commander != nullptr) && info->stackNode;
 
 	mainSection = std::make_shared<MainSection>(this, pos.h, showExp, showArt);
 
@@ -1087,7 +1088,7 @@ void CStackWindow::removeStackArtifact(ArtifactPosition pos)
 	{
 		auto artLoc = ArtifactLocation(info->owner->id, pos);
 		artLoc.creature = info->stackNode->armyObj->findStack(info->stackNode);
-		LOCPLINT->cb->swapArtifacts(artLoc, ArtifactLocation(info->owner->id, slot));
+		GAME->interface()->cb->swapArtifacts(artLoc, ArtifactLocation(info->owner->id, slot));
 		stackArtifactButton.reset();
 		stackArtifact.reset();
 		redraw();

+ 8 - 7
client/windows/CExchangeWindow.cpp

@@ -15,6 +15,7 @@
 #include "../CPlayerInterface.h"
 
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/CursorHandler.h"
 #include "../gui/Shortcut.h"
 #include "../gui/WindowHandler.h"
@@ -51,8 +52,8 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
 	OBJECT_CONSTRUCTION;
 	addUsedEvents(KEYBOARD);
 
-	heroInst[0] = LOCPLINT->cb->getHero(hero1);
-	heroInst[1] = LOCPLINT->cb->getHero(hero2);
+	heroInst[0] = GAME->interface()->cb->getHero(hero1);
+	heroInst[1] = GAME->interface()->cb->getHero(hero2);
 
 	auto genTitle = [](const CGHeroInstance * h)
 	{
@@ -130,7 +131,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
 		heroAreas[b]->addClickCallback([this, hero]() -> void
 									   {
 										   if(getPickedArtifact() == nullptr)
-											   LOCPLINT->openHeroWindow(hero);
+											   GAME->interface()->openHeroWindow(hero);
 									   });
 
 		specialtyAreas[b] = std::make_shared<LRClickableAreaWText>();
@@ -160,7 +161,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
 
 	quit = std::make_shared<CButton>(Point(732, 567), AnimationPath::builtin("IOKAY.DEF"), VLC->generaltexth->zelp[600], std::bind(&CExchangeWindow::close, this), EShortcut::GLOBAL_ACCEPT);
 	if(queryID.getNum() > 0)
-		quit->addCallback([=](){ LOCPLINT->cb->selectionMade(0, queryID); });
+		quit->addCallback([=](){ GAME->interface()->cb->selectionMade(0, queryID); });
 
 	questlogButton[0] = std::make_shared<CButton>(Point( 10, qeLayout ? 39 : 44), AnimationPath::builtin("hsbtns4.def"), CButton::tooltip(VLC->generaltexth->heroscrn[0]), std::bind(&CExchangeWindow::questLogShortcut, this));
 	questlogButton[1] = std::make_shared<CButton>(Point(740, qeLayout ? 39 : 44), AnimationPath::builtin("hsbtns4.def"), CButton::tooltip(VLC->generaltexth->heroscrn[0]), std::bind(&CExchangeWindow::questLogShortcut, this));
@@ -226,8 +227,8 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
 		backpackButtonLeft->setOverlay(std::make_shared<CPicture>(ImagePath::builtin("heroWindow/backpackButtonIcon")));
 		backpackButtonRight->setOverlay(std::make_shared<CPicture>(ImagePath::builtin("heroWindow/backpackButtonIcon")));
 
-		auto leftHeroBlock = heroInst[0]->tempOwner != LOCPLINT->cb->getPlayerID();
-		auto rightHeroBlock = heroInst[1]->tempOwner != LOCPLINT->cb->getPlayerID();
+		auto leftHeroBlock = heroInst[0]->tempOwner != GAME->interface()->cb->getPlayerID();
+		auto rightHeroBlock = heroInst[1]->tempOwner != GAME->interface()->cb->getPlayerID();
 
 		buttonMoveUnitsFromLeftToRight->block(leftHeroBlock);
 		buttonMoveUnitsFromRightToLeft->block(rightHeroBlock);
@@ -371,7 +372,7 @@ bool CExchangeWindow::holdsGarrison(const CArmedInstance * army)
 void CExchangeWindow::questLogShortcut()
 {
 	ENGINE->cursor().dragAndDropCursor(nullptr);
-	LOCPLINT->showQuestLog();
+	GAME->interface()->showQuestLog();
 }
 
 void CExchangeWindow::update()

+ 6 - 5
client/windows/CHeroBackpackWindow.cpp

@@ -11,6 +11,7 @@
 #include "CHeroBackpackWindow.h"
 
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 
 #include "../widgets/Buttons.h"
@@ -51,15 +52,15 @@ CHeroBackpackWindow::CHeroBackpackWindow(const CGHeroInstance * hero, const std:
 	
 	buttons.emplace_back(std::make_shared<CButton>(Point(), AnimationPath::builtin("heroBackpackSort"),
 		CButton::tooltipLocalized("vcmi.heroWindow.sortBackpackByCost"),
-		[hero]() { LOCPLINT->cb->sortBackpackArtifactsByCost(hero->id); }));
+		[hero]() { GAME->interface()->cb->sortBackpackArtifactsByCost(hero->id); }));
 	buttons.back()->setTextOverlay(sortByValue, EFonts::FONT_SMALL, Colors::YELLOW);
 	buttons.emplace_back(std::make_shared<CButton>(Point(), AnimationPath::builtin("heroBackpackSort"),
 		CButton::tooltipLocalized("vcmi.heroWindow.sortBackpackBySlot"),
-		[hero]() { LOCPLINT->cb->sortBackpackArtifactsBySlot(hero->id); }));
+		[hero]() { GAME->interface()->cb->sortBackpackArtifactsBySlot(hero->id); }));
 	buttons.back()->setTextOverlay(sortBySlot, EFonts::FONT_SMALL, Colors::YELLOW);
 	buttons.emplace_back(std::make_shared<CButton>(Point(), AnimationPath::builtin("heroBackpackSort"),
 		CButton::tooltipLocalized("vcmi.heroWindow.sortBackpackByClass"),
-		[hero]() { LOCPLINT->cb->sortBackpackArtifactsByClass(hero->id); }));
+		[hero]() { GAME->interface()->cb->sortBackpackArtifactsByClass(hero->id); }));
 	buttons.back()->setTextOverlay(sortByClass, EFonts::FONT_SMALL, Colors::YELLOW);
 
 	pos.w = stretchedBackground->pos.w = arts->pos.w + 2 * windowMargin;
@@ -86,7 +87,7 @@ void CHeroBackpackWindow::notFocusedClick()
 void CHeroBackpackWindow::showAll(Canvas & to)
 {
 	CIntObject::showAll(to);
-	CMessage::drawBorder(PlayerColor(LOCPLINT->playerID), to, pos.w+28, pos.h+29, pos.x-14, pos.y-15);
+	CMessage::drawBorder(PlayerColor(GAME->interface()->playerID), to, pos.w+28, pos.h+29, pos.x-14, pos.y-15);
 }
 
 CHeroQuickBackpackWindow::CHeroQuickBackpackWindow(const CGHeroInstance * hero, ArtifactPosition targetSlot)
@@ -137,6 +138,6 @@ void CHeroQuickBackpackWindow::showAll(Canvas & to)
 		close();
 		return;
 	}
-	CMessage::drawBorder(PlayerColor(LOCPLINT->playerID), to, pos.w + 28, pos.h + 29, pos.x - 14, pos.y - 15);
+	CMessage::drawBorder(PlayerColor(GAME->interface()->playerID), to, pos.w + 28, pos.h + 29, pos.x - 14, pos.y - 15);
 	CIntObject::showAll(to);
 }

+ 13 - 12
client/windows/CHeroWindow.cpp

@@ -18,6 +18,7 @@
 #include "../CPlayerInterface.h"
 
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/TextAlignment.h"
 #include "../gui/Shortcut.h"
 #include "../gui/WindowHandler.h"
@@ -76,7 +77,7 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
 	OBJECT_CONSTRUCTION;
 	curHero = hero;
 
-	banner = std::make_shared<CAnimImage>(AnimationPath::builtin("CREST58"), LOCPLINT->playerID.getNum(), 0, 606, 8);
+	banner = std::make_shared<CAnimImage>(AnimationPath::builtin("CREST58"), GAME->interface()->playerID.getNum(), 0, 606, 8);
 	name = std::make_shared<CLabel>(190, 38, EFonts::FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW);
 	title = std::make_shared<CLabel>(190, 65, EFonts::FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE);
 
@@ -86,7 +87,7 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
 
 	if(settings["general"]["enableUiEnhancements"].Bool())
 	{
-		questlogButton = std::make_shared<CButton>(Point(314, 429), AnimationPath::builtin("hsbtns4.def"), CButton::tooltip(heroscrn[0]), [=](){ LOCPLINT->showQuestLog(); }, EShortcut::ADVENTURE_QUEST_LOG);
+		questlogButton = std::make_shared<CButton>(Point(314, 429), AnimationPath::builtin("hsbtns4.def"), CButton::tooltip(heroscrn[0]), [=](){ GAME->interface()->showQuestLog(); }, EShortcut::ADVENTURE_QUEST_LOG);
 		backpackButton = std::make_shared<CButton>(Point(424, 429), AnimationPath::builtin("heroBackpack"), CButton::tooltipLocalized("vcmi.heroWindow.openBackpack"), [=](){ createBackpackWindow(); }, EShortcut::HERO_BACKPACK);
 		backpackButton->setOverlay(std::make_shared<CPicture>(ImagePath::builtin("heroWindow/backpackButtonIcon")));
 		dismissButton = std::make_shared<CButton>(Point(534, 429), AnimationPath::builtin("hsbtns2.def"), CButton::tooltip(heroscrn[28]), [=](){ dismissCurrent(); }, EShortcut::HERO_DISMISS);
@@ -96,7 +97,7 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
 		dismissLabel = std::make_shared<CTextBox>(VLC->generaltexth->jktexts[8], Rect(370, 430, 65, 35), 0, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE);
 		questlogLabel = std::make_shared<CTextBox>(VLC->generaltexth->jktexts[9], Rect(510, 430, 65, 35), 0, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE);
 		dismissButton = std::make_shared<CButton>(Point(454, 429), AnimationPath::builtin("hsbtns2.def"), CButton::tooltip(heroscrn[28]), [=](){ dismissCurrent(); }, EShortcut::HERO_DISMISS);
-		questlogButton = std::make_shared<CButton>(Point(314, 429), AnimationPath::builtin("hsbtns4.def"), CButton::tooltip(heroscrn[0]), [=](){ LOCPLINT->showQuestLog(); }, EShortcut::ADVENTURE_QUEST_LOG);
+		questlogButton = std::make_shared<CButton>(Point(314, 429), AnimationPath::builtin("hsbtns4.def"), CButton::tooltip(heroscrn[0]), [=](){ GAME->interface()->showQuestLog(); }, EShortcut::ADVENTURE_QUEST_LOG);
 	}
 
 	formations = std::make_shared<CToggleGroup>(0);
@@ -110,8 +111,8 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
 	}
 
 	//right list of heroes
-	for(int i=0; i < std::min(LOCPLINT->cb->howManyHeroes(false), 8); i++)
-		heroList.push_back(std::make_shared<CHeroSwitcher>(this, Point(612, 87 + i * 54), LOCPLINT->cb->getHeroBySerial(i, false)));
+	for(int i=0; i < std::min(GAME->interface()->cb->howManyHeroes(false), 8); i++)
+		heroList.push_back(std::make_shared<CHeroSwitcher>(this, Point(612, 87 + i * 54), GAME->interface()->cb->getHeroBySerial(i, false)));
 
 	//areas
 	portraitArea = std::make_shared<LRClickableAreaWText>(Rect(18, 18, 58, 64));
@@ -198,7 +199,7 @@ void CHeroWindow::update()
 		OBJECT_CONSTRUCTION;
 		if(!garr)
 		{
-			bool removableTroops = curHero->getOwner() == LOCPLINT->playerID;
+			bool removableTroops = curHero->getOwner() == GAME->interface()->playerID;
 			std::string helpBox = heroscrn[32];
 			boost::algorithm::replace_first(helpBox, "%s", VLC->generaltexth->allTexts[43]);
 
@@ -217,7 +218,7 @@ void CHeroWindow::update()
 			enableKeyboardShortcuts();
 		}
 
-		int serial = LOCPLINT->cb->getHeroSerial(curHero, false);
+		int serial = GAME->interface()->cb->getHeroSerial(curHero, false);
 
 		listSelection.reset();
 		if(serial >= 0)
@@ -275,7 +276,7 @@ void CHeroWindow::update()
 	}
 
 	//if player only have one hero and no towns
-	if(!LOCPLINT->cb->howManyTowns() && LOCPLINT->cb->howManyHeroes() == 1)
+	if(!GAME->interface()->cb->howManyTowns() && GAME->interface()->cb->howManyHeroes() == 1)
 		noDismiss = true;
 
 	if(curHero->isMissionCritical())
@@ -296,7 +297,7 @@ void CHeroWindow::update()
 	formations->resetCallback();
 	//setting formations
 	formations->setSelected(curHero->formation == EArmyFormation::TIGHT ? 1 : 0);
-	formations->addCallback([=](int value){ LOCPLINT->cb->setFormation(curHero, static_cast<EArmyFormation>(value));});
+	formations->addCallback([=](int value){ GAME->interface()->cb->setFormation(curHero, static_cast<EArmyFormation>(value));});
 
 	morale->set(curHero);
 	luck->set(curHero);
@@ -306,11 +307,11 @@ void CHeroWindow::update()
 
 void CHeroWindow::dismissCurrent()
 {
-	LOCPLINT->showYesNoDialog(VLC->generaltexth->allTexts[22], [this]()
+	GAME->interface()->showYesNoDialog(VLC->generaltexth->allTexts[22], [this]()
 		{
 			arts->putBackPickedArtifact();
 			close();
-			LOCPLINT->cb->dismissHero(curHero);
+			GAME->interface()->cb->dismissHero(curHero);
 			arts->setHero(nullptr);
 		}, nullptr);
 }
@@ -332,7 +333,7 @@ void CHeroWindow::commanderWindow()
 		{
 			ArtifactLocation dst(curHero->id, freeSlot);
 			dst.creature = SlotID::COMMANDER_SLOT_PLACEHOLDER;
-			LOCPLINT->cb->swapArtifacts(ArtifactLocation(hero->id, ArtifactPosition::TRANSITION_POS), dst);
+			GAME->interface()->cb->swapArtifacts(ArtifactLocation(hero->id, ArtifactPosition::TRANSITION_POS), dst);
 		}
 	}
 	else

+ 18 - 17
client/windows/CKingdomInterface.cpp

@@ -18,6 +18,7 @@
 #include "../PlayerLocalState.h"
 #include "../adventureMap/CResDataBar.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../gui/WindowHandler.h"
 #include "../widgets/CComponent.h"
@@ -111,7 +112,7 @@ void InfoBox::clickPressed(const Point & cursorPosition)
 	data->prepareMessage(text, comp);
 
 	if(comp)
-		LOCPLINT->showInfoDialog(text, CInfoWindow::TCompsInfo(1, comp));
+		GAME->interface()->showInfoDialog(text, CInfoWindow::TCompsInfo(1, comp));
 }
 
 IInfoBoxData::IInfoBoxData(InfoType Type)
@@ -466,7 +467,7 @@ CKingdomInterface::CKingdomInterface()
 
 	tabArea = std::make_shared<CTabbedInt>(std::bind(&CKingdomInterface::createMainTab, this, _1), Point(4,4));
 
-	std::vector<const CGObjectInstance * > ownedObjects = LOCPLINT->cb->getMyObjects();
+	std::vector<const CGObjectInstance * > ownedObjects = GAME->interface()->cb->getMyObjects();
 	generateObjectsList(ownedObjects);
 	generateMinesList(ownedObjects);
 	generateButtons();
@@ -590,10 +591,10 @@ void CKingdomInterface::generateMinesList(const std::vector<const CGObjectInstan
 		totalIncome += mapObject->asOwnable()->dailyIncome()[EGameResID::GOLD];
 
 	//if player has some modded boosts we want to show that as well
-	const auto * playerSettings = LOCPLINT->cb->getPlayerSettings(LOCPLINT->playerID);
-	const auto & towns = LOCPLINT->cb->getTownsInfo(true);
-	totalIncome += LOCPLINT->cb->getPlayerState(LOCPLINT->playerID)->valOfBonuses(BonusType::RESOURCES_CONSTANT_BOOST, BonusSubtypeID(GameResID(EGameResID::GOLD))) * playerSettings->handicap.percentIncome / 100;
-	totalIncome += LOCPLINT->cb->getPlayerState(LOCPLINT->playerID)->valOfBonuses(BonusType::RESOURCES_TOWN_MULTIPLYING_BOOST, BonusSubtypeID(GameResID(EGameResID::GOLD))) * towns.size() * playerSettings->handicap.percentIncome / 100;
+	const auto * playerSettings = GAME->interface()->cb->getPlayerSettings(GAME->interface()->playerID);
+	const auto & towns = GAME->interface()->cb->getTownsInfo(true);
+	totalIncome += GAME->interface()->cb->getPlayerState(GAME->interface()->playerID)->valOfBonuses(BonusType::RESOURCES_CONSTANT_BOOST, BonusSubtypeID(GameResID(EGameResID::GOLD))) * playerSettings->handicap.percentIncome / 100;
+	totalIncome += GAME->interface()->cb->getPlayerState(GAME->interface()->playerID)->valOfBonuses(BonusType::RESOURCES_TOWN_MULTIPLYING_BOOST, BonusSubtypeID(GameResID(EGameResID::GOLD))) * towns.size() * playerSettings->handicap.percentIncome / 100;
 
 	for(int i=0; i<7; i++)
 	{
@@ -671,22 +672,22 @@ void CKingdomInterface::updateGarrisons()
 
 bool CKingdomInterface::holdsGarrison(const CArmedInstance * army)
 {
-	return army->getOwner() == LOCPLINT->playerID;
+	return army->getOwner() == GAME->interface()->playerID;
 }
 
 CKingdHeroList::CKingdHeroList(size_t maxSize, const CreateHeroItemFunctor & onCreateHeroItemCallback)
 {
 	OBJECT_CONSTRUCTION;
 	title = std::make_shared<CPicture>(ImagePath::builtin("OVTITLE"),16,0);
-	title->setPlayerColor(LOCPLINT->playerID);
+	title->setPlayerColor(GAME->interface()->playerID);
 	heroLabel = std::make_shared<CLabel>(150, 10, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, VLC->generaltexth->overview[0]);
 	skillsLabel = std::make_shared<CLabel>(500, 10, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, VLC->generaltexth->overview[1]);
 
-	ui32 townCount = LOCPLINT->cb->howManyHeroes(false);
+	ui32 townCount = GAME->interface()->cb->howManyHeroes(false);
 	ui32 size = OVERVIEW_SIZE*116 + 19;
 	heroes = std::make_shared<CListBox>([onCreateHeroItemCallback](size_t idx) -> std::shared_ptr<CIntObject>
 		{
-			auto heroesList = LOCPLINT->localState->getWanderingHeroes();
+			auto heroesList = GAME->interface()->localState->getWanderingHeroes();
 			if(idx < heroesList.size())
 			{
 				auto hero = std::make_shared<CHeroItem>(heroesList[idx]);
@@ -722,12 +723,12 @@ CKingdTownList::CKingdTownList(size_t maxSize)
 {
 	OBJECT_CONSTRUCTION;
 	title = std::make_shared<CPicture>(ImagePath::builtin("OVTITLE"), 16, 0);
-	title->setPlayerColor(LOCPLINT->playerID);
+	title->setPlayerColor(GAME->interface()->playerID);
 	townLabel = std::make_shared<CLabel>(146, 10,FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, VLC->generaltexth->overview[3]);
 	garrHeroLabel = std::make_shared<CLabel>(375, 10, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, VLC->generaltexth->overview[4]);
 	visitHeroLabel = std::make_shared<CLabel>(608, 10, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, VLC->generaltexth->overview[5]);
 
-	ui32 townCount = LOCPLINT->cb->howManyTowns();
+	ui32 townCount = GAME->interface()->cb->howManyTowns();
 	ui32 size = OVERVIEW_SIZE*116 + 19;
 	towns = std::make_shared<CListBox>(std::bind(&CKingdTownList::createTownItem, this, _1),
 		Point(19,21), Point(0,116), maxSize, townCount, 0, 1, Rect(-19, -21, size, size));
@@ -765,7 +766,7 @@ std::shared_ptr<CIntObject> CKingdTownList::createTownItem(size_t index)
 {
 	ui32 picCount = 4; // OVSLOT contains 4 images
 
-	auto townsList = LOCPLINT->localState->getOwnedTowns();
+	auto townsList = GAME->interface()->localState->getOwnedTowns();
 
 	if(index < townsList.size())
 		return std::make_shared<CTownItem>(townsList[index]);
@@ -787,7 +788,7 @@ CTownItem::CTownItem(const CGTownInstance * Town)
 	garr = std::make_shared<CGarrisonInt>(Point(313, 3), 4, Point(232,0), town->getUpperArmy(), town->visitingHero, true, true, CGarrisonInt::ESlotsLayout::TWO_ROWS);
 	heroes = std::make_shared<HeroSlots>(town, Point(244,6), Point(475,6), garr, false);
 
-	size_t iconIndex = town->getTown()->clientInfo.icons[town->hasFort()][town->built >= LOCPLINT->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
+	size_t iconIndex = town->getTown()->clientInfo.icons[town->hasFort()][town->built >= GAME->interface()->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
 
 	picture = std::make_shared<CAnimImage>(AnimationPath::builtin("ITPT"), iconIndex, 0, 5, 6);
 	openTown = std::make_shared<LRClickableAreaOpenTown>(Rect(5, 6, 58, 64), town);
@@ -808,14 +809,14 @@ CTownItem::CTownItem(const CGTownInstance * Town)
 	fastTavern = std::make_shared<LRClickableArea>(Rect(5, 6, 58, 64), [&]()
 	{
 		if(town->hasBuilt(BuildingID::TAVERN))
-			LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
+			GAME->interface()->showTavernWindow(town, nullptr, QueryID::NONE);
 	}, [&]{
 		if(!town->getTown()->faction->getDescriptionTranslated().empty())
 			CRClickPopup::createAndPush(town->getFaction()->getDescriptionTranslated());
 	});
 	fastMarket = std::make_shared<LRClickableArea>(Rect(153, 6, 65, 64), []()
 	{
-		std::vector<const CGTownInstance*> towns = LOCPLINT->cb->getTownsInfo(true);
+		std::vector<const CGTownInstance*> towns = GAME->interface()->cb->getTownsInfo(true);
 		for(auto & town : towns)
 		{
 			if(town->hasBuilt(BuildingID::MARKETPLACE))
@@ -824,7 +825,7 @@ CTownItem::CTownItem(const CGTownInstance * Town)
 				return;
 			}
 		}
-		LOCPLINT->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.noTownWithMarket"));
+		GAME->interface()->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.noTownWithMarket"));
 	});
 	fastTown = std::make_shared<LRClickableArea>(Rect(67, 6, 165, 20), [&]()
 	{

+ 6 - 5
client/windows/CMarketWindow.cpp

@@ -12,6 +12,7 @@
 #include "CMarketWindow.h"
 
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 
 #include "../widgets/Buttons.h"
@@ -121,7 +122,7 @@ void CMarketWindow::createChangeModeButtons(EMarketMode currentMode, const IMark
 		if(modeButton == EMarketMode::RESOURCE_RESOURCE || modeButton == EMarketMode::RESOURCE_PLAYER)
 		{
 			if(const auto town = dynamic_cast<const CGTownInstance*>(market))
-				return town->getOwner() == LOCPLINT->playerID;
+				return town->getOwner() == GAME->interface()->playerID;
 			else
 				return true;
 		}
@@ -184,10 +185,10 @@ void CMarketWindow::initWidgetInternals(const EMarketMode mode, const std::pair<
 
 std::string CMarketWindow::getMarketTitle(const ObjectInstanceID marketId, const EMarketMode mode) const
 {
-	assert(LOCPLINT->cb->getMarket(marketId));
-	assert(vstd::contains(LOCPLINT->cb->getMarket(marketId)->availableModes(), mode));
+	assert(GAME->interface()->cb->getMarket(marketId));
+	assert(vstd::contains(GAME->interface()->cb->getMarket(marketId)->availableModes(), mode));
 
-	if(const auto town = LOCPLINT->cb->getTown(marketId))
+	if(const auto town = GAME->interface()->cb->getTown(marketId))
 	{
 		for(const auto & buildingId : town->getBuildings())
 		{
@@ -195,7 +196,7 @@ std::string CMarketWindow::getMarketTitle(const ObjectInstanceID marketId, const
 				return building->getNameTranslated();
 		}
 	}
-	return LOCPLINT->cb->getObj(marketId)->getObjectName();
+	return GAME->interface()->cb->getObj(marketId)->getObjectName();
 }
 
 void CMarketWindow::createArtifactsBuying(const IMarket * market, const CGHeroInstance * hero)

+ 2 - 1
client/windows/CPuzzleWindow.cpp

@@ -13,6 +13,7 @@
 #include "../CPlayerInterface.h"
 #include "../adventureMap/CResDataBar.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/TextAlignment.h"
 #include "../gui/Shortcut.h"
 #include "../mapView/MapView.h"
@@ -47,7 +48,7 @@ CPuzzleWindow::CPuzzleWindow(const int3 & GrailPos, double discoveredRatio)
 	title = std::make_shared<CLabel>(700, 95, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW, VLC->generaltexth->allTexts[463]);
 	resDataBar = std::make_shared<CResDataBar>(ImagePath::builtin("ARESBAR.bmp"), 3, 575, 32, 2, 85, 85);
 
-	int faction = LOCPLINT->cb->getStartInfo()->playerInfos.find(LOCPLINT->playerID)->second.castle;
+	int faction = GAME->interface()->cb->getStartInfo()->playerInfos.find(GAME->interface()->playerID)->second.castle;
 
 	auto & puzzleMap = (*VLC->townh)[faction]->puzzleMap;
 

+ 9 - 8
client/windows/CSpellWindow.cpp

@@ -21,6 +21,7 @@
 
 #include "../battle/BattleInterface.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../gui/WindowHandler.h"
 #include "../media/IVideoPlayer.h"
@@ -602,7 +603,7 @@ void CSpellWindow::SpellArea::clickPressed(const Point & cursorPosition)
 		auto spellCost = owner->myInt->cb->getSpellCost(mySpell, owner->myHero);
 		if(spellCost > owner->myHero->mana) //insufficient mana
 		{
-			LOCPLINT->showInfoDialog(boost::str(boost::format(VLC->generaltexth->allTexts[206]) % spellCost % owner->myHero->mana));
+			GAME->interface()->showInfoDialog(boost::str(boost::format(VLC->generaltexth->allTexts[206]) % spellCost % owner->myHero->mana));
 			return;
 		}
 
@@ -619,10 +620,10 @@ void CSpellWindow::SpellArea::clickPressed(const Point & cursorPosition)
 		const bool inCastle = owner->myInt->castleInt != nullptr;
 
 		//battle spell on adv map or adventure map spell during combat => display infowindow, not cast
-		if((combatSpell != inCombat) || inCastle || (!combatSpell && !LOCPLINT->makingTurn))
+		if((combatSpell != inCombat) || inCastle || (!combatSpell && !GAME->interface()->makingTurn))
 		{
 			std::vector<std::shared_ptr<CComponent>> hlp(1, std::make_shared<CComponent>(ComponentType::SPELL, mySpell->id));
-			LOCPLINT->showInfoDialog(mySpell->getDescriptionTranslated(schoolLevel), hlp);
+			GAME->interface()->showInfoDialog(mySpell->getDescriptionTranslated(schoolLevel), hlp);
 		}
 		else if(combatSpell)
 		{
@@ -637,9 +638,9 @@ void CSpellWindow::SpellArea::clickPressed(const Point & cursorPosition)
 				std::vector<std::string> texts;
 				problem.getAll(texts);
 				if(!texts.empty())
-					LOCPLINT->showInfoDialog(texts.front());
+					GAME->interface()->showInfoDialog(texts.front());
 				else
-					LOCPLINT->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.spellUnknownProblem"));
+					GAME->interface()->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.spellUnknownProblem"));
 			}
 		}
 		else //adventure spell
@@ -656,7 +657,7 @@ void CSpellWindow::SpellArea::clickPressed(const Point & cursorPosition)
 			});
 
 			spells::detail::ProblemImpl problem;
-			if (mySpell->getAdventureMechanics().canBeCast(problem, LOCPLINT->cb.get(), owner->myHero))
+			if (mySpell->getAdventureMechanics().canBeCast(problem, GAME->interface()->cb.get(), owner->myHero))
 			{
 				if(mySpell->getTargetType() == spells::AimType::LOCATION)
 					adventureInt->enterCastingMode(mySpell);
@@ -670,9 +671,9 @@ void CSpellWindow::SpellArea::clickPressed(const Point & cursorPosition)
 				std::vector<std::string> texts;
 				problem.getAll(texts);
 				if(!texts.empty())
-					LOCPLINT->showInfoDialog(texts.front());
+					GAME->interface()->showInfoDialog(texts.front());
 				else
-					LOCPLINT->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.spellUnknownProblem"));
+					GAME->interface()->showInfoDialog(VLC->generaltexth->translate("vcmi.adventureMap.spellUnknownProblem"));
 			}
 		}
 	}

+ 5 - 4
client/windows/CTutorialWindow.cpp

@@ -18,6 +18,7 @@
 #include "../CPlayerInterface.h"
 
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../gui/WindowHandler.h"
 #include "../widgets/Images.h"
@@ -69,8 +70,8 @@ void CTutorialWindow::openWindowFirstTime(const TutorialMode & m)
 {
 	if(ENGINE->input().getCurrentInputMode() == InputMode::TOUCH && !persistentStorage["gui"]["tutorialCompleted" + std::to_string(m)].Bool())
 	{
-		if(LOCPLINT)
-			LOCPLINT->showingDialog->setBusy();
+		if(GAME->interface())
+			GAME->interface()->showingDialog->setBusy();
 		ENGINE->windows().pushWindow(std::make_shared<CTutorialWindow>(m));
 
 		Settings s = persistentStorage.write["gui"]["tutorialCompleted" + std::to_string(m)];
@@ -80,8 +81,8 @@ void CTutorialWindow::openWindowFirstTime(const TutorialMode & m)
 
 void CTutorialWindow::exit()
 {
-	if(LOCPLINT)
-		LOCPLINT->showingDialog->setFree();
+	if(GAME->interface())
+		GAME->interface()->showingDialog->setFree();
 
 	close();
 }

+ 3 - 2
client/windows/CWindowObject.cpp

@@ -14,6 +14,7 @@
 #include "../widgets/Images.h"
 #include "../widgets/TextControls.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/CursorHandler.h"
 #include "../battle/BattleInterface.h"
 #include "../battle/BattleInterfaceClasses.h"
@@ -89,7 +90,7 @@ std::shared_ptr<CPicture> CWindowObject::createBg(const ImagePath & imageName, b
 
 	auto image = std::make_shared<CPicture>(imageName, Point(0,0), EImageBlitMode::OPAQUE);
 	if(playerColored)
-		image->setPlayerColor(LOCPLINT->playerID);
+		image->setPlayerColor(GAME->interface()->playerID);
 	return image;
 }
 
@@ -182,7 +183,7 @@ void CWindowObject::setShadow(bool on)
 
 void CWindowObject::showAll(Canvas & to)
 {
-	auto color = LOCPLINT ? LOCPLINT->playerID : PlayerColor(1);
+	auto color = GAME->interface() ? GAME->interface()->playerID : PlayerColor(1);
 	if(settings["session"]["spectate"].Bool())
 		color = PlayerColor(1); // TODO: Spectator shouldn't need special code for UI colors
 

+ 17 - 16
client/windows/CWindowWithArtifacts.cpp

@@ -16,6 +16,7 @@
 #include "CHeroBackpackWindow.h"
 
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/CursorHandler.h"
 #include "../gui/WindowHandler.h"
 
@@ -72,7 +73,7 @@ const CArtifactInstance * CWindowWithArtifacts::getPickedArtifact() const
 void CWindowWithArtifacts::clickPressedOnArtPlace(const CGHeroInstance * hero, const ArtifactPosition & slot,
 	bool allowExchange, bool altarTrading, bool closeWindow, const Point & cursorPosition)
 {
-	if(!LOCPLINT->makingTurn)
+	if(!GAME->interface()->makingTurn)
 		return;
 	if(hero == nullptr)
 		return;
@@ -88,7 +89,7 @@ void CWindowWithArtifacts::clickPressedOnArtPlace(const CGHeroInstance * hero, c
 	}
 	else if(auto art = hero->getArt(slot))
 	{
-		if(hero->getOwner() == LOCPLINT->playerID)
+		if(hero->getOwner() == GAME->interface()->playerID)
 		{
 			if(checkSpecialArts(*art, *hero, altarTrading))
 				onClickPressedCommonArtifact(*hero, slot, closeWindow);
@@ -98,7 +99,7 @@ void CWindowWithArtifacts::clickPressedOnArtPlace(const CGHeroInstance * hero, c
 			for(const auto & artSlot : ArtifactUtils::unmovableSlots())
 				if(slot == artSlot)
 				{
-					LOCPLINT->showInfoDialog(VLC->generaltexth->allTexts[21]);
+					GAME->interface()->showInfoDialog(VLC->generaltexth->allTexts[21]);
 					break;
 				}
 		}
@@ -108,7 +109,7 @@ void CWindowWithArtifacts::clickPressedOnArtPlace(const CGHeroInstance * hero, c
 void CWindowWithArtifacts::swapArtifactAndClose(const CArtifactsOfHeroBase & artsInst, const ArtifactPosition & slot,
 	const ArtifactLocation & dstLoc)
 {
-	LOCPLINT->cb->swapArtifacts(ArtifactLocation(artsInst.getHero()->id, slot), dstLoc);
+	GAME->interface()->cb->swapArtifacts(ArtifactLocation(artsInst.getHero()->id, slot), dstLoc);
 	close();
 }
 
@@ -117,9 +118,9 @@ void CWindowWithArtifacts::showArtifactAssembling(const CArtifactsOfHeroBase & a
 {
 	if(artsInst.getArt(artPlace.slot))
 	{
-		if(LOCPLINT->artifactController->askToDisassemble(artsInst.getHero(), artPlace.slot))
+		if(GAME->interface()->artifactController->askToDisassemble(artsInst.getHero(), artPlace.slot))
 			return;
-		if(LOCPLINT->artifactController->askToAssemble(artsInst.getHero(), artPlace.slot))
+		if(GAME->interface()->artifactController->askToAssemble(artsInst.getHero(), artPlace.slot))
 			return;
 		if(artPlace.text.size())
 			artPlace.LRClickableAreaWTextComp::showPopupWindow(cursorPosition);
@@ -199,7 +200,7 @@ void CWindowWithArtifacts::markPossibleSlots() const
 				continue;
 
 			if(getHeroPickedArtifact() == hero || !std::dynamic_pointer_cast<CArtifactsOfHeroKingdom>(artSet))
-				artSet->markPossibleSlots(pickedArtInst->getType(), hero->tempOwner == LOCPLINT->playerID);
+				artSet->markPossibleSlots(pickedArtInst->getType(), hero->tempOwner == GAME->interface()->playerID);
 		}
 	}
 }
@@ -210,19 +211,19 @@ bool CWindowWithArtifacts::checkSpecialArts(const CArtifactInstance & artInst, c
 	
 	if(artId == ArtifactID::SPELLBOOK)
 	{
-		ENGINE->windows().createAndPushWindow<CSpellWindow>(&hero, LOCPLINT, LOCPLINT->battleInt.get());
+		ENGINE->windows().createAndPushWindow<CSpellWindow>(&hero, GAME->interface(), GAME->interface()->battleInt.get());
 		return false;
 	}
 	if(artId == ArtifactID::CATAPULT)
 	{
 		// The Catapult must be equipped
-		LOCPLINT->showInfoDialog(VLC->generaltexth->allTexts[312],
+		GAME->interface()->showInfoDialog(VLC->generaltexth->allTexts[312],
 			std::vector<std::shared_ptr<CComponent>>(1, std::make_shared<CComponent>(ComponentType::ARTIFACT, ArtifactID(ArtifactID::CATAPULT))));
 		return false;
 	}
 	if(isTrade && !artInst.getType()->isTradable())
 	{
-		LOCPLINT->showInfoDialog(VLC->generaltexth->allTexts[21],
+		GAME->interface()->showInfoDialog(VLC->generaltexth->allTexts[21],
 			std::vector<std::shared_ptr<CComponent>>(1, std::make_shared<CComponent>(ComponentType::ARTIFACT, artId)));
 		return false;
 	}
@@ -257,20 +258,20 @@ void CWindowWithArtifacts::putPickedArtifact(const CGHeroInstance & curHero, con
 		if(pickedArt->getType()->isBig())
 		{
 			// War machines cannot go to backpack
-			LOCPLINT->showInfoDialog(boost::str(boost::format(VLC->generaltexth->allTexts[153]) % pickedArt->getType()->getNameTranslated()));
+			GAME->interface()->showInfoDialog(boost::str(boost::format(VLC->generaltexth->allTexts[153]) % pickedArt->getType()->getNameTranslated()));
 		}
 		else
 		{
 			if(ArtifactUtils::isBackpackFreeSlots(heroArtOwner))
-				LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
+				GAME->interface()->cb->swapArtifacts(srcLoc, dstLoc);
 			else
-				LOCPLINT->showInfoDialog(VLC->generaltexth->translate("core.genrltxt.152"));
+				GAME->interface()->showInfoDialog(VLC->generaltexth->translate("core.genrltxt.152"));
 		}
 	}
 	// Check if artifact transfer is possible
-	else if(pickedArt->canBePutAt(&curHero, dstLoc.slot, true) && (!curHero.getArt(targetSlot) || curHero.tempOwner == LOCPLINT->playerID))
+	else if(pickedArt->canBePutAt(&curHero, dstLoc.slot, true) && (!curHero.getArt(targetSlot) || curHero.tempOwner == GAME->interface()->playerID))
 	{
-		LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
+		GAME->interface()->cb->swapArtifacts(srcLoc, dstLoc);
 	}
 }
 
@@ -311,5 +312,5 @@ void CWindowWithArtifacts::onClickPressedCommonArtifact(const CGHeroInstance & c
 		close();
 	}
 	if(dstLoc.slot != ArtifactPosition::PRE_FIRST)
-		LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
+		GAME->interface()->cb->swapArtifacts(srcLoc, dstLoc);
 }

+ 36 - 35
client/windows/GUIClasses.cpp

@@ -20,6 +20,7 @@
 #include "../CPlayerInterface.h"
 
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/CursorHandler.h"
 #include "../gui/Shortcut.h"
 #include "../gui/WindowHandler.h"
@@ -116,7 +117,7 @@ void CRecruitmentWindow::select(std::shared_ptr<CCreatureCard> card)
 
 	if(card)
 	{
-		si32 maxAmount = card->creature->maxAmount(LOCPLINT->cb->getResourceAmount());
+		si32 maxAmount = card->creature->maxAmount(GAME->interface()->cb->getResourceAmount());
 
 		vstd::amin(maxAmount, card->amount);
 
@@ -156,11 +157,11 @@ void CRecruitmentWindow::buy()
 	if(!dstslot.validSlot() && (selected->creature->warMachine == ArtifactID::NONE)) //no available slot
 	{
 		std::pair<SlotID, SlotID> toMerge;
-		bool allowMerge = LOCPLINT->cb->getSettings().getBoolean(EGameSettings::DWELLINGS_ACCUMULATE_WHEN_OWNED);
+		bool allowMerge = GAME->interface()->cb->getSettings().getBoolean(EGameSettings::DWELLINGS_ACCUMULATE_WHEN_OWNED);
 
 		if (allowMerge && dst->mergeableStacks(toMerge))
 		{
-			LOCPLINT->cb->mergeStacks( dst, dst, toMerge.first, toMerge.second);
+			GAME->interface()->cb->mergeStacks( dst, dst, toMerge.first, toMerge.second);
 		}
 		else
 		{
@@ -175,7 +176,7 @@ void CRecruitmentWindow::buy()
 				txt = VLC->generaltexth->allTexts[17]; //There is no room in the garrison for this army.
 			}
 
-			LOCPLINT->showInfoDialog(txt);
+			GAME->interface()->showInfoDialog(txt);
 			return;
 		}
 	}
@@ -304,7 +305,7 @@ void CRecruitmentWindow::sliderMoved(int to)
 	if(!selected)
 		return;
 
-	buyButton->block(!to || !LOCPLINT->makingTurn);
+	buyButton->block(!to || !GAME->interface()->makingTurn);
 	availableValue->setText(std::to_string(selected->amount - to));
 	toRecruitValue->setText(std::to_string(to));
 
@@ -403,7 +404,7 @@ CLevelWindow::CLevelWindow(const CGHeroInstance * hero, PrimarySkill pskill, std
 {
 	OBJECT_CONSTRUCTION;
 
-	LOCPLINT->showingDialog->setBusy();
+	GAME->interface()->showingDialog->setBusy();
 
 	if(!skills.empty())
 	{
@@ -445,7 +446,7 @@ void CLevelWindow::close()
 	if (box && box->selectedIndex() != -1)
 		cb(box->selectedIndex());
 
-	LOCPLINT->showingDialog->setFree();
+	GAME->interface()->showingDialog->setFree();
 
 	CWindowObject::close();
 }
@@ -458,7 +459,7 @@ CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj, const std::func
 {
 	OBJECT_CONSTRUCTION;
 
-	std::vector<const CGHeroInstance*> h = LOCPLINT->cb->getAvailableHeroes(TavernObj);
+	std::vector<const CGHeroInstance*> h = GAME->interface()->cb->getAvailableHeroes(TavernObj);
 	if(h.size() < 2)
 		h.resize(2, nullptr);
 
@@ -478,37 +479,37 @@ CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj, const std::func
 	heroDescription = std::make_shared<CTextBox>("", Rect(30, 373, 233, 35), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
 	heroesForHire = std::make_shared<CLabel>(145, 283, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW, VLC->generaltexth->jktexts[38]);
 
-	rumor = std::make_shared<CTextBox>(LOCPLINT->cb->getTavernRumor(tavernObj), Rect(32, 188, 330, 66), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
+	rumor = std::make_shared<CTextBox>(GAME->interface()->cb->getTavernRumor(tavernObj), Rect(32, 188, 330, 66), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
 
 	statusbar = CGStatusBar::create(std::make_shared<CPicture>(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
 	cancel = std::make_shared<CButton>(Point(310, 428), AnimationPath::builtin("ICANCEL.DEF"), CButton::tooltip(VLC->generaltexth->tavernInfo[7]), std::bind(&CTavernWindow::close, this), EShortcut::GLOBAL_CANCEL);
 	recruit = std::make_shared<CButton>(Point(272, 355), AnimationPath::builtin("TPTAV01.DEF"), CButton::tooltip(), std::bind(&CTavernWindow::recruitb, this), EShortcut::GLOBAL_ACCEPT);
 	thiefGuild = std::make_shared<CButton>(Point(22, 428), AnimationPath::builtin("TPTAV02.DEF"), CButton::tooltip(VLC->generaltexth->tavernInfo[5]), std::bind(&CTavernWindow::thievesguildb, this), EShortcut::ADVENTURE_THIEVES_GUILD);
 
-	if(!LOCPLINT->makingTurn)
+	if(!GAME->interface()->makingTurn)
 	{
 		recruit->block(true);
 	}
-	else if(LOCPLINT->cb->getResourceAmount(EGameResID::GOLD) < GameConstants::HERO_GOLD_COST) //not enough gold
+	else if(GAME->interface()->cb->getResourceAmount(EGameResID::GOLD) < GameConstants::HERO_GOLD_COST) //not enough gold
 	{
 		recruit->addHoverText(EButtonState::NORMAL, VLC->generaltexth->tavernInfo[0]); //Cannot afford a Hero
 		recruit->block(true);
 	}
-	else if(LOCPLINT->cb->howManyHeroes(true) >= LOCPLINT->cb->getSettings().getInteger(EGameSettings::HEROES_PER_PLAYER_TOTAL_CAP))
+	else if(GAME->interface()->cb->howManyHeroes(true) >= GAME->interface()->cb->getSettings().getInteger(EGameSettings::HEROES_PER_PLAYER_TOTAL_CAP))
 	{
 		MetaString message;
 		message.appendTextID("core.tvrninfo.1");
-		message.replaceNumber(LOCPLINT->cb->howManyHeroes(true));
+		message.replaceNumber(GAME->interface()->cb->howManyHeroes(true));
 
 		//Cannot recruit. You already have %d Heroes.
 		recruit->addHoverText(EButtonState::NORMAL, message.toString());
 		recruit->block(true);
 	}
-	else if(LOCPLINT->cb->howManyHeroes(false) >= LOCPLINT->cb->getSettings().getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP))
+	else if(GAME->interface()->cb->howManyHeroes(false) >= GAME->interface()->cb->getSettings().getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP))
 	{
 		MetaString message;
 		message.appendTextID("core.tvrninfo.1");
-		message.replaceNumber(LOCPLINT->cb->howManyHeroes(false));
+		message.replaceNumber(GAME->interface()->cb->howManyHeroes(false));
 
 		recruit->addHoverText(EButtonState::NORMAL, message.toString());
 		recruit->block(true);
@@ -523,8 +524,8 @@ CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj, const std::func
 		if(selected == -1)
 			recruit->block(true);
 	}
-	if(LOCPLINT->castleInt)
-		videoPlayer = std::make_shared<VideoWidget>(Point(70, 56), LOCPLINT->castleInt->town->getTown()->clientInfo.tavernVideo, false);
+	if(GAME->interface()->castleInt)
+		videoPlayer = std::make_shared<VideoWidget>(Point(70, 56), GAME->interface()->castleInt->town->getTown()->clientInfo.tavernVideo, false);
 	else if(const auto * townObj = dynamic_cast<const CGTownInstance *>(TavernObj))
 		videoPlayer = std::make_shared<VideoWidget>(Point(70, 56), townObj->getTown()->clientInfo.tavernVideo, false);
 	else
@@ -537,10 +538,10 @@ void CTavernWindow::addInvite()
 {
 	OBJECT_CONSTRUCTION;
 
-	if(!LOCPLINT->cb->getSettings().getBoolean(EGameSettings::HEROES_TAVERN_INVITE))
+	if(!GAME->interface()->cb->getSettings().getBoolean(EGameSettings::HEROES_TAVERN_INVITE))
 		return;
 
-	const auto & heroesPool = CSH->client->gameState()->heroesPool;
+	const auto & heroesPool = GAME->server().client->gameState()->heroesPool;
 	for(auto & elem : heroesPool->unusedHeroesFromPool())
 	{
 		bool heroAvailable = heroesPool->isHeroAvailableFor(elem.first, tavernObj->getOwner());
@@ -565,7 +566,7 @@ void CTavernWindow::recruitb()
 	const CGHeroInstance *toBuy = (selected ? h2 : h1)->h;
 	const CGObjectInstance *obj = tavernObj;
 
-	LOCPLINT->cb->recruitHero(obj, toBuy, heroToInvite ? heroToInvite->getHeroTypeID() : HeroTypeID::NONE);
+	GAME->interface()->cb->recruitHero(obj, toBuy, heroToInvite ? heroToInvite->getHeroTypeID() : HeroTypeID::NONE);
 	close();
 }
 
@@ -769,7 +770,7 @@ CShipyardWindow::CShipyardWindow(const TResources & cost, int state, BoatId boat
 
 	for(GameResID i = EGameResID::WOOD; i <= EGameResID::GOLD; ++i)
 	{
-		if(cost[i] > LOCPLINT->cb->getResourceAmount(i))
+		if(cost[i] > GAME->interface()->cb->getResourceAmount(i))
 		{
 			build->block(true);
 			break;
@@ -824,7 +825,7 @@ void CTransformerWindow::makeDeal()
 	for(auto & elem : items)
 	{
 		if(!elem->left)
-			LOCPLINT->cb->trade(market->getObjInstanceID(), EMarketMode::CREATURE_UNDEAD, SlotID(elem->id), {}, {}, hero);
+			GAME->interface()->cb->trade(market->getObjInstanceID(), EMarketMode::CREATURE_UNDEAD, SlotID(elem->id), {}, {}, hero);
 	}
 }
 
@@ -905,7 +906,7 @@ CUniversityWindow::CItem::CItem(CUniversityWindow * _parent, int _ID, int X, int
 			bool canLearn = parent->hero->canLearnSkill(ID);
 
 			if(!skillKnown && canLearn)
-				ENGINE->windows().createAndPushWindow<CUnivConfirmWindow>(parent, ID, LOCPLINT->cb->getResourceAmount(EGameResID::GOLD) >= 2000);
+				ENGINE->windows().createAndPushWindow<CUnivConfirmWindow>(parent, ID, GAME->interface()->cb->getResourceAmount(EGameResID::GOLD) >= 2000);
 		});
 	update();
 }
@@ -991,7 +992,7 @@ void CUniversityWindow::updateSecondarySkills()
 
 void CUniversityWindow::makeDeal(SecondarySkill skill)
 {
-	LOCPLINT->cb->trade(market->getObjInstanceID(), EMarketMode::RESOURCE_SKILL, GameResID(GameResID::GOLD), skill, 1, hero);
+	GAME->interface()->cb->trade(market->getObjInstanceID(), EMarketMode::RESOURCE_SKILL, GameResID(GameResID::GOLD), skill, 1, hero);
 }
 
 CUnivConfirmWindow::CUnivConfirmWindow(CUniversityWindow * owner_, SecondarySkill SKILL, bool available)
@@ -1158,7 +1159,7 @@ void CHillFortWindow::updateGarrisons()
 			if(const CStackInstance * s = hero->getStackPtr(SlotID(i)))
 			{
 				UpgradeInfo info(s->getCreature()->getId());
-				LOCPLINT->cb->fillUpgradeInfo(hero, SlotID(i), info);
+				GAME->interface()->cb->fillUpgradeInfo(hero, SlotID(i), info);
 				if(info.canUpgrade())	//we have upgrades here - update costs
 				{
 					costs[i] = info.getUpgradeCosts() * hero->getStackCount(SlotID(i));
@@ -1176,7 +1177,7 @@ void CHillFortWindow::updateGarrisons()
 	//"Upgrade all" slot
 	State newState = State::MAKE_UPGRADE;
 	{
-		TResources myRes = LOCPLINT->cb->getResourceAmount();
+		TResources myRes = GAME->interface()->cb->getResourceAmount();
 
 		bool allUpgraded = true;//All creatures are upgraded?
 		for(int i=0; i<slotsCount; i++)
@@ -1253,15 +1254,15 @@ void CHillFortWindow::makeDeal(SlotID slot)
 	switch(currState[slot.getNum()])
 	{
 		case State::ALREADY_UPGRADED:
-			LOCPLINT->showInfoDialog(VLC->generaltexth->allTexts[313 + offset], std::vector<std::shared_ptr<CComponent>>(), soundBase::sound_todo);
+			GAME->interface()->showInfoDialog(VLC->generaltexth->allTexts[313 + offset], std::vector<std::shared_ptr<CComponent>>(), soundBase::sound_todo);
 			break;
 		case State::UNAFFORDABLE:
-			LOCPLINT->showInfoDialog(VLC->generaltexth->allTexts[314 + offset], std::vector<std::shared_ptr<CComponent>>(), soundBase::sound_todo);
+			GAME->interface()->showInfoDialog(VLC->generaltexth->allTexts[314 + offset], std::vector<std::shared_ptr<CComponent>>(), soundBase::sound_todo);
 			break;
 		case State::UNAVAILABLE:
 		{
 			std::string message = VLC->generaltexth->translate(dynamic_cast<const HillFort *>(fort)->getUnavailableUpgradeMessage());
-			LOCPLINT->showInfoDialog(message, std::vector<std::shared_ptr<CComponent>>(), soundBase::sound_todo);
+			GAME->interface()->showInfoDialog(message, std::vector<std::shared_ptr<CComponent>>(), soundBase::sound_todo);
 			break;
 		}
 		case State::MAKE_UPGRADE:
@@ -1272,8 +1273,8 @@ void CHillFortWindow::makeDeal(SlotID slot)
 					if(const CStackInstance * s = hero->getStackPtr(SlotID(i)))
 					{
 						UpgradeInfo info(s->getCreatureID());
-						LOCPLINT->cb->fillUpgradeInfo(hero, SlotID(i), info);
-						LOCPLINT->cb->upgradeCreature(hero, SlotID(i), info.getUpgrade());
+						GAME->interface()->cb->fillUpgradeInfo(hero, SlotID(i), info);
+						GAME->interface()->cb->upgradeCreature(hero, SlotID(i), info.getUpgrade());
 					}
 				}
 			}
@@ -1298,13 +1299,13 @@ std::string CHillFortWindow::getTextForSlot(SlotID slot)
 
 CHillFortWindow::State CHillFortWindow::getState(SlotID slot)
 {
-	TResources myRes = LOCPLINT->cb->getResourceAmount();
+	TResources myRes = GAME->interface()->cb->getResourceAmount();
 
 	if(hero->slotEmpty(slot))
 		return State::EMPTY;
 
 	UpgradeInfo info(hero->getStackPtr(slot)->getCreatureID());
-	LOCPLINT->cb->fillUpgradeInfo(hero, slot, info);
+	GAME->interface()->cb->fillUpgradeInfo(hero, slot, info);
 	if(info.hasUpgrades() && !info.canUpgrade())
 		return State::UNAVAILABLE;  // Hill Fort may limit level of upgradeable creatures, e.g. mini Hill Fort from HOTA
 
@@ -1324,7 +1325,7 @@ CThievesGuildWindow::CThievesGuildWindow(const CGObjectInstance * _owner):
 	OBJECT_CONSTRUCTION;
 
 	SThievesGuildInfo tgi; //info to be displayed
-	LOCPLINT->cb->getThievesGuildInfo(tgi, owner);
+	GAME->interface()->cb->getThievesGuildInfo(tgi, owner);
 
 	exitb = std::make_shared<CButton>(Point(748, 556), AnimationPath::builtin("TPMAGE1"), CButton::tooltip(VLC->generaltexth->allTexts[600]), [&](){ close();}, EShortcut::GLOBAL_RETURN);
 	statusbar = CGStatusBar::create(3, 555, ImagePath::builtin("TStatBar.bmp"), 742);
@@ -1530,7 +1531,7 @@ CObjectListWindow::CObjectListWindow(const std::vector<int> & _items, std::share
 	items.reserve(_items.size());
 
 	for(int id : _items)
-		items.push_back(std::make_pair(id, LOCPLINT->cb->getObjInstance(ObjectInstanceID(id))->getObjectName()));
+		items.push_back(std::make_pair(id, GAME->interface()->cb->getObjInstance(ObjectInstanceID(id))->getObjectName()));
 	itemsVisible = items;
 
 	init(titleWidget_, _title, _descr, searchBoxEnabled);

+ 29 - 28
client/windows/InfoWindows.cpp

@@ -16,6 +16,7 @@
 #include "../adventureMap/AdventureMapInterface.h"
 #include "../adventureMap/CMinimap.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/CursorHandler.h"
 #include "../gui/Shortcut.h"
 #include "../gui/WindowHandler.h"
@@ -56,7 +57,7 @@ CSelWindow::CSelWindow( const std::string & Text, PlayerColor player, int charpe
 	text = std::make_shared<CTextBox>(Text, Rect(0, 0, 250, 100), 0, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE);
 
 	if(buttons.size() > 1 && askID.getNum() >= 0) //cancel button functionality
-		buttons.back()->addCallback([askID](){LOCPLINT->cb->selectionMade(0, askID);});
+		buttons.back()->addCallback([askID](){GAME->interface()->cb->selectionMade(0, askID);});
 
 	if(buttons.size() == 1)
 		buttons.front()->assignedKey = EShortcut::GLOBAL_RETURN;
@@ -85,7 +86,7 @@ void CSelWindow::madeChoice()
 	if(components)
 		ret = components->selectedIndex();
 
-	LOCPLINT->cb->selectionMade(ret + 1, ID);
+	GAME->interface()->cb->selectionMade(ret + 1, ID);
 }
 
 void CSelWindow::madeChoiceAndClose()
@@ -141,14 +142,14 @@ void CInfoWindow::close()
 {
 	WindowBase::close();
 
-	if(LOCPLINT)
-		LOCPLINT->showingDialog->setFree();
+	if(GAME->interface())
+		GAME->interface()->showingDialog->setFree();
 }
 
 void CInfoWindow::showAll(Canvas & to)
 {
 	CIntObject::showAll(to);
-	CMessage::drawBorder(LOCPLINT ? LOCPLINT->playerID : PlayerColor(1), to, pos.w+28, pos.h+29, pos.x-14, pos.y-15);
+	CMessage::drawBorder(GAME->interface() ? GAME->interface()->playerID : PlayerColor(1), to, pos.w+28, pos.h+29, pos.x-14, pos.y-15);
 }
 
 CInfoWindow::~CInfoWindow() = default;
@@ -160,7 +161,7 @@ void CInfoWindow::showInfoDialog(const std::string & text, const TCompsInfo & co
 
 void CInfoWindow::showYesNoDialog(const std::string & text, const TCompsInfo & components, const CFunctionList<void()> & onYes, const CFunctionList<void()> & onNo, PlayerColor player)
 {
-	assert(!LOCPLINT || LOCPLINT->showingDialog->isBusy());
+	assert(!GAME->interface() || GAME->interface()->showingDialog->isBusy());
 	std::vector<std::pair<AnimationPath, CFunctionList<void()>>> pom;
 	pom.emplace_back(AnimationPath::builtin("IOKAY.DEF"), nullptr);
 	pom.emplace_back(AnimationPath::builtin("ICANCEL.DEF"), nullptr);
@@ -191,7 +192,7 @@ bool CRClickPopup::isPopupWindow() const
 
 void CRClickPopup::createAndPush(const std::string & txt, const CInfoWindow::TCompsInfo & comps)
 {
-	PlayerColor player = LOCPLINT ? LOCPLINT->playerID : PlayerColor(1); //if no player, then use blue
+	PlayerColor player = GAME->interface() ? GAME->interface()->playerID : PlayerColor(1); //if no player, then use blue
 	if(settings["session"]["spectate"].Bool()) //TODO: there must be better way to implement this
 		player = PlayerColor(1);
 
@@ -225,20 +226,20 @@ void CRClickPopup::createAndPush(const CGObjectInstance * obj, const Point & p,
 		std::vector<Component> components;
 		if(settings["general"]["enableUiEnhancements"].Bool())
 		{
-			if(LOCPLINT->localState->getCurrentHero())
-				components = obj->getPopupComponents(LOCPLINT->localState->getCurrentHero());
+			if(GAME->interface()->localState->getCurrentHero())
+				components = obj->getPopupComponents(GAME->interface()->localState->getCurrentHero());
 			else
-				components = obj->getPopupComponents(LOCPLINT->playerID);
+				components = obj->getPopupComponents(GAME->interface()->playerID);
 		}
 
 		std::vector<std::shared_ptr<CComponent>> guiComponents;
 		for(auto & component : components)
 			guiComponents.push_back(std::make_shared<CComponent>(component));
 
-		if(LOCPLINT->localState->getCurrentHero())
-			CRClickPopup::createAndPush(obj->getPopupText(LOCPLINT->localState->getCurrentHero()), guiComponents);
+		if(GAME->interface()->localState->getCurrentHero())
+			CRClickPopup::createAndPush(obj->getPopupText(GAME->interface()->localState->getCurrentHero()), guiComponents);
 		else
-			CRClickPopup::createAndPush(obj->getPopupText(LOCPLINT->playerID), guiComponents);
+			CRClickPopup::createAndPush(obj->getPopupText(GAME->interface()->playerID), guiComponents);
 	}
 }
 
@@ -291,7 +292,7 @@ CInfoBoxPopup::CInfoBoxPopup(Point position, const CGTownInstance * town)
 	: AdventureMapPopup(RCLICK_POPUP | PLAYER_COLORED, ImagePath::builtin("TOWNQVBK"), position)
 {
 	InfoAboutTown iah;
-	LOCPLINT->cb->getTownInfo(town, iah, LOCPLINT->localState->getCurrentArmy()); //todo: should this be nearest hero?
+	GAME->interface()->cb->getTownInfo(town, iah, GAME->interface()->localState->getCurrentArmy()); //todo: should this be nearest hero?
 
 	OBJECT_CONSTRUCTION;
 	tooltip = std::make_shared<CTownTooltip>(Point(9, 10), iah);
@@ -305,7 +306,7 @@ CInfoBoxPopup::CInfoBoxPopup(Point position, const CGHeroInstance * hero)
 	: AdventureMapPopup(RCLICK_POPUP | PLAYER_COLORED, ImagePath::builtin("HEROQVBK"), position)
 {
 	InfoAboutHero iah;
-	LOCPLINT->cb->getHeroInfo(hero, iah, LOCPLINT->localState->getCurrentArmy()); //todo: should this be nearest hero?
+	GAME->interface()->cb->getHeroInfo(hero, iah, GAME->interface()->localState->getCurrentArmy()); //todo: should this be nearest hero?
 
 	OBJECT_CONSTRUCTION;
 	tooltip = std::make_shared<CHeroTooltip>(Point(9, 10), iah);
@@ -319,7 +320,7 @@ CInfoBoxPopup::CInfoBoxPopup(Point position, const CGGarrison * garr)
 	: AdventureMapPopup(RCLICK_POPUP | PLAYER_COLORED, ImagePath::builtin("TOWNQVBK"), position)
 {
 	InfoAboutTown iah;
-	LOCPLINT->cb->getTownInfo(garr, iah);
+	GAME->interface()->cb->getTownInfo(garr, iah);
 
 	OBJECT_CONSTRUCTION;
 	tooltip = std::make_shared<CArmyTooltip>(Point(9, 10), iah);
@@ -351,7 +352,7 @@ MinimapWithIcons::MinimapWithIcons(const Point & position)
 	Rect borderSurface(10, 40, 147, 147);
 	Rect borderUnderground(166, 40, 147, 147);
 
-	bool singleLevelMap = LOCPLINT->cb->getMapSize().z == 1;
+	bool singleLevelMap = GAME->interface()->cb->getMapSize().z == 1;
 
 	if (singleLevelMap)
 	{
@@ -375,12 +376,12 @@ void MinimapWithIcons::addIcon(const int3 & coordinates, const ImagePath & image
 
 	Rect areaSurface(11, 41, 144, 144);
 	Rect areaUnderground(167, 41, 144, 144);
-	bool singleLevelMap = LOCPLINT->cb->getMapSize().z == 1;
+	bool singleLevelMap = GAME->interface()->cb->getMapSize().z == 1;
 	if (singleLevelMap)
 		areaSurface.x += 78;
 
-	int positionX = 144 * coordinates.x / LOCPLINT->cb->getMapSize().x;
-	int positionY = 144 * coordinates.y / LOCPLINT->cb->getMapSize().y;
+	int positionX = 144 * coordinates.x / GAME->interface()->cb->getMapSize().x;
+	int positionY = 144 * coordinates.y / GAME->interface()->cb->getMapSize().y;
 
 	Point iconPosition(positionX, positionY);
 
@@ -402,7 +403,7 @@ TeleporterPopup::TeleporterPopup(const Point & position, const CGTeleport * tele
 	pos.h = 200;
 
 	filledBackground = std::make_shared<FilledTexturePlayerColored>(Rect(0, 0, pos.w, pos.h));
-	labelTitle = std::make_shared<CLabel>(pos.w / 2, 20, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, teleporter->getPopupText(LOCPLINT->playerID));
+	labelTitle = std::make_shared<CLabel>(pos.w / 2, 20, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, teleporter->getPopupText(GAME->interface()->playerID));
 	minimap = std::make_shared<MinimapWithIcons>(Point(0,0));
 
 	const auto & entrances = teleporter->getAllEntrances();
@@ -414,7 +415,7 @@ TeleporterPopup::TeleporterPopup(const Point & position, const CGTeleport * tele
 
 	for (const auto exit : allTeleporters)
 	{
-		const auto * exitObject = LOCPLINT->cb->getObj(exit, false);
+		const auto * exitObject = GAME->interface()->cb->getObj(exit, false);
 
 		if (!exitObject)
 			continue;
@@ -444,10 +445,10 @@ KeymasterPopup::KeymasterPopup(const Point & position, const CGKeys * keymasterO
 
 	filledBackground = std::make_shared<FilledTexturePlayerColored>(Rect(0, 0, pos.w, pos.h));
 	labelTitle = std::make_shared<CLabel>(pos.w / 2, 20, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, keymasterOrGuard->getObjectName());
-	labelDescription = std::make_shared<CLabel>(pos.w / 2, 40, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, keymasterOrGuard->getObjectDescription(LOCPLINT->playerID));
+	labelDescription = std::make_shared<CLabel>(pos.w / 2, 40, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, keymasterOrGuard->getObjectDescription(GAME->interface()->playerID));
 	minimap = std::make_shared<MinimapWithIcons>(Point(0,20));
 
-	const auto allObjects = LOCPLINT->cb->getAllVisitableObjs();
+	const auto allObjects = GAME->interface()->cb->getAllVisitableObjs();
 
 	for (const auto mapObject : allObjects)
 	{
@@ -483,10 +484,10 @@ ObeliskPopup::ObeliskPopup(const Point & position, const CGObelisk * obelisk)
 
 	filledBackground = std::make_shared<FilledTexturePlayerColored>(Rect(0, 0, pos.w, pos.h));
 	labelTitle = std::make_shared<CLabel>(pos.w / 2, 20, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, obelisk->getObjectName());
-	labelDescription = std::make_shared<CLabel>(pos.w / 2, 40, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, obelisk->getObjectDescription(LOCPLINT->playerID));
+	labelDescription = std::make_shared<CLabel>(pos.w / 2, 40, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, obelisk->getObjectDescription(GAME->interface()->playerID));
 	minimap = std::make_shared<MinimapWithIcons>(Point(0,20));
 
-	const auto allObjects = LOCPLINT->cb->getAllVisitableObjs();
+	const auto allObjects = GAME->interface()->cb->getAllVisitableObjs();
 
 	for (const auto mapObject : allObjects)
 	{
@@ -496,7 +497,7 @@ ObeliskPopup::ObeliskPopup(const Point & position, const CGObelisk * obelisk)
 		if (mapObject->ID != Obj::OBELISK)
 			continue;
 
-		if (mapObject->wasVisited(LOCPLINT->playerID))
+		if (mapObject->wasVisited(GAME->interface()->playerID))
 			minimap->addIcon(mapObject->visitablePos(), ImagePath::builtin("minimapIcons/obeliskVisited"));
 		else
 			minimap->addIcon(mapObject->visitablePos(), ImagePath::builtin("minimapIcons/obelisk"));
@@ -509,7 +510,7 @@ std::shared_ptr<WindowBase>
 CRClickPopup::createCustomInfoWindow(Point position, const CGObjectInstance * specific) //specific=0 => draws info about selected town/hero
 {
 	if(nullptr == specific)
-		specific = LOCPLINT->localState->getCurrentArmy();
+		specific = GAME->interface()->localState->getCurrentArmy();
 
 	if(nullptr == specific)
 	{

+ 1 - 1
client/windows/InfoWindows.h

@@ -58,7 +58,7 @@ public:
 	CInfoWindow();
 	~CInfoWindow();
 
-	//use only before the game starts! (showYesNoDialog in LOCPLINT must be used then)
+	//use only before the game starts! (showYesNoDialog in GAME->interface() must be used then)
 	static void showInfoDialog(const std::string & text, const TCompsInfo & components, PlayerColor player = PlayerColor(1));
 	static void showYesNoDialog(const std::string & text, const TCompsInfo & components, const CFunctionList<void()> & onYes, const CFunctionList<void()> & onNo, PlayerColor player = PlayerColor(1));
 	static std::shared_ptr<CInfoWindow> create(const std::string & text, PlayerColor playerID = PlayerColor(1), const TCompsInfo & components = TCompsInfo());

+ 7 - 6
client/windows/QuickRecruitmentWindow.cpp

@@ -15,6 +15,7 @@
 #include "../widgets/CreatureCostBox.h"
 #include "../widgets/Slider.h"
 #include "../GameEngine.h"
+#include "../GameInstance.h"
 #include "../gui/Shortcut.h"
 #include "../../CCallback.h"
 #include "../../lib/ResourceSet.h"
@@ -80,7 +81,7 @@ void QuickRecruitmentWindow::initWindow(Rect startupPosition)
 
 void QuickRecruitmentWindow::maxAllCards(std::vector<std::shared_ptr<CreaturePurchaseCard> > cards)
 {
-	auto allAvailableResources = LOCPLINT->cb->getResourceAmount();
+	auto allAvailableResources = GAME->interface()->cb->getResourceAmount();
 	for(auto i : boost::adaptors::reverse(cards))
 	{
 		si32 maxAmount = i->creatureOnTheCard->maxAmount(allAvailableResources);
@@ -96,7 +97,7 @@ void QuickRecruitmentWindow::maxAllCards(std::vector<std::shared_ptr<CreaturePur
 		i->slider->scrollToMax();
 		allAvailableResources -= (i->creatureOnTheCard->getFullRecruitCost() * maxAmount);
 	}
-	maxButton->block(allAvailableResources == LOCPLINT->cb->getResourceAmount());
+	maxButton->block(allAvailableResources == GAME->interface()->cb->getResourceAmount());
 }
 
 
@@ -115,7 +116,7 @@ void QuickRecruitmentWindow::purchaseUnits()
 						level = i;
 				i++;
 			}
-			auto onRecruit = [=](CreatureID id, int count){ LOCPLINT->cb->recruitCreatures(town, town->getUpperArmy(), id, count, level); };
+			auto onRecruit = [=](CreatureID id, int count){ GAME->interface()->cb->recruitCreatures(town, town->getUpperArmy(), id, count, level); };
 			CreatureID crid =  selected->creatureOnTheCard->getId();
 			SlotID dstslot = town -> getSlotFor(crid);
 			if(!dstslot.validSlot())
@@ -137,7 +138,7 @@ int QuickRecruitmentWindow::getAvailableCreatures()
 
 void QuickRecruitmentWindow::updateAllSliders()
 {
-	auto allAvailableResources = LOCPLINT->cb->getResourceAmount();
+	auto allAvailableResources = GAME->interface()->cb->getResourceAmount();
 	for(auto i : boost::adaptors::reverse(cards))
 		allAvailableResources -= (i->creatureOnTheCard->getFullRecruitCost() * i->slider->getValue());
 	for(auto i : cards)
@@ -152,8 +153,8 @@ void QuickRecruitmentWindow::updateAllSliders()
 			i->slider->setAmount(i->maxAmount);
 		i->slider->scrollTo(i->slider->getValue());
 	}
-	totalCost->createItems(LOCPLINT->cb->getResourceAmount() - allAvailableResources);
-	totalCost->set(LOCPLINT->cb->getResourceAmount() - allAvailableResources);
+	totalCost->createItems(GAME->interface()->cb->getResourceAmount() - allAvailableResources);
+	totalCost->set(GAME->interface()->cb->getResourceAmount() - allAvailableResources);
 }
 
 QuickRecruitmentWindow::QuickRecruitmentWindow(const CGTownInstance * townd, Rect startupPosition)

+ 14 - 13
client/windows/settings/SettingsMainWindow.cpp

@@ -22,7 +22,8 @@
 #include "CPlayerInterface.h"
 #include "CServerHandler.h"
 #include "../../../lib/filesystem/ResourcePath.h"
-#include "GameEngine.h"
+#include "../../GameEngine.h"
+#include "../../GameInstance.h"
 #include "gui/WindowHandler.h"
 #include "render/Canvas.h"
 #include "lobby/CSavingScreen.h"
@@ -61,9 +62,9 @@ SettingsMainWindow::SettingsMainWindow(BattleInterface * parentBattleUi) : Inter
 	std::shared_ptr<CButton> restartButton = widget<CButton>("restartButton");
 	assert(restartButton);
 
-	loadButton->block(CSH->isGuest());
-	saveButton->block(CSH->isGuest() || parentBattleUi);
-	restartButton->block(CSH->isGuest() || parentBattleUi);
+	loadButton->block(GAME->server().isGuest());
+	saveButton->block(GAME->server().isGuest() || parentBattleUi);
+	restartButton->block(GAME->server().isGuest() || parentBattleUi);
 
 	int defaultTabIndex = 0;
 	if(parentBattleUi != nullptr)
@@ -78,7 +79,7 @@ SettingsMainWindow::SettingsMainWindow(BattleInterface * parentBattleUi) : Inter
 	std::shared_ptr<CToggleGroup> mainTabs = widget<CToggleGroup>("settingsTabs");
 	mainTabs->setSelected(defaultTabIndex);
 	
-	LOCPLINT->gamePause(true);
+	GAME->interface()->gamePause(true);
 }
 
 std::shared_ptr<CIntObject> SettingsMainWindow::createTab(size_t index)
@@ -113,13 +114,13 @@ void SettingsMainWindow::close()
 	if(!ENGINE->windows().isTopWindow(this))
 		logGlobal->error("Only top interface must be closed");
 	
-	LOCPLINT->gamePause(false);
+	GAME->interface()->gamePause(false);
 	ENGINE->windows().popWindows(1);
 }
 
 void SettingsMainWindow::quitGameButtonCallback()
 {
-	LOCPLINT->showYesNoDialog(
+	GAME->interface()->showYesNoDialog(
 		VLC->generaltexth->allTexts[578],
 		[this]()
 		{
@@ -140,12 +141,12 @@ void SettingsMainWindow::backButtonCallback()
 
 void SettingsMainWindow::mainMenuButtonCallback()
 {
-	LOCPLINT->showYesNoDialog(
+	GAME->interface()->showYesNoDialog(
 		VLC->generaltexth->allTexts[578],
 		[this]()
 		{
 			close();
-			CSH->endGameplay();
+			GAME->server().endGameplay();
 			CMM->menu->switchToTab("main");
 		},
 		0
@@ -155,7 +156,7 @@ void SettingsMainWindow::mainMenuButtonCallback()
 void SettingsMainWindow::loadGameButtonCallback()
 {
 	close();
-	LOCPLINT->proposeLoadingGame();
+	GAME->interface()->proposeLoadingGame();
 }
 
 void SettingsMainWindow::saveGameButtonCallback()
@@ -166,13 +167,13 @@ void SettingsMainWindow::saveGameButtonCallback()
 
 void SettingsMainWindow::restartGameButtonCallback()
 {
-	LOCPLINT->showYesNoDialog(
+	GAME->interface()->showYesNoDialog(
 		VLC->generaltexth->allTexts[67],
 		[this]()
 		{
 			close();
 			ENGINE->dispatchMainThread([](){
-				CSH->sendRestartGame();
+				GAME->server().sendRestartGame();
 			});
 		},
 		0
@@ -181,7 +182,7 @@ void SettingsMainWindow::restartGameButtonCallback()
 
 void SettingsMainWindow::showAll(Canvas & to)
 {
-	auto color = LOCPLINT ? LOCPLINT->playerID : PlayerColor(1);
+	auto color = GAME->interface() ? GAME->interface()->playerID : PlayerColor(1);
 	if(settings["session"]["spectate"].Bool())
 		color = PlayerColor(1); // TODO: Spectator shouldn't need special code for UI colors
 

+ 13 - 10
clientapp/EntryPoint.cpp

@@ -19,6 +19,7 @@
 #include "../client/CServerHandler.h"
 #include "../client/eventsSDL/InputHandler.h"
 #include "../client/GameEngine.h"
+#include "../client/GameInstance.h"
 #include "../client/gui/CursorHandler.h"
 #include "../client/gui/WindowHandler.h"
 #include "../client/mainmenu/CMainMenu.h"
@@ -307,7 +308,7 @@ int main(int argc, char * argv[])
 	if(!settings["session"]["headless"].Bool())
 		ENGINE->init();
 
-	CSH = new CServerHandler();
+	GAME = std::make_unique<GameInstance>();
 	
 #ifndef VCMI_NO_THREADED_LOAD
 	//we can properly play intro only in the main thread, so we have to move loading to the separate thread
@@ -347,6 +348,7 @@ int main(int argc, char * argv[])
 		CMessage::init();
 		logGlobal->info("Message handler: %d ms", pomtime.getDiff());
 
+		ENGINE->cursor().init();
 		ENGINE->cursor().show();
 	}
 
@@ -360,13 +362,13 @@ int main(int argc, char * argv[])
 	{
 		session["testmap"].String() = vm["testmap"].as<std::string>();
 		session["onlyai"].Bool() = true;
-		boost::thread(&CServerHandler::debugStartTest, CSH, session["testmap"].String(), false);
+		boost::thread(&CServerHandler::debugStartTest, &GAME->server(), session["testmap"].String(), false);
 	}
 	else if(vm.count("testsave"))
 	{
 		session["testsave"].String() = vm["testsave"].as<std::string>();
 		session["onlyai"].Bool() = true;
-		boost::thread(&CServerHandler::debugStartTest, CSH, session["testsave"].String(), true);
+		boost::thread(&CServerHandler::debugStartTest, &GAME->server(), session["testsave"].String(), true);
 	}
 	else
 	{
@@ -430,18 +432,17 @@ static void mainLoop()
 
 [[noreturn]] static void quitApplication()
 {
-	CSH->endNetwork();
+	GAME->server().endNetwork();
 
 	if(!settings["session"]["headless"].Bool())
 	{
-		if(CSH->client)
-			CSH->endGameplay();
+		if(GAME->server().client)
+			GAME->server().endGameplay();
 
 		ENGINE->windows().clear();
 	}
 
-	vstd::clear_pointer(CSH);
-
+	GAME.reset();
 	CMM.reset();
 
 	if(!settings["session"]["headless"].Bool())
@@ -466,6 +467,8 @@ static void mainLoop()
 		logConfig = nullptr;
 	}
 
+	ENGINE.reset();
+
 	std::cout << "Ending...\n";
 	quitApplicationImmediately(0);
 }
@@ -486,8 +489,8 @@ void handleQuit(bool ask)
 		return;
 	}
 
-	if (LOCPLINT)
-		LOCPLINT->showYesNoDialog(VLC->generaltexth->allTexts[69], quitApplication, nullptr);
+	if (GAME->interface())
+		GAME->interface()->showYesNoDialog(VLC->generaltexth->allTexts[69], quitApplication, nullptr);
 	else
 		CInfoWindow::showYesNoDialog(VLC->generaltexth->allTexts[69], {}, quitApplication, {}, PlayerColor(1));
 }