2
0
Эх сурвалжийг харах

- Foundation for starting a random map is done - Moved StdInc.h to header file in some /Map and /RMG compilation units(better syntax highlighting, should have no negative impact)

beegee1 13 жил өмнө
parent
commit
53169abea7

+ 1 - 1
client/BattleInterface/CBattleInterfaceClasses.cpp

@@ -314,7 +314,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
 	bg->colorize(owner->curInt->playerID);
 
 	exit = new CAdventureMapButton ("", "", boost::bind(&CBattleResultWindow::bExitf,this), 384, 505, "iok6432.def", SDLK_RETURN);
-	exit->borderColor = Colors::MetallicGold;
+	exit->borderColor = Colors::METALLIC_GOLD;
 	exit->borderEnabled = true;
 
 	if(br.winner==0) //attacker won

+ 2 - 2
client/CCastleInterface.cpp

@@ -1392,12 +1392,12 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin
 	{	//normal window
 		buy = new CAdventureMapButton(boost::str(boost::format(CGI->generaltexth->allTexts[595]) % building->Name()),
 		          "", boost::bind(&CBuildWindow::buyFunc,this), 45, 446,"IBUY30", SDLK_RETURN);
-		buy->borderColor = Colors::MetallicGold;
+		buy->borderColor = Colors::METALLIC_GOLD;
 		buy->borderEnabled = true;
 		
 		cancel = new CAdventureMapButton(boost::str(boost::format(CGI->generaltexth->allTexts[596]) % building->Name()),
 		             "", boost::bind(&CBuildWindow::close,this), 290, 445, "ICANCEL", SDLK_ESCAPE);
-		cancel->borderColor = Colors::MetallicGold;
+		cancel->borderColor = Colors::METALLIC_GOLD;
 		cancel->borderEnabled = true;
 		buy->block(state!=7 || LOCPLINT->playerID != town->tempOwner);
 	}

+ 1 - 1
client/CCreatureWindow.cpp

@@ -556,7 +556,7 @@ void CCreatureWindow::showAll(SDL_Surface * to)
 	if (type == COMMANDER_LEVEL_UP && upgradeOptions[selectedOption] >= 100) //add frame to selected skill
 	{
 		int index = selectedOption - selectableSkills.size(); //this is screwed
-		CSDL_Ext::drawBorder(to, Rect::around(selectableBonuses[index]->pos), int3(Colors::MetallicGold.r, Colors::MetallicGold.g, Colors::MetallicGold.b)); 
+		CSDL_Ext::drawBorder(to, Rect::around(selectableBonuses[index]->pos), int3(Colors::METALLIC_GOLD.r, Colors::METALLIC_GOLD.g, Colors::METALLIC_GOLD.b)); 
 	}
 }
 

+ 161 - 59
client/CPreGame.cpp

@@ -68,8 +68,15 @@ ISelectionScreenInfo *SEL;
 
 static int playerColor; //if more than one player - applies to the first
 
