Explorar o código

Always use ResourcePath for referencing images and animations

Ivan Savenko %!s(int64=2) %!d(string=hai) anos
pai
achega
823ffa7a07
Modificáronse 100 ficheiros con 661 adicións e 655 borrados
  1. 1 1
      AI/Nullkiller/Engine/PriorityEvaluator.cpp
  2. 1 1
      client/CMT.cpp
  3. 5 5
      client/CMusicHandler.cpp
  4. 3 3
      client/CPlayerInterface.cpp
  5. 1 1
      client/CServerHandler.cpp
  6. 1 1
      client/CVideoHandler.cpp
  7. 1 1
      client/Client.cpp
  8. 6 6
      client/ClientCommandManager.cpp
  9. 15 17
      client/adventureMap/AdventureMapWidget.cpp
  10. 2 2
      client/adventureMap/AdventureMapWidget.h
  11. 6 6
      client/adventureMap/AdventureOptions.cpp
  12. 19 19
      client/adventureMap/CInfoBar.cpp
  13. 2 1
      client/adventureMap/CInfoBar.h
  14. 10 10
      client/adventureMap/CList.cpp
  15. 1 1
      client/adventureMap/CMinimap.cpp
  16. 2 2
      client/adventureMap/CResDataBar.cpp
  17. 3 2
      client/adventureMap/CResDataBar.h
  18. 2 2
      client/adventureMap/TurnTimerWidget.cpp
  19. 8 8
      client/battle/BattleAnimationClasses.cpp
  20. 7 6
      client/battle/BattleAnimationClasses.h
  21. 3 3
      client/battle/BattleEffectsController.cpp
  22. 8 8
      client/battle/BattleFieldController.cpp
  23. 2 2
      client/battle/BattleInterface.cpp
  24. 20 20
      client/battle/BattleInterfaceClasses.cpp
  25. 4 4
      client/battle/BattleObstacleController.cpp
  26. 3 1
      client/battle/BattleObstacleController.h
  27. 3 3
      client/battle/BattleProjectileController.cpp
  28. 3 2
      client/battle/BattleProjectileController.h
  29. 23 23
      client/battle/BattleSiegeController.cpp
  30. 3 2
      client/battle/BattleSiegeController.h
  31. 4 4
      client/battle/BattleStacksController.cpp
  32. 9 9
      client/battle/BattleWindow.cpp
  33. 1 1
      client/battle/CreatureAnimation.cpp
  34. 2 2
      client/battle/CreatureAnimation.h
  35. 5 5
      client/gui/CursorHandler.cpp
  36. 2 1
      client/gui/CursorHandler.h
  37. 10 10
      client/gui/InterfaceObjectConfigurable.cpp
  38. 10 11
      client/lobby/CBonusSelection.cpp
  39. 8 8
      client/lobby/CLobbyScreen.cpp
  40. 2 2
      client/lobby/CSavingScreen.cpp
  41. 1 1
      client/lobby/CScenarioInfoScreen.cpp
  42. 11 11
      client/lobby/CSelectionBase.cpp
  43. 25 25
      client/lobby/OptionsTab.cpp
  44. 1 1
      client/lobby/OptionsTab.h
  45. 2 2
      client/lobby/RandomMapTab.cpp
  46. 23 23
      client/lobby/SelectionTab.cpp
  47. 7 6
      client/lobby/SelectionTab.h
  48. 3 3
      client/mainmenu/CCampaignScreen.cpp
  49. 24 24
      client/mainmenu/CMainMenu.cpp
  50. 1 1
      client/mainmenu/CMainMenu.h
  51. 1 1
      client/mainmenu/CreditsScreen.cpp
  52. 11 11
      client/mapView/MapRenderer.cpp
  53. 5 3
      client/mapView/MapRenderer.h
  54. 1 1
      client/mapView/MapViewCache.cpp
  55. 15 23
      client/render/CAnimation.cpp
  56. 3 2
      client/render/CAnimation.h
  57. 2 2
      client/render/CBitmapHandler.cpp
  58. 5 5
      client/render/CDefFile.cpp
  59. 2 1
      client/render/CDefFile.h
  60. 11 13
      client/render/Graphics.cpp
  61. 3 2
      client/render/Graphics.h
  62. 4 2
      client/render/IImage.h
  63. 2 2
      client/renderSDL/CBitmapFont.cpp
  64. 2 2
      client/renderSDL/CBitmapFont.h
  65. 1 1
      client/renderSDL/CBitmapHanFont.cpp
  66. 1 1
      client/renderSDL/CTrueTypeFont.cpp
  67. 3 3
      client/renderSDL/SDLImage.cpp
  68. 3 3
      client/widgets/Buttons.cpp
  69. 5 4
      client/widgets/Buttons.h
  70. 3 3
      client/widgets/CArtifactHolder.cpp
  71. 1 1
      client/widgets/CArtifactsOfHeroBackpack.cpp
  72. 2 2
      client/widgets/CArtifactsOfHeroBase.cpp
  73. 6 6
      client/widgets/CComponent.cpp
  74. 3 3
      client/widgets/CComponent.h
  75. 1 1
      client/widgets/CGarrisonInt.cpp
  76. 1 1
      client/widgets/CWindowWithArtifacts.cpp
  77. 1 1
      client/widgets/ComboBox.cpp
  78. 1 1
      client/widgets/ComboBox.h
  79. 1 1
      client/widgets/CreatureCostBox.cpp
  80. 8 8
      client/widgets/Images.cpp
  81. 9 8
      client/widgets/Images.h
  82. 24 24
      client/widgets/MiscWidgets.cpp
  83. 4 4
      client/widgets/RadialMenu.cpp
  84. 4 4
      client/widgets/Slider.cpp
  85. 2 2
      client/widgets/TextControls.cpp
  86. 3 2
      client/widgets/TextControls.h
  87. 39 40
      client/windows/CCastleInterface.cpp
  88. 2 2
      client/windows/CCastleInterface.h
  89. 30 30
      client/windows/CCreatureWindow.cpp
  90. 4 3
      client/windows/CCreatureWindow.h
  91. 2 2
      client/windows/CHeroBackpackWindow.cpp
  92. 20 20
      client/windows/CHeroWindow.cpp
  93. 31 31
      client/windows/CKingdomInterface.cpp
  94. 5 5
      client/windows/CKingdomInterface.h
  95. 2 2
      client/windows/CMessage.cpp
  96. 4 4
      client/windows/CPuzzleWindow.cpp
  97. 5 5
      client/windows/CQuestLog.cpp
  98. 1 1
      client/windows/CQuestLog.h
  99. 11 11
      client/windows/CSpellWindow.cpp
  100. 32 32
      client/windows/CTradeWindow.cpp

+ 1 - 1
AI/Nullkiller/Engine/PriorityEvaluator.cpp

@@ -68,7 +68,7 @@ PriorityEvaluator::~PriorityEvaluator()
 
 void PriorityEvaluator::initVisitTile()
 {
-	auto file = CResourceHandler::get()->load(ResourceID("config/ai/object-priorities.txt"))->readAll();
+	auto file = CResourceHandler::get()->load(ResourcePath("config/ai/object-priorities.txt"))->readAll();
 	std::string str = std::string((char *)file.first.get(), file.second);
 	engine = fl::FllImporter().fromString(str);
 	armyLossPersentageVariable = engine->getInputVariable("armyLoss");

+ 1 - 1
client/CMT.cpp

@@ -251,7 +251,7 @@ int main(int argc, char * argv[])
 	// Some basic data validation to produce better error messages in cases of incorrect install
 	auto testFile = [](std::string filename, std::string message)
 	{
-		if (!CResourceHandler::get()->existsResource(ResourceID(filename)))
+		if (!CResourceHandler::get()->existsResource(ResourcePath(filename)))
 			handleFatalError(message, false);
 	};
 

+ 5 - 5
client/CMusicHandler.cpp

@@ -75,7 +75,7 @@ void CSoundHandler::onVolumeChange(const JsonNode &volumeNode)
 
 CSoundHandler::CSoundHandler():
 	listener(settings.listen["general"]["sound"]),
-	ambientConfig(JsonNode(ResourceID("config/ambientSounds.json")))
+	ambientConfig(JsonNode(ResourcePath("config/ambientSounds.json")))
 {
 	listener(std::bind(&CSoundHandler::onVolumeChange, this, _1));
 
@@ -126,7 +126,7 @@ Mix_Chunk *CSoundHandler::GetSoundChunk(std::string &sound, bool cache)
 		if (cache && soundChunks.find(sound) != soundChunks.end())
 			return soundChunks[sound].first;
 
-		auto data = CResourceHandler::get()->load(ResourceID(std::string("SOUNDS/") + sound, EResType::SOUND))->readAll();
+		auto data = CResourceHandler::get()->load(ResourcePath(std::string("SOUNDS/") + sound, EResType::SOUND))->readAll();
 		SDL_RWops *ops = SDL_RWFromMem(data.first.get(), (int)data.second);
 		Mix_Chunk *chunk = Mix_LoadWAV_RW(ops, 1);	// will free ops
 
@@ -357,7 +357,7 @@ CMusicHandler::CMusicHandler():
 {
 	listener(std::bind(&CMusicHandler::onVolumeChange, this, _1));
 
-	auto mp3files = CResourceHandler::get()->getFilteredFiles([](const ResourceID & id) ->  bool
+	auto mp3files = CResourceHandler::get()->getFilteredFiles([](const ResourcePath & id) ->  bool
 	{
 		if(id.getType() != EResType::SOUND)
 			return false;
@@ -369,7 +369,7 @@ CMusicHandler::CMusicHandler():
 		return true;
 	});
 
-	for(const ResourceID & file : mp3files)
+	for(const ResourcePath & file : mp3files)
 	{
 		if(boost::algorithm::istarts_with(file.getName(), "MUSIC/Combat"))
 			addEntryToSet("battle", file.getName());
@@ -573,7 +573,7 @@ void MusicEntry::load(std::string musicURI)
 
 	try
 	{
-		auto musicFile = MakeSDLRWops(CResourceHandler::get()->load(ResourceID(std::move(musicURI), EResType::SOUND)));
+		auto musicFile = MakeSDLRWops(CResourceHandler::get()->load(ResourcePath(std::move(musicURI), EResType::SOUND)));
 		music = Mix_LoadMUS_RW(musicFile, SDL_TRUE);
 	}
 	catch(std::exception &e)

+ 3 - 3
client/CPlayerInterface.cpp

@@ -1112,11 +1112,11 @@ void CPlayerInterface::showBlockingDialog( const std::string &text, const std::v
 		for (auto & component : components)
 			intComps.push_back(std::make_shared<CSelectableComponent>(component)); //will be deleted by CSelWindow::close
 
-		std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
-		pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
+		std::vector<std::pair<AnimationPath,CFunctionList<void()> > > pom;
+		pom.push_back({ AnimationPath::builtin("IOKAY.DEF"),0});
 		if (cancel)
 		{
-			pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",0));
+			pom.push_back({AnimationPath::builtin("ICANCEL.DEF"),0});
 		}
 
 		int charperline = 35;

+ 1 - 1
client/CServerHandler.cpp

@@ -748,7 +748,7 @@ void CServerHandler::debugStartTest(std::string filename, bool save)
 	if(save)
 	{
 		resetStateForLobby(StartInfo::LOAD_GAME);
-		mapInfo->saveInit(ResourceID(filename, EResType::SAVEGAME));
+		mapInfo->saveInit(ResourcePath(filename, EResType::SAVEGAME));
 		screenType = ESelectionScreen::loadGame;
 	}
 	else

+ 1 - 1
client/CVideoHandler.cpp

@@ -85,7 +85,7 @@ bool CVideoPlayer::open(std::string fname, bool loop, bool useOverlay, bool scal
 	doLoop = loop;
 	frameTime = 0;
 
-	ResourceID resource(std::string("Video/") + fname, EResType::VIDEO);
+	ResourcePath resource(std::string("Video/") + fname, EResType::VIDEO);
 
 	if (!CResourceHandler::get()->existsResource(resource))
 	{

+ 1 - 1
client/Client.cpp

@@ -222,7 +222,7 @@ void CClient::loadGame(CGameState * initializedGameState)
 	// try to deserialize client data including sleepingHeroes
 	try
 	{
-		boost::filesystem::path clientSaveName = *CResourceHandler::get()->getResourceName(ResourceID(CSH->si->mapname, EResType::CLIENT_SAVEGAME));
+		boost::filesystem::path clientSaveName = *CResourceHandler::get()->getResourceName(ResourcePath(CSH->si->mapname, EResType::CLIENT_SAVEGAME));
 
 		if(clientSaveName.empty())
 			throw std::runtime_error("Cannot open client part of " + CSH->si->mapname);

+ 6 - 6
client/ClientCommandManager.cpp

@@ -182,12 +182,12 @@ void ClientCommandManager::handleNotDialogCommand()
 void ClientCommandManager::handleConvertTextCommand()
 {
 	logGlobal->info("Searching for available maps");
-	std::unordered_set<ResourceID> mapList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident)
+	std::unordered_set<ResourcePath> mapList = CResourceHandler::get()->getFilteredFiles([&](const ResourcePath & ident)
 	{
 		return ident.getType() == EResType::MAP;
 	});
 
-	std::unordered_set<ResourceID> campaignList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident)
+	std::unordered_set<ResourcePath> campaignList = CResourceHandler::get()->getFilteredFiles([&](const ResourcePath & ident)
 	{
 		return ident.getType() == EResType::CAMPAIGN;
 	});
@@ -292,7 +292,7 @@ void ClientCommandManager::handleGetTextCommand()
 			VCMIDirs::get().userExtractedPath();
 
 	auto list =
-			CResourceHandler::get()->getFilteredFiles([](const ResourceID & ident)
+			CResourceHandler::get()->getFilteredFiles([](const ResourcePath & ident)
 			{
 				return ident.getType() == EResType::TEXT && boost::algorithm::starts_with(ident.getName(), "DATA/");
 			});
@@ -317,7 +317,7 @@ void ClientCommandManager::handleDef2bmpCommand(std::istringstream& singleWordBu
 {
 	std::string URI;
 	singleWordBuffer >> URI;
-	std::unique_ptr<CAnimation> anim = std::make_unique<CAnimation>(URI);
+	std::unique_ptr<CAnimation> anim = std::make_unique<CAnimation>(AnimationPath::builtin(URI));
 	anim->preload();
 	anim->exportBitmaps(VCMIDirs::get().userExtractedPath());
 }
@@ -327,11 +327,11 @@ void ClientCommandManager::handleExtractCommand(std::istringstream& singleWordBu
 	std::string URI;
 	singleWordBuffer >> URI;
 
-	if(CResourceHandler::get()->existsResource(ResourceID(URI)))
+	if(CResourceHandler::get()->existsResource(ResourcePath(URI)))
 	{
 		const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / URI;
 
-		auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll();
+		auto data = CResourceHandler::get()->load(ResourcePath(URI))->readAll();
 
 		boost::filesystem::create_directories(outPath.parent_path());
 		std::ofstream outFile(outPath.c_str(), std::ofstream::binary);

+ 15 - 17
client/adventureMap/AdventureMapWidget.cpp

@@ -30,7 +30,7 @@
 #include "../PlayerLocalState.h"
 
 #include "../../lib/constants/StringConstants.h"
-#include "../../lib/filesystem/ResourceID.h"
+#include "../../lib/filesystem/ResourcePath.h"
 
 AdventureMapWidget::AdventureMapWidget( std::shared_ptr<AdventureMapShortcuts> shortcuts )
 	: shortcuts(shortcuts)
@@ -56,11 +56,11 @@ AdventureMapWidget::AdventureMapWidget( std::shared_ptr<AdventureMapShortcuts> s
 	for (const auto & entry : shortcuts->getShortcuts())
 		addShortcut(entry.shortcut, entry.callback);
 
-	const JsonNode config(ResourceID("config/widgets/adventureMap.json"));
+	const JsonNode config(ResourcePath("config/widgets/adventureMap.json"));
 
 	for(const auto & entry : config["options"]["imagesPlayerColored"].Vector())
 	{
-		ResourceID resourceName(entry.String(), EResType::IMAGE);
+		ResourcePath resourceName(entry.String(), EResType::IMAGE);
 		playerColorerImages.push_back(resourceName.getName());
 	}
 
@@ -127,22 +127,22 @@ Rect AdventureMapWidget::readArea(const JsonNode & source, const Rect & bounding
 	return Rect(topLeft + boundingBox.topLeft(), dimensions);
 }
 
-std::shared_ptr<IImage> AdventureMapWidget::loadImage(const std::string & name)
+std::shared_ptr<IImage> AdventureMapWidget::loadImage(const JsonNode & name)
 {
-	ResourceID resource(name, EResType::IMAGE);
+	ImagePath resource = ImagePath::fromJson(name);
 
 	if(images.count(resource.getName()) == 0)
-		images[resource.getName()] = IImage::createFromFile(resource.getName());
+		images[resource.getName()] = IImage::createFromFile(resource);
 
 	return images[resource.getName()];
 }
 
-std::shared_ptr<CAnimation> AdventureMapWidget::loadAnimation(const std::string & name)
+std::shared_ptr<CAnimation> AdventureMapWidget::loadAnimation(const JsonNode & name)
 {
-	ResourceID resource(name, EResType::ANIMATION);
+	AnimationPath resource = AnimationPath::fromJson(name);
 
 	if(animations.count(resource.getName()) == 0)
-		animations[resource.getName()] = std::make_shared<CAnimation>(resource.getName());
+		animations[resource.getName()] = std::make_shared<CAnimation>(resource);
 
 	return animations[resource.getName()];
 }
@@ -158,15 +158,14 @@ std::shared_ptr<CIntObject> AdventureMapWidget::buildMapImage(const JsonNode & i
 {
 	Rect targetArea = readTargetArea(input["area"]);
 	Rect sourceArea = readSourceArea(input["sourceArea"], input["area"]);
-	std::string image = input["image"].String();
 
-	return std::make_shared<CFilledTexture>(loadImage(image), targetArea, sourceArea);
+	return std::make_shared<CFilledTexture>(loadImage(input["image"]), targetArea, sourceArea);
 }
 
 std::shared_ptr<CIntObject> AdventureMapWidget::buildMapButton(const JsonNode & input)
 {
 	auto position = readTargetArea(input["area"]);
-	auto image = input["image"].String();
+	auto image = AnimationPath::fromJson(input["image"]);
 	auto help = readHintText(input["help"]);
 	bool playerColored = input["playerColored"].Bool();
 
@@ -259,9 +258,8 @@ std::shared_ptr<CIntObject> AdventureMapWidget::buildMapIcon(const JsonNode & in
 	Rect area = readTargetArea(input["area"]);
 	size_t index = input["index"].Integer();
 	size_t perPlayer = input["perPlayer"].Integer();
-	std::string image = input["image"].String();
 
-	return std::make_shared<CAdventureMapIcon>(area.topLeft(), loadAnimation(image), index, perPlayer);
+	return std::make_shared<CAdventureMapIcon>(area.topLeft(), loadAnimation(input["image"]), index, perPlayer);
 }
 
 std::shared_ptr<CIntObject> AdventureMapWidget::buildMapTownList(const JsonNode & input)
@@ -298,7 +296,7 @@ std::shared_ptr<CIntObject> AdventureMapWidget::buildMinimap(const JsonNode & in
 std::shared_ptr<CIntObject> AdventureMapWidget::buildResourceDateBar(const JsonNode & input)
 {
 	Rect area = readTargetArea(input["area"]);
-	std::string image = input["image"].String();
+	auto image = ImagePath::fromJson(input["image"]);
 
 	auto result = std::make_shared<CResDataBar>(image, area.topLeft());
 
@@ -320,7 +318,7 @@ std::shared_ptr<CIntObject> AdventureMapWidget::buildResourceDateBar(const JsonN
 std::shared_ptr<CIntObject> AdventureMapWidget::buildStatusBar(const JsonNode & input)
 {
 	Rect area = readTargetArea(input["area"]);
-	std::string image = input["image"].String();
+	auto image = ImagePath::fromJson(input["image"]);
 
 	auto background = std::make_shared<CFilledTexture>(image, area);
 
@@ -330,7 +328,7 @@ std::shared_ptr<CIntObject> AdventureMapWidget::buildStatusBar(const JsonNode &
 std::shared_ptr<CIntObject> AdventureMapWidget::buildTexturePlayerColored(const JsonNode & input)
 {
 	logGlobal->debug("Building widget CFilledTexture");
-	auto image = input["image"].String();
+	auto image = ImagePath::fromJson(input["image"]);
 	Rect area = readTargetArea(input["area"]);
 	return std::make_shared<FilledTexturePlayerColored>(image, area);
 }

+ 2 - 2
client/adventureMap/AdventureMapWidget.h

@@ -48,8 +48,8 @@ class AdventureMapWidget : public InterfaceObjectConfigurable
 	Rect readSourceArea(const JsonNode & source, const JsonNode & sourceCommon);
 	Rect readArea(const JsonNode & source, const Rect & boundingBox);
 
-	std::shared_ptr<IImage> loadImage(const std::string & name);
-	std::shared_ptr<CAnimation> loadAnimation(const std::string & name);
+	std::shared_ptr<IImage> loadImage(const JsonNode & name);
+	std::shared_ptr<CAnimation> loadAnimation(const JsonNode & name);
 
 	std::shared_ptr<CIntObject> buildInfobox(const JsonNode & input);
 	std::shared_ptr<CIntObject> buildMapImage(const JsonNode & input);

+ 6 - 6
client/adventureMap/AdventureOptions.cpp

@@ -25,22 +25,22 @@
 #include "../../lib/StartInfo.h"
 
 AdventureOptions::AdventureOptions()
-	: CWindowObject(PLAYER_COLORED, "ADVOPTS")
+	: CWindowObject(PLAYER_COLORED, ImagePath::builtin("ADVOPTS"))
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 
-	viewWorld = std::make_shared<CButton>(Point(24, 23), "ADVVIEW.DEF", CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_VIEW_WORLD);
+	viewWorld = std::make_shared<CButton>(Point(24, 23), AnimationPath::builtin("ADVVIEW.DEF"), CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_VIEW_WORLD);
 	viewWorld->addCallback( [] { LOCPLINT->viewWorldMap(); });
 
-	exit = std::make_shared<CButton>(Point(204, 313), "IOK6432.DEF", CButton::tooltip(), std::bind(&AdventureOptions::close, this), EShortcut::GLOBAL_RETURN);
+	exit = std::make_shared<CButton>(Point(204, 313), AnimationPath::builtin("IOK6432.DEF"), CButton::tooltip(), std::bind(&AdventureOptions::close, this), EShortcut::GLOBAL_RETURN);
 
-	scenInfo = std::make_shared<CButton>(Point(24, 198), "ADVINFO.DEF", CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_VIEW_SCENARIO);
+	scenInfo = std::make_shared<CButton>(Point(24, 198), AnimationPath::builtin("ADVINFO.DEF"), CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_VIEW_SCENARIO);
 	scenInfo->addCallback(AdventureOptions::showScenarioInfo);
 
-	puzzle = std::make_shared<CButton>(Point(24, 81), "ADVPUZ.DEF", CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_VIEW_PUZZLE);
+	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));
 
-	dig = std::make_shared<CButton>(Point(24, 139), "ADVDIG.DEF", CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_DIG_GRAIL);
+	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));
 	else

+ 19 - 19
client/adventureMap/CInfoBar.cpp

@@ -51,7 +51,7 @@ CInfoBar::EmptyVisibleInfo::EmptyVisibleInfo()
 CInfoBar::VisibleHeroInfo::VisibleHeroInfo(const CGHeroInstance * hero)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-	background = std::make_shared<CPicture>("ADSTATHR");
+	background = std::make_shared<CPicture>(ImagePath::builtin("ADSTATHR"));
 
 	if(settings["gameTweaks"]["infoBarCreatureManagement"].Bool())
 		heroTooltip = std::make_shared<CInteractableHeroTooltip>(Point(0,0), hero);
@@ -62,7 +62,7 @@ CInfoBar::VisibleHeroInfo::VisibleHeroInfo(const CGHeroInstance * hero)
 CInfoBar::VisibleTownInfo::VisibleTownInfo(const CGTownInstance * town)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-	background = std::make_shared<CPicture>("ADSTATCS");
+	background = std::make_shared<CPicture>(ImagePath::builtin("ADSTATCS"));
 
 	if(settings["gameTweaks"]["infoBarCreatureManagement"].Bool())
 		townTooltip = std::make_shared<CInteractableTownTooltip>(Point(0,0), town);
@@ -88,36 +88,36 @@ CInfoBar::VisibleDateInfo::VisibleDateInfo()
 	forceRefresh.push_back(label);
 }
 
-std::string CInfoBar::VisibleDateInfo::getNewDayName()
+AnimationPath CInfoBar::VisibleDateInfo::getNewDayName()
 {
 	if(LOCPLINT->cb->getDate(Date::DAY) == 1)
-		return "NEWDAY";
+		return AnimationPath::builtin("NEWDAY");
 
 	if(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK) != 1)
-		return "NEWDAY";
+		return AnimationPath("NEWDAY");
 
 	switch(LOCPLINT->cb->getDate(Date::WEEK))
 	{
 	case 1:
-		return "NEWWEEK1";
+		return AnimationPath("NEWWEEK1");
 	case 2:
-		return "NEWWEEK2";
+		return AnimationPath("NEWWEEK2");
 	case 3:
-		return "NEWWEEK3";
+		return AnimationPath("NEWWEEK3");
 	case 4:
-		return "NEWWEEK4";
+		return AnimationPath("NEWWEEK4");
 	default:
-		return "";
+		return AnimationPath();
 	}
 }
 
 CInfoBar::VisibleEnemyTurnInfo::VisibleEnemyTurnInfo(PlayerColor player)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-	background = std::make_shared<CPicture>("ADSTATNX");
-	banner = std::make_shared<CAnimImage>("CREST58", player.getNum(), 0, 20, 51);
-	sand = std::make_shared<CShowableAnim>(99, 51, "HOURSAND", 0, 100); // H3 uses around 100 ms per frame
-	glass = std::make_shared<CShowableAnim>(99, 51, "HOURGLAS", CShowableAnim::PLAY_ONCE, 1000); // H3 scales this nicely for AI turn duration, don't have anything like that in vcmi
+	background = std::make_shared<CPicture>(ImagePath::builtin("ADSTATNX"));
+	banner = std::make_shared<CAnimImage>(AnimationPath::builtin("CREST58"), player.getNum(), 0, 20, 51);
+	sand = std::make_shared<CShowableAnim>(99, 51, AnimationPath::builtin("HOURSAND"), 0, 100); // H3 uses around 100 ms per frame
+	glass = std::make_shared<CShowableAnim>(99, 51, AnimationPath::builtin("HOURGLAS"), CShowableAnim::PLAY_ONCE, 1000); // H3 scales this nicely for AI turn duration, don't have anything like that in vcmi
 }
 
 CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo()
@@ -148,14 +148,14 @@ CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo()
 	}
 
 	//generate widgets
-	background = std::make_shared<CPicture>("ADSTATIN");
+	background = std::make_shared<CPicture>(ImagePath::builtin("ADSTATIN"));
 	allyLabel = std::make_shared<CLabel>(10, 106, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[390] + ":");
 	enemyLabel = std::make_shared<CLabel>(10, 136, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[391] + ":");
 
 	int posx = allyLabel->pos.w + allyLabel->pos.x - pos.x + 4;
 	for(PlayerColor & player : allies)
 	{
-		auto image = std::make_shared<CAnimImage>("ITGFLAGS", player.getNum(), 0, posx, 102);
+		auto image = std::make_shared<CAnimImage>(AnimationPath::builtin("ITGFLAGS"), player.getNum(), 0, posx, 102);
 		posx += image->pos.w;
 		flags.push_back(image);
 	}
@@ -163,14 +163,14 @@ CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo()
 	posx = enemyLabel->pos.w + enemyLabel->pos.x - pos.x + 4;
 	for(PlayerColor & player : enemies)
 	{
-		auto image = std::make_shared<CAnimImage>("ITGFLAGS", player.getNum(), 0, posx, 132);
+		auto image = std::make_shared<CAnimImage>(AnimationPath::builtin("ITGFLAGS"), player.getNum(), 0, posx, 132);
 		posx += image->pos.w;
 		flags.push_back(image);
 	}
 
 	for(size_t i=0; i<halls.size(); i++)
 	{
-		hallIcons.push_back(std::make_shared<CAnimImage>("itmtl", i, 0, 6 + 42 * (int)i , 11));
+		hallIcons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("itmtl"), i, 0, 6 + 42 * (int)i , 11));
 		if(halls[i])
 			hallLabels.push_back(std::make_shared<CLabel>( 26 + 42 * (int)i, 64, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, std::to_string(halls[i])));
 	}
@@ -180,7 +180,7 @@ CInfoBar::VisibleComponentInfo::VisibleComponentInfo(const std::vector<Component
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 
-	background = std::make_shared<CPicture>("ADSTATOT", 1, 0);
+	background = std::make_shared<CPicture>(ImagePath::builtin("ADSTATOT"), 1, 0);
 	auto fullRect = Rect(CInfoBar::offset, CInfoBar::offset, data_width - 2 * CInfoBar::offset, data_height - 2 * CInfoBar::offset);
 	auto textRect = fullRect;
 	auto imageRect = fullRect;

+ 2 - 1
client/adventureMap/CInfoBar.h

@@ -11,6 +11,7 @@
 
 #include "../gui/CIntObject.h"
 #include "CConfigHandler.h"
+#include "../../lib/filesystem/ResourcePath.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -86,7 +87,7 @@ private:
 		std::shared_ptr<CShowableAnim> animation;
 		std::shared_ptr<CLabel> label;
 
-		std::string getNewDayName();
+		AnimationPath getNewDayName();
 	public:
 		VisibleDateInfo();
 	};

+ 10 - 10
client/adventureMap/CList.cpp

@@ -206,9 +206,9 @@ void CList::selectPrev()
 CHeroList::CEmptyHeroItem::CEmptyHeroItem()
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-	movement = std::make_shared<CAnimImage>("IMOBIL", 0, 0, 0, 1);
-	portrait = std::make_shared<CPicture>("HPSXXX", movement->pos.w + 1, 0);
-	mana = std::make_shared<CAnimImage>("IMANA", 0, 0, movement->pos.w + portrait->pos.w + 2, 1 );
+	movement = std::make_shared<CAnimImage>(AnimationPath::builtin("IMOBIL"), 0, 0, 0, 1);
+	portrait = std::make_shared<CPicture>(ImagePath::builtin("HPSXXX"), movement->pos.w + 1, 0);
+	mana = std::make_shared<CAnimImage>(AnimationPath::builtin("IMANA"), 0, 0, movement->pos.w + portrait->pos.w + 2, 1 );
 
 	pos.w = mana->pos.w + mana->pos.x - pos.x;
 	pos.h = std::max(std::max<int>(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h);
@@ -219,9 +219,9 @@ CHeroList::CHeroItem::CHeroItem(CHeroList *parent, const CGHeroInstance * Hero)
 	hero(Hero)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-	movement = std::make_shared<CAnimImage>("IMOBIL", 0, 0, 0, 1);
-	portrait = std::make_shared<CAnimImage>("PortraitsSmall", hero->portrait, 0, movement->pos.w + 1);
-	mana = std::make_shared<CAnimImage>("IMANA", 0, 0, movement->pos.w + portrait->pos.w + 2, 1);
+	movement = std::make_shared<CAnimImage>(AnimationPath::builtin("IMOBIL"), 0, 0, 0, 1);
+	portrait = std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsSmall"), hero->portrait, 0, movement->pos.w + 1);
+	mana = std::make_shared<CAnimImage>(AnimationPath::builtin("IMANA"), 0, 0, movement->pos.w + portrait->pos.w + 2, 1);
 
 	pos.w = mana->pos.w + mana->pos.x - pos.x;
 	pos.h = std::max(std::max<int>(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h);
@@ -238,7 +238,7 @@ void CHeroList::CHeroItem::update()
 
 std::shared_ptr<CIntObject> CHeroList::CHeroItem::genSelection()
 {
-	return std::make_shared<CPicture>("HPSYYY", movement->pos.w + 1, 0);
+	return std::make_shared<CPicture>(ImagePath::builtin("HPSYYY"), movement->pos.w + 1, 0);
 }
 
 void CHeroList::CHeroItem::select(bool on)
@@ -319,7 +319,7 @@ 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));
-	return std::make_shared<CAnimImage>("ITPA", 0);
+	return std::make_shared<CAnimImage>(AnimationPath::builtin("ITPA"), 0);
 }
 
 CTownList::CTownItem::CTownItem(CTownList *parent, const CGTownInstance *Town):
@@ -327,14 +327,14 @@ CTownList::CTownItem::CTownItem(CTownList *parent, const CGTownInstance *Town):
 	town(Town)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-	picture = std::make_shared<CAnimImage>("ITPA", 0);
+	picture = std::make_shared<CAnimImage>(AnimationPath::builtin("ITPA"), 0);
 	pos = picture->pos;
 	update();
 }
 
 std::shared_ptr<CIntObject> CTownList::CTownItem::genSelection()
 {
-	return std::make_shared<CAnimImage>("ITPA", 1);
+	return std::make_shared<CAnimImage>(AnimationPath::builtin("ITPA"), 1);
 }
 
 void CTownList::CTownItem::update()

+ 1 - 1
client/adventureMap/CMinimap.cpp

@@ -94,7 +94,7 @@ CMinimap::CMinimap(const Rect & position)
 	pos.w = position.w;
 	pos.h = position.h;
 
-	aiShield = std::make_shared<CPicture>("AIShield");
+	aiShield = std::make_shared<CPicture>(ImagePath::builtin("AIShield"));
 	aiShield->disable();
 }
 

+ 2 - 2
client/adventureMap/CResDataBar.cpp

@@ -24,7 +24,7 @@
 #include "../../lib/CGeneralTextHandler.h"
 #include "../../lib/ResourceSet.h"
 
-CResDataBar::CResDataBar(const std::string & imageName, const Point & position)
+CResDataBar::CResDataBar(const ImagePath & imageName, const Point & position)
 {
 	pos.x += position.x;
 	pos.y += position.y;
@@ -37,7 +37,7 @@ CResDataBar::CResDataBar(const std::string & imageName, const Point & position)
 	pos.h = background->pos.h;
 }
 
-CResDataBar::CResDataBar(const std::string & defname, int x, int y, int offx, int offy, int resdist, int datedist):
+CResDataBar::CResDataBar(const ImagePath & defname, int x, int y, int offx, int offy, int resdist, int datedist):
 	CResDataBar(defname, Point(x,y))
 {
 	for (int i = 0; i < 7 ; i++)

+ 3 - 2
client/adventureMap/CResDataBar.h

@@ -10,6 +10,7 @@
 #pragma once
 
 #include "../gui/CIntObject.h"
+#include "../../lib/filesystem/ResourcePath.h"
 
 /// Resources bar which shows information about how many gold, crystals,... you have
 /// Current date is displayed too
@@ -25,10 +26,10 @@ class CResDataBar : public CIntObject
 public:
 
 	/// For dynamically-sized UI windows, e.g. adventure map interface
-	CResDataBar(const std::string & imageName, const Point & position);
+	CResDataBar(const ImagePath & imageName, const Point & position);
 
 	/// For fixed-size UI windows, e.g. CastleInterface
-	CResDataBar(const std::string &defname, int x, int y, int offx, int offy, int resdist, int datedist);
+	CResDataBar(const ImagePath & defname, int x, int y, int offx, int offy, int resdist, int datedist);
 
 	void setDatePosition(const Point & position);
 	void setResourcePosition(const GameResID & resource, const Point & position);

+ 2 - 2
client/adventureMap/TurnTimerWidget.cpp

@@ -25,7 +25,7 @@
 #include "../../CCallback.h"
 #include "../../lib/CStack.h"
 #include "../../lib/CPlayerState.h"
-#include "../../lib/filesystem/ResourceID.h"
+#include "../../lib/filesystem/ResourcePath.h"
 
 TurnTimerWidget::DrawRect::DrawRect(const Rect & r, const ColorRGBA & c):
 	CIntObject(), rect(r), color(c)
@@ -47,7 +47,7 @@ TurnTimerWidget::TurnTimerWidget():
 	
 	recActions &= ~DEACTIVATE;
 	
-	const JsonNode config(ResourceID("config/widgets/turnTimer.json"));
+	const JsonNode config(ResourcePath("config/widgets/turnTimer.json"));
 	
 	build(config);
 	

+ 8 - 8
client/battle/BattleAnimationClasses.cpp

@@ -807,7 +807,7 @@ void CatapultAnimation::tick(uint32_t msPassed)
 	Point shotTarget = owner.stacksController->getStackPositionAtHex(dest, defendingStack) + Point(225, 225) - Point(126, 105);
 
 	std::string soundFilename  = (catapultDamage > 0) ? "WALLHIT" : "WALLMISS";
-	std::string effectFilename = (catapultDamage > 0) ? "SGEXPL" : "CSGRCK";
+	AnimationPath effectFilename = AnimationPath::builtin((catapultDamage > 0) ? "SGEXPL" : "CSGRCK");
 
 	CCS->soundh->playSound( soundFilename );
 	owner.stacksController->addNewAnim( new EffectAnimation(owner, effectFilename, shotTarget));
@@ -879,42 +879,42 @@ uint32_t CastAnimation::getAttackClimaxFrame() const
 	return maxFrames / 2;
 }
 
-EffectAnimation::EffectAnimation(BattleInterface & owner, std::string animationName, int effects, bool reversed):
+EffectAnimation::EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, int effects, bool reversed):
 	BattleAnimation(owner),
 	animation(std::make_shared<CAnimation>(animationName)),
 	effectFlags(effects),
 	effectFinished(false),
 	reversed(reversed)
 {
-	logAnim->debug("CPointEffectAnimation::init: effect %s", animationName);
+	logAnim->debug("CPointEffectAnimation::init: effect %s", animationName.getName());
 }
 
-EffectAnimation::EffectAnimation(BattleInterface & owner, std::string animationName, std::vector<BattleHex> hex, int effects, bool reversed):
+EffectAnimation::EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, std::vector<BattleHex> hex, int effects, bool reversed):
 	EffectAnimation(owner, animationName, effects, reversed)
 {
 	battlehexes = hex;
 }
 
-EffectAnimation::EffectAnimation(BattleInterface & owner, std::string animationName, BattleHex hex, int effects, bool reversed):
+EffectAnimation::EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, BattleHex hex, int effects, bool reversed):
 	EffectAnimation(owner, animationName, effects, reversed)
 {
 	assert(hex.isValid());
 	battlehexes.push_back(hex);
 }
 
-EffectAnimation::EffectAnimation(BattleInterface & owner, std::string animationName, std::vector<Point> pos, int effects, bool reversed):
+EffectAnimation::EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, std::vector<Point> pos, int effects, bool reversed):
 	EffectAnimation(owner, animationName, effects, reversed)
 {
 	positions = pos;
 }
 
-EffectAnimation::EffectAnimation(BattleInterface & owner, std::string animationName, Point pos, int effects, bool reversed):
+EffectAnimation::EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, Point pos, int effects, bool reversed):
 	EffectAnimation(owner, animationName, effects, reversed)
 {
 	positions.push_back(pos);
 }
 
-EffectAnimation::EffectAnimation(BattleInterface & owner, std::string animationName, Point pos, BattleHex hex, int effects, bool reversed):
+EffectAnimation::EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, Point pos, BattleHex hex, int effects, bool reversed):
 	EffectAnimation(owner, animationName, effects, reversed)
 {
 	assert(hex.isValid());

+ 7 - 6
client/battle/BattleAnimationClasses.h

@@ -10,6 +10,7 @@
 #pragma once
 
 #include "../../lib/battle/BattleHex.h"
+#include "../../lib/filesystem/ResourcePath.h"
 #include "BattleConstants.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
@@ -334,17 +335,17 @@ public:
 	};
 
 	/// Create animation with screen-wide effect
-	EffectAnimation(BattleInterface & owner, std::string animationName, int effects = 0, bool reversed = false);
+	EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, int effects = 0, bool reversed = false);
 
 	/// Create animation positioned at point(s). Note that positions must be are absolute, including battleint position offset
