Browse Source

* Separated map loading from the map object * Moved map classes to lib/Map * Renamed map.h/cpp to CMap.h/cpp * Profiling of map loading is now optional * Updated CMemoryStream

beegee1 13 years ago
parent
commit
a878f5f79a

+ 1 - 1
AI/VCAI/VCAI.h

@@ -14,7 +14,7 @@
 #include "../../lib/CObjectHandler.h"
 #include "../../lib/Connection.h"
 #include "../../lib/CGameState.h"
-#include "../../lib/map.h"
+#include "../../lib/Map/CMap.h"
 #include "../../lib/NetPacks.h"
 #include "../../lib/CondSh.h"
 #include "../../lib/CStopWatch.h"

+ 1 - 1
CCallback.cpp

@@ -7,7 +7,7 @@
 #include "lib/BattleState.h"
 #include "client/CPlayerInterface.h"
 #include "client/Client.h"
-#include "lib/map.h"
+#include "lib/Map/CMap.h"
 #include "lib/CBuildingHandler.h"
 #include "lib/CDefObjInfoHandler.h"
 #include "lib/CGeneralTextHandler.h"

+ 1 - 1
client/AdventureMapClasses.cpp

@@ -4,7 +4,7 @@
 #include "../CCallback.h"
 #include "../lib/JsonNode.h"
 #include "../lib/Filesystem/CResourceLoader.h"
-#include "../lib/map.h"
+#include "../lib/Map/CMap.h"
 #include "../lib/CModHandler.h"
 #include "../lib/CObjectHandler.h"
 #include "../lib/CGameState.h"

+ 1 - 1
client/BattleInterface/CBattleInterface.cpp

@@ -24,7 +24,7 @@
 #include "../CCreatureWindow.h"
 #include "../CVideoHandler.h"
 #include "../../lib/CTownHandler.h"
-#include "../../lib/map.h"
+#include "../../lib/Map/CMap.h"
 
 #include "CBattleAnimations.h"
 #include "CBattleInterfaceClasses.h"

+ 1 - 1
client/CAdvmapInterface.cpp

@@ -19,7 +19,7 @@
 #include "../lib/CHeroHandler.h"
 #include "../lib/CObjectHandler.h"
 #include "../lib/CTownHandler.h"
-#include "../lib/map.h"
+#include "../lib/Map/CMap.h"
 #include "../lib/JsonNode.h"
 #include "mapHandler.h"
 #include "CPreGame.h"

+ 1 - 1
client/CPlayerInterface.cpp

@@ -30,7 +30,7 @@
 #include "CMusicHandler.h"
 #include "../lib/CondSh.h"
 #include "../lib/NetPacks.h"
-#include "../lib/map.h"
+#include "../lib/Map/CMap.h"
 #include "../lib/VCMIDirs.h"
 #include "mapHandler.h"
 #include "../lib/CStopWatch.h"

+ 27 - 34
client/CPreGame.cpp

@@ -16,7 +16,7 @@
 #include "../lib/CTownHandler.h"
 #include "../lib/CHeroHandler.h"
 #include "../lib/CObjectHandler.h"
-#include "../lib/CCampaignHandler.h"
+#include "../lib/Map/CCampaignHandler.h"
 #include "../lib/CCreatureHandler.h"
 #include "../lib/JsonNode.h"
 #include "CMusicHandler.h"
@@ -24,7 +24,7 @@
 #include "Graphics.h"
 #include "../lib/Connection.h"
 #include "../lib/VCMIDirs.h"
-#include "../lib/map.h"
+#include "../lib/Map/CMap.h"
 #include "GUIClasses.h"
 #include "CPlayerInterface.h"
 #include "../CCallback.h"
@@ -41,6 +41,7 @@
 #include "../lib/GameConstants.h"
 #include "UIFramework/CGuiHandler.h"
 #include "UIFramework/CIntObjectClasses.h"
+#include "../lib/Map/CMapService.h"
 
 /*
  * CPreGame.cpp, part of VCMI engine
@@ -100,9 +101,8 @@ static void do_quit()
 
 static CMapInfo *mapInfoFromGame()
 {
-	CMapInfo *ret = new CMapInfo();
-	CMapHeader *headerCopy = new CMapHeader(*LOCPLINT->cb->getMapHeader()); //will be deleted by CMapInfo d-tor
-	ret->setHeader(headerCopy);
+    CMapInfo * ret = new CMapInfo();
+    ret->mapHeader = std::unique_ptr<CMapHeader>(new CMapHeader(*LOCPLINT->cb->getMapHeader()));
 	return ret;
 }
 
@@ -771,7 +771,7 @@ void CSelectionScreen::changeSelection( const CMapInfo *to )
 	   SEL->sInfo.difficulty = to->scenarioOpts->difficulty;
 	if(screenType != CMenuScreen::campaignList)
 	{
-		updateStartInfo(to ? to->fileURI : "", sInfo, to ? to->mapHeader : NULL);
+        updateStartInfo(to ? to->fileURI : "", sInfo, to ? to->mapHeader.get() : NULL);
 	}
 	card->changeSelection(to);
 	if(screenType != CMenuScreen::campaignList)
@@ -1036,31 +1036,24 @@ std::vector<ResourceID> SelectionTab::getFiles(std::string dirURI, int resType)
 		++iterator;
 	}
 
-	allItems.resize(ret.size());
 	return ret;
 }
 
-void SelectionTab::parseMaps(const std::vector<ResourceID> &files, int start, int threads)
+void SelectionTab::parseMaps(const std::vector<ResourceID> & files)
 {
-	ui8 mapBuffer[1500];
-
-	while(start < allItems.size())
+    allItems.clear();
+    for(int i = 0; i < files.size(); ++i)
 	{
-		try
-		{
-			TInputStreamPtr stream(CMap::getMapStream(files[start].getName()));
-			int read = stream->read(mapBuffer, 1500);
-
-			if(read < 50  ||  !mapBuffer[4])
-				throw std::runtime_error("corrupted map file");
-
-			allItems[start].mapInit(files[start].getName(), mapBuffer);
-		}
-		catch(std::exception &e)
-		{
-			tlog3 << "\t\tWarning: failed to load map " << files[start].getName() << ": " << e.what() << std::endl;
-		}
-		start += threads;
+        try
+        {
+            CMapInfo mapInfo;
+            mapInfo.mapInit(files[i].getName());
+            allItems.push_back(std::move(mapInfo));
+        }
+        catch(std::exception & e)
+        {
+            tlog2 << "Map " << files[i].getName() << " is invalid. Message: " << e.what() << std::endl;
+        }
 	}
 }
 
@@ -1077,7 +1070,7 @@ void SelectionTab::parseGames(const std::vector<ResourceID> &files, bool multi)
 			if(std::memcmp(sign,"VCMISVG",7))
 				throw std::runtime_error("not a correct savefile!");
 
-			allItems[i].mapHeader = new CMapHeader();
+            allItems[i].mapHeader = std::unique_ptr<CMapHeader>(new CMapHeader);
 			lf >> *(allItems[i].mapHeader) >> allItems[i].scenarioOpts;
 			allItems[i].fileURI = files[i].getName();
 			allItems[i].countPlayers();
@@ -1086,12 +1079,12 @@ void SelectionTab::parseGames(const std::vector<ResourceID> &files, bool multi)
 
 			if((allItems[i].actualHumanPlayers > 1) != multi) //if multi mode then only multi games, otherwise single
 			{
-				vstd::clear_pointer(allItems[i].mapHeader);
+                allItems[i].mapHeader.reset(nullptr);
 			}
 		}
 		catch(std::exception &e)
 		{
-			vstd::clear_pointer(allItems[i].mapHeader);
+            allItems[i].mapHeader.reset(nullptr);
 			tlog3 << "Failed to process " << files[i].getName() <<": " << e.what() << std::endl;
 		}
 	}
@@ -2612,8 +2605,8 @@ CScenarioInfo::~CScenarioInfo()
 
 bool mapSorter::operator()(const CMapInfo *aaa, const CMapInfo *bbb)
 {
-	const CMapHeader * a = aaa->mapHeader,
-		* b = bbb->mapHeader;
+    const CMapHeader * a = aaa->mapHeader.get(),
+            * b = bbb->mapHeader.get();
 	if(a && b) //if we are sorting scenarios
 	{
 		switch (sortBy)
@@ -2949,10 +2942,10 @@ void CBonusSelection::selectMap( int whichOne )
 	ourCampaign->currentMap = whichOne;
 
 	//get header
-	int i = 0;
 	delete ourHeader;
-	ourHeader = new CMapHeader();
-	ourHeader->initFromMemory((const unsigned char*)ourCampaign->camp->mapPieces.find(whichOne)->second.data(), i);
+    std::string & headerStr = ourCampaign->camp->mapPieces.find(whichOne)->second;
+    auto buffer = reinterpret_cast<const ui8 *>(headerStr.data());
+    ourHeader = CMapService::loadMapHeader(buffer, headerStr.size()).release();
 
 	std::map<TPlayerColor, std::string> names;
 	names[1] = settings["general"]["playerName"].String();

+ 2 - 2
client/CPreGame.h

@@ -5,7 +5,7 @@
 #include "../lib/StartInfo.h"
 #include "GUIClasses.h"
 #include "FunctionList.h"
-#include "../lib/CMapInfo.h"
+#include "../lib/Map/CMapInfo.h"
 
 /*
  * CPreGame.h, part of VCMI engine
@@ -142,7 +142,7 @@ class SelectionTab : public CIntObject
 private:
 	CDefHandler *format; //map size
 
-	void parseMaps(const std::vector<ResourceID> &files, int start = 0, int threads = 1);
+    void parseMaps(const std::vector<ResourceID> &files);
 	void parseGames(const std::vector<ResourceID> &files, bool multi);
 	void parseCampaigns(const std::vector<ResourceID> & files );
 	std::vector<ResourceID> getFiles(std::string dirURI, int resType);

+ 2 - 2
client/Client.cpp

@@ -1,7 +1,7 @@
 #include "StdInc.h"
 
 #include "CMusicHandler.h"
-#include "../lib/CCampaignHandler.h"
+#include "../lib/Map/CCampaignHandler.h"
 #include "../CCallback.h"
 #include "../lib/CConsoleHandler.h"
 #include "CGameInfo.h"
@@ -23,7 +23,7 @@
 #include "../lib/NetPacks.h"
 #include "../lib/VCMI_Lib.h"
 #include "../lib/VCMIDirs.h"
-#include "../lib/map.h"
+#include "../lib/Map/CMap.h"
 #include "../lib/JsonNode.h"
 #include "mapHandler.h"
 #include "../lib/CConfigHandler.h"

+ 1 - 1
client/GUIClasses.cpp

@@ -26,7 +26,7 @@
 #include "../lib/CSpellHandler.h"
 #include "../lib/CTownHandler.h"
 #include "../lib/CondSh.h"
-#include "../lib/map.h"
+#include "../lib/Map/CMap.h"
 #include "mapHandler.h"
 #include "../lib/CStopWatch.h"
 #include "../lib/NetPacks.h"

+ 2 - 2
client/NetPacksClient.cpp

@@ -13,7 +13,7 @@
 #include "../lib/CHeroHandler.h"
 #include "../lib/CObjectHandler.h"
 #include "../lib/VCMI_Lib.h"
-#include "../lib/map.h"
+#include "../lib/Map/CMap.h"
 #include "../lib/VCMIDirs.h"
 #include "../lib/CSpellHandler.h"
 #include "CSoundBase.h"
@@ -22,7 +22,7 @@
 #include "../lib/CConfigHandler.h"
 #include "UIFramework/SDL_Extensions.h"
 #include "BattleInterface/CBattleInterface.h"
-#include "../lib/CCampaignHandler.h"
+#include "../lib/Map/CCampaignHandler.h"
 #include "../lib/CGameState.h"
 #include "../lib/BattleState.h"
 #include "../lib/GameConstants.h"

+ 1 - 1
client/mapHandler.cpp

@@ -9,7 +9,7 @@
 #include "../lib/CTownHandler.h"
 #include "Graphics.h"
 #include "../lib/CObjectHandler.h"
-#include "../lib/map.h"
+#include "../lib/Map/CMap.h"
 #include "CDefHandler.h"
 #include "../lib/CConfigHandler.h"
 #include "../lib/CGeneralTextHandler.h"

+ 10 - 7
lib/CGameState.cpp

@@ -2,7 +2,7 @@
 #include "CGameState.h"
 
 #include <boost/random/linear_congruential.hpp>
-#include "CCampaignHandler.h"
+#include "Map/CCampaignHandler.h"
 #include "CDefObjInfoHandler.h"
 #include "CArtHandler.h"
 #include "CBuildingHandler.h"
@@ -15,11 +15,12 @@
 #include "CModHandler.h"
 #include "VCMI_Lib.h"
 #include "Connection.h"
-#include "map.h"
+#include "Map/CMap.h"
+#include "Map/CMapService.h"
 #include "StartInfo.h"
 #include "NetPacks.h"
 #include "RegisterTypes.h"
-#include "CMapInfo.h"
+#include "Map/CMapInfo.h"
 #include "BattleState.h"
 #include "JsonNode.h"
 #include "Filesystem/CResourceLoader.h"
@@ -865,16 +866,18 @@ void CGameState::init(StartInfo * si)
 	switch(scenarioOps->mode)
 	{
 	case StartInfo::NEW_GAME:
-        map = new CMap(scenarioOps->mapname);
+        tlog0 << "Open map file: " << scenarioOps->mapname << std::endl;
+        map = CMapService::loadMap(scenarioOps->mapname).release();
 		break;
 	case StartInfo::CAMPAIGN:
 		{
+            tlog0 << "Open campaign map file: " << scenarioOps->campState->currentMap << std::endl;
 			auto campaign = scenarioOps->campState;
 			assert(vstd::contains(campaign->camp->mapPieces, scenarioOps->campState->currentMap));
 
-			std::string &mapContent = campaign->camp->mapPieces[scenarioOps->campState->currentMap];
-            map = new CMap();
-			map->initFromBytes((const ui8*)mapContent.c_str(), mapContent.size());
+            std::string & mapContent = campaign->camp->mapPieces[scenarioOps->campState->currentMap];
+            auto buffer = reinterpret_cast<const ui8 *>(mapContent.data());
+            map = CMapService::loadMap(buffer, mapContent.size()).release();
 		}
 		break;
 	case StartInfo::DUEL:

+ 1 - 1
lib/CGameState.h

@@ -5,7 +5,7 @@
 #ifndef _MSC_VER
 #include "CCreatureHandler.h"
 #include "VCMI_Lib.h"
-#include "map.h"
+#include "Map/CMap.h"
 #endif
 
 #include "HeroBonus.h"

+ 4 - 3
lib/CMakeLists.txt

@@ -13,13 +13,16 @@ set(lib_SRCS
         Filesystem/CResourceLoader.cpp
         Filesystem/CFileInputStream.cpp
         Filesystem/CCompressedStream.cpp
+        Map/CCampaignHandler.cpp
+        Map/CMap.cpp
+        Map/CMapInfo.cpp
+        Map/CMapService.cpp
         BattleAction.cpp
         BattleHex.cpp
         BattleState.cpp
         CArtHandler.cpp
         CBattleCallback.cpp
         CBuildingHandler.cpp
-        CCampaignHandler.cpp
         CConfigHandler.cpp
         CConsoleHandler.cpp
         CCreatureHandler.cpp
@@ -30,7 +33,6 @@ set(lib_SRCS
         CGeneralTextHandler.cpp
         CHeroHandler.cpp
         CLogger.cpp
-        CMapInfo.cpp
         CModHandler.cpp
         CObjectHandler.cpp
         CObstacleInstance.cpp
@@ -41,7 +43,6 @@ set(lib_SRCS
         HeroBonus.cpp
         IGameCallback.cpp
         JsonNode.cpp
-        map.cpp
         NetPacksLib.cpp
         ResourceSet.cpp
         VCMI_Lib.cpp

+ 0 - 71
lib/CMapInfo.cpp

@@ -1,71 +0,0 @@
-#include "StdInc.h"
-#include "CMapInfo.h"
-
-#include "StartInfo.h"
-#include "map.h"
-#include "CCampaignHandler.h"
-#include "GameConstants.h"
-
-void CMapInfo::countPlayers()
-{
-	actualHumanPlayers = playerAmnt = humanPlayers = 0;
-	for(int i=0;i<GameConstants::PLAYER_LIMIT;i++)
-	{
-		if(mapHeader->players[i].canHumanPlay)
-		{
-			playerAmnt++;
-			humanPlayers++;
-		}
-		else if(mapHeader->players[i].canComputerPlay)
-		{
-			playerAmnt++;
-		}
-	}
-
-	if(scenarioOpts)
-		for (auto i = scenarioOpts->playerInfos.cbegin(); i != scenarioOpts->playerInfos.cend(); i++)
-			if(i->second.human)
-				actualHumanPlayers++;
-}
-
-CMapInfo::CMapInfo(bool map)
-	: mapHeader(NULL), campaignHeader(NULL), scenarioOpts(NULL)
-{
-}
-
-void CMapInfo::mapInit(const std::string &fname, const ui8 *map )
-{
-	fileURI = fname;
-	int i = 0;
-	mapHeader = new CMapHeader();
-    mapHeader->version = EMapFormat::INVALID;
-
-	try
-	{
-		mapHeader->initFromMemory(map, i);
-		countPlayers();
-	}
-	catch (const std::exception &e)
-	{
-		tlog1 << "\t\tWarning: evil map file: " << fname << ": " << e.what() << std::endl; 
-		delete mapHeader;
-		mapHeader = NULL;
-	}
-}
-
-CMapInfo::~CMapInfo()
-{
-	delete mapHeader;
-	delete campaignHeader;
-}
-
-void CMapInfo::campaignInit()
-{
-	campaignHeader = new CCampaignHeader( CCampaignHandler::getHeader(fileURI) );
-}
-
-void CMapInfo::setHeader(CMapHeader *header)
-{
-	mapHeader = header;
-}
-

+ 0 - 35
lib/CMapInfo.h

@@ -1,35 +0,0 @@
-#pragma once
-
-
-
-class CMapHeader;
-class CCampaignHeader;
-struct StartInfo;
-
-/// A class which stores the count of human players and all players, the filename,
-/// scenario options, the map header information,...
-class DLL_LINKAGE CMapInfo
-{
-public:
-	CMapHeader * mapHeader; //may be NULL if campaign
-	CCampaignHeader * campaignHeader; //may be NULL if scenario
-	StartInfo *scenarioOpts; //options with which scenario has been started (used only with saved games)
-	std::string fileURI;
-	std::string date;
-	int playerAmnt, //players in map
-		humanPlayers; //players ALLOWED to be controlled by human
-	int actualHumanPlayers; // >1 if multiplayer game
-	CMapInfo(bool map = true);
-	~CMapInfo();
-	//CMapInfo(const std::string &fname, const ui8 *map);
-	void setHeader(CMapHeader *header);
-	void mapInit(const std::string &fname, const ui8 *map);
-	void campaignInit();
-	void countPlayers();
-
-	template <typename Handler> void serialize(Handler &h, const int Version)
-	{
-		h & mapHeader & campaignHeader & scenarioOpts & fileURI & date & playerAmnt & humanPlayers;
-		h & actualHumanPlayers;
-	}
-};

+ 1 - 1
lib/CObjectHandler.cpp

@@ -16,7 +16,7 @@
 #include "CGameState.h"
 #include "NetPacks.h"
 #include "StartInfo.h"
-#include "map.h"
+#include "Map/CMap.h"
 #include <SDL_stdinc.h>
 #include "CBuildingHandler.h"
 #include "JsonNode.h"

+ 3 - 3
lib/Connection.cpp

@@ -6,11 +6,11 @@
 #endif
 
 //for smart objs serialization over net
-#include "../lib/CMapInfo.h"
+#include "../lib/Map/CMapInfo.h"
 #include "StartInfo.h"
 #include "BattleState.h"
 #include "CGameState.h"
-#include "map.h"
+#include "Map/CMap.h"
 #include "CModHandler.h"
 #include "CObjectHandler.h"
 #include "CCreatureHandler.h"
@@ -19,7 +19,7 @@
 #include "CHeroHandler.h"
 #include "CSpellHandler.h"
 #include "CTownHandler.h"
-#include "CCampaignHandler.h"
+#include "Map/CCampaignHandler.h"
 #include "NetPacks.h"
 
 #include <boost/asio.hpp>

+ 1 - 1
lib/Connection.h

@@ -23,7 +23,7 @@
 #include "ConstTransitivePtr.h"
 #include "CCreatureSet.h" //for CStackInstance
 #include "CObjectHandler.h" //for CArmedInstance
-#include "CCampaignHandler.h" //for CCampaignState
+#include "Map/CCampaignHandler.h" //for CCampaignState
 
 const ui32 version = 733;
 const TSlot COMMANDER_SLOT_PLACEHOLDER = -2;

+ 3 - 3
lib/Filesystem/CFileInputStream.cpp

@@ -49,9 +49,9 @@ si64 CFileInputStream::read(ui8 * data, si64 size)
 
 si64 CFileInputStream::seek(si64 position)
 {
-	fileStream.seekg(dataStart + std::min(position, dataSize));
-
-	return tell();
+    si64 origin = tell();
+    fileStream.seekg(dataStart + std::min(position, dataSize));
+    return tell() - origin;
 }
 
 si64 CFileInputStream::tell()

+ 12 - 20
lib/Filesystem/CMemoryStream.cpp

@@ -1,45 +1,37 @@
 #include "StdInc.h"
 #include "CMemoryStream.h"
 
-CMemoryStream::CMemoryStream(const ui8 * data, si64 size, bool freeData /*= false*/):
-    data(data),
-    size(size),
-    position(0),
-    freeData(freeData)
+CMemoryStream::CMemoryStream(const ui8 * data, si64 size) :
+    data(data), size(size), position(0)
 {
-}
 
-CMemoryStream::~CMemoryStream()
-{
-	if(freeData)
-	{
-		delete[] data;
-	}
 }
 
 si64 CMemoryStream::read(ui8 * data, si64 size)
 {
-	std::copy(this->data + position, this->data + position + size, data);
+    si64 toRead = std::min(this->size - tell(), size);
+    std::copy(this->data + position, this->data + position + toRead, data);
 	position += size;
-	return size;
+    return toRead;
 }
 
 si64 CMemoryStream::seek(si64 position)
 {
-	si64 diff = this->position;
-	this->position = position;
-	return position - diff;
+    si64 origin = tell();
+    this->position = std::min(position, size);
+    return tell() - origin;
 }
 
 si64 CMemoryStream::tell()
 {
-	return this->position;
+    return this->position;
 }
 
 si64 CMemoryStream::skip(si64 delta)
 {
-	this->position += delta;
-	return delta;
+    si64 origin = tell();
+    this->position += std::min(size - origin, delta);
+    return tell() - origin;
 }
 
 si64 CMemoryStream::getSize()

+ 5 - 14
lib/Filesystem/CMemoryStream.h

@@ -20,18 +20,12 @@ class DLL_LINKAGE CMemoryStream : public CInputStream
 {
 public:
 	/**
-	 * C-tor. The data buffer will be freed by the stream's destructor.
+     * C-tor. The data buffer won't be free'd. (no ownership)
 	 *
-	 * @param data A pointer to the data array.
+     * @param data a pointer to the data array.
 	 * @param size The size in bytes of the array.
-	 * @param freeData Flag which specifies if the data array should be freed in the memory stream's destructor.
 	 */
-	CMemoryStream(const ui8 * data, si64 size, bool freeData);
-
-	/**
-	 * D-tor. Frees the data array if the freeData flag was set to true.
-	 */
-	~CMemoryStream();
+    CMemoryStream(const ui8 * data, si64 size);
 
 	/**
 	 * Reads n bytes from the stream into the data buffer.
@@ -73,15 +67,12 @@ public:
 	si64 getSize();
 
 private:
-	/** A pointer to the data array. */
-	const ui8 * data;
+    /** A pointer to the data array. */
+    const ui8 * data;
 
 	/** The size in bytes of the array. */
 	si64 size;
 
 	/** Current reading position of the stream. */
 	si64 position;
-
-	/** Flag which specifies if the data array should be freed in the memory stream's destructor. */
-	bool freeData;
 };

+ 1 - 2
lib/Filesystem/CResourceLoader.h

@@ -330,8 +330,7 @@ public:
 	 */
 	void addLoader(std::string mountPoint, shared_ptr<ISimpleResourceLoader> loader, bool writeable);
 