-static std::string selectedName; //set when game is started/loaded
-
+/**
+ * Stores the current name of the savegame.
+ *
+ * TODO better solution for auto-selection when saving already saved games.
+ * -> CSelectionScreen should be divided into CLoadGameScreen, CSaveGameScreen,...
+ * The name of the savegame can then be stored non-statically in CGameState and
+ * passed separately to CSaveGameScreen.
+ */
+static std::string saveGameName;
 
 struct EvilHlpStruct
 {
@@ -137,16 +144,17 @@ void setPlayer(PlayerSettings &pset, TPlayerColor player, const std::map<TPlayer
 void updateStartInfo(std::string filename, StartInfo & sInfo, const CMapHeader * mapHeader, const std::map<TPlayerColor, std::string> &playerNames)
 {
 	sInfo.playerInfos.clear();
-	if(!filename.size())
+	if(!mapHeader)
+	{
 		return;
+	}
 
-	/*sInfo.playerInfos.resize(to->playerAmnt);*/
 	sInfo.mapname = filename;
 	playerColor = -1;
 
 	auto namesIt = playerNames.cbegin();
 
-	for (int i = 0; i < GameConstants::PLAYER_LIMIT; i++)
+	for (int i = 0; i < mapHeader->players.size(); i++)
 	{
 		const PlayerInfo &pinfo = mapHeader->players[i];
 
@@ -597,6 +605,7 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
 		opt->recActions = DISPOSE;
 
 		randMapTab = new RandomMapTab();
+		randMapTab->getMapInfoChanged() += bind(&CSelectionScreen::changeSelection, this, _1);
 		randMapTab->recActions = DISPOSE;
 	}
 	sel = new SelectionTab(screenType, bind(&CSelectionScreen::changeSelection, this, _1), multiPlayer); //scenario selection tab
@@ -608,7 +617,12 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
 		{
 			card->difficulty->onChange = bind(&CSelectionScreen::difficultyChange, this, _1);
 			card->difficulty->select(1, 0);
-			CAdventureMapButton *select = new CAdventureMapButton(CGI->generaltexth->zelp[45], bind(&CSelectionScreen::toggleTab, this, sel), 411, 80, "GSPBUTT.DEF", SDLK_s);
+			CAdventureMapButton * select = new CAdventureMapButton(CGI->generaltexth->zelp[45], 0, 411, 80, "GSPBUTT.DEF", SDLK_s);
+			select->callback = [&]()
+			{
+				toggleTab(sel);
+				changeSelection(sel->getSelectedMapInfo());
+			};
 			select->addTextOverlay(CGI->generaltexth->allTexts[500], FONT_SMALL);
 
 			CAdventureMapButton *opts = new CAdventureMapButton(CGI->generaltexth->zelp[46], bind(&CSelectionScreen::toggleTab, this, opt), 411, 510, "GSPBUTT.DEF", SDLK_a);
@@ -618,7 +632,11 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
 			randomBtn->addTextOverlay(CGI->generaltexth->allTexts[740], FONT_SMALL);
 			if(settings["general"]["enableRMG"].Bool())
 			{
-				randomBtn->callback = bind(&CSelectionScreen::toggleTab, this, randMapTab);
+				randomBtn->callback = [&]()
+				{
+					toggleTab(randMapTab);
+					changeSelection(&randMapTab->getMapInfo());
+				};
 			}
 
 			start  = new CAdventureMapButton(CGI->generaltexth->zelp[103], bind(&CSelectionScreen::startGame, this), 411, 535, "SCNRBEG.DEF", SDLK_b);
@@ -766,7 +784,7 @@ void CSelectionScreen::toggleTab(CIntObject *tab)
 	GH.totalRedraw();
 }
 
-void CSelectionScreen::changeSelection( const CMapInfo *to )
+void CSelectionScreen::changeSelection(const CMapInfo * to)
 {
 	if(multiPlayer == CMenuScreen::MULTI_NETWORK_GUEST)
 	{
@@ -781,6 +799,19 @@ void CSelectionScreen::changeSelection( const CMapInfo *to )
 	if(screenType != CMenuScreen::campaignList)
 	{
 		updateStartInfo(to ? to->fileURI : "", sInfo, to ? to->mapHeader.get() : NULL);
+
+		if(screenType == CMenuScreen::newGame)
+		{
+			sInfo.createRandomMap = to->isRandomMap;
+			if(to->isRandomMap)
+			{
+				sInfo.mapGenOptions = std::shared_ptr<CMapGenOptions>(new CMapGenOptions(randMapTab->getMapGenOptions()));
+			}
+			else
+			{
+				sInfo.mapGenOptions = nullptr;
+			}
+		}
 	}
 	card->changeSelection(to);
 	if(screenType != CMenuScreen::campaignList)
@@ -837,11 +868,19 @@ void CSelectionScreen::startGame()
 		if(!current)
 			return;
 
-		selectedName = sInfo.mapname;
-		StartInfo *si = new StartInfo(sInfo);
+		saveGameName.clear();
+		if(screenType == CMenuScreen::loadGame)
+		{
+			saveGameName = sInfo.mapname;
+		}
+		if(sInfo.createRandomMap)
+		{
+			// Random map generation fails for now, so don't start game...
+			return;
+		}
+
+		StartInfo * si = new StartInfo(sInfo);
 		CGP->removeFromGui();
-		//SEL->current = NULL;
-		//curOpts = NULL;
 		::startGame(si);
 	}
 	else
@@ -849,13 +888,13 @@ void CSelectionScreen::startGame()
 		if(!(sel && sel->txt && sel->txt->text.size()))
 			return;
 
-		selectedName = "Saves/" + sel->txt->text;
+		saveGameName = "Saves/" + sel->txt->text;
 
 		CFunctionList<void()> overWrite;
-		overWrite += boost::bind(&CCallback::save, LOCPLINT->cb, selectedName);
+		overWrite += boost::bind(&CCallback::save, LOCPLINT->cb, saveGameName);
 		overWrite += bind(&CGuiHandler::popIntTotally, &GH, this);
 
-		if(CResourceHandler::get()->existsResource(ResourceID(selectedName, EResType::LIB_SAVEGAME)))
+		if(CResourceHandler::get()->existsResource(ResourceID(saveGameName, EResType::LIB_SAVEGAME)))
 		{
 			std::string hlp = CGI->generaltexth->allTexts[493]; //%s exists. Overwrite?
 			boost::algorithm::replace_first(hlp, "%s", sel->txt->text);
@@ -1228,12 +1267,13 @@ SelectionTab::SelectionTab(CMenuScreen::EState Type, const boost::function<void(
 		select(0);
 		break;
 	case CMenuScreen::saveGame:;
-		if(selectedName.size())
+		if(saveGameName.empty())
 		{
-			if(selectedName[2] == 'M') //name starts with ./Maps instead of ./Games => there was nothing to select
-				txt->setTxt("NEWGAME");
-			else
-				selectFName(selectedName);
+			txt->setTxt("NEWGAME");
+		}
+		else
+		{
+			selectFName(saveGameName);
 		}
 	}
 }
@@ -1541,6 +1581,11 @@ void SelectionTab::selectFName( std::string fname )
 	selectAbs(0);
 }
 
+const CMapInfo * SelectionTab::getSelectedMapInfo() const
+{
+	return curItems.empty() ? nullptr : curItems[selectionPos];
+}
+
 RandomMapTab::RandomMapTab()
 {
 	OBJ_CONSTRUCTION;
@@ -1556,16 +1601,17 @@ RandomMapTab::RandomMapTab()
 	mapSizeBtnGroup->onChange = [&](int btnId)
 	{
 		const std::vector<int> mapSizeVal = boost::assign::list_of(36)(72)(108)(144); // Map sizes in this order: S, M, L, XL
-		options.setWidth(mapSizeVal[btnId]);
-		options.setHeight(mapSizeVal[btnId]);
+		mapGenOptions.setWidth(mapSizeVal[btnId]);
+		mapGenOptions.setHeight(mapSizeVal[btnId]);
+		updateMapInfo();
 	};
 
 	// Two levels
 	twoLevelsBtn = new CHighlightableButton(0, 0, std::map<int,std::string>(),
 		CGI->generaltexth->zelp[202].second, false, "RANUNDR", nullptr, 346, 81);
-	twoLevelsBtn->callback = [&]() { options.setHasTwoLevels(true); };
-	twoLevelsBtn->callback2 = [&]() { options.setHasTwoLevels(false); };
 	twoLevelsBtn->select(true);
+	twoLevelsBtn->callback = [&]() { mapGenOptions.setHasTwoLevels(true); updateMapInfo(); };
+	twoLevelsBtn->callback2 = [&]() { mapGenOptions.setHasTwoLevels(false); updateMapInfo(); };
 
 	// Create number defs list
 	std::vector<std::string> numberDefs;
@@ -1583,10 +1629,11 @@ RandomMapTab::RandomMapTab()
 	addButtonsWithRandToGroup(playersCntGroup, numberDefs, 1, 8, NUMBERS_WIDTH, 204, 212);
 	playersCntGroup->onChange = [&](int btnId)
 	{
-		options.setPlayersCnt(btnId);
+		mapGenOptions.setPlayersCnt(btnId);
 		deactivateButtonsFrom(teamsCntGroup, btnId);
 		deactivateButtonsFrom(compOnlyPlayersCntGroup, 8 - btnId + 1);
 		validatePlayersCnt(btnId);
+		updateMapInfo();
 	};
 
 	// Amount of teams
@@ -1596,7 +1643,8 @@ RandomMapTab::RandomMapTab()
 	addButtonsWithRandToGroup(teamsCntGroup, numberDefs, 0, 7, NUMBERS_WIDTH, 214, 222);
 	teamsCntGroup->onChange = [&](int btnId)
 	{
-		options.setTeamsCnt(btnId);
+		mapGenOptions.setTeamsCnt(btnId);
+		updateMapInfo();
 	};
 
 	// Computer only players
@@ -1604,11 +1652,13 @@ RandomMapTab::RandomMapTab()
 	compOnlyPlayersCntGroup->pos.y = 285;
 	compOnlyPlayersCntGroup->pos.x = BTNS_GROUP_LEFT_MARGIN;
 	addButtonsWithRandToGroup(compOnlyPlayersCntGroup, numberDefs, 0, 7, NUMBERS_WIDTH, 224, 232);
+	compOnlyPlayersCntGroup->select(0, true);
 	compOnlyPlayersCntGroup->onChange = [&](int btnId)
 	{
-		options.setCompOnlyPlayersCnt(btnId);
+		mapGenOptions.setCompOnlyPlayersCnt(btnId);
 		deactivateButtonsFrom(compOnlyTeamsCntGroup, btnId);
 		validateCompOnlyPlayersCnt(btnId);
+		updateMapInfo();
 	};
 
 	// Computer only teams
@@ -1616,9 +1666,11 @@ RandomMapTab::RandomMapTab()
 	compOnlyTeamsCntGroup->pos.y = 351;
 	compOnlyTeamsCntGroup->pos.x = BTNS_GROUP_LEFT_MARGIN;
 	addButtonsWithRandToGroup(compOnlyTeamsCntGroup, numberDefs, 0, 6, NUMBERS_WIDTH, 234, 241);
+	deactivateButtonsFrom(compOnlyTeamsCntGroup, 0);
 	compOnlyTeamsCntGroup->onChange = [&](int btnId)
 	{
-		options.setCompOnlyTeamsCnt(btnId);
+		mapGenOptions.setCompOnlyTeamsCnt(btnId);
+		updateMapInfo();
 	};
 
 	const int WIDE_BTN_WIDTH = 85;
@@ -1630,7 +1682,7 @@ RandomMapTab::RandomMapTab()
 	addButtonsWithRandToGroup(waterContentGroup, waterContentBtns, 0, 2, WIDE_BTN_WIDTH, 243, 246);
 	waterContentGroup->onChange = [&](int btnId)
 	{
-		options.setWaterContent(static_cast<EWaterContent::EWaterContent>(btnId));
+		mapGenOptions.setWaterContent(static_cast<EWaterContent::EWaterContent>(btnId));
 	};
 
 	// Monster strength
@@ -1641,37 +1693,39 @@ RandomMapTab::RandomMapTab()
 	addButtonsWithRandToGroup(monsterStrengthGroup, monsterStrengthBtns, 0, 2, WIDE_BTN_WIDTH, 248, 251);
 	monsterStrengthGroup->onChange = [&](int btnId)
 	{
-		options.setMonsterStrength(static_cast<EMonsterStrength::EMonsterStrength>(btnId));
+		mapGenOptions.setMonsterStrength(static_cast<EMonsterStrength::EMonsterStrength>(btnId));
 	};
 
 	// Show random maps btn
 	showRandMaps = new CAdventureMapButton("", CGI->generaltexth->zelp[252].second, 0, 54, 535, "RANSHOW");
+
+	// Initialize map info object
+	mapInfo.isRandomMap = true;
+	shared_ptr<CMapHeader> mapHeader(new CMapHeader());
+	mapHeader->version = EMapFormat::SOD;
+	mapHeader->name = CGI->generaltexth->allTexts[740];
+	mapHeader->description = CGI->generaltexth->allTexts[741];
+	mapHeader->difficulty = 1; // Normal
+	mapInfo.mapHeader = mapHeader;
+	updateMapInfo();
 }
 
 void RandomMapTab::addButtonsWithRandToGroup(CHighlightableButtonsGroup * group, const std::vector<std::string> & defs, int nStart, int nEnd, int btnWidth, int helpStartIndex, int helpRandIndex) const
 {
 	addButtonsToGroup(group, defs, nStart, nEnd, btnWidth, helpStartIndex);
 
-	// Add rand button and select rand if help text index is given
-	const std::string randomDef = "RANRAND";
-	if (helpRandIndex != -1)
-	{
-		// Buttons are relative to button group, TODO better solution?
-		SObjectConstruction obj__i(group);
-
-		group->addButton(new CHighlightableButton("", CGI->generaltexth->zelp[helpRandIndex].second, 0, 256, 0, randomDef, -1));
-		group->select(-1, true);
-	}
+	// Buttons are relative to button group, TODO better solution?
+	SObjectConstruction obj__i(group);
+	const std::string RANDOM_DEF = "RANRAND";
+	group->addButton(new CHighlightableButton("", CGI->generaltexth->zelp[helpRandIndex].second, 0, 256, 0, RANDOM_DEF, CMapGenOptions::RANDOM_SIZE));
+	group->select(CMapGenOptions::RANDOM_SIZE, true);
 }
 
 void RandomMapTab::addButtonsToGroup(CHighlightableButtonsGroup * group, const std::vector<std::string> & defs, int nStart, int nEnd, int btnWidth, int helpStartIndex) const
 {
 	// Buttons are relative to button group, TODO better solution?
 	SObjectConstruction obj__i(group);
-
-	const int cnt = nEnd - nStart + 1;
-
-	// Buttons
+	int cnt = nEnd - nStart + 1;
 	for(int i = 0; i < cnt; ++i)
 	{
 		group->addButton(new CHighlightableButton("", CGI->generaltexth->zelp[helpStartIndex + i].second, 0, i * btnWidth, 0, defs[i + nStart], i + nStart));
@@ -1682,7 +1736,7 @@ void RandomMapTab::deactivateButtonsFrom(CHighlightableButtonsGroup * group, int
 {
 	BOOST_FOREACH(CHighlightableButton * btn, group->buttons)
 	{
-		if(startId == -1 || btn->ID < startId)
+		if(startId == CMapGenOptions::RANDOM_SIZE || btn->ID < startId)
 		{
 			if(btn->isBlocked())
 			{
@@ -1701,36 +1755,36 @@ void RandomMapTab::deactivateButtonsFrom(CHighlightableButtonsGroup * group, int
 
 void RandomMapTab::validatePlayersCnt(int playersCnt)
 {
-	if(playersCnt == -1)
+	if(playersCnt == CMapGenOptions::RANDOM_SIZE)
 	{
 		return;
 	}
 
-	if(options.getTeamsCnt() >= playersCnt)
+	if(mapGenOptions.getTeamsCnt() >= playersCnt)
 	{
-		options.setTeamsCnt(playersCnt - 1);
-		teamsCntGroup->select(options.getTeamsCnt(), true);
+		mapGenOptions.setTeamsCnt(playersCnt - 1);
+		teamsCntGroup->select(mapGenOptions.getTeamsCnt(), true);
 	}
-	if(options.getCompOnlyPlayersCnt() > 8 - playersCnt)
+	if(mapGenOptions.getCompOnlyPlayersCnt() > 8 - playersCnt)
 	{
-		options.setCompOnlyPlayersCnt(8 - playersCnt);
-		compOnlyPlayersCntGroup->select(options.getCompOnlyPlayersCnt(), true);
+		mapGenOptions.setCompOnlyPlayersCnt(8 - playersCnt);
+		compOnlyPlayersCntGroup->select(mapGenOptions.getCompOnlyPlayersCnt(), true);
 	}
 
-	validateCompOnlyPlayersCnt(options.getCompOnlyPlayersCnt());
+	validateCompOnlyPlayersCnt(mapGenOptions.getCompOnlyPlayersCnt());
 }
 
 void RandomMapTab::validateCompOnlyPlayersCnt(int compOnlyPlayersCnt)
 {
-	if(compOnlyPlayersCnt == -1)
+	if(compOnlyPlayersCnt == CMapGenOptions::RANDOM_SIZE)
 	{
 		return;
 	}
 
-	if(options.getCompOnlyTeamsCnt() >= compOnlyPlayersCnt)
+	if(mapGenOptions.getCompOnlyTeamsCnt() >= compOnlyPlayersCnt)
 	{
-		options.setCompOnlyTeamsCnt(compOnlyPlayersCnt - 1);
-		compOnlyTeamsCntGroup->select(options.getCompOnlyTeamsCnt(), true);
+		mapGenOptions.setCompOnlyTeamsCnt(compOnlyPlayersCnt - 1);
+		compOnlyTeamsCntGroup->select(mapGenOptions.getCompOnlyTeamsCnt(), true);
 	}
 }
 
@@ -1764,6 +1818,53 @@ void RandomMapTab::showAll(SDL_Surface * to)
 	printAtLoc(CGI->generaltexth->allTexts[758], 68, 465, FONT_SMALL, Colors::WHITE, to);
 }
 
+void RandomMapTab::updateMapInfo()
+{
+	mapInfo.mapHeader->height = mapGenOptions.getHeight();
+	mapInfo.mapHeader->width = mapGenOptions.getWidth();
+	mapInfo.mapHeader->twoLevel = mapGenOptions.getHasTwoLevels();
+
+	// Generate player information
+	mapInfo.mapHeader->players.clear();
+	int playersToGen = (mapGenOptions.getPlayersCnt() == CMapGenOptions::RANDOM_SIZE
+		|| mapGenOptions.getCompOnlyPlayersCnt() == CMapGenOptions::RANDOM_SIZE)
+			? 8 : mapGenOptions.getPlayersCnt() + mapGenOptions.getCompOnlyPlayersCnt();
+	mapInfo.mapHeader->howManyTeams = playersToGen;
+
+	for(int i = 0; i < playersToGen; ++i)
+	{
+		PlayerInfo player;
+		player.canComputerPlay = true;
+		if(i >= mapGenOptions.getPlayersCnt() && mapGenOptions.getPlayersCnt() != CMapGenOptions::RANDOM_SIZE)
+		{
+			player.canHumanPlay = false;
+		}
+		else
+		{
+			player.canHumanPlay = true;
+		}
+		player.team = i;
+		mapInfo.mapHeader->players.push_back(player);
+	}
+
+	mapInfoChanged(&mapInfo);
+}
+
+CFunctionList<void(const CMapInfo *)> & RandomMapTab::getMapInfoChanged()
+{
+	return mapInfoChanged;
+}
+
+const CMapInfo & RandomMapTab::getMapInfo() const
+{
+	return mapInfo;
+}
+
+const CMapGenOptions & RandomMapTab::getMapGenOptions() const
+{
+	return mapGenOptions;
+}
+
 CChatBox::CChatBox(const Rect &rect)
 {
 	OBJ_CONSTRUCTION;
@@ -3435,7 +3536,8 @@ void CBonusSelection::updateBonusSelection()
 			CAnimation * anim = new CAnimation();
 			anim->setCustom(picName, 0);
 			bonusButton->setImage(anim);
-			bonusButton->borderColor = Colors::Maize; // yellow border
+			const SDL_Color brightYellow = { 242, 226, 110, 0 };
+			bonusButton->borderColor = brightYellow;
 			bonuses->addButton(bonusButton);
 		}
 }
@@ -3784,7 +3886,7 @@ void StartWithCurrentSettings::apply(CSelectionScreen *selScreen)
 
 	selScreen->serv = NULL; //hide it so it won't be deleted
 	vstd::clear_pointer(selScreen->serverHandlingThread); //detach us
-	selectedName = selScreen->sInfo.mapname;
+	saveGameName.clear();
 
 	CGP->removeFromGui();
 

+ 37 - 1
client/CPreGame.h

@@ -175,6 +175,7 @@ public:
 	void printMaps(SDL_Surface *to);
 	int getLine();
 	void selectFName(std::string fname);
+	const CMapInfo * getSelectedMapInfo() const;
 
 	void showAll(SDL_Surface * to);
 	void clickLeft(tribool down, bool previousState);
@@ -270,6 +271,34 @@ public:
      */
     void showAll(SDL_Surface * to);
 
+	/**
+	 * Updates the map info object and fires the associated callback method.
+	 */
+	void updateMapInfo();
+
+	/**
+	 * Gets the map info changed callback method list object. This event
+	 * occurs when the updateMapInfo method has been called or the options
+	 * of this tab have been changed.
+	 *
+	 * @return the map info changed callback method list object
+	 */
+	CFunctionList<void (const CMapInfo *)> & getMapInfoChanged();
+
+	/**
+	 * Gets the created map info object.
+	 *
+	 * @return the created map info object
+	 */
+	const CMapInfo & getMapInfo() const;
+
+	/**
+	 * Gets the map generation options.
+	 *
+	 * @return the map generation options
+	 */
+	const CMapGenOptions & getMapGenOptions() const;
+
 private:
     /**
      * Adds buttons specified by the defs list to the given buttons group.
@@ -347,10 +376,17 @@ private:
     /** the monster strength group */
     CHighlightableButtonsGroup * monsterStrengthGroup;
 
+	/** show previously created random maps button */
     CAdventureMapButton * showRandMaps;
 
     /** the map options selected by the user */
-    CMapGenOptions options;
+	CMapGenOptions mapGenOptions;
+
+	/** map info object describing a randomly created map */
+	CMapInfo mapInfo;
+
+	/** callback method which gets called when the random options have been changed */
+	CFunctionList<void(const CMapInfo *)> mapInfoChanged;
 };
 
 /// Interface for selecting a map.

+ 1 - 1
client/CQuestLog.cpp

@@ -160,7 +160,7 @@ void CQuestLog::showAll(SDL_Surface * to)
 	}
 	if (labels.size() && labels[questIndex]->active)
 	{
-		CSDL_Ext::drawBorder(to, Rect::around(labels[questIndex]->pos), int3(Colors::MetallicGold.r, Colors::MetallicGold.g, Colors::MetallicGold.b));
+		CSDL_Ext::drawBorder(to, Rect::around(labels[questIndex]->pos), int3(Colors::METALLIC_GOLD.r, Colors::METALLIC_GOLD.g, Colors::METALLIC_GOLD.b));
 	}
 	description->show(to);
 	minimap->update();

+ 2 - 2
client/Client.cpp

@@ -250,7 +250,7 @@ void CClient::loadGame( const std::string & fname )
 
 		const_cast<CGameInfo*>(CGI)->state = gs;
 		const_cast<CGameInfo*>(CGI)->mh->map = gs->map;
-		pathInfo = new CPathsInfo(int3(gs->map->width, gs->map->height, gs->map->twoLevel+1));
+		pathInfo = new CPathsInfo(int3(gs->map->width, gs->map->height, gs->map->twoLevel ? 2 : 1));
 		CGI->mh->init();
 
 		tlog0 <<"Initing maphandler: "<<tmh.getDiff()<<std::endl;
@@ -351,7 +351,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 		CGI->mh->map = gs->map;
 		tlog0 <<"Creating mapHandler: "<<tmh.getDiff()<<std::endl;
 		CGI->mh->init();
-		pathInfo = new CPathsInfo(int3(gs->map->width, gs->map->height, gs->map->twoLevel+1));
+		pathInfo = new CPathsInfo(int3(gs->map->width, gs->map->height, gs->map->twoLevel ? 2 : 1));
 		tlog0 <<"Initializing mapHandler (together): "<<tmh.getDiff()<<std::endl;
 	}
 

+ 2 - 2
client/GUIClasses.cpp

@@ -602,7 +602,7 @@ CInfoWindow::CInfoWindow(std::string Text, int player, const TCompsInfo &comps,
 	for(int i=0;i<Buttons.size();i++)
 	{
 		CAdventureMapButton *button = new CAdventureMapButton("","",boost::bind(&CInfoWindow::close,this),0,0,Buttons[i].first);
-		button->borderColor = Colors::MetallicGold;
+		button->borderColor = Colors::METALLIC_GOLD;
 		button->borderEnabled = true;
 		button->callback.add(Buttons[i].second); //each button will close the window apart from call-defined actions
 		buttons.push_back(button);
@@ -5026,7 +5026,7 @@ CPuzzleWindow::CPuzzleWindow(const int3 &GrailPos, double discoveredRatio):
 
 	quitb = new CAdventureMapButton(CGI->generaltexth->allTexts[599], "", boost::bind(&CPuzzleWindow::close, this), 670, 538, "IOK6432.DEF", SDLK_RETURN);
 	quitb->assignedKeys.insert(SDLK_ESCAPE);
-	quitb->borderColor = Colors::MetallicGold;
+	quitb->borderColor = Colors::METALLIC_GOLD;
 	quitb->borderEnabled = true;
 
 	new CPicture("PUZZLOGO", 607, 3);

+ 8 - 3
client/UIFramework/CGuiHandler.cpp

@@ -375,7 +375,7 @@ void CGuiHandler::run()
 	inGuiThread.reset(new bool(true));
 	try
 	{
-		if (settings["video"]["fullscreen"].Bool())
+		if(settings["video"]["fullscreen"].Bool())
 			CCS->curh->centerCursor();
 
 		mainFPSmng->init(); // resets internal clock, needed for FPS manager
@@ -386,7 +386,12 @@ void CGuiHandler::run()
 
 			mainFPSmng->framerateDelay(); // holds a constant FPS
 		}
-	} HANDLE_EXCEPTION
+	}
+	catch(const std::exception & ex)
+	{
+		tlog1 << "Error: " << ex.what() << std::endl;
+		exit(EXIT_FAILURE);
+	}
 }
 
 CGuiHandler::CGuiHandler()
@@ -521,4 +526,4 @@ void CFramerateManager::framerateDelay()
 	//recalculate timeElapsed for external calls via getElapsed()
 	timeElapsed = currentTicks - lastticks;
 	lastticks = SDL_GetTicks();
-}
+}

+ 3 - 20
client/UIFramework/SDL_Extensions.cpp

@@ -8,26 +8,9 @@
 #include "../CDefHandler.h"
 #include "../Graphics.h"
 
-/*
- * SDL_Extensions.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
- *
- */
-
-SDL_Color Colors::createColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a /*= 0*/)
-{
-	SDL_Color temp = {r, g, b, a};
-	return temp;
-}
-
-const SDL_Color Colors::YELLOW = createColor(229, 215, 123, 0);
-const SDL_Color Colors::WHITE = createColor(255, 243, 222, 0);
-const SDL_Color Colors::MetallicGold = createColor(173, 142, 66);
-const SDL_Color Colors::Maize = createColor(242, 226, 110);
+const SDL_Color Colors::YELLOW = { 229, 215, 123, 0 };
+const SDL_Color Colors::WHITE = { 255, 243, 222, 0 };
+const SDL_Color Colors::METALLIC_GOLD = { 173, 142, 66, 0 };
 
 SDL_Surface * CSDL_Ext::newSurface(int w, int h, SDL_Surface * mod) //creates new surface, with flags/format same as in surface given
 {

+ 2 - 15
client/UIFramework/SDL_Extensions.h

@@ -16,7 +16,6 @@
  *
  */
 
-
 //A macro to force inlining some of our functions. Compiler (at least MSVC) is not so smart here-> without that displaying is MUCH slower
 #ifdef _MSC_VER
 	#define STRONG_INLINE __forceinline
@@ -50,20 +49,8 @@ public:
 	/** the standard h3 white color */
 	static const SDL_Color WHITE;
 
-	static const SDL_Color MetallicGold;
-	static const SDL_Color Maize;
-
-private:
-	/**
-	 * Creates a SDL_Color object.
-	 *
-	 * @param r the red value ranging from 0 to 255
-	 * @param g the green value ranging from 0 to 255
-	 * @param b the blue value ranging from 0 to 255
-	 * @param a the alpha value ranging from 0(opaque) to 255(transparent)
-	 * @return the created SDL_Color object
-	 */
-	static SDL_Color createColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a = 0);
+	/** the metallic gold color used mostly as a border around buttons */
+	static const SDL_Color METALLIC_GOLD;
 };
 
 //MSVC gives an error when calling abs with ui64 -> we add template that will match calls with unsigned arg and return it

+ 1 - 1
client/mapHandler.cpp

@@ -349,7 +349,7 @@ void CMapHandler::init()
 	//sizes of terrain
 	sizes.x = map->width;
 	sizes.y = map->height;
-	sizes.z = map->twoLevel+1;
+	sizes.z = map->twoLevel ? 2 : 1;
 
 	// Total number of visible tiles. Subtract the center tile, then
 	// compute the number of tiles on each side, and reassemble.

+ 1 - 1
lib/CGameInterface.cpp

@@ -49,7 +49,7 @@ rett * createAny(std::string dllname, std::string methodName)
 	if (!dll)
 	{
 		tlog1 << "Cannot open dynamic library ("<<dllname<<"). Throwing..."<<std::endl;
-		throw new std::string("Cannot open dynamic library");
+		throw std::runtime_error("Cannot open dynamic library");
 	}
 
 	getName(temp);

+ 16 - 5
lib/CGameState.cpp

@@ -25,6 +25,7 @@
 #include "JsonNode.h"
 #include "Filesystem/CResourceLoader.h"
 #include "GameConstants.h"
+#include "RMG/CMapGenOptions.h"
 
 DLL_LINKAGE boost::rand48 ran;
 class CGObjectInstance;
@@ -863,8 +864,18 @@ void CGameState::init(StartInfo * si)
 	switch(scenarioOps->mode)
 	{
 	case StartInfo::NEW_GAME:
-		tlog0 << "Open map file: " << scenarioOps->mapname << std::endl;
-		map = CMapService::loadMap(scenarioOps->mapname).release();
+		{
+			if(scenarioOps->createRandomMap)
+			{
+				tlog0 << "Create random map." << std::endl;
+				//TODO random map
+			}
+			else
+			{
+				tlog0 << "Open map file: " << scenarioOps->mapname << std::endl;
+				map = CMapService::loadMap(scenarioOps->mapname).release();
+			}
+		}
 		break;
 	case StartInfo::CAMPAIGN:
 		{
@@ -920,7 +931,7 @@ void CGameState::init(StartInfo * si)
 		{
 			for (int j = 0; j < map->height ; j++)
 			{
-				for (int k = 0; k <= map->twoLevel ; k++)
+				for (int k = 0; k < (map->twoLevel ? 2 : 1); k++)
 				{
 					const TerrainTile &t = map->terrain[i][j][k];
 					if(!t.blocked
@@ -1266,11 +1277,11 @@ void CGameState::init(StartInfo * si)
 
 		for(int g=-0; g<map->width; ++g)
 			for(int h=0; h<map->height; ++h)
-				k->second.fogOfWarMap[g][h].resize(map->twoLevel+1, 0);
+				k->second.fogOfWarMap[g][h].resize(map->twoLevel ? 2 : 1, 0);
 
 		for(int g=0; g<map->width; ++g)
 			for(int h=0; h<map->height; ++h)
-				for(int v=0; v<map->twoLevel+1; ++v)
+				for(int v = 0; v < (map->twoLevel ? 2 : 1); ++v)
 					k->second.fogOfWarMap[g][h][v] = 0;
 
 		BOOST_FOREACH(CGObjectInstance *obj, map->objects)

+ 14 - 0
lib/CHeroHandler.cpp

@@ -323,6 +323,20 @@ void CHeroHandler::loadTerrains()
 		terrCosts.push_back(config[name].Float());
 }
 
+std::vector<ui8> CHeroHandler::getDefaultAllowedHeroes() const
+{
+	// Look Data/HOTRAITS.txt for reference
+	std::vector<ui8> allowedHeroes;
+	allowedHeroes.resize(156, 1);
+	for(int i = 145; i < 156; ++i)
+	{
+		allowedHeroes[i] = 0;
+	}
+	allowedHeroes[4] = 0;
+	allowedHeroes[25] = 0;
+	return allowedHeroes;
+}
+
 CHero::CHero()
 {
 	startingSpell = -1;

+ 11 - 0
lib/CHeroHandler.h

@@ -141,6 +141,17 @@ public:
 	CHeroHandler(); //c-tor
 	~CHeroHandler(); //d-tor
 
+	/**
+	 * Gets a list of default allowed heroes.
+	 *
+	 * TODO Proposal for hero modding: Replace hero id with a unique machine readable hero name and
+	 * create a JSON config file or merge it with a existing config file which describes which heroes can be used for
+	 * random map generation / map editor(default map settings). (Gelu, ... should be excluded)
+	 *
+	 * @return a list of allowed heroes, the index is the hero id and the value either 0 for not allowed and 1 for allowed
+	 */
+	std::vector<ui8> getDefaultAllowedHeroes() const;
+
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & heroClasses & heroes & expPerLevel & ballistics & terrCosts;

+ 10 - 0
lib/CTownHandler.cpp

@@ -522,3 +522,13 @@ void CTownHandler::load()
 	}
 	load(buildingsConf);
 }
+
+std::set<ui32> CTownHandler::getDefaultAllowedFactions() const
+{
+	std::set<ui32> allowedFactions;
+	for(int i = 0; i <= 8; ++i)
+	{
+		allowedFactions.insert(i);
+	}
+	return allowedFactions;
+}

+ 11 - 0
lib/CTownHandler.h

@@ -216,6 +216,17 @@ public:
 	/// and loads resulting structure to game using loadTowns method
 	void load();
 
+	/**
+	 * Gets a list of default allowed factions. OH3 factions are in the range of 0 to 8.
+	 *
+	 * TODO Proposal for town modding: Replace faction id with a unique machine readable town name
+	 * and create a JSON config file or merge it with other configs which describes which
+	 * towns can be used for random map generation / map editor(default map settings).
+	 *
+	 * @return a list of allowed factions, the index which is unique is the faction id
+	 */
+	std::set<ui32> getDefaultAllowedFactions() const;
+
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & towns & factions;

+ 3 - 2
lib/Connection.cpp

@@ -21,6 +21,7 @@
 #include "CTownHandler.h"
 #include "Map/CCampaignHandler.h"
 #include "NetPacks.h"
+#include "CDefObjInfoHandler.h"
 
 #include <boost/asio.hpp>
 
@@ -199,11 +200,11 @@ CConnection::~CConnection(void)
 
 template<class T>
 CConnection & CConnection::operator&(const T &t) {
-    throw new std::exception();
+	throw std::exception();
 //XXX this is temporaly ? solution to fix gcc (4.3.3, other?) compilation
 //    problem for more details contact [email protected] or [email protected]
 //    do not remove this exception it shoudnt be called
-    return *this;
+	return *this;
 }
 
 void CConnection::close()

+ 11 - 12
lib/Connection.h

@@ -1,5 +1,15 @@
-#pragma once
 
+/*
+ * Connection.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
 
 #include <typeinfo> //XXX this is in namespace std if you want w/o use typeinfo.h?
 
@@ -12,7 +22,6 @@
 #include <boost/type_traits/remove_pointer.hpp>
 #include <boost/type_traits/remove_const.hpp>
 
-
 #include <boost/variant.hpp>
 #include <boost/mpl/eval_if.hpp>
 #include <boost/mpl/equal_to.hpp>
@@ -39,16 +48,6 @@ struct CPack;
 extern DLL_LINKAGE LibClasses * VLC;
 namespace mpl = boost::mpl;
 
-/*
- * Connection.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
- *
- */
-
 namespace boost
 {
 	namespace asio

+ 3 - 5
lib/IGameCallback.cpp

@@ -116,9 +116,7 @@ void CPrivilagedInfoCallback::getAllTiles (boost::unordered_set<int3, ShashInt3>
 	std::vector<int> floors;
 	if(level == -1)
 	{
-		
-		for (int xd = 0; xd <= gs->map->width - 1; xd++)
-		for(int b=0; b<gs->map->twoLevel + 1; ++b) //if gs->map->twoLevel is false then false (0) + 1 is 1, if it's true (1) then we have 2
+		for(int b = 0; b < (gs->map->twoLevel ? 2 : 1); ++b)
 		{
 			floors.push_back(b);
 		}
@@ -144,7 +142,7 @@ void CPrivilagedInfoCallback::getAllTiles (boost::unordered_set<int3, ShashInt3>
 void CPrivilagedInfoCallback::getFreeTiles (std::vector<int3> &tiles) const
 {
 	std::vector<int> floors;
-	for (int b=0; b<gs->map->twoLevel + 1; ++b) //if gs->map->twoLevel is false then false (0) + 1 is 1, if it's true (1) then we have 2
+	for (int b = 0; b < (gs->map->twoLevel ? 2 : 1); ++b)
 	{
 		floors.push_back(b);
 	}
@@ -529,7 +527,7 @@ std::vector < const CGObjectInstance * > CGameInfoCallback::getFlaggableObjects(
 
 int3 CGameInfoCallback::getMapSize() const
 {
-	return int3(gs->map->width, gs->map->height, gs->map->twoLevel+1);
+	return int3(gs->map->width, gs->map->height, gs->map->twoLevel ? 2 : 1);
 }
 
 std::vector<const CGHeroInstance *> CGameInfoCallback::getAvailableHeroes(const CGObjectInstance * townOrTavern) const

+ 26 - 19
lib/Map/CMap.cpp

@@ -1,8 +1,9 @@
-#include "StdInc.h"
 #include "CMap.h"
 
-#include "../CObjectHandler.h"
 #include "../CArtHandler.h"
+#include "../VCMI_Lib.h"
+#include "../CTownHandler.h"
+#include "../CHeroHandler.h"
 #include "../CDefObjInfoHandler.h"
 
 SHeroName::SHeroName() : heroId(-1)
@@ -10,18 +11,15 @@ SHeroName::SHeroName() : heroId(-1)
 
 }
 
-PlayerInfo::PlayerInfo(): p7(0), p8(0), p9(0), powerPlaceholders(-1),
-	canHumanPlay(false), canComputerPlay(false),
-	aiTactic(EAiTactic::RANDOM), isFactionRandom(false), mainHeroPortrait(0), hasMainTown(false),
-	generateHeroAtMainTown(false), team(255), generateHero(false)
+PlayerInfo::PlayerInfo(): canHumanPlay(false), canComputerPlay(false),
+	aiTactic(EAiTactic::RANDOM), isFactionRandom(false), mainHeroPortrait(255), hasMainTown(true),
+	generateHeroAtMainTown(true), team(255), generateHero(false), p7(0), p8(0), p9(0), powerPlaceholders(-1)
 {
-
+	allowedFactions = VLC->townh->getDefaultAllowedFactions();
 }
 
 si8 PlayerInfo::defaultCastle() const
 {
-	assert(!allowedFactions.empty()); // impossible?
-
 	if(allowedFactions.size() == 1)
 	{
 		// only one faction is available - pick it
@@ -126,11 +124,10 @@ bool TerrainTile::isWater() const
 	return terType == ETerrainType::WATER;
 }
 
-CMapHeader::CMapHeader() : version(EMapFormat::INVALID), areAnyPlayers(false),
-	height(-1), width(-1), twoLevel(-1), difficulty(0), levelLimit(0),
-	howManyTeams(0)
+CMapHeader::CMapHeader() : version(EMapFormat::SOD), height(72), width(72),
+	twoLevel(true), difficulty(1), levelLimit(0), howManyTeams(0), areAnyPlayers(false)
 {
-
+	allowedHeroes = VLC->heroh->getDefaultAllowedHeroes();
 }
 
 CMapHeader::~CMapHeader()
@@ -225,9 +222,15 @@ CGHeroInstance * CMap::getHero(int heroID)
 
 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)
+	if(pos.x < 0 || pos.y < 0 || pos.z < 0 || pos.x >= width || pos.y >= height
+			|| pos.z > (twoLevel ? 1 : 0))
+	{
 		return false;
-	else return true;
+	}
+	else
+	{
+		return true;
+	}
 }
 
 TerrainTile & CMap::getTile( const int3 & tile )
@@ -245,9 +248,9 @@ bool CMap::isWaterTile(const int3 &pos) const
 	return isInTheMap(pos) && getTile(pos).terType == ETerrainType::WATER;
 }
 
-const CGObjectInstance *CMap::getObjectiveObjectFrom(int3 pos, bool lookForHero)
+const CGObjectInstance * CMap::getObjectiveObjectFrom(int3 pos, bool lookForHero)
 {
-	const std::vector <CGObjectInstance *> & objs = getTile(pos).visitableObjects;
+	const std::vector<CGObjectInstance *> & objs = getTile(pos).visitableObjects;
 	assert(objs.size());
 	if(objs.size() > 1 && lookForHero && objs.front()->ID != Obj::HERO)
 	{
@@ -261,19 +264,23 @@ const CGObjectInstance *CMap::getObjectiveObjectFrom(int3 pos, bool lookForHero)
 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 )
+void CMap::addNewArtifactInstance(CArtifactInstance * art)
 {
 	art->id = artInstances.size();
 	artInstances.push_back(art);
 }
 
-void CMap::eraseArtifactInstance(CArtifactInstance *art)
+void CMap::eraseArtifactInstance(CArtifactInstance * art)
 {
 	assert(artInstances[art->id] == art);
 	artInstances[art->id].dellNull();

+ 61 - 50
lib/Map/CMap.h

@@ -11,12 +11,10 @@
 
 #pragma once
 
-#ifndef _MSC_VER
-#include "../CObjectHandler.h"
-#include "../CDefObjInfoHandler.h"
-#endif
+#include "StdInc.h"
 
 #include "../ConstTransitivePtr.h"
+#include "../CObjectHandler.h"
 #include "../ResourceSet.h"
 #include "../int3.h"
 #include "../GameConstants.h"
@@ -96,57 +94,61 @@ struct DLL_LINKAGE PlayerInfo
 	 */
 	si8 defaultHero() const;
 
-	/** unknown, unused */
-	si32 p7;
-
-	/** TODO ? */
-	si32 p8;
-
-	/** TODO ? */
-	si32 p9;
-
-	/** TODO unused, q-ty of hero placeholders containing hero type, WARNING: powerPlaceholders sometimes gives false 0 (eg. even if there is one placeholder), maybe different meaning??? */
-	ui8 powerPlaceholders;
-
-	/** true if player can be played by a human */
+	/** True if the player can be played by a human. */
 	bool canHumanPlay;
 
-	/** true if player can be played by the computer */
+	/** True if th player can be played by the computer */
 	bool canComputerPlay;
 
-	/** defines the tactical setting of the AI */
+	/** Defines the tactical setting of the AI. The default value is EAiTactic::RANDOM. */
 	EAiTactic::EAiTactic aiTactic;
 
-	/** IDs of allowed factions */
+	/** A list of unique IDs of allowed factions. */
 	std::set<ui32> allowedFactions;
 
-	/** unused. is the faction random */
+	/** Unused. True if the faction should be chosen randomly. */
 	bool isFactionRandom;
 
-	/** specifies the ID of hero with chosen portrait; 255 if standard */
+	/** Specifies the ID of the main hero with chosen portrait. The default value is 255. */
 	ui32 mainHeroPortrait;
 
-	/** the name of the main hero */
+	/** The name of the main hero. */
 	std::string mainHeroName;
 
-	/** list of available heroes */
+	/** The list of renamed heroes. */
 	std::vector<SHeroName> heroesNames;
 
-	/** true if the player has a main town */
+	/** True if the player has a main town. The default value is true. */
 	bool hasMainTown;
 
-	/** true if the hero should be generated at the main town */
+	/** True if the main hero should be generated at the main town. The default value is true. */
 	bool generateHeroAtMainTown;
 
-	/** the position of the main town */
+	/** The position of the main town. */
 	int3 posOfMainTown;
 
-	/** the team id to which the player belongs to */
+	/** The team id to which the player belongs to. The default value is 255 representing that the player belongs to no team. */
 	ui8 team;
 
-	/** unused. true if a hero should be generated */
+	/** Unused. True if a hero should be generated. */
 	bool generateHero;
 
+	/** Unknown and unused. */
+	si32 p7;
+
+	/** TODO ? */
+	si32 p8;
+
+	/** TODO ? */
+	si32 p9;
+
+	/**
+	 * Unused. Count of hero placeholders containing hero type.
+	 * WARNING: powerPlaceholders sometimes gives false 0 (eg. even if there is one placeholder),
+	 * maybe different meaning ???
+	 */
+	ui8 powerPlaceholders;
+
 	/**
 	 * Serialize method.
 	 */
@@ -548,51 +550,60 @@ public:
 	 */
 	virtual ~CMapHeader();
 
-	/** the version of the map */
+	/** The version of the map. The default value is EMapFormat::SOD. */
 	EMapFormat::EMapFormat version;
 
-	/** unused. if there are any playable players on the map */
-	bool areAnyPlayers;
-
-	/** the height of the map */
+	/** The height of the map. The default value is 72. */
 	si32 height;
 
-	/** the width of the map */
+	/** The width of the map. The default value is 72. */
 	si32 width;
 
-	/** specifies if the map has two levels */
-	si32 twoLevel;
+	/** Specifies if the map has two levels. The default value is true. */
+	bool twoLevel;
 
-	/** the name of the map */
+	/** The name of the map. */
 	std::string name;
 
-	/** the description of the map */
+	/** The description of the map. */
 	std::string description;
 
-	/** specifies the difficulty of the map ranging from 0 easy to 4 impossible */
+	/**
+	 * Specifies the difficulty of the map ranging from 0 easy to 4 impossible.
+	 * The default value is 1 representing a normal map difficulty.
+	 */
 	ui8 difficulty;
 
-	/** specifies the maximum level to reach for a hero */
+	/**
+	 * Specifies the maximum level to reach for a hero. A value of 0 states that there is no
+	 * maximum level for heroes.
+	 */
 	ui8 levelLimit;
 
-	/** the loss condition */
+	/** Specifies the loss condition. The default value is lose all your towns and heroes. */
 	LossCondition lossCondition;
 
-	/** the victory condition */
+	/** Specifies the victory condition. The default value is defeat all enemies. */
 	VictoryCondition victoryCondition;
 
-	/** list of player information */
+	/** A list containing information about players. */
 	std::vector<PlayerInfo> players;
 
-	/** number of teams */
+	/** The number of teams. */
 	ui8 howManyTeams;
 
-	/** list of allowed heroes, index is hero id */
+	/**
+	 * A list of allowed heroes. The index is the hero id and the value is either 0 for not allowed or 1 for allowed.
+	 * The default value is a list of default allowed heroes. See CHeroHandler::getDefaultAllowedHeroes for more info.
+	 */
 	std::vector<ui8> allowedHeroes;
 
-	/** list of placeholded heroes, index is id of heroes types */
+	/** A list of placeholded heroes. The index is the id of a hero type. */
 	std::vector<ui16> placeholdedHeroes;
 
+	/** Unused. True if there are any playable players on the map. */
+	bool areAnyPlayers;
+
 	/**
 	 * Serialize method.
 	 */
@@ -778,7 +789,7 @@ public:
 			{
 				for(int j = 0; j < height ; ++j)
 				{
-					for(int k = 0; k <= twoLevel; ++k)
+					for(int k = 0; k < (twoLevel ? 2 : 1); ++k)
 					{
 						h & terrain[i][j][k];
 					}
@@ -794,14 +805,14 @@ public:
 				terrain[ii] = new TerrainTile*[height];
 				for(int jj = 0; jj < height; ++jj)
 				{
-					terrain[ii][jj] = new TerrainTile[twoLevel + 1];
+					terrain[ii][jj] = new TerrainTile[twoLevel ? 2 : 1];
 				}
 			}
 			for(int i = 0; i < width ; ++i)
 			{
 				for(int j = 0; j < height ; ++j)
 				{
-					for(int k = 0; k <= twoLevel ; ++k)
+					for(int k = 0; k < (twoLevel ? 2 : 1); ++k)
 					{
 						h & terrain[i][j][k];
 					}

+ 2 - 3
lib/Map/CMapInfo.cpp

@@ -1,4 +1,3 @@
-#include "StdInc.h"
 #include "CMapInfo.h"
 
 #include "../StartInfo.h"
@@ -29,8 +28,8 @@ void CMapInfo::countPlayers()
 				actualHumanPlayers++;
 }
 
-CMapInfo::CMapInfo() :
-	scenarioOpts(nullptr)
+CMapInfo::CMapInfo() : scenarioOpts(nullptr), playerAmnt(0), humanPlayers(0),
+	actualHumanPlayers(0), isRandomMap(false)
 {
 
 }

+ 3 - 0
lib/Map/CMapInfo.h

@@ -1,5 +1,7 @@
 #pragma once
 
+#include "StdInc.h"
+
 // 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
@@ -30,6 +32,7 @@ public:
 	int playerAmnt; //players in map
 	int humanPlayers; //players ALLOWED to be controlled by human
 	int actualHumanPlayers; // >1 if multiplayer game
+	bool isRandomMap; // true if the map will be created randomly, false if not
 
 	CMapInfo();
 	void mapInit(const std::string & fname);

+ 4 - 3
lib/Map/CMapService.cpp

@@ -1,5 +1,5 @@
-#include "StdInc.h"
 #include "CMapService.h"
+
 #include "../Filesystem/CResourceLoader.h"
 #include "../Filesystem/CBinaryReader.h"
 #include "../Filesystem/CCompressedStream.h"
@@ -208,7 +208,7 @@ void CMapLoaderH3M::readHeader()
 	mapHeader->areAnyPlayers = static_cast<bool>(readChar(buffer, pos));
 	mapHeader->height = mapHeader->width = (read_le_u32(buffer + pos));
 	pos += 4;
-	mapHeader->twoLevel = readChar(buffer, pos);
+	mapHeader->twoLevel = static_cast<bool>(readChar(buffer, pos));
 	mapHeader->name = readString(buffer, pos);
 	mapHeader->description = readString(buffer, pos);
 	mapHeader->difficulty = readChar(buffer, pos);
@@ -272,6 +272,7 @@ void CMapLoaderH3M::readPlayerInfo()
 			allowedFactions += (buffer[pos++]) * 256;
 		}
 
+		mapHeader->players[i].allowedFactions.clear();
 		for(int fact = 0; fact < 16; ++fact)
 		{
 			if(allowedFactions & (1 << fact))
@@ -884,7 +885,7 @@ void CMapLoaderH3M::readTerrain()
 		map->terrain[ii] = new TerrainTile*[map->height];
 		for(int jj = 0; jj < map->height; jj++)
 		{
-			map->terrain[ii][jj] = new TerrainTile[map->twoLevel + 1];
+			map->terrain[ii][jj] = new TerrainTile[map->twoLevel ? 2 : 1];
 		}
 	}
 

+ 2 - 0
lib/Map/CMapService.h

@@ -11,6 +11,8 @@
 
 #pragma once
 
+#include "StdInc.h"
+
 class CMap;
 class CMapHeader;
 class CInputStream;

+ 17 - 18
lib/RMG/CMapGenOptions.cpp

@@ -1,14 +1,13 @@
-#include "StdInc.h"
 #include "CMapGenOptions.h"
 
 CMapGenOptions::CMapGenOptions() : width(72), height(72), hasTwoLevels(true),
-	playersCnt(-1), teamsCnt(-1), compOnlyPlayersCnt(-1), compOnlyTeamsCnt(-1),
-	waterContent(EWaterContent::NORMAL), monsterStrength(EMonsterStrength::NORMAL)
+	playersCnt(-1), teamsCnt(-1), compOnlyPlayersCnt(0), compOnlyTeamsCnt(-1),
+	waterContent(EWaterContent::RANDOM), monsterStrength(EMonsterStrength::RANDOM)
 {
 
 }
 
-int CMapGenOptions::getWidth() const
+si32 CMapGenOptions::getWidth() const
 {
 	return width;
 }
@@ -25,12 +24,12 @@ void CMapGenOptions::setWidth(int value)
 	}
 }
 
-int CMapGenOptions::getHeight() const
+si32 CMapGenOptions::getHeight() const
 {
 	return height;
 }
 
-void CMapGenOptions::setHeight(int value)
+void CMapGenOptions::setHeight(si32 value)
 {
 	if(value > 0)
 	{
@@ -52,14 +51,14 @@ void CMapGenOptions::setHasTwoLevels(bool value)
 	hasTwoLevels = value;
 }
 
-int CMapGenOptions::getPlayersCnt() const
+si8 CMapGenOptions::getPlayersCnt() const
 {
 	return playersCnt;
 }
 
-void CMapGenOptions::setPlayersCnt(int value)
+void CMapGenOptions::setPlayersCnt(si8 value)
 {
-	if((value >= 1 && value <= 8) || value == -1)
+	if((value >= 1 && value <= 8) || value == RANDOM_SIZE)
 	{
 		playersCnt = value;
 	}
@@ -69,14 +68,14 @@ void CMapGenOptions::setPlayersCnt(int value)
 	}
 }
 
-int CMapGenOptions::getTeamsCnt() const
+si8 CMapGenOptions::getTeamsCnt() const
 {
 	return teamsCnt;
 }
 
-void CMapGenOptions::setTeamsCnt(int value)
+void CMapGenOptions::setTeamsCnt(si8 value)
 {
-	if(playersCnt == -1 || (value >= 0 && value < playersCnt) || value == -1)
+	if(playersCnt == RANDOM_SIZE || (value >= 0 && value < playersCnt) || value == RANDOM_SIZE)
 	{
 		teamsCnt = value;
 	}
@@ -87,14 +86,14 @@ void CMapGenOptions::setTeamsCnt(int value)
 	}
 }
 
-int CMapGenOptions::getCompOnlyPlayersCnt() const
+si8 CMapGenOptions::getCompOnlyPlayersCnt() const
 {
 	return compOnlyPlayersCnt;
 }
 
-void CMapGenOptions::setCompOnlyPlayersCnt(int value)
+void CMapGenOptions::setCompOnlyPlayersCnt(si8 value)
 {
-	if(value == -1 || (value >= 0 && value <= 8 - playersCnt))
+	if(value == RANDOM_SIZE || (value >= 0 && value <= 8 - playersCnt))
 	{
 		compOnlyPlayersCnt = value;
 	}
@@ -106,14 +105,14 @@ void CMapGenOptions::setCompOnlyPlayersCnt(int value)
 	}
 }
 
-int CMapGenOptions::getCompOnlyTeamsCnt() const
+si8 CMapGenOptions::getCompOnlyTeamsCnt() const
 {
 	return compOnlyTeamsCnt;
 }
 
-void CMapGenOptions::setCompOnlyTeamsCnt(int value)
+void CMapGenOptions::setCompOnlyTeamsCnt(si8 value)
 {
-	if(value == -1 || compOnlyPlayersCnt == -1 || (value >= 0 && value <= compOnlyPlayersCnt - 1))
+	if(value == RANDOM_SIZE || compOnlyPlayersCnt == RANDOM_SIZE || (value >= 0 && value <= compOnlyPlayersCnt - 1))
 	{
 		compOnlyTeamsCnt = value;
 	}

+ 65 - 45
lib/RMG/CMapGenOptions.h

@@ -11,6 +11,8 @@
 
 #pragma once
 
+#include "StdInc.h"
+
 namespace EWaterContent
 {
 	enum EWaterContent
@@ -46,37 +48,38 @@ public:
 	CMapGenOptions();
 
 	/**
-	 * Gets the width of the map.
+	 * Gets the width of the map. The default value is 72.
 	 *
-	 * @return width of the map in tiles, default is 72
+	 * @return width of the map in tiles
 	 */
-	int getWidth() const;
+	si32 getWidth() const;
 
 	/**
 	 * Sets the width of the map.
 	 *
 	 * @param value the width of the map in tiles, any values higher than 0 are allowed
 	 */
-	void setWidth(int value);
+	void setWidth(si32 value);
 
 	/**
-	 * Gets the height of the map.
+	 * Gets the height of the map. The default value is 72.
 	 *
-	 * @return height of the map in tiles, default is 72
+	 * @return height of the map in tiles
 	 */
-	int getHeight() const;
+	si32 getHeight() const;
 
 	/**
 	 * Sets the height of the map.
 	 *
 	 * @param value the height of the map in tiles, any values higher than 0 are allowed
 	 */
-	void setHeight(int value);
+	void setHeight(si32 value);
 
 	/**
-	 * Gets the flag whether the map should be generated with two levels.
+	 * Gets the flag whether the map should be generated with two levels. The
+	 * default value is true.
 	 *
-	 * @return true for two level map, default is true
+	 * @return true for two level map
 	 */
 	bool getHasTwoLevels() const;
 
@@ -88,65 +91,68 @@ public:
 	void setHasTwoLevels(bool value);
 
 	/**
-	 * Gets the count of the players.
+	 * Gets the count of the players. The default value is -1 representing a random
+	 * player count.
 	 *
-	 * @return the count of the players ranging from 1 to 8, -1 for random, default is -1
+	 * @return the count of the players ranging from 1 to 8 or -1 for random
 	 */
-	int getPlayersCnt() const;
+	si8 getPlayersCnt() const;
 
 	/**
 	 * Sets the count of the players.
 	 *
 	 * @param value the count of the players ranging from 1 to 8, -1 for random
 	 */
-	void setPlayersCnt(int value);
+	void setPlayersCnt(si8 value);
 
 	/**
-	 * Gets the count of the teams.
+	 * Gets the count of the teams. The default value is -1 representing a random
+	 * team count.
 	 *
-	 * @return the count of the teams ranging from 0 to <players count - 1>, -1 for random, default is -1
+	 * @return the count of the teams ranging from 0 to <players count - 1> or -1 for random
 	 */
-	int getTeamsCnt() const;
+	si8 getTeamsCnt() const;
 
 	/**
 	 * Sets the count of the teams
 	 *
 	 * @param value the count of the teams ranging from 0 to <players count - 1>, -1 for random
 	 */
-	void setTeamsCnt(int value);
+	void setTeamsCnt(si8 value);
 
 	/**
-	 * Gets the count of the computer only players.
+	 * Gets the count of the computer only players. The default value is 0.
 	 *
-	 * @return the count of the computer only players ranging from 0 to <8 - players count>, -1 for random, default is -1
+	 * @return the count of the computer only players ranging from 0 to <8 - players count> or -1 for random
 	 */
-	int getCompOnlyPlayersCnt() const;
+	si8 getCompOnlyPlayersCnt() const;
 
 	/**
 	 * Sets the count of the computer only players.
 	 *
 	 * @param value the count of the computer only players ranging from 0 to <8 - players count>, -1 for random
 	 */
-	void setCompOnlyPlayersCnt(int value);
+	void setCompOnlyPlayersCnt(si8 value);
 
 	/**
-	 * Gets the count of the computer only teams.
+	 * Gets the count of the computer only teams. The default value is -1 representing
+	 * a random computer only team count.
 	 *
-	 * @return the count of the computer only teams ranging from 0 to <comp only players - 1>, -1 for random, default is -1
+	 * @return the count of the computer only teams ranging from 0 to <comp only players - 1> or -1 for random
 	 */
-	int getCompOnlyTeamsCnt() const;
+	si8 getCompOnlyTeamsCnt() const;
 
 	/**
 	 * Sets the count of the computer only teams.
 	 *
 	 * @param value the count of the computer only teams ranging from 0 to <comp only players - 1>, -1 for random
 	 */
-	void setCompOnlyTeamsCnt(int value);
+	void setCompOnlyTeamsCnt(si8 value);
 
 	/**
-	 * Gets the water content.
+	 * Gets the water content. The default value is random.
 	 *
-	 * @return the water content, default is normal
+	 * @return the water content
 	 */
 	EWaterContent::EWaterContent getWaterContent() const;
 
@@ -158,9 +164,9 @@ public:
 	void setWaterContent(EWaterContent::EWaterContent value);
 
 	/**
-	 * Gets the strength of the monsters.
+	 * Gets the strength of the monsters. The default value is random.
 	 *
-	 * @return the strenght of the monsters, default is normal
+	 * @return the strenght of the monsters
 	 */
 	EMonsterStrength::EMonsterStrength getMonsterStrength() const;
 
@@ -171,31 +177,45 @@ public:
 	 */
 	void setMonsterStrength(EMonsterStrength::EMonsterStrength value);
 
+	/** The constant for specifying a random number of sth. */
+	static const si8 RANDOM_SIZE = -1;
+
 private:
-	/** the width of the map in tiles */
-	int width;
+	/** The width of the map in tiles. */
+	si32 width;
 
-	/** the height of the map in tiles */
-	int height;
+	/** The height of the map in tiles. */
+	si32 height;
 
-	/** true if the map has two levels/underground */
+	/** True if the map has two levels that means an underground. */
 	bool hasTwoLevels;
 
-	/** the count of the players(human + computer); -1 if random */
-	int playersCnt;
+	/** The count of the players(human + computer). */
+	si8 playersCnt;
 
-	/** the count of the teams; -1 if random */
-	int teamsCnt;
+	/** The count of the teams. */
+	si8 teamsCnt;
 
-	/** the count of computer only players; -1 if random */
-	int compOnlyPlayersCnt;
+	/** The count of computer only players. */
+	si8 compOnlyPlayersCnt;
 
-	/** the count of computer only teams; -1 if random */
-	int compOnlyTeamsCnt;
+	/** The count of computer only teams. */
+	si8 compOnlyTeamsCnt;
 
-	/** the water content, -1 if random */
+	/** The amount of water content. */
 	EWaterContent::EWaterContent waterContent;
 
-	/** the strength of the monsters, -1 if random */
+	/** The strength of the monsters. */
 	EMonsterStrength::EMonsterStrength monsterStrength;
+
+public:
+	/**
+	 * Serialize method.
+	 */
+	template <typename Handler>
+	void serialize(Handler & h, const int version)
+	{
+		h & width & height & hasTwoLevels & playersCnt & teamsCnt & compOnlyPlayersCnt;
+		h & compOnlyTeamsCnt & waterContent & monsterStrength;
+	}
 };

+ 10 - 4
lib/StartInfo.h

@@ -12,6 +12,8 @@
  *
  */
 
+#include "RMG/CMapGenOptions.h"
+
 class CCampaignState;
 
 /// Struct which describes the name, the color, the starting bonus of a player
@@ -66,7 +68,9 @@ struct StartInfo
 	ui32 seedPostInit; //so we know that game is correctly synced at the start; 0 if not known yet
 	ui32 mapfileChecksum; //0 if not relevant
 	ui8 turnTime; //in minutes, 0=unlimited
-	std::string mapname;
+	std::string mapname; // empty for random map, otherwise name of the map or savegame
+	bool createRandomMap; // true if a random map should be created
+	shared_ptr<CMapGenOptions> mapGenOptions; // needs to be not nullptr if createRandomMap=true
 
 	shared_ptr<CCampaignState> campState;
 
@@ -96,12 +100,14 @@ struct StartInfo
 		h & mapfileChecksum;
 		h & turnTime;
 		h & mapname;
+		h & createRandomMap;
+		h & mapGenOptions;
 		h & campState;
 	}
 
-	StartInfo()
+	StartInfo() : mode(INVALID), difficulty(0), seedToBeUsed(0), seedPostInit(0),
+		mapfileChecksum(0), turnTime(0), createRandomMap(false)
 	{
-		mapfileChecksum = seedPostInit = seedToBeUsed = 0;
-		mode = INVALID;
+
 	}
 };

+ 2 - 2
server/CGameHandler.cpp

@@ -3822,11 +3822,11 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
 		FoWChange fc;
 		fc.mode = 1;
 		fc.player = player;
-		int3 * hlp_tab = new int3[gs->map->width * gs->map->height * (gs->map->twoLevel + 1)];
+		int3 * hlp_tab = new int3[gs->map->width * gs->map->height * (gs->map->twoLevel ? 2 : 1)];
 		int lastUnc = 0;
 		for(int i=0;i<gs->map->width;i++)
 			for(int j=0;j<gs->map->height;j++)
-				for(int k=0;k<gs->map->twoLevel+1;k++)
+				for(int k = 0; k < (gs->map->twoLevel ? 2 : 1); k++)
 					if(!gs->getPlayerTeam(fc.player)->fogOfWarMap[i][j][k])
 						hlp_tab[lastUnc++] = int3(i,j,k);
 		fc.tiles.insert(hlp_tab, hlp_tab + lastUnc);

+ 11 - 9
server/CVCMIServer.cpp

@@ -315,18 +315,20 @@ CGameHandler * CVCMIServer::initGhFromHostingConnection(CConnection &c)
 	StartInfo si;
 	c >> si; //get start options
 
-	bool mapFound = CResourceHandler::get()->existsResource(ResourceID(si.mapname, EResType::MAP));
-
-	if(!mapFound && si.mode == StartInfo::NEW_GAME) //TODO some checking for campaigns
-	{
-		c << ui8(1); //WRONG!
-		return NULL;
-	}
-	else
+	if(!si.createRandomMap)
 	{
-		c << ui8(0); //OK!
+		bool mapFound = CResourceHandler::get()->existsResource(ResourceID(si.mapname, EResType::MAP));
+
+		//TODO some checking for campaigns
+		if(!mapFound && si.mode == StartInfo::NEW_GAME)
+		{
+			c << ui8(1); //WRONG!
+			return nullptr;
+		}
 	}
 
+	c << ui8(0); //OK!
+
 	gh->init(&si);
 	gh->conns.insert(&c);