-	EffectAnimation(BattleInterface & owner, std::string animationName, Point pos                 , int effects = 0, bool reversed = false);
-	EffectAnimation(BattleInterface & owner, std::string animationName, std::vector<Point> pos    , int effects = 0, bool reversed = false);
+	EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, Point pos                 , int effects = 0, bool reversed = false);
+	EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, std::vector<Point> pos    , int effects = 0, bool reversed = false);
 
 	/// Create animation positioned at certain hex(es)
-	EffectAnimation(BattleInterface & owner, std::string animationName, BattleHex hex             , int effects = 0, bool reversed = false);
-	EffectAnimation(BattleInterface & owner, std::string animationName, std::vector<BattleHex> hex, int effects = 0, bool reversed = false);
+	EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, BattleHex hex             , int effects = 0, bool reversed = false);
+	EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, std::vector<BattleHex> hex, int effects = 0, bool reversed = false);
 
-	EffectAnimation(BattleInterface & owner, std::string animationName, Point pos, BattleHex hex,   int effects = 0, bool reversed = false);
+	EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, Point pos, BattleHex hex,   int effects = 0, bool reversed = false);
 	 ~EffectAnimation();
 
 	bool init() override;

+ 3 - 3
client/battle/BattleEffectsController.cpp

@@ -27,7 +27,7 @@
 
 #include "../../CCallback.h"
 #include "../../lib/battle/BattleAction.h"
-#include "../../lib/filesystem/ResourceID.h"
+#include "../../lib/filesystem/ResourcePath.h"
 #include "../../lib/NetPacks.h"
 #include "../../lib/CStack.h"
 #include "../../lib/IGameEventsReceiver.h"
@@ -48,7 +48,7 @@ void BattleEffectsController::displayEffect(EBattleEffect effect, std::string so
 {
 	size_t effectID = static_cast<size_t>(effect);
 
-	std::string customAnim = graphics->battleACToDef[effectID][0];
+	AnimationPath customAnim = AnimationPath::builtinTODO(graphics->battleACToDef[effectID][0]);
 
 	CCS->soundh->playSound( soundFile );
 
@@ -132,7 +132,7 @@ void BattleEffectsController::collectRenderableObjects(BattleRenderer & renderer
 
 void BattleEffectsController::loadColorMuxers()
 {
-	const JsonNode config(ResourceID("config/battleEffects.json"));
+	const JsonNode config(ResourcePath("config/battleEffects.json"));
 
 	for(auto & muxer : config["colorMuxers"].Struct())
 	{

+ 8 - 8
client/battle/BattleFieldController.cpp

@@ -120,20 +120,20 @@ BattleFieldController::BattleFieldController(BattleInterface & owner):
 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
 
 	//preparing cells and hexes
-	cellBorder = IImage::createFromFile("CCELLGRD.BMP", EImageBlitMode::COLORKEY);
-	cellShade = IImage::createFromFile("CCELLSHD.BMP");
-	cellUnitMovementHighlight = IImage::createFromFile("UnitMovementHighlight.PNG", EImageBlitMode::COLORKEY);
-	cellUnitMaxMovementHighlight = IImage::createFromFile("UnitMaxMovementHighlight.PNG", EImageBlitMode::COLORKEY);
+	cellBorder = IImage::createFromFile(ImagePath::builtin("CCELLGRD.BMP"), EImageBlitMode::COLORKEY);
+	cellShade = IImage::createFromFile(ImagePath::builtin("CCELLSHD.BMP"));
+	cellUnitMovementHighlight = IImage::createFromFile(ImagePath::builtin("UnitMovementHighlight.PNG"), EImageBlitMode::COLORKEY);
+	cellUnitMaxMovementHighlight = IImage::createFromFile(ImagePath::builtin("UnitMaxMovementHighlight.PNG"), EImageBlitMode::COLORKEY);
 
-	attackCursors = std::make_shared<CAnimation>("CRCOMBAT");
+	attackCursors = std::make_shared<CAnimation>(AnimationPath::builtin("CRCOMBAT"));
 	attackCursors->preload();
 
 	initializeHexEdgeMaskToFrameIndex();
 
-	rangedFullDamageLimitImages = std::make_shared<CAnimation>("battle/rangeHighlights/rangeHighlightsGreen.json");
+	rangedFullDamageLimitImages = std::make_shared<CAnimation>(AnimationPath::builtin("battle/rangeHighlights/rangeHighlightsGreen.json"));
 	rangedFullDamageLimitImages->preload();
 
-	shootingRangeLimitImages = std::make_shared<CAnimation>("battle/rangeHighlights/rangeHighlightsRed.json");
+	shootingRangeLimitImages = std::make_shared<CAnimation>(AnimationPath::builtin("battle/rangeHighlights/rangeHighlightsRed.json"));
 	shootingRangeLimitImages->preload();
 
 	flipRangeLimitImagesIntoPositions(rangedFullDamageLimitImages);
@@ -150,7 +150,7 @@ BattleFieldController::BattleFieldController(BattleInterface & owner):
 	}
 	else
 	{
-		std::string backgroundName = owner.siegeController->getBattleBackgroundName();
+		auto backgroundName = owner.siegeController->getBattleBackgroundName();
 		background = IImage::createFromFile(backgroundName, EImageBlitMode::OPAQUE);
 	}
 

+ 2 - 2
client/battle/BattleInterface.cpp

@@ -440,8 +440,8 @@ void BattleInterface::spellCast(const BattleSpellCast * sc)
 		bool side = sc->side;
 
 		addToAnimationStage(EAnimationEvents::AFTER_HIT, [=](){
-			stacksController->addNewAnim(new EffectAnimation(*this, side ? "SP07_A.DEF" : "SP07_B.DEF", leftHero));
-			stacksController->addNewAnim(new EffectAnimation(*this, side ? "SP07_B.DEF" : "SP07_A.DEF", rightHero));
+			stacksController->addNewAnim(new EffectAnimation(*this, AnimationPath::builtin(side ? "SP07_A.DEF" : "SP07_B.DEF"), leftHero));
+			stacksController->addNewAnim(new EffectAnimation(*this, AnimationPath::builtin(side ? "SP07_B.DEF" : "SP07_A.DEF"), rightHero));
 		});
 	}
 

+ 20 - 20
client/battle/BattleInterfaceClasses.cpp

@@ -342,7 +342,7 @@ BattleHero::BattleHero(const BattleInterface & owner, const CGHeroInstance * her
 	currentFrame(0.f),
 	flagCurrentFrame(0.f)
 {
-	std::string animationPath;
+	AnimationPath animationPath;
 
 	if(!hero->type->battleImage.empty())
 		animationPath = hero->type->battleImage;
@@ -364,9 +364,9 @@ BattleHero::BattleHero(const BattleInterface & owner, const CGHeroInstance * her
 		animation->verticalFlip();
 
 	if(defender)
-		flagAnimation = std::make_shared<CAnimation>("CMFLAGR");
+		flagAnimation = std::make_shared<CAnimation>(AnimationPath::builtin("CMFLAGR"));
 	else
-		flagAnimation = std::make_shared<CAnimation>("CMFLAGL");
+		flagAnimation = std::make_shared<CAnimation>(AnimationPath::builtin("CMFLAGL"));
 
 	flagAnimation->preload();
 	flagAnimation->playerColored(hero->tempOwner);
@@ -386,7 +386,7 @@ HeroInfoBasicPanel::HeroInfoBasicPanel(const InfoAboutHero & hero, Point * posit
 
 	if(initializeBackground)
 	{
-		background = std::make_shared<CPicture>("CHRPOP");
+		background = std::make_shared<CPicture>(ImagePath::builtin("CHRPOP"));
 		background->getSurface()->setBlitMode(EImageBlitMode::OPAQUE);
 		background->colorize(hero.owner);
 	}
@@ -406,7 +406,7 @@ void HeroInfoBasicPanel::initializeData(const InfoAboutHero & hero)
 	auto currentSpellPoints = hero.details->mana;
 	auto maxSpellPoints = hero.details->manaLimit;
 
-	icons.push_back(std::make_shared<CAnimImage>("PortraitsLarge", hero.portrait, 0, 10, 6));
+	icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsLarge"), hero.portrait, 0, 10, 6));
 
 	//primary stats
 	labels.push_back(std::make_shared<CLabel>(9, 75, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[380] + ":"));
@@ -423,8 +423,8 @@ void HeroInfoBasicPanel::initializeData(const InfoAboutHero & hero)
 	labels.push_back(std::make_shared<CLabel>(9, 131, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[384] + ":"));
 	labels.push_back(std::make_shared<CLabel>(9, 143, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[385] + ":"));
 
-	icons.push_back(std::make_shared<CAnimImage>("IMRL22", morale + 3, 0, 47, 131));
-	icons.push_back(std::make_shared<CAnimImage>("ILCK22", luck + 3, 0, 47, 143));
+	icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("IMRL22"), morale + 3, 0, 47, 131));
+	icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("ILCK22"), luck + 3, 0, 47, 143));
 
 	//spell points
 	labels.push_back(std::make_shared<CLabel>(39, 174, EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[387]));
@@ -446,7 +446,7 @@ void HeroInfoBasicPanel::show(Canvas & to)
 }
 
 HeroInfoWindow::HeroInfoWindow(const InfoAboutHero & hero, Point * position)
-	: CWindowObject(RCLICK_POPUP | SHADOW_DISABLED, "CHRPOP")
+	: CWindowObject(RCLICK_POPUP | SHADOW_DISABLED, ImagePath::builtin("CHRPOP"))
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 	if (position != nullptr)
@@ -462,16 +462,16 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 
-	background = std::make_shared<CPicture>("CPRESULT");
+	background = std::make_shared<CPicture>(ImagePath::builtin("CPRESULT"));
 	background->colorize(owner.playerID);
 	pos = center(background->pos);
 
-	exit = std::make_shared<CButton>(Point(384, 505), "iok6432.def", std::make_pair("", ""), [&](){ bExitf();}, EShortcut::GLOBAL_ACCEPT);
+	exit = std::make_shared<CButton>(Point(384, 505), AnimationPath::builtin("iok6432.def"), std::make_pair("", ""), [&](){ bExitf();}, EShortcut::GLOBAL_ACCEPT);
 	exit->setBorderColor(Colors::METALLIC_GOLD);
 	
 	if(allowReplay)
 	{
-		repeat = std::make_shared<CButton>(Point(24, 505), "icn6432.def", std::make_pair("", ""), [&](){ bRepeatf();}, EShortcut::GLOBAL_CANCEL);
+		repeat = std::make_shared<CButton>(Point(24, 505), AnimationPath::builtin("icn6432.def"), std::make_pair("", ""), [&](){ bRepeatf();}, EShortcut::GLOBAL_CANCEL);
 		repeat->setBorderColor(Colors::METALLIC_GOLD);
 		labels.push_back(std::make_shared<CLabel>(232, 520, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->translate("vcmi.battleResultsWindow.applyResultsLabel")));
 	}
@@ -507,7 +507,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
 
 		if(heroInfo.portrait >= 0) //attacking hero
 		{
-			icons.push_back(std::make_shared<CAnimImage>("PortraitsLarge", heroInfo.portrait, 0, xs[i], 38));
+			icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsLarge"), heroInfo.portrait, 0, xs[i], 38));
 			sideNames[i] = heroInfo.name;
 		}
 		else
@@ -525,7 +525,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
 
 			if(best != stacks.end()) //should be always but to be safe...
 			{
-				icons.push_back(std::make_shared<CAnimImage>("TWCRPORT", (*best)->unitType()->getIconIndex(), 0, xs[i], 38));
+				icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("TWCRPORT"), (*best)->unitType()->getIconIndex(), 0, xs[i], 38));
 				sideNames[i] = (*best)->unitType()->getNamePluralTranslated();
 			}
 		}
@@ -552,7 +552,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
 				if (creature->getId() == CreatureID::ARROW_TOWERS )
 					continue; // do not show destroyed towers in battle results
 
-				icons.push_back(std::make_shared<CAnimImage>("CPRSMALL", creature->getIconIndex(), 0, xPos, yPos));
+				icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("CPRSMALL"), creature->getIconIndex(), 0, xPos, yPos));
 				std::ostringstream amount;
 				amount<<elem.second;
 				labels.push_back(std::make_shared<CLabel>(xPos + 16, yPos + 42, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, amount.str()));
@@ -676,8 +676,8 @@ StackQueue::StackQueue(bool Embedded, BattleInterface & owner)
 		pos.x += parent->pos.w/2 - pos.w/2;
 		pos.y += 10;
 
-		icons = std::make_shared<CAnimation>("CPRSMALL");
-		stateIcons = std::make_shared<CAnimation>("VCMI/BATTLEQUEUE/STATESSMALL");
+		icons = std::make_shared<CAnimation>(AnimationPath::builtin("CPRSMALL"));
+		stateIcons = std::make_shared<CAnimation>(AnimationPath::builtin("VCMI/BATTLEQUEUE/STATESSMALL"));
 	}
 	else
 	{
@@ -686,10 +686,10 @@ StackQueue::StackQueue(bool Embedded, BattleInterface & owner)
 		pos.x += 0;
 		pos.y -= pos.h;
 
-		background = std::make_shared<CFilledTexture>("DIBOXBCK", Rect(0, 0, pos.w, pos.h));
+		background = std::make_shared<CFilledTexture>(ImagePath::builtin("DIBOXBCK"), Rect(0, 0, pos.w, pos.h));
 
-		icons = std::make_shared<CAnimation>("TWCRPORT");
-		stateIcons = std::make_shared<CAnimation>("VCMI/BATTLEQUEUE/STATESSMALL");
+		icons = std::make_shared<CAnimation>(AnimationPath::builtin("TWCRPORT"));
+		stateIcons = std::make_shared<CAnimation>(AnimationPath::builtin("VCMI/BATTLEQUEUE/STATESSMALL"));
 		//TODO: where use big icons?
 		//stateIcons = std::make_shared<CAnimation>("VCMI/BATTLEQUEUE/STATESBIG");
 	}
@@ -750,7 +750,7 @@ StackQueue::StackBox::StackBox(StackQueue * owner):
 	CIntObject(SHOW_POPUP | HOVER), owner(owner)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-	background = std::make_shared<CPicture>(owner->embedded ? "StackQueueSmall" : "StackQueueLarge");
+	background = std::make_shared<CPicture>(ImagePath::builtin(owner->embedded ? "StackQueueSmall" : "StackQueueLarge"));
 
 	pos.w = background->pos.w;
 	pos.h = background->pos.h;

+ 4 - 4
client/battle/BattleObstacleController.cpp