-	public:
-
+private:
 	/**
 	 * Contains lists of same resources which can be accessed uniquely by an
 	 * resource identifier.

+ 1 - 1
lib/IGameCallback.cpp

@@ -4,7 +4,7 @@
 #include <boost/random/linear_congruential.hpp>
 
 #include "CGameState.h"
-#include "map.h"
+#include "Map/CMap.h"
 #include "CObjectHandler.h"
 #include "CHeroHandler.h"
 #include "StartInfo.h"

+ 9 - 9
lib/CCampaignHandler.cpp → lib/Map/CCampaignHandler.cpp

@@ -1,15 +1,15 @@
 #include "StdInc.h"
 #include "CCampaignHandler.h"
 
-#include "Filesystem/CResourceLoader.h"
-#include "Filesystem/CCompressedStream.h"
-#include "../lib/VCMI_Lib.h"
-#include "../lib/vcmi_endian.h"
-#include "CGeneralTextHandler.h"
-#include "StartInfo.h"
-#include "CArtHandler.h" //for hero crossover
-#include "CObjectHandler.h" //for hero crossover
-#include "CHeroHandler.h"
+#include "../Filesystem/CResourceLoader.h"
+#include "../Filesystem/CCompressedStream.h"
+#include "../VCMI_Lib.h"
+#include "../vcmi_endian.h"
+#include "../CGeneralTextHandler.h"
+#include "../StartInfo.h"
+#include "../CArtHandler.h" //for hero crossover
+#include "../CObjectHandler.h" //for hero crossover
+#include "../CHeroHandler.h"
 
 namespace fs = boost::filesystem;
 

+ 0 - 0
lib/CCampaignHandler.h → lib/Map/CCampaignHandler.h


+ 241 - 0
lib/Map/CMap.cpp

@@ -0,0 +1,241 @@
+#include "StdInc.h"
+#include "CMap.h"
+
+#include "../CObjectHandler.h"
+#include "../CArtHandler.h"
+
+PlayerInfo::PlayerInfo(): p7(0), p8(0), p9(0), canHumanPlay(0), canComputerPlay(0),
+    AITactic(0), isFactionRandom(0),
+    mainHeroPortrait(0), hasMainTown(0), generateHeroAtMainTown(0),
+    team(255), generateHero(0)
+{
+
+}
+
+si8 PlayerInfo::defaultCastle() const
+{
+    assert(!allowedFactions.empty()); // impossible?
+
+    if(allowedFactions.size() == 1)
+    {
+        // only one faction is available - pick it
+        return *allowedFactions.begin();
+    }
+
+    // set to random
+    return -1;
+}
+
+si8 PlayerInfo::defaultHero() const
+{
+    // we will generate hero in front of main town
+    if((generateHeroAtMainTown && hasMainTown) || p8)
+    {
+        //random hero
+        return -1;
+    }
+
+    return -2;
+}
+
+CMapHeader::CMapHeader() : version(EMapFormat::INVALID)
+{
+    areAnyPLayers = difficulty = levelLimit = howManyTeams = 0;
+    height = width = twoLevel = -1;
+}
+
+CMapHeader::~CMapHeader()
+{
+
+}
+
+void CMap::removeBlockVisTiles(CGObjectInstance * obj, bool total)
+{
+    for(int fx=0; fx<8; ++fx)
+    {
+        for(int fy=0; fy<6; ++fy)
+        {
+            int xVal = obj->pos.x + fx - 7;
+            int yVal = obj->pos.y + fy - 5;
+            int zVal = obj->pos.z;
+            if(xVal>=0 && xVal<width && yVal>=0 && yVal<height)
+            {
+                TerrainTile & curt = terrain[xVal][yVal][zVal];
+                if(total || ((obj->defInfo->visitMap[fy] >> (7 - fx)) & 1))
+                {
+                    curt.visitableObjects -= obj;
+                    curt.visitable = curt.visitableObjects.size();
+                }
+                if(total || !((obj->defInfo->blockMap[fy] >> (7 - fx)) & 1))
+                {
+                    curt.blockingObjects -= obj;
+                    curt.blocked = curt.blockingObjects.size();
+                }
+            }
+        }
+    }
+}
+void CMap::addBlockVisTiles(CGObjectInstance * obj)
+{
+    for(int fx=0; fx<8; ++fx)
+    {
+        for(int fy=0; fy<6; ++fy)
+        {
+            int xVal = obj->pos.x + fx - 7;
+            int yVal = obj->pos.y + fy - 5;
+            int zVal = obj->pos.z;
+            if(xVal>=0 && xVal<width && yVal>=0 && yVal<height)
+            {
+                TerrainTile & curt = terrain[xVal][yVal][zVal];
+                if(((obj->defInfo->visitMap[fy] >> (7 - fx)) & 1))
+                {
+                    curt.visitableObjects.push_back(obj);
+                    curt.visitable = true;
+                }
+                if(!((obj->defInfo->blockMap[fy] >> (7 - fx)) & 1))
+                {
+                    curt.blockingObjects.push_back(obj);
+                    curt.blocked = true;
+                }
+            }
+        }
+    }
+}
+
+CMap::CMap() : terrain(nullptr)
+{
+
+}
+
+CMap::~CMap()
+{
+    if(terrain)
+    {
+        for(int ii=0;ii<width;ii++)
+        {
+            for(int jj=0;jj<height;jj++)
+                delete [] terrain[ii][jj];
+            delete [] terrain[ii];
+        }
+        delete [] terrain;
+    }
+
+    for(std::list<ConstTransitivePtr<CMapEvent> >::iterator i = events.begin(); i != events.end(); i++)
+    {
+        i->dellNull();
+    }
+}
+
+CGHeroInstance * CMap::getHero(int heroID)
+{
+    for(ui32 i=0; i<heroes.size();i++)
+        if(heroes[i]->subID == heroID)
+            return heroes[i];
+    return nullptr;
+}
+
+bool CMap::isInTheMap(const int3 &pos) const
+{
+    if(pos.x<0 || pos.y<0 || pos.z<0 || pos.x >= width || pos.y >= height || pos.z > twoLevel)
+        return false;
+    else return true;
+}
+
+TerrainTile & CMap::getTile( const int3 & tile )
+{
+    return terrain[tile.x][tile.y][tile.z];
+}
+
+const TerrainTile & CMap::getTile( const int3 & tile ) const
+{
+    return terrain[tile.x][tile.y][tile.z];
+}
+
+bool CMap::isWaterTile(const int3 &pos) const
+{
+    return isInTheMap(pos) && getTile(pos).tertype == ETerrainType::WATER;
+}
+
+const CGObjectInstance *CMap::getObjectiveObjectFrom(int3 pos, bool lookForHero)
+{
+    const std::vector <CGObjectInstance *> & objs = getTile(pos).visitableObjects;
+    assert(objs.size());
+    if(objs.size() > 1 && lookForHero && objs.front()->ID != Obj::HERO)
+    {
+        assert(objs.back()->ID == Obj::HERO);
+        return objs.back();
+    }
+    else
+        return objs.front();
+}
+
+void CMap::checkForObjectives()
+{
+    if(isInTheMap(victoryCondition.pos))
+        victoryCondition.obj = getObjectiveObjectFrom(victoryCondition.pos, victoryCondition.condition == EVictoryConditionType::BEATHERO);
+
+    if(isInTheMap(lossCondition.pos))
+        lossCondition.obj = getObjectiveObjectFrom(lossCondition.pos, lossCondition.typeOfLossCon == ELossConditionType::LOSSHERO);
+}
+
+void CMap::addNewArtifactInstance( CArtifactInstance *art )
+{
+    art->id = artInstances.size();
+    artInstances.push_back(art);
+}
+
+void CMap::eraseArtifactInstance(CArtifactInstance *art)
+{
+    assert(artInstances[art->id] == art);
+    artInstances[art->id].dellNull();
+}
+
+LossCondition::LossCondition()
+{
+    obj = NULL;
+    timeLimit = -1;
+    pos = int3(-1,-1,-1);
+}
+
+VictoryCondition::VictoryCondition()
+{
+    pos = int3(-1,-1,-1);
+    obj = NULL;
+    ID = allowNormalVictory = appliesToAI = count = 0;
+}
+
+bool TerrainTile::entrableTerrain(const TerrainTile * from /*= NULL*/) const
+{
+    return entrableTerrain(from ? from->tertype != ETerrainType::WATER : true, from ? from->tertype == ETerrainType::WATER : true);
+}
+
+bool TerrainTile::entrableTerrain(bool allowLand, bool allowSea) const
+{
+    return tertype != ETerrainType::ROCK
+        && ((allowSea && tertype == ETerrainType::WATER)  ||  (allowLand && tertype != ETerrainType::WATER));
+}
+
+bool TerrainTile::isClear(const TerrainTile *from /*= NULL*/) const
+{
+    return entrableTerrain(from) && !blocked;
+}
+
+int TerrainTile::topVisitableID() const
+{
+    return visitableObjects.size() ? visitableObjects.back()->ID : -1;
+}
+
+bool TerrainTile::isCoastal() const
+{
+    return extTileFlags & 64;
+}
+
+bool TerrainTile::hasFavourableWinds() const
+{
+    return extTileFlags & 128;
+}
+
+bool TerrainTile::isWater() const
+{
+    return tertype == ETerrainType::WATER;
+}

+ 196 - 384
lib/map.h → lib/Map/CMap.h

@@ -1,18 +1,6 @@
-#pragma once
-
-
-#ifndef _MSC_VER
-#include "CObjectHandler.h"
-#include "CDefObjInfoHandler.h"
-#endif
-
-#include "ConstTransitivePtr.h"
-#include "ResourceSet.h"
-#include "int3.h"
-#include "GameConstants.h"
 
 /*
- * map.h, part of VCMI engine
+ * CMap.h, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *
@@ -21,6 +9,18 @@
  *
  */
 
+#pragma once
+
+#ifndef _MSC_VER
+#include "../CObjectHandler.h"
+#include "../CDefObjInfoHandler.h"
+#endif
+
+#include "../ConstTransitivePtr.h"
+#include "../ResourceSet.h"
+#include "../int3.h"
+#include "../GameConstants.h"
+
 class CArtifactInstance;
 class CGDefInfo;
 class CGObjectInstance;
@@ -31,9 +31,7 @@ class CQuest;
 class CGTownInstance;
 class IModableArt;
 class IQuestObject;
-
 class CInputStream;
-typedef std::unique_ptr<CInputStream> TInputStreamPtr;
 
 namespace ETerrainType
 {
@@ -139,21 +137,21 @@ struct DLL_LINKAGE TerrainTile
      *
      * @return true if the terrain type is water
      */
-	bool isWater() const;
+    bool isWater() const;
 
     /**
      * Gets true if the terrain tile is coastal.
      *
      * @return true if the terrain tile is coastal
      */
-	bool isCoastal() const;
+    bool isCoastal() const;
 
     /**
      * Gets true if the terrain tile has favourable winds.
      *
      * @return true if the terrain tile has favourable winds
      */
-	bool hasFavourableWinds() const;
+    bool hasFavourableWinds() const;
 
     /**
      * Serialize method.
@@ -174,22 +172,22 @@ struct DLL_LINKAGE TerrainTile
 /**
  * The hero name struct consists of the hero id and name.
  */
-struct DLL_LINKAGE SheroName 
+struct DLL_LINKAGE SheroName
 {
     /** the id of the hero */
-	int heroID;
+    int heroID;
 
     /** the name of the hero */
-	std::string heroName;
+    std::string heroName;
 
     /**
      * Serialize method.
      */
     template <typename Handler>
     void serialize(Handler & h, const int version)
-	{
-		h & heroID & heroName;
-	}
+    {
+        h & heroID & heroName;
+    }
 };
 
 /**
@@ -211,10 +209,10 @@ struct DLL_LINKAGE PlayerInfo
     ui8 powerPlacehodlers;
 
     /** player can be played by a human */
-	ui8 canHumanPlay;
+    ui8 canHumanPlay;
 
     /** player can be played by the computer */
-	ui8 canComputerPlay;
+    ui8 canComputerPlay;
 
     /** defines the tactical setting of the AI: 0 - random, 1 -  warrior, 2 - builder, 3 - explorer */
     ui32 AITactic;
@@ -229,25 +227,25 @@ struct DLL_LINKAGE PlayerInfo
     ui32 mainHeroPortrait;
 
     /** the name of the main hero */
-	std::string mainHeroName;
+    std::string mainHeroName;
 
     /** list of available heroes */
-	std::vector<SheroName> heroesNames;
+    std::vector<SheroName> heroesNames;
 
     /** has the player a main town */
-	ui8 hasMainTown;
+    ui8 hasMainTown;
 
     /** generates the hero at the main town */
-	ui8 generateHeroAtMainTown;
+    ui8 generateHeroAtMainTown;
 
     /** the position of the main town */
-	int3 posOfMainTown;
+    int3 posOfMainTown;
 
     /** the team id to which the player belongs to */
-	ui8 team;
+    ui8 team;
 
     /** unused. generates a hero */
-	ui8 generateHero;
+    ui8 generateHero;
 
     /**
      * Default constructor.
@@ -273,11 +271,11 @@ struct DLL_LINKAGE PlayerInfo
      */
     template <typename Handler>
     void serialize(Handler & h, const int version)
-	{
-		h & p7 & p8 & p9 & canHumanPlay & canComputerPlay & AITactic & allowedFactions & isFactionRandom &
-			mainHeroPortrait & mainHeroName & heroesNames & hasMainTown & generateHeroAtMainTown &
-			posOfMainTown & team & generateHero;
-	}
+    {
+        h & p7 & p8 & p9 & canHumanPlay & canComputerPlay & AITactic & allowedFactions & isFactionRandom &
+            mainHeroPortrait & mainHeroName & heroesNames & hasMainTown & generateHeroAtMainTown &
+            posOfMainTown & team & generateHero;
+    }
 };
 
 /**
@@ -286,10 +284,10 @@ struct DLL_LINKAGE PlayerInfo
 struct DLL_LINKAGE LossCondition
 {
     /** specifies the condition type */
-	ELossConditionType::ELossConditionType typeOfLossCon;
+    ELossConditionType::ELossConditionType typeOfLossCon;
 
     /** the position of an object which mustn't be lost */
-	int3 pos;
+    int3 pos;
 
     /** time limit in days, -1 if not used */
     si32 timeLimit;
@@ -307,9 +305,9 @@ struct DLL_LINKAGE LossCondition
      */
     template <typename Handler>
     void serialize(Handler & h, const int version)
-	{
-		h & typeOfLossCon & pos & timeLimit & obj;
-	}
+    {
+        h & typeOfLossCon & pos & timeLimit & obj;
+    }
 };
 
 /**
@@ -349,9 +347,9 @@ struct DLL_LINKAGE VictoryCondition
      */
     template <typename Handler>
     void serialize(Handler & h, const int version)
-	{
-		h & condition & allowNormalVictory & appliesToAI & pos & ID & count & obj;
-	}
+    {
+        h & condition & allowNormalVictory & appliesToAI & pos & ID & count & obj;
+    }
 };
 
 /**
@@ -370,9 +368,9 @@ struct DLL_LINKAGE Rumor
      */
     template <typename Handler>
     void serialize(Handler & h, const int version)
-	{
-		h & name & text;
-	}
+    {
+        h & name & text;
+    }
 };
 
 /**
@@ -381,13 +379,13 @@ struct DLL_LINKAGE Rumor
 struct DLL_LINKAGE DisposedHero
 {
     /** the id of the hero */
-	ui32 ID;
+    ui32 ID;
 
     /** the portrait id of the hero, 0xFF is default */
     ui16 portrait;
 
     /** the name of the hero */
-	std::string name;
+    std::string name;
 
     /** who can hire this hero (bitfield) */
     ui8 players;
@@ -397,9 +395,9 @@ struct DLL_LINKAGE DisposedHero
      */
     template <typename Handler>
     void serialize(Handler & h, const int version)
-	{
-		h & ID & portrait & name & players;
-	}
+    {
+        h & ID & portrait & name & players;
+    }
 };
 
 /// Class which manages map events.
@@ -424,13 +422,13 @@ public:
     ui8 players;
 
     /** affected humans */
-	ui8 humanAffected;
+    ui8 humanAffected;
 
     /** affacted computer players */
-	ui8 computerAffected;
+    ui8 computerAffected;
 
     /** the day counted continously where the event happens */
-	ui32 firstOccurence;
+    ui32 firstOccurence;
 
     /** specifies after how many days the event will occur the next time; 0 if event occurs only one time */
     ui32 nextOccurence;
@@ -449,10 +447,10 @@ public:
      */
     template <typename Handler>
     void serialize(Handler & h, const int version)
-	{
-		h & name & message & resources
-			& players & humanAffected & computerAffected & firstOccurence & nextOccurence;
-	}
+    {
+        h & name & message & resources
+            & players & humanAffected & computerAffected & firstOccurence & nextOccurence;
+    }
 };
 
 /**
@@ -475,10 +473,10 @@ public:
      */
     template <typename Handler>
     void serialize(Handler & h, const int version)
-	{
+    {
         h & static_cast<CMapEvent &>(*this);
-		h & buildings & creatures;
-	}
+        h & buildings & creatures;
+    }
 };
 
 namespace EMapFormat
@@ -502,42 +500,10 @@ public:
     CMapHeader();
 
     /**
-     * Constructor.
-     *
-     * @param map a pointer to an buffer which contains bytes describing a map header
-     */
-    CMapHeader(const ui8 * map);
-
-    /**
-     * Destructor.
+     * D-tor.
      */
     virtual ~CMapHeader();
 
-    /**
-     * Initializes the map header from memory.
-     *
-     * @param buffer a pointer to an buffer which contains bytes describing a map header
-     * @param i the index where to start reading from
-     */
-    void initFromMemory(const ui8 * buffer, int & i);
-
-    /**
-     * Loads victory/loss conditions.
-     *
-     * @param buffer a pointer to an buffer which contains bytes describing a map header
-     * @param i the index where to start reading from
-     */
-    void loadViCLossConditions(const ui8 * buffer, int & i);
-
-    /**
-     * Loads information about players.
-     *
-     * @param pom
-     * @param buffer a pointer to an buffer which contains bytes describing a map header
-     * @param i the index where to start reading from
-     */
-    void loadPlayerInfo(int & pom, const ui8 * buffer, int & i);
-
     /** the version of the map */
     EMapFormat::EMapFormat version;
 
@@ -566,7 +532,7 @@ public:
     ui8 levelLimit;
 
     /** the loss condition */
-	LossCondition lossCondition;
+    LossCondition lossCondition;
 
     /** the victory condition */
     VictoryCondition victoryCondition;
@@ -575,7 +541,7 @@ public:
     std::vector<PlayerInfo> players;
 
     /** number of teams */
-	ui8 howManyTeams;
+    ui8 howManyTeams;
 
     /** list of allowed heroes, index is hero id */
     std::vector<ui8> allowedHeroes;
@@ -588,10 +554,10 @@ public:
      */
     template <typename Handler>
     void serialize(Handler & h, const int Version)
-	{
-		h & version & name & description & width & height & twoLevel & difficulty & levelLimit & areAnyPLayers;
+    {
+        h & version & name & description & width & height & twoLevel & difficulty & levelLimit & areAnyPLayers;
         h & players & lossCondition & victoryCondition & howManyTeams & allowedHeroes;
-	}
+    }
 };
 
 /**
@@ -601,205 +567,15 @@ public:
 class DLL_LINKAGE CMap : public CMapHeader
 {
 public:
-    /** the checksum of the map */
-	ui32 checksum;
-
-    /** a 3-dimensional array of terrain tiles, access is as follows: x, y, level */
-	TerrainTile*** terrain; 
-
-    /** list of rumors */
-	std::vector<Rumor> rumors;
-
-    /** list of disposed heroes */
-	std::vector<DisposedHero> disposedHeroes;
-
-    /** list of predefined heroes */
-	std::vector<ConstTransitivePtr<CGHeroInstance> > predefinedHeroes;
-
-    /** list of .def files with definitions from .h3m (may be custom) */
-    std::vector<ConstTransitivePtr<CGDefInfo> > customDefs;
-
-    /** list of allowed spells, index is the spell id */
-    std::vector<ui8> allowedSpell;
-
-    /** list of allowed artifacts, index is the artifact id */
-    std::vector<ui8> allowedArtifact;
-
-    /** list of allowed abilities, index is the ability id */
-    std::vector<ui8> allowedAbilities;
-
-    /** list of map events */
-	std::list<ConstTransitivePtr<CMapEvent> > events;
-
-    /** specifies the position of the grail */
-	int3 grailPos;
-
-    /** specifies the radius of the grail */
-	int grailRadious;
-
-    /** list of objects */
-	std::vector< ConstTransitivePtr<CGObjectInstance> > objects;
-
-    /** list of heroes */
-	std::vector< ConstTransitivePtr<CGHeroInstance> > heroes;
-
-    /** list of towns */
-	std::vector< ConstTransitivePtr<CGTownInstance> > towns;
-
-    /** list of artifacts */
-    std::vector< ConstTransitivePtr<CArtifactInstance> > artInstances;
-
-    /** list of quests */
-    std::vector< ConstTransitivePtr<CQuest> > quests;
-
-    /** associative list to identify which hero/creature id belongs to which object id(index for objects) */
-	bmap<si32, si32> questIdentifierToId;
-
-    /**
-     * Creates map from decompressed .h3m data.
-     *
-     * @param buffer a pointer to an buffer which contains bytes describing a map
-     * @param size the length of the buffer
-     */
-    void initFromBytes(const ui8 * buffer, size_t size);
-
-    /**
-     * Reads events from a buffer.
-     *
-     * @param buffer a pointer to an buffer which contains bytes describing events
-     * @param i the index where to start reading from
-     */
-    void readEvents(const ui8 * buffer, int & i);
-
-    /**
-     * Reads objects from a buffer.
-     *
-     * @param buffer a pointer to an buffer which contains bytes describing objects
-     * @param i the index where to start reading from
-     */
-    void readObjects(const ui8 * buffer, int & i);
-
-    /**
-     * Loads quest information and stores that to a quest guard object.
-     *
-     * @param guard the quest guard object where the quest info should be applied to
-     * @param buffer a pointer to an buffer which contains bytes describing objects
-     * @param i the index where to start reading from
-     */
-    void loadQuest(IQuestObject * guard, const ui8 * buffer, int & i);
-
-    /**
-     * Reads def information from a buffer.
-     *
-     * @param buffer a pointer to an buffer which contains bytes describing def information
-     * @param i the index where to start reading from
-     */
-    void readDefInfo(const ui8 * buffer, int & i);
-
-    /**
-     * Reads terrain data from a buffer.
-     *
-     * @param buffer a pointer to an buffer which contains bytes describing terrain data
-     * @param i the index where to start reading from
-     */
-    void readTerrain(const ui8 * buffer, int & i);
-
-    /**
-     * Reads predefined heroes from a buffer.
-     *
-     * @param buffer a pointer to an buffer which contains bytes describing events
-     * @param i the index where to start reading from
-     */
-    void readPredefinedHeroes(const ui8 * buffer, int & i);
-
-    /**
-     * Reads events from a buffer.
-     *
-     * @param buffer a pointer to an buffer which contains bytes describing events
-     * @param i the index where to start reading from
-     */
-    void readHeader(const ui8 * buffer, int & i);
-
-    /**
-     * Reads events from a buffer.
-     *
-     * @param buffer a pointer to an buffer which contains bytes describing events
-     * @param i the index where to start reading from
-     */
-    void readRumors(const ui8 * buffer, int & i);
-
-    /**
-     * Loads a hero from a buffer.
-     *
-     * @param buffer a pointer to an buffer which contains bytes describing events
-     * @param i the index where to start reading from
-     * @param idToBeGiven the object id which should be set for the hero
-     * @return a object instance
-     */
-    CGObjectInstance * loadHero(const ui8 * buffer, int & i, int idToBeGiven);
-
-    /**
-     * Loads artifacts of a hero from a buffer.
-     *
-     * @param buffer a pointer to an buffer which contains bytes describing events
-     * @param i the index where to start reading from
-     * @param hero the hero which should hold those artifacts
-     */
-    void loadArtifactsOfHero(const ui8 * buffer, int & i, CGHeroInstance * hero);
-
     /**
-     * Loads an artifact from a buffer to the given slot of the specified hero.
-     *
-     * @param hero the hero which should hold that artifact
-     * @param slot the artifact slot where to place that artifact
-     * @param buffer a pointer to an buffer which contains bytes describing events
-     * @param i the index where to start reading from
-     * @return true if it loaded an artifact
-     */
-    bool loadArtifactToSlot(CGHeroInstance * hero, int slot, const ui8 * buffer, int & i);
-
-    /**
-     * Loads a town from a buffer.
-     *
-     * @param town a pointer to a town object which gets filled by data
-     * @param buffer a pointer to an buffer which contains bytes describing events
-     * @param i the index where to start reading from
-     * @param castleID the id of the castle type
-     */
-    void loadTown(CGObjectInstance * & town, const ui8 * buffer, int & i, int castleID);
-
-    /**
-     * Loads a seer hut from a buffer.
-     *
-     * @param buffer a pointer to an buffer which contains bytes describing events
-     * @param i the index where to start reading from
-     * @param seerHut the seer hut object which gets filled by data
-     * @return index of the reading position of the buffer
-     */
-    int loadSeerHut(const ui8 * buffer, int i, CGObjectInstance * & seerHut);
-
-    /**
-     * Creates an artifact instance.
-     *
-     * @param aid the id of the artifact
-     * @param spellID optional. the id of a spell if a spell scroll object should be created
-     * @return the created artifact instance
-     */
-    CArtifactInstance * createArt(int aid, int spellID = -1);
-
-    /**
-     * Adds the specified artifact instance to the list of artifacts of this map.
-     *
-     * @param art the artifact which should be added to the list of artifacts
+     * Default constructor.
      */
-    void addNewArtifactInstance(CArtifactInstance * art);
+    CMap();
 
     /**
-     * Adds a quest to the list of quests of this map.
-     *
-     * @param quest the quest object which should be added to the list of quests
+     * Destructor.
      */
-    void addQuest(CGObjectInstance * quest);
+    ~CMap();
 
     /**
      * Erases an artifact instance.
@@ -822,14 +598,14 @@ public:
     /**
      * Sets the victory/loss condition objectives.
      */
-	void checkForObjectives();
+    void checkForObjectives();
 
     /**
      * Adds an visitable/blocking object to a terrain tile.
      *
      * @param obj the visitable/blocking object to add to a tile
      */
-	void addBlockVisTiles(CGObjectInstance * obj);
+    void addBlockVisTiles(CGObjectInstance * obj);
 
     /**
      * Removes an visitable/blocking object from a terrain tile.
@@ -839,23 +615,6 @@ public:
      */
     void removeBlockVisTiles(CGObjectInstance * obj, bool total = false);
 
-    /**
-     * Constructor. Creates a map from file.
-     *
-     * @param filename the name of the h3m map file
-     */
-    CMap(std::string filename);
-
-    /**
-     * Default constructor.
-     */
-    CMap();
-
-    /**
-     * Destructor.
-     */
-    ~CMap();
-
     /**
      * Gets the terrain tile of the specified position.
      *
@@ -896,27 +655,80 @@ public:
     bool isWaterTile(const int3 & pos) const;
 
     /**
-     * Gets a input stream from the given map name.
+     * Adds the specified artifact instance to the list of artifacts of this map.
      *
-     * @param name the name of the map
-     * @return a unique ptr to the input stream
+     * @param art the artifact which should be added to the list of artifacts
      */
-    static TInputStreamPtr getMapStream(std::string name);
+    void addNewArtifactInstance(CArtifactInstance * art);
+
+    /** the checksum of the map */
+    ui32 checksum;
+
+    /** a 3-dimensional array of terrain tiles, access is as follows: x, y, level */
+    TerrainTile*** terrain;
+
+    /** list of rumors */
+    std::vector<Rumor> rumors;
+
+    /** list of disposed heroes */
+    std::vector<DisposedHero> disposedHeroes;
+
+    /** list of predefined heroes */
+    std::vector<ConstTransitivePtr<CGHeroInstance> > predefinedHeroes;
+
+    /** list of .def files with definitions from .h3m (may be custom) */
+    std::vector<ConstTransitivePtr<CGDefInfo> > customDefs;
+
+    /** list of allowed spells, index is the spell id */
+    std::vector<ui8> allowedSpell;
+
+    /** list of allowed artifacts, index is the artifact id */
+    std::vector<ui8> allowedArtifact;
+
+    /** list of allowed abilities, index is the ability id */
+    std::vector<ui8> allowedAbilities;
+
+    /** list of map events */
+    std::list<ConstTransitivePtr<CMapEvent> > events;
+
+    /** specifies the position of the grail */
+    int3 grailPos;
+
+    /** specifies the radius of the grail */
+    int grailRadious;
+
+    /** list of objects */
+    std::vector< ConstTransitivePtr<CGObjectInstance> > objects;
+
+    /** list of heroes */
+    std::vector< ConstTransitivePtr<CGHeroInstance> > heroes;
+
+    /** list of towns */
+    std::vector< ConstTransitivePtr<CGTownInstance> > towns;
+
+    /** list of artifacts */
+    std::vector< ConstTransitivePtr<CArtifactInstance> > artInstances;
+
+    /** list of quests */
+    std::vector< ConstTransitivePtr<CQuest> > quests;
+
+    /** associative list to identify which hero/creature id belongs to which object id(index for objects) */
+    bmap<si32, si32> questIdentifierToId;
 
     /**
      * Serialize method.
      */
     template <typename Handler>
     void serialize(Handler &h, const int formatVersion)