@@ -42,7 +42,7 @@ BattleObstacleController::BattleObstacleController(BattleInterface & owner):
 
 void BattleObstacleController::loadObstacleImage(const CObstacleInstance & oi)
 {
-	std::string animationName = oi.getAnimation();
+	AnimationPath animationName = oi.getAnimation();
 
 	if (animationsCache.count(animationName) == 0)
 	{
@@ -50,7 +50,7 @@ void BattleObstacleController::loadObstacleImage(const CObstacleInstance & oi)
 		{
 			// obstacle uses single bitmap image for animations
 			auto animation = std::make_shared<CAnimation>();
-			animation->setCustom(animationName, 0, 0);
+			animation->setCustom(animationName.getName(), 0, 0);
 			animationsCache[animationName] = animation;
 			animation->preload();
 		}
@@ -76,7 +76,7 @@ void BattleObstacleController::obstacleRemoved(const std::vector<ObstacleChanges
 			continue;
 		}
 
-		auto animation = std::make_shared<CAnimation>(obstacle["appearAnimation"].String());
+		auto animation = std::make_shared<CAnimation>(AnimationPath::fromJson(obstacle["appearAnimation"]));
 		animation->preload();
 
 		auto first = animation->getImage(0, 0);
@@ -87,7 +87,7 @@ void BattleObstacleController::obstacleRemoved(const std::vector<ObstacleChanges
 		// -> if we know how to blit obstacle, let's blit the effect in the same place
 		Point whereTo = getObstaclePosition(first, obstacle);
 		//AFAIK, in H3 there is no sound of obstacle removal
-		owner.stacksController->addNewAnim(new EffectAnimation(owner, obstacle["appearAnimation"].String(), whereTo, obstacle["position"].Integer(), 0, true));
+		owner.stacksController->addNewAnim(new EffectAnimation(owner, AnimationPath::fromJson(obstacle["appearAnimation"]), whereTo, obstacle["position"].Integer(), 0, true));
 
 		obstacleAnimations.erase(oi.id);
 		//so when multiple obstacles are removed, they show up one after another

+ 3 - 1
client/battle/BattleObstacleController.h

@@ -9,6 +9,8 @@
  */
 #pragma once
 
+#include "../../lib/filesystem/ResourcePath.h"
+
 VCMI_LIB_NAMESPACE_BEGIN
 
 struct BattleHex;
@@ -35,7 +37,7 @@ class BattleObstacleController
 	float timePassed;
 
 	/// cached animations of all obstacles in current battle
-	std::map<std::string, std::shared_ptr<CAnimation>> animationsCache;
+	std::map<AnimationPath, std::shared_ptr<CAnimation>> animationsCache;
 
 	/// list of all obstacles that are currently being rendered
 	std::map<si32, std::shared_ptr<CAnimation>> obstacleAnimations;

+ 3 - 3
client/battle/BattleProjectileController.cpp

@@ -188,7 +188,7 @@ void BattleProjectileController::initStackProjectile(const CStack * stack)
 	projectilesCache[creature.animation.projectileImageName] = createProjectileImage(creature.animation.projectileImageName);
 }
 
-std::shared_ptr<CAnimation> BattleProjectileController::createProjectileImage(const std::string & path )
+std::shared_ptr<CAnimation> BattleProjectileController::createProjectileImage(const AnimationPath & path )
 {
 	std::shared_ptr<CAnimation> projectile = std::make_shared<CAnimation>(path);
 	projectile->preload();
@@ -204,7 +204,7 @@ std::shared_ptr<CAnimation> BattleProjectileController::createProjectileImage(co
 std::shared_ptr<CAnimation> BattleProjectileController::getProjectileImage(const CStack * stack)
 {
 	const CCreature & creature = getShooter(stack);
-	std::string imageName = creature.animation.projectileImageName;
+	AnimationPath imageName = creature.animation.projectileImageName;
 
 	if (!projectilesCache.count(imageName))
 		initStackProjectile(stack);
@@ -361,7 +361,7 @@ void BattleProjectileController::createProjectile(const CStack * shooter, Point
 void BattleProjectileController::createSpellProjectile(const CStack * shooter, Point from, Point dest, const CSpell * spell)
 {
 	double projectileAngle = std::abs(atan2(dest.x - from.x, dest.y - from.y));
-	std::string animToDisplay = spell->animationInfo.selectProjectile(projectileAngle);
+	AnimationPath animToDisplay = spell->animationInfo.selectProjectile(projectileAngle);
 
 	assert(!animToDisplay.empty());
 

+ 3 - 2
client/battle/BattleProjectileController.h

@@ -11,6 +11,7 @@
 
 #include "../../lib/CCreatureHandler.h"
 #include "../../lib/Point.h"
+#include "../../lib/filesystem/ResourcePath.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -83,13 +84,13 @@ class BattleProjectileController
 	BattleInterface & owner;
 
 	/// all projectiles loaded during current battle
-	std::map<std::string, std::shared_ptr<CAnimation>> projectilesCache;
+	std::map<AnimationPath, std::shared_ptr<CAnimation>> projectilesCache;
 
 	/// projectiles currently flying on battlefield
 	std::vector<std::shared_ptr<ProjectileBase>> projectiles;
 
 	std::shared_ptr<CAnimation> getProjectileImage(const CStack * stack);
-	std::shared_ptr<CAnimation> createProjectileImage(const std::string & path );
+	std::shared_ptr<CAnimation> createProjectileImage(const AnimationPath & path );
 	void initStackProjectile(const CStack * stack);
 
 	bool stackUsesRayProjectile(const CStack * stack) const;

+ 23 - 23
client/battle/BattleSiegeController.cpp

@@ -28,7 +28,7 @@
 #include "../../lib/CStack.h"
 #include "../../lib/mapObjects/CGTownInstance.h"
 
-std::string BattleSiegeController::getWallPieceImageName(EWallVisual::EWallVisual what, EWallState state) const
+ImagePath BattleSiegeController::getWallPieceImageName(EWallVisual::EWallVisual what, EWallState state) const
 {
 	auto getImageIndex = [&]() -> int
 	{
@@ -68,44 +68,44 @@ std::string BattleSiegeController::getWallPieceImageName(EWallVisual::EWallVisua
 			auto faction = town->town->faction->getIndex();
 
 			if (faction == ETownType::RAMPART || faction == ETownType::NECROPOLIS || faction == ETownType::DUNGEON || faction == ETownType::STRONGHOLD)
-				return prefix + "TPW1.BMP";
+				return ImagePath::builtinTODO(prefix + "TPW1.BMP");
 			else
-				return prefix + "TPWL.BMP";
+				return ImagePath::builtinTODO(prefix + "TPWL.BMP");
 		}
 	case EWallVisual::KEEP:
-		return prefix + "MAN" + addit + ".BMP";
+		return ImagePath::builtinTODO(prefix + "MAN" + addit + ".BMP");
 	case EWallVisual::BOTTOM_TOWER:
-		return prefix + "TW1" + addit + ".BMP";
+		return ImagePath::builtinTODO(prefix + "TW1" + addit + ".BMP");
 	case EWallVisual::BOTTOM_WALL:
-		return prefix + "WA1" + addit + ".BMP";
+		return ImagePath::builtinTODO(prefix + "WA1" + addit + ".BMP");
 	case EWallVisual::WALL_BELLOW_GATE:
-		return prefix + "WA3" + addit + ".BMP";
+		return ImagePath::builtinTODO(prefix + "WA3" + addit + ".BMP");
 	case EWallVisual::WALL_OVER_GATE:
-		return prefix + "WA4" + addit + ".BMP";
+		return ImagePath::builtinTODO(prefix + "WA4" + addit + ".BMP");
 	case EWallVisual::UPPER_WALL:
-		return prefix + "WA6" + addit + ".BMP";
+		return ImagePath::builtinTODO(prefix + "WA6" + addit + ".BMP");
 	case EWallVisual::UPPER_TOWER:
-		return prefix + "TW2" + addit + ".BMP";
+		return ImagePath::builtinTODO(prefix + "TW2" + addit + ".BMP");
 	case EWallVisual::GATE:
-		return prefix + "DRW" + addit + ".BMP";
+		return ImagePath::builtinTODO(prefix + "DRW" + addit + ".BMP");
 	case EWallVisual::GATE_ARCH:
-		return prefix + "ARCH.BMP";
+		return ImagePath::builtinTODO(prefix + "ARCH.BMP");
 	case EWallVisual::BOTTOM_STATIC_WALL:
-		return prefix + "WA2.BMP";
+		return ImagePath::builtinTODO(prefix + "WA2.BMP");
 	case EWallVisual::UPPER_STATIC_WALL:
-		return prefix + "WA5.BMP";
+		return ImagePath::builtinTODO(prefix + "WA5.BMP");
 	case EWallVisual::MOAT:
-		return prefix + "MOAT.BMP";
+		return ImagePath::builtinTODO(prefix + "MOAT.BMP");
 	case EWallVisual::MOAT_BANK:
-		return prefix + "MLIP.BMP";
+		return ImagePath::builtinTODO(prefix + "MLIP.BMP");
 	case EWallVisual::KEEP_BATTLEMENT:
-		return prefix + "MANC.BMP";
+		return ImagePath::builtinTODO(prefix + "MANC.BMP");
 	case EWallVisual::BOTTOM_BATTLEMENT:
-		return prefix + "TW1C.BMP";
+		return ImagePath::builtinTODO(prefix + "TW1C.BMP");
 	case EWallVisual::UPPER_BATTLEMENT:
-		return prefix + "TW2C.BMP";
+		return ImagePath::builtinTODO(prefix + "TW2C.BMP");
 	default:
-		return "";
+		return ImagePath();
 	}
 }
 
@@ -118,10 +118,10 @@ void BattleSiegeController::showWallPiece(Canvas & canvas, EWallVisual::EWallVis
 		canvas.draw(wallPieceImages[what], Point(pos.x, pos.y));
 }
 
-std::string BattleSiegeController::getBattleBackgroundName() const
+ImagePath BattleSiegeController::getBattleBackgroundName() const
 {
 	const std::string & prefix = town->town->clientInfo.siegePrefix;
-	return prefix + "BACK.BMP";
+	return ImagePath::builtinTODO(prefix + "BACK.BMP");
 }
 
 bool BattleSiegeController::getWallPieceExistance(EWallVisual::EWallVisual what) const
@@ -341,7 +341,7 @@ void BattleSiegeController::stackIsCatapulting(const CatapultAttack & ca)
 			positions.push_back(owner.stacksController->getStackPositionAtHex(attackInfo.destinationTile, nullptr) + Point(99, 120));
 
 		CCS->soundh->playSound( "WALLHIT" );
-		owner.stacksController->addNewAnim(new EffectAnimation(owner, "SGEXPL.DEF", positions));
+		owner.stacksController->addNewAnim(new EffectAnimation(owner, AnimationPath::builtin("SGEXPL.DEF"), positions));
 	}
 
 	owner.waitForAnimations();

+ 3 - 2
client/battle/BattleSiegeController.h

@@ -11,6 +11,7 @@
 
 #include "../../lib/GameConstants.h"
 #include "../../lib/battle/BattleHex.h"
+#include "../../lib/filesystem/ResourcePath.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -76,7 +77,7 @@ class BattleSiegeController
 	std::array<std::shared_ptr<IImage>, EWallVisual::WALL_LAST + 1> wallPieceImages;
 
 	/// return URI for image for a wall piece
-	std::string getWallPieceImageName(EWallVisual::EWallVisual what, EWallState state) const;
+	ImagePath getWallPieceImageName(EWallVisual::EWallVisual what, EWallState state) const;
 
 	/// returns BattleHex to which chosen wall piece is bound
 	BattleHex getWallPiecePosition(EWallVisual::EWallVisual what) const;
@@ -102,7 +103,7 @@ public:
 
 	/// queries from other battle controllers
 	bool isAttackableByCatapult(BattleHex hex) const;
-	std::string getBattleBackgroundName() const;
+	ImagePath getBattleBackgroundName() const;
 	const CCreature *getTurretCreature() const;
 	Point getTurretCreaturePosition( BattleHex position ) const;
 

+ 4 - 4
client/battle/BattleStacksController.cpp

@@ -76,10 +76,10 @@ BattleStacksController::BattleStacksController(BattleInterface & owner):
 	animIDhelper(0)
 {
 	//preparing graphics for displaying amounts of creatures
-	amountNormal     = IImage::createFromFile("CMNUMWIN.BMP", EImageBlitMode::COLORKEY);
-	amountPositive   = IImage::createFromFile("CMNUMWIN.BMP", EImageBlitMode::COLORKEY);
-	amountNegative   = IImage::createFromFile("CMNUMWIN.BMP", EImageBlitMode::COLORKEY);
-	amountEffNeutral = IImage::createFromFile("CMNUMWIN.BMP", EImageBlitMode::COLORKEY);
+	amountNormal     = IImage::createFromFile(ImagePath::builtin("CMNUMWIN.BMP"), EImageBlitMode::COLORKEY);
+	amountPositive   = IImage::createFromFile(ImagePath::builtin("CMNUMWIN.BMP"), EImageBlitMode::COLORKEY);
+	amountNegative   = IImage::createFromFile(ImagePath::builtin("CMNUMWIN.BMP"), EImageBlitMode::COLORKEY);
+	amountEffNeutral = IImage::createFromFile(ImagePath::builtin("CMNUMWIN.BMP"), EImageBlitMode::COLORKEY);
 
 	static const auto shifterNormal   = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 0.6f, 0.2f, 1.0f );
 	static const auto shifterPositive = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 0.2f, 1.0f, 0.2f );

+ 9 - 9
client/battle/BattleWindow.cpp

@@ -37,7 +37,7 @@
 #include "../../lib/mapObjects/CGHeroInstance.h"
 #include "../../lib/CStack.h"
 #include "../../lib/CConfigHandler.h"
-#include "../../lib/filesystem/ResourceID.h"
+#include "../../lib/filesystem/ResourcePath.h"
 #include "../windows/settings/SettingsMainWindow.h"
 
 BattleWindow::BattleWindow(BattleInterface & owner):
@@ -51,7 +51,7 @@ BattleWindow::BattleWindow(BattleInterface & owner):
 
 	REGISTER_BUILDER("battleConsole", &BattleWindow::buildBattleConsole);
 	
-	const JsonNode config(ResourceID("config/widgets/BattleWindow2.json"));
+	const JsonNode config(ResourcePath("config/widgets/BattleWindow2.json"));
 	
 	addShortcut(EShortcut::GLOBAL_OPTIONS, std::bind(&BattleWindow::bOptionsf, this));
 	addShortcut(EShortcut::BATTLE_SURRENDER, std::bind(&BattleWindow::bSurrenderf, this));
@@ -436,23 +436,23 @@ void BattleWindow::showAlternativeActionIcon(PossiblePlayerBattleAction action)
 	if(!w)
 		return;
 	
-	std::string iconName = variables["actionIconDefault"].String();
+	AnimationPath iconName = AnimationPath::fromJson(variables["actionIconDefault"]);
 	switch(action.get())
 	{
 		case PossiblePlayerBattleAction::ATTACK:
-			iconName = variables["actionIconAttack"].String();
+			iconName = AnimationPath::fromJson(variables["actionIconAttack"]);
 			break;
 			
 		case PossiblePlayerBattleAction::SHOOT:
-			iconName = variables["actionIconShoot"].String();
+			iconName = AnimationPath::fromJson(variables["actionIconShoot"]);
 			break;
 			
 		case PossiblePlayerBattleAction::AIMED_SPELL_CREATURE:
-			iconName = variables["actionIconSpell"].String();
+			iconName = AnimationPath::fromJson(variables["actionIconSpell"]);
 			break;
 
 		case PossiblePlayerBattleAction::ANY_LOCATION:
-			iconName = variables["actionIconSpell"].String();
+			iconName = AnimationPath::fromJson(variables["actionIconSpell"]);
 			break;
 			
 		//TODO: figure out purpose of this icon
@@ -461,11 +461,11 @@ void BattleWindow::showAlternativeActionIcon(PossiblePlayerBattleAction action)
 			//break;
 			
 		case PossiblePlayerBattleAction::ATTACK_AND_RETURN:
-			iconName = variables["actionIconReturn"].String();
+			iconName = AnimationPath::fromJson(variables["actionIconReturn"]);
 			break;
 			
 		case PossiblePlayerBattleAction::WALK_AND_ATTACK:
-			iconName = variables["actionIconNoReturn"].String();
+			iconName = AnimationPath::fromJson(variables["actionIconNoReturn"]);
 			break;
 	}
 		

+ 1 - 1
client/battle/CreatureAnimation.cpp

@@ -185,7 +185,7 @@ void CreatureAnimation::setType(ECreatureAnimType type)
 	speed = speedController(this, type);
 }
 
-CreatureAnimation::CreatureAnimation(const std::string & name_, TSpeedController controller)
+CreatureAnimation::CreatureAnimation(const AnimationPath & name_, TSpeedController controller)
 	: name(name_),
 	  speed(0.1f),
 	  shadowAlpha(128),

+ 2 - 2
client/battle/CreatureAnimation.h

@@ -70,7 +70,7 @@ public:
 	using TSpeedController = std::function<float(CreatureAnimation *, ECreatureAnimType)>;
 
 private:
-	std::string name;
+	AnimationPath name;
 
 	/// animation for rendering stack in default orientation - facing right
 	std::shared_ptr<CAnimation> forward;
@@ -122,7 +122,7 @@ public:
 	/// name - path to .def file, relative to SPRITES/ directory
 	/// controller - function that will return for how long *each* frame
 	/// in specified group of animation should be played, measured in seconds
-	CreatureAnimation(const std::string & name_, TSpeedController speedController);
+	CreatureAnimation(const AnimationPath & name_, TSpeedController speedController);
 
 	/// sets type of animation and resets framecount
 	void setType(ECreatureAnimType type);

+ 5 - 5
client/gui/CursorHandler.cpp

@@ -46,10 +46,10 @@ CursorHandler::CursorHandler()
 
 	cursors =
 	{
-		std::make_unique<CAnimation>("CRADVNTR"),
-		std::make_unique<CAnimation>("CRCOMBAT"),
-		std::make_unique<CAnimation>("CRDEFLT"),
-		std::make_unique<CAnimation>("CRSPELL")
+		std::make_unique<CAnimation>(AnimationPath::builtin("CRADVNTR")),
+		std::make_unique<CAnimation>(AnimationPath::builtin("CRCOMBAT")),
+		std::make_unique<CAnimation>(AnimationPath::builtin("CRDEFLT")),
+		std::make_unique<CAnimation>(AnimationPath::builtin("CRSPELL"))
 	};
 
 	for (auto & cursor : cursors)
@@ -100,7 +100,7 @@ void CursorHandler::dragAndDropCursor(std::shared_ptr<IImage> image)
 	cursor->setImage(getCurrentImage(), getPivotOffset());
 }
 
-void CursorHandler::dragAndDropCursor (std::string path, size_t index)
+void CursorHandler::dragAndDropCursor (const AnimationPath & path, size_t index)
 {
 	CAnimation anim(path);
 	anim.load(index);

+ 2 - 1
client/gui/CursorHandler.h

@@ -10,6 +10,7 @@
 #pragma once
 
 #include "../../lib/Point.h"
+#include "../../lib/filesystem/ResourcePath.h"
 
 class ICursor;
 class IImage;
@@ -143,7 +144,7 @@ public:
 	/// @param image Image to replace cursor with or nullptr to use the normal cursor.
 	void dragAndDropCursor(std::shared_ptr<IImage> image);
 
-	void dragAndDropCursor(std::string path, size_t index);
+	void dragAndDropCursor(const AnimationPath & path, size_t index);
 
 	/// Changes cursor to specified index
 	void set(Cursor::Default index);

+ 10 - 10
client/gui/InterfaceObjectConfigurable.cpp

@@ -31,7 +31,7 @@
 
 #include "../../lib//constants/StringConstants.h"
 #include "../../lib/CGeneralTextHandler.h"
-#include "../../lib/filesystem/ResourceID.h"
+#include "../../lib/filesystem/ResourcePath.h"
 
 InterfaceObjectConfigurable::InterfaceObjectConfigurable(const JsonNode & config, int used, Point offset):
 	InterfaceObjectConfigurable(used, offset)
@@ -110,7 +110,7 @@ void InterfaceObjectConfigurable::build(const JsonNode &config)
 	{
 		if (!config["library"].isNull())
 		{
-			const JsonNode library(ResourceID(config["library"].String()));
+			const JsonNode library(ResourcePath(config["library"].String()));
 			loadCustomBuilders(library);
 		}
 
@@ -305,7 +305,7 @@ EShortcut InterfaceObjectConfigurable::readHotkey(const JsonNode & config) const
 std::shared_ptr<CPicture> InterfaceObjectConfigurable::buildPicture(const JsonNode & config) const
 {
 	logGlobal->debug("Building widget CPicture");
-	auto image = config["image"].String();
+	auto image = ImagePath::fromJson(config["image"]);
 	auto position = readPosition(config["position"]);
 	auto pic = std::make_shared<CPicture>(image, position.x, position.y);
 	if(!config["visible"].isNull())
@@ -369,7 +369,7 @@ std::shared_ptr<CToggleButton> InterfaceObjectConfigurable::buildToggleButton(co
 {
 	logGlobal->debug("Building widget CToggleButton");
 	auto position = readPosition(config["position"]);
-	auto image = config["image"].String();
+	auto image = AnimationPath::fromJson(config["image"]);
 	auto help = readHintText(config["help"]);
 	auto button = std::make_shared<CToggleButton>(position, image, help);
 	if(!config["items"].isNull())
@@ -395,7 +395,7 @@ std::shared_ptr<CButton> InterfaceObjectConfigurable::buildButton(const JsonNode
 {
 	logGlobal->debug("Building widget CButton");
 	auto position = readPosition(config["position"]);
-	auto image = config["image"].String();
+	auto image = AnimationPath::fromJson(config["image"]);
 	auto help = readHintText(config["help"]);
 	auto button = std::make_shared<CButton>(position, image, help);
 	if(!config["items"].isNull())
@@ -522,7 +522,7 @@ std::shared_ptr<CAnimImage> InterfaceObjectConfigurable::buildImage(const JsonNo
 {
 	logGlobal->debug("Building widget CAnimImage");
 	auto position = readPosition(config["position"]);
-	auto image = config["image"].String();
+	auto image = AnimationPath::fromJson(config["image"]);
 	int group = config["group"].isNull() ? 0 : config["group"].Integer();
 	int frame = config["frame"].isNull() ? 0 : config["frame"].Integer();
 	return std::make_shared<CAnimImage>(image, frame, group, position.x, position.y);
@@ -531,7 +531,7 @@ std::shared_ptr<CAnimImage> InterfaceObjectConfigurable::buildImage(const JsonNo
 std::shared_ptr<CFilledTexture> InterfaceObjectConfigurable::buildTexture(const JsonNode & config) const
 {
 	logGlobal->debug("Building widget CFilledTexture");
-	auto image = config["image"].String();
+	auto image = ImagePath::fromJson(config["image"]);
 	auto rect = readRect(config["rect"]);
 	auto playerColor = readPlayerColor(config["color"]);
 	if(playerColor.isValidPlayer())
@@ -546,7 +546,7 @@ std::shared_ptr<ComboBox> InterfaceObjectConfigurable::buildComboBox(const JsonN
 {
 	logGlobal->debug("Building widget ComboBox");
 	auto position = readPosition(config["position"]);
-	auto image = config["image"].String();
+	auto image = AnimationPath::fromJson(config["image"]);
 	auto help = readHintText(config["help"]);
 	auto result = std::make_shared<ComboBox>(position, image, help, config["dropDown"]);
 	if(!config["items"].isNull())
@@ -573,7 +573,7 @@ std::shared_ptr<CTextInput> InterfaceObjectConfigurable::buildTextInput(const Js
 	logGlobal->debug("Building widget CTextInput");
 	auto rect = readRect(config["rect"]);
 	auto offset = readPosition(config["backgroundOffset"]);
-	auto bgName = config["background"].String();
+	auto bgName = ImagePath::fromJson(config["background"]);
 	auto result = std::make_shared<CTextInput>(rect, offset, bgName, 0);
 	if(!config["alignment"].isNull())
 		result->alignment = readTextAlignment(config["alignment"]);
@@ -664,7 +664,7 @@ std::shared_ptr<CShowableAnim> InterfaceObjectConfigurable::buildAnimation(const
 {
 	logGlobal->debug("Building widget CShowableAnim");
 	auto position = readPosition(config["position"]);
-	auto image = config["image"].String();
+	auto image = AnimationPath::fromJson(config["image"]);
 	ui8 flags = 0;
 	if(!config["repeat"].Bool())
 		flags |= CShowableAnim::EFlags::PLAY_ONCE;

+ 10 - 11
client/lobby/CBonusSelection.cpp

@@ -65,18 +65,17 @@ CBonusSelection::CBonusSelection()
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
 
-	std::string bgName = getCampaign()->getRegions().getBackgroundName();
-	setBackground(bgName);
+	setBackground(getCampaign()->getRegions().getBackgroundName());
 
-	panelBackground = std::make_shared<CPicture>("CAMPBRF.BMP", 456, 6);
+	panelBackground = std::make_shared<CPicture>(ImagePath::builtin("CAMPBRF.BMP"), 456, 6);
 
-	buttonStart = std::make_shared<CButton>(Point(475, 536), "CBBEGIB.DEF", CButton::tooltip(), std::bind(&CBonusSelection::startMap, this), EShortcut::GLOBAL_ACCEPT);
-	buttonRestart = std::make_shared<CButton>(Point(475, 536), "CBRESTB.DEF", CButton::tooltip(), std::bind(&CBonusSelection::restartMap, this), EShortcut::GLOBAL_ACCEPT);
-	buttonBack = std::make_shared<CButton>(Point(624, 536), "CBCANCB.DEF", CButton::tooltip(), std::bind(&CBonusSelection::goBack, this), EShortcut::GLOBAL_CANCEL);
+	buttonStart = std::make_shared<CButton>(Point(475, 536), AnimationPath::builtin("CBBEGIB.DEF"), CButton::tooltip(), std::bind(&CBonusSelection::startMap, this), EShortcut::GLOBAL_ACCEPT);
+	buttonRestart = std::make_shared<CButton>(Point(475, 536), AnimationPath::builtin("CBRESTB.DEF"), CButton::tooltip(), std::bind(&CBonusSelection::restartMap, this), EShortcut::GLOBAL_ACCEPT);
+	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());
 
-	iconsMapSizes = std::make_shared<CAnimImage>("SCNRMPSZ", 4, 0, 735, 26);
+	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, CGI->generaltexth->allTexts[38]);
 	campaignDescription = std::make_shared<CTextBox>(getCampaign()->getDescription(), Rect(480, 86, 286, 117), 1);
@@ -97,13 +96,13 @@ CBonusSelection::CBonusSelection()
 
 	for(size_t b = 0; b < difficultyIcons.size(); ++b)
 	{
-		difficultyIcons[b] = std::make_shared<CAnimImage>("GSPBUT" + std::to_string(b + 3) + ".DEF", 0, 0, 709, 455);
+		difficultyIcons[b] = std::make_shared<CAnimImage>(AnimationPath::builtinTODO("GSPBUT" + std::to_string(b + 3) + ".DEF"), 0, 0, 709, 455);
 	}
 
 	if(getCampaign()->playerSelectedDifficulty())
 	{
-		buttonDifficultyLeft = std::make_shared<CButton>(Point(694, 508), "SCNRBLF.DEF", CButton::tooltip(), std::bind(&CBonusSelection::decreaseDifficulty, this));
-		buttonDifficultyRight = std::make_shared<CButton>(Point(738, 508), "SCNRBRT.DEF", CButton::tooltip(), std::bind(&CBonusSelection::increaseDifficulty, this));
+		buttonDifficultyLeft = std::make_shared<CButton>(Point(694, 508), AnimationPath::builtin("SCNRBLF.DEF"), CButton::tooltip(), std::bind(&CBonusSelection::decreaseDifficulty, this));
+		buttonDifficultyRight = std::make_shared<CButton>(Point(738, 508), AnimationPath::builtin("SCNRBRT.DEF"), CButton::tooltip(), std::bind(&CBonusSelection::increaseDifficulty, this));
 	}
 
 	for(auto scenarioID : getCampaign()->allScenarios())
@@ -302,7 +301,7 @@ void CBonusSelection::createBonusesIcons()
 			break;
 		}
 
-		std::shared_ptr<CToggleButton> bonusButton = std::make_shared<CToggleButton>(Point(475 + i * 68, 455), "", CButton::tooltip(desc, desc));
+		std::shared_ptr<CToggleButton> bonusButton = std::make_shared<CToggleButton>(Point(475 + i * 68, 455), AnimationPath(), CButton::tooltip(desc, desc));
 
 		if(picNumber != -1)
 			picName += ":" + std::to_string(picNumber);

+ 8 - 8
client/lobby/CLobbyScreen.cpp

@@ -43,17 +43,17 @@ CLobbyScreen::CLobbyScreen(ESelectionScreen screenType)
 	{
 		tabSel->callOnSelect = std::bind(&IServerAPI::setMapInfo, CSH, _1, nullptr);
 
-		buttonSelect = std::make_shared<CButton>(Point(411, 80), "GSPBUTT.DEF", CGI->generaltexth->zelp[45], 0, EShortcut::LOBBY_SELECT_SCENARIO);
+		buttonSelect = std::make_shared<CButton>(Point(411, 80), AnimationPath::builtin("GSPBUTT.DEF"), CGI->generaltexth->zelp[45], 0, EShortcut::LOBBY_SELECT_SCENARIO);
 		buttonSelect->addCallback([&]()
 		{
 			toggleTab(tabSel);
 			CSH->setMapInfo(tabSel->getSelectedMapInfo());
 		});
 
-		buttonOptions = std::make_shared<CButton>(Point(411, 510), "GSPBUTT.DEF", CGI->generaltexth->zelp[46], std::bind(&CLobbyScreen::toggleTab, this, tabOpt), EShortcut::LOBBY_ADDITIONAL_OPTIONS);
+		buttonOptions = std::make_shared<CButton>(Point(411, 510), AnimationPath::builtin("GSPBUTT.DEF"), CGI->generaltexth->zelp[46], std::bind(&CLobbyScreen::toggleTab, this, tabOpt), EShortcut::LOBBY_ADDITIONAL_OPTIONS);
 	};
 
-	buttonChat = std::make_shared<CButton>(Point(619, 80), "GSPBUT2.DEF", CGI->generaltexth->zelp[48], std::bind(&CLobbyScreen::toggleChat, this), EShortcut::LOBBY_HIDE_CHAT);
+	buttonChat = std::make_shared<CButton>(Point(619, 80), AnimationPath::builtin("GSPBUT2.DEF"), CGI->generaltexth->zelp[48], std::bind(&CLobbyScreen::toggleChat, this), EShortcut::LOBBY_HIDE_CHAT);
 	buttonChat->addTextOverlay(CGI->generaltexth->allTexts[532], FONT_SMALL, Colors::WHITE);
 
 	switch(screenType)
@@ -63,7 +63,7 @@ CLobbyScreen::CLobbyScreen(ESelectionScreen screenType)
 		tabOpt = std::make_shared<OptionsTab>();
 		tabRand = std::make_shared<RandomMapTab>();
 		tabRand->mapInfoChanged += std::bind(&IServerAPI::setMapInfo, CSH, _1, _2);
-		buttonRMG = std::make_shared<CButton>(Point(411, 105), "GSPBUTT.DEF", CGI->generaltexth->zelp[47], 0, EShortcut::LOBBY_RANDOM_MAP);
+		buttonRMG = std::make_shared<CButton>(Point(411, 105), AnimationPath::builtin("GSPBUTT.DEF"), CGI->generaltexth->zelp[47], 0, EShortcut::LOBBY_RANDOM_MAP);
 		buttonRMG->addCallback([&]()
 		{
 			toggleTab(tabRand);
@@ -72,24 +72,24 @@ CLobbyScreen::CLobbyScreen(ESelectionScreen screenType)
 
 		card->iconDifficulty->addCallback(std::bind(&IServerAPI::setDifficulty, CSH, _1));
 
-		buttonStart = std::make_shared<CButton>(Point(411, 535), "SCNRBEG.DEF", CGI->generaltexth->zelp[103], std::bind(&CLobbyScreen::startScenario, this, true), EShortcut::LOBBY_BEGIN_GAME);
+		buttonStart = std::make_shared<CButton>(Point(411, 535), AnimationPath::builtin("SCNRBEG.DEF"), CGI->generaltexth->zelp[103], std::bind(&CLobbyScreen::startScenario, this, true), EShortcut::LOBBY_BEGIN_GAME);
 		initLobby();
 		break;
 	}
 	case ESelectionScreen::loadGame:
 	{
 		tabOpt = std::make_shared<OptionsTab>();
-		buttonStart = std::make_shared<CButton>(Point(411, 535), "SCNRLOD.DEF", CGI->generaltexth->zelp[103], std::bind(&CLobbyScreen::startScenario, this, true), EShortcut::LOBBY_LOAD_GAME);
+		buttonStart = std::make_shared<CButton>(Point(411, 535), AnimationPath::builtin("SCNRLOD.DEF"), CGI->generaltexth->zelp[103], std::bind(&CLobbyScreen::startScenario, this, true), EShortcut::LOBBY_LOAD_GAME);
 		initLobby();
 		break;
 	}
 	case ESelectionScreen::campaignList:
 		tabSel->callOnSelect = std::bind(&IServerAPI::setMapInfo, CSH, _1, nullptr);
-		buttonStart = std::make_shared<CButton>(Point(411, 535), "SCNRLOD.DEF", CButton::tooltip(), std::bind(&CLobbyScreen::startCampaign, this), EShortcut::LOBBY_BEGIN_GAME);
+		buttonStart = std::make_shared<CButton>(Point(411, 535), AnimationPath::builtin("SCNRLOD.DEF"), CButton::tooltip(), std::bind(&CLobbyScreen::startCampaign, this), EShortcut::LOBBY_BEGIN_GAME);
 		break;
 	}
 
-	buttonBack = std::make_shared<CButton>(Point(581, 535), "SCNRBACK.DEF", CGI->generaltexth->zelp[105], [&]()
+	buttonBack = std::make_shared<CButton>(Point(581, 535), AnimationPath::builtin("SCNRBACK.DEF"), CGI->generaltexth->zelp[105], [&]()
 	{
 		CSH->sendClientDisconnecting();
 		close();

+ 2 - 2
client/lobby/CSavingScreen.cpp

@@ -40,7 +40,7 @@ CSavingScreen::CSavingScreen()
 	tabSel->toggleMode();
 	curTab = tabSel;
 		
-	buttonStart = std::make_shared<CButton>(Point(411, 535), "SCNRSAV.DEF", CGI->generaltexth->zelp[103], std::bind(&CSavingScreen::saveGame, this), EShortcut::LOBBY_SAVE_GAME);
+	buttonStart = std::make_shared<CButton>(Point(411, 535), AnimationPath::builtin("SCNRSAV.DEF"), CGI->generaltexth->zelp[103], std::bind(&CSavingScreen::saveGame, this), EShortcut::LOBBY_SAVE_GAME);
 }
 
 const CMapInfo * CSavingScreen::getMapInfo()
@@ -80,7 +80,7 @@ void CSavingScreen::saveGame()
 		close();
 	};
 
-	if(CResourceHandler::get("local")->existsResource(ResourceID(path, EResType::SAVEGAME)))
+	if(CResourceHandler::get("local")->existsResource(ResourcePath(path, EResType::SAVEGAME)))
 	{
 		std::string hlp = CGI->generaltexth->allTexts[493]; //%s exists. Overwrite?
 		boost::algorithm::replace_first(hlp, "%s", tabSel->inputName->getText());

+ 1 - 1
client/lobby/CScenarioInfoScreen.cpp

@@ -45,7 +45,7 @@ CScenarioInfoScreen::CScenarioInfoScreen()
 	card->changeSelection();
 
 	card->iconDifficulty->setSelected(getCurrentDifficulty());
-	buttonBack = std::make_shared<CButton>(Point(584, 535), "SCNRBACK.DEF", CGI->generaltexth->zelp[105], [=](){ close();}, EShortcut::GLOBAL_CANCEL);
+	buttonBack = std::make_shared<CButton>(Point(584, 535), AnimationPath::builtin("SCNRBACK.DEF"), CGI->generaltexth->zelp[105], [=](){ close();}, EShortcut::GLOBAL_CANCEL);
 }
 
 CScenarioInfoScreen::~CScenarioInfoScreen()

+ 11 - 11
client/lobby/CSelectionBase.cpp

@@ -80,16 +80,16 @@ CSelectionBase::CSelectionBase(ESelectionScreen type)
 	pos.h = 584;
 	if(screenType == ESelectionScreen::campaignList)
 	{
-		setBackground("CamCust.bmp");
+		setBackground(ImagePath::builtin("CamCust.bmp"));
 	}
 	else
 	{
 		const JsonVector & bgNames = CMainMenuConfig::get().getConfig()["game-select"].Vector();
-		setBackground(RandomGeneratorUtil::nextItem(bgNames, CRandomGenerator::getDefault())->String());
+		setBackground(ImagePath::fromJson(*RandomGeneratorUtil::nextItem(bgNames, CRandomGenerator::getDefault())));
 	}
 	pos = background->center();
 	card = std::make_shared<InfoCard>();
-	buttonBack = std::make_shared<CButton>(Point(581, 535), "SCNRBACK.DEF", CGI->generaltexth->zelp[105], [=](){ close();}, EShortcut::GLOBAL_CANCEL);
+	buttonBack = std::make_shared<CButton>(Point(581, 535), AnimationPath::builtin("SCNRBACK.DEF"), CGI->generaltexth->zelp[105], [=](){ close();}, EShortcut::GLOBAL_CANCEL);
 }
 
 void CSelectionBase::toggleTab(std::shared_ptr<CIntObject> tab)
@@ -125,7 +125,7 @@ InfoCard::InfoCard()
 	mapName = std::make_shared<CLabel>(26, 39, FONT_BIG, ETextAlignment::TOPLEFT, Colors::YELLOW);
 	Rect descriptionRect(26, 149, 320, 115);
 	mapDescription = std::make_shared<CTextBox>("", descriptionRect, 1);
-	playerListBg = std::make_shared<CPicture>("CHATPLUG.bmp", 16, 276);
+	playerListBg = std::make_shared<CPicture>(ImagePath::builtin("CHATPLUG.bmp"), 16, 276);
 	chat = std::make_shared<CChatBox>(Rect(26, 132, 340, 132));
 
 	if(SEL->screenType == ESelectionScreen::campaignList)
@@ -134,14 +134,14 @@ InfoCard::InfoCard()
 	}
 	else
 	{
-		background = std::make_shared<CPicture>("GSELPOP1.bmp", 0, 0);
+		background = std::make_shared<CPicture>(ImagePath::builtin("GSELPOP1.bmp"), 0, 0);
 		parent->addChild(background.get());
 		auto it = vstd::find(parent->children, this); //our position among parent children
 		parent->children.insert(it, background.get()); //put BG before us
 		parent->children.pop_back();
 		pos.w = background->pos.w;
 		pos.h = background->pos.h;
-		iconsMapSizes = std::make_shared<CAnimImage>("SCNRMPSZ", 4, 0, 318, 22); //let it be custom size (frame 4) by default
+		iconsMapSizes = std::make_shared<CAnimImage>(AnimationPath::builtin("SCNRMPSZ"), 4, 0, 318, 22); //let it be custom size (frame 4) by default
 
 		iconDifficulty = std::make_shared<CToggleGroup>(0);
 		{
@@ -149,7 +149,7 @@ InfoCard::InfoCard()
 
 			for(int i = 0; i < 5; i++)
 			{
-				auto button = std::make_shared<CToggleButton>(Point(110 + i * 32, 450), difButns[i], CGI->generaltexth->zelp[24 + i]);
+				auto button = std::make_shared<CToggleButton>(Point(110 + i * 32, 450), AnimationPath::builtin(difButns[i]), CGI->generaltexth->zelp[24 + i]);
 
 				iconDifficulty->addToggle(i, button);
 				if(SEL->screenType != ESelectionScreen::newGame)
@@ -165,8 +165,8 @@ InfoCard::InfoCard()
 		labelScenarioDescription = std::make_shared<CLabel>(26, 132, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::YELLOW, CGI->generaltexth->allTexts[496]);
 		labelVictoryCondition = std::make_shared<CLabel>(26, 283, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::YELLOW, CGI->generaltexth->allTexts[497]);
 		labelLossCondition = std::make_shared<CLabel>(26, 339, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::YELLOW, CGI->generaltexth->allTexts[498]);
-		iconsVictoryCondition = std::make_shared<CAnimImage>("SCNRVICT", 0, 0, 24, 302);
-		iconsLossCondition = std::make_shared<CAnimImage>("SCNRLOSS", 0, 0, 24, 359);
+		iconsVictoryCondition = std::make_shared<CAnimImage>(AnimationPath::builtin("SCNRVICT"), 0, 0, 24, 302);
+		iconsLossCondition = std::make_shared<CAnimImage>(AnimationPath::builtin("SCNRLOSS"), 0, 0, 24, 359);
 
 		labelVictoryConditionText = std::make_shared<CLabel>(60, 307, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE);
 		labelLossConditionText = std::make_shared<CLabel>(60, 366, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE);
@@ -356,7 +356,7 @@ CFlagBox::CFlagBox(const Rect & rect)
 	labelAllies = std::make_shared<CLabel>(0, 0, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[390] + ":");
 	labelEnemies = std::make_shared<CLabel>(133, 0, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[391] + ":");
 
-	iconsTeamFlags = std::make_shared<CAnimation>("ITGFLAGS.DEF");
+	iconsTeamFlags = std::make_shared<CAnimation>(AnimationPath::builtin("ITGFLAGS.DEF"));
 	iconsTeamFlags->preload();
 }
 
@@ -390,7 +390,7 @@ void CFlagBox::showPopupWindow(const Point & cursorPosition)
 }
 
 CFlagBox::CFlagBoxTooltipBox::CFlagBoxTooltipBox(std::shared_ptr<CAnimation> icons)
-	: CWindowObject(BORDERED | RCLICK_POPUP | SHADOW_DISABLED, "DIBOXBCK")
+	: CWindowObject(BORDERED | RCLICK_POPUP | SHADOW_DISABLED, ImagePath::builtin("DIBOXBCK"))
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
 

+ 25 - 25
client/lobby/OptionsTab.cpp

@@ -137,7 +137,7 @@ OptionsTab::OptionsTab() : humanPlayers(0)
 		}
 	});
 	
-	const JsonNode config(ResourceID("config/widgets/optionsTab.json"));
+	const JsonNode config(ResourcePath("config/widgets/optionsTab.json"));
 	build(config);
 	
 	//set timers combo box callbacks
@@ -343,18 +343,18 @@ size_t OptionsTab::CPlayerSettingsHelper::getImageIndex(bool big)
 	return 0;
 }
 
-std::string OptionsTab::CPlayerSettingsHelper::getImageName(bool big)
+AnimationPath OptionsTab::CPlayerSettingsHelper::getImageName(bool big)
 {
 	switch(type)
 	{
 	case OptionsTab::TOWN:
-		return big ? "ITPt": "ITPA";
+		return AnimationPath::builtin(big ? "ITPt": "ITPA");
 	case OptionsTab::HERO:
-		return big ? "PortraitsLarge": "PortraitsSmall";
+		return AnimationPath::builtin(big ? "PortraitsLarge": "PortraitsSmall");
 	case OptionsTab::BONUS:
-		return "SCNRSTAR";
+		return AnimationPath::builtin("SCNRSTAR");
 	}
-	return "";
+	return {};
 }
 
 std::string OptionsTab::CPlayerSettingsHelper::getName()
@@ -553,7 +553,7 @@ OptionsTab::CPlayerOptionTooltipBox::CPlayerOptionTooltipBox(CPlayerSettingsHelp
 
 void OptionsTab::CPlayerOptionTooltipBox::genHeader()
 {
-	backgroundTexture = std::make_shared<CFilledTexture>("DIBOXBCK", pos);
+	backgroundTexture = std::make_shared<CFilledTexture>(ImagePath::builtin("DIBOXBCK"), pos);
 	updateShadow();
 
 	labelTitle = std::make_shared<CLabel>(pos.w / 2 + 8, 21, FONT_MEDIUM, ETextAlignment::CENTER, Colors::YELLOW, getTitle());
@@ -585,7 +585,7 @@ void OptionsTab::CPlayerOptionTooltipBox::genHeroWindow()
 	labelHeroSpeciality = std::make_shared<CLabel>(pos.w / 2 + 4, 117, FONT_MEDIUM, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[78]);
 	auto heroIndex = settings.hero.getNum() >= CGI->heroh->size() ? 0 : settings.hero.getNum();
 
-	imageSpeciality = std::make_shared<CAnimImage>("UN44", (*CGI->heroh)[heroIndex]->imageIndex, 0, pos.w / 2 - 22, 134);
+	imageSpeciality = std::make_shared<CAnimImage>(AnimationPath::builtin("UN44"), (*CGI->heroh)[heroIndex]->imageIndex, 0, pos.w / 2 - 22, 134);
 	labelSpecialityName = std::make_shared<CLabel>(pos.w / 2, 188, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, (*CGI->heroh)[heroIndex]->getSpecialtyNameTranslated());
 }
 
@@ -717,7 +717,7 @@ void OptionsTab::SelectionWindow::recreate()
 
 	pos = Rect(0, 0, x, y);
 
-	backgroundTexture = std::make_shared<FilledTexturePlayerColored>("DiBoxBck", pos);
+	backgroundTexture = std::make_shared<FilledTexturePlayerColored>(ImagePath::builtin("DiBoxBck"), pos);
 	backgroundTexture->playerColored(PlayerColor(1));
 	updateShadow();
 
@@ -747,7 +747,7 @@ void OptionsTab::SelectionWindow::genContentGrid(int lines)
 	{
 		for(int x = 0; x < elementsPerLine; x++)
 		{
-			components.push_back(std::make_shared<CPicture>("lobby/townBorderBig", x * (ICON_BIG_WIDTH-1), y * (ICON_BIG_HEIGHT-1)));
+			components.push_back(std::make_shared<CPicture>(ImagePath::builtin("lobby/townBorderBig"), x * (ICON_BIG_WIDTH-1), y * (ICON_BIG_HEIGHT-1)));
 		}
 	}
 }
@@ -763,7 +763,7 @@ void OptionsTab::SelectionWindow::genContentFactions()
 	components.push_back(std::make_shared<CAnimImage>(helper.getImageName(), helper.getImageIndex(), 0, 6, (ICON_SMALL_HEIGHT/2)));
 	drawOutlinedText(TEXT_POS_X, TEXT_POS_Y, (selectedFaction.getNum() == PlayerSettings::RANDOM) ? Colors::YELLOW : Colors::WHITE, helper.getName());
 	if(selectedFaction.getNum() == PlayerSettings::RANDOM)
-		components.push_back(std::make_shared<CPicture>("lobby/townBorderSmallActivated", 6, (ICON_SMALL_HEIGHT/2)));
+		components.push_back(std::make_shared<CPicture>(ImagePath::builtin("lobby/townBorderSmallActivated"), 6, (ICON_SMALL_HEIGHT/2)));
 
 	for(auto & elem : allowedFactions)
 	{
@@ -776,7 +776,7 @@ void OptionsTab::SelectionWindow::genContentFactions()
 		CPlayerSettingsHelper helper = CPlayerSettingsHelper(set, SelType::TOWN);
 
 		components.push_back(std::make_shared<CAnimImage>(helper.getImageName(true), helper.getImageIndex(true), 0, x * (ICON_BIG_WIDTH-1), y * (ICON_BIG_HEIGHT-1)));
-		components.push_back(std::make_shared<CPicture>(selectedFaction == elem ? "lobby/townBorderBigActivated" : "lobby/townBorderBig", x * (ICON_BIG_WIDTH-1), y * (ICON_BIG_HEIGHT-1)));
+		components.push_back(std::make_shared<CPicture>(ImagePath::builtin(selectedFaction == elem ? "lobby/townBorderBigActivated" : "lobby/townBorderBig"), x * (ICON_BIG_WIDTH-1), y * (ICON_BIG_HEIGHT-1)));
 		drawOutlinedText(x * (ICON_BIG_WIDTH-1) + TEXT_POS_X, y * (ICON_BIG_HEIGHT-1) + TEXT_POS_Y, (selectedFaction == elem) ? Colors::YELLOW : Colors::WHITE, helper.getName());
 		factions.push_back(elem);
 
@@ -795,7 +795,7 @@ void OptionsTab::SelectionWindow::genContentHeroes()
 	components.push_back(std::make_shared<CAnimImage>(helper.getImageName(), helper.getImageIndex(), 0, 6, (ICON_SMALL_HEIGHT/2)));
 	drawOutlinedText(TEXT_POS_X, TEXT_POS_Y, (selectedHero.getNum() == PlayerSettings::RANDOM) ? Colors::YELLOW : Colors::WHITE, helper.getName());
 	if(selectedHero.getNum() == PlayerSettings::RANDOM)
-		components.push_back(std::make_shared<CPicture>("lobby/townBorderSmallActivated", 6, (ICON_SMALL_HEIGHT/2)));
+		components.push_back(std::make_shared<CPicture>(ImagePath::builtin("lobby/townBorderSmallActivated"), 6, (ICON_SMALL_HEIGHT/2)));
 
 	for(auto & elem : allowedHeroes)
 	{
@@ -814,11 +814,11 @@ void OptionsTab::SelectionWindow::genContentHeroes()
 
 			components.push_back(std::make_shared<CAnimImage>(helper.getImageName(true), helper.getImageIndex(true), 0, x * (ICON_BIG_WIDTH-1), y * (ICON_BIG_HEIGHT-1)));
 			drawOutlinedText(x * (ICON_BIG_WIDTH-1) + TEXT_POS_X, y * (ICON_BIG_HEIGHT-1) + TEXT_POS_Y, (selectedHero == elem) ? Colors::YELLOW : Colors::WHITE, helper.getName());
-			std::string image = "lobby/townBorderBig";
+			ImagePath image = ImagePath::builtin("lobby/townBorderBig");
 			if(selectedHero == elem)
-				image = "lobby/townBorderBigActivated";
+				image = ImagePath::builtin("lobby/townBorderBigActivated");
 			if(unusableHeroes.count(elem))
-				image = "lobby/townBorderBigGrayedOut";
+				image = ImagePath::builtin("lobby/townBorderBigGrayedOut");
 			components.push_back(std::make_shared<CPicture>(image, x * (ICON_BIG_WIDTH-1), y * (ICON_BIG_HEIGHT-1)));
 			heroes.push_back(elem);
 
@@ -843,7 +843,7 @@ void OptionsTab::SelectionWindow::genContentBonus()
 		drawOutlinedText(x * (ICON_BIG_WIDTH-1) + TEXT_POS_X, y * (ICON_BIG_HEIGHT-1) + TEXT_POS_Y, Colors::WHITE , helper.getName());
 		if(selectedBonus == elem)
 		{
-			components.push_back(std::make_shared<CPicture>("lobby/townBorderSmallActivated", x * (ICON_BIG_WIDTH-1) + 6, y * (ICON_BIG_HEIGHT-1) + (ICON_SMALL_HEIGHT/2)));
+			components.push_back(std::make_shared<CPicture>(ImagePath::builtin("lobby/townBorderSmallActivated"), x * (ICON_BIG_WIDTH-1) + 6, y * (ICON_BIG_HEIGHT-1) + (ICON_SMALL_HEIGHT/2)));
 			drawOutlinedText(x * (ICON_BIG_WIDTH-1) + TEXT_POS_X, y * (ICON_BIG_HEIGHT-1) + TEXT_POS_Y, Colors::YELLOW , helper.getName());
 		}
 
@@ -1075,18 +1075,18 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry(const PlayerSettings & S, con
 		"ADOPOPNL.bmp", "ADOPPPNL.bmp", "ADOPTPNL.bmp", "ADOPSPNL.bmp"
 	}};
 
-	background = std::make_shared<CPicture>(bgs[s->color.getNum()], 0, 0);
+	background = std::make_shared<CPicture>(ImagePath::builtin(bgs[s->color.getNum()]), 0, 0);
 	labelPlayerName = std::make_shared<CLabel>(55, 10, EFonts::FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, s->name);
 	labelWhoCanPlay = std::make_shared<CMultiLineLabel>(Rect(6, 23, 45, (int)graphics->fonts[EFonts::FONT_TINY]->getLineHeight()*2), EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->arraytxt[206 + whoCanPlay]);
 
 	if(SEL->screenType == ESelectionScreen::newGame)
 	{
-		buttonTownLeft = std::make_shared<CButton>(Point(107, 5), "ADOPLFA.DEF", CGI->generaltexth->zelp[132], std::bind(&IServerAPI::setPlayerOption, CSH, LobbyChangePlayerOption::TOWN, -1, s->color));
-		buttonTownRight = std::make_shared<CButton>(Point(168, 5), "ADOPRTA.DEF", CGI->generaltexth->zelp[133], std::bind(&IServerAPI::setPlayerOption, CSH, LobbyChangePlayerOption::TOWN, +1, s->color));
-		buttonHeroLeft = std::make_shared<CButton>(Point(183, 5), "ADOPLFA.DEF", CGI->generaltexth->zelp[148], std::bind(&IServerAPI::setPlayerOption, CSH, LobbyChangePlayerOption::HERO, -1, s->color));
-		buttonHeroRight = std::make_shared<CButton>(Point(244, 5), "ADOPRTA.DEF", CGI->generaltexth->zelp[149], std::bind(&IServerAPI::setPlayerOption, CSH, LobbyChangePlayerOption::HERO, +1, s->color));
-		buttonBonusLeft = std::make_shared<CButton>(Point(259, 5), "ADOPLFA.DEF", CGI->generaltexth->zelp[164], std::bind(&IServerAPI::setPlayerOption, CSH, LobbyChangePlayerOption::BONUS, -1, s->color));
-		buttonBonusRight = std::make_shared<CButton>(Point(320, 5), "ADOPRTA.DEF", CGI->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"), CGI->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"), CGI->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"), CGI->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"), CGI->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"), CGI->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"), CGI->generaltexth->zelp[165], std::bind(&IServerAPI::setPlayerOption, CSH, LobbyChangePlayerOption::BONUS, +1, s->color));
 	}
 
 	hideUnavailableButtons();
@@ -1095,7 +1095,7 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry(const PlayerSettings & S, con
 	{
 		flag = std::make_shared<CButton>(
 			Point(-43, 2),
-			flags[s->color.getNum()],
+			AnimationPath::builtin(flags[s->color.getNum()]),
 			CGI->generaltexth->zelp[180],
 			std::bind(&OptionsTab::onSetPlayerClicked, &parentTab, *s)
 		);

+ 1 - 1
client/lobby/OptionsTab.h

@@ -62,7 +62,7 @@ private:
 
 		/// visible image settings
 		size_t getImageIndex(bool big = false);
-		std::string getImageName(bool big = false);
+		AnimationPath getImageName(bool big = false);
 
 		std::string getName(); /// name visible in options dialog
 		std::string getTitle(); /// title in popup box

+ 2 - 2
client/lobby/RandomMapTab.cpp

@@ -118,7 +118,7 @@ RandomMapTab::RandomMapTab():
 		});
 	}
 	
-	const JsonNode config(ResourceID("config/widgets/randomMapTab.json"));
+	const JsonNode config(ResourcePath("config/widgets/randomMapTab.json"));
 	build(config);
 	
 	//set combo box callbacks
@@ -388,7 +388,7 @@ std::vector<int> RandomMapTab::getPossibleMapSizes()
 TeamAlignmentsWidget::TeamAlignmentsWidget(RandomMapTab & randomMapTab):
 	InterfaceObjectConfigurable()
 {
-	const JsonNode config(ResourceID("config/widgets/randomMapTeamsWidget.json"));
+	const JsonNode config(ResourcePath("config/widgets/randomMapTeamsWidget.json"));
 	variables = config["variables"];
 	
 	int humanPlayers = randomMapTab.obtainMapGenOptions().getPlayerCount();

+ 23 - 23
client/lobby/SelectionTab.cpp

@@ -158,16 +158,16 @@ SelectionTab::SelectionTab(ESelectionScreen Type)
 	if(tabType != ESelectionScreen::campaignList)
 	{
 		sortingBy = _format;
-		background = std::make_shared<CPicture>("SCSELBCK.bmp", 0, 6);
+		background = std::make_shared<CPicture>(ImagePath::builtin("SCSELBCK.bmp"), 0, 6);
 		pos = background->pos;
-		inputName = std::make_shared<CTextInput>(inputNameRect, Point(-32, -25), "GSSTRIP.bmp", 0);
+		inputName = std::make_shared<CTextInput>(inputNameRect, Point(-32, -25), ImagePath::builtin("GSSTRIP.bmp"), 0);
 		inputName->filters += CTextInput::filenameFilter;
 		labelMapSizes = std::make_shared<CLabel>(87, 62, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[510]);
 
 		int sizes[] = {36, 72, 108, 144, 0};
 		const char * filterIconNmes[] = {"SCSMBUT.DEF", "SCMDBUT.DEF", "SCLGBUT.DEF", "SCXLBUT.DEF", "SCALBUT.DEF"};
 		for(int i = 0; i < 5; i++)
-			buttonsSortBy.push_back(std::make_shared<CButton>(Point(158 + 47 * i, 46), filterIconNmes[i], CGI->generaltexth->zelp[54 + i], std::bind(&SelectionTab::filter, this, sizes[i], true)));
+			buttonsSortBy.push_back(std::make_shared<CButton>(Point(158 + 47 * i, 46), AnimationPath::builtin(filterIconNmes[i]), CGI->generaltexth->zelp[54 + i], std::bind(&SelectionTab::filter, this, sizes[i], true)));
 
 		int xpos[] = {23, 55, 88, 121, 306, 339};
 		const char * sortIconNames[] = {"SCBUTT1.DEF", "SCBUTT2.DEF", "SCBUTCP.DEF", "SCBUTT3.DEF", "SCBUTT4.DEF", "SCBUTT5.DEF"};
@@ -177,7 +177,7 @@ SelectionTab::SelectionTab(ESelectionScreen Type)
 			if(criteria == _name)
 				criteria = generalSortingBy;
 
-			buttonsSortBy.push_back(std::make_shared<CButton>(Point(xpos[i], 86), sortIconNames[i], CGI->generaltexth->zelp[107 + i], std::bind(&SelectionTab::sortBy, this, criteria)));
+			buttonsSortBy.push_back(std::make_shared<CButton>(Point(xpos[i], 86), AnimationPath::builtin(sortIconNames[i]), CGI->generaltexth->zelp[107 + i], std::bind(&SelectionTab::sortBy, this, criteria)));
 		}
 	}
 
@@ -203,17 +203,17 @@ SelectionTab::SelectionTab(ESelectionScreen Type)
 		pos.x += 3;
 		pos.y += 6;
 
-		buttonsSortBy.push_back(std::make_shared<CButton>(Point(23, 86), "CamCusM.DEF", CButton::tooltip(), std::bind(&SelectionTab::sortBy, this, _numOfMaps)));
-		buttonsSortBy.push_back(std::make_shared<CButton>(Point(55, 86), "CamCusL.DEF", CButton::tooltip(), std::bind(&SelectionTab::sortBy, this, _name)));
+		buttonsSortBy.push_back(std::make_shared<CButton>(Point(23, 86), AnimationPath::builtin("CamCusM.DEF"), CButton::tooltip(), std::bind(&SelectionTab::sortBy, this, _numOfMaps)));
+		buttonsSortBy.push_back(std::make_shared<CButton>(Point(55, 86), AnimationPath::builtin("CamCusL.DEF"), CButton::tooltip(), std::bind(&SelectionTab::sortBy, this, _name)));
 		break;
 	default:
 		assert(0);
 		break;
 	}
 
-	iconsMapFormats = std::make_shared<CAnimation>("SCSELC.DEF");
-	iconsVictoryCondition = std::make_shared<CAnimation>("SCNRVICT.DEF");
-	iconsLossCondition = std::make_shared<CAnimation>("SCNRLOSS.DEF");
+	iconsMapFormats = std::make_shared<CAnimation>(AnimationPath::builtin("SCSELC.DEF"));
+	iconsVictoryCondition = std::make_shared<CAnimation>(AnimationPath::builtin("SCNRVICT.DEF"));
+	iconsLossCondition = std::make_shared<CAnimation>(AnimationPath::builtin("SCNRLOSS.DEF"));
 	for(int i = 0; i < positionsToShow; i++)
 		listItems.push_back(std::make_shared<ListItem>(Point(30, 129 + i * 25), iconsMapFormats, iconsVictoryCondition, iconsLossCondition));
 
@@ -244,7 +244,7 @@ void SelectionTab::toggleMode()
 			{
 				inputName->disable();
 				auto files = getFiles("Maps/", EResType::MAP);
-				files.erase(ResourceID("Maps/Tutorial.tut", EResType::MAP));
+				files.erase(ResourcePath("Maps/Tutorial.tut", EResType::MAP));
 				parseMaps(files);
 				break;
 			}
@@ -367,7 +367,7 @@ void SelectionTab::showPopupWindow(const Point & cursorPosition)
 		if(curItems[py]->date != "")
 			text += boost::str(boost::format("\r\n\r\n%1%:\r\n%2%") % CGI->generaltexth->translate("vcmi.lobby.creationDate") % curItems[py]->date);
 
-		GH.windows().createAndPushWindow<CMapInfoTooltipBox>(text, ResourceID(curItems[py]->fileURI), tabType);
+		GH.windows().createAndPushWindow<CMapInfoTooltipBox>(text, ResourcePath(curItems[py]->fileURI), tabType);
 	}
 }
 
@@ -556,7 +556,7 @@ void SelectionTab::select(int position)
 
 	if(inputName && inputName->isActive())
 	{
-		auto filename = *CResourceHandler::get()->getResourceName(ResourceID(curItems[py]->fileURI, EResType::SAVEGAME));
+		auto filename = *CResourceHandler::get()->getResourceName(ResourcePath(curItems[py]->fileURI, EResType::SAVEGAME));
 		inputName->setText(filename.stem().string());
 	}
 
@@ -723,7 +723,7 @@ bool SelectionTab::isMapSupported(const CMapInfo & info)
 	return false;
 }
 
-void SelectionTab::parseMaps(const std::unordered_set<ResourceID> & files)
+void SelectionTab::parseMaps(const std::unordered_set<ResourcePath> & files)
 {
 	logGlobal->debug("Parsing %d maps", files.size());
 	allItems.clear();
@@ -744,7 +744,7 @@ void SelectionTab::parseMaps(const std::unordered_set<ResourceID> & files)
 	}
 }
 
-void SelectionTab::parseSaves(const std::unordered_set<ResourceID> & files)
+void SelectionTab::parseSaves(const std::unordered_set<ResourcePath> & files)
 {
 	for(auto & file : files)
 	{
@@ -786,7 +786,7 @@ void SelectionTab::parseSaves(const std::unordered_set<ResourceID> & files)
 	}
 }
 
-void SelectionTab::parseCampaigns(const std::unordered_set<ResourceID> & files)
+void SelectionTab::parseCampaigns(const std::unordered_set<ResourcePath> & files)
 {
 	allItems.reserve(files.size());
 	for(auto & file : files)
@@ -800,7 +800,7 @@ void SelectionTab::parseCampaigns(const std::unordered_set<ResourceID> & files)
 	}
 }
 
-std::unordered_set<ResourceID> SelectionTab::getFiles(std::string dirURI, int resType)
+std::unordered_set<ResourcePath> SelectionTab::getFiles(std::string dirURI, EResType resType)
 {
 	boost::to_upper(dirURI);
 	CResourceHandler::get()->updateFilteredFiles([&](const std::string & mount)
@@ -808,7 +808,7 @@ std::unordered_set<ResourceID> SelectionTab::getFiles(std::string dirURI, int re
 		return boost::algorithm::starts_with(mount, dirURI);
 	});
 
-	std::unordered_set<ResourceID> ret = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident)
+	std::unordered_set<ResourcePath> ret = CResourceHandler::get()->getFilteredFiles([&](const ResourcePath & ident)
 	{
 		return ident.getType() == resType && boost::algorithm::starts_with(ident.getName(), dirURI);
 	});
@@ -816,7 +816,7 @@ std::unordered_set<ResourceID> SelectionTab::getFiles(std::string dirURI, int re
 	return ret;
 }
 
-SelectionTab::CMapInfoTooltipBox::CMapInfoTooltipBox(std::string text, ResourceID resource, ESelectionScreen tabType)
+SelectionTab::CMapInfoTooltipBox::CMapInfoTooltipBox(std::string text, ResourcePath resource, ESelectionScreen tabType)
 	: CWindowObject(BORDERED | RCLICK_POPUP)
 {
 	drawPlayerElements = tabType == ESelectionScreen::newGame;
@@ -826,7 +826,7 @@ SelectionTab::CMapInfoTooltipBox::CMapInfoTooltipBox(std::string text, ResourceI
 
 	std::vector<std::shared_ptr<IImage>> mapLayerImages;
 	if(renderImage)
-		mapLayerImages = createMinimaps(ResourceID(resource.getName(), EResType::MAP), IMAGE_SIZE);
+		mapLayerImages = createMinimaps(ResourcePath(resource.getName(), EResType::MAP), IMAGE_SIZE);
 
 	if(mapLayerImages.size() == 0)
 		renderImage = false;
@@ -844,7 +844,7 @@ SelectionTab::CMapInfoTooltipBox::CMapInfoTooltipBox(std::string text, ResourceI
 	pos.h = BORDER + textHeight + BORDER;
 	if(renderImage)
 		pos.h += IMAGE_SIZE + BORDER;
-	backgroundTexture = std::make_shared<CFilledTexture>("DIBOXBCK", pos);
+	backgroundTexture = std::make_shared<CFilledTexture>(ImagePath::builtin("DIBOXBCK"), pos);
 	updateShadow();
 
 	drawLabel();
@@ -903,7 +903,7 @@ Canvas SelectionTab::CMapInfoTooltipBox::createMinimapForLayer(std::unique_ptr<C
 	return canvas;
 }
 
-std::vector<std::shared_ptr<IImage>> SelectionTab::CMapInfoTooltipBox::createMinimaps(ResourceID resource, int size)
+std::vector<std::shared_ptr<IImage>> SelectionTab::CMapInfoTooltipBox::createMinimaps(ResourcePath resource, int size)
 {
 	std::vector<std::shared_ptr<IImage>> ret = std::vector<std::shared_ptr<IImage>>();
 
@@ -935,7 +935,7 @@ SelectionTab::ListItem::ListItem(Point position, std::shared_ptr<CAnimation> ico
 	: CIntObject(LCLICK, position)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
-	pictureEmptyLine = std::make_shared<CPicture>(IImage::createFromFile("camcust"), Rect(25, 121, 349, 26), -8, -14);
+	pictureEmptyLine = std::make_shared<CPicture>(IImage::createFromFile(ImagePath::builtin("camcust")), Rect(25, 121, 349, 26), -8, -14);
 	labelName = std::make_shared<CLabel>(184, 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
 	labelName->setAutoRedraw(false);
 	labelAmountOfPlayers = std::make_shared<CLabel>(8, 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
@@ -945,7 +945,7 @@ SelectionTab::ListItem::ListItem(Point position, std::shared_ptr<CAnimation> ico
 	labelMapSizeLetter = std::make_shared<CLabel>(41, 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
 	labelMapSizeLetter->setAutoRedraw(false);
 	// FIXME: This -12 should not be needed, but for some reason CAnimImage displaced otherwise
-	iconFolder = std::make_shared<CPicture>("lobby/iconFolder.png", -8, -12);
+	iconFolder = std::make_shared<CPicture>(ImagePath::builtin("lobby/iconFolder.png"), -8, -12);
 	iconFormat = std::make_shared<CAnimImage>(iconsFormats, 0, 0, 59, -12);
 	iconVictoryCondition = std::make_shared<CAnimImage>(iconsVictory, 0, 0, 277, -12);
 	iconLossCondition = std::make_shared<CAnimImage>(iconsLoss, 0, 0, 310, -12);

+ 7 - 6
client/lobby/SelectionTab.h

@@ -14,6 +14,7 @@ VCMI_LIB_NAMESPACE_BEGIN
 class CMap;
 VCMI_LIB_NAMESPACE_END
 #include "../../lib/mapping/CMapInfo.h"
+#include "../../lib/filesystem/ResourcePath.h"
 
 class CSlider;
 class CLabel;
@@ -81,9 +82,9 @@ class SelectionTab : public CIntObject
 		std::shared_ptr<CPicture> image2;
 
 		Canvas createMinimapForLayer(std::unique_ptr<CMap> & map, int layer);
-		std::vector<std::shared_ptr<IImage>> createMinimaps(ResourceID resource, int size);
+		std::vector<std::shared_ptr<IImage>> createMinimaps(ResourcePath resource, int size);
 	public:
-		CMapInfoTooltipBox(std::string text, ResourceID resource, ESelectionScreen tabType);
+		CMapInfoTooltipBox(std::string text, ResourcePath resource, ESelectionScreen tabType);
 	};
 public:
 	std::vector<std::shared_ptr<ElementInfo>> allItems;
@@ -134,8 +135,8 @@ private:
 	auto checkSubfolder(std::string path);
 
 	bool isMapSupported(const CMapInfo & info);
-	void parseMaps(const std::unordered_set<ResourceID> & files);
-	void parseSaves(const std::unordered_set<ResourceID> & files);
-	void parseCampaigns(const std::unordered_set<ResourceID> & files);
-	std::unordered_set<ResourceID> getFiles(std::string dirURI, int resType);
+	void parseMaps(const std::unordered_set<ResourcePath> & files);
+	void parseSaves(const std::unordered_set<ResourcePath> & files);
+	void parseCampaigns(const std::unordered_set<ResourcePath> & files);
+	std::unordered_set<ResourcePath> getFiles(std::string dirURI, EResType resType);
 };

+ 3 - 3
client/mainmenu/CCampaignScreen.cpp

@@ -86,7 +86,7 @@ std::shared_ptr<CButton> CCampaignScreen::createExitButton(const JsonNode & butt
 	if(!button["help"].isNull() && button["help"].Float() > 0)
 		help = CGI->generaltexth->zelp[(size_t)button["help"].Float()];
 
-	return std::make_shared<CButton>(Point((int)button["x"].Float(), (int)button["y"].Float()), button["name"].String(), help, [=](){ close();}, EShortcut::GLOBAL_CANCEL);
+	return std::make_shared<CButton>(Point((int)button["x"].Float(), (int)button["y"].Float()), AnimationPath::fromJson(button["name"]), help, [=](){ close();}, EShortcut::GLOBAL_CANCEL);
 }
 
 CCampaignScreen::CCampaignButton::CCampaignButton(const JsonNode & config)
@@ -109,14 +109,14 @@ CCampaignScreen::CCampaignButton::CCampaignButton(const JsonNode & config)
 	if(status != CCampaignScreen::DISABLED)
 	{
 		addUsedEvents(LCLICK | HOVER);
-		graphicsImage = std::make_shared<CPicture>(config["image"].String());
+		graphicsImage = std::make_shared<CPicture>(ImagePath::fromJson(config["image"]));
 
 		hoverLabel = std::make_shared<CLabel>(pos.w / 2, pos.h + 20, FONT_MEDIUM, ETextAlignment::CENTER, Colors::YELLOW, "");
 		parent->addChild(hoverLabel.get());
 	}
 
 	if(status == CCampaignScreen::COMPLETED)
-		graphicsCompleted = std::make_shared<CPicture>("CAMPCHK");
+		graphicsCompleted = std::make_shared<CPicture>(ImagePath::builtin("CAMPCHK"));
 }
 
 void CCampaignScreen::CCampaignButton::show(Canvas & to)

+ 24 - 24
client/mainmenu/CMainMenu.cpp

@@ -78,7 +78,7 @@ CMenuScreen::CMenuScreen(const JsonNode & configNode)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
 
-	background = std::make_shared<CPicture>(config["background"].String());
+	background = std::make_shared<CPicture>(ImagePath::fromJson(config["background"]));
 	if(config["scalable"].Bool())
 		background->scaleTo(GH.screenDimensions());
 
@@ -237,7 +237,7 @@ std::shared_ptr<CButton> CMenuEntry::createButton(CMenuScreen * parent, const Js
 
 	EShortcut shortcut = GH.shortcuts().findShortcut(button["shortcut"].String());
 
-	auto result = std::make_shared<CButton>(Point(posx, posy), button["name"].String(), help, command, shortcut);
+	auto result = std::make_shared<CButton>(Point(posx, posy), AnimationPath::fromJson(button["name"]), help, command, shortcut);
 
 	if (button["center"].Bool())
 		result->moveBy(Point(-result->pos.w/2, -result->pos.h/2));
@@ -262,7 +262,7 @@ CMenuEntry::CMenuEntry(CMenuScreen * parent, const JsonNode & config)
 }
 
 CMainMenuConfig::CMainMenuConfig()
-	: campaignSets(JsonNode(ResourceID("config/campaignSets.json"))), config(JsonNode(ResourceID("config/mainmenu.json")))
+	: campaignSets(JsonNode(ResourcePath("config/campaignSets.json"))), config(JsonNode(ResourcePath("config/mainmenu.json")))
 {
 
 }
@@ -291,7 +291,7 @@ CMainMenu::CMainMenu()
 	GH.defActionsDef = 63;
 	menu = std::make_shared<CMenuScreen>(CMainMenuConfig::get().getConfig()["window"]);
 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
-	backgroundAroundMenu = std::make_shared<CFilledTexture>("DIBOXBCK", pos);
+	backgroundAroundMenu = std::make_shared<CFilledTexture>(ImagePath::builtin("DIBOXBCK"), pos);
 }
 
 CMainMenu::~CMainMenu()
@@ -374,7 +374,7 @@ void CMainMenu::openCampaignScreen(std::string name)
 
 void CMainMenu::startTutorial()
 {
-	ResourceID tutorialMap("Maps/Tutorial.tut", EResType::MAP);
+	ResourcePath tutorialMap("Maps/Tutorial.tut", EResType::MAP);
 	if(!CResourceHandler::get()->existsResource(tutorialMap))
 	{
 		CInfoWindow::showInfoDialog(CGI->generaltexth->translate("core.genrltxt.742"), std::vector<std::shared_ptr<CComponent>>(), PlayerColor(1));
@@ -397,7 +397,7 @@ std::shared_ptr<CMainMenu> CMainMenu::create()
 
 std::shared_ptr<CPicture> CMainMenu::createPicture(const JsonNode & config)
 {
-	return std::make_shared<CPicture>(config["name"].String(), (int)config["x"].Float(), (int)config["y"].Float());
+	return std::make_shared<CPicture>(ImagePath::fromJson(config["name"]), (int)config["x"].Float(), (int)config["y"].Float());
 }
 
 CMultiMode::CMultiMode(ESelectionScreen ScreenType)
@@ -405,20 +405,20 @@ CMultiMode::CMultiMode(ESelectionScreen ScreenType)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
 
-	background = std::make_shared<CPicture>("MUPOPUP.bmp");
+	background = std::make_shared<CPicture>(ImagePath::builtin("MUPOPUP.bmp"));
 	pos = background->center(); //center, window has size of bg graphic
 
-	picture = std::make_shared<CPicture>("MUMAP.bmp", 16, 77);
+	picture = std::make_shared<CPicture>(ImagePath::builtin("MUMAP.bmp"), 16, 77);
 
 	statusBar = CGStatusBar::create(std::make_shared<CPicture>(background->getSurface(), Rect(7, 465, 440, 18), 7, 465));
 	playerName = std::make_shared<CTextInput>(Rect(19, 436, 334, 16), background->getSurface());
 	playerName->setText(getPlayerName());
 	playerName->cb += std::bind(&CMultiMode::onNameChange, this, _1);
 
-	buttonHotseat = std::make_shared<CButton>(Point(373, 78), "MUBHOT.DEF", CGI->generaltexth->zelp[266], std::bind(&CMultiMode::hostTCP, this));
-	buttonHost = std::make_shared<CButton>(Point(373, 78 + 57 * 1), "MUBHOST.DEF", CButton::tooltip(CGI->generaltexth->translate("vcmi.mainMenu.hostTCP"), ""), std::bind(&CMultiMode::hostTCP, this));
-	buttonJoin = std::make_shared<CButton>(Point(373, 78 + 57 * 2), "MUBJOIN.DEF", CButton::tooltip(CGI->generaltexth->translate("vcmi.mainMenu.joinTCP"), ""), std::bind(&CMultiMode::joinTCP, this));
-	buttonCancel = std::make_shared<CButton>(Point(373, 424), "MUBCANC.DEF", CGI->generaltexth->zelp[288], [=](){ close();}, EShortcut::GLOBAL_CANCEL);
+	buttonHotseat = std::make_shared<CButton>(Point(373, 78), AnimationPath::builtin("MUBHOT.DEF"), CGI->generaltexth->zelp[266], std::bind(&CMultiMode::hostTCP, this));
+	buttonHost = std::make_shared<CButton>(Point(373, 78 + 57 * 1), AnimationPath::builtin("MUBHOST.DEF"), CButton::tooltip(CGI->generaltexth->translate("vcmi.mainMenu.hostTCP"), ""), std::bind(&CMultiMode::hostTCP, this));
+	buttonJoin = std::make_shared<CButton>(Point(373, 78 + 57 * 2), AnimationPath::builtin("MUBJOIN.DEF"), CButton::tooltip(CGI->generaltexth->translate("vcmi.mainMenu.joinTCP"), ""), std::bind(&CMultiMode::joinTCP, this));
+	buttonCancel = std::make_shared<CButton>(Point(373, 424), AnimationPath::builtin("MUBCANC.DEF"), CGI->generaltexth->zelp[288], [=](){ close();}, EShortcut::GLOBAL_CANCEL);
 }
 
 void CMultiMode::hostTCP()
@@ -453,7 +453,7 @@ CMultiPlayers::CMultiPlayers(const std::string & firstPlayer, ESelectionScreen S
 	: loadMode(LoadMode), screenType(ScreenType), host(Host)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
-	background = std::make_shared<CPicture>("MUHOTSEA.bmp");
+	background = std::make_shared<CPicture>(ImagePath::builtin("MUHOTSEA.bmp"));
 	pos = background->center(); //center, window has size of bg graphic
 
 	std::string text = CGI->generaltexth->allTexts[446];
@@ -466,8 +466,8 @@ CMultiPlayers::CMultiPlayers(const std::string & firstPlayer, ESelectionScreen S
 		inputNames[i]->cb += std::bind(&CMultiPlayers::onChange, this, _1);
 	}
 
-	buttonOk = std::make_shared<CButton>(Point(95, 338), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], std::bind(&CMultiPlayers::enterSelectionScreen, this), EShortcut::GLOBAL_ACCEPT);
-	buttonCancel = std::make_shared<CButton>(Point(205, 338), "MUBCANC.DEF", CGI->generaltexth->zelp[561], [=](){ close();}, EShortcut::GLOBAL_CANCEL);
+	buttonOk = std::make_shared<CButton>(Point(95, 338), AnimationPath::builtin("MUBCHCK.DEF"), CGI->generaltexth->zelp[560], std::bind(&CMultiPlayers::enterSelectionScreen, this), EShortcut::GLOBAL_ACCEPT);
+	buttonCancel = std::make_shared<CButton>(Point(205, 338), AnimationPath::builtin("MUBCANC.DEF"), CGI->generaltexth->zelp[561], [=](){ close();}, EShortcut::GLOBAL_CANCEL);
 	statusBar = CGStatusBar::create(std::make_shared<CPicture>(background->getSurface(), Rect(7, 381, 348, 18), 7, 381));
 
 	inputNames[0]->setText(firstPlayer, true);
@@ -498,7 +498,7 @@ void CMultiPlayers::enterSelectionScreen()
 CSimpleJoinScreen::CSimpleJoinScreen(bool host)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
-	background = std::make_shared<CPicture>("MUDIALOG.bmp"); // address background
+	background = std::make_shared<CPicture>(ImagePath::builtin("MUDIALOG.bmp")); // address background
 	pos = background->center(); //center, window has size of bg graphic (x,y = 396,278 w=232 h=212)
 
 	textTitle = std::make_shared<CTextBox>("", Rect(20, 20, 205, 50), 0, FONT_BIG, ETextAlignment::CENTER, Colors::WHITE);
@@ -515,14 +515,14 @@ CSimpleJoinScreen::CSimpleJoinScreen(bool host)
 		inputAddress->cb += std::bind(&CSimpleJoinScreen::onChange, this, _1);
 		inputPort->cb += std::bind(&CSimpleJoinScreen::onChange, this, _1);
 		inputPort->filters += std::bind(&CTextInput::numberFilter, _1, _2, 0, 65535);
-		buttonOk = std::make_shared<CButton>(Point(26, 142), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], std::bind(&CSimpleJoinScreen::connectToServer, this), EShortcut::GLOBAL_ACCEPT);
+		buttonOk = std::make_shared<CButton>(Point(26, 142), AnimationPath::builtin("MUBCHCK.DEF"), CGI->generaltexth->zelp[560], std::bind(&CSimpleJoinScreen::connectToServer, this), EShortcut::GLOBAL_ACCEPT);
 
 		inputAddress->giveFocus();
 	}
 	inputAddress->setText(host ? CServerHandler::localhostAddress : CSH->getHostAddress(), true);
 	inputPort->setText(std::to_string(CSH->getHostPort()), true);
 
-	buttonCancel = std::make_shared<CButton>(Point(142, 142), "MUBCANC.DEF", CGI->generaltexth->zelp[561], std::bind(&CSimpleJoinScreen::leaveScreen, this), EShortcut::GLOBAL_CANCEL);
+	buttonCancel = std::make_shared<CButton>(Point(142, 142), AnimationPath::builtin("MUBCANC.DEF"), CGI->generaltexth->zelp[561], std::bind(&CSimpleJoinScreen::leaveScreen, this), EShortcut::GLOBAL_CANCEL);
 	statusBar = CGStatusBar::create(std::make_shared<CPicture>(background->getSurface(), Rect(7, 186, 218, 18), 7, 186));
 }
 
@@ -601,7 +601,7 @@ CLoadingScreen::CLoadingScreen()
 		
 		for(int i = 0; i < blocksAmount; ++i)
 		{
-			progressBlocks.push_back(std::make_shared<CAnimImage>(conf["name"].String(), i, 0, posx + i * blockSize, posy));
+			progressBlocks.push_back(std::make_shared<CAnimImage>(AnimationPath::fromJson(conf["name"]), i, 0, posx + i * blockSize, posy));
 			progressBlocks.back()->deactivate();
 			progressBlocks.back()->visible = false;
 		}
@@ -626,24 +626,24 @@ void CLoadingScreen::tick(uint32_t msPassed)
 	}
 }
 
-std::string CLoadingScreen::getBackground()
+ImagePath CLoadingScreen::getBackground()
 {
-	std::string fname = "loadbar";
+	ImagePath fname = ImagePath::builtin("loadbar");
 	const auto & conf = CMainMenuConfig::get().getConfig()["loading"];
 
 	if(conf.isStruct())
 	{
 		if(conf["background"].isVector())
-			return RandomGeneratorUtil::nextItem(conf["background"].Vector(), CRandomGenerator::getDefault())->String();
+			return ImagePath::fromJson(*RandomGeneratorUtil::nextItem(conf["background"].Vector(), CRandomGenerator::getDefault()));
 		
 		if(conf["background"].isString())
-			return conf["background"].String();
+			return ImagePath::fromJson(conf["background"]);
 		
 		return fname;
 	}
 	
 	if(conf.isVector() && !conf.Vector().empty())
-		return RandomGeneratorUtil::nextItem(conf.Vector(), CRandomGenerator::getDefault())->String();
+		return ImagePath::fromJson(*RandomGeneratorUtil::nextItem(conf.Vector(), CRandomGenerator::getDefault()));
 	
 	return fname;
 }

+ 1 - 1
client/mainmenu/CMainMenu.h

@@ -185,7 +185,7 @@ class CLoadingScreen : virtual public CWindowObject, virtual public Load::Progre
 {
 	std::vector<std::shared_ptr<CAnimImage>> progressBlocks;
 	
-	std::string getBackground();
+	ImagePath getBackground();
 
 public:	
 	CLoadingScreen();

+ 1 - 1
client/mainmenu/CreditsScreen.cpp

@@ -26,7 +26,7 @@ CreditsScreen::CreditsScreen(Rect rect)
 	pos.h = rect.h;
 	setRedrawParent(true);
 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
-	auto textFile = CResourceHandler::get()->load(ResourceID("DATA/CREDITS.TXT"))->readAll();
+	auto textFile = CResourceHandler::get()->load(ResourcePath("DATA/CREDITS.TXT"))->readAll();
 	std::string text((char *)textFile.first.get(), textFile.second);
 	size_t firstQuote = text.find('\"') + 1;
 	text = text.substr(firstQuote, text.find('\"', firstQuote) - firstQuote);

+ 11 - 11
client/mapView/MapRenderer.cpp

@@ -94,7 +94,7 @@ MapTileStorage::MapTileStorage(size_t capacity)
 {
 }
 
-void MapTileStorage::load(size_t index, const std::string & filename, EImageBlitMode blitMode)
+void MapTileStorage::load(size_t index, const AnimationPath & filename, EImageBlitMode blitMode)
 {
 	auto & terrainAnimations = animations[index];
 
@@ -247,7 +247,7 @@ uint8_t MapRendererRoad::checksum(IMapRendererContext & context, const int3 & co
 MapRendererBorder::MapRendererBorder()
 {
 	emptyFill = std::make_unique<Canvas>(Point(32,32));
-	animation = std::make_unique<CAnimation>("EDG");
+	animation = std::make_unique<CAnimation>(AnimationPath::builtin("EDG"));
 	animation->preload();
 }
 
@@ -309,9 +309,9 @@ uint8_t MapRendererBorder::checksum(IMapRendererContext & context, const int3 &
 
 MapRendererFow::MapRendererFow()
 {
-	fogOfWarFullHide = std::make_unique<CAnimation>("TSHRC");
+	fogOfWarFullHide = std::make_unique<CAnimation>(AnimationPath::builtin("TSHRC"));
 	fogOfWarFullHide->preload();
-	fogOfWarPartialHide = std::make_unique<CAnimation>("TSHRE");
+	fogOfWarPartialHide = std::make_unique<CAnimation>(AnimationPath::builtin("TSHRE"));
 	fogOfWarPartialHide->preload();
 
 	for(size_t i = 0; i < fogOfWarFullHide->size(); ++i)
@@ -387,7 +387,7 @@ std::shared_ptr<CAnimation> MapRendererObjects::getBaseAnimation(const CGObjectI
 	return getAnimation(info->animationFile, generateMovementGroups);
 }
 
-std::shared_ptr<CAnimation> MapRendererObjects::getAnimation(const std::string & filename, bool generateMovementGroups)
+std::shared_ptr<CAnimation> MapRendererObjects::getAnimation(const AnimationPath & filename, bool generateMovementGroups)
 {
 	auto it = animations.find(filename);
 
@@ -422,7 +422,7 @@ std::shared_ptr<CAnimation> MapRendererObjects::getFlagAnimation(const CGObjectI
 	{
 		assert(dynamic_cast<const CGHeroInstance *>(obj) != nullptr);
 		assert(obj->tempOwner.isValidPlayer());
-		return getAnimation(heroFlags[obj->tempOwner.getNum()], true);
+		return getAnimation(AnimationPath::builtin(heroFlags[obj->tempOwner.getNum()]), true);
 	}
 
 	if(obj->ID == Obj::BOAT)
@@ -557,10 +557,10 @@ uint8_t MapRendererObjects::checksum(IMapRendererContext & context, const int3 &
 }
 
 MapRendererOverlay::MapRendererOverlay()
-	: imageGrid(IImage::createFromFile("debug/grid", EImageBlitMode::ALPHA))
-	, imageBlocked(IImage::createFromFile("debug/blocked", EImageBlitMode::ALPHA))
-	, imageVisitable(IImage::createFromFile("debug/visitable", EImageBlitMode::ALPHA))
-	, imageSpellRange(IImage::createFromFile("debug/spellRange", EImageBlitMode::ALPHA))
+	: imageGrid(IImage::createFromFile(ImagePath::builtin("debug/grid"), EImageBlitMode::ALPHA))
+	, imageBlocked(IImage::createFromFile(ImagePath::builtin("debug/blocked"), EImageBlitMode::ALPHA))
+	, imageVisitable(IImage::createFromFile(ImagePath::builtin("debug/visitable"), EImageBlitMode::ALPHA))
+	, imageSpellRange(IImage::createFromFile(ImagePath::builtin("debug/spellRange"), EImageBlitMode::ALPHA))
 {
 
 }
@@ -616,7 +616,7 @@ uint8_t MapRendererOverlay::checksum(IMapRendererContext & context, const int3 &
 }
 
 MapRendererPath::MapRendererPath()
-	: pathNodes(new CAnimation("ADAG"))
+	: pathNodes(new CAnimation(AnimationPath::builtin("ADAG")))
 {
 	pathNodes->preload();
 }

+ 5 - 3
client/mapView/MapRenderer.h

@@ -9,6 +9,8 @@
  */
 #pragma once
 
+#include "../../lib/filesystem/ResourcePath.h"
+
 VCMI_LIB_NAMESPACE_BEGIN
 
 class int3;
@@ -30,7 +32,7 @@ class MapTileStorage
 
 public:
 	explicit MapTileStorage(size_t capacity);
-	void load(size_t index, const std::string & filename, EImageBlitMode blitMode);
+	void load(size_t index, const AnimationPath & filename, EImageBlitMode blitMode);
 	std::shared_ptr<IImage> find(size_t fileIndex, size_t rotationIndex, size_t imageIndex);
 };
 
@@ -69,13 +71,13 @@ public:
 
 class MapRendererObjects
 {
-	std::unordered_map<std::string, std::shared_ptr<CAnimation>> animations;
+	std::map<AnimationPath, std::shared_ptr<CAnimation>> animations;
 
 	std::shared_ptr<CAnimation> getBaseAnimation(const CGObjectInstance * obj);
 	std::shared_ptr<CAnimation> getFlagAnimation(const CGObjectInstance * obj);
 	std::shared_ptr<CAnimation> getOverlayAnimation(const CGObjectInstance * obj);
 
-	std::shared_ptr<CAnimation> getAnimation(const std::string & filename, bool generateMovementGroups);
+	std::shared_ptr<CAnimation> getAnimation(const AnimationPath & filename, bool generateMovementGroups);
 
 	std::shared_ptr<IImage> getImage(IMapRendererContext & context, const CGObjectInstance * obj, const std::shared_ptr<CAnimation> & animation) const;
 

+ 1 - 1
client/mapView/MapViewCache.cpp

@@ -28,7 +28,7 @@ MapViewCache::MapViewCache(const std::shared_ptr<MapViewModel> & model)
 	: model(model)
 	, cachedLevel(0)
 	, mapRenderer(new MapRenderer())
-	, iconsStorage(new CAnimation("VwSymbol"))
+	, iconsStorage(new CAnimation(AnimationPath::builtin("VwSymbol")))
 	, intermediate(new Canvas(Point(32, 32)))
 	, terrain(new Canvas(model->getCacheDimensionsPixels()))
 	, terrainTransition(new Canvas(model->getPixelsVisibleDimensions()))

+ 15 - 23
client/render/CAnimation.cpp

@@ -22,7 +22,7 @@ std::shared_ptr<IImage> CAnimation::getFromExtraDef(std::string filename)
 	size_t pos = filename.find(':');
 	if (pos == -1)
 		return nullptr;
-	CAnimation anim(filename.substr(0, pos));
+	CAnimation anim(AnimationPath::builtinTODO(filename.substr(0, pos)));
 	pos++;
 	size_t frame = atoi(filename.c_str()+pos);
 	size_t group = 0;
@@ -144,7 +144,7 @@ void CAnimation::exportBitmaps(const boost::filesystem::path& path) const
 		return;
 	}
 
-	boost::filesystem::path actualPath = path / "SPRITES" / name;
+	boost::filesystem::path actualPath = path / "SPRITES" / name.getName();
 	boost::filesystem::create_directories(actualPath);
 
 	size_t counter = 0;
@@ -179,16 +179,15 @@ void CAnimation::init()
 			source[defEntry.first].resize(defEntry.second);
 	}
 
-	ResourceID resID(std::string("SPRITES/") + name, EResType::TEXT);
+	if (vstd::contains(graphics->imageLists, name.getName()))
+		initFromJson(graphics->imageLists[name.getName()]);
 
-	if (vstd::contains(graphics->imageLists, resID.getName()))
-		initFromJson(graphics->imageLists[resID.getName()]);
-
-	auto configList = CResourceHandler::get()->getResourcesWithName(resID);
+	auto jsonResource = name.toType<EResType::TEXT>();
+	auto configList = CResourceHandler::get()->getResourcesWithName(jsonResource);
 
 	for(auto & loader : configList)
 	{
-		auto stream = loader->load(resID);
+		auto stream = loader->load(jsonResource);
 		std::unique_ptr<ui8[]> textData(new ui8[stream->getSize()]);
 		stream->read(textData.get(), stream->getSize());
 
@@ -200,28 +199,21 @@ void CAnimation::init()
 
 void CAnimation::printError(size_t frame, size_t group, std::string type) const
 {
-	logGlobal->error("%s error: Request for frame not present in CAnimation! File name: %s, Group: %d, Frame: %d", type, name, group, frame);
+	logGlobal->error("%s error: Request for frame not present in CAnimation! File name: %s, Group: %d, Frame: %d", type, name.getOriginalName(), group, frame);
 }
 
-CAnimation::CAnimation(std::string Name):
-	name(Name),
+CAnimation::CAnimation(const AnimationPath & Name):
+	name(boost::starts_with(Name.getName(), "SPRITES") ? Name : Name.addPrefix("SPRITES/")),
 	preloaded(false),
 	defFile()
 {
-	size_t dotPos = name.find_last_of('.');
-	if ( dotPos!=-1 )
-		name.erase(dotPos);
-	std::transform(name.begin(), name.end(), name.begin(), toupper);
-
-	ResourceID resource(std::string("SPRITES/") + name, EResType::ANIMATION);
-
-	if(CResourceHandler::get()->existsResource(resource))
+	if(CResourceHandler::get()->existsResource(name))
 		defFile = std::make_shared<CDefFile>(name);
 
 	init();
 
 	if(source.empty())
-		logAnim->error("Animation %s failed to load", Name);
+		logAnim->error("Animation %s failed to load", Name.getOriginalName());
 }
 
 CAnimation::CAnimation():
@@ -238,13 +230,13 @@ void CAnimation::duplicateImage(const size_t sourceGroup, const size_t sourceFra
 {
 	if(!source.count(sourceGroup))
 	{
-		logAnim->error("Group %d missing in %s", sourceGroup, name);
+		logAnim->error("Group %d missing in %s", sourceGroup, name.getName());
 		return;
 	}
 
 	if(source[sourceGroup].size() <= sourceFrame)
 	{
-		logAnim->error("Frame [%d %d] missing in %s", sourceGroup, sourceFrame, name);
+		logAnim->error("Frame [%d %d] missing in %s", sourceGroup, sourceFrame, name.getName());
 		return;
 	}
 
@@ -253,7 +245,7 @@ void CAnimation::duplicateImage(const size_t sourceGroup, const size_t sourceFra
 
 	if(clone.getType() == JsonNode::JsonType::DATA_NULL)
 	{
-		std::string temp =  name+":"+std::to_string(sourceGroup)+":"+std::to_string(sourceFrame);
+		std::string temp =  name.getName()+":"+std::to_string(sourceGroup)+":"+std::to_string(sourceFrame);
 		clone["file"].String() = temp;
 	}
 

+ 3 - 2
client/render/CAnimation.h

@@ -10,6 +10,7 @@
 #pragma once
 
 #include "../../lib/GameConstants.h"
+#include "../../lib/filesystem/ResourcePath.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 class JsonNode;
@@ -29,7 +30,7 @@ private:
 	std::map<size_t, std::map<size_t, std::shared_ptr<IImage> > > images;
 
 	//animation file name
-	std::string name;
+	AnimationPath name;
 
 	bool preloaded;
 
@@ -53,7 +54,7 @@ private:
 	std::shared_ptr<IImage> getFromExtraDef(std::string filename);
 
 public:
-	CAnimation(std::string Name);
+	CAnimation(const AnimationPath & Name);
 	CAnimation();
 	~CAnimation();
 

+ 2 - 2
client/render/CBitmapHandler.cpp

@@ -110,14 +110,14 @@ SDL_Surface * BitmapHandler::loadBitmapFromDir(std::string path, std::string fna
 		logGlobal->warn("Call to loadBitmap with void fname!");
 		return nullptr;
 	}
-	if (!CResourceHandler::get()->existsResource(ResourceID(path + fname, EResType::IMAGE)))
+	if (!CResourceHandler::get()->existsResource(ResourcePath(path + fname, EResType::IMAGE)))
 	{
 		return nullptr;
 	}
 
 	SDL_Surface * ret=nullptr;
 
-	auto readFile = CResourceHandler::get()->load(ResourceID(path + fname, EResType::IMAGE))->readAll();
+	auto readFile = CResourceHandler::get()->load(ResourcePath(path + fname, EResType::IMAGE))->readAll();
 
 	if (isPCX(readFile.first.get()))
 	{//H3-style PCX

+ 5 - 5
client/render/CDefFile.cpp

@@ -24,7 +24,7 @@ class CFileCache
 	static const int cacheSize = 50; //Max number of cached files
 	struct FileData
 	{
-		ResourceID             name;
+		AnimationPath             name;
 		size_t                 size;
 		std::unique_ptr<ui8[]> data;
 
@@ -34,7 +34,7 @@ class CFileCache
 			std::copy(data.get(), data.get() + size, ret.get());
 			return ret;
 		}
-		FileData(ResourceID name_, size_t size_, std::unique_ptr<ui8[]> data_):
+		FileData(AnimationPath name_, size_t size_, std::unique_ptr<ui8[]> data_):
 			name{std::move(name_)},
 			size{size_},
 			data{std::move(data_)}
@@ -43,7 +43,7 @@ class CFileCache
 
 	std::deque<FileData> cache;
 public:
-	std::unique_ptr<ui8[]> getCachedFile(ResourceID rid)
+	std::unique_ptr<ui8[]> getCachedFile(AnimationPath rid)
 	{
 		for(auto & file : cache)
 		{
@@ -97,7 +97,7 @@ static bool colorsSimilar (const SDL_Color & lhs, const SDL_Color & rhs)
 	return std::abs(diffR) < threshold && std::abs(diffG) < threshold && std::abs(diffB) < threshold && std::abs(diffA) < threshold;
 }
 
-CDefFile::CDefFile(std::string Name):
+CDefFile::CDefFile(const AnimationPath & Name):
 	data(nullptr),
 	palette(nullptr)
 {
@@ -124,7 +124,7 @@ CDefFile::CDefFile(std::string Name):
 		{0, 0, 0, 64 }  // shadow border below selection ( used in battle def's )
 	};
 
-	data = animationCache.getCachedFile(ResourceID(std::string("SPRITES/") + Name, EResType::ANIMATION));
+	data = animationCache.getCachedFile(Name);
 
 	palette = std::unique_ptr<SDL_Color[]>(new SDL_Color[256]);
 	int it = 0;

+ 2 - 1
client/render/CDefFile.h

@@ -10,6 +10,7 @@
 #pragma once
 
 #include "../../lib/vcmi_endian.h"
+#include "../../lib/filesystem/ResourcePath.h"
 
 class IImageLoader;
 struct SDL_Color;
@@ -39,7 +40,7 @@ private:
 	std::unique_ptr<SDL_Color[]> palette;
 
 public:
-	CDefFile(std::string Name);
+	CDefFile(const AnimationPath & Name);
 	~CDefFile();
 
 	//load frame as SDL_Surface

+ 11 - 13
client/render/Graphics.cpp

@@ -44,7 +44,7 @@ Graphics * graphics = nullptr;
 
 void Graphics::loadPaletteAndColors()
 {
-	auto textFile = CResourceHandler::get()->load(ResourceID("DATA/PLAYERS.PAL"))->readAll();
+	auto textFile = CResourceHandler::get()->load(ResourcePath("DATA/PLAYERS.PAL"))->readAll();
 	std::string pals((char*)textFile.first.get(), textFile.second);
 
 	int startPoint = 24; //beginning byte; used to read
@@ -62,7 +62,7 @@ void Graphics::loadPaletteAndColors()
 		}
 	}
 
-	auto stream = CResourceHandler::get()->load(ResourceID("config/NEUTRAL.PAL"));
+	auto stream = CResourceHandler::get()->load(ResourcePath("config/NEUTRAL.PAL"));
 	CBinaryReader reader(stream.get());
 
 	for(int i=0; i<32; ++i)
@@ -102,10 +102,10 @@ void Graphics::initializeBattleGraphics()
 	allConfigs.insert(allConfigs.begin(), ModScope::scopeBuiltin());
 	for(auto & mod : allConfigs)
 	{
-		if(!CResourceHandler::get(mod)->existsResource(ResourceID("config/battles_graphics.json")))
+		if(!CResourceHandler::get(mod)->existsResource(ResourcePath("config/battles_graphics.json")))
 			continue;
 			
-		const JsonNode config(mod, ResourceID("config/battles_graphics.json"));
+		const JsonNode config(mod, ResourcePath("config/battles_graphics.json"));
 
 		//initialization of AC->def name mapping
 		if(!config["ac_mapping"].isNull())
@@ -204,7 +204,7 @@ void Graphics::blueToPlayersAdv(SDL_Surface * sur, PlayerColor player)
 
 void Graphics::loadFonts()
 {
-	const JsonNode config(ResourceID("config/fonts.json"));
+	const JsonNode config(ResourcePath("config/fonts.json"));
 
 	const JsonVector & bmpConf = config["bitmap"].Vector();
 	const JsonNode   & ttfConf = config["trueType"];
@@ -228,7 +228,7 @@ void Graphics::loadFonts()
 void Graphics::loadErmuToPicture()
 {
 	//loading ERMU to picture
-	const JsonNode config(ResourceID("config/ERMU_to_picture.json"));
+	const JsonNode config(ResourcePath("config/ERMU_to_picture.json"));
 	int etp_idx = 0;
 	for(const JsonNode &etp : config["ERMU_to_picture"].Vector()) {
 		int idx = 0;
@@ -279,16 +279,14 @@ void Graphics::initializeImageLists()
 	addImageListEntries(CGI->skills());
 }
 
-std::shared_ptr<CAnimation> Graphics::getAnimation(const std::string & path)
+std::shared_ptr<CAnimation> Graphics::getAnimation(const AnimationPath & path)
 {
-	ResourceID animationPath(path, EResType::ANIMATION);
+	if (cachedAnimations.count(path) != 0)
+		return cachedAnimations.at(path);
 
-	if (cachedAnimations.count(animationPath.getName()) != 0)
-		return cachedAnimations.at(animationPath.getName());
-
-	auto newAnimation = std::make_shared<CAnimation>(animationPath.getName());
+	auto newAnimation = std::make_shared<CAnimation>(path);
 
 	newAnimation->preload();
-	cachedAnimations[animationPath.getName()] = newAnimation;
+	cachedAnimations[path] = newAnimation;
 	return newAnimation;
 }

+ 3 - 2
client/render/Graphics.h

@@ -11,6 +11,7 @@
 
 #include "../lib/GameConstants.h"
 #include "../lib/Color.h"
+#include "../lib/filesystem/ResourcePath.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -42,10 +43,10 @@ class Graphics
 	void loadFonts();
 	void initializeImageLists();
 
-	std::map<std::string, std::shared_ptr<CAnimation>> cachedAnimations;
+	std::map<AnimationPath, std::shared_ptr<CAnimation>> cachedAnimations;
 
 public:
-	std::shared_ptr<CAnimation> getAnimation(const std::string & path);
+	std::shared_ptr<CAnimation> getAnimation(const AnimationPath & path);
 
 	//Fonts
 	static const int FONTS_NUMBER = 9;

+ 4 - 2
client/render/IImage.h

@@ -9,6 +9,8 @@
  */
 #pragma once
 
+#include "../../lib/filesystem/ResourcePath.h"
+
 VCMI_LIB_NAMESPACE_BEGIN
 
 class PlayerColor;
@@ -84,8 +86,8 @@ public:
 	virtual ~IImage();
 
 	/// loads image from specified file. Returns 0-sized images on failure
-	static std::shared_ptr<IImage> createFromFile( const std::string & path );
-	static std::shared_ptr<IImage> createFromFile( const std::string & path, EImageBlitMode mode );
+	static std::shared_ptr<IImage> createFromFile( const ImagePath & path );
+	static std::shared_ptr<IImage> createFromFile( const ImagePath & path, EImageBlitMode mode );
 
 	/// temporary compatibility method. Creates IImage from existing SDL_Surface
 	/// Surface will be shared, called must still free it with SDL_FreeSurface

+ 2 - 2
client/renderSDL/CBitmapFont.cpp

@@ -24,7 +24,7 @@
 
 #include <SDL_surface.h>
 
-void CBitmapFont::loadModFont(const std::string & modName, const ResourceID & resource)
+void CBitmapFont::loadModFont(const std::string & modName, const ResourcePath & resource)
 {
 	if (!CResourceHandler::get(modName)->existsResource(resource))
 	{
@@ -72,7 +72,7 @@ void CBitmapFont::loadModFont(const std::string & modName, const ResourceID & re
 CBitmapFont::CBitmapFont(const std::string & filename):
 	maxHeight(0)
 {
-	ResourceID resource("data/" + filename, EResType::BMP_FONT);
+	ResourcePath resource("data/" + filename, EResType::BMP_FONT);
 
 	loadModFont("core", resource);
 

+ 2 - 2
client/renderSDL/CBitmapFont.h

@@ -12,7 +12,7 @@
 #include "../render/IFont.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
-class ResourceID;
+class ResourcePath;
 VCMI_LIB_NAMESPACE_END
 
 class CBitmapFont : public IFont
@@ -31,7 +31,7 @@ class CBitmapFont : public IFont
 	std::unordered_map<CodePoint, BitmapChar> chars;
 	uint32_t maxHeight;
 
-	void loadModFont(const std::string & modName, const ResourceID & resource);
+	void loadModFont(const std::string & modName, const ResourcePath & resource);
 
 	void renderCharacter(SDL_Surface * surface, const BitmapChar & character, const ColorRGBA & color, int &posX, int &posY) const;
 	void renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const override;

+ 1 - 1
client/renderSDL/CBitmapHanFont.cpp

@@ -98,7 +98,7 @@ void CBitmapHanFont::renderText(SDL_Surface * surface, const std::string & data,
 
 CBitmapHanFont::CBitmapHanFont(const JsonNode &config):
 	fallback(new CBitmapFont(config["fallback"].String())),
-	data(CResourceHandler::get()->load(ResourceID("data/" + config["name"].String(), EResType::OTHER))->readAll()),
+	data(CResourceHandler::get()->load(ResourcePath("data/" + config["name"].String(), EResType::OTHER))->readAll()),
 	size((size_t)config["size"].Float())
 {
 	// basic tests to make sure that fonts are OK

+ 1 - 1
client/renderSDL/CTrueTypeFont.cpp

@@ -24,7 +24,7 @@
 std::pair<std::unique_ptr<ui8[]>, ui64> CTrueTypeFont::loadData(const JsonNode & config)
 {
 	std::string filename = "Data/" + config["file"].String();
-	return CResourceHandler::get()->load(ResourceID(filename, EResType::TTF_FONT))->readAll();
+	return CResourceHandler::get()->load(ResourcePath(filename, EResType::TTF_FONT))->readAll();
 }
 
 TTF_Font * CTrueTypeFont::loadFont(const JsonNode &config)

+ 3 - 3
client/renderSDL/SDLImage.cpp

@@ -24,14 +24,14 @@
 
 class SDLImageLoader;
 
-std::shared_ptr<IImage> IImage::createFromFile( const std::string & path )
+std::shared_ptr<IImage> IImage::createFromFile( const ImagePath & path )
 {
 	return createFromFile(path, EImageBlitMode::ALPHA);
 }
 
-std::shared_ptr<IImage> IImage::createFromFile( const std::string & path, EImageBlitMode mode )
+std::shared_ptr<IImage> IImage::createFromFile( const ImagePath & path, EImageBlitMode mode )
 {
-	return std::shared_ptr<IImage>(new SDLImage(path, mode));
+	return std::shared_ptr<IImage>(new SDLImage(path.getName(), mode));
 }
 
 std::shared_ptr<IImage> IImage::createFromSurface( SDL_Surface * source )

+ 3 - 3
client/widgets/Buttons.cpp

@@ -89,7 +89,7 @@ void CButton::addOverlay(std::shared_ptr<CIntObject> newOverlay)
 	update();
 }
 
-void CButton::addImage(std::string filename)
+void CButton::addImage(const AnimationPath & filename)
 {
 	imageNames.push_back(filename);
 }
@@ -232,7 +232,7 @@ void CButton::hover (bool on)
 	}
 }
 
-CButton::CButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help, CFunctionList<void()> Callback, EShortcut key, bool playerColoredButton):
+CButton::CButton(Point position, const AnimationPath &defName, const std::pair<std::string, std::string> &help, CFunctionList<void()> Callback, EShortcut key, bool playerColoredButton):
     CKeyShortcut(key),
     callback(Callback)
 {
@@ -357,7 +357,7 @@ void CToggleBase::addCallback(std::function<void(bool)> function)
 	callback += function;
 }
 
-CToggleButton::CToggleButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help,
+CToggleButton::CToggleButton(Point position, const AnimationPath &defName, const std::pair<std::string, std::string> &help,
 							 CFunctionList<void(bool)> callback, EShortcut key, bool playerColoredButton):
   CButton(position, defName, help, 0, key, playerColoredButton),
   CToggleBase(callback)

+ 5 - 4
client/widgets/Buttons.h

@@ -12,6 +12,7 @@
 #include "../gui/CIntObject.h"
 #include "../render/EFont.h"
 #include "../../lib/FunctionList.h"
+#include "../../lib/filesystem/ResourcePath.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 class Rect;
@@ -36,7 +37,7 @@ public:
 		HIGHLIGHTED=3
 	};
 protected:
-	std::vector<std::string> imageNames;//store list of images that can be used by this button
+	std::vector<AnimationPath> imageNames;//store list of images that can be used by this button
 	size_t currentImage;
 
 	ButtonState state;//current state of button from enum
@@ -72,7 +73,7 @@ public:
 	void addOverlay(std::shared_ptr<CIntObject> newOverlay);
 	void addTextOverlay(const std::string & Text, EFonts font, ColorRGBA color);
 
-	void addImage(std::string filename);
+	void addImage(const AnimationPath & filename);
 	void addHoverText(ButtonState state, std::string text);
 
 	void setImageOrder(int state1, int state2, int state3, int state4);
@@ -84,7 +85,7 @@ public:
 	bool isHighlighted();
 
 	/// Constructor
-	CButton(Point position, const std::string & defName, const std::pair<std::string, std::string> & help,
+	CButton(Point position, const AnimationPath & defName, const std::pair<std::string, std::string> & help,
 			CFunctionList<void()> Callback = 0, EShortcut key = {}, bool playerColoredButton = false );
 
 	/// Appearance modifiers
@@ -145,7 +146,7 @@ class CToggleButton : public CButton, public CToggleBase
 	void setEnabled(bool enabled) override;
 
 public:
-	CToggleButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help,
+	CToggleButton(Point position, const AnimationPath &defName, const std::pair<std::string, std::string> &help,
 				  CFunctionList<void(bool)> Callback = 0, EShortcut key = {}, bool playerColoredButton = false );
 
 	void clickPressed(const Point & cursorPosition) override;

+ 3 - 3
client/widgets/CArtifactHolder.cpp

@@ -89,7 +89,7 @@ void CCommanderArtPlace::createImage()
 	if(ourArt)
 		imageIndex = ourArt->artType->getIconIndex();
 
-	image = std::make_shared<CAnimImage>("artifact", imageIndex);
+	image = std::make_shared<CAnimImage>(AnimationPath::builtin("artifact"), imageIndex);
 	if(!ourArt)
 		image->disable();
 }
@@ -247,11 +247,11 @@ void CHeroArtPlace::createImage()
 	else if(ourArt)
 		imageIndex = ourArt->artType->getIconIndex();
 
-	image = std::make_shared<CAnimImage>("artifact", imageIndex);
+	image = std::make_shared<CAnimImage>(AnimationPath::builtin("artifact"), imageIndex);
 	if(!ourArt)
 		image->disable();
 
-	selection = std::make_shared<CAnimImage>("artifact", ArtifactID::ART_SELECTION);
+	selection = std::make_shared<CAnimImage>(AnimationPath::builtin("artifact"), ArtifactID::ART_SELECTION);
 	selection->disable();
 }
 

+ 1 - 1
client/widgets/CArtifactsOfHeroBackpack.cpp

@@ -42,7 +42,7 @@ CArtifactsOfHeroBackpack::CArtifactsOfHeroBackpack(const Point & position)
 
 	for(int i = 0; i < visibleCapacityMax; i++)
 	{
-		auto artifactSlotBackground = std::make_shared<CPicture>("heroWindow/artifactSlotEmpty",
+		auto artifactSlotBackground = std::make_shared<CPicture>( ImagePath::builtin("heroWindow/artifactSlotEmpty"),
 			Point(slotSizeWithMargin * (i % HERO_BACKPACK_WINDOW_SLOT_COLUMNS), slotSizeWithMargin * (i / HERO_BACKPACK_WINDOW_SLOT_COLUMNS)));
 
 		backpackSlotsBackgrounds.emplace_back(artifactSlotBackground);

+ 2 - 2
client/widgets/CArtifactsOfHeroBase.cpp

@@ -86,8 +86,8 @@ void CArtifactsOfHeroBase::init(
 		artPlace->leftClickCallback = lClickCallback;
 		artPlace->rightClickCallback = rClickCallback;
 	}
-	leftBackpackRoll = std::make_shared<CButton>(Point(379, 364), "hsbtns3.def", CButton::tooltip(), [scrollHandler]() { scrollHandler(-1); }, EShortcut::MOVE_LEFT);
-	rightBackpackRoll = std::make_shared<CButton>(Point(632, 364), "hsbtns5.def", CButton::tooltip(), [scrollHandler]() { scrollHandler(+1); }, EShortcut::MOVE_RIGHT);
+	leftBackpackRoll = std::make_shared<CButton>(Point(379, 364), AnimationPath::builtin("hsbtns3.def"), CButton::tooltip(), [scrollHandler]() { scrollHandler(-1); }, EShortcut::MOVE_LEFT);
+	rightBackpackRoll = std::make_shared<CButton>(Point(632, 364), AnimationPath::builtin("hsbtns5.def"), CButton::tooltip(), [scrollHandler]() { scrollHandler(+1); }, EShortcut::MOVE_RIGHT);
 	leftBackpackRoll->block(true);
 	rightBackpackRoll->block(true);
 }

+ 6 - 6
client/widgets/CComponent.cpp

@@ -102,7 +102,7 @@ void CComponent::init(Etype Type, int Subtype, int Val, ESize imageSize, EFonts
 	}
 }
 
-const std::vector<std::string> CComponent::getFileName()
+std::vector<AnimationPath> CComponent::getFileName()
 {
 	static const std::string  primSkillsArr [] = {"PSKIL32",        "PSKIL32",        "PSKIL42",        "PSKILL"};
 	static const std::string  secSkillsArr [] =  {"SECSK32",        "SECSK32",        "SECSKILL",       "SECSK82"};
@@ -115,9 +115,9 @@ const std::vector<std::string> CComponent::getFileName()
 	static const std::string  heroArr [] =       {"PortraitsSmall", "PortraitsSmall", "PortraitsSmall", "PortraitsLarge"};
 	static const std::string  flagArr [] =       {"CREST58",        "CREST58",        "CREST58",        "CREST58"};
 
-	auto gen = [](const std::string * arr)
+	auto gen = [](const std::string * arr) -> std::vector<AnimationPath>
 	{
-		return std::vector<std::string>(arr, arr + 4);
+		return { AnimationPath::builtin(arr[0]), AnimationPath::builtin(arr[1]), AnimationPath::builtin(arr[2]), AnimationPath::builtin(arr[3]) };
 	};
 
 	switch(compType)
@@ -131,12 +131,12 @@ const std::vector<std::string> CComponent::getFileName()
 	case spell:      return gen(spellsArr);
 	case morale:     return gen(moraleArr);
 	case luck:       return gen(luckArr);
-	case building:   return std::vector<std::string>(4, (*CGI->townh)[subtype]->town->clientInfo.buildingsIcons);
+	case building:   return std::vector<AnimationPath>(4, (*CGI->townh)[subtype]->town->clientInfo.buildingsIcons);
 	case hero:       return gen(heroArr);
 	case flag:       return gen(flagArr);
 	}
 	assert(0);
-	return std::vector<std::string>();
+	return {};
 }
 
 size_t CComponent::getIndex()
@@ -251,7 +251,7 @@ std::string CComponent::getSubtitleInternal()
 	return "";
 }
 
-void CComponent::setSurface(std::string defName, int imgPos)
+void CComponent::setSurface(const AnimationPath & defName, int imgPos)
 {
 	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
 	image = std::make_shared<CAnimImage>(defName, imgPos);

+ 3 - 3
client/widgets/CComponent.h

@@ -11,7 +11,7 @@
 
 #include "../gui/CIntObject.h"
 #include "../render/EFont.h"
-
+#include "../../lib/filesystem/ResourcePath.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -45,8 +45,8 @@ private:
 	std::vector<std::shared_ptr<CLabel>> lines;
 
 	size_t getIndex();
-	const std::vector<std::string> getFileName();
-	void setSurface(std::string defName, int imgPos);
+	std::vector<AnimationPath> getFileName();
+	void setSurface(const AnimationPath & defName, int imgPos);
 	std::string getSubtitleInternal();
 
 	void init(Etype Type, int Subtype, int Val, ESize imageSize, EFonts font = FONT_SMALL);

+ 1 - 1
client/widgets/CGarrisonInt.cpp

@@ -421,7 +421,7 @@ CGarrisonSlot::CGarrisonSlot(CGarrisonInt * Owner, int x, int y, SlotID IID, EGa
 	pos.x += x;
 	pos.y += y;
 
-	std::string imgName = owner->smallIcons ? "cprsmall" : "TWCRPORT";
+	AnimationPath imgName = AnimationPath::builtin(owner->smallIcons ? "cprsmall" : "TWCRPORT");
 
 	creatureImage = std::make_shared<CAnimImage>(graphics->getAnimation(imgName), 0);
 	creatureImage->disable();

+ 1 - 1
client/widgets/CWindowWithArtifacts.cpp

@@ -271,7 +271,7 @@ void CWindowWithArtifacts::artifactMoved(const ArtifactLocation & srcLoc, const
 			{
 				if(artSetPtr->isActive())
 				{
-					CCS->curh->dragAndDropCursor("artifact", pickedArtInst->artType->getIconIndex());
+					CCS->curh->dragAndDropCursor(AnimationPath::builtin("artifact"), pickedArtInst->artType->getIconIndex());
 					if(srcLoc.isHolder(hero) || !std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroKingdom>>)
 						artSetPtr->markPossibleSlots(pickedArtInst, hero->tempOwner == LOCPLINT->playerID);
 				}

+ 1 - 1
client/widgets/ComboBox.cpp

@@ -155,7 +155,7 @@ void ComboBox::DropDown::setItem(const void * item)
 	GH.windows().popWindows(1);
 }
 
-ComboBox::ComboBox(Point position, const std::string & defName, const std::pair<std::string, std::string> & help, const JsonNode & dropDownDescriptor, EShortcut key, bool playerColoredButton):
+ComboBox::ComboBox(Point position, const AnimationPath & defName, const std::pair<std::string, std::string> & help, const JsonNode & dropDownDescriptor, EShortcut key, bool playerColoredButton):
 	CButton(position, defName, help, 0, key, playerColoredButton)
 {
 	addCallback([&, dropDownDescriptor]()

+ 1 - 1
client/widgets/ComboBox.h

@@ -54,7 +54,7 @@ class ComboBox : public CButton
 	void setItem(const void *);
 
 public:
-	ComboBox(Point position, const std::string & defName, const std::pair<std::string, std::string> & help, const JsonNode & dropDownDescriptor, EShortcut key = {}, bool playerColoredButton = false);
+	ComboBox(Point position, const AnimationPath & defName, const std::pair<std::string, std::string> & help, const JsonNode & dropDownDescriptor, EShortcut key = {}, bool playerColoredButton = false);
 	
 	//define this callback to fill input vector with data for the combo box
 	std::function<void(std::vector<const void *> &)> onConstructItems;

+ 1 - 1
client/widgets/CreatureCostBox.cpp

@@ -38,7 +38,7 @@ void CreatureCostBox::createItems(TResources res)
 	TResources::nziterator iter(res);
 	while(iter.valid())
 	{
-		ImagePtr image = std::make_shared<CAnimImage>("RESOURCE", iter->resType);
+		ImagePtr image = std::make_shared<CAnimImage>(AnimationPath::builtin("RESOURCE"), iter->resType);
 		LabelPtr text = std::make_shared<CLabel>(15, 43, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, "0");
 
 		resources.insert(std::make_pair(iter->resType, std::make_pair(text, image)));

+ 8 - 8
client/widgets/Images.cpp

@@ -42,15 +42,15 @@ CPicture::CPicture(std::shared_ptr<IImage> image, const Point & position)
 	pos.h = bg->height();
 }
 
-CPicture::CPicture( const std::string &bmpname, int x, int y )
+CPicture::CPicture( const ImagePath &bmpname, int x, int y )
 	: CPicture(bmpname, Point(x,y))
 {}
 
-CPicture::CPicture( const std::string &bmpname )
+CPicture::CPicture( const ImagePath & bmpname )
 	: CPicture(bmpname, Point(0,0))
 {}
 
-CPicture::CPicture( const std::string &bmpname, const Point & position )
+CPicture::CPicture( const ImagePath & bmpname, const Point & position )
 	: bg(IImage::createFromFile(bmpname))
 	, visible(true)
 	, needRefresh(false)
@@ -113,7 +113,7 @@ void CPicture::colorize(PlayerColor player)
 	bg->playerColored(player);
 }
 
-CFilledTexture::CFilledTexture(std::string imageName, Rect position):
+CFilledTexture::CFilledTexture(const ImagePath & imageName, Rect position):
     CIntObject(0, position.topLeft()),
 	texture(IImage::createFromFile(imageName))
 {
@@ -142,7 +142,7 @@ void CFilledTexture::showAll(Canvas & to)
 	}
 }
 
-FilledTexturePlayerColored::FilledTexturePlayerColored(std::string imageName, Rect position)
+FilledTexturePlayerColored::FilledTexturePlayerColored(const ImagePath & imageName, Rect position)
 	: CFilledTexture(imageName, position)
 {
 }
@@ -171,7 +171,7 @@ void FilledTexturePlayerColored::playerColored(PlayerColor player)
 	texture->adjustPalette(filters[player.getNum()], 0);
 }
 
-CAnimImage::CAnimImage(const std::string & name, size_t Frame, size_t Group, int x, int y, ui8 Flags):
+CAnimImage::CAnimImage(const AnimationPath & name, size_t Frame, size_t Group, int x, int y, ui8 Flags):
 	frame(Frame),
 	group(Group),
 	flags(Flags)
@@ -307,7 +307,7 @@ bool CAnimImage::isPlayerColored() const
 	return player.has_value();
 }
 
-CShowableAnim::CShowableAnim(int x, int y, std::string name, ui8 Flags, ui32 frameTime, size_t Group, uint8_t alpha):
+CShowableAnim::CShowableAnim(int x, int y, const AnimationPath & name, ui8 Flags, ui32 frameTime, size_t Group, uint8_t alpha):
 	anim(std::make_shared<CAnimation>(name)),
 	group(Group),
 	frame(0),
@@ -448,7 +448,7 @@ void CShowableAnim::setDuration(int durationMs)
 	frameTimeTotal = durationMs/(last - first);
 }
 
-CCreatureAnim::CCreatureAnim(int x, int y, std::string name, ui8 flags, ECreatureAnimType type):
+CCreatureAnim::CCreatureAnim(int x, int y, const AnimationPath & name, ui8 flags, ECreatureAnimType type):
 	CShowableAnim(x, y, name, flags, 100, size_t(type)) // H3 uses 100 ms per frame, irregardless of battle speed settings
 {
 	xOffset = 0;

+ 9 - 8
client/widgets/Images.h

@@ -11,6 +11,7 @@
 
 #include "../gui/CIntObject.h"
 #include "../battle/BattleConstants.h"
+#include "../../lib/filesystem/ResourcePath.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 class Rect;
@@ -49,9 +50,9 @@ public:
 	CPicture(std::shared_ptr<IImage> image, const Rect &SrcRext, int x = 0, int y = 0); //wrap subrect of given surface
 
 	/// Loads image from specified file name
-	CPicture(const std::string & bmpname);
-	CPicture(const std::string & bmpname, const Point & position);
-	CPicture(const std::string & bmpname, int x, int y);
+	CPicture(const ImagePath & bmpname);
+	CPicture(const ImagePath & bmpname, const Point & position);
+	CPicture(const ImagePath & bmpname, int x, int y);
 
 	/// set alpha value for whole surface. Note: may be messed up if surface is shared
 	/// 0=transparent, 255=opaque
@@ -71,7 +72,7 @@ protected:
 	Rect imageArea;
 
 public:
-	CFilledTexture(std::string imageName, Rect position);
+	CFilledTexture(const ImagePath & imageName, Rect position);
 	CFilledTexture(std::shared_ptr<IImage> image, Rect position, Rect imageArea);
 
 	void showAll(Canvas & to) override;
@@ -80,7 +81,7 @@ public:
 class FilledTexturePlayerColored : public CFilledTexture
 {
 public:
-	FilledTexturePlayerColored(std::string imageName, Rect position);
+	FilledTexturePlayerColored(const ImagePath & imageName, Rect position);
 
 	void playerColored(PlayerColor player);
 };
@@ -105,7 +106,7 @@ private:
 public:
 	bool visible;
 
-	CAnimImage(const std::string & name, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
+	CAnimImage(const AnimationPath & name, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
 	CAnimImage(std::shared_ptr<CAnimation> Anim, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
 	CAnimImage(std::shared_ptr<CAnimation> Anim, size_t Frame, Rect targetPos, size_t Group=0, ui8 Flags=0);
 	~CAnimImage();
@@ -166,7 +167,7 @@ public:
 	//Set per-surface alpha, 0 = transparent, 255 = opaque
 	void setAlpha(ui32 alphaValue);
 
-	CShowableAnim(int x, int y, std::string name, ui8 flags, ui32 frameTime, size_t Group=0, uint8_t alpha = UINT8_MAX);
+	CShowableAnim(int x, int y, const AnimationPath & name, ui8 flags, ui32 frameTime, size_t Group=0, uint8_t alpha = UINT8_MAX);
 	~CShowableAnim();
 
 	//set animation to group or part of group
@@ -213,6 +214,6 @@ public:
 	//clear queue and set animation to this sequence
 	void clearAndSet(ECreatureAnimType type);
 
-	CCreatureAnim(int x, int y, std::string name, ui8 flags = 0, ECreatureAnimType = ECreatureAnimType::HOLDING);
+	CCreatureAnim(int x, int y, const AnimationPath & name, ui8 flags = 0, ECreatureAnimType = ECreatureAnimType::HOLDING);
 
 };

+ 24 - 24
client/widgets/MiscWidgets.cpp

@@ -126,7 +126,7 @@ CHeroArea::CHeroArea(int x, int y, const CGHeroInstance * _hero)
 	pos.h = 64;
 
 	if(hero)
-		portrait = std::make_shared<CAnimImage>("PortraitsLarge", hero->portrait);
+		portrait = std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsLarge"), hero->portrait);
 }
 
 void CHeroArea::clickPressed(const Point & cursorPosition)
@@ -201,7 +201,7 @@ CMinorResDataBar::CMinorResDataBar()
 	pos.x = 7;
 	pos.y = 575;
 
-	background = std::make_shared<CPicture>("KRESBAR.bmp");
+	background = std::make_shared<CPicture>(ImagePath::builtin("KRESBAR.bmp"));
 	background->colorize(LOCPLINT->playerID);
 
 	pos.w = background->pos.w;
@@ -233,7 +233,7 @@ void CArmyTooltip::init(const InfoAboutArmy &army)
 			continue;
 		}
 
-		icons.push_back(std::make_shared<CAnimImage>("CPRSMALL", slot.second.type->getIconIndex(), 0, slotsPos[slot.first.getNum()].x, slotsPos[slot.first.getNum()].y));
+		icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("CPRSMALL"), slot.second.type->getIconIndex(), 0, slotsPos[slot.first.getNum()].x, slotsPos[slot.first.getNum()].y));
 
 		std::string subtitle;
 		if(army.army.isDetailed)
@@ -276,7 +276,7 @@ CArmyTooltip::CArmyTooltip(Point pos, const CArmedInstance * army):
 void CHeroTooltip::init(const InfoAboutHero & hero)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-	portrait = std::make_shared<CAnimImage>("PortraitsLarge", hero.portrait, 0, 3, 2);
+	portrait = std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsLarge"), hero.portrait, 0, 3, 2);
 
 	if(hero.details)
 	{
@@ -286,8 +286,8 @@ void CHeroTooltip::init(const InfoAboutHero & hero)
 
 		labels.push_back(std::make_shared<CLabel>(158, 98, FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, std::to_string(hero.details->mana)));
 
-		morale = std::make_shared<CAnimImage>("IMRL22", hero.details->morale + 3, 0, 5, 74);
-		luck = std::make_shared<CAnimImage>("ILCK22", hero.details->luck + 3, 0, 5, 91);
+		morale = std::make_shared<CAnimImage>(AnimationPath::builtin("IMRL22"), hero.details->morale + 3, 0, 5, 74);
+		luck = std::make_shared<CAnimImage>(AnimationPath::builtin("ILCK22"), hero.details->luck + 3, 0, 5, 91);
 	}
 }
 
@@ -314,7 +314,7 @@ CInteractableHeroTooltip::CInteractableHeroTooltip(Point pos, const CGHeroInstan
 void CInteractableHeroTooltip::init(const InfoAboutHero & hero)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-	portrait = std::make_shared<CAnimImage>("PortraitsLarge", hero.portrait, 0, 3, 2);
+	portrait = std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsLarge"), hero.portrait, 0, 3, 2);
 	title = std::make_shared<CLabel>(66, 2, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, hero.name);
 
 	if(hero.details)
@@ -325,8 +325,8 @@ void CInteractableHeroTooltip::init(const InfoAboutHero & hero)
 
 		labels.push_back(std::make_shared<CLabel>(158, 98, FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, std::to_string(hero.details->mana)));
 
-		morale = std::make_shared<CAnimImage>("IMRL22", hero.details->morale + 3, 0, 5, 74);
-		luck = std::make_shared<CAnimImage>("ILCK22", hero.details->luck + 3, 0, 5, 91);
+		morale = std::make_shared<CAnimImage>(AnimationPath::builtin("IMRL22"), hero.details->morale + 3, 0, 5, 74);
+		luck = std::make_shared<CAnimImage>(AnimationPath::builtin("ILCK22"), hero.details->luck + 3, 0, 5, 91);
 	}
 }
 
@@ -337,17 +337,17 @@ void CTownTooltip::init(const InfoAboutTown & town)
 	//order of icons in def: fort, citadel, castle, no fort
 	size_t fortIndex = town.fortLevel ? town.fortLevel - 1 : 3;
 
-	fort = std::make_shared<CAnimImage>("ITMCLS", fortIndex, 0, 105, 31);
+	fort = std::make_shared<CAnimImage>(AnimationPath::builtin("ITMCLS"), fortIndex, 0, 105, 31);
 
 	assert(town.tType);
 
 	size_t iconIndex = town.tType->clientInfo.icons[town.fortLevel > 0][town.built >= CGI->settings()->getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
 
-	build = std::make_shared<CAnimImage>("itpt", iconIndex, 0, 3, 2);
+	build = std::make_shared<CAnimImage>(AnimationPath::builtin("itpt"), iconIndex, 0, 3, 2);
 
 	if(town.details)
 	{
-		hall = std::make_shared<CAnimImage>("ITMTLS", town.details->hallLevel, 0, 67, 31);
+		hall = std::make_shared<CAnimImage>(AnimationPath::builtin("ITMTLS"), town.details->hallLevel, 0, 67, 31);
 
 		if(town.details->goldIncome)
 		{
@@ -355,18 +355,18 @@ void CTownTooltip::init(const InfoAboutTown & town)
 					   std::to_string(town.details->goldIncome));
 		}
 		if(town.details->garrisonedHero) //garrisoned hero icon
-			garrisonedHero = std::make_shared<CPicture>("TOWNQKGH", 149, 76);
+			garrisonedHero = std::make_shared<CPicture>(ImagePath::builtin("TOWNQKGH"), 149, 76);
 
 		if(town.details->customRes)//silo is built
 		{
 			if(town.tType->primaryRes == EGameResID::WOOD_AND_ORE )// wood & ore
 			{
-				res1 = std::make_shared<CAnimImage>("SMALRES", GameResID(EGameResID::WOOD), 0, 7, 75);
-				res2 = std::make_shared<CAnimImage>("SMALRES", GameResID(EGameResID::ORE), 0, 7, 88);
+				res1 = std::make_shared<CAnimImage>(AnimationPath::builtin("SMALRES"), GameResID(EGameResID::WOOD), 0, 7, 75);
+				res2 = std::make_shared<CAnimImage>(AnimationPath::builtin("SMALRES"), GameResID(EGameResID::ORE), 0, 7, 88);
 			}
 			else
 			{
-				res1 = std::make_shared<CAnimImage>("SMALRES", town.tType->primaryRes, 0, 7, 81);
+				res1 = std::make_shared<CAnimImage>(AnimationPath::builtin("SMALRES"), town.tType->primaryRes, 0, 7, 81);
 			}
 		}
 	}
@@ -399,18 +399,18 @@ void CInteractableTownTooltip::init(const InfoAboutTown & town)
 	//order of icons in def: fort, citadel, castle, no fort
 	size_t fortIndex = town.fortLevel ? town.fortLevel - 1 : 3;
 
-	fort = std::make_shared<CAnimImage>("ITMCLS", fortIndex, 0, 105, 31);
+	fort = std::make_shared<CAnimImage>(AnimationPath::builtin("ITMCLS"), fortIndex, 0, 105, 31);
 
 	assert(town.tType);
 
 	size_t iconIndex = town.tType->clientInfo.icons[town.fortLevel > 0][town.built >= CGI->settings()->getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
 
-	build = std::make_shared<CAnimImage>("itpt", iconIndex, 0, 3, 2);
+	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, town.name);
 
 	if(town.details)
 	{
-		hall = std::make_shared<CAnimImage>("ITMTLS", town.details->hallLevel, 0, 67, 31);
+		hall = std::make_shared<CAnimImage>(AnimationPath::builtin("ITMTLS"), town.details->hallLevel, 0, 67, 31);
 
 		if(town.details->goldIncome)
 		{
@@ -418,18 +418,18 @@ void CInteractableTownTooltip::init(const InfoAboutTown & town)
 											  std::to_string(town.details->goldIncome));
 		}
 		if(town.details->garrisonedHero) //garrisoned hero icon
-			garrisonedHero = std::make_shared<CPicture>("TOWNQKGH", 149, 76);
+			garrisonedHero = std::make_shared<CPicture>(ImagePath::builtin("TOWNQKGH"), 149, 76);
 
 		if(town.details->customRes)//silo is built
 		{
 			if(town.tType->primaryRes == EGameResID::WOOD_AND_ORE )// wood & ore
 			{
-				res1 = std::make_shared<CAnimImage>("SMALRES", GameResID(EGameResID::WOOD), 0, 7, 75);
-				res2 = std::make_shared<CAnimImage>("SMALRES", GameResID(EGameResID::ORE), 0, 7, 88);
+				res1 = std::make_shared<CAnimImage>(AnimationPath::builtin("SMALRES"), GameResID(EGameResID::WOOD), 0, 7, 75);
+				res2 = std::make_shared<CAnimImage>(AnimationPath::builtin("SMALRES"), GameResID(EGameResID::ORE), 0, 7, 88);
 			}
 			else
 			{
-				res1 = std::make_shared<CAnimImage>("SMALRES", town.tType->primaryRes, 0, 7, 81);
+				res1 = std::make_shared<CAnimImage>(AnimationPath::builtin("SMALRES"), town.tType->primaryRes, 0, 7, 81);
 			}
 		}
 	}
@@ -492,7 +492,7 @@ void MoraleLuckBox::set(const AFactionMember * node)
 	else
 		imageName = morale ? "IMRL42" : "ILCK42";
 
-	image = std::make_shared<CAnimImage>(imageName, bonusValue + 3);
+	image = std::make_shared<CAnimImage>(AnimationPath::builtin(imageName), bonusValue + 3);
 	image->moveBy(Point(pos.w/2 - image->pos.w/2, pos.h/2 - image->pos.h/2));//center icon
 }
 

+ 4 - 4
client/widgets/RadialMenu.cpp

@@ -27,10 +27,10 @@ RadialMenuItem::RadialMenuItem(const std::string & imageName, const std::string
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
 
-	inactiveImage = std::make_shared<CPicture>("radialMenu/itemInactive", Point(0, 0));
-	selectedImage = std::make_shared<CPicture>("radialMenu/itemEmpty", Point(0, 0));
+	inactiveImage = std::make_shared<CPicture>(ImagePath::builtin("radialMenu/itemInactive"), Point(0, 0));
+	selectedImage = std::make_shared<CPicture>(ImagePath::builtin("radialMenu/itemEmpty"), Point(0, 0));
 
-	iconImage = std::make_shared<CPicture>("radialMenu/" + imageName, Point(0, 0));
+	iconImage = std::make_shared<CPicture>(ImagePath::builtin("radialMenu/" + imageName), Point(0, 0));
 
 	pos = selectedImage->pos;
 	selectedImage->setEnabled(false);
@@ -56,7 +56,7 @@ RadialMenu::RadialMenu(const Point & positionToCenter, const std::vector<RadialM
 	for (auto const & item : menuConfig)
 		addItem(item.itemPosition, item.enabled, item.imageName, item.hoverText, item.callback);
 
-	statusBar = CGStatusBar::create(-80, -100, "radialMenu/statusBar");
+	statusBar = CGStatusBar::create(-80, -100, ImagePath::builtin("radialMenu/statusBar"));
 
 	for(const auto & item : items)
 		pos = pos.include(item->pos);

+ 4 - 4
client/widgets/Slider.cpp

@@ -178,7 +178,7 @@ CSlider::CSlider(Point position, int totalw, std::function<void(int)> Moved, int
 
 	if(style == BROWN)
 	{
-		std::string name = getOrientation() == Orientation::HORIZONTAL ? "IGPCRDIV.DEF" : "OVBUTN2.DEF";
+		AnimationPath name = AnimationPath::builtin(getOrientation() == Orientation::HORIZONTAL ? "IGPCRDIV.DEF" : "OVBUTN2.DEF");
 		//NOTE: this images do not have "blocked" frames. They should be implemented somehow (e.g. palette transform or something...)
 
 		left = std::make_shared<CButton>(Point(), name, CButton::tooltip());
@@ -191,9 +191,9 @@ CSlider::CSlider(Point position, int totalw, std::function<void(int)> Moved, int
 	}
 	else
 	{
-		left = std::make_shared<CButton>(Point(), getOrientation() == Orientation::HORIZONTAL ? "SCNRBLF.DEF" : "SCNRBUP.DEF", CButton::tooltip());
-		right = std::make_shared<CButton>(Point(), getOrientation() == Orientation::HORIZONTAL ? "SCNRBRT.DEF" : "SCNRBDN.DEF", CButton::tooltip());
-		slider = std::make_shared<CButton>(Point(), "SCNRBSL.DEF", CButton::tooltip());
+		left = std::make_shared<CButton>(Point(), AnimationPath::builtin(getOrientation() == Orientation::HORIZONTAL ? "SCNRBLF.DEF" : "SCNRBUP.DEF"), CButton::tooltip());
+		right = std::make_shared<CButton>(Point(), AnimationPath::builtin(getOrientation() == Orientation::HORIZONTAL ? "SCNRBRT.DEF" : "SCNRBDN.DEF"), CButton::tooltip());
+		slider = std::make_shared<CButton>(Point(), AnimationPath::builtin("SCNRBSL.DEF"), CButton::tooltip());
 	}
 	slider->actOnDown = true;
 	slider->soundDisabled = true;

+ 2 - 2
client/widgets/TextControls.cpp

@@ -419,7 +419,7 @@ CGStatusBar::CGStatusBar(std::shared_ptr<CIntObject> background_, EFonts Font, E
 	autoRedraw = false;
 }
 
-CGStatusBar::CGStatusBar(int x, int y, std::string name, int maxw)
+CGStatusBar::CGStatusBar(int x, int y, const ImagePath & name, int maxw)
 	: CLabel(x, y, FONT_SMALL, ETextAlignment::CENTER)
 	, enteringText(false)
 {
@@ -503,7 +503,7 @@ CTextInput::CTextInput(const Rect & Pos, EFonts font, const CFunctionList<void(c
 #endif
 }
 
-CTextInput::CTextInput(const Rect & Pos, const Point & bgOffset, const std::string & bgName, const CFunctionList<void(const std::string &)> & CB)
+CTextInput::CTextInput(const Rect & Pos, const Point & bgOffset, const ImagePath & bgName, const CFunctionList<void(const std::string &)> & CB)
 	:cb(CB), 	CFocusable(std::make_shared<CKeyboardFocusListener>(this))
 {
 	pos += Pos.topLeft();

+ 3 - 2
client/widgets/TextControls.h

@@ -14,6 +14,7 @@
 #include "../render/Colors.h"
 #include "../render/EFont.h"
 #include "../../lib/FunctionList.h"
+#include "../../lib/filesystem/ResourcePath.h"
 
 class IImage;
 class CSlider;
@@ -124,7 +125,7 @@ class CGStatusBar : public CLabel, public std::enable_shared_from_this<CGStatusB
 	bool enteringText;
 
 	CGStatusBar(std::shared_ptr<CIntObject> background_, EFonts Font = FONT_SMALL, ETextAlignment Align = ETextAlignment::CENTER, const ColorRGBA & Color = Colors::WHITE);
-	CGStatusBar(int x, int y, std::string name, int maxw = -1);
+	CGStatusBar(int x, int y, const ImagePath & name, int maxw = -1);
 
 	//make CLabel API private
 	using CLabel::getText;
@@ -223,7 +224,7 @@ public:
 	void setHelpText(const std::string &);
 
 	CTextInput(const Rect & Pos, EFonts font, const CFunctionList<void(const std::string &)> & CB);
-	CTextInput(const Rect & Pos, const Point & bgOffset, const std::string & bgName, const CFunctionList<void(const std::string &)> & CB);
+	CTextInput(const Rect & Pos, const Point & bgOffset, const ImagePath & bgName, const CFunctionList<void(const std::string &)> & CB);
 	CTextInput(const Rect & Pos, std::shared_ptr<IImage> srf);
 
 	void clickPressed(const Point & cursorPosition) override;

+ 39 - 40
client/windows/CCastleInterface.cpp

@@ -263,7 +263,7 @@ bool CBuildingRect::receiveEvent(const Point & position, int eventType) const
 }
 
 CDwellingInfoBox::CDwellingInfoBox(int centerX, int centerY, const CGTownInstance * Town, int level)
-	: CWindowObject(RCLICK_POPUP, "CRTOINFO", Point(centerX, centerY))
+	: CWindowObject(RCLICK_POPUP, ImagePath::builtin("CRTOINFO"), Point(centerX, centerY))
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 	background->colorize(Town->tempOwner);
@@ -282,7 +282,7 @@ CDwellingInfoBox::CDwellingInfoBox(int centerX, int centerY, const CGTownInstanc
 		auto res = static_cast<EGameResID>(i);
 		if(creature->getRecruitCost(res))
 		{
-			resPicture.push_back(std::make_shared<CAnimImage>("RESOURCE", i, 0, 0, 0));
+			resPicture.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("RESOURCE"), i, 0, 0, 0));
 			resAmount.push_back(std::make_shared<CLabel>(0,0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, std::to_string(creature->getRecruitCost(res))));
 		}
 	}
@@ -310,13 +310,13 @@ CHeroGSlot::CHeroGSlot(int x, int y, int updown, const CGHeroInstance * h, HeroS
 	pos.h = 64;
 	upg = updown;
 
-	portrait = std::make_shared<CAnimImage>("PortraitsLarge", 0, 0, 0, 0);
+	portrait = std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsLarge"), 0, 0, 0, 0);
 	portrait->visible = false;
 
-	flag = std::make_shared<CAnimImage>("CREST58", 0, 0, 0, 0);
+	flag = std::make_shared<CAnimImage>(AnimationPath::builtin("CREST58"), 0, 0, 0, 0);
 	flag->visible = false;
 
-	selection = std::make_shared<CAnimImage>("TWCRPORT", 1, 0);
+	selection = std::make_shared<CAnimImage>(AnimationPath::builtin("TWCRPORT"), 1, 0);
 	selection->visible = false;
 
 	set(h);
@@ -981,9 +981,8 @@ void CCastleBuildings::enterTownHall()
 
 void CCastleBuildings::openMagesGuild()
 {
-	std::string mageGuildBackground;
-	mageGuildBackground = LOCPLINT->castleInt->town->town->clientInfo.guildBackground;
-	GH.windows().createAndPushWindow<CMageGuildScreen>(LOCPLINT->castleInt,mageGuildBackground);
+	auto mageGuildBackground = LOCPLINT->castleInt->town->town->clientInfo.guildBackground;
+	GH.windows().createAndPushWindow<CMageGuildScreen>(LOCPLINT->castleInt, mageGuildBackground);
 }
 
 void CCastleBuildings::openTownHall()
@@ -1009,7 +1008,7 @@ CCreaInfo::CCreaInfo(Point position, const CGTownInstance * Town, int Level, boo
 	ui32 creatureID = town->creatures[level].second.back();
 	creature = CGI->creh->objects[creatureID];
 
-	picture = std::make_shared<CAnimImage>("CPRSMALL", creature->getIconIndex(), 0, 8, 0);
+	picture = std::make_shared<CAnimImage>(AnimationPath::builtin("CPRSMALL"), creature->getIconIndex(), 0, 8, 0);
 
 	std::string value;
 	if(showAvailable)
@@ -1109,14 +1108,14 @@ CTownInfo::CTownInfo(int posX, int posY, const CGTownInstance * Town, bool townH
 	if(townHall)
 	{
 		buildID = 10 + town->hallLevel();
-		picture = std::make_shared<CAnimImage>("ITMTL.DEF", town->hallLevel());
+		picture = std::make_shared<CAnimImage>(AnimationPath::builtin("ITMTL.DEF"), town->hallLevel());
 	}
 	else
 	{
 		buildID = 6 + town->fortLevel();
 		if(buildID == 6)
 			return;//FIXME: suspicious statement, fix or comment
-		picture = std::make_shared<CAnimImage>("ITMCL.DEF", town->fortLevel()-1);
+		picture = std::make_shared<CAnimImage>(AnimationPath::builtin("ITMCL.DEF"), town->fortLevel()-1);
 	}
 	building = town->town->buildings.at(BuildingID(buildID));
 	pos = picture->pos;
@@ -1154,7 +1153,7 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, const CGTownInst
 	addUsedEvents(KEYBOARD);
 
 	builds = std::make_shared<CCastleBuildings>(town);
-	panel = std::make_shared<CPicture>("TOWNSCRN", 0, builds->pos.h);
+	panel = std::make_shared<CPicture>(ImagePath::builtin("TOWNSCRN"), 0, builds->pos.h);
 	panel->colorize(LOCPLINT->playerID);
 	pos.w = panel->pos.w;
 	pos.h = builds->pos.h + panel->pos.h;
@@ -1167,12 +1166,12 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, const CGTownInst
 	heroes = std::make_shared<HeroSlots>(town, Point(241, 387), Point(241, 483), garr, true);
 	title = std::make_shared<CLabel>(85, 387, FONT_MEDIUM, ETextAlignment::TOPLEFT, Colors::WHITE, town->getNameTranslated());
 	income = std::make_shared<CLabel>(195, 443, FONT_SMALL, ETextAlignment::CENTER);
-	icon = std::make_shared<CAnimImage>("ITPT", 0, 0, 15, 387);
+	icon = std::make_shared<CAnimImage>(AnimationPath::builtin("ITPT"), 0, 0, 15, 387);
 
-	exit = std::make_shared<CButton>(Point(744, 544), "TSBTNS", CButton::tooltip(CGI->generaltexth->tcommands[8]), [&](){close();}, EShortcut::GLOBAL_RETURN);
+	exit = std::make_shared<CButton>(Point(744, 544), AnimationPath::builtin("TSBTNS"), CButton::tooltip(CGI->generaltexth->tcommands[8]), [&](){close();}, EShortcut::GLOBAL_RETURN);
 	exit->setImageOrder(4, 5, 6, 7);
 
-	auto split = std::make_shared<CButton>(Point(744, 382), "TSBTNS", CButton::tooltip(CGI->generaltexth->tcommands[3]), [&]()
+	auto split = std::make_shared<CButton>(Point(744, 382), AnimationPath::builtin("TSBTNS"), CButton::tooltip(CGI->generaltexth->tcommands[3]), [&]()
 	{
 		garr->splitClick();
 		heroes->splitClicked();
@@ -1182,11 +1181,11 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, const CGTownInst
 	Rect barRect(9, 182, 732, 18);
 	auto statusbarBackground = std::make_shared<CPicture>(panel->getSurface(), barRect, 9, 555);
 	statusbar = CGStatusBar::create(statusbarBackground);
-	resdatabar = std::make_shared<CResDataBar>("ARESBAR", 3, 575, 37, 3, 84, 78);
+	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->setScrollUpButton( std::make_shared<CButton>( Point(744, 414), "IAM014", CButton::tooltipLocalized("core.help.306")));
-	townlist->setScrollDownButton( std::make_shared<CButton>( Point(744, 526), "IAM015", CButton::tooltipLocalized("core.help.307")));
+	townlist->setScrollUpButton( std::make_shared<CButton>( Point(744, 414), AnimationPath::builtin("IAM014"), CButton::tooltipLocalized("core.help.306")));
+	townlist->setScrollDownButton( std::make_shared<CButton>( Point(744, 526), AnimationPath::builtin("IAM015"), CButton::tooltipLocalized("core.help.307")));
 
 	if(from)
 		townlist->select(from);
@@ -1277,7 +1276,7 @@ void CCastleInterface::recreateIcons()
 	hall = std::make_shared<CTownInfo>(80, 413, town, true);
 	fort = std::make_shared<CTownInfo>(122, 413, town, false);
 
-	fastArmyPurchase = std::make_shared<CButton>(Point(122, 413), "itmcl.def", CButton::tooltip(), [&](){ builds->enterToTheQuickRecruitmentWindow(); });
+	fastArmyPurchase = std::make_shared<CButton>(Point(122, 413), AnimationPath::builtin("itmcl.def"), CButton::tooltip(), [&](){ builds->enterToTheQuickRecruitmentWindow(); });
 	fastArmyPurchase->setImageOrder(town->fortLevel() - 1, town->fortLevel() - 1, town->fortLevel() - 1, town->fortLevel() - 1);
 	fastArmyPurchase->setAnimateLonelyFrame(true);
 
@@ -1351,9 +1350,9 @@ CHallInterface::CBuildingBox::CBuildingBox(int x, int y, const CGTownInstance *
 	};
 
 	icon = std::make_shared<CAnimImage>(town->town->clientInfo.buildingsIcons, building->bid, 0, 2, 2);
-	header = std::make_shared<CAnimImage>("TPTHBAR", panelIndex[static_cast<int>(state)], 0, 1, 73);
+	header = std::make_shared<CAnimImage>(AnimationPath::builtin("TPTHBAR"), panelIndex[static_cast<int>(state)], 0, 1, 73);
 	if(iconIndex[static_cast<int>(state)] >=0)
-		mark = std::make_shared<CAnimImage>("TPTHCHK", iconIndex[static_cast<int>(state)], 0, 136, 56);
+		mark = std::make_shared<CAnimImage>(AnimationPath::builtin("TPTHCHK"), iconIndex[static_cast<int>(state)], 0, 136, 56);
 	name = std::make_shared<CLabel>(75, 81, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, building->getNameTranslated());
 
 	//todo: add support for all possible states
@@ -1405,7 +1404,7 @@ CHallInterface::CHallInterface(const CGTownInstance * Town):
 	statusbar = CGStatusBar::create(statusbarBackground);
 
 	title = std::make_shared<CLabel>(399, 12, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, town->town->buildings.at(BuildingID(town->hallLevel()+BuildingID::VILLAGE_HALL))->getNameTranslated());
-	exit = std::make_shared<CButton>(Point(748, 556), "TPMAGE1.DEF", CButton::tooltip(CGI->generaltexth->hcommands[8]), [&](){close();}, EShortcut::GLOBAL_RETURN);
+	exit = std::make_shared<CButton>(Point(748, 556), AnimationPath::builtin("TPMAGE1.DEF"), CButton::tooltip(CGI->generaltexth->hcommands[8]), [&](){close();}, EShortcut::GLOBAL_RETURN);
 
 	auto & boxList = town->town->clientInfo.hallSlots;
 	boxes.resize(boxList.size());
@@ -1440,7 +1439,7 @@ CHallInterface::CHallInterface(const CGTownInstance * Town):
 }
 
 CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Building, EBuildingState state, bool rightClick):
-	CStatusbarWindow(PLAYER_COLORED | (rightClick ? RCLICK_POPUP : 0), "TPUBUILD"),
+	CStatusbarWindow(PLAYER_COLORED | (rightClick ? RCLICK_POPUP : 0), ImagePath::builtin("TPUBUILD")),
 	town(Town),
 	building(Building)
 {
@@ -1480,11 +1479,11 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin
 		tooltipNo.appendTextID("core.genrltxt.596");
 		tooltipNo.replaceTextID(building->getNameTextID());
 
-		buy = std::make_shared<CButton>(Point(45, 446), "IBUY30", CButton::tooltip(tooltipYes.toString()), [&](){ buyFunc(); }, EShortcut::GLOBAL_ACCEPT);
+		buy = 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);
 
-		cancel = std::make_shared<CButton>(Point(290, 445), "ICANCEL", CButton::tooltip(tooltipNo.toString()), [&](){ close();}, EShortcut::GLOBAL_CANCEL);
+		cancel = std::make_shared<CButton>(Point(290, 445), AnimationPath::builtin("ICANCEL"), CButton::tooltip(tooltipNo.toString()), [&](){ close();}, EShortcut::GLOBAL_CANCEL);
 		cancel->setBorderColor(Colors::METALLIC_GOLD);
 	}
 }
@@ -1589,7 +1588,7 @@ CFortScreen::CFortScreen(const CGTownInstance * town):
 	title = std::make_shared<CLabel>(400, 12, FONT_BIG, ETextAlignment::CENTER, Colors::WHITE, fortBuilding->getNameTranslated());
 
 	std::string text = boost::str(boost::format(CGI->generaltexth->fcommands[6]) % fortBuilding->getNameTranslated());
-	exit = std::make_shared<CButton>(Point(748, 556), "TPMAGE1", CButton::tooltip(text), [&](){ close(); }, EShortcut::GLOBAL_RETURN);
+	exit = std::make_shared<CButton>(Point(748, 556), AnimationPath::builtin("TPMAGE1"), CButton::tooltip(text), [&](){ close(); }, EShortcut::GLOBAL_RETURN);
 
 	std::vector<Point> positions =
 	{
@@ -1637,16 +1636,16 @@ CFortScreen::CFortScreen(const CGTownInstance * town):
 	statusbar = CGStatusBar::create(statusbarBackground);
 }
 
-std::string CFortScreen::getBgName(const CGTownInstance * town)
+ImagePath CFortScreen::getBgName(const CGTownInstance * town)
 {
 	ui32 fortSize = static_cast<ui32>(town->creatures.size());
 	if(fortSize > GameConstants::CREATURES_PER_TOWN && town->creatures.back().second.empty())
 		fortSize--;
 
 	if(fortSize == GameConstants::CREATURES_PER_TOWN)
-		return "TPCASTL7";
+		return ImagePath::builtin("TPCASTL7");
 	else
-		return "TPCASTL8";
+		return ImagePath::builtin("TPCASTL8");
 }
 
 void CFortScreen::creaturesChangedEventHandler()
@@ -1673,7 +1672,7 @@ CFortScreen::RecruitArea::RecruitArea(int posX, int posY, const CGTownInstance *
 
 	addUsedEvents(SHOW_POPUP);
 
-	icons = std::make_shared<CPicture>("TPCAINFO", 261, 3);
+	icons = std::make_shared<CPicture>(ImagePath::builtin("TPCAINFO"), 261, 3);
 
 	if(getMyBuilding() != nullptr)
 	{
@@ -1766,8 +1765,8 @@ void CFortScreen::RecruitArea::showPopupWindow(const Point & cursorPosition)
 		GH.windows().createAndPushWindow<CStackWindow>(getMyCreature(), true);
 }
 
-CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner,std::string imagem)
-	: CStatusbarWindow(BORDERED, imagem)
+CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner, const ImagePath & imagename)
+	: CStatusbarWindow(BORDERED, imagename)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 
@@ -1781,7 +1780,7 @@ CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner,std::string imagem)
 	auto statusbarBackground = std::make_shared<CPicture>(background->getSurface(), barRect, 7, 556);
 	statusbar = CGStatusBar::create(statusbarBackground);
 
-	exit = std::make_shared<CButton>(Point(748, 556), "TPMAGE1.DEF", CButton::tooltip(CGI->generaltexth->allTexts[593]), [&](){ close(); }, EShortcut::GLOBAL_RETURN);
+	exit = std::make_shared<CButton>(Point(748, 556), AnimationPath::builtin("TPMAGE1.DEF"), CButton::tooltip(CGI->generaltexth->allTexts[593]), [&](){ close(); }, EShortcut::GLOBAL_RETURN);
 
 	static const std::vector<std::vector<Point> > positions =
 	{
@@ -1800,7 +1799,7 @@ CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner,std::string imagem)
 			if(i<owner->town->mageGuildLevel() && owner->town->spells[i].size()>j)
 				spells.push_back(std::make_shared<Scroll>(positions[i][j], CGI->spellh->objects[owner->town->spells[i][j]]));
 			else
-				emptyScrolls.push_back(std::make_shared<CAnimImage>("TPMAGES.DEF", 1, 0, positions[i][j].x, positions[i][j].y));
+				emptyScrolls.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("TPMAGES.DEF"), 1, 0, positions[i][j].x, positions[i][j].y));
 		}
 	}
 }
@@ -1812,7 +1811,7 @@ CMageGuildScreen::Scroll::Scroll(Point position, const CSpell *Spell)
 
 	addUsedEvents(LCLICK | SHOW_POPUP | HOVER);
 	pos += position;
-	image = std::make_shared<CAnimImage>("SPELLSCR", spell->id);
+	image = std::make_shared<CAnimImage>(AnimationPath::builtin("SPELLSCR"), spell->id);
 	pos = image->pos;
 }
 
@@ -1836,7 +1835,7 @@ void CMageGuildScreen::Scroll::hover(bool on)
 }
 
 CBlacksmithDialog::CBlacksmithDialog(bool possible, CreatureID creMachineID, ArtifactID aid, ObjectInstanceID hid):
-	CStatusbarWindow(PLAYER_COLORED, "TPSMITH")
+	CStatusbarWindow(PLAYER_COLORED, ImagePath::builtin("TPSMITH"))
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 
@@ -1845,7 +1844,7 @@ CBlacksmithDialog::CBlacksmithDialog(bool possible, CreatureID creMachineID, Art
 	auto statusbarBackground = std::make_shared<CPicture>(background->getSurface(), barRect, 8, pos.h - 26);
 	statusbar = CGStatusBar::create(statusbarBackground);
 
-	animBG = std::make_shared<CPicture>("TPSMITBK", 64, 50);
+	animBG = std::make_shared<CPicture>(ImagePath::builtin("TPSMITBK"), 64, 50);
 	animBG->needRefresh = true;
 
 	const CCreature * creature = CGI->creh->objects[creMachineID];
@@ -1869,13 +1868,13 @@ CBlacksmithDialog::CBlacksmithDialog(bool possible, CreatureID creMachineID, Art
 	title = std::make_shared<CLabel>(165, 28, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW, titleString.toString());
 	costText = std::make_shared<CLabel>(165, 218, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->jktexts[43]);
 	costValue = std::make_shared<CLabel>(165, 292, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, costString);
-	buy = std::make_shared<CButton>(Point(42, 312), "IBUY30.DEF", CButton::tooltip(buyText.toString()), [&](){ close(); }, EShortcut::GLOBAL_ACCEPT);
-	cancel = std::make_shared<CButton>(Point(224, 312), "ICANCEL.DEF", CButton::tooltip(cancelText.toString()), [&](){ close(); }, EShortcut::GLOBAL_CANCEL);
+	buy = std::make_shared<CButton>(Point(42, 312), AnimationPath::builtin("IBUY30.DEF"), CButton::tooltip(buyText.toString()), [&](){ close(); }, EShortcut::GLOBAL_ACCEPT);
+	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); });
 	else
 		buy->block(true);
 
-	costIcon = std::make_shared<CAnimImage>("RESOURCE", GameResID(EGameResID::GOLD), 0, 148, 244);
+	costIcon = std::make_shared<CAnimImage>(AnimationPath::builtin("RESOURCE"), GameResID(EGameResID::GOLD), 0, 148, 244);
 }

+ 2 - 2
client/windows/CCastleInterface.h

@@ -355,7 +355,7 @@ class CFortScreen : public CStatusbarWindow
 	std::shared_ptr<CMinorResDataBar> resdatabar;
 	std::shared_ptr<CButton> exit;
 
-	std::string getBgName(const CGTownInstance * town);
+	ImagePath getBgName(const CGTownInstance * town);
 
 public:
 	CFortScreen(const CGTownInstance * town);
@@ -385,7 +385,7 @@ class CMageGuildScreen : public CStatusbarWindow
 	std::shared_ptr<CMinorResDataBar> resdatabar;
 
 public:
-	CMageGuildScreen(CCastleInterface * owner,std::string image);
+	CMageGuildScreen(CCastleInterface * owner, const ImagePath & image);
 };
 
 /// The blacksmith window where you can buy available in town war machine

+ 30 - 30
client/windows/CCreatureWindow.cpp

@@ -118,7 +118,7 @@ void CCommanderSkillIcon::clickPressed(const Point & cursorPosition)
 	callback();
 }
 
-static std::string skillToFile(int skill, int level, bool selected)
+static ImagePath skillToFile(int skill, int level, bool selected)
 {
 	// FIXME: is this a correct hadling?
 	// level 0 = skill not present, use image with "no" suffix
@@ -156,24 +156,24 @@ static std::string skillToFile(int skill, int level, bool selected)
 	if (selected)
 		sufix += "="; //level-up highlight
 
-	return file + sufix + ".bmp";
+	return ImagePath::builtin(file + sufix + ".bmp");
 }
 
-CStackWindow::CWindowSection::CWindowSection(CStackWindow * parent, std::string backgroundPath, int yOffset)
+CStackWindow::CWindowSection::CWindowSection(CStackWindow * parent, const ImagePath & backgroundPath, int yOffset)
 	: parent(parent)
 {
 	pos.y += yOffset;
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 	if(!backgroundPath.empty())
 	{
-		background = std::make_shared<CPicture>("stackWindow/" + backgroundPath);
+		background = std::make_shared<CPicture>(backgroundPath);
 		pos.w = background->pos.w;
 		pos.h = background->pos.h;
 	}
 }
 
 CStackWindow::ActiveSpellsSection::ActiveSpellsSection(CStackWindow * owner, int yOffset)
-	: CWindowSection(owner, "spell-effects", yOffset)
+	: CWindowSection(owner, ImagePath::builtin("stackWindow/spell-effects"), yOffset)
 {
 	static const Point firstPos(6, 2); // position of 1st spell box
 	static const Point offset(54, 0);  // offset of each spell box from previous
@@ -205,7 +205,7 @@ CStackWindow::ActiveSpellsSection::ActiveSpellsSection(CStackWindow * owner, int
 			int duration = battleStack->getBonusLocalFirst(Selector::source(BonusSource::SPELL_EFFECT,effect))->turnsRemain;
 			boost::replace_first(spellText, "%d", std::to_string(duration));
 
-			spellIcons.push_back(std::make_shared<CAnimImage>("SpellInt", effect + 1, 0, firstPos.x + offset.x * printed, firstPos.y + offset.y * printed));
+			spellIcons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("SpellInt"), effect + 1, 0, firstPos.x + offset.x * printed, firstPos.y + offset.y * printed));
 			clickableAreas.push_back(std::make_shared<LRClickableAreaWText>(Rect(firstPos + offset * printed, Point(50, 38)), spellText, spellText));
 			if(++printed >= 8) // interface limit reached
 				break;
@@ -214,7 +214,7 @@ CStackWindow::ActiveSpellsSection::ActiveSpellsSection(CStackWindow * owner, int
 }
 
 CStackWindow::BonusLineSection::BonusLineSection(CStackWindow * owner, size_t lineIndex)
-	: CWindowSection(owner, "bonus-effects", 0)
+	: CWindowSection(owner, ImagePath::builtin("stackWindow/bonus-effects"), 0)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 
@@ -240,7 +240,7 @@ CStackWindow::BonusLineSection::BonusLineSection(CStackWindow * owner, size_t li
 }
 
 CStackWindow::BonusesSection::BonusesSection(CStackWindow * owner, int yOffset, std::optional<size_t> preferredSize):
-	CWindowSection(owner, "", yOffset)
+	CWindowSection(owner, {}, yOffset)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 
@@ -262,7 +262,7 @@ CStackWindow::BonusesSection::BonusesSection(CStackWindow * owner, int yOffset,
 }
 
 CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset)
-	: CWindowSection(owner, "button-panel", yOffset)
+	: CWindowSection(owner, ImagePath::builtin("stackWindow/button-panel"), yOffset)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 
@@ -277,7 +277,7 @@ CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset)
 		{
 			LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[12], onDismiss, nullptr);
 		};
-		dismiss = std::make_shared<CButton>(Point(5, 5),"IVIEWCR2.DEF", CGI->generaltexth->zelp[445], onClick, EShortcut::HERO_DISMISS);
+		dismiss = std::make_shared<CButton>(Point(5, 5),AnimationPath::builtin("IVIEWCR2.DEF"), CGI->generaltexth->zelp[445], onClick, EShortcut::HERO_DISMISS);
 	}
 
 	if(parent->info->upgradeInfo && !parent->info->commander)
@@ -314,9 +314,9 @@ CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset)
 					LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[314], resComps);
 				}
 			};
-			auto upgradeBtn = std::make_shared<CButton>(Point(221 + (int)buttonIndex * 40, 5), "stackWindow/upgradeButton", CGI->generaltexth->zelp[446], onClick);
+			auto upgradeBtn = std::make_shared<CButton>(Point(221 + (int)buttonIndex * 40, 5), AnimationPath::builtin("stackWindow/upgradeButton"), CGI->generaltexth->zelp[446], onClick);
 
-			upgradeBtn->addOverlay(std::make_shared<CAnimImage>("CPRSMALL", VLC->creh->objects[upgradeInfo.info.newID[buttonIndex]]->getIconIndex()));
+			upgradeBtn->addOverlay(std::make_shared<CAnimImage>(AnimationPath::builtin("CPRSMALL"), VLC->creh->objects[upgradeInfo.info.newID[buttonIndex]]->getIconIndex()));
 
 			if(buttonsToCreate == 1) // single upgrade avaialbe
 				upgradeBtn->assignedKey = EShortcut::RECRUITMENT_UPGRADE;