-	{
-		h & static_cast<CMapHeader&>(*this);
+    {
+        h & static_cast<CMapHeader&>(*this);
         h & rumors & allowedSpell & allowedAbilities & allowedArtifact & events & grailPos;
         h & artInstances & quests;
         h & questIdentifierToId;
 
-		//TODO: viccondetails
-		if(h.saving)
-		{
+        //TODO: viccondetails
+        if(h.saving)
+        {
             // Save terrain
             for(int i = 0; i < width ; ++i)
             {
@@ -924,60 +736,60 @@ public:
                 {
                     for(int k = 0; k <= twoLevel; ++k)
                     {
-						h & terrain[i][j][k];
+                        h & terrain[i][j][k];
                     }
                 }
             }
-		}
-		else
-		{
+        }
+        else
+        {
             // Load terrain
             terrain = new TerrainTile**[width];
             for(int ii = 0; ii < width; ++ii)
-			{
+            {
                 terrain[ii] = new TerrainTile*[height];
                 for(int jj = 0; jj < height; ++jj)
                 {
                     terrain[ii][jj] = new TerrainTile[twoLevel + 1];
                 }
-			}
+            }
             for(int i = 0; i < width ; ++i)
             {
                 for(int j = 0; j < height ; ++j)
                 {
                     for(int k = 0; k <= twoLevel ; ++k)
                     {
-						h & terrain[i][j][k];
+                        h & terrain[i][j][k];
                     }
                 }
             }
-		}
-		
+        }
+
         h & customDefs & objects;
 
         // static members
-		h & CGTeleport::objs;
-		h & CGTeleport::gates;
-		h & CGKeys::playerKeyMap;
-		h & CGMagi::eyelist;
-		h & CGObelisk::obeliskCount & CGObelisk::visited;
-		h & CGTownInstance::merchantArtifacts;
-
-		if(!h.saving)
-		{
+        h & CGTeleport::objs;
+        h & CGTeleport::gates;
+        h & CGKeys::playerKeyMap;
+        h & CGMagi::eyelist;
+        h & CGObelisk::obeliskCount & CGObelisk::visited;
+        h & CGTownInstance::merchantArtifacts;
+
+        if(!h.saving)
+        {
             for(ui32 i = 0; i < objects.size(); ++i)
-			{
-				if(!objects[i]) continue;
-
-				switch (objects[i]->ID)
-				{
-					case Obj::HERO:
-						heroes.push_back (static_cast<CGHeroInstance*>(+objects[i]));
-						break;
-					case Obj::TOWN:
-						towns.push_back (static_cast<CGTownInstance*>(+objects[i]));
-						break;
-				}
+            {
+                if(!objects[i]) continue;
+
+                switch (objects[i]->ID)
+                {
+                    case Obj::HERO:
+                        heroes.push_back (static_cast<CGHeroInstance*>(+objects[i]));
+                        break;
+                    case Obj::TOWN:
+                        towns.push_back (static_cast<CGTownInstance*>(+objects[i]));
+                        break;
+                }
 
                 // recreate blockvis map
                 addBlockVisTiles(objects[i]);
@@ -985,46 +797,46 @@ public:
 
             // if hero is visiting/garrisoned in town set appropriate pointers
             for(ui32 i = 0; i < heroes.size(); ++i)
-			{
+            {
                 int3 vistile = heroes[i]->pos;
                 vistile.x++;
                 for(ui32 j = 0; j < towns.size(); ++j)
-				{
+                {
                     // hero stands on the town entrance
                     if(vistile == towns[j]->pos)
-					{
-						if(heroes[i]->inTownGarrison)
-						{
-							towns[j]->garrisonHero = heroes[i];
-							removeBlockVisTiles(heroes[i]);
-						}
-						else
-						{
-							towns[j]->visitingHero = heroes[i];
-						}
-
-						heroes[i]->visitedTown = towns[j];
-						break;
-					}
-				}
-
-				vistile.x -= 2; //manifest pos
+                    {
+                        if(heroes[i]->inTownGarrison)
+                        {
+                            towns[j]->garrisonHero = heroes[i];
+                            removeBlockVisTiles(heroes[i]);
+                        }
+                        else
+                        {
+                            towns[j]->visitingHero = heroes[i];
+                        }
+
+                        heroes[i]->visitedTown = towns[j];
+                        break;
+                    }
+                }
+
+                vistile.x -= 2; //manifest pos
                 const TerrainTile & t = getTile(vistile);
                 if(t.tertype != ETerrainType::WATER) continue;
 
-				//hero stands on the water - he must be in the boat
+                //hero stands on the water - he must be in the boat
                 for(ui32 j = 0; j < t.visitableObjects.size(); ++j)
-				{
-					if(t.visitableObjects[j]->ID == Obj::BOAT)
-					{
+                {
+                    if(t.visitableObjects[j]->ID == Obj::BOAT)
+                    {
                         CGBoat * b = static_cast<CGBoat *>(t.visitableObjects[j]);
-						heroes[i]->boat = b;
-						b->hero = heroes[i];
-						removeBlockVisTiles(b);
-						break;
-					}
-				}
+                        heroes[i]->boat = b;
+                        b->hero = heroes[i];
+                        removeBlockVisTiles(b);
+                        break;
+                    }
+                }
             }
         }
-	}
+    }
 };

+ 49 - 0
lib/Map/CMapInfo.cpp

@@ -0,0 +1,49 @@
+#include "StdInc.h"
+#include "CMapInfo.h"
+
+#include "../StartInfo.h"
+#include "CMap.h"
+#include "CCampaignHandler.h"
+#include "../GameConstants.h"
+#include "CMapService.h"
+
+void CMapInfo::countPlayers()
+{
+    actualHumanPlayers = playerAmnt = humanPlayers = 0;
+    for(int i=0;i<GameConstants::PLAYER_LIMIT;i++)
+    {
+        if(mapHeader->players[i].canHumanPlay)
+        {
+            playerAmnt++;
+            humanPlayers++;
+        }
+        else if(mapHeader->players[i].canComputerPlay)
+        {
+            playerAmnt++;
+        }
+    }
+
+    if(scenarioOpts)
+        for (auto i = scenarioOpts->playerInfos.cbegin(); i != scenarioOpts->playerInfos.cend(); i++)
+            if(i->second.human)
+                actualHumanPlayers++;
+}
+
+CMapInfo::CMapInfo() : mapHeader(nullptr), campaignHeader(nullptr),
+    scenarioOpts(nullptr)
+{
+
+}
+
+void CMapInfo::mapInit(const std::string & fname)
+{
+    fileURI = fname;
+    mapHeader = CMapService::loadMapHeader(fname);
+    countPlayers();
+}
+
+void CMapInfo::campaignInit()
+{
+    campaignHeader = std::unique_ptr<CCampaignHeader>(new CCampaignHeader(CCampaignHandler::getHeader(fileURI)));
+}
+

+ 42 - 0
lib/Map/CMapInfo.h

@@ -0,0 +1,42 @@
+#pragma once
+
+// Forward class declarations aren't enough here. The compiler
+// generated CMapInfo d-tor, generates the unique_ptr d-tor as well here
+// as a inline method. The unique_ptr d-tor requires a complete type. Defining
+// the CMapInfo d-tor to let the compiler add the d-tor stuff in the .cpp file
+// would work with one exception. It prevents the generation of the move
+// constructor which is needed. (Writing such a c-tor is nasty.) With the
+// new c++11 keyword "default" for constructors this problem could be solved. But it isn't
+// available for Visual Studio for now. (Empty d-tor in .cpp would be required anyway)
+#include "CMap.h"
+#include "CCampaignHandler.h"
+
+struct StartInfo;
+
+/**
+ * A class which stores the count of human players and all players, the filename,
+ * scenario options, the map header information,...
+ */
+class DLL_LINKAGE CMapInfo
+{
+public:
+    std::unique_ptr<CMapHeader> mapHeader; //may be nullptr if campaign
+    std::unique_ptr<CCampaignHeader> campaignHeader; //may be nullptr if scenario
+    StartInfo * scenarioOpts; //options with which scenario has been started (used only with saved games)
+    std::string fileURI;
+    std::string date;
+    int playerAmnt; //players in map
+    int humanPlayers; //players ALLOWED to be controlled by human
+    int actualHumanPlayers; // >1 if multiplayer game
+
+    CMapInfo();
+    void mapInit(const std::string & fname);
+    void campaignInit();
+    void countPlayers();
+
+    template <typename Handler> void serialize(Handler &h, const int Version)
+    {
+        h & mapHeader & campaignHeader & scenarioOpts & fileURI & date & playerAmnt & humanPlayers;
+        h & actualHumanPlayers;
+    }
+};

+ 2543 - 0
lib/Map/CMapService.cpp

@@ -0,0 +1,2543 @@
+#include "StdInc.h"
+#include "CMapService.h"
+#include "../Filesystem/CResourceLoader.h"
+#include "../Filesystem/CBinaryReader.h"
+#include "../Filesystem/CCompressedStream.h"
+#include "../Filesystem/CMemoryStream.h"
+#include "CMap.h"
+#include <boost/crc.hpp>
+#include "../vcmi_endian.h"
+#include "../CStopWatch.h"
+#include "../VCMI_Lib.h"
+#include "../CSpellHandler.h"
+#include "../CCreatureHandler.h"
+
+std::unique_ptr<CMap> CMapService::loadMap(const std::string & name)
+{
+    auto stream = getStreamFromFS(name);
+    return getMapLoader(stream)->loadMap();
+}
+
+std::unique_ptr<CMapHeader> CMapService::loadMapHeader(const std::string & name)
+{
+    auto stream = getStreamFromFS(name);
+    return getMapLoader(stream)->loadMapHeader();
+}
+
+std::unique_ptr<CMap> CMapService::loadMap(const ui8 * buffer, int size)
+{
+    auto stream = getStreamFromMem(buffer, size);
+    return getMapLoader(stream)->loadMap();
+}
+
+std::unique_ptr<CMapHeader> CMapService::loadMapHeader(const ui8 * buffer, int size)
+{
+    auto stream = getStreamFromMem(buffer, size);
+    return getMapLoader(stream)->loadMapHeader();
+}
+
+std::unique_ptr<CInputStream> CMapService::getStreamFromFS(const std::string & name)
+{
+    return CResourceHandler::get()->load(ResourceID(name, EResType::MAP));
+}
+
+std::unique_ptr<CInputStream> CMapService::getStreamFromMem(const ui8 * buffer, int size)
+{
+    return std::unique_ptr<CInputStream>(new CMemoryStream(buffer, size));
+}
+
+std::unique_ptr<IMapLoader> CMapService::getMapLoader(std::unique_ptr<CInputStream> & stream)
+{
+    // Read map header
+    CBinaryReader reader(*stream.get());
+    ui32 header = reader.readUInt32();
+    reader.getStream()->seek(0);
+
+    // Check which map format is used
+    // gzip header is 3 bytes only in size
+    switch(header & 0xffffff)
+    {
+        // gzip header magic number, reversed for LE
+        case 0x00088B1F:
+            stream = std::unique_ptr<CInputStream>(new CCompressedStream(std::move(stream), true));
+            return std::unique_ptr<IMapLoader>(new CMapLoaderH3M(stream.get()));
+        case EMapFormat::WOG :
+        case EMapFormat::AB  :
+        case EMapFormat::ROE :
+        case EMapFormat::SOD :
+            return std::unique_ptr<IMapLoader>(new CMapLoaderH3M(stream.get()));
+        default :
+            throw std::runtime_error("Unknown map format");
+    }
+}
+
+const bool CMapLoaderH3M::IS_PROFILING_ENABLED = false;
+
+CMapLoaderH3M::CMapLoaderH3M(CInputStream * stream) : map(nullptr), mapHeader(nullptr), buffer(nullptr), pos(-1), size(-1)
+{
+    initBuffer(stream);
+}
+
+CMapLoaderH3M::~CMapLoaderH3M()
+{
+    delete buffer;
+}
+
+void CMapLoaderH3M::initBuffer(CInputStream * stream)
+{
+    // Read map data into memory completely
+    // TODO Replace with CBinaryReader later... (no need for reading whole
+    // file in memory at once, storing pos & size separately...)
+    stream->seek(0);
+    size = stream->getSize();
+    buffer = new ui8[size];
+    stream->read(buffer, size);
+}
+
+std::unique_ptr<CMap> CMapLoaderH3M::loadMap()
+{
+    // Init map object by parsing the input buffer
+    map = new CMap;
+    mapHeader = std::unique_ptr<CMapHeader>(dynamic_cast<CMapHeader *>(map));
+    init();
+
+    return std::unique_ptr<CMap>(dynamic_cast<CMap *>(mapHeader.release()));;
+}
+
+std::unique_ptr<CMapHeader> CMapLoaderH3M::loadMapHeader()
+{
+    // Read header
+    mapHeader = std::unique_ptr<CMapHeader>(new CMapHeader);
+    readHeader();
+
+    return std::move(mapHeader);
+}
+
+void CMapLoaderH3M::init()
+{
+    // Compute checksum
+    boost::crc_32_type  result;
+    result.process_bytes(buffer, size);
+    map->checksum = result.checksum();
+
+    CStopWatch sw;
+
+    struct MapLoadingTime
+    {
+        std::string name;
+        si64 time;
+
+        MapLoadingTime(std::string name, si64 time) : name(name),
+            time(time)
+        {
+
+        }
+    };
+    std::vector<MapLoadingTime> times;
+
+    readHeader();
+    times.push_back(MapLoadingTime("header", sw.getDiff()));
+
+    readDisposedHeroes();
+    times.push_back(MapLoadingTime("disposed heroes", sw.getDiff()));
+
+    readAllowedArtifacts();
+    times.push_back(MapLoadingTime("allowed artifacts", sw.getDiff()));
+
+    readAllowedSpellsAbilities();
+    times.push_back(MapLoadingTime("allowed spells and abilities", sw.getDiff()));
+
+    readRumors();
+    times.push_back(MapLoadingTime("rumors", sw.getDiff()));
+
+    readPredefinedHeroes();
+    times.push_back(MapLoadingTime("predefined heroes", sw.getDiff()));
+
+    readTerrain();
+    times.push_back(MapLoadingTime("terrain", sw.getDiff()));
+
+    readDefInfo();
+    times.push_back(MapLoadingTime("def info", sw.getDiff()));
+
+    readObjects();
+    times.push_back(MapLoadingTime("objects", sw.getDiff()));
+
+    readEvents();
+    times.push_back(MapLoadingTime("events", sw.getDiff()));
+
+    // Calculate blocked / visitable positions
+    for(int f = 0; f < map->objects.size(); ++f)
+    {
+        if(!map->objects[f]->defInfo) continue;
+        addBlockVisibleTiles(map->objects[f]);
+    }
+    times.push_back(MapLoadingTime("blocked/visitable tiles", sw.getDiff()));
+
+    // Print profiling times
+    if(IS_PROFILING_ENABLED)
+    {
+        BOOST_FOREACH(MapLoadingTime & mlt, times)
+        {
+            tlog0 << "\tReading " << mlt.name << " took " << mlt.time << " ms." << std::endl;
+        }
+    }
+}
+
+void CMapLoaderH3M::readHeader()
+{
+    pos = 0;
+
+    // Check map for validity
+    if(size < 50  || !buffer[4])
+    {
+        throw std::runtime_error("Corrupted map file.");
+    }
+
+    // Map version
+    mapHeader->version = (EMapFormat::EMapFormat)(read_le_u32(buffer + pos));
+    pos += 4;
+    if(mapHeader->version != EMapFormat::ROE && mapHeader->version != EMapFormat::AB && mapHeader->version != EMapFormat::SOD
+            && mapHeader->version != EMapFormat::WOG)
+    {
+        throw std::runtime_error("Invalid map format!");
+    }
+
+    // Read map name, description, dimensions,...
+    mapHeader->areAnyPLayers = readChar(buffer, pos); // Invalid on some maps
+    mapHeader->height = mapHeader->width = (read_le_u32(buffer + pos));
+    pos += 4;
+    mapHeader->twoLevel = readChar(buffer, pos);
+    mapHeader->name = readString(buffer, pos);
+    mapHeader->description = readString(buffer, pos);
+    mapHeader->difficulty = readChar(buffer, pos);
+    if(mapHeader->version != EMapFormat::ROE)
+    {
+        mapHeader->levelLimit = readChar(buffer, pos);
+    }
+    else
+    {
+        mapHeader->levelLimit = 0;
+    }
+
+    readPlayerInfo();
+    readVictoryLossConditions();
+    readTeamInfo();
+    readAllowedHeroes();
+}
+
+void CMapLoaderH3M::readPlayerInfo()
+{
+    mapHeader->players.resize(8);
+    for(int i = 0; i < 8; ++i)
+    {
+        mapHeader->players[i].canHumanPlay = buffer[pos++];
+        mapHeader->players[i].canComputerPlay = buffer[pos++];
+
+        // If nobody can play with this player
+        if((!(mapHeader->players[i].canHumanPlay || mapHeader->players[i].canComputerPlay)))
+        {
+            switch(mapHeader->version)
+            {
+            case EMapFormat::SOD:
+            case EMapFormat::WOG:
+                pos += 13;
+                break;
+            case EMapFormat::AB:
+                pos += 12;
+                break;
+            case EMapFormat::ROE:
+                pos += 6;
+                break;
+            }
+            continue;
+        }
+
+        mapHeader->players[i].AITactic = buffer[pos++];
+
+        if(mapHeader->version == EMapFormat::SOD || mapHeader->version == EMapFormat::WOG)
+        {
+            mapHeader->players[i].p7 = buffer[pos++];
+        }
+        else
+        {
+            mapHeader->players[i].p7 = -1;
+        }
+
+        // Factions this player can choose
+        ui16 allowedFactions = buffer[pos++];
+        if(mapHeader->version != EMapFormat::ROE)
+        {
+            allowedFactions += (buffer[pos++]) * 256;
+        }
+
+        for(int fact = 0; fact < 16; ++fact)
+        {
+            if(allowedFactions & (1 << fact))
+            {
+                mapHeader->players[i].allowedFactions.insert(fact);
+            }
+        }
+
+        mapHeader->players[i].isFactionRandom = buffer[pos++];
+        mapHeader->players[i].hasMainTown = buffer[pos++];
+        if(mapHeader->players[i].hasMainTown)
+        {
+            if(mapHeader->version != EMapFormat::ROE)
+            {
+                mapHeader->players[i].generateHeroAtMainTown = buffer[pos++];
+                mapHeader->players[i].generateHero = buffer[pos++];
+            }
+            else
+            {
+                mapHeader->players[i].generateHeroAtMainTown = true;
+                mapHeader->players[i].generateHero = false;
+            }
+
+            mapHeader->players[i].posOfMainTown.x = buffer[pos++];
+            mapHeader->players[i].posOfMainTown.y = buffer[pos++];
+            mapHeader->players[i].posOfMainTown.z = buffer[pos++];
+        }
+
+        mapHeader->players[i].p8 = buffer[pos++];
+        mapHeader->players[i].p9 = buffer[pos++];
+        if(mapHeader->players[i].p9 != 0xff)
+        {
+            mapHeader->players[i].mainHeroPortrait = buffer[pos++];
+            mapHeader->players[i].mainHeroName = readString(buffer, pos);
+        }
+
+        if(mapHeader->version != EMapFormat::ROE)
+        {
+            mapHeader->players[i].powerPlacehodlers = buffer[pos++]; //unknown byte
+            int heroCount = buffer[pos++];
+            pos += 3;
+            for(int pp = 0; pp < heroCount; ++pp)
+            {
+                SheroName vv;
+                vv.heroID = buffer[pos++];
+                int hnl = buffer[pos++];
+                pos += 3;
+                for(int zz = 0; zz < hnl; ++zz)
+                {
+                    vv.heroName += buffer[pos++];
+                }
+                mapHeader->players[i].heroesNames.push_back(vv);
+            }
+        }
+    }
+}
+
+void CMapLoaderH3M::readVictoryLossConditions()
+{
+    mapHeader->victoryCondition.obj = nullptr;
+    mapHeader->victoryCondition.condition = (EVictoryConditionType::EVictoryConditionType)buffer[pos++];
+
+    // Specific victory conditions
+    if(mapHeader->victoryCondition.condition != EVictoryConditionType::WINSTANDARD)
+    {
+        // Read victory conditions
+        int nr = 0;
+        switch(mapHeader->victoryCondition.condition)
+        {
+        case EVictoryConditionType::ARTIFACT:
+            {
+                mapHeader->victoryCondition.ID = buffer[pos + 2];
+                nr = (mapHeader->version == EMapFormat::ROE ? 1 : 2);
+                break;
+            }
+        case EVictoryConditionType::GATHERTROOP:
+            {
+                mapHeader->victoryCondition.ID = buffer[pos + 2];
+                mapHeader->victoryCondition.count = read_le_u32(buffer + pos + (mapHeader->version == EMapFormat::ROE ? 3 : 4));
+                nr = (mapHeader->version == EMapFormat::ROE ? 5 : 6);
+                break;
+            }
+        case EVictoryConditionType::GATHERRESOURCE:
+            {
+                mapHeader->victoryCondition.ID = buffer[pos + 2];
+                mapHeader->victoryCondition.count = read_le_u32(buffer + pos + 3);
+                nr = 5;
+                break;
+            }
+        case EVictoryConditionType::BUILDCITY:
+            {
+                mapHeader->victoryCondition.pos.x = buffer[pos + 2];
+                mapHeader->victoryCondition.pos.y = buffer[pos + 3];
+                mapHeader->victoryCondition.pos.z = buffer[pos + 4];
+                mapHeader->victoryCondition.count = buffer[pos + 5];
+                mapHeader->victoryCondition.ID = buffer[pos + 6];
+                nr = 5;
+                break;
+            }
+        case EVictoryConditionType::BUILDGRAIL:
+            {
+                if(buffer[pos + 4] > 2)
+                {
+                    mapHeader->victoryCondition.pos = int3(-1,-1,-1);
+                }
+                else
+                {
+                    mapHeader->victoryCondition.pos.x = buffer[pos + 2];
+                    mapHeader->victoryCondition.pos.y = buffer[pos + 3];
+                    mapHeader->victoryCondition.pos.z = buffer[pos + 4];
+                }
+                nr = 3;
+                break;
+            }
+        case EVictoryConditionType::BEATHERO:
+        case EVictoryConditionType::CAPTURECITY:
+        case EVictoryConditionType::BEATMONSTER:
+            {
+                mapHeader->victoryCondition.pos.x = buffer[pos + 2];
+                mapHeader->victoryCondition.pos.y = buffer[pos + 3];
+                mapHeader->victoryCondition.pos.z = buffer[pos + 4];
+                nr = 3;
+                break;
+            }
+        case EVictoryConditionType::TAKEDWELLINGS:
+        case EVictoryConditionType::TAKEMINES:
+            {
+                nr = 0;
+                break;
+            }
+        case EVictoryConditionType::TRANSPORTITEM:
+            {
+                mapHeader->victoryCondition.ID =  buffer[pos + 2];
+                mapHeader->victoryCondition.pos.x = buffer[pos + 3];
+                mapHeader->victoryCondition.pos.y = buffer[pos + 4];
+                mapHeader->victoryCondition.pos.z = buffer[pos + 5];
+                nr = 4;
+                break;
+            }
+        default:
+            assert(0);
+        }
+        mapHeader->victoryCondition.allowNormalVictory = buffer[pos++];
+        mapHeader->victoryCondition.appliesToAI = buffer[pos++];
+        pos += nr;
+    }
+
+    // Read loss conditions
+    mapHeader->lossCondition.typeOfLossCon = (ELossConditionType::ELossConditionType)buffer[pos++];
+    switch(mapHeader->lossCondition.typeOfLossCon)
+    {
+    case ELossConditionType::LOSSCASTLE:
+    case ELossConditionType::LOSSHERO:
+        {
+            mapHeader->lossCondition.pos.x = buffer[pos++];
+            mapHeader->lossCondition.pos.y = buffer[pos++];
+            mapHeader->lossCondition.pos.z = buffer[pos++];
+            break;
+        }
+    case ELossConditionType::TIMEEXPIRES:
+        {
+            mapHeader->lossCondition.timeLimit = read_le_u16(buffer + pos);
+            pos += 2;
+            break;
+        }
+    }
+}
+
+void CMapLoaderH3M::readTeamInfo()
+{
+    mapHeader->howManyTeams = buffer[pos++];
+    if(mapHeader->howManyTeams > 0)
+    {
+        // Teams
+        for(int i = 0; i < 8; ++i)
+        {
+            mapHeader->players[i].team = buffer[pos++];
+        }
+    }
+    else
+    {
+        // No alliances
+        for(int i = 0; i < GameConstants::PLAYER_LIMIT; i++)
+        {
+            if(mapHeader->players[i].canComputerPlay || mapHeader->players[i].canHumanPlay)
+            {
+                mapHeader->players[i].team = mapHeader->howManyTeams++;
+            }
+        }
+    }
+}
+
+void CMapLoaderH3M::readAllowedHeroes()
+{
+    int pom = pos;
+    mapHeader->allowedHeroes.resize(GameConstants::HEROES_QUANTITY, false);
+    for(; pos < pom + (mapHeader->version == EMapFormat::ROE ? 16 : 20) ; ++pos)
+    {
+        ui8 c = buffer[pos];
+        for(int yy = 0; yy < 8; ++yy)
+        {
+            if((pos - pom) * 8 + yy < GameConstants::HEROES_QUANTITY)
+            {
+                if(c == (c | static_cast<ui8>(std::pow(2, yy))))
+                {
+                    mapHeader->allowedHeroes[(pos - pom) * 8 + yy] = true;
+                }
+            }
+        }
+    }
+
+    // Probably reserved for further heroes
+    if(mapHeader->version > EMapFormat::ROE)
+    {
+        int placeholdersQty = read_le_u32(buffer + pos);
+        pos += 4;
+        for(int p = 0; p < placeholdersQty; ++p)
+        {
+            mapHeader->placeholdedHeroes.push_back(buffer[pos++]);
+        }
+    }
+}
+
+void CMapLoaderH3M::readDisposedHeroes()
+{
+    // Reading disposed heroes (20 bytes)
+    ui8 disp = 0;
+    if(map->version >= EMapFormat::SOD)
+    {
+        disp = buffer[pos++];
+        map->disposedHeroes.resize(disp);
+        for(int g = 0; g < disp; ++g)
+        {
+            map->disposedHeroes[g].ID = buffer[pos++];
+            map->disposedHeroes[g].portrait = buffer[pos++];
+            int lenbuf = read_le_u32(buffer + pos);
+            pos += 4;
+            for(int zz = 0; zz < lenbuf; zz++)
+            {
+                map->disposedHeroes[g].name += buffer[pos++];
+            }
+            map->disposedHeroes[g].players = buffer[pos++];
+        }
+    }
+
+    //omitting NULLS
+    pos += 31;
+}
+
+void CMapLoaderH3M::readAllowedArtifacts()
+{
+    map->allowedArtifact.resize(GameConstants::ARTIFACTS_QUANTITY);
+    for(ui32 x = 0; x < map->allowedArtifact.size(); x++)
+    {
+        map->allowedArtifact[x] = true;
+    }
+
+    // Reading allowed artifacts:  17 or 18 bytes
+    if(map->version != EMapFormat::ROE)
+    {
+        // Starting i for loop
+        int ist = pos;
+        for(; pos < ist + (map->version == EMapFormat::AB ? 17 : 18); ++pos)
+        {
+            ui8 c = buffer[pos];
+            for(int yy = 0; yy < 8; ++yy)
+            {
+                if((pos - ist) * 8 + yy < GameConstants::ARTIFACTS_QUANTITY)
+                {
+                    if(c == (c | static_cast<ui8>(std::pow(2, yy))))
+                    {
+                        map->allowedArtifact[(pos - ist) * 8 + yy] = false;
+                    }
+                }
+            }
+        }
+    }
+
+    // ban combo artifacts
+    if (map->version == EMapFormat::ROE || map->version == EMapFormat::AB)
+    {
+        BOOST_FOREACH(CArtifact * artifact, VLC->arth->artifacts)
+        {
+            // combo
+            if (artifact->constituents)
+            {
+                map->allowedArtifact[artifact->id] = false;
+            }
+        }
+        if (map->version == EMapFormat::ROE)
+        {
+            // Armageddon's Blade
+            map->allowedArtifact[128] = false;
+        }
+    }
+
+    // Messy, but needed
+    if(map->victoryCondition.condition == EVictoryConditionType::ARTIFACT
+            || map->victoryCondition.condition == EVictoryConditionType::TRANSPORTITEM)
+    {
+        map->allowedArtifact[map->victoryCondition.ID] = false;
+    }
+}
+
+void CMapLoaderH3M::readAllowedSpellsAbilities()
+{
+    // Read allowed spells
+    map->allowedSpell.resize(GameConstants::SPELLS_QUANTITY);
+    for(ui32 x = 0; x < map->allowedSpell.size(); x++)
+    {
+        map->allowedSpell[x] = true;
+    }
+
+    // Read allowed abilities
+    map->allowedAbilities.resize(GameConstants::SKILL_QUANTITY);
+    for(ui32 x = 0; x < map->allowedAbilities.size(); x++)
+    {
+        map->allowedAbilities[x] = true;
+    }
+
+    if(map->version >= EMapFormat::SOD)
+    {
+        // Reading allowed spells (9 bytes)
+        int ist = pos;
+        for(; pos < ist + 9; ++pos)
+        {
+            ui8 c = buffer[pos];
+            for(int yy = 0; yy < 8; ++yy)
+            {
+                if((pos - ist) * 8 + yy < GameConstants::SPELLS_QUANTITY)
+                {
+                    if(c == (c | static_cast<ui8>(std::pow(2, yy))))
+                    {
+                        map->allowedSpell[(pos - ist) * 8 + yy] = false;
+                    }
+                }
+            }
+        }
+
+
+        // Allowed hero's abilities (4 bytes)
+        ist = pos;
+        for(; pos < ist + 4; ++pos)
+        {
+            ui8 c = buffer[pos];
+            for(int yy = 0; yy < 8; ++yy)
+            {
+                if((pos - ist) * 8 + yy < GameConstants::SKILL_QUANTITY)
+                {
+                    if(c == (c | static_cast<ui8>(std::pow(2, yy))))
+                    {
+                        map->allowedAbilities[(pos - ist) * 8 + yy] = false;
+                    }
+                }
+            }
+        }
+    }
+}
+
+void CMapLoaderH3M::readRumors()
+{
+    int rumNr = read_le_u32(buffer + pos);
+    pos += 4;
+
+    for(int it = 0; it < rumNr; it++)
+    {
+        Rumor ourRumor;
+
+        // Read rumor name and text
+        int nameL = read_le_u32(buffer + pos);
+        pos += 4;
+        for(int zz = 0; zz < nameL; zz++)
+        {
+            ourRumor.name += buffer[pos++];
+        }
+
+        nameL = read_le_u32(buffer + pos);
+        pos += 4;
+        for(int zz = 0; zz < nameL; zz++)
+        {
+            ourRumor.text += buffer[pos++];
+        }
+
+        map->rumors.push_back(ourRumor);
+    }
+}
+
+void CMapLoaderH3M::readPredefinedHeroes()
+{
+    switch(map->version)
+    {
+    case EMapFormat::WOG:
+    case EMapFormat::SOD:
+        {
+            // Disposed heroes
+            for(int z = 0; z < GameConstants::HEROES_QUANTITY; z++)
+            {
+                int custom =  buffer[pos++];
+                if(!custom) continue;
+
+                CGHeroInstance * hero = new CGHeroInstance;
+                hero->ID = Obj::HERO;
+                hero->subID = z;
+
+                // True if hore's experience is greater than 0
+                if(readChar(buffer, pos))
+                {
+                    hero->exp = read_le_u32(buffer + pos);
+                    pos += 4;
+                }
+                else
+                {
+                    hero->exp = 0;
+                }
+
+                // True if hero has specified abilities
+                if(readChar(buffer, pos))
+                {
+                    int howMany = read_le_u32(buffer + pos);
+                    pos += 4;
+                    hero->secSkills.resize(howMany);
+                    for(int yy = 0; yy < howMany; ++yy)
+                    {
+                        hero->secSkills[yy].first = buffer[pos];
+                        ++pos;
+                        hero->secSkills[yy].second = buffer[pos];
+                        ++pos;
+                    }
+                }
+
+                loadArtifactsOfHero(hero);
+
+                // custom bio
+                if(readChar(buffer, pos))
+                {
+                    hero->biography = readString(buffer, pos);
+                }
+
+                // 0xFF is default, 00 male, 01 female
+                hero->sex = buffer[pos++];
+
+                // are spells
+                if(readChar(buffer, pos))
+                {
+                    int ist = pos;
+                    for(; pos < ist + 9; ++pos)
+                    {
+                        ui8 c = buffer[pos];
+                        for(int yy = 0; yy < 8; ++yy)
+                        {
+                            if((pos - ist) * 8 + yy < GameConstants::SPELLS_QUANTITY)
+                            {
+                                if(c == (c | static_cast<ui8>(std::pow(2, yy))))
+                                {
+                                    hero->spells.insert((pos - ist) * 8 + yy);
+                                }
+                            }
+                        }
+                    }
+                }
+
+                // customPrimSkills
+                if(readChar(buffer, pos))
+                {
+                    for(int xx = 0; xx < GameConstants::PRIMARY_SKILLS; xx++)
+                    {
+                        hero->pushPrimSkill(xx, buffer[pos++]);
+                    }
+                }
+                map->predefinedHeroes.push_back(hero);
+            }
+            break;
+        }
+    case EMapFormat::ROE:
+        pos+=0;
+        break;
+    }
+}
+
+void CMapLoaderH3M::loadArtifactsOfHero(CGHeroInstance * hero)
+{
+    bool artSet = buffer[pos];
+    ++pos;
+
+    // True if artifact set is not default (hero has some artifacts)
+    if(artSet)
+    {
+        for(int pom = 0; pom < 16; pom++)
+        {
+            loadArtifactToSlot(hero, pom);
+        }
+
+        // misc5 art //17
+        if(map->version >= EMapFormat::SOD)
+        {
+            if(!loadArtifactToSlot(hero, ArtifactPosition::MACH4))
+            {
+                // catapult by default
+                hero->putArtifact(ArtifactPosition::MACH4, createArtifact(GameConstants::ID_CATAPULT));
+            }
+        }
+
+        loadArtifactToSlot(hero, ArtifactPosition::SPELLBOOK);
+
+        // 19 //???what is that? gap in file or what? - it's probably fifth slot..
+        if(map->version > EMapFormat::ROE)
+        {
+            loadArtifactToSlot(hero, ArtifactPosition::MISC5);
+        }
+        else
+        {
+            ++pos;
+        }
+
+        // bag artifacts //20
+        // number of artifacts in hero's bag
+        int amount = read_le_u16(buffer + pos);
+        pos += 2;
+        for(int ss = 0; ss < amount; ++ss)
+        {
+            loadArtifactToSlot(hero, GameConstants::BACKPACK_START + hero->artifactsInBackpack.size());
+        }
+    }
+}
+
+bool CMapLoaderH3M::loadArtifactToSlot(CGHeroInstance * hero, int slot)
+{
+    const int artmask = map->version == EMapFormat::ROE ? 0xff : 0xffff;
+    int aid;
+
+    if(map->version == EMapFormat::ROE)
+    {
+        aid = buffer[pos];
+        pos++;
+    }
+    else
+    {
+        aid = read_le_u16(buffer + pos);
+        pos += 2;
+    }
+
+    bool isArt  =  aid != artmask;
+    if(isArt)
+    {
+        if(vstd::contains(VLC->arth->bigArtifacts, aid) && slot >= GameConstants::BACKPACK_START)
+        {
+            tlog3 << "Warning: A big artifact (war machine) in hero's backpack, ignoring..." << std::endl;
+            return false;
+        }
+        if(aid == 0 && slot == ArtifactPosition::MISC5)
+        {
+            //TODO: check how H3 handles it -> art 0 in slot 18 in AB map
+            tlog3 << "Spellbook to MISC5 slot? Putting it spellbook place. AB format peculiarity ? (format "
+                  << static_cast<int>(map->version) << ")" << std::endl;
+            slot = ArtifactPosition::SPELLBOOK;
+        }
+
+        hero->putArtifact(slot, createArtifact(aid));
+    }
+
+    return isArt;
+}
+
+CArtifactInstance * CMapLoaderH3M::createArtifact(int aid, int spellID /*= -1*/)
+{
+    CArtifactInstance * a = nullptr;
+    if(aid >= 0)
+    {
+        if(spellID < 0)
+        {
+            a = CArtifactInstance::createNewArtifactInstance(aid);
+        }
+        else
+        {
+            a = CArtifactInstance::createScroll(VLC->spellh->spells[spellID]);
+        }
+    }
+    else
+    {
+        a = new CArtifactInstance;
+    }
+
+    addNewArtifactInstance(a);
+
+    //TODO make it nicer
+    if(a->artType && a->artType->constituents)
+    {
+        CCombinedArtifactInstance * comb = dynamic_cast<CCombinedArtifactInstance *>(a);
+        BOOST_FOREACH(CCombinedArtifactInstance::ConstituentInfo & ci, comb->constituentsInfo)
+        {
+            addNewArtifactInstance(ci.art);
+        }
+    }
+
+    return a;
+}
+
+void CMapLoaderH3M::addNewArtifactInstance(CArtifactInstance * art)
+{
+    art->id = map->artInstances.size();
+    map->artInstances.push_back(art);
+}
+
+void CMapLoaderH3M::readTerrain()
+{
+    // Allocate memory for terrain data
+    map->terrain = new TerrainTile**[map->width];
+    for(int ii = 0; ii < map->width; ii++)
+    {
+        map->terrain[ii] = new TerrainTile*[map->height];
+        for(int jj = 0; jj < map->height; jj++)
+        {
+            map->terrain[ii][jj] = new TerrainTile[map->twoLevel + 1];
+        }
+    }
+
+    // Read terrain
+    for(int a = 0; a < 2; ++a)
+    {
+        if(a == 1 && !map->twoLevel)
+        {
+            break;
+        }
+
+        for(int c = 0; c < map->width; c++)
+        {
+            for(int z = 0; z < map->height; z++)
+            {
+                map->terrain[z][c][a].tertype = static_cast<ETerrainType::ETerrainType>(buffer[pos++]);
+                map->terrain[z][c][a].terview = buffer[pos++];
+                map->terrain[z][c][a].riverType = static_cast<ERiverType::ERiverType>(buffer[pos++]);
+                map->terrain[z][c][a].riverDir = buffer[pos++];
+                map->terrain[z][c][a].roadType = static_cast<ERoadType::ERoadType>(buffer[pos++]);
+                map->terrain[z][c][a].roadDir = buffer[pos++];
+                map->terrain[z][c][a].extTileFlags = buffer[pos++];
+                map->terrain[z][c][a].blocked = (map->terrain[z][c][a].tertype == ETerrainType::ROCK ? 1 : 0); //underground tiles are always blocked
+                map->terrain[z][c][a].visitable = 0;
+            }
+        }
+    }
+}
+
+void CMapLoaderH3M::readDefInfo()
+{
+    int defAmount = read_le_u32(buffer + pos);
+    pos += 4;
+    map->customDefs.reserve(defAmount + 8);
+
+    // Read custom defs
+    for(int idd = 0; idd < defAmount; ++idd)
+    {
+        CGDefInfo * defInfo = new CGDefInfo;
+
+        // Read name
+        int nameLength = read_le_u32(buffer + pos);
+        pos += 4;
+        defInfo->name.reserve(nameLength);
+        for(int cd = 0; cd < nameLength; ++cd)
+        {
+            defInfo->name += buffer[pos++];
+        }
+        std::transform(defInfo->name.begin(),defInfo->name.end(),defInfo->name.begin(),(int(*)(int))toupper);
+
+        ui8 bytes[12];
+        for(int v = 0; v < 12; ++v)
+        {
+            bytes[v] = buffer[pos++];
+        }
+
+        defInfo->terrainAllowed = read_le_u16(buffer + pos);
+        pos += 2;
+        defInfo->terrainMenu = read_le_u16(buffer + pos);
+        pos += 2;
+        defInfo->id = read_le_u32(buffer + pos);
+        pos += 4;
+        defInfo->subid = read_le_u32(buffer + pos);
+        pos += 4;
+        defInfo->type = buffer[pos++];
+        defInfo->printPriority = buffer[pos++];
+        for(int zi = 0; zi < 6; ++zi)
+        {
+            defInfo->blockMap[zi] = reverse(bytes[zi]);
+        }
+        for(int zi = 0; zi < 6; ++zi)
+        {
+            defInfo->visitMap[zi] = reverse(bytes[6 + zi]);
+        }
+        pos += 16;
+        if(defInfo->id != Obj::HERO && defInfo->id != 70)
+        {
+            CGDefInfo * h = VLC->dobjinfo->gobjs[defInfo->id][defInfo->subid];
+            if(!h)
+            {
+                //remove fake entry
+                VLC->dobjinfo->gobjs[defInfo->id].erase(defInfo->subid);
+                if(VLC->dobjinfo->gobjs[defInfo->id].size())
+                {
+                    VLC->dobjinfo->gobjs.erase(defInfo->id);
+                }
+                tlog2 << "\t\tWarning: no defobjinfo entry for object ID="
+                      << defInfo->id << " subID=" << defInfo->subid << std::endl;
+            }
+            else
+            {
+                defInfo->visitDir = VLC->dobjinfo->gobjs[defInfo->id][defInfo->subid]->visitDir;
+            }
+        }
+        else
+        {
+            defInfo->visitDir = 0xff;
+        }
+
+        if(defInfo->id == Obj::EVENT)
+        {
+            std::memset(defInfo->blockMap, 255, 6);
+        }
+
+        //calculating coverageMap
+        defInfo->fetchInfoFromMSK();
+
+        map->customDefs.push_back(defInfo);
+    }
+
+    //add holes - they always can appear
+    for(int i = 0; i < 8 ; ++i)
+    {
+        map->customDefs.push_back(VLC->dobjinfo->gobjs[124][i]);
+    }
+}
+
+void CMapLoaderH3M::readObjects()
+{
+    int howManyObjs = read_le_u32(buffer + pos);
+    pos += 4;
+
+    for(int ww = 0; ww < howManyObjs; ++ww)
+    {
+        CGObjectInstance * nobj = 0;
+
+        int3 objPos;
+        objPos.x = buffer[pos++];
+        objPos.y = buffer[pos++];
+        objPos.z = buffer[pos++];
+
+        int defnum = read_le_u32(buffer + pos);
+        pos += 4;
+        int idToBeGiven = map->objects.size();
+
+        CGDefInfo * defInfo = map->customDefs.at(defnum);
+        pos += 5;
+
+        switch(defInfo->id)
+        {
+        case Obj::EVENT:
+            {
+                CGEvent * evnt = new CGEvent();
+                nobj = evnt;
+
+                bool guardMess = buffer[pos];
+                ++pos;
+                if(guardMess)
+                {
+                    int messLong = read_le_u32(buffer + pos);
+                    pos += 4;
+                    if(messLong > 0)
+                    {
+                        for(int yy = 0; yy < messLong; ++yy)
+                        {
+                            evnt->message += buffer[pos + yy];
+                        }
+                        pos += messLong;
+                    }
+                    if(buffer[pos++])
+                    {
+                        readCreatureSet(evnt, 7, map->version > EMapFormat::ROE);
+                    }
+                    pos += 4;
+                }
+                evnt->gainedExp = read_le_u32(buffer + pos);
+                pos += 4;
+                evnt->manaDiff = read_le_u32(buffer + pos);
+                pos += 4;
+                evnt->moraleDiff = static_cast<char>(buffer[pos]);
+                ++pos;
+                evnt->luckDiff = static_cast<char>(buffer[pos]);
+                ++pos;
+
+                evnt->resources.resize(GameConstants::RESOURCE_QUANTITY);
+                for(int x = 0; x < 7; ++x)
+                {
+                    evnt->resources[x] = read_le_u32(buffer + pos);
+                    pos += 4;
+                }
+
+                evnt->primskills.resize(GameConstants::PRIMARY_SKILLS);
+                for(int x = 0; x < 4; ++x)
+                {
+                    evnt->primskills[x] = buffer[pos];
+                    ++pos;
+                }
+
+                int gabn; // Number of gained abilities
+                gabn = buffer[pos];
+                ++pos;
+                for(int oo = 0; oo < gabn; ++oo)
+                {
+                    evnt->abilities.push_back(buffer[pos]);
+                    ++pos;
+                    evnt->abilityLevels.push_back(buffer[pos]);
+                    ++pos;
+                }
+
+                int gart = buffer[pos]; // Number of gained artifacts
+                ++pos;
+                for(int oo = 0; oo < gart; ++oo)
+                {
+                    if(map->version == EMapFormat::ROE)
+                    {
+                        evnt->artifacts.push_back(buffer[pos]);
+                        ++pos;
+                    }
+                    else
+                    {
+                        evnt->artifacts.push_back(read_le_u16(buffer + pos));
+                        pos += 2;
+                    }
+                }
+
+                int gspel = buffer[pos]; // Number of gained spells
+                ++pos;
+                for(int oo = 0; oo < gspel; ++oo)
+                {
+                    evnt->spells.push_back(buffer[pos]);
+                    ++pos;
+                }
+
+                int gcre = buffer[pos]; //number of gained creatures
+                ++pos;
+                readCreatureSet(&evnt->creatures, gcre, map->version > EMapFormat::ROE);
+
+                pos += 8;
+                evnt->availableFor = buffer[pos];
+                ++pos;
+                evnt->computerActivate = buffer[pos];
+                ++pos;
+                evnt->removeAfterVisit = buffer[pos];
+                ++pos;
+                evnt->humanActivate = true;
+
+                pos += 4;
+                break;
+            }
+        case 34: case 70: case 62: //34 - hero; 70 - random hero; 62 - prison
+            {
+                nobj = readHero(idToBeGiven);
+                break;
+            }
+        case 4: //Arena
+        case 51: //Mercenary Camp
+        case 23: //Marletto Tower
+        case 61: // Star Axis
+        case 32: // Garden of Revelation
+        case 100: //Learning Stone
+        case 102: //Tree of Knowledge
+        case 41: //Library of Enlightenment
+        case 47: //School of Magic
+        case 107: //School of War
+            {
+                nobj = new CGVisitableOPH;
+                break;
+            }
+        case 55: //mystical garden
+        case 112://windmill
+        case 109://water wheel
+            {
+                nobj = new CGVisitableOPW;
+                break;
+            }
+        case 43: //teleport
+        case 44: //teleport
+        case 45: //teleport
+        case 103://subterranean gate
+        case 111://Whirlpool
+            {
+                nobj = new CGTeleport;
+                break;
+            }
+        case 12: //campfire
+        case 29: //Flotsam
+        case 82: //Sea Chest
+        case 86: //Shipwreck Survivor
+        case 101://treasure chest
+            {
+                nobj = new CGPickable;
+                break;
+            }
+        case 54:  //Monster
+        case 71: case 72: case 73: case 74: case 75:	// Random Monster 1 - 4
+        case 162: case 163: case 164:					// Random Monster 5 - 7
+            {
+                CGCreature * cre = new CGCreature;
+                nobj = cre;
+
+                if(map->version > EMapFormat::ROE)
+                {
+                    cre->identifier = read_le_u32(buffer + pos);
+                    pos += 4;
+                    map->questIdentifierToId[cre->identifier] = idToBeGiven;
+                }
+
+                CStackInstance * hlp = new CStackInstance;
+                hlp->count = read_le_u16(buffer + pos);
+                pos += 2;
+
+                //type will be set during initialization
+                cre->putStack(0, hlp);
+
+                cre->character = buffer[pos];
+                ++pos;
+                bool isMesTre = buffer[pos]; //true if there is message or treasury
+                ++pos;
+                if(isMesTre)
+                {
+                    cre->message = readString(buffer, pos);
+                    cre->resources.resize(GameConstants::RESOURCE_QUANTITY);
+                    for(int j = 0; j < 7; ++j)
+                    {
+                        cre->resources[j] = read_le_u32(buffer + pos);
+                        pos += 4;
+                    }
+
+                    int artID;
+                    if (map->version == EMapFormat::ROE)
+                    {
+                        artID = buffer[pos];
+                        ++pos;
+                    }
+                    else
+                    {
+                        artID = read_le_u16(buffer + pos);
+                        pos += 2;
+                    }
+
+                    if(map->version == EMapFormat::ROE)
+                    {
+                        if(artID != 0xff)
+                        {
+                            cre->gainedArtifact = artID;
+                        }
+                        else
+                        {
+                            cre->gainedArtifact = -1;
+                        }
+                    }
+                    else
+                    {
+                        if(artID != 0xffff)
+                        {
+                            cre->gainedArtifact = artID;
+                        }
+                        else
+                        {
+                            cre->gainedArtifact = -1;
+                        }
+                    }
+                }
+                cre->neverFlees = buffer[pos];
+                ++pos;
+                cre->notGrowingTeam = buffer[pos];
+                ++pos;
+                pos += 2;
+                break;
+            }
+        case 59: case 91: //ocean bottle and sign
+            {
+                CGSignBottle * sb = new CGSignBottle;
+                nobj = sb;
+                sb->message = readString(buffer, pos);
+                pos += 4;
+                break;
+            }
+        case 83: //seer's hut
+            {
+                nobj = readSeerHut();
+                addQuest(nobj);
+                break;
+            }
+        case 113: //witch hut
+            {
+                CGWitchHut * wh = new CGWitchHut;
+                nobj = wh;
+
+                // in reo we cannot specify it - all are allowed (I hope)
+                if(map->version > EMapFormat::ROE)
+                {
+                    int ist=pos;
+                    for(; pos < ist + 4; ++pos)
+                    {
+                        ui8 c = buffer[pos];
+                        for(int yy = 0; yy < 8; ++yy)
+                        {
+                            if((pos - ist) * 8 + yy < GameConstants::SKILL_QUANTITY)
+                            {
+                                if(c == (c | static_cast<ui8>(std::pow(2, yy))))
+                                {
+                                    wh->allowedAbilities.push_back((pos - ist) * 8 + yy);
+                                }
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    // RoE map
+                    for(int gg = 0; gg < GameConstants::SKILL_QUANTITY; ++gg)
+                    {
+                        wh->allowedAbilities.push_back(gg);
+                    }
+                }
+                break;
+            }
+        case 81: //scholar
+            {
+                CGScholar * sch = new CGScholar;
+                nobj = sch;
+                sch->bonusType = buffer[pos++];
+                sch->bonusID = buffer[pos++];
+                pos += 6;
+                break;
+            }
+        case 33: case 219: //garrison
+            {
+                CGGarrison * gar = new CGGarrison;
+                nobj = gar;
+                nobj->setOwner(buffer[pos++]);
+                pos += 3;
+                readCreatureSet(gar, 7, map->version > EMapFormat::ROE);
+                if(map->version > EMapFormat::ROE)
+                {
+                    gar->removableUnits = buffer[pos];
+                    ++pos;
+                }
+                else
+                {
+                    gar->removableUnits = true;
+                }
+                pos += 8;
+                break;
+            }
+        case 5: //artifact
+        case 65: case 66: case 67: case 68: case 69: //random artifact
+        case 93: //spell scroll
+            {
+                int artID = -1;
+                int spellID = -1;
+                CGArtifact * art = new CGArtifact;
+                nobj = art;
+
+                bool areSettings = buffer[pos++];
+                if(areSettings)
+                {
+                    art->message = readString(buffer, pos);
+                    bool areGuards = buffer[pos++];
+                    if(areGuards)
+                    {
+                        readCreatureSet(art, 7, map->version > EMapFormat::ROE);
+                    }
+                    pos += 4;
+                }
+
+                if(defInfo->id == 93)
+                {
+                    spellID = read_le_u32(buffer + pos);
+                    pos += 4;
+                    artID = 1;
+                }
+                else if(defInfo->id == 5)
+                {
+                    //specific artifact
+                    artID = defInfo->subid;
+                }
+
+                art->storedArtifact = createArtifact(artID, spellID);
+                break;
+            }
+        case 76: case 79: //random resource; resource
+            {
+                CGResource * res = new CGResource;
+                nobj = res;
+
+                bool isMessGuard = buffer[pos];
+                ++pos;
+                if(isMessGuard)
+                {
+                    res->message = readString(buffer, pos);
+                    if(buffer[pos++])
+                    {
+                        readCreatureSet(res, 7, map->version > EMapFormat::ROE);
+                    }
+                    pos += 4;
+                }
+                res->amount = read_le_u32(buffer + pos);
+                pos += 4;
+                if(defInfo->subid == 6)
+                {
+                    // Gold is multiplied by 100.
+                    res->amount *= 100;
+                }
+                pos += 4;
+
+                break;
+            }
+        case 77: case 98: //random town; town
+            {
+                nobj = readTown(defInfo->subid);
+                break;
+            }
+        case 53:
+        case 220://mine (?)
+            {
+                nobj = new CGMine;
+                nobj->setOwner(buffer[pos++]);
+                pos += 3;
+                break;
+            }
+        case 17: case 18: case 19: case 20: //dwellings
+            {
+                nobj = new CGDwelling;
+                nobj->setOwner(buffer[pos++]);
+                pos += 3;
+                break;
+            }
+        case 78: //Refugee Camp
+        case 106: //War Machine Factory
+            {
+                nobj = new CGDwelling;
+                break;
+            }
+        case 88: case 89: case 90: //spell shrine
+            {
+                CGShrine * shr = new CGShrine;
+                nobj = shr;
+                shr->spell = buffer[pos];
+                pos += 4;
+                break;
+            }
+        case 6: //pandora's box
+            {
+                CGPandoraBox * box = new CGPandoraBox;
+                nobj = box;
+                bool messg = buffer[pos];
+                ++pos;
+                if(messg)
+                {
+                    box->message = readString(buffer, pos);
+                    if(buffer[pos++])
+                    {
+                        readCreatureSet(box, 7, map->version > EMapFormat::ROE);
+                    }
+                    pos += 4;
+                }
+
+                box->gainedExp = read_le_u32(buffer + pos);
+                pos += 4;
+                box->manaDiff = read_le_u32(buffer + pos);
+                pos += 4;
+                box->moraleDiff = static_cast<si8>(buffer[pos]);
+                ++pos;
+                box->luckDiff = static_cast<si8>(buffer[pos]);
+                ++pos;
+
+                box->resources.resize(GameConstants::RESOURCE_QUANTITY);
+                for(int x = 0; x < 7; ++x)
+                {
+                    box->resources[x] = read_le_u32(buffer + pos);
+                    pos += 4;
+                }
+
+                box->primskills.resize(GameConstants::PRIMARY_SKILLS);
+                for(int x = 0; x < 4; ++x)
+                {
+                    box->primskills[x] = buffer[pos];
+                    ++pos;
+                }
+
+                int gabn; //number of gained abilities
+                gabn = buffer[pos];
+                ++pos;
+                for(int oo = 0; oo < gabn; ++oo)
+                {
+                    box->abilities.push_back(buffer[pos]);
+                    ++pos;
+                    box->abilityLevels.push_back(buffer[pos]);
+                    ++pos;
+                }
+                int gart = buffer[pos]; //number of gained artifacts
+                ++pos;
+                for(int oo = 0; oo < gart; ++oo)
+                {
+                    if(map->version > EMapFormat::ROE)
+                    {
+                        box->artifacts.push_back(read_le_u16(buffer + pos));
+                        pos += 2;
+                    }
+                    else
+                    {
+                        box->artifacts.push_back(buffer[pos]);
+                        ++pos;
+                    }
+                }
+                int gspel = buffer[pos]; //number of gained spells
+                ++pos;
+                for(int oo = 0; oo < gspel; ++oo)
+                {
+                    box->spells.push_back(buffer[pos]);
+                    ++pos;
+                }
+                int gcre = buffer[pos]; //number of gained creatures
+                ++pos;
+                readCreatureSet(&box->creatures, gcre, map->version > EMapFormat::ROE);
+                pos += 8;
+                break;
+            }
+        case 36: //grail
+            {
+                map->grailPos = objPos;
+                map->grailRadious = read_le_u32(buffer + pos);
+                pos += 4;
+                continue;
+            }
+        //dwellings
+        case 216: //same as castle + level range
+        case 217: //same as castle
+        case 218: //level range
+            {
+                nobj = new CGDwelling;
+                CSpecObjInfo * spec = nullptr;
+                switch(defInfo->id)
+                {
+                    break; case 216: spec = new CCreGenLeveledCastleInfo;
+                    break; case 217: spec = new CCreGenAsCastleInfo;
+                    break; case 218: spec = new CCreGenLeveledInfo;
+                }
+
+                spec->player = read_le_u32(buffer + pos);
+                pos += 4;
+
+                //216 and 217
+                if (auto castleSpec = dynamic_cast<CCreGenAsCastleInfo *>(spec))
+                {
+                    castleSpec->identifier =  read_le_u32(buffer + pos);
+                    pos += 4;
+                    if(!castleSpec->identifier)
+                    {
+                        castleSpec->asCastle = false;
+                        castleSpec->castles[0] = buffer[pos];
+                        ++pos;
+                        castleSpec->castles[1] = buffer[pos];
+                        ++pos;
+                    }
+                    else
+                    {
+                        castleSpec->asCastle = true;
+                    }
+                }
+
+                //216 and 218
+                if (auto lvlSpec = dynamic_cast<CCreGenLeveledInfo *>(spec))
+                {
+                    lvlSpec->minLevel = std::max(buffer[pos], ui8(1));
+                    ++pos;
+                    lvlSpec->maxLevel = std::min(buffer[pos], ui8(7));
+                    ++pos;
+                }
+                nobj->setOwner(spec->player);
+                static_cast<CGDwelling *>(nobj)->info = spec;
+                break;
+            }
+        case 215:
+            {
+                CGQuestGuard * guard = new CGQuestGuard;
+                addQuest(guard);
+                readQuest(guard);
+                nobj = guard;
+                break;
+            }
+        case 28: //faerie ring
+        case 14: //Swan pond
+        case 38: //idol of fortune
+        case 30: //Fountain of Fortune
+        case 64: //Rally Flag
+        case 56: //oasis
+        case 96: //temple
+        case 110://Watering Hole
+        case 31: //Fountain of Youth
+        case 11: //Buoy
+        case 52: //Mermaid
+        case 94: //Stables
+            {
+                nobj = new CGBonusingObject;
+                break;
+            }
+        case 49: //Magic Well
+            {
+                nobj = new CGMagicWell;
+                break;
+            }
+        case 15: //Cover of darkness
+        case 58: //Redwood Observatory
+        case 60: //Pillar of Fire
+            {
+                nobj = new CGObservatory;
+                break;
+            }
+        case 22: //Corpse
+        case 39: //Lean To
+        case 105://Wagon
+        case 108://Warrior's Tomb
+            {
+                nobj = new CGOnceVisitable;
+                break;
+            }
+        case 8: //Boat
+            {
+                nobj = new CGBoat;
+                break;
+            }
+        case 92: //Sirens
+            {
+                nobj = new CGSirens;
+                break;
+            }
+        case 87: //Shipyard
+            {
+                nobj = new CGShipyard;
+                nobj->setOwner(read_le_u32(buffer + pos));
+                pos += 4;
+                break;
+            }
+        case 214: //hero placeholder
+            {
+                CGHeroPlaceholder * hp = new CGHeroPlaceholder;
+                nobj = hp;
+
+                int a = buffer[pos++]; //unknown byte, seems to be always 0 (if not - scream!)
+                tlog2 << "Unhandled Hero Placeholder detected: " << a << std::endl;
+
+                int htid = buffer[pos++]; //hero type id
+                nobj->subID = htid;
+
+                if(htid == 0xff)
+                {
+                    hp->power = buffer[pos++];
+                }
+                else
+                {
+                    hp->power = 0;
+                }
+
+                break;
+            }
+        case 10: //Keymaster
+            {
+                nobj = new CGKeymasterTent;
+                break;
+            }
+        case 9: //Border Guard
+            {
+                nobj = new CGBorderGuard;
+                addQuest(nobj);
+                break;
+            }
+        case 212: //Border Gate
+            {
+                nobj = new CGBorderGate;
+                addQuest (nobj);
+                break;
+            }
+        case 27: case 37: //Eye and Hut of Magi
+            {
+                nobj = new CGMagi;
+                break;
+            }
+        case 16: case 24: case 25: case 84: case 85: //treasure bank
+            {
+                nobj = new CBank;
+                break;
+            }
+        case 63: //Pyramid
+            {
+                nobj = new CGPyramid;
+                break;
+            }
+        case 13: //Cartographer
+            {
+                nobj = new CCartographer;
+                break;
+            }
+        case 48: //Magic Spring
+            {
+                nobj = new CGMagicSpring;
+                break;
+            }
+        case 97: //den of thieves
+            {
+                nobj = new CGDenOfthieves;
+                break;
+            }
+        case 57: //Obelisk
+            {
+                nobj = new CGObelisk;
+                break;
+            }
+        case 42: //Lighthouse
+            {
+                nobj = new CGLighthouse;
+                nobj->tempOwner = read_le_u32(buffer + pos);
+                pos += 4;
+                break;
+            }
+        case 2: //Altar of Sacrifice
+        case 99: //Trading Post
+        case 213: //Freelancer's Guild
+        case 221: //Trading Post (snow)
+            {
+                nobj = new CGMarket;
+                break;
+            }
+        case 104: //University
+            {
+                nobj = new CGUniversity;
+                break;
+            }
+        case 7: //Black Market
+            {
+                nobj = new CGBlackMarket;
+                break;
+            }
+        default: //any other object
+            {
+                nobj = new CGObjectInstance;
+                break;
+            }
+        }
+
+        nobj->pos = objPos;
+        nobj->ID = defInfo->id;
+        nobj->id = idToBeGiven;
+        if(nobj->ID != Obj::HERO && nobj->ID != Obj::HERO_PLACEHOLDER && nobj->ID != Obj::PRISON)
+        {
+            nobj->subID = defInfo->subid;
+        }
+        nobj->defInfo = defInfo;
+        assert(idToBeGiven == map->objects.size());
+        map->objects.push_back(nobj);
+        if(nobj->ID == Obj::TOWN)
+        {
+            map->towns.push_back(static_cast<CGTownInstance *>(nobj));
+        }
+        if(nobj->ID == Obj::HERO)
+        {
+            map->heroes.push_back(static_cast<CGHeroInstance*>(nobj));
+        }
+    }
+
+    std::sort(map->heroes.begin(), map->heroes.end(), [](const ConstTransitivePtr<CGHeroInstance> & a, const ConstTransitivePtr<CGHeroInstance> & b)
+    {
+        return a->subID < b->subID;
+    });
+}
+
+void CMapLoaderH3M::readCreatureSet(CCreatureSet * out, int number, bool version)
+{
+    const int bytesPerCre = version ? 4 : 3;
+    const int maxID = version ? 0xffff : 0xff;
+
+    for(int ir = 0; ir < number; ++ir)
+    {
+        int creID;
+        int count;
+
+        if(version)
+        {
+            creID = read_le_u16(buffer + pos + ir * bytesPerCre);
+            count = read_le_u16(buffer + pos + ir * bytesPerCre + 2);
+        }
+        else
+        {
+            creID = buffer[pos + ir * bytesPerCre];
+            count = read_le_u16(buffer + pos + ir * bytesPerCre + 1);
+        }
+
+        // Empty slot
+        if(creID == maxID) continue;
+
+        CStackInstance * hlp = new CStackInstance;
+        hlp->count = count;
+
+        if(creID > maxID - 0xf)
+        {
+            //this will happen when random object has random army
+            creID = maxID + 1 - creID + VLC->creh->creatures.size();
+            hlp->idRand = creID;
+        }
+        else
+        {
+            hlp->setType(creID);
+        }
+
+        out->putStack(ir, hlp);
+    }
+
+    pos += number * bytesPerCre;
+    out->validTypes(true);
+}
+
+CGObjectInstance * CMapLoaderH3M::readHero(int idToBeGiven)
+{
+    CGHeroInstance * nhi = new CGHeroInstance;
+
+    int identifier = 0;
+    if(map->version > EMapFormat::ROE)
+    {
+        identifier = read_le_u32(buffer + pos);
+        pos += 4;
+        map->questIdentifierToId[identifier] = idToBeGiven;
+    }
+
+    ui8 owner = buffer[pos++];
+    nhi->subID = buffer[pos++];
+
+    for(int j = 0; j < map->predefinedHeroes.size(); ++j)
+    {
+        if(map->predefinedHeroes[j]->subID == nhi->subID)
+        {
+            tlog0 << "Hero " << nhi->subID << " will be taken from the predefined heroes list." << std::endl;
+            delete nhi;
+            nhi = map->predefinedHeroes[j];
+            break;
+        }
+    }
+    nhi->setOwner(owner);
+
+    nhi->portrait = nhi->subID;
+
+    for(int j = 0; j < map->disposedHeroes.size(); ++j)
+    {
+        if(map->disposedHeroes[j].ID == nhi->subID)
+        {
+            nhi->name = map->disposedHeroes[j].name;
+            nhi->portrait = map->disposedHeroes[j].portrait;
+            break;
+        }
+    }
+
+    // True if hero has nonstandard name
+    if(readChar(buffer, pos))
+    {
+        nhi->name = readString(buffer, pos);
+    }
+    if(map->version > EMapFormat::AB)
+    {
+        // True if hero's experience is greater than 0
+        if(readChar(buffer, pos))
+        {
+            nhi->exp = read_le_u32(buffer + pos);
+            pos += 4;
+        }
+        else
+        {
+            nhi->exp = 0xffffffff;
+        }
+    }
+    else
+    {
+        nhi->exp = read_le_u32(buffer + pos);
+        pos += 4;
+
+        //0 means "not set" in <=AB maps
+        if(!nhi->exp)
+        {
+            nhi->exp = 0xffffffff;
+        }
+    }
+
+    bool portrait = buffer[pos];
+    ++pos;
+    if(portrait)
+    {
+        nhi->portrait = buffer[pos++];
+    }
+
+    // True if hero has specified abilities
+    if(readChar(buffer, pos))
+    {
+        int howMany = read_le_u32(buffer + pos);
+        pos += 4;
+        nhi->secSkills.resize(howMany);
+        for(int yy = 0; yy < howMany; ++yy)
+        {
+            nhi->secSkills[yy].first = buffer[pos++];
+            nhi->secSkills[yy].second = buffer[pos++];
+        }
+    }
+
+    // True if hero has nonstandard garrison
+    if(readChar(buffer, pos))
+    {
+        readCreatureSet(nhi, 7, map->version > EMapFormat::ROE);
+    }
+
+    nhi->formation = buffer[pos];
+    ++pos;
+    loadArtifactsOfHero(nhi);
+    nhi->patrol.patrolRadious = buffer[pos];
+    ++pos;
+    if(nhi->patrol.patrolRadious == 0xff)
+    {
+        nhi->patrol.patrolling = false;
+    }
+    else
+    {
+        nhi->patrol.patrolling = true;
+    }
+
+    if(map->version > EMapFormat::ROE)
+    {
+        // True if hero has nonstandard (mapmaker defined) biography
+        if(readChar(buffer, pos))
+        {
+            nhi->biography = readString(buffer, pos);
+        }
+        nhi->sex = buffer[pos];
+        ++pos;
+
+        // Remove trash
+        if (nhi->sex != 0xFF)
+        {
+            nhi->sex &= 1;
+        }
+    }
+    else
+    {
+        nhi->sex = 0xFF;
+    }
+
+    // Spells
+    if(map->version > EMapFormat::AB)
+    {
+        bool areSpells = buffer[pos];
+        ++pos;
+
+        if(areSpells)
+        {
+            nhi->spells.insert(0xffffffff); //placeholder "preset spells"
+            int ist = pos;
+            for(; pos < ist + 9; ++pos)
+            {
+                ui8 c = buffer[pos];
+                for(int yy = 0; yy < 8; ++yy)
+                {
+                    if((pos - ist) * 8 + yy < GameConstants::SPELLS_QUANTITY)
+                    {
+                        if(c == (c | static_cast<ui8>(std::pow(2, yy))))
+                        {
+                            nhi->spells.insert((pos - ist) * 8 + yy);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    else if(map->version == EMapFormat::AB)
+    {
+        //we can read one spell
+        ui8 buff = buffer[pos];
+        ++pos;
+        if(buff != 254)
+        {
+            nhi->spells.insert(0xffffffff); //placeholder "preset spells"
+            if(buff < 254) //255 means no spells
+            {
+                nhi->spells.insert(buff);
+            }
+        }
+    }
+
+    if(map->version > EMapFormat::AB)
+    {
+        //customPrimSkills
+        if(readChar(buffer, pos))
+        {
+            for(int xx = 0; xx < GameConstants::PRIMARY_SKILLS; ++xx)
+            {
+                nhi->pushPrimSkill(xx, buffer[pos++]);
+            }
+        }
+    }
+    pos += 16;
+
+    return nhi;
+}
+
+CGSeerHut * CMapLoaderH3M::readSeerHut()
+{
+    CGSeerHut * hut = new CGSeerHut;
+
+    if(map->version > EMapFormat::ROE)
+    {
+        readQuest(hut);
+    }
+    else
+    {
+        //RoE
+        int artID = buffer[pos];
+        ++pos;
+        if (artID != 255)
+        {
+            //not none quest
+            hut->quest->m5arts.push_back (artID);
+            hut->quest->missionType = CQuest::MISSION_ART;
+        }
+        else
+        {
+            hut->quest->missionType = CQuest::MISSION_NONE;
+        }
+        hut->quest->lastDay = -1; //no timeout
+        hut->quest->isCustomFirst = hut->quest->isCustomNext = hut->quest->isCustomComplete = false;
+    }
+
+    if (hut->quest->missionType)
+    {
+        ui8 rewardType = buffer[pos];
+        ++pos;
+        hut->rewardType = rewardType;
+
+        switch(rewardType)
+        {
+        case 1:
+            {
+                hut->rVal = read_le_u32(buffer + pos);
+                pos += 4;
+                break;
+            }
+        case 2:
+            {
+                hut->rVal = read_le_u32(buffer + pos);
+                pos += 4;
+                break;
+            }
+        case 3:
+            {
+                hut->rVal = buffer[pos];
+                ++pos;
+                break;
+            }
+        case 4:
+            {
+                hut->rVal = buffer[pos];
+                ++pos;
+                break;
+            }
+        case 5:
+            {
+                hut->rID = buffer[pos];
+                ++pos;
+                // Only the first 3 bytes are used. Skip the 4th.
+                hut->rVal = read_le_u32(buffer + pos) & 0x00ffffff;
+                pos += 4;
+                break;
+            }
+        case 6:
+            {
+                hut->rID = buffer[pos];
+                ++pos;
+                hut->rVal = buffer[pos];
+                ++pos;
+                break;
+            }
+        case 7:
+            {
+                hut->rID = buffer[pos];
+                ++pos;
+                hut->rVal = buffer[pos];
+                ++pos;
+                break;
+            }
+        case 8:
+            {
+                if (map->version == EMapFormat::ROE)
+                {
+                    hut->rID = buffer[pos];
+                    ++pos;
+                }
+                else
+                {
+                    hut->rID = read_le_u16(buffer + pos);
+                    pos += 2;
+                }
+                break;
+            }
+        case 9:
+            {
+                hut->rID = buffer[pos];
+                ++pos;
+                break;
+            }
+        case 10:
+            {
+                if(map->version > EMapFormat::ROE)
+                {
+                    hut->rID = read_le_u16(buffer + pos);
+                    pos += 2;
+                    hut->rVal = read_le_u16(buffer + pos);
+                    pos += 2;
+                }
+                else
+                {
+                    hut->rID = buffer[pos];
+                    ++pos;
+                    hut->rVal = read_le_u16(buffer + pos);
+                    pos += 2;
+                }
+                break;
+            }
+        }
+        pos += 2;
+    }
+    else
+    {
+        // missionType==255
+        pos += 3;
+    }
+
+    return hut;
+}
+
+void CMapLoaderH3M::readQuest(IQuestObject * guard)
+{
+    guard->quest->missionType = buffer[pos];
+    ++pos;
+
+    switch(guard->quest->missionType)
+    {
+    case 0:
+        return;
+    case 2:
+        {
+            guard->quest->m2stats.resize(4);
+            for(int x = 0; x < 4; ++x)
+            {
+                guard->quest->m2stats[x] = buffer[pos++];
+            }
+        }
+        break;
+    case 1:
+    case 3:
+    case 4:
+        {
+            guard->quest->m13489val = read_le_u32(buffer + pos);
+            pos += 4;
+            break;
+        }
+    case 5:
+        {
+            int artNumber = buffer[pos];
+            ++pos;
+            for(int yy = 0; yy < artNumber; ++yy)
+            {
+                int artid = read_le_u16(buffer + pos);
+                pos += 2;
+                guard->quest->m5arts.push_back(artid);
+                map->allowedArtifact[artid] = false; //these are unavailable for random generation
+            }
+            break;
+        }
+    case 6:
+        {
+            int typeNumber = buffer[pos];
+            ++pos;
+            guard->quest->m6creatures.resize(typeNumber);
+            for(int hh = 0; hh < typeNumber; ++hh)
+            {
+                guard->quest->m6creatures[hh].type = VLC->creh->creatures[read_le_u16(buffer + pos)];
+                pos += 2;
+                guard->quest->m6creatures[hh].count = read_le_u16(buffer + pos);
+                pos += 2;
+            }
+            break;
+        }
+    case 7:
+        {
+            guard->quest->m7resources.resize(7);
+            for(int x = 0; x < 7; ++x)
+            {
+                guard->quest->m7resources[x] = read_le_u32(buffer + pos);
+                pos += 4;
+            }
+            break;
+        }
+    case 8:
+    case 9:
+        {
+            guard->quest->m13489val = buffer[pos];
+            ++pos;
+            break;
+        }
+    }
+
+    int limit = read_le_u32(buffer + pos);
+    pos += 4;
+    if(limit == (static_cast<int>(0xffffffff)))
+    {
+        guard->quest->lastDay = -1;
+    }
+    else
+    {
+        guard->quest->lastDay = limit;
+    }
+    guard->quest->firstVisitText = readString(buffer, pos);
+    guard->quest->nextVisitText = readString(buffer, pos);
+    guard->quest->completedText = readString(buffer, pos);
+    guard->quest->isCustomFirst = guard->quest->firstVisitText.size() > 0;
+    guard->quest->isCustomNext = guard->quest->nextVisitText.size() > 0;
+    guard->quest->isCustomComplete = guard->quest->completedText.size() > 0;
+}
+
+void CMapLoaderH3M::addQuest(CGObjectInstance * quest)
+{
+    auto q = dynamic_cast<IQuestObject *>(quest);
+    q->quest->qid = map->quests.size();
+    map->quests.push_back(q->quest);
+}
+
+CGTownInstance * CMapLoaderH3M::readTown(int castleID)
+{
+    CGTownInstance * nt = new CGTownInstance;
+    nt->identifier = 0;
+    if(map->version > EMapFormat::ROE)
+    {
+        nt->identifier = read_le_u32(buffer + pos);
+        pos += 4;
+    }
+    nt->tempOwner = buffer[pos];
+    ++pos;
+    if(readChar(buffer, pos))
+    {
+        // Has name
+        nt->name = readString(buffer, pos);
+    }
+
+    // True if garrison isn't empty
+    if(readChar(buffer, pos))
+    {
+        readCreatureSet(nt, 7, map->version > EMapFormat::ROE);
+    }
+    nt->formation = buffer[pos];
+    ++pos;
+
+    // Custom buildings info
+    if(readChar(buffer, pos))
+    {
+        // Built buildings
+        for(int byte = 0; byte < 6; ++byte)
+        {
+            for(int bit = 0; bit < 8; ++bit)
+            {
+                if(buffer[pos] & (1 << bit))
+                {
+                    nt->builtBuildings.insert(byte * 8 + bit);
+                }
+            }
+            ++pos;
+        }
+
+        // Forbidden buildings
+        for(int byte = 6; byte < 12; ++byte)
+        {
+            for(int bit = 0; bit < 8; ++bit)
+            {
+                if(buffer[pos] & (1 << bit))
+                {
+                    nt->forbiddenBuildings.insert((byte - 6) * 8 + bit);
+                }
+            }
+            ++pos;
+        }
+        nt->builtBuildings = convertBuildings(nt->builtBuildings, castleID);
+        nt->forbiddenBuildings = convertBuildings(nt->forbiddenBuildings, castleID);
+    }
+    // Standard buildings
+    else
+    {
+        if(readChar(buffer, pos))
+        {
+            // Has fort
+            nt->builtBuildings.insert(EBuilding::FORT);
+        }
+
+        //means that set of standard building should be included
+        nt->builtBuildings.insert(-50);
+    }
+
+    int ist = pos;
+    if(map->version > EMapFormat::ROE)
+    {
+        for(; pos < ist + 9; ++pos)
+        {
+            ui8 c = buffer[pos];
+            for(int yy = 0; yy < 8; ++yy)
+            {
+                if((pos - ist) * 8 + yy < GameConstants::SPELLS_QUANTITY)
+                {
+                    if(c == (c | static_cast<ui8>(std::pow(2, yy))))
+                    {
+                        nt->obligatorySpells.push_back((pos - ist) * 8 + yy);
+                    }
+                }
+            }
+        }
+    }
+
+    ist = pos;
+    for(; pos < ist + 9; ++pos)
+    {
+        ui8 c = buffer[pos];
+        for(int yy = 0; yy < 8; ++yy)
+        {
+            if((pos - ist) * 8 + yy < GameConstants::SPELLS_QUANTITY)
+            {
+                if(c == (c | static_cast<ui8>(std::pow(2, yy))))
+                {
+                    nt->possibleSpells.push_back((pos - ist) * 8 + yy);
+                }
+            }
+        }
+    }
+
+    // Read castle events
+    int numberOfEvent = read_le_u32(buffer + pos);
+    pos += 4;
+
+    for(int gh = 0; gh < numberOfEvent; ++gh)
+    {
+        CCastleEvent * nce = new CCastleEvent;
+        nce->town = nt;
+        nce->name = readString(buffer, pos);
+        nce->message = readString(buffer, pos);
+        for(int x = 0; x < 7; ++x)
+        {
+            nce->resources[x] = read_le_u32(buffer + pos);
+            pos += 4;
+        }
+
+        nce->players = buffer[pos];
+        ++pos;
+        if(map->version > EMapFormat::AB)
+        {
+            nce->humanAffected = buffer[pos];
+            ++pos;
+        }
+        else
+        {
+            nce->humanAffected = true;
+        }
+
+        nce->computerAffected = buffer[pos];
+        ++pos;
+        nce->firstOccurence = read_le_u16(buffer + pos);
+        pos += 2;
+        nce->nextOccurence = buffer[pos];
+        ++pos;
+
+        pos += 17;
+
+        // New buildings
+        for(int byte = 0; byte < 6; ++byte)
+        {
+            for(int bit = 0; bit < 8; ++bit)
+            {
+                if(buffer[pos] & (1 << bit))
+                {
+                    nce->buildings.insert(byte * 8 + bit);
+                }
+            }
+            ++pos;
+        }
+        nce->buildings = convertBuildings(nce->buildings, castleID, false);
+
+        nce->creatures.resize(7);
+        for(int vv = 0; vv < 7; ++vv)
+        {
+            nce->creatures[vv] = read_le_u16(buffer + pos);
+            pos += 2;
+        }
+        pos += 4;
+        nt->events.push_back(nce);
+    }
+
+    if(map->version > EMapFormat::AB)
+    {
+        nt->alignment = buffer[pos];
+        ++pos;
+    }
+    else
+    {
+        nt->alignment = 0xff;
+    }
+    pos += 3;
+
+    nt->builded = 0;
+    nt->destroyed = 0;
+    nt->garrisonHero = nullptr;
+
+    return nt;
+}
+
+std::set<si32> CMapLoaderH3M::convertBuildings(const std::set<si32> h3m, int castleID, bool addAuxiliary /*= true*/)
+{
+    std::map<int, int> mapa;
+    std::set<si32> ret;
+
+    // Note: this file is parsed many times.
+    const JsonNode config(ResourceID("config/buildings5.json"));
+
+    BOOST_FOREACH(const JsonNode & entry, config["table"].Vector())
+    {
+        int town = entry["town"].Float();
+
+        if (town == castleID || town == -1)
+        {
+            mapa[entry["h3"].Float()] = entry["vcmi"].Float();
+        }
+    }
+
+    for(auto i = h3m.begin(); i != h3m.end(); ++i)
+    {
+        if(mapa[*i] >= 0)
+        {
+            ret.insert(mapa[*i]);
+        }
+        // horde buildings
+        else if(mapa[*i] >= (-GameConstants::CREATURES_PER_TOWN))
+        {
+            int level = (mapa[*i]);
+
+            //(-30)..(-36) - horde buildings (for game loading only), don't see other way to handle hordes in random towns
+            ret.insert(level - 30);
+        }
+        else
+        {
+            tlog3 << "Conversion warning: unknown building " << *i << " in castle "
+                  << castleID << std::endl;
+        }
+    }
+
+    if(addAuxiliary)
+    {
+        //village hall is always present
+        ret.insert(EBuilding::VILLAGE_HALL);
+    }
+
+    if(ret.find(EBuilding::CITY_HALL) != ret.end())
+    {
+        ret.insert(EBuilding::EXTRA_CITY_HALL);
+    }
+    if(ret.find(EBuilding::TOWN_HALL) != ret.end())
+    {
+        ret.insert(EBuilding::EXTRA_TOWN_HALL);
+    }
+    if(ret.find(EBuilding::CAPITOL) != ret.end())
+    {
+        ret.insert(EBuilding::EXTRA_CAPITOL);
+    }
+
+    return ret;
+}
+
+void CMapLoaderH3M::readEvents()
+{
+    int numberOfEvents = read_le_u32(buffer + pos);
+    pos += 4;
+    for(int yyoo = 0; yyoo < numberOfEvents; ++yyoo)
+    {
+        CMapEvent * ne = new CMapEvent;
+        ne->name = std::string();
+        ne->message = std::string();
+        int nameLen = read_le_u32(buffer + pos);
+        pos += 4;
+        for(int qq = 0; qq < nameLen; ++qq)
+        {
+            ne->name += buffer[pos];
+            ++pos;
+        }
+        int messLen = read_le_u32(buffer + pos);
+        pos += 4;
+        for(int qq = 0; qq < messLen; ++qq)
+        {
+            ne->message +=buffer[pos];
+            ++pos;
+        }
+        for(int k = 0; k < 7; ++k)
+        {
+            ne->resources[k] = read_le_u32(buffer + pos);
+            pos += 4;
+        }
+        ne->players = buffer[pos];
+        ++pos;
+        if(map->version > EMapFormat::AB)
+        {
+            ne->humanAffected = buffer[pos];
+            ++pos;
+        }
+        else
+        {
+            ne->humanAffected = true;
+        }
+        ne->computerAffected = buffer[pos];
+        ++pos;
+        ne->firstOccurence = read_le_u16(buffer + pos);
+        pos += 2;
+        ne->nextOccurence = buffer[pos];
+        ++pos;
+
+        char unknown[17];
+        memcpy(unknown, buffer + pos, 17);
+        pos += 17;
+
+        map->events.push_back(ne);
+    }
+}
+
+void CMapLoaderH3M::addBlockVisibleTiles(CGObjectInstance * obj)
+{
+    for(int fx = 0; fx < 8; ++fx)
+    {
+        for(int fy = 0; fy < 6; ++fy)
+        {
+            int xVal = obj->pos.x + fx - 7;
+            int yVal = obj->pos.y + fy - 5;
+            int zVal = obj->pos.z;
+            if(xVal >= 0 && xVal < map->width && yVal >= 0 && yVal < map->height)
+            {
+                TerrainTile & curt = map->terrain[xVal][yVal][zVal];
+                if(((obj->defInfo->visitMap[fy] >> (7 - fx)) & 1))
+                {
+                    curt.visitableObjects.push_back(obj);
+                    curt.visitable = true;
+                }
+                if(!((obj->defInfo->blockMap[fy] >> (7 - fx)) & 1))
+                {
+                    curt.blockingObjects.push_back(obj);
+                    curt.blocked = true;
+                }
+            }
+        }
+    }
+}
+
+ui8 CMapLoaderH3M::reverse(ui8 arg)
+{
+    ui8 ret = 0;
+    for(int i = 0; i < 8; ++i)
+    {
+        if((arg & (1 << i)) >> i)
+        {
+            ret |= (128 >> i);
+        }
+    }
+    return ret;
+}

+ 361 - 0
lib/Map/CMapService.h

@@ -0,0 +1,361 @@
+
+/*
+ * CMapService.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#pragma once
+
+class CMap;
+class CMapHeader;
+class CInputStream;
+class CGHeroInstance;
+class CArtifactInstance;
+class CGObjectInstance;
+class CGSeerHut;
+class IQuestObject;
+class CGTownInstance;
+class CCreatureSet;
+class CInputStream;
+class IMapLoader;
+
+/**
+ * The map service provides loading of VCMI/H3 map files. It can
+ * be extended to save maps later as well.
+ */
+class DLL_LINKAGE CMapService
+{
+public:
+    /**
+     * Loads the VCMI/H3 map file specified by the name.
+     *
+     * @param name the name of the map
+     * @return a unique ptr to the loaded map class
+     */
+    static std::unique_ptr<CMap> loadMap(const std::string & name);
+
+    /**
+     * Loads the VCMI/H3 map header specified by the name.
+     *
+     * @param name the name of the map
+     * @return a unique ptr to the loaded map header class
+     */
+    static std::unique_ptr<CMapHeader> loadMapHeader(const std::string & name);
+
+    /**
+     * Loads the VCMI/H3 map file from a buffer. This method is temporarily
+     * in use to ease the transition to use the new map service.
+     *
+     * TODO Replace method params with a CampaignMapInfo struct which contains
+     * a campaign loading object + name of map.
+     *
+     * @param buffer a pointer to a buffer containing the map data
+     * @param size the size of the buffer
+     * @return a unique ptr to the loaded map class
+     */
+    static std::unique_ptr<CMap> loadMap(const ui8 * buffer, int size);
+
+    /**
+     * Loads the VCMI/H3 map header from a buffer. This method is temporarily
+     * in use to ease the transition to use the new map service.
+     *
+     * TODO Replace method params with a CampaignMapInfo struct which contains
+     * a campaign loading object + name of map.
+     *
+     * @param buffer a pointer to a buffer containing the map header data
+     * @param size the size of the buffer
+     * @return a unique ptr to the loaded map class
+     */
+    static std::unique_ptr<CMapHeader> loadMapHeader(const ui8 * buffer, int size);
+
+private:
+    /**
+     * Gets a map input stream object specified by a map name.
+     *
+     * @param name the name of the map
+     * @return a unique ptr to the input stream class
+     */
+    static std::unique_ptr<CInputStream> getStreamFromFS(const std::string & name);
+
+    /**
+     * Gets a map input stream from a buffer.
+     *
+     * @param buffer a pointer to a buffer containing the map data
+     * @param size the size of the buffer
+     * @return a unique ptr to the input stream class
+     */
+    static std::unique_ptr<CInputStream> getStreamFromMem(const ui8 * buffer, int size);
+
+    /**
+     * Gets a map loader from the given stream. It performs checks to test
+     * in which map format the map is.
+     *
+     * @param stream the input map stream
+     * @return the constructed map loader
+     */
+    static std::unique_ptr<IMapLoader> getMapLoader(std::unique_ptr<CInputStream> & stream);
+};
+
+/**
+ * Interface for loading a map.
+ */
+class DLL_LINKAGE IMapLoader
+{
+public:
+    /**
+     * Loads the VCMI/H3 map file.
+     *
+     * @return a unique ptr of the loaded map class
+     */
+    virtual std::unique_ptr<CMap> loadMap() = 0;
+
+    /**
+     * Loads the VCMI/H3 map header.
+     *
+     * @return a unique ptr of the loaded map header class
+     */
+    virtual std::unique_ptr<CMapHeader> loadMapHeader() = 0;
+};
+
+class DLL_LINKAGE CMapLoaderH3M : public IMapLoader
+{
+public:
+    /**
+     * Default constructor.
+     *
+     * @param stream a stream containing the map data
+     */
+    CMapLoaderH3M(CInputStream * stream);
+
+    /**
+     * Destructor.
+     */
+    ~CMapLoaderH3M();
+
+    /**
+     * Loads the VCMI/H3 map file.
+     *
+     * @return a unique ptr of the loaded map class
+     */
+    std::unique_ptr<CMap> loadMap();
+
+    /**
+     * Loads the VCMI/H3 map header.
+     *
+     * @return a unique ptr of the loaded map header class
+     */
+    std::unique_ptr<CMapHeader> loadMapHeader();
+
+    /** true if you want to enable the map loader profiler to see how long a specific part took; default=false */
+    static const bool IS_PROFILING_ENABLED;
+
+private:
+    /**
+     * Initializes the map object from parsing the input buffer.
+     */
+    void init();
+
+    /**
+     * Reads the map header.
+     */
+    void readHeader();
+
+    /**
+     * Reads player information.
+     */
+    void readPlayerInfo();
+
+    /**
+     * Reads victory/loss conditions.
+     */
+    void readVictoryLossConditions();
+
+    /**
+     * Reads team information.
+     */
+    void readTeamInfo();
+
+    /**
+     * Reads the list of allowed heroes.
+     */
+    void readAllowedHeroes();
+
+    /**
+     * Reads the list of disposed heroes.
+     */
+    void readDisposedHeroes();
+
+    /**
+     * Reads the list of allowed artifacts.
+     */
+    void readAllowedArtifacts();
+
+    /**
+     * Reads the list of allowed spells and abilities.
+     */
+    void readAllowedSpellsAbilities();
+
+    /**
+     * Loads artifacts of a hero.
+     *
+     * @param hero the hero which should hold those artifacts
+     */
+    void loadArtifactsOfHero(CGHeroInstance * hero);
+
+    /**
+     * Loads an artifact to the given slot of the specified hero.
+     *
+     * @param hero the hero which should hold that artifact
+     * @param slot the artifact slot where to place that artifact
+     * @return true if it loaded an artifact
+     */
+    bool loadArtifactToSlot(CGHeroInstance * hero, int slot);
+
+    /**
+     * Creates an artifact instance.
+     *
+     * @param aid the id of the artifact
+     * @param spellID optional. the id of a spell if a spell scroll object should be created
+     * @return the created artifact instance
+     */
+    CArtifactInstance * createArtifact(int aid, int spellID = -1);
+
+    /**
+     * Adds the specified artifact instance to the list of artifacts of this map.
+     *
+     * @param art the artifact which should be added to the list of artifacts
+     */
+    void addNewArtifactInstance(CArtifactInstance * art);
+
+    /**
+     * Read rumors.
+     */
+    void readRumors();
+
+    /**
+     * Reads predefined heroes.
+     */
+    void readPredefinedHeroes();
+
+    /**
+     * Reads terrain data.
+     */
+    void readTerrain();
+
+    /**
+     * Reads custom(map) def information.
+     */
+    void readDefInfo();
+
+    /**
+     * Reads objects(towns, mines,...).
+     */
+    void readObjects();
+
+    /**
+     * Reads a creature set.
+     *
+     * @param out the loaded creature set
+     * @param number the count of creatures to read
+     * @param version true for > ROE maps
+     */
+    void readCreatureSet(CCreatureSet * out, int number, bool version);
+
+    /**
+     * Reads a hero.
+     *
+     * @param idToBeGiven the object id which should be set for the hero
+     * @return a object instance
+     */
+    CGObjectInstance * readHero(int idToBeGiven);
+
+    /**
+     * Reads a seer hut.
+     *
+     * @return the initialized seer hut object
+     */
+    CGSeerHut * readSeerHut();
+
+    /**
+     * Reads a quest for the given quest guard.
+     *
+     * @param guard the quest guard where that quest should be applied to
+     */
+    void readQuest(IQuestObject * guard);
+
+    /**
+     * Adds the specified quest instance to the list of quests.
+     *
+     * @param quest the quest object which should be added to the list of quests
+     */
+    void addQuest(CGObjectInstance * quest);
+
+    /**
+     * Reads a town.
+     *
+     * @param castleID the id of the castle type
+     * @return the loaded town object
+     */
+    CGTownInstance * readTown(int castleID);
+
+    /**
+     * Converts buildings to the specified castle id.
+     *
+     * @param h3m the ids of the buildings
+     * @param castleID the castle id
+     * @param addAuxiliary true if the village hall should be added
+     * @return the converted buildings
+     */
+    std::set<si32> convertBuildings(const std::set<si32> h3m, int castleID, bool addAuxiliary = true);
+
+    /**
+     * Reads events.
+     */
+    void readEvents();
+
+    /**
+     * Adds object instance to block visitable tiles.
+     *
+     * @param obj the object to add
+     */
+    void addBlockVisibleTiles(CGObjectInstance * obj);
+
+    /**
+     * Reverses the input argument.
+     *
+     * @param arg the input argument
+     * @return the reversed 8-bit integer
+     */
+    ui8 reverse(ui8 arg);
+
+    /**
+     * Init buffer / size.
+     *
+     * @param stream the stream which serves as the data input
+     */
+    void initBuffer(CInputStream * stream);
+
+    /** ptr to the map object which gets filled by data from the buffer */
+    CMap * map;
+
+    /**
+     * ptr to the map header object which gets filled by data from the buffer.
+     * (when loading a map then the mapHeader ptr points to the same object)
+     */
+    std::unique_ptr<CMapHeader> mapHeader;
+
+    /** pointer to the array containing the map data;
+     * TODO replace with CBinaryReader later (this makes pos & size redundant) */
+    ui8 * buffer;
+
+    /** current buffer reading position */
+    int pos;
+
+    /** size of the map in bytes */
+    int size;
+};

+ 1 - 1
lib/NetPacks.h

@@ -5,7 +5,7 @@
 #include "BattleAction.h"
 #include "HeroBonus.h"
 #include "CCreatureSet.h"
-#include "CMapInfo.h"
+#include "Map/CMapInfo.h"
 #include "StartInfo.h"
 #include "ConstTransitivePtr.h"
 #include "int3.h"

+ 1 - 1
lib/NetPacksLib.cpp

@@ -8,7 +8,7 @@
 #include "CObjectHandler.h"
 #include "CModHandler.h"
 #include "VCMI_Lib.h"
-#include "map.h"
+#include "Map/CMap.h"
 #include "CSpellHandler.h"
 #include "CCreatureHandler.h"
 #include "CGameState.h"

+ 9 - 7
lib/VCMI_lib.vcxproj

@@ -225,7 +225,6 @@
     <ClCompile Include="BattleState.cpp" />
     <ClCompile Include="CArtHandler.cpp" />
     <ClCompile Include="CBuildingHandler.cpp" />
-    <ClCompile Include="CCampaignHandler.cpp" />
     <ClCompile Include="CConfigHandler.cpp" />
     <ClCompile Include="CConsoleHandler.cpp" />
     <ClCompile Include="CCreatureHandler.cpp" />
@@ -236,7 +235,6 @@
     <ClCompile Include="CGeneralTextHandler.cpp" />
     <ClCompile Include="CHeroHandler.cpp" />
     <ClCompile Include="CLogger.cpp" />
-    <ClCompile Include="CMapInfo.cpp" />
     <ClCompile Include="CModHandler.cpp" />
     <ClCompile Include="CObjectHandler.cpp" />
     <ClCompile Include="CObstacleInstance.cpp" />
@@ -252,11 +250,14 @@
     <ClCompile Include="Filesystem\CLodArchiveLoader.cpp" />
     <ClCompile Include="Filesystem\CMemoryStream.cpp" />
     <ClCompile Include="Filesystem\CResourceLoader.cpp" />
+    <ClCompile Include="Map\CCampaignHandler.cpp" />
+    <ClCompile Include="Map\CMap.cpp" />
+    <ClCompile Include="Map\CMapInfo.cpp" />
+    <ClCompile Include="Map\CMapService.cpp" />
     <ClCompile Include="HeroBonus.cpp" />
     <ClCompile Include="CBattleCallback.cpp" />
     <ClCompile Include="IGameCallback.cpp" />
     <ClCompile Include="JsonNode.cpp" />
-    <ClCompile Include="map.cpp" />
     <ClCompile Include="NetPacksLib.cpp" />
     <ClCompile Include="ResourceSet.cpp" />
     <ClCompile Include="StdInc.cpp">
@@ -278,7 +279,6 @@
     <ClInclude Include="BattleState.h" />
     <ClInclude Include="CArtHandler.h" />
     <ClInclude Include="CBuildingHandler.h" />
-    <ClInclude Include="CCampaignHandler.h" />
     <ClInclude Include="CConfigHandler.h" />
     <ClInclude Include="CConsoleHandler.h" />
     <ClInclude Include="CCreatureHandler.h" />
@@ -289,7 +289,6 @@
     <ClInclude Include="CGeneralTextHandler.h" />
     <ClInclude Include="CHeroHandler.h" />
     <ClInclude Include="CLogger.h" />
-    <ClInclude Include="CMapInfo.h" />
     <ClInclude Include="CModHandler.h" />
     <ClInclude Include="CObjectHandler.h" />
     <ClInclude Include="CObstacleInstance.h" />
@@ -311,6 +310,10 @@
     <ClInclude Include="Filesystem\CMemoryStream.h" />
     <ClInclude Include="Filesystem\CResourceLoader.h" />
     <ClInclude Include="Filesystem\ISimpleResourceLoader.h" />
+    <ClCompile Include="Map\CCampaignHandler.h" />
+    <ClCompile Include="Map\CMap.h" />
+    <ClCompile Include="Map\CMapInfo.h" />
+    <ClCompile Include="Map\CMapService.h" />
     <ClInclude Include="GameConstants.h" />
     <ClInclude Include="HeroBonus.h" />
     <ClInclude Include="CBattleCallback.h" />
@@ -319,7 +322,6 @@
     <ClInclude Include="int3.h" />
     <ClInclude Include="Interprocess.h" />
     <ClInclude Include="JsonNode.h" />
-    <ClInclude Include="map.h" />
     <ClInclude Include="NetPacks.h" />
     <ClInclude Include="RegisterTypes.h" />
     <ClInclude Include="ResourceSet.h" />
@@ -332,4 +334,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
+</Project>

+ 0 - 2281
lib/map.cpp

@@ -1,2281 +0,0 @@
-#include "StdInc.h"
-#include "map.h"
-
-#include "Filesystem/CBinaryReader.h"
-#include "Filesystem/CResourceLoader.h"
-#include "Filesystem/CCompressedStream.h"
-#include "CObjectHandler.h"
-#include "CDefObjInfoHandler.h"
-#include "VCMI_Lib.h"
-#include <boost/crc.hpp>
-#include "CArtHandler.h"
-#include "CCreatureHandler.h"
-#include "CSpellHandler.h"
-#include "../lib/JsonNode.h"
-#include "vcmi_endian.h"
-#include "GameConstants.h"
-#include "CStopWatch.h"
-
-/*
- * map.cpp, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-
-static std::set<si32> convertBuildings(const std::set<si32> h3m, int castleID, bool addAuxiliary = true)
-{
-	std::map<int,int> mapa;
-	std::set<si32> ret;
-
-	// Note: this file is parsed many times.
-	const JsonNode config(ResourceID("config/buildings5.json"));
-
-	BOOST_FOREACH(const JsonNode &entry, config["table"].Vector())
-	{
-		int town = entry["town"].Float();
-
-		if ( town == castleID || town == -1 )
-			mapa[entry["h3"].Float()] = entry["vcmi"].Float();
-	}
-
-	for(std::set<si32>::const_iterator i=h3m.begin();i!=h3m.end();i++)
-	{
-		if(mapa[*i]>=0)
-			ret.insert(mapa[*i]);
-		else if(mapa[*i]  >=  (-GameConstants::CREATURES_PER_TOWN)) // horde buildings
-		{
-			int level = (mapa[*i]);
-			ret.insert(level-30);//(-30)..(-36) - horde buildings (for game loading only), don't see other way to handle hordes in random towns
-		}
-		else
-		{
-			tlog3<<"Conversion warning: unknown building "<<*i<<" in castle "<<castleID<<std::endl;
-		}
-	}
-
-	if(addAuxiliary)
-		ret.insert(EBuilding::VILLAGE_HALL); //village hall is always present
-
-	if(ret.find(EBuilding::CITY_HALL)!=ret.end())
-		ret.insert(EBuilding::EXTRA_CITY_HALL);
-	if(ret.find(EBuilding::TOWN_HALL)!=ret.end())
-		ret.insert(EBuilding::EXTRA_TOWN_HALL);
-	if(ret.find(EBuilding::CAPITOL)!=ret.end())
-		ret.insert(EBuilding::EXTRA_CAPITOL);
-
-	return ret;
-}
-static ui32 intPow(ui32 a, ui32 b)
-{
-	ui32 ret=1;
-	for(ui32 i=0; i<b; ++i)
-		ret*=a;
-	return ret;
-}
-static ui8 reverse(ui8 arg)
-{
-	ui8 ret = 0;
-	for (int i=0; i<8;i++)
-	{
-		if(((arg)&(1<<i))>>i)
-		{
-			ret |= (128>>i);
-		}
-	}
-	return ret;
-}
-
-void readCreatureSet(CCreatureSet *out, const ui8 * buffer, int &i, int number, bool version) //version==true for >RoE maps
-{
-	const int bytesPerCre = version ? 4 : 3,
-		maxID = version ? 0xffff : 0xff;
-
-	for(int ir=0;ir < number; ir++)
-	{
-		int creID;
-		int count;
-
-		if (version)
-		{
-            creID = read_le_u16(buffer + i+ir*bytesPerCre);
-            count = read_le_u16(buffer + i+ir*bytesPerCre + 2);
-		}
-		else
-		{
-            creID = buffer[i+ir*bytesPerCre];
-            count = read_le_u16(buffer + i+ir*bytesPerCre + 1);
-		}
-
-		if(creID == maxID) //empty slot
-			continue;
-
-		CStackInstance *hlp = new CStackInstance();
-		hlp->count = count;
-
-		if(creID > maxID - 0xf)
-		{
-			creID = maxID + 1 - creID + VLC->creh->creatures.size();//this will happen when random object has random army
-			hlp->idRand = creID;
-		}
-		else
-			hlp->setType(creID);
-
-		out->putStack(ir, hlp);
-	}
-	i+=number*bytesPerCre;
-	
-	out->validTypes(true);
-}
-
-PlayerInfo::PlayerInfo(): p7(0), p8(0), p9(0), canHumanPlay(0), canComputerPlay(0),
-    AITactic(0), isFactionRandom(0),
-    mainHeroPortrait(0), hasMainTown(0), generateHeroAtMainTown(0),
-    team(255), generateHero(0)
-{
-
-}
-
-si8 PlayerInfo::defaultCastle() const
-{
-    assert(!allowedFactions.empty()); // impossible?
-
-    if(allowedFactions.size() == 1)
-    {
-        // only one faction is available - pick it
-        return *allowedFactions.begin();
-    }
-
-    // set to random
-    return -1;
-}
-
-si8 PlayerInfo::defaultHero() const
-{
-    // we will generate hero in front of main town
-    if((generateHeroAtMainTown && hasMainTown) || p8)
-    {
-        //random hero
-        return -1;
-    }
-
-    return -2;
-}
-
-CMapHeader::CMapHeader(const ui8 *map)
-{
-	int i=0;
-	initFromMemory(map,i);
-}
-
-CMapHeader::CMapHeader()
-{
-	areAnyPLayers = difficulty = levelLimit = howManyTeams = 0;
-	height = width = twoLevel = -1;
-}
-
-void CMapHeader::initFromMemory( const ui8 *buffer, int &i )
-{
-    version = (EMapFormat::EMapFormat)(read_le_u32(buffer + i)); i+=4; //map version
-    if(version != EMapFormat::ROE && version != EMapFormat::AB && version != EMapFormat::SOD
-            && version != EMapFormat::WOG)
-	{
-		throw std::runtime_error("Invalid map format!");
-	}
-    areAnyPLayers = readChar(buffer,i); //invalid on some maps
-    height = width = (read_le_u32(buffer + i)); i+=4; // dimensions of map
-    twoLevel = readChar(buffer,i); //if there is underground
-	int pom;
-    name = readString(buffer,i);
-    description= readString(buffer,i);
-    difficulty = readChar(buffer,i); // reading map difficulty
-    if(version != EMapFormat::ROE)
-        levelLimit = readChar(buffer,i); // hero level limit
-	else
-		levelLimit = 0;
-    loadPlayerInfo(pom, buffer, i);
-    loadViCLossConditions(buffer, i);
-
-    howManyTeams=buffer[i++]; //read number of teams
-	if(howManyTeams>0) //read team numbers
-	{
-		for(int rr=0; rr<8; ++rr)
-		{
-            players[rr].team = buffer[i++];
-		}
-	}
-	else//no alliances
-	{
-		for(int i=0;i<GameConstants::PLAYER_LIMIT;i++)
-			if(players[i].canComputerPlay || players[i].canHumanPlay)
-				players[i].team = howManyTeams++;
-	}
-
-
-	pom = i;
-	allowedHeroes.resize(GameConstants::HEROES_QUANTITY,false);
-    for(; i<pom+ (version == EMapFormat::ROE ? 16 : 20) ; ++i)
-	{
-        ui8 c = buffer[i];
-		for(int yy=0; yy<8; ++yy)
-			if((i-pom)*8+yy < GameConstants::HEROES_QUANTITY)
-				if(c == (c|((ui8)intPow(2, yy))))
-					allowedHeroes[(i-pom)*8+yy] = true;
-	}
-    if(version > EMapFormat::ROE) //probably reserved for further heroes
-	{
-        int placeholdersQty = read_le_u32(buffer + i); i+=4;
-		for(int p = 0; p < placeholdersQty; p++)
-            placeholdedHeroes.push_back(buffer[i++]);
-	}
-}
-void CMapHeader::loadPlayerInfo( int &pom, const ui8 * buffer, int &i )
-{
-	players.resize(8);
-	for (pom=0;pom<8;pom++)
-	{
-        players[pom].canHumanPlay = buffer[i++];
-        players[pom].canComputerPlay = buffer[i++];
-		if ((!(players[pom].canHumanPlay || players[pom].canComputerPlay))) //if nobody can play with this player
-		{
-			switch(version)
-			{
-            case EMapFormat::SOD:
-            case EMapFormat::WOG:
-				i+=13;
-				break;
-            case EMapFormat::AB:
-				i+=12;
-				break;
-            case EMapFormat::ROE:
-				i+=6;
-				break;
-			}
-			continue;
-		}
-
-        players[pom].AITactic = buffer[i++];
-
-        if(version == EMapFormat::SOD || version == EMapFormat::WOG)
-            players[pom].p7= buffer[i++];
-		else
-			players[pom].p7= -1;
-
-		//factions this player can choose
-        ui16 allowedFactions = buffer[i++];
-        if(version != EMapFormat::ROE)
-            allowedFactions += (buffer[i++])*256;
-
-		for (size_t fact=0; fact<16; fact++)
-			if (allowedFactions & (1 << fact))
-				players[pom].allowedFactions.insert(fact);
-
-        players[pom].isFactionRandom = buffer[i++];
-        players[pom].hasMainTown = buffer[i++];
-		if (players[pom].hasMainTown)
-		{
-            if(version != EMapFormat::ROE)
-			{
-                players[pom].generateHeroAtMainTown = buffer[i++];
-                players[pom].generateHero = buffer[i++];
-			}
-			else
-			{
-				players[pom].generateHeroAtMainTown = true;
-				players[pom].generateHero = false;
-			}
-
-            players[pom].posOfMainTown.x = buffer[i++];
-            players[pom].posOfMainTown.y = buffer[i++];
-            players[pom].posOfMainTown.z = buffer[i++];
-
-
-		}
-        players[pom].p8= buffer[i++];
-        players[pom].p9= buffer[i++];
-		if(players[pom].p9!=0xff)
-		{
-            players[pom].mainHeroPortrait = buffer[i++];
-            players[pom].mainHeroName = readString(buffer,i);
-		}
-
-        if(version != EMapFormat::ROE)
-		{
-            players[pom].powerPlacehodlers = buffer[i++];//unknown byte
-            int heroCount = buffer[i++];
-			i+=3;
-			for (int pp=0;pp<heroCount;pp++)
-			{
-				SheroName vv;
-                vv.heroID=buffer[i++];
-                int hnl = buffer[i++];
-				i+=3;
-				for (int zz=0;zz<hnl;zz++)
-				{
-                    vv.heroName+=buffer[i++];
-				}
-				players[pom].heroesNames.push_back(vv);
-			}
-		}
-	}
-}
-
-void CMapHeader::loadViCLossConditions( const ui8 * buffer, int &i)
-{
-	victoryCondition.obj = NULL;
-    victoryCondition.condition = (EVictoryConditionType::EVictoryConditionType)buffer[i++];
-	if (victoryCondition.condition != EVictoryConditionType::WINSTANDARD) //specific victory conditions
-	{
-		int nr=0;
-		switch (victoryCondition.condition) //read victory conditions
-		{
-		case EVictoryConditionType::ARTIFACT:
-			{
-                victoryCondition.ID = buffer[i+2];
-                nr=(version == EMapFormat::ROE ? 1 : 2);
-				break;
-			}
-		case EVictoryConditionType::GATHERTROOP:
-			{
-// 				int temp1 = buffer[i+2];
-// 				int temp2 = buffer[i+3];
-                victoryCondition.ID = buffer[i+2];
-                victoryCondition.count = read_le_u32(buffer + i+(version == EMapFormat::ROE ? 3 : 4));
-                nr=(version == EMapFormat::ROE ? 5 : 6);
-				break;
-			}
-		case EVictoryConditionType::GATHERRESOURCE:
-			{
-                victoryCondition.ID = buffer[i+2];
-                victoryCondition.count = read_le_u32(buffer + i+3);
-				nr = 5;
-				break;
-			}
-		case EVictoryConditionType::BUILDCITY:
-			{
-                victoryCondition.pos.x = buffer[i+2];
-                victoryCondition.pos.y = buffer[i+3];
-                victoryCondition.pos.z = buffer[i+4];
-                victoryCondition.count = buffer[i+5];
-                victoryCondition.ID = buffer[i+6];
-				nr = 5;
-				break;
-			}
-		case EVictoryConditionType::BUILDGRAIL:
-			{
-                if (buffer[i+4]>2)
-					victoryCondition.pos = int3(-1,-1,-1);
-				else
-				{
-                    victoryCondition.pos.x = buffer[i+2];
-                    victoryCondition.pos.y = buffer[i+3];
-                    victoryCondition.pos.z = buffer[i+4];
-				}
-				nr = 3;
-				break;
-			}
-		case EVictoryConditionType::BEATHERO:
-		case EVictoryConditionType::CAPTURECITY:
-		case EVictoryConditionType::BEATMONSTER:
-			{
-                victoryCondition.pos.x = buffer[i+2];
-                victoryCondition.pos.y = buffer[i+3];
-                victoryCondition.pos.z = buffer[i+4];
-				nr = 3;
-				break;
-			}
-		case EVictoryConditionType::TAKEDWELLINGS:
-		case EVictoryConditionType::TAKEMINES:
-			{
-				nr = 0;
-				break;
-			}
-		case EVictoryConditionType::TRANSPORTITEM:
-			{
-                victoryCondition.ID =  buffer[i+2];
-                victoryCondition.pos.x = buffer[i+3];
-                victoryCondition.pos.y = buffer[i+4];
-                victoryCondition.pos.z = buffer[i+5];
-				nr = 4;
-				break;
-			}
-		default:
-			assert(0);
-		}
-        victoryCondition.allowNormalVictory = buffer[i++];
-        victoryCondition.appliesToAI = buffer[i++];
-		i+=nr;
-	}
-    lossCondition.typeOfLossCon = (ELossConditionType::ELossConditionType)buffer[i++];
-	switch (lossCondition.typeOfLossCon) //read loss conditions
-	{
-	case ELossConditionType::LOSSCASTLE:
-	case ELossConditionType::LOSSHERO:
-		{
-            lossCondition.pos.x=buffer[i++];
-            lossCondition.pos.y=buffer[i++];
-            lossCondition.pos.z=buffer[i++];
-			break;
-		}
-	case ELossConditionType::TIMEEXPIRES:
-		{
-            lossCondition.timeLimit = read_le_u16(buffer + i);
-			i+=2;
-			break;
-		}
-	}
-}
-
-CMapHeader::~CMapHeader()
-{
-
-}
-
-void CMap::initFromBytes(const ui8 * buffer, size_t size)
-{
-	// Compute checksum
-	boost::crc_32_type  result;
-    result.process_bytes(buffer, size);
-	checksum = result.checksum();
-	tlog0 << "\tOur map checksum: "<<result.checksum() << std::endl;
-
-	int i=0;
-    CMapHeader::initFromMemory(buffer,i);
-	CStopWatch th;
-	th.getDiff();
-    readHeader(buffer, i);
-	tlog0<<"\tReading header: "<<th.getDiff()<<std::endl;
-
-	if (victoryCondition.condition == EVictoryConditionType::ARTIFACT || victoryCondition.condition == EVictoryConditionType::TRANSPORTITEM)
-	{ //messy, but needed
-		allowedArtifact[victoryCondition.ID] = false;
-	}
-
-    readRumors(buffer, i);
-	tlog0<<"\tReading rumors: "<<th.getDiff()<<std::endl;
-
-    readPredefinedHeroes(buffer, i);
-	tlog0<<"\tReading predefined heroes: "<<th.getDiff()<<std::endl;
-
-    readTerrain(buffer, i);
-	tlog0<<"\tReading terrain: "<<th.getDiff()<<std::endl;
-
-    readDefInfo(buffer, i);
-	tlog0<<"\tReading defs info: "<<th.getDiff()<<std::endl;
-
-    readObjects(buffer, i);
-	tlog0<<"\tReading objects: "<<th.getDiff()<<std::endl;
-	
-    readEvents(buffer, i);
-	tlog0<<"\tReading events: "<<th.getDiff()<<std::endl;
-
-    //map readed, buffer no longer needed
-	for(ui32 f=0; f<objects.size(); ++f) //calculationg blocked / visitable positions
-	{
-		if(!objects[f]->defInfo)
-			continue;
-		addBlockVisTiles(objects[f]);
-	}
-	tlog0<<"\tCalculating blocked/visitable tiles: "<<th.getDiff()<<std::endl;
-	tlog0 << "\tMap initialization done!" << std::endl;
-}
-
-void CMap::removeBlockVisTiles(CGObjectInstance * obj, bool total)
-{
-	for(int fx=0; fx<8; ++fx)
-	{
-		for(int fy=0; fy<6; ++fy)
-		{
-			int xVal = obj->pos.x + fx - 7;
-			int yVal = obj->pos.y + fy - 5;
-			int zVal = obj->pos.z;
-			if(xVal>=0 && xVal<width && yVal>=0 && yVal<height)
-			{
-				TerrainTile & curt = terrain[xVal][yVal][zVal];
-				if(total || ((obj->defInfo->visitMap[fy] >> (7 - fx)) & 1))
-				{
-					curt.visitableObjects -= obj;
-					curt.visitable = curt.visitableObjects.size();
-				}
-				if(total || !((obj->defInfo->blockMap[fy] >> (7 - fx)) & 1))
-				{
-					curt.blockingObjects -= obj;
-					curt.blocked = curt.blockingObjects.size();
-				}
-			}
-		}
-	}
-}
-void CMap::addBlockVisTiles(CGObjectInstance * obj)
-{
-	for(int fx=0; fx<8; ++fx)
-	{
-		for(int fy=0; fy<6; ++fy)
-		{
-			int xVal = obj->pos.x + fx - 7;
-			int yVal = obj->pos.y + fy - 5;
-			int zVal = obj->pos.z;
-			if(xVal>=0 && xVal<width && yVal>=0 && yVal<height)
-			{
-				TerrainTile & curt = terrain[xVal][yVal][zVal];
-				if(((obj->defInfo->visitMap[fy] >> (7 - fx)) & 1))
-				{
-					curt.visitableObjects.push_back(obj);
-					curt.visitable = true;
-				}
-				if(!((obj->defInfo->blockMap[fy] >> (7 - fx)) & 1))
-				{
-					curt.blockingObjects.push_back(obj);
-					curt.blocked = true;
-				}
-			}
-		}
-	}
-}
-
-TInputStreamPtr CMap::getMapStream(std::string name)
-{
-    TInputStreamPtr file = CResourceHandler::get()->load(ResourceID(name, EResType::MAP));
-
-	CBinaryReader reader(*file.get());
-
-	ui32 header = reader.readUInt32();
-	file->seek(0); //reset file
-
-	switch (header & 0xffffff) // gzip header is 3 bytes only in size
-	{
-		case 0x00088B1F: // gzip header magic number, reversed for LE
-			return TInputStreamPtr(new CCompressedStream(std::move(file), true));
-        case EMapFormat::WOG :
-        case EMapFormat::AB  :
-        case EMapFormat::ROE :
-        case EMapFormat::SOD :
-			return file;
-		default :
-            tlog0 << "Error: Failed to open map " << name << ": unknown format\n";
-			return TInputStreamPtr();
-	}
-}
-
-CMap::CMap(std::string filename)
-    : grailPos(-1, -1, -1), grailRadious(0)
-{
-	tlog0<<"Opening map file: "<<filename<<"\t "<<std::flush;
-	
-	TInputStreamPtr file = getMapStream(filename);
-
-	//load file and decompress
-	size_t mapSize = file->getSize();
-	std::unique_ptr<ui8[]>  data(new ui8 [mapSize] );
-	file->read(data.get(), mapSize);
-
-	tlog0<<"done."<<std::endl;
-
-	initFromBytes(data.get(), mapSize);
-}
-
-CMap::CMap()
-{
-	terrain = NULL;
-
-}
-CMap::~CMap()
-{
-    //for(int i=0; i < customDefs.size(); i++)
-    //	if(customDefs[i]->serial < 0) //def not present in the main vector in defobjinfo
-    //		delete customDefs[i];
-
-	if(terrain)
-	{
-        for(int ii=0;ii<width;ii++)
-		{
-			for(int jj=0;jj<height;jj++)
-				delete [] terrain[ii][jj];
-			delete [] terrain[ii];
-		}
-		delete [] terrain;
-	}
-	for(std::list<ConstTransitivePtr<CMapEvent> >::iterator i = events.begin(); i != events.end(); i++)
-    {
-		i->dellNull();
-    }
-}
-
-CGHeroInstance * CMap::getHero(int heroID)
-{
-	for(ui32 i=0; i<heroes.size();i++)
-        if(heroes[i]->subID == heroID)
-			return heroes[i];
-    return nullptr;
-}
-
-int CMap::loadSeerHut(const ui8 * buffer, int i, CGObjectInstance * & seerHut)
-{
-	CGSeerHut *hut = new CGSeerHut();
-    seerHut = hut;
-
-    if(version > EMapFormat::ROE)
-	{
-        loadQuest(hut,buffer,i);
-	}
-	else //RoE
-	{
-        int artID = buffer[i]; ++i;
-		if (artID != 255) //not none quest
-		{
-			hut->quest->m5arts.push_back (artID);
-			hut->quest->missionType = CQuest::MISSION_ART;
-		}
-		else
-		{
-			hut->quest->missionType = CQuest::MISSION_NONE; //no mission
-		}
-		hut->quest->lastDay = -1; //no timeout
-		hut->quest->isCustomFirst = hut->quest->isCustomNext = hut->quest->isCustomComplete = false;
-	}
-
-	if (hut->quest->missionType)
-	{
-        ui8 rewardType = buffer[i]; ++i;
-		hut->rewardType = rewardType;
-
-		switch(rewardType)
-		{
-		case 1:
-			{
-                hut->rVal = read_le_u32(buffer + i); i+=4;
-				break;
-			}
-		case 2:
-			{
-                hut->rVal = read_le_u32(buffer + i); i+=4;
-				break;
-			}
-		case 3:
-			{
-                hut->rVal = buffer[i]; ++i;
-				break;
-			}
-		case 4:
-			{
-                hut->rVal = buffer[i]; ++i;
-				break;
-			}
-		case 5:
-			{
-                hut->rID = buffer[i]; ++i;
-				/* Only the first 3 bytes are used. Skip the 4th. */
-                hut->rVal = read_le_u32(buffer + i) & 0x00ffffff;
-				i+=4;
-				break;
-			}
-		case 6:
-			{
-                hut->rID = buffer[i]; ++i;
-                hut->rVal = buffer[i]; ++i;
-				break;
-			}
-		case 7:
-			{
-                hut->rID = buffer[i]; ++i;
-                hut->rVal = buffer[i]; ++i;
-				break;
-			}
-		case 8:
-			{
-                if (version == EMapFormat::ROE)
-				{
-                    hut->rID = buffer[i]; i++;
-				}
-				else
-				{
-                    hut->rID = read_le_u16(buffer + i); i+=2;
-				}
-				break;
-			}
-		case 9:
-			{
-                hut->rID = buffer[i]; ++i;
-				break;
-			}
-		case 10:
-			{
-                if(version > EMapFormat::ROE)
-				{
-                    hut->rID = read_le_u16(buffer + i); i+=2;
-                    hut->rVal = read_le_u16(buffer + i); i+=2;
-				}
-				else
-				{
-                    hut->rID = buffer[i]; ++i;
-                    hut->rVal = read_le_u16(buffer + i); i+=2;
-				}
-				break;
-			}
-		}// end of internal switch
-		i+=2;
-	}
-	else //missionType==255
-	{
-		i+=3;
-	}
-	return i;
-}
-
-void CMap::loadTown(CGObjectInstance * & town, const ui8 * buffer, int &i, int castleID)
-{
-	CGTownInstance * nt = new CGTownInstance();
-    town = nt;
-	nt->identifier = 0;
-    if(version > EMapFormat::ROE)
-	{	
-        nt->identifier = read_le_u32(buffer + i); i+=4;
-	}
-    nt->tempOwner = buffer[i]; ++i;
-    if(readChar(buffer,i)) //has name
-        nt->name = readString(buffer,i);
-    if(readChar(buffer,i))//true if garrison isn't empty
-        readCreatureSet(nt, buffer, i, 7, version > EMapFormat::ROE);
-    nt->formation = buffer[i]; ++i;
-    if(readChar(buffer,i)) //custom buildings info
-	{
-		//built buildings
-		for(int byte=0;byte<6;byte++)
-		{
-			for(int bit=0;bit<8;bit++)
-                if(buffer[i] & (1<<bit))
-					nt->builtBuildings.insert(byte*8+bit);
-			i++;
-		}
-		//forbidden buildings
-		for(int byte=6;byte<12;byte++)
-		{
-			for(int bit=0;bit<8;bit++)
-                if(buffer[i] & (1<<bit))
-					nt->forbiddenBuildings.insert((byte-6)*8+bit);
-			i++;
-		}
-        nt->builtBuildings = convertBuildings(nt->builtBuildings,castleID);
-        nt->forbiddenBuildings = convertBuildings(nt->forbiddenBuildings,castleID);
-	}
-	else //standard buildings
-	{
-        if(readChar(buffer,i)) //has fort
-			nt->builtBuildings.insert(EBuilding::FORT);
-		nt->builtBuildings.insert(-50); //means that set of standard building should be included
-	}
-
-	int ist = i;
-    if(version > EMapFormat::ROE)
-	{
-		for(; i<ist+9; ++i)
-		{
-            ui8 c = buffer[i];
-			for(int yy=0; yy<8; ++yy)
-			{
-				if((i-ist)*8+yy < GameConstants::SPELLS_QUANTITY)
-				{
-					if(c == (c|((ui8)intPow(2, yy))))
-						nt->obligatorySpells.push_back((i-ist)*8+yy);
-				}
-			}
-		}
-	}
-
-	ist = i;
-	for(; i<ist+9; ++i)
-	{
-        ui8 c = buffer[i];
-		for(int yy=0; yy<8; ++yy)
-		{
-			if((i-ist)*8+yy < GameConstants::SPELLS_QUANTITY)
-			{
-				if(c != (c|((ui8)intPow(2, yy))))
-					nt->possibleSpells.push_back((i-ist)*8+yy);
-			}
-		}
-	}
-
-	/////// reading castle events //////////////////////////////////
-
-    int numberOfEvent = read_le_u32(buffer + i); i+=4;
-
-	for(int gh = 0; gh<numberOfEvent; ++gh)
-	{
-		CCastleEvent *nce = new CCastleEvent();
-		nce->town = nt;
-        nce->name = readString(buffer,i);
-        nce->message = readString(buffer,i);
-		for(int x=0; x < 7; x++)
-		{
-            nce->resources[x] = read_le_u32(buffer + i);
-			i+=4;
-		}
-
-        nce->players = buffer[i]; ++i;
-        if(version > EMapFormat::AB)
-		{
-            nce->humanAffected = buffer[i]; ++i;
-		}
-		else
-			nce->humanAffected = true;
-
-        nce->computerAffected = buffer[i]; ++i;
-        nce->firstOccurence = read_le_u16(buffer + i); i+=2;
-        nce->nextOccurence = buffer[i]; ++i;
-
-		i+=17;
-
-		//new buildings
-		for(int byte=0;byte<6;byte++)
-		{
-			for(int bit=0;bit<8;bit++)
-                if(buffer[i] & (1<<bit))
-					nce->buildings.insert(byte*8+bit);
-			i++;
-		}
-        nce->buildings = convertBuildings(nce->buildings,castleID, false);
-		
-		nce->creatures.resize(7);
-		for(int vv=0; vv<7; ++vv)
-		{
-            nce->creatures[vv] = read_le_u16(buffer + i);i+=2;
-		}
-		i+=4;
-		nt->events.push_back(nce);
-	}//castle events have been read 
-
-    if(version > EMapFormat::AB)
-	{
-        nt->alignment = buffer[i]; ++i;
-	}
-	else
-		nt->alignment = 0xff;
-	i+=3;
-
-	nt->builded = 0;
-	nt->destroyed = 0;
-	nt->garrisonHero = NULL;
-}
-
-CGObjectInstance * CMap::loadHero(const ui8 * buffer, int &i, int idToBeGiven)
-{
-	CGHeroInstance * nhi = new CGHeroInstance();
-
-	int identifier = 0;
-    if(version > EMapFormat::ROE)
-	{
-        identifier = read_le_u32(buffer + i); i+=4;
-		questIdentifierToId[identifier] = idToBeGiven;
-	}
-
-    ui8 owner = buffer[i++];
-    nhi->subID = buffer[i++];
-	
-	for(ui32 j=0; j<predefinedHeroes.size(); j++)
-	{
-		if(predefinedHeroes[j]->subID == nhi->subID)
-		{
-			tlog0 << "Hero " << nhi->subID << " will be taken from the predefined heroes list.\n";
-			delete nhi;
-			nhi = predefinedHeroes[j];
-			break;
-		}
-	}
-	nhi->setOwner(owner);
-
-	nhi->portrait = nhi->subID;
-
-	for(ui32 j=0; j<disposedHeroes.size(); j++)
-	{
-		if(disposedHeroes[j].ID == nhi->subID)
-		{
-			nhi->name = disposedHeroes[j].name;
-			nhi->portrait = disposedHeroes[j].portrait;
-			break;
-		}
-	}
-    if(readChar(buffer,i))//true if hero has nonstandard name
-        nhi->name = readString(buffer,i);
-    if(version > EMapFormat::AB)
-	{
-        if(readChar(buffer,i))//true if hero's experience is greater than 0
-        {	nhi->exp = read_le_u32(buffer + i); i+=4;	}
-		else
-			nhi->exp = 0xffffffff;
-	}
-	else
-	{	
-        nhi->exp = read_le_u32(buffer + i); i+=4;
-		if(!nhi->exp) //0 means "not set" in <=AB maps
-			nhi->exp = 0xffffffff;
-	}
-
-    bool portrait=buffer[i]; ++i;
-	if (portrait)
-        nhi->portrait = buffer[i++];
-    if(readChar(buffer,i))//true if hero has specified abilities
-	{
-        int howMany = read_le_u32(buffer + i); i+=4;
-		nhi->secSkills.resize(howMany);
-		for(int yy=0; yy<howMany; ++yy)
-		{
-            nhi->secSkills[yy].first = buffer[i++];
-            nhi->secSkills[yy].second = buffer[i++];
-		}
-	}
-    if(readChar(buffer,i))//true if hero has nonstandard garrison
-        readCreatureSet(nhi, buffer, i, 7, version > EMapFormat::ROE);
-
-    nhi->formation =buffer[i]; ++i; //formation
-    loadArtifactsOfHero(buffer, i, nhi);
-    nhi->patrol.patrolRadious = buffer[i]; ++i;
-	if(nhi->patrol.patrolRadious == 0xff)
-		nhi->patrol.patrolling = false;
-	else 
-		nhi->patrol.patrolling = true;
-
-    if(version > EMapFormat::ROE)
-	{
-        if(readChar(buffer,i))//true if hero has nonstandard (mapmaker defined) biography
-            nhi->biography = readString(buffer,i);
-        nhi->sex = buffer[i]; ++i;
-		
-		if (nhi->sex != 0xFF)//remove trash
-			nhi->sex &=1;
-	}
-	else
-		nhi->sex = 0xFF;
-	//spells
-    if(version > EMapFormat::AB)
-	{
-        bool areSpells = buffer[i]; ++i;
-
-		if(areSpells) //TODO: sprawdzi //seems to be ok - tow
-		{
-			nhi->spells.insert(0xffffffff); //placeholder "preset spells"
-			int ist = i;
-			for(; i<ist+9; ++i)
-			{
-                ui8 c = buffer[i];
-				for(int yy=0; yy<8; ++yy)
-				{
-					if((i-ist)*8+yy < GameConstants::SPELLS_QUANTITY)
-					{
-						if(c == (c|((ui8)intPow(2, yy))))
-							nhi->spells.insert((i-ist)*8+yy);
-					}
-				}
-			}
-		}
-	}
-    else if(version == EMapFormat::AB) //we can read one spell
-	{
-        ui8 buff = buffer[i]; ++i;
-		if(buff != 254)
-		{
-			nhi->spells.insert(0xffffffff); //placeholder "preset spells"
-			if(buff < 254) //255 means no spells
-				nhi->spells.insert(buff);
-		}
-	}
-	//spells loaded
-    if(version > EMapFormat::AB)
-	{
-        if(readChar(buffer,i))//customPrimSkills
-		{
-			for(int xx=0; xx<GameConstants::PRIMARY_SKILLS; xx++)
-                nhi->pushPrimSkill(xx, buffer[i++]);
-		}
-	}
-	i+=16;
-
-	return nhi;
-}
-
-void CMap::readRumors( const ui8 * buffer, int &i)
-{
-    int rumNr = read_le_u32(buffer + i);i+=4;
-	for (int it=0;it<rumNr;it++)
-	{
-		Rumor ourRumor;
-        int nameL = read_le_u32(buffer + i);i+=4; //read length of name of rumor
-		for (int zz=0; zz<nameL; zz++)
-            ourRumor.name+=buffer[i++];
-        nameL = read_le_u32(buffer + i);i+=4; //read length of rumor
-		for (int zz=0; zz<nameL; zz++)
-            ourRumor.text+=buffer[i++];
-		rumors.push_back(ourRumor); //add to our list
-	}
-}
-
-void CMap::readHeader( const ui8 * buffer, int &i)
-{
-	//reading allowed heroes (20 bytes)
-	int ist;
-	ui8 disp = 0;
-
-    if(version >= EMapFormat::SOD)
-	{
-        disp = buffer[i++];
-		disposedHeroes.resize(disp);
-		for(int g=0; g<disp; ++g)
-		{
-            disposedHeroes[g].ID = buffer[i++];
-            disposedHeroes[g].portrait = buffer[i++];
-            int lenbuf = read_le_u32(buffer + i); i+=4;
-			for (int zz=0; zz<lenbuf; zz++)
-                disposedHeroes[g].name+=buffer[i++];
-            disposedHeroes[g].players = buffer[i++];
-		}
-	}
-
-	i+=31; //omitting NULLS
-
-	allowedArtifact.resize(GameConstants::ARTIFACTS_QUANTITY);
-	for (ui32 x=0; x<allowedArtifact.size(); x++)
-		allowedArtifact[x] = true;
-
-	//reading allowed artifacts:  17 or 18 bytes
-    if (version != EMapFormat::ROE)
-	{
-		ist=i; //starting i for loop
-        for (; i<ist+(version == EMapFormat::AB ? 17 : 18); ++i)
-		{
-            ui8 c = buffer[i];
-			for (int yy=0; yy<8; ++yy)
-			{
-				if ((i-ist)*8+yy < GameConstants::ARTIFACTS_QUANTITY)
-				{
-					if (c == (c|((ui8)intPow(2, yy))))
-						allowedArtifact[(i-ist)*8+yy] = false;
-				}
-			}
-		}//allowed artifacts have been read
-	}
-    if (version == EMapFormat::ROE || version == EMapFormat::AB) //ban combo artifacts
-	{
-		BOOST_FOREACH(CArtifact *artifact, VLC->arth->artifacts) 
-		{
-			if (artifact->constituents) //combo
-			{
-				allowedArtifact[artifact->id] = false;
-			}
-		}
-        if (version == EMapFormat::ROE)
-			allowedArtifact[128] = false; //Armageddon's Blade
-	}
-
-	allowedSpell.resize(GameConstants::SPELLS_QUANTITY);
-	for(ui32 x=0;x<allowedSpell.size();x++)
-		allowedSpell[x] = true;
-
-	allowedAbilities.resize(GameConstants::SKILL_QUANTITY);
-	for(ui32 x=0;x<allowedAbilities.size();x++)
-		allowedAbilities[x] = true;
-
-    if(version >= EMapFormat::SOD)
-	{
-		//reading allowed spells (9 bytes)
-		ist=i; //starting i for loop
-		for(; i<ist+9; ++i)
-		{
-            ui8 c = buffer[i];
-			for(int yy=0; yy<8; ++yy)
-				if((i-ist)*8+yy < GameConstants::SPELLS_QUANTITY)
-					if(c == (c|((ui8)intPow(2, yy))))
-						allowedSpell[(i-ist)*8+yy] = false;
-		}
-
-
-		//allowed hero's abilities (4 bytes)
-		ist=i; //starting i for loop
-		for(; i<ist+4; ++i)
-		{
-            ui8 c = buffer[i];
-			for(int yy=0; yy<8; ++yy)
-			{
-				if((i-ist)*8+yy < GameConstants::SKILL_QUANTITY)
-				{
-					if(c == (c|((ui8)intPow(2, yy))))
-						allowedAbilities[(i-ist)*8+yy] = false;
-				}
-			}
-		}
-	}
-}
-
-void CMap::readPredefinedHeroes( const ui8 * buffer, int &i)
-{
-	switch(version)
-	{
-    case EMapFormat::WOG:
-    case EMapFormat::SOD:
-		{
-			for(int z=0;z<GameConstants::HEROES_QUANTITY;z++) //disposed heroes
-			{
-                int custom =  buffer[i++];
-				if(!custom)
-					continue;
-				CGHeroInstance * cgh = new CGHeroInstance;
-				cgh->ID = Obj::HERO;
-				cgh->subID = z;
-                if(readChar(buffer,i))//true if hore's experience is greater than 0
-                {	cgh->exp = read_le_u32(buffer + i); i+=4;	}
-				else
-					cgh->exp = 0;
-                if(readChar(buffer,i))//true if hero has specified abilities
-				{
-                    int howMany = read_le_u32(buffer + i); i+=4;
-					cgh->secSkills.resize(howMany);
-					for(int yy=0; yy<howMany; ++yy)
-					{
-                        cgh->secSkills[yy].first = buffer[i]; ++i;
-                        cgh->secSkills[yy].second = buffer[i]; ++i;
-					}
-				}
-
-                loadArtifactsOfHero(buffer, i, cgh);
-
-                if(readChar(buffer,i))//customBio
-                    cgh->biography = readString(buffer,i);
-                cgh->sex = buffer[i++]; // 0xFF is default, 00 male, 01 female
-                if(readChar(buffer,i))//are spells
-				{
-					int ist = i;
-					for(; i<ist+9; ++i)
-					{
-                        ui8 c = buffer[i];
-						for(int yy=0; yy<8; ++yy)
-						{
-							if((i-ist)*8+yy < GameConstants::SPELLS_QUANTITY)
-							{
-								if(c == (c|((ui8)intPow(2, yy))))
-									cgh->spells.insert((i-ist)*8+yy);
-							}
-						}
-					}
-				}
-                if(readChar(buffer,i))//customPrimSkills
-				{
-					for(int xx=0; xx<GameConstants::PRIMARY_SKILLS; xx++)
-                        cgh->pushPrimSkill(xx, buffer[i++]);
-				}
-				predefinedHeroes.push_back(cgh);
-			}
-			break;
-		}
-    case EMapFormat::ROE:
-		i+=0;
-		break;
-	}
-}
-
-void CMap::readTerrain( const ui8 * buffer, int &i)
-{
-	terrain = new TerrainTile**[width]; // allocate memory 
-	for (int ii=0;ii<width;ii++)
-	{
-		terrain[ii] = new TerrainTile*[height]; // allocate memory 
-		for(int jj=0;jj<height;jj++)
-			terrain[ii][jj] = new TerrainTile[twoLevel+1];
-	}
-
-	for (int c=0; c<width; c++) // reading terrain
-	{
-		for (int z=0; z<height; z++)
-		{
-            terrain[z][c][0].tertype = static_cast<ETerrainType::ETerrainType>(buffer[i++]);
-            terrain[z][c][0].terview = buffer[i++];
-            terrain[z][c][0].riverType = static_cast<ERiverType::ERiverType>(buffer[i++]);
-            terrain[z][c][0].riverDir = buffer[i++];
-            terrain[z][c][0].roadType = static_cast<ERoadType::ERoadType>(buffer[i++]);
-            terrain[z][c][0].roadDir = buffer[i++];
-            terrain[z][c][0].extTileFlags = buffer[i++];
-            terrain[z][c][0].blocked = (terrain[z][c][0].tertype == ETerrainType::ROCK ? 1 : 0); //underground tiles are always blocked
-			terrain[z][c][0].visitable = 0;
-		}
-	}
-	if (twoLevel) // read underground terrain
-	{
-		for (int c=0; c<width; c++) // reading terrain
-		{
-			for (int z=0; z<height; z++)
-			{
-                terrain[z][c][1].tertype = static_cast<ETerrainType::ETerrainType>(buffer[i++]);
-                terrain[z][c][1].terview = buffer[i++];
-                terrain[z][c][1].riverType = static_cast<ERiverType::ERiverType>(buffer[i++]);
-                terrain[z][c][1].riverDir = buffer[i++];
-                terrain[z][c][1].roadType = static_cast<ERoadType::ERoadType>(buffer[i++]);
-                terrain[z][c][1].roadDir = buffer[i++];
-                terrain[z][c][1].extTileFlags = buffer[i++];
-                terrain[z][c][1].blocked = (terrain[z][c][1].tertype == ETerrainType::ROCK ? 1 : 0); //underground tiles are always blocked
-				terrain[z][c][1].visitable = 0;
-			}
-		}
-	}
-}
-
-void CMap::readDefInfo( const ui8 * buffer, int &i)
-{
-    int defAmount = read_le_u32(buffer + i); i+=4;
-    customDefs.reserve(defAmount+8);
-	for (int idd = 0 ; idd<defAmount; idd++) // reading defs
-	{
-		CGDefInfo * vinya = new CGDefInfo(); // info about new def 
-
-		//reading name
-        int nameLength = read_le_u32(buffer + i);i+=4;
-		vinya->name.reserve(nameLength);
-		for (int cd=0;cd<nameLength;cd++)
-		{
-            vinya->name += buffer[i++];
-		}
-		std::transform(vinya->name.begin(),vinya->name.end(),vinya->name.begin(),(int(*)(int))toupper);
-
-
-		ui8 bytes[12];
-		for (int v=0; v<12; v++) // read info
-		{
-            bytes[v] = buffer[i++];
-		}
-        vinya->terrainAllowed = read_le_u16(buffer + i);i+=2;
-        vinya->terrainMenu = read_le_u16(buffer + i);i+=2;
-        vinya->id = read_le_u32(buffer + i);i+=4;
-        vinya->subid = read_le_u32(buffer + i);i+=4;
-        vinya->type = buffer[i++];
-        vinya->printPriority = buffer[i++];
-		for (int zi=0; zi<6; zi++)
-		{
-			vinya->blockMap[zi] = reverse(bytes[zi]);
-		}
-		for (int zi=0; zi<6; zi++)
-		{
-			vinya->visitMap[zi] = reverse(bytes[6+zi]);
-		}
-		i+=16;
-		if(vinya->id!=Obj::HERO && vinya->id!=70)
-		{
-			CGDefInfo *h = VLC->dobjinfo->gobjs[vinya->id][vinya->subid];
-			if(!h) 
-			{
-				//remove fake entry
-				VLC->dobjinfo->gobjs[vinya->id].erase(vinya->subid);
-				if(VLC->dobjinfo->gobjs[vinya->id].size())
-					VLC->dobjinfo->gobjs.erase(vinya->id);
-				tlog2<<"\t\tWarning: no defobjinfo entry for object ID="<<vinya->id<<" subID=" << vinya->subid<<std::endl;
-			}
-			else
-			{
-				vinya->visitDir = VLC->dobjinfo->gobjs[vinya->id][vinya->subid]->visitDir;
-			}
-		}
-		else
-		{
-			vinya->visitDir = 0xff;
-		}
-
-		if(vinya->id == Obj::EVENT)
-			std::memset(vinya->blockMap,255,6);
-
-		//calculating coverageMap
-		vinya->fetchInfoFromMSK();
-
-        customDefs.push_back(vinya); // add this def to the vector
-	}
-
-	//add holes - they always can appear 
-	for (int i = 0; i < 8 ; i++)
-	{
-        customDefs.push_back(VLC->dobjinfo->gobjs[124][i]);
-	}
-}
-
-class _HERO_SORTER
-{
-public:
-	bool operator()(const ConstTransitivePtr<CGHeroInstance> & a, const ConstTransitivePtr<CGHeroInstance> & b)
-	{
-		return a->subID < b->subID;
-	}
-};
-
-void CMap::readObjects(const ui8 * buffer, int &i)
-{
-    int howManyObjs = read_le_u32(buffer + i); i+=4;
-	for(int ww=0; ww<howManyObjs; ++ww) //comment this line to turn loading objects off
-	{
-		CGObjectInstance * nobj = 0;
-
-		int3 pos;
-        pos.x = buffer[i++];
-        pos.y = buffer[i++];
-        pos.z = buffer[i++];
-
-        int defnum = read_le_u32(buffer + i); i+=4;
-		int idToBeGiven = objects.size();
-
-        CGDefInfo * defInfo = customDefs.at(defnum);
-		i+=5;
-
-		switch(defInfo->id)
-		{
-		case Obj::EVENT: //for event objects
-			{
-				CGEvent *evnt = new CGEvent();
-				nobj = evnt;
-
-                bool guardMess = buffer[i]; ++i;
-				if(guardMess)
-				{
-                    int messLong = read_le_u32(buffer + i); i+=4;
-					if(messLong>0)
-					{
-						for(int yy=0; yy<messLong; ++yy)
-						{
-                            evnt->message +=buffer[i+yy];
-						}
-						i+=messLong;
-					}
-                    if(buffer[i++])
-					{
-                        readCreatureSet(evnt, buffer, i, 7, version > EMapFormat::ROE);
-					}
-					i+=4;
-				}
-                evnt->gainedExp = read_le_u32(buffer + i); i+=4;
-                evnt->manaDiff = read_le_u32(buffer + i); i+=4;
-                evnt->moraleDiff = (char)buffer[i]; ++i;
-                evnt->luckDiff = (char)buffer[i]; ++i;
-
-				evnt->resources.resize(GameConstants::RESOURCE_QUANTITY);
-				for(int x=0; x<7; x++)
-				{
-                    evnt->resources[x] = read_le_u32(buffer + i);
-					i+=4;
-				}
-
-				evnt->primskills.resize(GameConstants::PRIMARY_SKILLS);
-				for(int x=0; x<4; x++)
-				{
-                    evnt->primskills[x] = buffer[i];
-					i++;
-				}
-
-				int gabn; //number of gained abilities
-                gabn = buffer[i]; ++i;
-				for(int oo = 0; oo<gabn; ++oo)
-				{
-                    evnt->abilities.push_back(buffer[i]); ++i;
-                    evnt->abilityLevels.push_back(buffer[i]); ++i;
-				}
-
-                int gart = buffer[i]; ++i; //number of gained artifacts
-				for(int oo = 0; oo<gart; ++oo)
-				{
-                    if (version == EMapFormat::ROE)
-					{
-                        evnt->artifacts.push_back(buffer[i]); i++;
-					}
-					else
-					{
-                        evnt->artifacts.push_back(read_le_u16(buffer + i)); i+=2;
-					}
-				}
-
-                int gspel = buffer[i]; ++i; //number of gained spells
-				for(int oo = 0; oo<gspel; ++oo)
-				{
-                    evnt->spells.push_back(buffer[i]); ++i;
-				}
-
-                int gcre = buffer[i]; ++i; //number of gained creatures
-                readCreatureSet(&evnt->creatures, buffer,i,gcre,(version > EMapFormat::ROE));
-
-				i+=8;
-                evnt->availableFor = buffer[i]; ++i;
-                evnt->computerActivate = buffer[i]; ++i;
-                evnt->removeAfterVisit = buffer[i]; ++i;
-				evnt->humanActivate = true;
-
-				i+=4;
-				break;
-			}
-		case 34: case 70: case 62: //34 - hero; 70 - random hero; 62 - prison
-			{
-                nobj = loadHero(buffer, i, idToBeGiven);
-				break;
-			}
-		case 4: //Arena
-		case 51: //Mercenary Camp
-		case 23: //Marletto Tower
-		case 61: // Star Axis
-		case 32: // Garden of Revelation
-		case 100: //Learning Stone
-		case 102: //Tree of Knowledge
-		case 41: //Library of Enlightenment
-		case 47: //School of Magic
-		case 107: //School of War
-			{
-				nobj = new CGVisitableOPH();
-				break;
-			}
-		case 55: //mystical garden
-		case 112://windmill
-		case 109://water wheel
-			{
-				nobj = new CGVisitableOPW();
-				break;
-			}
-		case 43: //teleport
-		case 44: //teleport
-		case 45: //teleport
-		case 103://subterranean gate
-		case 111://Whirlpool
-			{
-				nobj = new CGTeleport();
-				break;
-			}
-		case 12: //campfire
-		case 29: //Flotsam
-		case 82: //Sea Chest
-		case 86: //Shipwreck Survivor
-		case 101://treasure chest
-			{
-				nobj = new CGPickable();
-				break;
-			}
-		case 54:  //Monster 
-		case 71: case 72: case 73: case 74: case 75:	// Random Monster 1 - 4
-		case 162: case 163: case 164:					// Random Monster 5 - 7
-			{
-				CGCreature *cre = new CGCreature();
-				nobj = cre;
-
-                if(version > EMapFormat::ROE)
-				{
-                    cre->identifier = read_le_u32(buffer + i); i+=4;
-					questIdentifierToId[cre->identifier] = idToBeGiven;
-					//monsters[cre->identifier] = cre;
-				}
-
-				CStackInstance *hlp = new CStackInstance();
-                hlp->count =  read_le_u16(buffer + i); i+=2;
-				//type will be set during initialization
-				cre->putStack(0, hlp);
-
-                cre->character = buffer[i]; ++i;
-                bool isMesTre = buffer[i]; ++i; //true if there is message or treasury
-				if(isMesTre)
-				{
-                    cre->message = readString(buffer,i);
-					cre->resources.resize(GameConstants::RESOURCE_QUANTITY);
-					for(int j=0; j<7; j++)
-					{
-                        cre->resources[j] = read_le_u32(buffer + i); i+=4;
-					}
-
-					int artID;
-                    if (version == EMapFormat::ROE)
-					{
-                        artID = buffer[i]; i++;
-					}
-					else
-					{
-                        artID = read_le_u16(buffer + i); i+=2;
-					}
-
-                    if(version == EMapFormat::ROE)
-					{
-						if(artID!=0xff)
-							cre->gainedArtifact = artID;
-						else
-							cre->gainedArtifact = -1;
-					}
-					else
-					{
-						if(artID!=0xffff)
-							cre->gainedArtifact = artID;
-						else
-							cre->gainedArtifact = -1;
-					}
-				}
-                cre->neverFlees = buffer[i]; ++i;
-                cre->notGrowingTeam = buffer[i]; ++i;
-				i+=2;;
-				break;
-			}
-		case 59: case 91: //ocean bottle and sign
-			{
-				CGSignBottle *sb = new CGSignBottle();
-				nobj = sb;
-                sb->message = readString(buffer,i);
-				i+=4;
-				break;
-			}
-		case 83: //seer's hut
-			{
-                i = loadSeerHut(buffer, i, nobj);
-				addQuest (nobj);
-				break;
-			}
-		case 113: //witch hut
-			{
-				CGWitchHut *wh = new CGWitchHut();
-				nobj = wh;
-                if(version > EMapFormat::ROE) //in reo we cannot specify it - all are allowed (I hope)
-				{
-					int ist=i; //starting i for loop
-					for(; i<ist+4; ++i)
-					{
-                        ui8 c = buffer[i];
-						for(int yy=0; yy<8; ++yy)
-						{
-							if((i-ist)*8+yy < GameConstants::SKILL_QUANTITY)
-							{
-								if(c == (c|((ui8)intPow(2, yy))))
-									wh->allowedAbilities.push_back((i-ist)*8+yy);
-							}
-						}
-					}
-				}
-				else //(RoE map)
-				{
-					for(int gg=0; gg<GameConstants::SKILL_QUANTITY; ++gg)
-					{
-						wh->allowedAbilities.push_back(gg);
-					}
-				}
-				break;
-			}
-		case 81: //scholar
-			{
-				CGScholar *sch = new CGScholar();
-				nobj = sch;
-                sch->bonusType = buffer[i++];
-                sch->bonusID = buffer[i++];
-				i+=6;
-				break;
-			}
-		case 33: case 219: //garrison
-			{
-				CGGarrison *gar = new CGGarrison();
-				nobj = gar;
-                nobj->setOwner(buffer[i++]);
-				i+=3;
-                readCreatureSet(gar, buffer, i, 7, version > EMapFormat::ROE);
-                if(version > EMapFormat::ROE)
-				{
-                    gar->removableUnits = buffer[i]; ++i;
-				}
-				else
-					gar->removableUnits = true;
-				i+=8;
-				break;
-			}
-		case 5: //artifact	
-		case 65: case 66: case 67: case 68: case 69: //random artifact
-		case 93: //spell scroll
-			{
-				int artID = -1;
-				int spellID = -1;
-				CGArtifact *art = new CGArtifact();
-				nobj = art;
-
-                bool areSettings = buffer[i++];
-				if(areSettings)
-				{
-                    art->message = readString(buffer,i);
-                    bool areGuards = buffer[i++];
-					if(areGuards)
-					{
-                        readCreatureSet(art, buffer, i, 7, version > EMapFormat::ROE);
-					}
-					i+=4;
-				}
-
-				if(defInfo->id==93)
-				{
-                    spellID = read_le_u32(buffer + i); i+=4;
-					artID = 1;
-				}
-				else if(defInfo->id == 5) //specific artifact
-				{
-					artID = defInfo->subid;
-				}
-
-				art->storedArtifact = createArt(artID, spellID);
-				break;
-			}
-		case 76: case 79: //random resource; resource
-			{
-				CGResource *res = new CGResource();
-				nobj = res;
-
-                bool isMessGuard = buffer[i]; ++i;
-				if(isMessGuard)
-				{
-                    res->message = readString(buffer,i);
-                    if(buffer[i++])
-					{
-                        readCreatureSet(res, buffer, i, 7, version > EMapFormat::ROE);
-					}
-					i+=4;
-				}
-                res->amount = read_le_u32(buffer + i); i+=4;
-				if (defInfo->subid == 6) // Gold is multiplied by 100.
-					res->amount *= 100;
-				i+=4;
-
-				break;
-			}
-		case 77: case 98: //random town; town
-			{
-                loadTown(nobj, buffer, i, defInfo->subid);
-				break;
-			}
-		case 53: 
-		case 220://mine (?)
-			{
-				nobj = new CGMine();
-                nobj->setOwner(buffer[i++]);
-				i+=3;
-				break;
-			}
-		case 17: case 18: case 19: case 20: //dwellings
-			{
-				nobj = new CGDwelling();
-                nobj->setOwner(buffer[i++]);
-				i+=3;
-				break;
-			}
-		case 78: //Refugee Camp
-		case 106: //War Machine Factory
-			{
-				nobj = new CGDwelling();
-				break;
-			}
-		case 88: case 89: case 90: //spell shrine
-			{
-				CGShrine * shr = new CGShrine();
-				nobj = shr;
-                shr->spell = buffer[i]; i+=4;
-				break;
-			}
-		case 6: //pandora's box
-			{
-				CGPandoraBox *box = new CGPandoraBox();
-				nobj = box;
-                bool messg = buffer[i]; ++i;
-				if(messg)
-				{
-                    box->message = readString(buffer,i);
-                    if(buffer[i++])
-					{
-                        readCreatureSet(box, buffer, i, 7, version > EMapFormat::ROE);
-					}
-					i+=4;
-				}
-
-                box->gainedExp = read_le_u32(buffer + i); i+=4;
-                box->manaDiff = read_le_u32(buffer + i); i+=4;
-                box->moraleDiff = (si8)buffer[i]; ++i;
-                box->luckDiff = (si8)buffer[i]; ++i;
-
-				box->resources.resize(GameConstants::RESOURCE_QUANTITY);
-				for(int x=0; x<7; x++)
-				{
-                    box->resources[x] = read_le_u32(buffer + i);
-					i+=4;
-				}
-
-				box->primskills.resize(GameConstants::PRIMARY_SKILLS);
-				for(int x=0; x<4; x++)
-				{
-                    box->primskills[x] = buffer[i];
-					i++;
-				}
-
-				int gabn; //number of gained abilities
-                gabn = buffer[i]; ++i;
-				for(int oo = 0; oo<gabn; ++oo)
-				{
-                    box->abilities.push_back(buffer[i]); ++i;
-                    box->abilityLevels.push_back(buffer[i]); ++i;
-				}
-                int gart = buffer[i]; ++i; //number of gained artifacts
-				for(int oo = 0; oo<gart; ++oo)
-				{
-                    if(version > EMapFormat::ROE)
-					{
-                        box->artifacts.push_back(read_le_u16(buffer + i)); i+=2;
-					}
-					else
-					{
-                        box->artifacts.push_back(buffer[i]); i+=1;
-					}
-				}
-                int gspel = buffer[i]; ++i; //number of gained spells
-				for(int oo = 0; oo<gspel; ++oo)
-				{
-                    box->spells.push_back(buffer[i]); ++i;
-				}
-                int gcre = buffer[i]; ++i; //number of gained creatures
-                readCreatureSet(&box->creatures, buffer,i,gcre,(version > EMapFormat::ROE));
-				i+=8;
-				break;
-			}
-		case 36: //grail
-			{
-				grailPos = pos;
-                grailRadious = read_le_u32(buffer + i); i+=4;
-				continue;
-			}
-		//dwellings
-		case 216: //same as castle + level range
-		case 217: //same as castle
-		case 218: //level range
-			{
-				nobj = new CGDwelling();
-				CSpecObjInfo * spec = nullptr;
-				switch(defInfo->id)
-				{
-					break; case 216: spec = new CCreGenLeveledCastleInfo;
-					break; case 217: spec = new CCreGenAsCastleInfo;
-					break; case 218: spec = new CCreGenLeveledInfo;
-				}
-
-                spec->player = read_le_u32(buffer + i); i+=4;
-				//216 and 217
-				if (auto castleSpec = dynamic_cast<CCreGenAsCastleInfo*>(spec))
-				{
-                    castleSpec->identifier =  read_le_u32(buffer + i); i+=4;
-					if(!castleSpec->identifier)
-					{
-						castleSpec->asCastle = false;
-                        castleSpec->castles[0] = buffer[i]; ++i;
-                        castleSpec->castles[1] = buffer[i]; ++i;
-					}
-					else
-					{
-						castleSpec->asCastle = true;
-					}
-				}
-
-				//216 and 218
-				if (auto lvlSpec = dynamic_cast<CCreGenLeveledInfo*>(spec))
-				{
-                    lvlSpec->minLevel = std::max(buffer[i], ui8(1)); ++i;
-                    lvlSpec->maxLevel = std::min(buffer[i], ui8(7)); ++i;
-				}
-				nobj->setOwner(spec->player);
-				static_cast<CGDwelling*>(nobj)->info = spec;
-				break;
-			}
-		case 215:
-			{
-				CGQuestGuard *guard = new CGQuestGuard();
-				addQuest (guard);
-                loadQuest(guard, buffer, i);
-				nobj = guard;
-				break;
-			}
-		case 28: //faerie ring
-		case 14: //Swan pond
-		case 38: //idol of fortune
-		case 30: //Fountain of Fortune
-		case 64: //Rally Flag
-		case 56: //oasis
-		case 96: //temple
-		case 110://Watering Hole
-		case 31: //Fountain of Youth
-		case 11: //Buoy
-		case 52: //Mermaid
-		case 94: //Stables
-			{
-				nobj = new CGBonusingObject();
-				break;
-			}
-		case 49: //Magic Well
-			{
-				nobj = new CGMagicWell();
-				break;
-			}
-		case 15: //Cover of darkness
-		case 58: //Redwood Observatory
-		case 60: //Pillar of Fire
-			{
-				nobj = new CGObservatory();
-				break;
-			}
-		case 22: //Corpse
-		case 39: //Lean To
-		case 105://Wagon
-		case 108://Warrior's Tomb
-			{
-				nobj = new CGOnceVisitable();
-				break;
-			}
-		case 8: //Boat
-			{
-				nobj = new CGBoat();
-				break;
-			}
-		case 92: //Sirens
-			{
-				nobj = new CGSirens();
-				break;
-			}
-		case 87: //Shipyard
-			{
-				nobj = new CGShipyard();
-                nobj->setOwner(read_le_u32(buffer + i)); i+=4;
-				break;
-			}
-		case 214: //hero placeholder
-			{
-				CGHeroPlaceholder *hp = new CGHeroPlaceholder();;
-				nobj = hp;
-
-                int a = buffer[i++]; //unknown byte, seems to be always 0 (if not - scream!)
-				tlog2 << "Unhandled Hero Placeholder detected: "<<a<<"\n";
-
-                int htid = buffer[i++]; //hero type id
-				nobj->subID = htid;
-
-				if(htid == 0xff)
-                    hp->power = buffer[i++];
-				else
-					hp->power = 0;
-
-				break;
-			}
-		case 10: //Keymaster
-			{
-				nobj = new CGKeymasterTent();
-				break;
-			}
-		case 9: //Border Guard
-			{
-				nobj = new CGBorderGuard();
-				addQuest (nobj);
-				break;
-			}
-		case 212: //Border Gate
-			{
-				nobj = new CGBorderGate();
-				addQuest (nobj);
-				break;
-			}
-		case 27: case 37: //Eye and Hut of Magi
-			{
-				nobj = new CGMagi();
-				break;
-			}
-		case 16: case 24: case 25: case 84: case 85: //treasure bank
-			{
-				nobj = new CBank();
-				break;
-			}
-		case 63: //Pyramid
-			{
-				nobj = new CGPyramid();
-				break;
-			}
-		case 13: //Cartographer
-			{
-				nobj = new CCartographer();
-				break;
-			}
-		case 48: //Magic Spring
-			{
-				nobj = new CGMagicSpring();
-				break;
-			}
-		case 97: //den of thieves
-			{
-				nobj = new CGDenOfthieves();
-				break;
-			}
-		case 57: //Obelisk
-			{
-				nobj = new CGObelisk();
-				break;
-			}
-		case 42: //Lighthouse
-			{
-				nobj = new CGLighthouse();
-                nobj->tempOwner = read_le_u32(buffer + i); i+=4;
-				break;
-			}
-		case 2: //Altar of Sacrifice
-		case 99: //Trading Post
-		case 213: //Freelancer's Guild
-		case 221: //Trading Post (snow)
-			{
-				nobj = new CGMarket();
-				break;
-			}
-		case 104: //University
-			{
-				nobj = new CGUniversity();
-				break;
-			}
-		case 7: //Black Market
-			{
-				nobj = new CGBlackMarket();
-				break;
-			}
-
-		default: //any other object
-			{
-				nobj = new CGObjectInstance();
-				break;
-			}
-
-		} //end of main switch
-
-		nobj->pos = pos;
-		nobj->ID = defInfo->id;
-		nobj->id = idToBeGiven;
-		if(nobj->ID != Obj::HERO && nobj->ID != Obj::HERO_PLACEHOLDER && nobj->ID != Obj::PRISON)
-			nobj->subID = defInfo->subid;
-		nobj->defInfo = defInfo;
-		assert(idToBeGiven == objects.size());
-		objects.push_back(nobj);
-		if(nobj->ID==Obj::TOWN)
-			towns.push_back(static_cast<CGTownInstance*>(nobj));
-		if(nobj->ID==Obj::HERO)
-			heroes.push_back(static_cast<CGHeroInstance*>(nobj));
-	}
-
-	std::sort(heroes.begin(), heroes.end(), _HERO_SORTER());
-}
-
-void CMap::readEvents( const ui8 * buffer, int &i )
-{
-    int numberOfEvents = read_le_u32(buffer + i); i+=4;
-	for(int yyoo=0; yyoo<numberOfEvents; ++yyoo)
-	{
-		CMapEvent *ne = new CMapEvent();
-		ne->name = std::string();
-		ne->message = std::string();
-        int nameLen = read_le_u32(buffer + i); i+=4;
-		for(int qq=0; qq<nameLen; ++qq)
-		{
-            ne->name += buffer[i]; ++i;
-		}
-        int messLen = read_le_u32(buffer + i); i+=4;
-		for(int qq=0; qq<messLen; ++qq)
-		{
-            ne->message +=buffer[i]; ++i;
-		}
-		for(int k=0; k < 7; k++)
-		{
-            ne->resources[k] = read_le_u32(buffer + i); i+=4;
-		}
-        ne->players = buffer[i]; ++i;
-        if(version > EMapFormat::AB)
-		{
-            ne->humanAffected = buffer[i]; ++i;
-		}
-		else
-			ne->humanAffected = true;
-        ne->computerAffected = buffer[i]; ++i;
-        ne->firstOccurence = read_le_u16(buffer + i); i+=2;
-        ne->nextOccurence = buffer[i]; ++i;
-
-		char unknown[17];
-        memcpy(unknown, buffer+i, 17);
-		i+=17;
-
-		events.push_back(ne);
-	}
-}
-
-bool CMap::isInTheMap(const int3 &pos) const
-{
-	if(pos.x<0 || pos.y<0 || pos.z<0 || pos.x >= width || pos.y >= height || pos.z > twoLevel)
-		return false;
-	else return true;
-}
-
-void CMap::loadQuest(IQuestObject * guard, const ui8 * buffer, int & i)
-{
-    guard->quest->missionType = buffer[i]; ++i;
-	//int len1, len2, len3;
-	switch(guard->quest->missionType)
-	{
-	case 0:
-		return;
-	case 2:
-		{
-			guard->quest->m2stats.resize(4);
-			for(int x=0; x<4; x++)
-			{
-                guard->quest->m2stats[x] = buffer[i++];
-			}
-		}
-		break;
-	case 1:
-	case 3:
-	case 4:
-		{
-            guard->quest->m13489val = read_le_u32(buffer + i); i+=4;
-			break;
-		}
-	case 5:
-		{
-            int artNumber = buffer[i]; ++i;
-			for(int yy=0; yy<artNumber; ++yy)
-			{
-                int artid = read_le_u16(buffer + i); i+=2;
-				guard->quest->m5arts.push_back(artid); 
-				allowedArtifact[artid] = false; //these are unavailable for random generation
-			}
-			break;
-		}
-	case 6:
-		{
-            int typeNumber = buffer[i]; ++i;
-			guard->quest->m6creatures.resize(typeNumber);
-			for(int hh=0; hh<typeNumber; ++hh)
-			{
-                guard->quest->m6creatures[hh].type = VLC->creh->creatures[read_le_u16(buffer + i)]; i+=2;
-                guard->quest->m6creatures[hh].count = read_le_u16(buffer + i); i+=2;
-			}
-			break;
-		}
-	case 7:
-		{
-			guard->quest->m7resources.resize(7);
-			for(int x=0; x<7; x++)
-			{
-                guard->quest->m7resources[x] = read_le_u32(buffer + i);
-				i+=4;
-			}
-			break;
-		}
-	case 8:
-	case 9:
-		{
-            guard->quest->m13489val = buffer[i]; ++i;
-			break;
-		}
-	}
-
-
-    int limit = read_le_u32(buffer + i); i+=4;
-	if(limit == ((int)0xffffffff))
-	{
-		guard->quest->lastDay = -1;
-	}
-	else
-	{
-		guard->quest->lastDay = limit;
-	}
-    guard->quest->firstVisitText = readString(buffer,i);
-    guard->quest->nextVisitText = readString(buffer,i);
-    guard->quest->completedText = readString(buffer,i);
-	guard->quest->isCustomFirst = guard->quest->firstVisitText.size() > 0;
-	guard->quest->isCustomNext = guard->quest->nextVisitText.size() > 0;
-	guard->quest->isCustomComplete = guard->quest->completedText.size() > 0;
-}
-
-TerrainTile & CMap::getTile( const int3 & tile )
-{
-	return terrain[tile.x][tile.y][tile.z];
-}
-
-const TerrainTile & CMap::getTile( const int3 & tile ) const
-{
-	return terrain[tile.x][tile.y][tile.z];
-}
-
-bool CMap::isWaterTile(const int3 &pos) const
-{
-    return isInTheMap(pos) && getTile(pos).tertype == ETerrainType::WATER;
-}
-
-const CGObjectInstance *CMap::getObjectiveObjectFrom(int3 pos, bool lookForHero)
-{
-    const std::vector <CGObjectInstance *> & objs = getTile(pos).visitableObjects;
-	assert(objs.size());
-	if(objs.size() > 1 && lookForHero && objs.front()->ID != Obj::HERO)
-	{
-		assert(objs.back()->ID == Obj::HERO);
-		return objs.back();
-	}
-	else
-		return objs.front();
-}
-
-void CMap::checkForObjectives()
-{
-	if(isInTheMap(victoryCondition.pos))
-		victoryCondition.obj = getObjectiveObjectFrom(victoryCondition.pos, victoryCondition.condition == EVictoryConditionType::BEATHERO);
-
-	if(isInTheMap(lossCondition.pos))
-		lossCondition.obj = getObjectiveObjectFrom(lossCondition.pos, lossCondition.typeOfLossCon == ELossConditionType::LOSSHERO);
-}
-
-void CMap::addNewArtifactInstance( CArtifactInstance *art )
-{
-	art->id = artInstances.size();
-	artInstances.push_back(art);
-}
-
-void CMap::addQuest (CGObjectInstance * quest)
-{
-    auto q = dynamic_cast<IQuestObject *>(quest);
-	q->quest->qid = quests.size();
-	quests.push_back (q->quest);
-}
-
-bool CMap::loadArtifactToSlot(CGHeroInstance * hero, int slot, const ui8 * buffer, int & i)
-{
-    const int artmask = version == EMapFormat::ROE ? 0xff : 0xffff;
-	int aid;
-
-    if (version == EMapFormat::ROE)
-	{
-        aid = buffer[i]; i++;
-	}
-	else
-	{
-        aid = read_le_u16(buffer + i); i+=2;
-	}
-
-	bool isArt  =  aid != artmask;
-	if(isArt)
-	{
-		if(vstd::contains(VLC->arth->bigArtifacts, aid) && slot >= GameConstants::BACKPACK_START)
-		{
-			tlog3 << "Warning: A big artifact (war machine) in hero's backpack, ignoring...\n";
-			return false;
-		}
-		if(aid == 0 && slot == ArtifactPosition::MISC5)
-		{
-			//TODO: check how H3 handles it -> art 0 in slot 18 in AB map
-			tlog3 << "Spellbook to MISC5 slot? Putting it spellbook place. AB format peculiarity ? (format " << (int)version << ")\n";
-			slot = ArtifactPosition::SPELLBOOK;
-		}
-		
-        hero->putArtifact(slot, createArt(aid));
-	}
-	return isArt;
-}
-
-void CMap::loadArtifactsOfHero(const ui8 * buffer, int & i, CGHeroInstance * hero)
-{
-    bool artSet = buffer[i]; ++i; //true if artifact set is not default (hero has some artifacts)
-	if(artSet)
-	{
-		for(int pom=0;pom<16;pom++)
-            loadArtifactToSlot(hero, pom, buffer, i);
-
-		//misc5 art //17
-        if(version >= EMapFormat::SOD)
-		{
-            if(!loadArtifactToSlot(hero, ArtifactPosition::MACH4, buffer, i))
-                hero->putArtifact(ArtifactPosition::MACH4, createArt(GameConstants::ID_CATAPULT)); //catapult by default
-		}
-
-        loadArtifactToSlot(hero, ArtifactPosition::SPELLBOOK, buffer, i);
-
-		//19 //???what is that? gap in file or what? - it's probably fifth slot..
-        if(version > EMapFormat::ROE)
-            loadArtifactToSlot(hero, ArtifactPosition::MISC5, buffer, i);
-		else
-			i+=1;
-
-		//bag artifacts //20
-        int amount = read_le_u16(buffer + i); i+=2; //number of artifacts in hero's bag
-		for(int ss = 0; ss < amount; ++ss)
-            loadArtifactToSlot(hero, GameConstants::BACKPACK_START + hero->artifactsInBackpack.size(), buffer, i);
-	} //artifacts
-}
-
-CArtifactInstance * CMap::createArt(int aid, int spellID /*= -1*/)
-{
-	CArtifactInstance *a = NULL;
-	if(aid >= 0)
-	{
-        if(spellID < 0)
-			a = CArtifactInstance::createNewArtifactInstance(aid);
-		else
-            a = CArtifactInstance::createScroll(VLC->spellh->spells[spellID]);
-	}
-	else
-		a = new CArtifactInstance();
-
-	addNewArtifactInstance(a);
-	if(a->artType && a->artType->constituents) //TODO make it nicer
-	{
-		CCombinedArtifactInstance *comb = dynamic_cast<CCombinedArtifactInstance*>(a);
-		BOOST_FOREACH(CCombinedArtifactInstance::ConstituentInfo &ci, comb->constituentsInfo)
-		{
-			addNewArtifactInstance(ci.art);
-		}
-	}
-	return a;
-}
-
-void CMap::eraseArtifactInstance(CArtifactInstance *art)
-{
-	assert(artInstances[art->id] == art);
-	artInstances[art->id].dellNull();
-}
-
-LossCondition::LossCondition()
-{
-	obj = NULL;
-	timeLimit = -1;
-	pos = int3(-1,-1,-1);
-}
-
-VictoryCondition::VictoryCondition()
-{
-	pos = int3(-1,-1,-1);
-	obj = NULL;
-	ID = allowNormalVictory = appliesToAI = count = 0;
-}
-
-bool TerrainTile::entrableTerrain(const TerrainTile * from /*= NULL*/) const
-{
-    return entrableTerrain(from ? from->tertype != ETerrainType::WATER : true, from ? from->tertype == ETerrainType::WATER : true);
-}
-
-bool TerrainTile::entrableTerrain(bool allowLand, bool allowSea) const
-{
-    return tertype != ETerrainType::ROCK
-        && ((allowSea && tertype == ETerrainType::WATER)  ||  (allowLand && tertype != ETerrainType::WATER));
-}
-
-bool TerrainTile::isClear(const TerrainTile *from /*= NULL*/) const
-{
-	return entrableTerrain(from) && !blocked;
-}
-
-int TerrainTile::topVisitableID() const
-{
-	return visitableObjects.size() ? visitableObjects.back()->ID : -1;
-}
-
-bool TerrainTile::isCoastal() const
-{
-    return extTileFlags & 64;
-}
-
-bool TerrainTile::hasFavourableWinds() const
-{
-    return extTileFlags & 128;
-}
-
-bool TerrainTile::isWater() const
-{
-    return tertype == ETerrainType::WATER;
-}

+ 9 - 7
lib/vcmi_endian.h

@@ -44,19 +44,21 @@ static inline ui32 read_unaligned_u32(const void *p)
 #define read_le_u32(p) (SDL_SwapLE32(* reinterpret_cast<const ui32 *>(p)))
 #endif
 
-static inline char readChar(const ui8 * bufor, int &i)
+static inline char readChar(const ui8 * buffer, int & i)
 {
-	return bufor[i++];
+    return buffer[i++];
 }
 
-static inline std::string readString(const ui8 * bufor, int &i)
+static inline std::string readString(const ui8 * buffer, int & i)
 {
-	int len = read_le_u32(bufor + i); i+=4;
+    int len = read_le_u32(buffer + i);
+    i += 4;
 	assert(len >= 0 && len <= 500000); //not too long
-	std::string ret; ret.reserve(len);
-	for(int gg=0; gg<len; ++gg)
+    std::string ret;
+    ret.reserve(len);
+    for(int gg = 0; gg < len; ++gg)
 	{
-		ret += bufor[i++];
+        ret += buffer[i++];
 	}
 	return ret;
 }

+ 2 - 2
server/CGameHandler.cpp

@@ -3,7 +3,7 @@
 #include "../lib/Filesystem/CResourceLoader.h"
 #include "../lib/Filesystem/CFileInfo.h"
 #include "../lib/int3.h"
-#include "../lib/CCampaignHandler.h"
+#include "../lib/Map/CCampaignHandler.h"
 #include "../lib/StartInfo.h"
 #include "../lib/CModHandler.h"
 #include "../lib/CArtHandler.h"
@@ -20,7 +20,7 @@
 #include "../lib/CondSh.h"
 #include "../lib/NetPacks.h"
 #include "../lib/VCMI_Lib.h"
-#include "../lib/map.h"
+#include "../lib/Map/CMap.h"
 #include "../lib/VCMIDirs.h"
 #include "../client/CSoundBase.h"
 #include "CGameHandler.h"

+ 3 - 3
server/CVCMIServer.cpp

@@ -1,7 +1,7 @@
 #include "StdInc.h"
 
 #include "../lib/Filesystem/CResourceLoader.h"
-#include "../lib/CCampaignHandler.h"
+#include "../lib/Map/CCampaignHandler.h"
 #include "../lib/CThreadHelper.h"
 #include "../lib/Connection.h"
 #include "../lib/CModHandler.h"
@@ -16,12 +16,12 @@
 #include "zlib.h"
 #include "CVCMIServer.h"
 #include "../lib/StartInfo.h"
-#include "../lib/map.h"
+#include "../lib/Map/CMap.h"
 #include "../lib/Interprocess.h"
 #include "../lib/VCMI_Lib.h"
 #include "../lib/VCMIDirs.h"
 #include "CGameHandler.h"
-#include "../lib/CMapInfo.h"
+#include "../lib/Map/CMapInfo.h"
 #include "../lib/CObjectHandler.h"
 #include "../lib/GameConstants.h"
 

+ 1 - 1
server/NetPacksServer.cpp

@@ -4,7 +4,7 @@
 #include "CGameHandler.h"
 #include "../lib/CObjectHandler.h"
 #include "../lib/IGameCallback.h"
-#include "../lib/map.h"
+#include "../lib/Map/CMap.h"
 #include "../lib/CGameState.h"
 #include "../lib/BattleState.h"
 #include "../lib/BattleAction.h"