@@ -341,17 +341,17 @@ CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset)
 			};
 
 			std::string tooltipText = "vcmi.creatureWindow." + btnIDs[buttonIndex];
-			parent->switchButtons[buttonIndex] = std::make_shared<CButton>(Point(302 + (int)buttonIndex*40, 5), "stackWindow/upgradeButton", CButton::tooltipLocalized(tooltipText), onSwitch);
-			parent->switchButtons[buttonIndex]->addOverlay(std::make_shared<CAnimImage>("stackWindow/switchModeIcons", buttonIndex));
+			parent->switchButtons[buttonIndex] = std::make_shared<CButton>(Point(302 + (int)buttonIndex*40, 5), AnimationPath::builtin("stackWindow/upgradeButton"), CButton::tooltipLocalized(tooltipText), onSwitch);
+			parent->switchButtons[buttonIndex]->addOverlay(std::make_shared<CAnimImage>(AnimationPath::builtin("stackWindow/switchModeIcons"), buttonIndex));
 		}
 		parent->switchButtons[parent->activeTab]->disable();
 	}
 
-	exit = std::make_shared<CButton>(Point(382, 5), "hsbtns.def", CGI->generaltexth->zelp[447], [=](){ parent->close(); }, EShortcut::GLOBAL_RETURN);
+	exit = std::make_shared<CButton>(Point(382, 5), AnimationPath::builtin("hsbtns.def"), CGI->generaltexth->zelp[447], [=](){ parent->close(); }, EShortcut::GLOBAL_RETURN);
 }
 
 CStackWindow::CommanderMainSection::CommanderMainSection(CStackWindow * owner, int yOffset)
-	: CWindowSection(owner, "commander-bg", yOffset)
+	: CWindowSection(owner, ImagePath::builtin("stackWindow/commander-bg"), yOffset)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 
@@ -360,7 +360,7 @@ CStackWindow::CommanderMainSection::CommanderMainSection(CStackWindow * owner, i
 		return Point(10 + 80 * (index%3), 20 + 80 * (index/3));
 	};
 
-	auto getSkillImage = [this](int skillIndex) -> std::string
+	auto getSkillImage = [this](int skillIndex)
 	{
 		bool selected = ((parent->selectedSkill == skillIndex) && parent->info->levelupInfo );
 		return skillToFile(skillIndex, parent->info->commander->secondarySkills[skillIndex], selected);
@@ -413,7 +413,7 @@ CStackWindow::CommanderMainSection::CommanderMainSection(CStackWindow * owner, i
 
 	if(parent->info->levelupInfo)
 	{
-		abilitiesBackground = std::make_shared<CPicture>("stackWindow/commander-abilities.png");
+		abilitiesBackground = std::make_shared<CPicture>(ImagePath::builtin("stackWindow/commander-abilities.png"));
 		abilitiesBackground->moveBy(Point(0, pos.h));
 
 		size_t abilitiesCount = boost::range::count_if(parent->info->levelupInfo->skills, [](ui32 skillID)
@@ -447,8 +447,8 @@ CStackWindow::CommanderMainSection::CommanderMainSection(CStackWindow * owner, i
 
 		abilities = std::make_shared<CListBox>(onCreate, Point(38, 3+pos.h), Point(63, 0), 6, abilitiesCount);
 
-		leftBtn = std::make_shared<CButton>(Point(10,  pos.h + 6), "hsbtns3.def", CButton::tooltip(), [=](){ abilities->moveToPrev(); }, EShortcut::MOVE_LEFT);
-		rightBtn = std::make_shared<CButton>(Point(411, pos.h + 6), "hsbtns5.def", CButton::tooltip(), [=](){ abilities->moveToNext(); }, EShortcut::MOVE_RIGHT);
+		leftBtn = std::make_shared<CButton>(Point(10,  pos.h + 6), AnimationPath::builtin("hsbtns3.def"), CButton::tooltip(), [=](){ abilities->moveToPrev(); }, EShortcut::MOVE_LEFT);
+		rightBtn = std::make_shared<CButton>(Point(411, pos.h + 6), AnimationPath::builtin("hsbtns5.def"), CButton::tooltip(), [=](){ abilities->moveToNext(); }, EShortcut::MOVE_RIGHT);
 
 		if(abilitiesCount <= 6)
 		{
@@ -505,7 +505,7 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
 	if(parent->info->owner && parent->info->stackNode->hasBonusOfType(BonusType::SIEGE_WEAPON))
 		dmgMultiply += parent->info->owner->getPrimSkillLevel(PrimarySkill::ATTACK);
 
-	icons = std::make_shared<CPicture>("stackWindow/icons", 117, 32);
+	icons = std::make_shared<CPicture>(ImagePath::builtin("stackWindow/icons"), 117, 32);
 
 	const CStack * battleStack = parent->info->stack;
 
@@ -556,7 +556,7 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
 		if(parent->info->commander)
 		{
 			const CCommanderInstance * commander = parent->info->commander;
-			expRankIcon = std::make_shared<CAnimImage>("PSKIL42", 4, 0, pos.x, pos.y);
+			expRankIcon = std::make_shared<CAnimImage>(AnimationPath::builtin("PSKIL42"), 4, 0, pos.x, pos.y);
 
 			auto area = std::make_shared<LRClickableAreaWTextComp>(Rect(pos.x, pos.y, 44, 44), CComponent::experience);
 			expArea = area;
@@ -568,7 +568,7 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
 		}
 		else
 		{
-			expRankIcon = std::make_shared<CAnimImage>("stackWindow/levels", stack->getExpRank(), 0, pos.x, pos.y);
+			expRankIcon = std::make_shared<CAnimImage>(AnimationPath::builtin("stackWindow/levels"), stack->getExpRank(), 0, pos.x, pos.y);
 			expArea = std::make_shared<LRClickableAreaWText>(Rect(pos.x, pos.y, 44, 44));
 			expArea->text = parent->generateStackExpDescription();
 		}
@@ -586,14 +586,14 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
 		auto art = parent->info->stackNode->getArt(ArtifactPosition::CREATURE_SLOT);
 		if(art)
 		{
-			parent->stackArtifactIcon = std::make_shared<CAnimImage>("ARTIFACT", art->artType->getIconIndex(), 0, pos.x, pos.y);
+			parent->stackArtifactIcon = std::make_shared<CAnimImage>(AnimationPath::builtin("ARTIFACT"), art->artType->getIconIndex(), 0, pos.x, pos.y);
 			parent->stackArtifactHelp = std::make_shared<LRClickableAreaWTextComp>(Rect(pos, Point(44, 44)), CComponent::artifact);
 			parent->stackArtifactHelp->type = art->artType->getId();
 
 			if(parent->info->owner)
 			{
 				parent->stackArtifactButton = std::make_shared<CButton>(
-						Point(pos.x - 2 , pos.y + 46), "stackWindow/cancelButton",
+						Point(pos.x - 2 , pos.y + 46), AnimationPath::builtin("stackWindow/cancelButton"),
 						CButton::tooltipLocalized("vcmi.creatureWindow.returnArtifact"),	[=]()
 				{
 					parent->removeStackArtifact(ArtifactPosition::CREATURE_SLOT);
@@ -604,14 +604,14 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
 }
 
 
-std::string CStackWindow::MainSection::getBackgroundName(bool showExp, bool showArt)
+ImagePath CStackWindow::MainSection::getBackgroundName(bool showExp, bool showArt)
 {
 	if(showExp && showArt)
-		return "info-panel-2";
+		return ImagePath::builtin("stackWindow/info-panel-2");
 	else if(showExp || showArt)
-		return "info-panel-1";
+		return ImagePath::builtin("stackWindow/info-panel-1");
 	else
-		return "info-panel-0";
+		return ImagePath::builtin("stackWindow/info-panel-0");
 }
 
 void CStackWindow::MainSection::addStatLabel(EStat index, int64_t value1, int64_t value2)
@@ -882,7 +882,7 @@ void CStackWindow::setSelection(si32 newSkill, std::shared_ptr<CCommanderSkillIc
 			return CGI->generaltexth->znpc00[152 + (12 * skillIndex) + (info->commander->secondarySkills[skillIndex] * 2)];
 	};
 
-	auto getSkillImage = [this](int skillIndex) -> std::string
+	auto getSkillImage = [this](int skillIndex)
 	{
 		bool selected = ((selectedSkill == skillIndex) && info->levelupInfo );
 		return skillToFile(skillIndex, info->commander->secondarySkills[skillIndex], selected);

+ 4 - 3
client/windows/CCreatureWindow.h

@@ -10,6 +10,7 @@
 #pragma once
 
 #include "../../lib/bonuses/Bonus.h"
+#include "../../lib/filesystem/ResourcePath.h"
 #include "../widgets/MiscWidgets.h"
 #include "CWindowObject.h"
 
@@ -48,7 +49,7 @@ class CStackWindow : public CWindowObject
 	{
 		std::string name;
 		std::string description;
-		std::string imagePath;
+		ImagePath imagePath;
 	};
 
 	class CWindowSection : public CIntObject
@@ -58,7 +59,7 @@ class CStackWindow : public CWindowObject
 	protected:
 		CStackWindow * parent;
 	public:
-		CWindowSection(CStackWindow * parent, std::string backgroundPath, int yOffset);
+		CWindowSection(CStackWindow * parent, const ImagePath & backgroundPath, int yOffset);
 	};
 
 	class ActiveSpellsSection : public CWindowSection
@@ -138,7 +139,7 @@ class CStackWindow : public CWindowObject
 		void addStatLabel(EStat index, int64_t value1, int64_t value2);
 		void addStatLabel(EStat index, int64_t value);
 
-		static std::string getBackgroundName(bool showExp, bool showArt);
+		static ImagePath getBackgroundName(bool showExp, bool showArt);
 
 		std::array<std::string, 8> statNames;
 		std::array<std::string, 8> statFormats;

+ 2 - 2
client/windows/CHeroBackpackWindow.cpp

@@ -24,7 +24,7 @@ CHeroBackpackWindow::CHeroBackpackWindow(const CGHeroInstance * hero)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 
-	stretchedBackground = std::make_shared<CFilledTexture>("DIBOXBCK", Rect(0, 0, 410, 425));
+	stretchedBackground = std::make_shared<CFilledTexture>(ImagePath::builtin("DIBOXBCK"), Rect(0, 0, 410, 425));
 	pos.w = stretchedBackground->pos.w;
 	pos.h = stretchedBackground->pos.h;
 	center();
@@ -36,7 +36,7 @@ CHeroBackpackWindow::CHeroBackpackWindow(const CGHeroInstance * hero)
 
 	addCloseCallback(std::bind(&CHeroBackpackWindow::close, this));
 
-	quitButton = std::make_shared<CButton>(Point(173, 385), "IOKAY32.def", CButton::tooltip(""), [this]() { close(); }, EShortcut::GLOBAL_RETURN);
+	quitButton = std::make_shared<CButton>(Point(173, 385), AnimationPath::builtin("IOKAY32.def"), CButton::tooltip(""), [this]() { close(); }, EShortcut::GLOBAL_RETURN);
 }
 
 void CHeroBackpackWindow::showAll(Canvas &to)

+ 20 - 20
client/windows/CHeroWindow.cpp

@@ -63,48 +63,48 @@ CHeroSwitcher::CHeroSwitcher(CHeroWindow * owner_, Point pos_, const CGHeroInsta
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 	pos += pos_;
 
-	image = std::make_shared<CAnimImage>("PortraitsSmall", hero->portrait);
+	image = std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsSmall"), hero->portrait);
 	pos.w = image->pos.w;
 	pos.h = image->pos.h;
 }
 
 CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
-	: CStatusbarWindow(PLAYER_COLORED, "HeroScr4")
+	: CStatusbarWindow(PLAYER_COLORED, ImagePath::builtin("HeroScr4"))
 {
 	auto & heroscrn = CGI->generaltexth->heroscrn;
 
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 	curHero = hero;
 
-	banner = std::make_shared<CAnimImage>("CREST58", LOCPLINT->playerID.getNum(), 0, 606, 8);
+	banner = std::make_shared<CAnimImage>(AnimationPath::builtin("CREST58"), LOCPLINT->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);
 
-	statusbar = CGStatusBar::create(7, 559, "ADROLLVR.bmp", 660);
+	statusbar = CGStatusBar::create(7, 559, ImagePath::builtin("ADROLLVR.bmp"), 660);
 
-	quitButton = std::make_shared<CButton>(Point(609, 516), "hsbtns.def", CButton::tooltip(heroscrn[17]), [=](){ close(); }, EShortcut::GLOBAL_RETURN);
+	quitButton = std::make_shared<CButton>(Point(609, 516), AnimationPath::builtin("hsbtns.def"), CButton::tooltip(heroscrn[17]), [=](){ close(); }, EShortcut::GLOBAL_RETURN);
 
 	if(settings["general"]["enableUiEnhancements"].Bool())
 	{
-		questlogButton = std::make_shared<CButton>(Point(314, 429), "hsbtns4.def", CButton::tooltip(heroscrn[0]), [=](){ LOCPLINT->showQuestLog(); }, EShortcut::ADVENTURE_QUEST_LOG);
-		backpackButton = std::make_shared<CButton>(Point(424, 429), "buttons/backpack", CButton::tooltipLocalized("vcmi.heroWindow.Backpack"), [=](){ createBackpackWindow(); }, EShortcut::HERO_BACKPACK);
-		dismissButton = std::make_shared<CButton>(Point(534, 429), "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);
+		backpackButton = std::make_shared<CButton>(Point(424, 429), AnimationPath::builtin("buttons/backpack"), CButton::tooltipLocalized("vcmi.heroWindow.Backpack"), [=](){ createBackpackWindow(); }, EShortcut::HERO_BACKPACK);
+		dismissButton = std::make_shared<CButton>(Point(534, 429), AnimationPath::builtin("hsbtns2.def"), CButton::tooltip(heroscrn[28]), [=](){ dismissCurrent(); }, EShortcut::HERO_DISMISS);
 	}
 	else
 	{
 		dismissLabel = std::make_shared<CTextBox>(CGI->generaltexth->jktexts[8], Rect(370, 430, 65, 35), 0, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE);
 		questlogLabel = std::make_shared<CTextBox>(CGI->generaltexth->jktexts[9], Rect(510, 430, 65, 35), 0, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE);
-		dismissButton = std::make_shared<CButton>(Point(454, 429), "hsbtns2.def", CButton::tooltip(heroscrn[28]), [=](){ dismissCurrent(); }, EShortcut::HERO_DISMISS);
-		questlogButton = std::make_shared<CButton>(Point(314, 429), "hsbtns4.def", CButton::tooltip(heroscrn[0]), [=](){ LOCPLINT->showQuestLog(); }, EShortcut::ADVENTURE_QUEST_LOG);
+		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);
 	}
 
 	formations = std::make_shared<CToggleGroup>(0);
-	formations->addToggle(0, std::make_shared<CToggleButton>(Point(481, 483), "hsbtns6.def", std::make_pair(heroscrn[23], heroscrn[29]), 0, EShortcut::HERO_TIGHT_FORMATION));
-	formations->addToggle(1, std::make_shared<CToggleButton>(Point(481, 519), "hsbtns7.def", std::make_pair(heroscrn[24], heroscrn[30]), 0, EShortcut::HERO_LOOSE_FORMATION));
+	formations->addToggle(0, std::make_shared<CToggleButton>(Point(481, 483), AnimationPath::builtin("hsbtns6.def"), std::make_pair(heroscrn[23], heroscrn[29]), 0, EShortcut::HERO_TIGHT_FORMATION));
+	formations->addToggle(1, std::make_shared<CToggleButton>(Point(481, 519), AnimationPath::builtin("hsbtns7.def"), std::make_pair(heroscrn[24], heroscrn[30]), 0, EShortcut::HERO_LOOSE_FORMATION));
 
 	if(hero->commander)
 	{
-		commanderButton = std::make_shared<CButton>(Point(317, 18), "buttons/commander", CButton::tooltipLocalized("vcmi.heroWindow.openCommander"), [&](){ commanderWindow(); }, EShortcut::HERO_COMMANDER);
+		commanderButton = std::make_shared<CButton>(Point(317, 18), AnimationPath::builtin("buttons/commander"), CButton::tooltipLocalized("vcmi.heroWindow.openCommander"), [&](){ commanderWindow(); }, EShortcut::HERO_COMMANDER);
 	}
 
 	//right list of heroes
@@ -113,7 +113,7 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
 
 	//areas
 	portraitArea = std::make_shared<LRClickableAreaWText>(Rect(18, 18, 58, 64));
-	portraitImage = std::make_shared<CAnimImage>("PortraitsLarge", 0, 0, 19, 19);
+	portraitImage = std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsLarge"), 0, 0, 19, 19);
 
 	for(int v = 0; v < GameConstants::PRIMARY_SKILLS; ++v)
 	{
@@ -127,7 +127,7 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
 		primSkillValues.push_back(value);
 	}
 
-	auto primSkills = std::make_shared<CAnimation>("PSKIL42");
+	auto primSkills = std::make_shared<CAnimation>(AnimationPath::builtin("PSKIL42"));
 	primSkills->preload();
 	primSkillImages.push_back(std::make_shared<CAnimImage>(primSkills, 0, 0, 32, 111));
 	primSkillImages.push_back(std::make_shared<CAnimImage>(primSkills, 1, 0, 102, 111));
@@ -136,7 +136,7 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
 	primSkillImages.push_back(std::make_shared<CAnimImage>(primSkills, 4, 0, 20, 230));
 	primSkillImages.push_back(std::make_shared<CAnimImage>(primSkills, 5, 0, 242, 111));
 
-	specImage = std::make_shared<CAnimImage>("UN44", 0, 0, 18, 180);
+	specImage = std::make_shared<CAnimImage>(AnimationPath::builtin("UN44"), 0, 0, 18, 180);
 	specArea = std::make_shared<LRClickableAreaWText>(Rect(18, 180, 136, 42), CGI->generaltexth->heroscrn[27]);
 	specName = std::make_shared<CLabel>(69, 205);
 
@@ -148,7 +148,7 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
 	expValue = std::make_shared<CLabel>(68, 252);
 	manaValue = std::make_shared<CLabel>(211, 252);
 
-	auto secSkills = std::make_shared<CAnimation>("SECSKILL");
+	auto secSkills = std::make_shared<CAnimation>(AnimationPath::builtin("SECSKILL"));
 	for(int i = 0; i < std::min<size_t>(hero->secSkills.size(), 8u); ++i)
 	{
 		Rect r = Rect(i%2 == 0  ?  18  :  162,  276 + 48 * (i/2),  136,  42);
@@ -194,7 +194,7 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded)
 	specImage->setFrame(curHero->type->imageIndex);
 	specName->setText(curHero->type->getSpecialtyNameTranslated());
 
-	tacticsButton = std::make_shared<CToggleButton>(Point(539, 483), "hsbtns8.def", std::make_pair(heroscrn[26], heroscrn[31]), 0, EShortcut::HERO_TOGGLE_TACTICS);
+	tacticsButton = std::make_shared<CToggleButton>(Point(539, 483), AnimationPath::builtin("hsbtns8.def"), std::make_pair(heroscrn[26], heroscrn[31]), 0, EShortcut::HERO_TOGGLE_TACTICS);
 	tacticsButton->addHoverText(CButton::HIGHLIGHTED, CGI->generaltexth->heroscrn[25]);
 
 	dismissButton->addHoverText(CButton::NORMAL, boost::str(boost::format(CGI->generaltexth->heroscrn[16]) % curHero->getNameTranslated() % curHero->type->heroClass->getNameTranslated()));
@@ -210,7 +210,7 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded)
 			boost::algorithm::replace_first(helpBox, "%s", CGI->generaltexth->allTexts[43]);
 
 			garr = std::make_shared<CGarrisonInt>(Point(15, 485), 8, Point(), curHero);
-			auto split = std::make_shared<CButton>(Point(539, 519), "hsbtns9.def", CButton::tooltip(CGI->generaltexth->allTexts[256], helpBox), [&](){ garr->splitClick(); });
+			auto split = std::make_shared<CButton>(Point(539, 519), AnimationPath::builtin("hsbtns9.def"), CButton::tooltip(CGI->generaltexth->allTexts[256], helpBox), [&](){ garr->splitClick(); });
 			garr->addSplitBtn(split);
 		}
 		if(!arts)
@@ -224,7 +224,7 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded)
 
 		listSelection.reset();
 		if(serial >= 0)
-			listSelection = std::make_shared<CPicture>("HPSYYY", 612, 33 + serial * 54);
+			listSelection = std::make_shared<CPicture>(ImagePath::builtin("HPSYYY"), 612, 33 + serial * 54);
 	}
 
 	//primary skills support

+ 31 - 31
client/windows/CKingdomInterface.cpp

@@ -169,7 +169,7 @@ std::string InfoBoxAbstractHeroData::getNameText()
 	return "";
 }
 
-std::string InfoBoxAbstractHeroData::getImageName(InfoBox::InfoSize size)
+AnimationPath InfoBoxAbstractHeroData::getImageName(InfoBox::InfoSize size)
 {
 	//TODO: sizes
 	switch(size)
@@ -181,11 +181,11 @@ std::string InfoBoxAbstractHeroData::getImageName(InfoBox::InfoSize size)
 			case HERO_PRIMARY_SKILL:
 			case HERO_MANA:
 			case HERO_EXPERIENCE:
-				return "PSKIL32";
+				return AnimationPath::builtin("PSKIL32");
 			case HERO_SPECIAL:
-				return "UN32";
+				return AnimationPath::builtin("UN32");
 			case HERO_SECONDARY_SKILL:
-				return "SECSK32";
+				return AnimationPath::builtin("SECSK32");
 			default:
 				assert(0);
 			}
@@ -197,11 +197,11 @@ std::string InfoBoxAbstractHeroData::getImageName(InfoBox::InfoSize size)
 			case HERO_PRIMARY_SKILL:
 			case HERO_MANA:
 			case HERO_EXPERIENCE:
-				return "PSKIL42";
+				return AnimationPath::builtin("PSKIL42");
 			case HERO_SPECIAL:
-				return "UN44";
+				return AnimationPath::builtin("UN44");
 			case HERO_SECONDARY_SKILL:
-				return "SECSKILL";
+				return AnimationPath::builtin("SECSKILL");
 			default:
 				assert(0);
 			}
@@ -209,7 +209,7 @@ std::string InfoBoxAbstractHeroData::getImageName(InfoBox::InfoSize size)
 	default:
 		assert(0);
 	}
-	return "";
+	return {};
 }
 
 std::string InfoBoxAbstractHeroData::getHoverText()
@@ -437,7 +437,7 @@ size_t InfoBoxCustom::getImageIndex()
 	return imageIndex;
 }
 
-std::string InfoBoxCustom::getImageName(InfoBox::InfoSize size)
+AnimationPath InfoBoxCustom::getImageName(InfoBox::InfoSize size)
 {
 	return imageName;
 }
@@ -457,7 +457,7 @@ void InfoBoxCustom::prepareMessage(std::string & text, std::shared_ptr<CComponen
 }
 
 CKingdomInterface::CKingdomInterface()
-	: CWindowObject(PLAYER_COLORED | BORDERED, OVERVIEW_BACKGROUND)
+	: CWindowObject(PLAYER_COLORED | BORDERED, ImagePath::builtin(OVERVIEW_BACKGROUND))
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 	ui32 footerPos = OVERVIEW_SIZE * 116;
@@ -469,8 +469,8 @@ CKingdomInterface::CKingdomInterface()
 	generateMinesList(ownedObjects);
 	generateButtons();
 
-	statusbar = CGStatusBar::create(std::make_shared<CPicture>("KSTATBAR", 10,pos.h - 45));
-	resdatabar = std::make_shared<CResDataBar>("KRESBAR", 7, 111+footerPos, 29, 5, 76, 81);
+	statusbar = CGStatusBar::create(std::make_shared<CPicture>(ImagePath::builtin("KSTATBAR"), 10,pos.h - 45));
+	resdatabar = std::make_shared<CResDataBar>(ImagePath::builtin("KRESBAR"), 7, 111+footerPos, 29, 5, 76, 81);
 }
 
 void CKingdomInterface::generateObjectsList(const std::vector<const CGObjectInstance * > &ownedObjects)
@@ -602,27 +602,27 @@ void CKingdomInterface::generateButtons()
 	ui32 footerPos = OVERVIEW_SIZE * 116;
 
 	//Main control buttons
-	btnHeroes = std::make_shared<CButton>(Point(748, 28+footerPos), "OVBUTN1.DEF", CButton::tooltip(CGI->generaltexth->overview[11], CGI->generaltexth->overview[6]),
+	btnHeroes = std::make_shared<CButton>(Point(748, 28+footerPos), AnimationPath::builtin("OVBUTN1.DEF"), CButton::tooltip(CGI->generaltexth->overview[11], CGI->generaltexth->overview[6]),
 		std::bind(&CKingdomInterface::activateTab, this, 0), EShortcut::KINGDOM_HEROES_TAB);
 	btnHeroes->block(true);
 
-	btnTowns = std::make_shared<CButton>(Point(748, 64+footerPos), "OVBUTN6.DEF", CButton::tooltip(CGI->generaltexth->overview[12], CGI->generaltexth->overview[7]),
+	btnTowns = std::make_shared<CButton>(Point(748, 64+footerPos), AnimationPath::builtin("OVBUTN6.DEF"), CButton::tooltip(CGI->generaltexth->overview[12], CGI->generaltexth->overview[7]),
 		std::bind(&CKingdomInterface::activateTab, this, 1), EShortcut::KINGDOM_TOWNS_TAB);
 
-	btnExit = std::make_shared<CButton>(Point(748,99+footerPos), "OVBUTN1.DEF", CButton::tooltip(CGI->generaltexth->allTexts[600]),
+	btnExit = std::make_shared<CButton>(Point(748,99+footerPos), AnimationPath::builtin("OVBUTN1.DEF"), CButton::tooltip(CGI->generaltexth->allTexts[600]),
 		std::bind(&CKingdomInterface::close, this), EShortcut::GLOBAL_RETURN);
 	btnExit->setImageOrder(3, 4, 5, 6);
 
 	//Object list control buttons
-	dwellTop = std::make_shared<CButton>(Point(733, 4), "OVBUTN4.DEF", CButton::tooltip(), [&](){ dwellingsList->moveToPos(0);});
+	dwellTop = std::make_shared<CButton>(Point(733, 4), AnimationPath::builtin("OVBUTN4.DEF"), CButton::tooltip(), [&](){ dwellingsList->moveToPos(0);});
 
-	dwellBottom = std::make_shared<CButton>(Point(733, footerPos+2), "OVBUTN4.DEF", CButton::tooltip(), [&](){ dwellingsList->moveToPos(-1); });
+	dwellBottom = std::make_shared<CButton>(Point(733, footerPos+2), AnimationPath::builtin("OVBUTN4.DEF"), CButton::tooltip(), [&](){ dwellingsList->moveToPos(-1); });
 	dwellBottom->setImageOrder(2, 3, 4, 5);
 
-	dwellUp = std::make_shared<CButton>(Point(733, 24), "OVBUTN4.DEF", CButton::tooltip(), [&](){ dwellingsList->moveToPrev(); });
+	dwellUp = std::make_shared<CButton>(Point(733, 24), AnimationPath::builtin("OVBUTN4.DEF"), CButton::tooltip(), [&](){ dwellingsList->moveToPrev(); });
 	dwellUp->setImageOrder(4, 5, 6, 7);
 
-	dwellDown = std::make_shared<CButton>(Point(733, footerPos-18), "OVBUTN4.DEF", CButton::tooltip(), [&](){ dwellingsList->moveToNext(); });
+	dwellDown = std::make_shared<CButton>(Point(733, footerPos-18), AnimationPath::builtin("OVBUTN4.DEF"), CButton::tooltip(), [&](){ dwellingsList->moveToNext(); });
 	dwellDown->setImageOrder(6, 7, 8, 9);
 }
 
@@ -677,7 +677,7 @@ void CKingdomInterface::artifactRemoved(const ArtifactLocation& artLoc)
 CKingdHeroList::CKingdHeroList(size_t maxSize)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-	title = std::make_shared<CPicture>("OVTITLE",16,0);
+	title = std::make_shared<CPicture>(ImagePath::builtin("OVTITLE"),16,0);
 	title->colorize(LOCPLINT->playerID);
 	heroLabel = std::make_shared<CLabel>(150, 10, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->overview[0]);
 	skillsLabel = std::make_shared<CLabel>(500, 10, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->overview[1]);
@@ -711,14 +711,14 @@ std::shared_ptr<CIntObject> CKingdHeroList::createHeroItem(size_t index)
 	}
 	else
 	{
-		return std::make_shared<CAnimImage>("OVSLOT", (index-2) % picCount );
+		return std::make_shared<CAnimImage>(AnimationPath::builtin("OVSLOT"), (index-2) % picCount );
 	}
 }
 
 CKingdTownList::CKingdTownList(size_t maxSize)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-	title = std::make_shared<CPicture>("OVTITLE", 16, 0);
+	title = std::make_shared<CPicture>(ImagePath::builtin("OVTITLE"), 16, 0);
 	title->colorize(LOCPLINT->playerID);
 	townLabel = std::make_shared<CLabel>(146, 10,FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->overview[3]);
 	garrHeroLabel = std::make_shared<CLabel>(375, 10, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->overview[4]);
@@ -758,14 +758,14 @@ std::shared_ptr<CIntObject> CKingdTownList::createTownItem(size_t index)
 	if(index < townsList.size())
 		return std::make_shared<CTownItem>(townsList[index]);
 	else
-		return std::make_shared<CAnimImage>("OVSLOT", (index-2) % picCount );
+		return std::make_shared<CAnimImage>(AnimationPath::builtin("OVSLOT"), (index-2) % picCount );
 }
 
 CTownItem::CTownItem(const CGTownInstance * Town)
 	: town(Town)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-	background = std::make_shared<CAnimImage>("OVSLOT", 6);
+	background = std::make_shared<CAnimImage>(AnimationPath::builtin("OVSLOT"), 6);
 	name = std::make_shared<CLabel>(74, 8, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, town->getNameTranslated());
 
 	income = std::make_shared<CLabel>( 190, 60, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, std::to_string(town->dailyIncome()[EGameResID::GOLD]));
@@ -777,7 +777,7 @@ CTownItem::CTownItem(const CGTownInstance * Town)
 
 	size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->builded >= CGI->settings()->getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
 
-	picture = std::make_shared<CAnimImage>("ITPT", iconIndex, 0, 5, 6);
+	picture = std::make_shared<CAnimImage>(AnimationPath::builtin("ITPT"), iconIndex, 0, 5, 6);
 	openTown = std::make_shared<LRClickableAreaOpenTown>(Rect(5, 6, 58, 64), town);
 
 	for(size_t i=0; i<town->creatures.size(); i++)
@@ -819,7 +819,7 @@ public:
 	ArtSlotsTab()
 	{
 		OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-		background = std::make_shared<CAnimImage>("OVSLOT", 4);
+		background = std::make_shared<CAnimImage>(AnimationPath::builtin("OVSLOT"), 4);
 		pos = background->pos;
 		for(int i=0; i<9; i++)
 			arts.push_back(std::make_shared<CHeroArtPlace>(Point(269+i*48, 66)));
@@ -837,10 +837,10 @@ public:
 	BackpackTab()
 	{
 		OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-		background = std::make_shared<CAnimImage>("OVSLOT", 5);
+		background = std::make_shared<CAnimImage>(AnimationPath::builtin("OVSLOT"), 5);
 		pos = background->pos;
-		btnLeft = std::make_shared<CButton>(Point(269, 66), "HSBTNS3", CButton::tooltip(), 0);
-		btnRight = std::make_shared<CButton>(Point(675, 66), "HSBTNS5", CButton::tooltip(), 0);
+		btnLeft = std::make_shared<CButton>(Point(269, 66), AnimationPath::builtin("HSBTNS3"), CButton::tooltip(), 0);
+		btnRight = std::make_shared<CButton>(Point(675, 66), AnimationPath::builtin("HSBTNS5"), CButton::tooltip(), 0);
 		for(int i=0; i<8; i++)
 			arts.push_back(std::make_shared<CHeroArtPlace>(Point(294+i*48, 66)));
 	}
@@ -905,7 +905,7 @@ CHeroItem::CHeroItem(const CGHeroInstance * Hero)
 		std::string hover = CGI->generaltexth->overview[13+it];
 		std::string overlay = CGI->generaltexth->overview[8+it];
 
-		auto button = std::make_shared<CToggleButton>(Point(364+(int)it*112, 46), "OVBUTN3", CButton::tooltip(hover, overlay), 0);
+		auto button = std::make_shared<CToggleButton>(Point(364+(int)it*112, 46), AnimationPath::builtin("OVBUTN3"), CButton::tooltip(hover, overlay), 0);
 		button->addTextOverlay(CGI->generaltexth->allTexts[stringID[it]], FONT_SMALL, Colors::YELLOW);
 		artButtons->addToggle((int)it, button);
 	}
@@ -915,7 +915,7 @@ CHeroItem::CHeroItem(const CGHeroInstance * Hero)
 
 	garr = std::make_shared<CGarrisonInt>(Point(6, 78), 4, Point(), hero, nullptr, true, true);
 
-	portrait = std::make_shared<CAnimImage>("PortraitsLarge", hero->portrait, 0, 5, 6);
+	portrait = std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsLarge"), hero->portrait, 0, 5, 6);
 	heroArea = std::make_shared<CHeroArea>(5, 6, hero);
 
 	name = std::make_shared<CLabel>(73, 7, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, hero->getNameTranslated());

+ 5 - 5
client/windows/CKingdomInterface.h

@@ -103,7 +103,7 @@ public:
 	//methods that generate values for displaying
 	virtual std::string getValueText()=0;
 	virtual std::string getNameText()=0;
-	virtual std::string getImageName(InfoBox::InfoSize size)=0;
+	virtual AnimationPath getImageName(InfoBox::InfoSize size)=0;
 	virtual std::string getHoverText()=0;
 	virtual size_t getImageIndex()=0;
 
@@ -124,7 +124,7 @@ public:
 
 	std::string getValueText() override;
 	std::string getNameText() override;
-	std::string getImageName(InfoBox::InfoSize size) override;
+	AnimationPath getImageName(InfoBox::InfoSize size) override;
 	std::string getHoverText() override;
 	size_t getImageIndex() override;
 
@@ -166,7 +166,7 @@ class InfoBoxCustom : public IInfoBoxData
 public:
 	std::string valueText;
 	std::string nameText;
-	std::string imageName;
+	AnimationPath imageName;
 	std::string hoverText;
 	size_t imageIndex;
 
@@ -174,7 +174,7 @@ public:
 
 	std::string getValueText() override;
 	std::string getNameText() override;
-	std::string getImageName(InfoBox::InfoSize size) override;
+	AnimationPath getImageName(InfoBox::InfoSize size) override;
 	std::string getHoverText() override;
 	size_t getImageIndex() override;
 
@@ -194,7 +194,7 @@ public:
 
 	std::string getValueText() override;
 	std::string getNameText() override;
-	std::string getImageName(InfoBox::InfoSize size) override;
+	AnimationPath getImageName(InfoBox::InfoSize size) override;
 	std::string getHoverText() override;
 	size_t getImageIndex() override;
 };

+ 2 - 2
client/windows/CMessage.cpp

@@ -79,7 +79,7 @@ void CMessage::init()
 {
 	for(int i=0; i<PlayerColor::PLAYER_LIMIT_I; i++)
 	{
-		dialogBorders[i] = std::make_unique<CAnimation>("DIALGBOX");
+		dialogBorders[i] = std::make_unique<CAnimation>(AnimationPath::builtin("DIALGBOX"));
 		dialogBorders[i]->preload();
 
 		for(int j=0; j < dialogBorders[i]->size(0); j++)
@@ -92,7 +92,7 @@ void CMessage::init()
 		}
 	}
 
-	background = IImage::createFromFile("DIBOXBCK.BMP", EImageBlitMode::OPAQUE);
+	background = IImage::createFromFile(ImagePath::builtin("DIBOXBCK.BMP"), EImageBlitMode::OPAQUE);
 }
 
 void CMessage::dispose()

+ 4 - 4
client/windows/CPuzzleWindow.cpp

@@ -28,7 +28,7 @@
 #include "../../lib/StartInfo.h"
 
 CPuzzleWindow::CPuzzleWindow(const int3 & GrailPos, double discoveredRatio)
-	: CWindowObject(PLAYER_COLORED | BORDERED, "PUZZLE"),
+	: CWindowObject(PLAYER_COLORED | BORDERED, ImagePath::builtin("PUZZLE")),
 	grailPos(GrailPos),
 	currentAlpha(ColorRGBA::ALPHA_OPAQUE)
 {
@@ -36,14 +36,14 @@ CPuzzleWindow::CPuzzleWindow(const int3 & GrailPos, double discoveredRatio)
 
 	CCS->soundh->playSound(soundBase::OBELISK);
 
-	quitb = std::make_shared<CButton>(Point(670, 538), "IOK6432.DEF", CButton::tooltip(CGI->generaltexth->allTexts[599]), std::bind(&CPuzzleWindow::close, this), EShortcut::GLOBAL_RETURN);
+	quitb = std::make_shared<CButton>(Point(670, 538), AnimationPath::builtin("IOK6432.DEF"), CButton::tooltip(CGI->generaltexth->allTexts[599]), std::bind(&CPuzzleWindow::close, this), EShortcut::GLOBAL_RETURN);
 	quitb->setBorderColor(Colors::METALLIC_GOLD);
 
 	mapView = std::make_shared<PuzzleMapView>(Point(8,9), Point(591, 544), grailPos);
 
-	logo = std::make_shared<CPicture>("PUZZLOGO", 607, 3);
+	logo = std::make_shared<CPicture>(ImagePath::builtin("PUZZLOGO"), 607, 3);
 	title = std::make_shared<CLabel>(700, 95, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[463]);
-	resDataBar = std::make_shared<CResDataBar>("ARESBAR.bmp", 3, 575, 32, 2, 85, 85);
+	resDataBar = std::make_shared<CResDataBar>(ImagePath("ARESBAR.bmp"), 3, 575, 32, 2, 85, 85);
 
 	int faction = LOCPLINT->cb->getStartInfo()->playerInfos.find(LOCPLINT->playerID)->second.castle;
 

+ 5 - 5
client/windows/CQuestLog.cpp

@@ -49,7 +49,7 @@ void CQuestLabel::showAll(Canvas & to)
 	CMultiLineLabel::showAll (to);
 }
 
-CQuestIcon::CQuestIcon (const std::string &defname, int index, int x, int y) :
+CQuestIcon::CQuestIcon (const AnimationPath &defname, int index, int x, int y) :
 	CAnimImage(defname, index, 0, x, y)
 {
 	addUsedEvents(LCLICK);
@@ -87,7 +87,7 @@ void CQuestMinimap::addQuestMarks (const QuestInfo * q)
 
 	onMapViewMoved(Rect(), tile.z);
 
-	auto pic = std::make_shared<CQuestIcon>("VwSymbol.def", 3, offset.x, offset.y);
+	auto pic = std::make_shared<CQuestIcon>(AnimationPath::builtin("VwSymbol.def"), 3, offset.x, offset.y);
 
 	pic->moveBy (Point ( -pic->pos.w/2, -pic->pos.h/2));
 	pic->callback = std::bind (&CQuestMinimap::iconClicked, this);
@@ -117,7 +117,7 @@ void CQuestMinimap::showAll(Canvas & to)
 }
 
 CQuestLog::CQuestLog (const std::vector<QuestInfo> & Quests)
-	: CWindowObject(PLAYER_COLORED | BORDERED, "questDialog"),
+	: CWindowObject(PLAYER_COLORED | BORDERED, ImagePath::builtin("questDialog")),
 	questIndex(0),
 	currentQuest(nullptr),
 	hideComplete(false),
@@ -128,9 +128,9 @@ CQuestLog::CQuestLog (const std::vector<QuestInfo> & Quests)
 	minimap = std::make_shared<CQuestMinimap>(Rect(12, 12, 169, 169));
 	// TextBox have it's own 4 pixel padding from top at least for English. To achieve 10px from both left and top only add 6px margin
 	description = std::make_shared<CTextBox>("", Rect(205, 18, 385, DESCRIPTION_HEIGHT_MAX), CSlider::BROWN, FONT_MEDIUM, ETextAlignment::TOPLEFT, Colors::WHITE);
-	ok = std::make_shared<CButton>(Point(539, 398), "IOKAY.DEF", CGI->generaltexth->zelp[445], std::bind(&CQuestLog::close, this), EShortcut::GLOBAL_ACCEPT);
+	ok = std::make_shared<CButton>(Point(539, 398), AnimationPath::builtin("IOKAY.DEF"), CGI->generaltexth->zelp[445], std::bind(&CQuestLog::close, this), EShortcut::GLOBAL_ACCEPT);
 	// Both button and lable are shifted to -2px by x and y to not make them actually look like they're on same line with quests list and ok button
-	hideCompleteButton = std::make_shared<CToggleButton>(Point(10, 396), "sysopchk.def", CButton::tooltipLocalized("vcmi.questLog.hideComplete"), std::bind(&CQuestLog::toggleComplete, this, _1));
+	hideCompleteButton = std::make_shared<CToggleButton>(Point(10, 396), AnimationPath::builtin("sysopchk.def"), CButton::tooltipLocalized("vcmi.questLog.hideComplete"), std::bind(&CQuestLog::toggleComplete, this, _1));
 	hideCompleteLabel = std::make_shared<CLabel>(46, 398, FONT_MEDIUM, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->translate("vcmi.questLog.hideComplete.hover"));
 	slider = std::make_shared<CSlider>(Point(166, 195), 191, std::bind(&CQuestLog::sliderMoved, this, _1), QUEST_COUNT, 0, 0, Orientation::VERTICAL, CSlider::BROWN);
 	slider->setPanningStep(32);

+ 1 - 1
client/windows/CQuestLog.h

@@ -54,7 +54,7 @@ class CQuestIcon : public CAnimImage
 public:
 	std::function<void()> callback; //TODO: merge with other similar classes?
 
-	CQuestIcon(const std::string &defname, int index, int x=0, int y=0);
+	CQuestIcon(const AnimationPath & defname, int index, int x=0, int y=0);
 
 	void clickPressed(const Point & cursorPosition) override;
 	void showAll(Canvas & to) override;

+ 11 - 11
client/windows/CSpellWindow.cpp

@@ -93,7 +93,7 @@ public:
 } spellsorter;
 
 CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _myInt, bool openOnBattleSpells):
-    CWindowObject(PLAYER_COLORED, "SpelBack"),
+	CWindowObject(PLAYER_COLORED, ImagePath::builtin("SpelBack")),
 	battleSpellsOnly(openOnBattleSpells),
 	selectedTab(4),
 	currentPage(0),
@@ -166,23 +166,23 @@ CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _m
 
 	//numbers of spell pages computed
 
-	leftCorner = std::make_shared<CPicture>("SpelTrnL.bmp", 97, 77);
-	rightCorner = std::make_shared<CPicture>("SpelTrnR.bmp", 487, 72);
+	leftCorner = std::make_shared<CPicture>(ImagePath::builtin("SpelTrnL.bmp"), 97, 77);
+	rightCorner = std::make_shared<CPicture>(ImagePath::builtin("SpelTrnR.bmp"), 487, 72);
 
-	spellIcons = std::make_shared<CAnimation>("Spells");
+	spellIcons = std::make_shared<CAnimation>(AnimationPath::builtin("Spells"));
 
-	schoolTab = std::make_shared<CAnimImage>("SpelTab", selectedTab, 0, 524, 88);
-	schoolPicture = std::make_shared<CAnimImage>("Schools", 0, 0, 117, 74);
+	schoolTab = std::make_shared<CAnimImage>(AnimationPath::builtin("SpelTab"), selectedTab, 0, 524, 88);
+	schoolPicture = std::make_shared<CAnimImage>(AnimationPath::builtin("Schools"), 0, 0, 117, 74);
 
-	schoolBorders[0] = std::make_shared<CAnimation>("SplevA.def");
-	schoolBorders[1] = std::make_shared<CAnimation>("SplevF.def");
-	schoolBorders[2] = std::make_shared<CAnimation>("SplevW.def");
-	schoolBorders[3] = std::make_shared<CAnimation>("SplevE.def");
+	schoolBorders[0] = std::make_shared<CAnimation>(AnimationPath::builtin("SplevA.def"));
+	schoolBorders[1] = std::make_shared<CAnimation>(AnimationPath::builtin("SplevF.def"));
+	schoolBorders[2] = std::make_shared<CAnimation>(AnimationPath::builtin("SplevW.def"));
+	schoolBorders[3] = std::make_shared<CAnimation>(AnimationPath::builtin("SplevE.def"));
 
 	for(auto item : schoolBorders)
 		item->preload();
 	mana = std::make_shared<CLabel>(435, 426, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, std::to_string(myHero->mana));
-	statusBar = CGStatusBar::create(7, 569, "Spelroll.bmp");
+	statusBar = CGStatusBar::create(7, 569, ImagePath::builtin("Spelroll.bmp"));
 
 	interactiveAreas.push_back(std::make_shared<InteractiveArea>( Rect( 479 + pos.x, 405 + pos.y, 36, 56), std::bind(&CSpellWindow::fexitb,         this),    460, this));
 	interactiveAreas.push_back(std::make_shared<InteractiveArea>( Rect( 221 + pos.x, 405 + pos.y, 36, 56), std::bind(&CSpellWindow::fbattleSpellsb, this),    453, this));

+ 32 - 32
client/windows/CTradeWindow.cpp

@@ -87,22 +87,22 @@ void CTradeWindow::CTradeableItem::setID(int newID)
 	}
 }
 
-std::string CTradeWindow::CTradeableItem::getFilename()
+AnimationPath CTradeWindow::CTradeableItem::getFilename()
 {
 	switch(type)
 	{
 	case RESOURCE:
-		return "RESOURCE";
+		return AnimationPath::builtin("RESOURCE");
 	case PLAYER:
-		return "CREST58";
+		return AnimationPath::builtin("CREST58");
 	case ARTIFACT_TYPE:
 	case ARTIFACT_PLACEHOLDER:
 	case ARTIFACT_INSTANCE:
-		return "artifact";
+		return AnimationPath::builtin("artifact");
 	case CREATURE:
-		return "TWCRPORT";
+		return AnimationPath::builtin("TWCRPORT");
 	default:
-		return "";
+		return {};
 	}
 }
 
@@ -317,7 +317,7 @@ void CTradeWindow::CTradeableItem::setArtInstance(const CArtifactInstance *art)
 		setID(-1);
 }
 
-CTradeWindow::CTradeWindow(std::string bgName, const IMarket *Market, const CGHeroInstance *Hero, EMarketMode Mode):
+CTradeWindow::CTradeWindow(const ImagePath & bgName, const IMarket *Market, const CGHeroInstance *Hero, EMarketMode Mode):
 	CWindowObject(PLAYER_COLORED, bgName),
 	market(Market),
 	hero(Hero),
@@ -616,23 +616,23 @@ void CTradeWindow::artifactSelected(CHeroArtPlace *slot)
 	selectionChanged(true);
 }
 
-std::string CMarketplaceWindow::getBackgroundForMode(EMarketMode mode)
+ImagePath CMarketplaceWindow::getBackgroundForMode(EMarketMode mode)
 {
 	switch(mode)
 	{
 	case EMarketMode::RESOURCE_RESOURCE:
-		return "TPMRKRES.bmp";
+		return ImagePath::builtin("TPMRKRES.bmp");
 	case EMarketMode::RESOURCE_PLAYER:
-		return "TPMRKPTS.bmp";
+		return ImagePath::builtin("TPMRKPTS.bmp");
 	case EMarketMode::CREATURE_RESOURCE:
-		return "TPMRKCRS.bmp";
+		return ImagePath::builtin("TPMRKCRS.bmp");
 	case EMarketMode::RESOURCE_ARTIFACT:
-		return "TPMRKABS.bmp";
+		return ImagePath::builtin("TPMRKABS.bmp");
 	case EMarketMode::ARTIFACT_RESOURCE:
-		return "TPMRKASS.bmp";
+		return ImagePath::builtin("TPMRKASS.bmp");
 	}
 	assert(0);
-	return "";
+	return {};
 }
 
 CMarketplaceWindow::CMarketplaceWindow(const IMarket * Market, const CGHeroInstance * Hero, EMarketMode Mode)
@@ -685,14 +685,14 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket * Market, const CGHeroInsta
 	initItems(false);
 	initItems(true);
 
-	ok = std::make_shared<CButton>(Point(516, 520), "IOK6432.DEF", CGI->generaltexth->zelp[600], [&](){ close(); }, EShortcut::GLOBAL_RETURN);
-	deal = std::make_shared<CButton>(Point(307, 520), "TPMRKB.DEF", CGI->generaltexth->zelp[595], [&](){ makeDeal(); } );
+	ok = std::make_shared<CButton>(Point(516, 520), AnimationPath::builtin("IOK6432.DEF"), CGI->generaltexth->zelp[600], [&](){ close(); }, EShortcut::GLOBAL_RETURN);
+	deal = std::make_shared<CButton>(Point(307, 520), AnimationPath::builtin("TPMRKB.DEF"), CGI->generaltexth->zelp[595], [&](){ makeDeal(); } );
 	deal->block(true);
 
 	if(sliderNeeded)
 	{
 		slider = std::make_shared<CSlider>(Point(231, 490), 137, std::bind(&CMarketplaceWindow::sliderMoved, this, _1), 0, 0, 0, Orientation::HORIZONTAL);
-		max = std::make_shared<CButton>(Point(229, 520), "IRCBTNS.DEF", CGI->generaltexth->zelp[596], [&](){ setMax(); });
+		max = std::make_shared<CButton>(Point(229, 520), AnimationPath::builtin("IRCBTNS.DEF"), CGI->generaltexth->zelp[596], [&](){ setMax(); });
 		max->block(true);
 	}
 	else
@@ -740,15 +740,15 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket * Market, const CGHeroInsta
 	int specialOffset = mode == EMarketMode::ARTIFACT_RESOURCE ? 35 : 0; //in selling artifacts mode we need to move res-res and art-res buttons down
 
 	if(printButtonFor(EMarketMode::RESOURCE_PLAYER))
-		buttons.push_back(std::make_shared<CButton>(Point(18, 520),"TPMRKBU1.DEF", CGI->generaltexth->zelp[612], [&](){ setMode(EMarketMode::RESOURCE_PLAYER);}));
+		buttons.push_back(std::make_shared<CButton>(Point(18, 520),AnimationPath::builtin("TPMRKBU1.DEF"), CGI->generaltexth->zelp[612], [&](){ setMode(EMarketMode::RESOURCE_PLAYER);}));
 	if(printButtonFor(EMarketMode::RESOURCE_RESOURCE))
-		buttons.push_back(std::make_shared<CButton>(Point(516, 450 + specialOffset),"TPMRKBU5.DEF", CGI->generaltexth->zelp[605], [&](){ setMode(EMarketMode::RESOURCE_RESOURCE);}));
+		buttons.push_back(std::make_shared<CButton>(Point(516, 450 + specialOffset),AnimationPath::builtin("TPMRKBU5.DEF"), CGI->generaltexth->zelp[605], [&](){ setMode(EMarketMode::RESOURCE_RESOURCE);}));
 	if(printButtonFor(EMarketMode::CREATURE_RESOURCE))
-		buttons.push_back(std::make_shared<CButton>(Point(516, 485),"TPMRKBU4.DEF", CGI->generaltexth->zelp[599], [&](){ setMode(EMarketMode::CREATURE_RESOURCE);}));
+		buttons.push_back(std::make_shared<CButton>(Point(516, 485),AnimationPath::builtin("TPMRKBU4.DEF"), CGI->generaltexth->zelp[599], [&](){ setMode(EMarketMode::CREATURE_RESOURCE);}));
 	if(printButtonFor(EMarketMode::RESOURCE_ARTIFACT))
-		buttons.push_back(std::make_shared<CButton>(Point(18, 450 + specialOffset),"TPMRKBU2.DEF", CGI->generaltexth->zelp[598], [&](){ setMode(EMarketMode::RESOURCE_ARTIFACT);}));
+		buttons.push_back(std::make_shared<CButton>(Point(18, 450 + specialOffset),AnimationPath::builtin("TPMRKBU2.DEF"), CGI->generaltexth->zelp[598], [&](){ setMode(EMarketMode::RESOURCE_ARTIFACT);}));
 	if(printButtonFor(EMarketMode::ARTIFACT_RESOURCE))
-		buttons.push_back(std::make_shared<CButton>(Point(18, 485),"TPMRKBU3.DEF", CGI->generaltexth->zelp[613], [&](){ setMode(EMarketMode::ARTIFACT_RESOURCE);}));
+		buttons.push_back(std::make_shared<CButton>(Point(18, 485),AnimationPath::builtin("TPMRKBU3.DEF"), CGI->generaltexth->zelp[613], [&](){ setMode(EMarketMode::ARTIFACT_RESOURCE);}));
 
 	updateTraderText();
 }
@@ -1076,7 +1076,7 @@ void CMarketplaceWindow::updateTraderText()
 }
 
 CAltarWindow::CAltarWindow(const IMarket * Market, const CGHeroInstance * Hero, EMarketMode Mode)
-	: CTradeWindow((Mode == EMarketMode::CREATURE_EXP ? "ALTARMON.bmp" : "ALTRART2.bmp"), Market, Hero, Mode)
+	: CTradeWindow(ImagePath::builtin(Mode == EMarketMode::CREATURE_EXP ? "ALTARMON.bmp" : "ALTRART2.bmp"), Market, Hero, Mode)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 
@@ -1093,10 +1093,10 @@ CAltarWindow::CAltarWindow(const IMarket * Market, const CGHeroInstance * Hero,
 		new CTextBox(CGI->generaltexth->allTexts[480], Rect(320, 56, 256, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW);
 
 		slider = std::make_shared<CSlider>(Point(231, 481), 137, std::bind(&CAltarWindow::sliderMoved, this, _1), 0, 0, 0, Orientation::HORIZONTAL);
-		max = std::make_shared<CButton>(Point(147, 520), "IRCBTNS.DEF", CGI->generaltexth->zelp[578], std::bind(&CSlider::scrollToMax, slider));
+		max = std::make_shared<CButton>(Point(147, 520), AnimationPath::builtin("IRCBTNS.DEF"), CGI->generaltexth->zelp[578], std::bind(&CSlider::scrollToMax, slider));
 
 		sacrificedUnits.resize(GameConstants::ARMY_SIZE, 0);
-		sacrificeAll = std::make_shared<CButton>(Point(393, 520), "ALTARMY.DEF", CGI->generaltexth->zelp[579], std::bind(&CAltarWindow::SacrificeAll,this));
+		sacrificeAll = std::make_shared<CButton>(Point(393, 520), AnimationPath::builtin("ALTARMY.DEF"), CGI->generaltexth->zelp[579], std::bind(&CAltarWindow::SacrificeAll,this));
 
 		initItems(true);
 		mimicCres();
@@ -1108,9 +1108,9 @@ CAltarWindow::CAltarWindow(const IMarket * Market, const CGHeroInstance * Hero,
 		//%s's Creatures
 		labels.push_back(std::make_shared<CLabel>(302, 423, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[478]));
 
-		sacrificeAll = std::make_shared<CButton>(Point(393, 520), "ALTFILL.DEF", CGI->generaltexth->zelp[571], std::bind(&CAltarWindow::SacrificeAll,this));
+		sacrificeAll = std::make_shared<CButton>(Point(393, 520), AnimationPath::builtin("ALTFILL.DEF"), CGI->generaltexth->zelp[571], std::bind(&CAltarWindow::SacrificeAll,this));
 		sacrificeAll->block(hero->artifactsInBackpack.empty() && hero->artifactsWorn.empty());
-		sacrificeBackpack = std::make_shared<CButton>(Point(147, 520), "ALTEMBK.DEF", CGI->generaltexth->zelp[570], std::bind(&CAltarWindow::SacrificeBackpack,this));
+		sacrificeBackpack = std::make_shared<CButton>(Point(147, 520), AnimationPath::builtin("ALTEMBK.DEF"), CGI->generaltexth->zelp[570], std::bind(&CAltarWindow::SacrificeBackpack,this));
 		sacrificeBackpack->block(hero->artifactsInBackpack.empty());
 
 		arts = std::make_shared<CArtifactsOfHeroAltar>(Point(-365, -12));
@@ -1119,7 +1119,7 @@ CAltarWindow::CAltarWindow(const IMarket * Market, const CGHeroInstance * Hero,
 
 		initItems(true);
 		initItems(false);
-		artIcon = std::make_shared<CAnimImage>("ARTIFACT", 0, 0, 281, 442);
+		artIcon = std::make_shared<CAnimImage>(AnimationPath::builtin("ARTIFACT"), 0, 0, 281, 442);
 		artIcon->disable();
 	}
 
@@ -1130,20 +1130,20 @@ CAltarWindow::CAltarWindow(const IMarket * Market, const CGHeroInstance * Hero,
 
 	statusBar = CGStatusBar::create(std::make_shared<CPicture>(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
 
-	ok = std::make_shared<CButton>(Point(516, 520), "IOK6432.DEF", CGI->generaltexth->zelp[568], [&](){ close();}, EShortcut::GLOBAL_RETURN);
+	ok = std::make_shared<CButton>(Point(516, 520), AnimationPath::builtin("IOK6432.DEF"), CGI->generaltexth->zelp[568], [&](){ close();}, EShortcut::GLOBAL_RETURN);
 
-	deal = std::make_shared<CButton>(Point(269, 520), "ALTSACR.DEF", CGI->generaltexth->zelp[585], std::bind(&CAltarWindow::makeDeal,this));
+	deal = std::make_shared<CButton>(Point(269, 520), AnimationPath::builtin("ALTSACR.DEF"), CGI->generaltexth->zelp[585], std::bind(&CAltarWindow::makeDeal,this));
 
 	if(Mode == EMarketMode::CREATURE_EXP)
 	{
-		auto changeMode = std::make_shared<CButton>(Point(516, 421), "ALTART.DEF", CGI->generaltexth->zelp[580], std::bind(&CTradeWindow::setMode,this, EMarketMode::ARTIFACT_EXP));
+		auto changeMode = std::make_shared<CButton>(Point(516, 421), AnimationPath::builtin("ALTART.DEF"), CGI->generaltexth->zelp[580], std::bind(&CTradeWindow::setMode,this, EMarketMode::ARTIFACT_EXP));
 		if(Hero->getAlignment() == ::EAlignment::EVIL)
 			changeMode->block(true);
 		buttons.push_back(changeMode);
 	}
 	else if(Mode == EMarketMode::ARTIFACT_EXP)
 	{
-		auto changeMode = std::make_shared<CButton>(Point(516, 421), "ALTSACC.DEF", CGI->generaltexth->zelp[572], std::bind(&CTradeWindow::setMode,this, EMarketMode::CREATURE_EXP));
+		auto changeMode = std::make_shared<CButton>(Point(516, 421), AnimationPath::builtin("ALTSACC.DEF"), CGI->generaltexth->zelp[572], std::bind(&CTradeWindow::setMode,this, EMarketMode::CREATURE_EXP));
 		if(Hero->getAlignment() == ::EAlignment::GOOD)
 			changeMode->block(true);
 		buttons.push_back(changeMode);

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio