mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	- Added basic mock/test generation - Added stub for terrain editing
This commit is contained in:
		
							
								
								
									
										3
									
								
								Global.h
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Global.h
									
									
									
									
									
								
							| @@ -94,6 +94,9 @@ typedef boost::int32_t si32; //signed int 32 bits (4 bytes) | ||||
| typedef boost::int16_t si16; //signed int 16 bits (2 bytes) | ||||
| typedef boost::int8_t si8; //signed int 8 bits (1 byte) | ||||
|  | ||||
| // Fixed width bool data type is important for serialization | ||||
| static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size."); | ||||
|  | ||||
| #if defined _M_X64 && defined _WIN32 //Win64 -> cannot load 32-bit DLLs for video handling | ||||
| 	#define DISABLE_VIDEO | ||||
| #endif | ||||
|   | ||||
| @@ -165,9 +165,17 @@ void updateStartInfo(std::string filename, StartInfo & sInfo, const CMapHeader * | ||||
| 		PlayerSettings &pset = sInfo.playerInfos[i]; | ||||
| 		pset.color = i; | ||||
| 		if(pinfo.canHumanPlay && namesIt != playerNames.cend()) | ||||
| 		{ | ||||
| 			setPlayer(pset, namesIt++->first, playerNames); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			setPlayer(pset, 0, playerNames); | ||||
| 			if(!pinfo.canHumanPlay) | ||||
| 			{ | ||||
| 				pset.compOnly = true; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		pset.castle = pinfo.defaultCastle(); | ||||
| 		pset.hero = pinfo.defaultHero(); | ||||
| @@ -873,11 +881,6 @@ void CSelectionScreen::startScenario() | ||||
| 		{ | ||||
| 			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(); | ||||
| @@ -1138,9 +1141,9 @@ void SelectionTab::parseGames(const std::vector<ResourceID> &files, bool multi) | ||||
|  | ||||
| 			allItems.push_back(mapInfo); | ||||
| 		} | ||||
| 		catch(std::exception & e) | ||||
| 		catch(const std::exception & e) | ||||
| 		{ | ||||
| 			tlog3 << "Failed to process " << files[i].getName() <<": " << e.what() << std::endl; | ||||
| 			tlog3 << "Error: Failed to process " << files[i].getName() <<": " << e.what() << std::endl; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -1590,8 +1593,8 @@ RandomMapTab::RandomMapTab() | ||||
|  | ||||
| 	// Map Size | ||||
| 	mapSizeBtnGroup = new CHighlightableButtonsGroup(0); | ||||
| 	mapSizeBtnGroup->pos.y = 81; | ||||
| 	mapSizeBtnGroup->pos.x = 158; | ||||
| 	mapSizeBtnGroup->pos.y += 81; | ||||
| 	mapSizeBtnGroup->pos.x += 158; | ||||
| 	const std::vector<std::string> mapSizeBtns = boost::assign::list_of("RANSIZS")("RANSIZM")("RANSIZL")("RANSIZX"); | ||||
| 	addButtonsToGroup(mapSizeBtnGroup, mapSizeBtns, 0, 3, 47, 198); | ||||
| 	mapSizeBtnGroup->select(1, false); | ||||
| @@ -1621,8 +1624,8 @@ RandomMapTab::RandomMapTab() | ||||
| 	const int BTNS_GROUP_LEFT_MARGIN = 67; | ||||
| 	// Amount of players | ||||
| 	playersCntGroup = new CHighlightableButtonsGroup(0); | ||||
| 	playersCntGroup->pos.y = 153; | ||||
| 	playersCntGroup->pos.x = BTNS_GROUP_LEFT_MARGIN; | ||||
| 	playersCntGroup->pos.y += 153; | ||||
| 	playersCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN; | ||||
| 	addButtonsWithRandToGroup(playersCntGroup, numberDefs, 1, 8, NUMBERS_WIDTH, 204, 212); | ||||
| 	playersCntGroup->onChange = [&](int btnId) | ||||
| 	{ | ||||
| @@ -1635,8 +1638,8 @@ RandomMapTab::RandomMapTab() | ||||
|  | ||||
| 	// Amount of teams | ||||
| 	teamsCntGroup = new CHighlightableButtonsGroup(0); | ||||
| 	teamsCntGroup->pos.y = 219; | ||||
| 	teamsCntGroup->pos.x = BTNS_GROUP_LEFT_MARGIN; | ||||
| 	teamsCntGroup->pos.y += 219; | ||||
| 	teamsCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN; | ||||
| 	addButtonsWithRandToGroup(teamsCntGroup, numberDefs, 0, 7, NUMBERS_WIDTH, 214, 222); | ||||
| 	teamsCntGroup->onChange = [&](int btnId) | ||||
| 	{ | ||||
| @@ -1646,8 +1649,8 @@ RandomMapTab::RandomMapTab() | ||||
|  | ||||
| 	// Computer only players | ||||
| 	compOnlyPlayersCntGroup = new CHighlightableButtonsGroup(0); | ||||
| 	compOnlyPlayersCntGroup->pos.y = 285; | ||||
| 	compOnlyPlayersCntGroup->pos.x = BTNS_GROUP_LEFT_MARGIN; | ||||
| 	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) | ||||
| @@ -1660,8 +1663,8 @@ RandomMapTab::RandomMapTab() | ||||
|  | ||||
| 	// Computer only teams | ||||
| 	compOnlyTeamsCntGroup = new CHighlightableButtonsGroup(0); | ||||
| 	compOnlyTeamsCntGroup->pos.y = 351; | ||||
| 	compOnlyTeamsCntGroup->pos.x = BTNS_GROUP_LEFT_MARGIN; | ||||
| 	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) | ||||
| @@ -1673,8 +1676,8 @@ RandomMapTab::RandomMapTab() | ||||
| 	const int WIDE_BTN_WIDTH = 85; | ||||
| 	// Water content | ||||
| 	waterContentGroup = new CHighlightableButtonsGroup(0); | ||||
| 	waterContentGroup->pos.y = 419; | ||||
| 	waterContentGroup->pos.x = BTNS_GROUP_LEFT_MARGIN; | ||||
| 	waterContentGroup->pos.y += 419; | ||||
| 	waterContentGroup->pos.x += BTNS_GROUP_LEFT_MARGIN; | ||||
| 	const std::vector<std::string> waterContentBtns = boost::assign::list_of("RANNONE")("RANNORM")("RANISLD"); | ||||
| 	addButtonsWithRandToGroup(waterContentGroup, waterContentBtns, 0, 2, WIDE_BTN_WIDTH, 243, 246); | ||||
| 	waterContentGroup->onChange = [&](int btnId) | ||||
| @@ -1684,8 +1687,8 @@ RandomMapTab::RandomMapTab() | ||||
|  | ||||
| 	// Monster strength | ||||
| 	monsterStrengthGroup = new CHighlightableButtonsGroup(0); | ||||
| 	monsterStrengthGroup->pos.y = 485; | ||||
| 	monsterStrengthGroup->pos.x = BTNS_GROUP_LEFT_MARGIN; | ||||
| 	monsterStrengthGroup->pos.y += 485; | ||||
| 	monsterStrengthGroup->pos.x += BTNS_GROUP_LEFT_MARGIN; | ||||
| 	const std::vector<std::string> monsterStrengthBtns = boost::assign::list_of("RANWEAK")("RANNORM")("RANSTRG"); | ||||
| 	addButtonsWithRandToGroup(monsterStrengthGroup, monsterStrengthBtns, 0, 2, WIDE_BTN_WIDTH, 248, 251); | ||||
| 	monsterStrengthGroup->onChange = [&](int btnId) | ||||
|   | ||||
| @@ -387,9 +387,9 @@ void CGuiHandler::run() | ||||
| 			mainFPSmng->framerateDelay(); // holds a constant FPS | ||||
| 		} | ||||
| 	} | ||||
| 	catch(const std::exception & ex) | ||||
| 	catch(const std::exception & e) | ||||
| 	{ | ||||
| 		tlog1 << "Error: " << ex.what() << std::endl; | ||||
| 		tlog1 << "Error: " << e.what() << std::endl; | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										428
									
								
								config/terrainViewPatterns.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										428
									
								
								config/terrainViewPatterns.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,428 @@ | ||||
| // Defines terrain view patterns. | ||||
|  | ||||
| // The following properties are mandatory: | ||||
| // data:		the 3x3 pattern | ||||
| // mapping:		maps the pattern to a range of terrain view images/frames of the .DEF, e.g. 10-15 | ||||
| //				for patterns which represent two transitions a comma can be used to distinct between dirt and sand | ||||
| //				e.g. 10-15, 25-35 whereas the first value is always dirt and the second sand | ||||
|  | ||||
| // The following properties are optional: | ||||
| // flipMode:	should the same be flipped or different images be used(see rock) or is flip not supported at all; allowed values: sameImage | diffImages; default is: sameImage | ||||
| // id:			the identifier for the pattern if it's referenced by other patterns | ||||
| // minPoints:	the minimum points to reach to validate the pattern successfully | ||||
|  | ||||
| // The following table shows the rules for the 3x3 pattern of all terrain types:  | ||||
| // I) normal(e.g. grass, lava, ...): | ||||
| // N:		Native type | ||||
| // D:		Dirt border | ||||
| // S:		Sand border | ||||
| // T:		Sand OR dirt border(all Ts in the pattern are replaced by dirt OR sand) | ||||
| // ?:		T or N | ||||
| // II) dirt: | ||||
| // N:		Native type | ||||
| // D:		Dirt border | ||||
| // S:		Sand border | ||||
| // ?:		Any border | ||||
| // III) sand: | ||||
| // N:		Native type | ||||
| // S:		Sand border | ||||
| // IV) water: | ||||
| // N:		Native type | ||||
| // S:		Sand border | ||||
| // ?:		Any border | ||||
| // V) rock: | ||||
| // N:		Native type | ||||
| // S:		Sand border | ||||
| // ?:		Any border | ||||
|  | ||||
| // Some additional info: | ||||
| // Rules can be combined with comma. e.g. T, N which would be the same meaning of ?. It's most useful in combination with pattern chaining. | ||||
| // Chaining of patterns is supported. To reference a another pattern you simply add the <Ref Id> to the relevant field of the pattern. | ||||
| // Rules can be given points: <[Rule OR Ref Id]-Points> With the property minPoints simple conditions can be built. | ||||
|  | ||||
| { | ||||
| 	"normal" : | ||||
| 	[ | ||||
| 		// Standard transitions | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "?", "T", | ||||
| 				"?", "N", "N", | ||||
| 				"T", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "0-3, 20-23" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "N", "N", | ||||
| 				"T", "N", "N", | ||||
| 				"?", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "4-7, 24-27" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "T", "?", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "8-11, 28-31" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "T" | ||||
| 			], | ||||
| 			"mapping" : "12-15, 32-35" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"T", "T", "a-1,?", | ||||
| 				"T", "N", "N", | ||||
| 				"a-1,?", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "16-17, 36-37", | ||||
| 			"id" : "a", | ||||
| 			"minPoints" : 1 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "a-1,N", | ||||
| 				"N", "a-1,N", "T" | ||||
| 			], | ||||
| 			"mapping" : "18-19, 38-39", | ||||
| 			"minPoints" : 1 | ||||
| 		}, | ||||
| 		// Mixed transitions | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"T", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "T" | ||||
| 			], | ||||
| 			"mapping" : "40, 42" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"D", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "S" | ||||
| 			], | ||||
| 			"mapping" : "41" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "D,N", | ||||
| 				"N", "N", "D", | ||||
| 				"S", "D", "D,N" | ||||
| 			], | ||||
| 			"mapping" : "43" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "S", | ||||
| 				"N", "N", "D", | ||||
| 				"D,N", "D", "D,N" | ||||
| 			], | ||||
| 			"mapping" : "44" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "D,N", | ||||
| 				"N", "N", "D", | ||||
| 				"N", "N", "S" | ||||
| 			], | ||||
| 			"mapping" : "45" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"D,N", "D", "S" | ||||
| 			], | ||||
| 			"mapping" : "46" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "D,S,N", | ||||
| 				"N", "N", "S", | ||||
| 				"D", "D", "D,S,N" | ||||
| 			], | ||||
| 			"mapping" : "47" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "D", | ||||
| 				"N", "N", "D", | ||||
| 				"D,S,N", "S", "D,S,N" | ||||
| 			], | ||||
| 			"mapping" : "48" | ||||
| 		}, | ||||
| 		// No transition | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "49-72" | ||||
| 		} | ||||
| 	], | ||||
| 	"dirt" : | ||||
| 	[ | ||||
| 		// Standard transitions | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "S", "S", | ||||
| 				"S", "N", "N", | ||||
| 				"S", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "0-3" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "D", "D", | ||||
| 				"S", "N", "N", | ||||
| 				"?", "D", "D" | ||||
| 			], | ||||
| 			"mapping" : "4-7" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "S", "?", | ||||
| 				"D", "N", "D", | ||||
| 				"D", "N", "D" | ||||
| 			], | ||||
| 			"mapping" : "8-11" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"D", "D", "D", | ||||
| 				"D", "N", "N", | ||||
| 				"D", "N", "S" | ||||
| 			], | ||||
| 			"mapping" : "12-15" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"S", "S", "D", | ||||
| 				"S", "N", "b-1,D", | ||||
| 				"D", "b-1,D", "D" | ||||
| 			], | ||||
| 			"mapping" : "16-17", | ||||
| 			"id" : "a", | ||||
| 			"minPoints" : 1 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"D", "D", "D", | ||||
| 				"D", "N", "a-1,D", | ||||
| 				"D", "a-1,D", "S" | ||||
| 			], | ||||
| 			"mapping" : "18-19", | ||||
| 			"id" : "b", | ||||
| 			"minPoints" : 1 | ||||
| 		}, | ||||
| 		// Mixed transition | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"S", "D", "D", | ||||
| 				"D", "N", "D", | ||||
| 				"D", "D", "S" | ||||
| 			], | ||||
| 			"mapping" : "20" | ||||
| 		}, | ||||
| 		// No transition | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"D", "D", "D", | ||||
| 				"D", "N", "D", | ||||
| 				"D", "D", "D" | ||||
| 			], | ||||
| 			"mapping" : "21-44" | ||||
| 		} | ||||
| 	], | ||||
| 	"sand" : | ||||
| 	[ | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"S", "S", "S", | ||||
| 				"S", "N", "S", | ||||
| 				"S", "S", "S" | ||||
| 			], | ||||
| 			"mapping" : "0-23" | ||||
| 		} | ||||
| 	], | ||||
| 	"water" : | ||||
| 	[ | ||||
| 		// Standard transitions | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"S", "S", "S", | ||||
| 				"S", "N", "N", | ||||
| 				"S", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "0-3" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "N", "N", | ||||
| 				"S", "N", "N", | ||||
| 				"?", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "4-7" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "S", "?", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "8-11" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "S" | ||||
| 			], | ||||
| 			"mapping" : "12-15" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"S", "S", "N", | ||||
| 				"S", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "16-17", | ||||
| 			"id" : "a" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "a-1,N", | ||||
| 				"N", "a-1,N", "S" | ||||
| 			], | ||||
| 			"mapping" : "18-19", | ||||
| 			"minPoints" : 1 | ||||
| 		}, | ||||
| 		// No transition | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "20-32" | ||||
| 		} | ||||
| 	], | ||||
| 	"rock" : | ||||
| 	[ | ||||
| 		// No transition | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "0-7" | ||||
| 		}, | ||||
| 		// Standard transitions | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "S", "?", | ||||
| 				"S", "N", "N", | ||||
| 				"?", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "8-15", | ||||
| 			"flipMode" : "diffImages" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "N", "N", | ||||
| 				"S", "N", "N", | ||||
| 				"?", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "16-19", | ||||
| 			"flipMode" : "diffImages" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "S", "?", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "20-23", | ||||
| 			"flipMode" : "diffImages" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "S" | ||||
| 			], | ||||
| 			"mapping" : "24-31", | ||||
| 			"flipMode" : "diffImages" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"S", "S", "N", | ||||
| 				"S", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "32-39", | ||||
| 			"flipMode" : "diffImages", | ||||
| 			"id" : "a" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "a-1,N", | ||||
| 				"N", "a-1,N", "S" | ||||
| 			], | ||||
| 			"mapping" : "40-47", | ||||
| 			"flipMode" : "diffImages", | ||||
| 			"minPoints" : 1 | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| @@ -9,6 +9,7 @@ | ||||
| #include "CSpellHandler.h" | ||||
| #include "CObjectHandler.h" | ||||
| #include "NetPacks.h" | ||||
| #include "GameConstants.h" | ||||
|  | ||||
| using namespace boost::assign; | ||||
|  | ||||
| @@ -776,14 +777,23 @@ void CArtHandler::initAllowedArtifactsList(const std::vector<ui8> &allowed) | ||||
| 			allowedArtifacts.push_back(artifacts[i]); | ||||
| 		 else //check if active modules allow artifact to be every used | ||||
| 		 { | ||||
| 			 if (artifacts[i]->possibleSlots[ArtBearer::COMMANDER].size() && VLC->modh->modules.COMMANDERS || | ||||
| 				 artifacts[i]->possibleSlots[ArtBearer::CREATURE].size() && VLC->modh->modules.STACK_ARTIFACT) | ||||
| 			 if ((artifacts[i]->possibleSlots[ArtBearer::COMMANDER].size() && VLC->modh->modules.COMMANDERS) || | ||||
| 				 (artifacts[i]->possibleSlots[ArtBearer::CREATURE].size() && VLC->modh->modules.STACK_ARTIFACT)) | ||||
| 				 allowedArtifacts.push_back(artifacts[i]); | ||||
| 			 //keep im mind that artifact can be worn by more than one type of bearer | ||||
| 		 } | ||||
| 	} | ||||
| } | ||||
|  | ||||
| std::vector<ui8> CArtHandler::getDefaultAllowedArtifacts() const | ||||
| { | ||||
| 	std::vector<ui8> allowedArtifacts; | ||||
| 	allowedArtifacts.resize(127, 1); | ||||
| 	allowedArtifacts.resize(141, 0); | ||||
| 	allowedArtifacts.resize(GameConstants::ARTIFACTS_QUANTITY, 1); | ||||
| 	return allowedArtifacts; | ||||
| } | ||||
|  | ||||
| CArtifactInstance::CArtifactInstance() | ||||
| { | ||||
| 	init(); | ||||
|   | ||||
| @@ -256,6 +256,13 @@ public: | ||||
| 	CArtHandler(); | ||||
| 	~CArtHandler(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets a list of default allowed artifacts. | ||||
| 	 * | ||||
| 	 * @return a list of allowed artifacts, the index is the artifact id and the value either 0 for not allowed or 1 for allowed | ||||
| 	 */ | ||||
| 	std::vector<ui8> getDefaultAllowedArtifacts() const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & artifacts & allowedArtifacts & treasures & minors & majors & relics | ||||
|   | ||||
| @@ -26,6 +26,7 @@ | ||||
| #include "Filesystem/CResourceLoader.h" | ||||
| #include "GameConstants.h" | ||||
| #include "RMG/CMapGenOptions.h" | ||||
| #include "RMG/CMapGenerator.h" | ||||
|  | ||||
| DLL_LINKAGE boost::rand48 ran; | ||||
| class CGObjectInstance; | ||||
| @@ -872,7 +873,46 @@ void CGameState::init(StartInfo * si) | ||||
| 			if(scenarioOps->createRandomMap) | ||||
| 			{ | ||||
| 				tlog0 << "Create random map." << std::endl; | ||||
| 				//TODO random map | ||||
|  | ||||
| 				// Create player settings for RMG | ||||
| 				std::map<TPlayerColor, CMapGenerator::CPlayerSettings> players; | ||||
| 				BOOST_FOREACH(auto pInfo, scenarioOps->playerInfos) | ||||
| 				{ | ||||
| 					const PlayerSettings & startSettings = pInfo.second; | ||||
| 					CMapGenerator::CPlayerSettings player; | ||||
| 					player.setColor(startSettings.color); | ||||
| 					player.setStartingTown(startSettings.castle); | ||||
| 					if(startSettings.playerID > 0) | ||||
| 					{ | ||||
| 						player.setPlayerType(CMapGenerator::CPlayerSettings::HUMAN); | ||||
| 					} | ||||
| 					else if(startSettings.compOnly) | ||||
| 					{ | ||||
| 						player.setPlayerType(CMapGenerator::CPlayerSettings::COMP_ONLY); | ||||
| 					} | ||||
| 					players[player.getColor()] = player; | ||||
| 				} | ||||
|  | ||||
| 				// Gen map | ||||
| 				CMapGenerator mapGen(*scenarioOps->mapGenOptions, players, scenarioOps->seedToBeUsed); | ||||
| 				map = mapGen.generate().release(); | ||||
|  | ||||
| 				// Update starting options | ||||
| 				for(auto it = scenarioOps->playerInfos.begin(); it != scenarioOps->playerInfos.end();) | ||||
| 				{ | ||||
| 					PlayerSettings & pSettings = it->second; | ||||
| 					if(!(map->players[pSettings.color].canHumanPlay || map->players[pSettings.color].canComputerPlay)) | ||||
| 					{ | ||||
| 						scenarioOps->playerInfos.erase(it++); | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						pSettings.compOnly = !(map->players[pSettings.color].canHumanPlay); | ||||
| 						pSettings.team = map->players[pSettings.color].team; | ||||
| 						pSettings.castle = map->players[pSettings.color].defaultCastle(); | ||||
| 						++it; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| @@ -902,7 +942,6 @@ void CGameState::init(StartInfo * si) | ||||
| 	VLC->arth->initAllowedArtifactsList(map->allowedArtifact); | ||||
| 	tlog0 << "Map loaded!" << std::endl; | ||||
|  | ||||
|  | ||||
| 	//tlog0 <<"Reading and detecting map file (together): "<<tmh.getDif()<<std::endl; | ||||
| 	tlog0 << "\tOur checksum for the map: "<< map->checksum << std::endl; | ||||
| 	if(scenarioOps->mapfileChecksum) | ||||
|   | ||||
| @@ -498,3 +498,10 @@ std::vector<ui8> CHeroHandler::getDefaultAllowedHeroes() const | ||||
|  | ||||
| 	return allowedHeroes; | ||||
| } | ||||
|  | ||||
| std::vector<ui8> CHeroHandler::getDefaultAllowedAbilities() const | ||||
| { | ||||
| 	std::vector<ui8> allowedAbilities; | ||||
| 	allowedAbilities.resize(GameConstants::SKILL_QUANTITY, 1); | ||||
| 	return allowedAbilities; | ||||
| } | ||||
|   | ||||
| @@ -218,10 +218,17 @@ public: | ||||
| 	 * 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 | ||||
| 	 * @return a list of allowed heroes, the index is the hero id and the value either 0 for not allowed or 1 for allowed | ||||
| 	 */ | ||||
| 	std::vector<ui8> getDefaultAllowedHeroes() const; | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets a list of default allowed abilities. OH3 abilities/skills are all allowed by default. | ||||
| 	 * | ||||
| 	 * @return a list of allowed abilities, the index is the ability id and the value either 0 for not allowed or 1 for allowed | ||||
| 	 */ | ||||
| 	std::vector<ui8> getDefaultAllowedAbilities() const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & classes & heroes & expPerLevel & ballistics & terrCosts; | ||||
|   | ||||
| @@ -1,79 +1,82 @@ | ||||
| project(libvcmi) | ||||
| cmake_minimum_required(VERSION 2.6) | ||||
|  | ||||
| include_directories(${CMAKE_HOME_DIRECTORY} ${CMAKE_CURRENT_SOURCE_DIRECTORY} ${CMAKE_HOME_DIRECTORY}/lib) | ||||
| include_directories(${Boost_INCLUDE_DIRS} ${SDL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}) | ||||
|  | ||||
| set(lib_SRCS | ||||
|         Filesystem/CBinaryReader.cpp | ||||
|         Filesystem/CFilesystemLoader.cpp | ||||
|         Filesystem/CMemoryStream.cpp | ||||
|         Filesystem/CFileInfo.cpp | ||||
|         Filesystem/CLodArchiveLoader.cpp | ||||
|         Filesystem/CResourceLoader.cpp | ||||
|         Filesystem/CFileInputStream.cpp | ||||
|         Filesystem/CCompressedStream.cpp | ||||
|         Mapping/CCampaignHandler.cpp | ||||
|         Mapping/CMap.cpp | ||||
|         Mapping/CMapInfo.cpp | ||||
|         Mapping/CMapService.cpp | ||||
|    		RMG/CMapGenOptions.cpp | ||||
|         BattleAction.cpp | ||||
|         BattleHex.cpp | ||||
|         BattleState.cpp | ||||
|         CArtHandler.cpp | ||||
|         CBattleCallback.cpp | ||||
|         CBuildingHandler.cpp | ||||
|         CConfigHandler.cpp | ||||
|         CConsoleHandler.cpp | ||||
|         CCreatureHandler.cpp | ||||
|         CCreatureSet.cpp | ||||
|         CDefObjInfoHandler.cpp | ||||
|         CGameInterface.cpp | ||||
|         CGameState.cpp | ||||
|         CGeneralTextHandler.cpp | ||||
|         CHeroHandler.cpp | ||||
|         CLogger.cpp | ||||
|         CModHandler.cpp | ||||
|         CObjectHandler.cpp | ||||
|         CObstacleInstance.cpp | ||||
|         Connection.cpp | ||||
|         CSpellHandler.cpp | ||||
|         CThreadHelper.cpp | ||||
|         CTownHandler.cpp | ||||
|         HeroBonus.cpp | ||||
|         IGameCallback.cpp | ||||
|         JsonNode.cpp | ||||
|         NetPacksLib.cpp | ||||
|         ResourceSet.cpp | ||||
|         VCMI_Lib.cpp | ||||
| ) | ||||
|  | ||||
| set(lib_HEADERS | ||||
| 		Filesystem/CInputStream.h | ||||
| 		Filesystem/ISimpleResourceLoader.h | ||||
| 		AI_Base.h | ||||
| 		CondSh.h | ||||
| 		ConstTransitivePtr.h | ||||
| 		CScriptingModule.h | ||||
| 		CStopWatch.h | ||||
| 		GameConstants.h | ||||
| 		StringConstants.h | ||||
| 		IGameEventsReceiver.h | ||||
| 		int3.h | ||||
| 		Interprocess.h | ||||
| 		NetPacks.h | ||||
| 		RegisterTypes.h | ||||
| 		StartInfo.h | ||||
| 		UnlockGuard.h | ||||
| 		VCMIDirs.h | ||||
| 		vcmi_endian.h | ||||
| ) | ||||
|  | ||||
| add_library(vcmi SHARED ${lib_SRCS} ${lib_HEADERS}) | ||||
| set_target_properties(vcmi PROPERTIES XCODE_ATTRIBUTE_LD_DYLIB_INSTALL_NAME "@executable_path/libvcmi.dylib") | ||||
| target_link_libraries(vcmi ${Boost_LIBRARIES} ${SDL_LIBRARY} ${ZLIB_LIBRARIES}) | ||||
|  | ||||
| if (NOT APPLE) # Already inside vcmiclient bundle | ||||
|     install(TARGETS vcmi DESTINATION ${LIB_DIR}) | ||||
| endif() | ||||
| project(libvcmi) | ||||
| cmake_minimum_required(VERSION 2.6) | ||||
|  | ||||
| include_directories(${CMAKE_HOME_DIRECTORY} ${CMAKE_CURRENT_SOURCE_DIRECTORY} ${CMAKE_HOME_DIRECTORY}/lib) | ||||
| include_directories(${Boost_INCLUDE_DIRS} ${SDL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}) | ||||
|  | ||||
| set(lib_SRCS | ||||
| 		Filesystem/CBinaryReader.cpp | ||||
| 		Filesystem/CFilesystemLoader.cpp | ||||
| 		Filesystem/CMemoryStream.cpp | ||||
| 		Filesystem/CFileInfo.cpp | ||||
| 		Filesystem/CLodArchiveLoader.cpp | ||||
| 		Filesystem/CResourceLoader.cpp | ||||
| 		Filesystem/CFileInputStream.cpp | ||||
| 		Filesystem/CCompressedStream.cpp | ||||
| 		Mapping/CCampaignHandler.cpp | ||||
| 		Mapping/CMap.cpp | ||||
| 		Mapping/CMapEditManager.cpp | ||||
| 		Mapping/CMapInfo.cpp | ||||
| 		Mapping/CMapService.cpp | ||||
| 		RMG/CMapGenOptions.cpp | ||||
| 		RMG/CMapGenerator.cpp | ||||
| 		BattleAction.cpp | ||||
| 		BattleHex.cpp | ||||
| 		BattleState.cpp | ||||
| 		CArtHandler.cpp | ||||
| 		CBattleCallback.cpp | ||||
| 		CBuildingHandler.cpp | ||||
| 		CConfigHandler.cpp | ||||
| 		CConsoleHandler.cpp | ||||
| 		CCreatureHandler.cpp | ||||
| 		CCreatureSet.cpp | ||||
| 		CDefObjInfoHandler.cpp | ||||
| 		CGameInterface.cpp | ||||
| 		CGameState.cpp | ||||
| 		CGeneralTextHandler.cpp | ||||
| 		CHeroHandler.cpp | ||||
| 		CLogger.cpp | ||||
| 		CModHandler.cpp | ||||
| 		CObjectHandler.cpp | ||||
| 		CObstacleInstance.cpp | ||||
| 		Connection.cpp | ||||
| 		CSpellHandler.cpp | ||||
| 		CThreadHelper.cpp | ||||
| 		CTownHandler.cpp | ||||
| 		HeroBonus.cpp | ||||
| 		IGameCallback.cpp | ||||
| 		JsonNode.cpp | ||||
| 		NetPacksLib.cpp | ||||
| 		ResourceSet.cpp | ||||
| 		VCMI_Lib.cpp | ||||
| ) | ||||
|  | ||||
| set(lib_HEADERS | ||||
| 		Filesystem/CInputStream.h | ||||
| 		Filesystem/ISimpleResourceLoader.h | ||||
| 		AI_Base.h | ||||
| 		CondSh.h | ||||
| 		ConstTransitivePtr.h | ||||
| 		CRandomGenerator.h | ||||
| 		CScriptingModule.h | ||||
| 		CStopWatch.h | ||||
| 		GameConstants.h | ||||
| 		StringConstants.h | ||||
| 		IGameEventsReceiver.h | ||||
| 		int3.h | ||||
| 		Interprocess.h | ||||
| 		NetPacks.h | ||||
| 		RegisterTypes.h | ||||
| 		StartInfo.h | ||||
| 		UnlockGuard.h | ||||
| 		VCMIDirs.h | ||||
| 		vcmi_endian.h | ||||
| ) | ||||
|  | ||||
| add_library(vcmi SHARED ${lib_SRCS} ${lib_HEADERS}) | ||||
| set_target_properties(vcmi PROPERTIES XCODE_ATTRIBUTE_LD_DYLIB_INSTALL_NAME "@executable_path/libvcmi.dylib") | ||||
| target_link_libraries(vcmi ${Boost_LIBRARIES} ${SDL_LIBRARY} ${ZLIB_LIBRARIES}) | ||||
|  | ||||
| if (NOT APPLE) # Already inside vcmiclient bundle | ||||
|     install(TARGETS vcmi DESTINATION ${LIB_DIR}) | ||||
| endif() | ||||
|   | ||||
| @@ -1971,11 +1971,9 @@ bool CGTownInstance::hasCapitol() const | ||||
| 	return hasBuilt(EBuilding::CAPITOL); | ||||
| } | ||||
| CGTownInstance::CGTownInstance() | ||||
| 	:IShipyard(this), IMarket(this) | ||||
| 	:IShipyard(this), IMarket(this), town(nullptr), builded(0), destroyed(0), identifier(0), alignment(0xff) | ||||
| { | ||||
| 	builded=-1; | ||||
| 	destroyed=-1; | ||||
| 	town=NULL; | ||||
|  | ||||
| } | ||||
|  | ||||
| CGTownInstance::~CGTownInstance() | ||||
|   | ||||
							
								
								
									
										122
									
								
								lib/CRandomGenerator.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								lib/CRandomGenerator.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | ||||
|  | ||||
| /* | ||||
|  * CRandomGenerator.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 <boost/random/mersenne_twister.hpp> | ||||
| #include <boost/random/uniform_int_distribution.hpp> | ||||
| #include <boost/random/uniform_real_distribution.hpp> | ||||
| #include <boost/random/variate_generator.hpp> | ||||
|  | ||||
| typedef boost::mt19937 TGenerator; | ||||
| typedef boost::random::uniform_int_distribution<int> TIntDist; | ||||
| typedef boost::random::uniform_real_distribution<double> TRealDist; | ||||
| typedef boost::variate_generator<TGenerator &, TIntDist> TRandI; | ||||
| typedef boost::variate_generator<TGenerator &, TRealDist> TRand; | ||||
|  | ||||
| /** | ||||
|  * The random generator randomly generates integers and real numbers("doubles") between | ||||
|  * a given range. This is a header only class and mainly a wrapper for | ||||
|  * convenient usage of the boost random API. | ||||
|  */ | ||||
| class CRandomGenerator | ||||
| { | ||||
| public: | ||||
| 	/** | ||||
| 	 * Constructor. Seeds the generator with the current time by default. | ||||
| 	 */ | ||||
| 	CRandomGenerator()  | ||||
| 	{ | ||||
| 		gen.seed(std::time(nullptr));  | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Seeds the generator with the given value. | ||||
| 	 * | ||||
| 	 * @param value the random seed | ||||
| 	 */ | ||||
| 	void seed(int value) | ||||
| 	{ | ||||
| 		gen.seed(value); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets a generator which generates integers in the given range. | ||||
| 	 * | ||||
| 	 * Example how to use: | ||||
| 	 * @code | ||||
| 	 * TRandI rand = getRangeI(0, 10); | ||||
| 	 * int a = rand(); // with the operator() the next value can be obtained | ||||
| 	 * int b = rand(); // you can generate more values | ||||
| 	 * @endcode | ||||
| 	 * | ||||
| 	 * @param lower the lower boundary | ||||
| 	 * @param upper the upper boundary | ||||
| 	 * @return the generator which can be used to generate integer numbers | ||||
| 	 */ | ||||
| 	TRandI getRangeI(int lower, int upper) | ||||
| 	{ | ||||
| 		TIntDist range(lower, upper); | ||||
| 		return TRandI(gen, range); | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Gets a integer in the given range. In comparison to getRangeI it's | ||||
| 	 * a convenient method if you want to generate only one value in a given | ||||
| 	 * range. | ||||
| 	 * | ||||
| 	 * @param lower the lower boundary | ||||
| 	 * @param upper the upper boundary | ||||
| 	 * @return the generated integer | ||||
| 	 */ | ||||
| 	int getInteger(int lower, int upper) | ||||
| 	{ | ||||
| 		return getRangeI(lower, upper)(); | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Gets a generator which generates doubles in the given range. | ||||
| 	 * | ||||
| 	 * Example how to use: | ||||
| 	 * @code | ||||
| 	 * TRand rand = getRange(23.56, 32.10); | ||||
| 	 * double a = rand(); // with the operator() the next value can be obtained | ||||
| 	 * double b = rand(); // you can generate more values | ||||
| 	 * @endcode | ||||
| 	 * | ||||
| 	 * @param lower the lower boundary | ||||
| 	 * @param upper the upper boundary | ||||
| 	 * @return the generated double | ||||
| 	 */ | ||||
| 	TRand getRange(double lower, double upper) | ||||
| 	{ | ||||
| 		TRealDist range(lower, upper); | ||||
| 		return TRand(gen, range); | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Gets a double in the given range. In comparison to getRange it's | ||||
| 	 * a convenient method if you want to generate only one value in a given | ||||
| 	 * range. | ||||
| 	 * | ||||
| 	 * @param lower the lower boundary | ||||
| 	 * @param upper the upper boundary | ||||
| 	 * @return the generated double | ||||
| 	 */ | ||||
| 	double getDouble(double lower, double upper) | ||||
| 	{ | ||||
| 		return getRange(lower, upper)(); | ||||
| 	} | ||||
|  | ||||
| private: | ||||
| 	/** The actual boost random generator. */ | ||||
| 	TGenerator gen; | ||||
| }; | ||||
| @@ -378,3 +378,10 @@ void CSpellHandler::loadSpells() | ||||
| 	risingSpells += 38, 39, 40; | ||||
| 	mindSpells += 50, 59, 60, 61, 62; | ||||
| } | ||||
|  | ||||
| std::vector<ui8> CSpellHandler::getDefaultAllowedSpells() const | ||||
| { | ||||
| 	std::vector<ui8> allowedSpells; | ||||
| 	allowedSpells.resize(GameConstants::SPELLS_QUANTITY, 1); | ||||
| 	return allowedSpells; | ||||
| } | ||||
|   | ||||
| @@ -101,6 +101,13 @@ public: | ||||
| 	std::set<TSpell> mindSpells; | ||||
| 	void loadSpells(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets a list of default allowed spells. OH3 spells are all allowed by default. | ||||
| 	 * | ||||
| 	 * @return a list of allowed spells, the index is the spell id and the value either 0 for not allowed or 1 for allowed | ||||
| 	 */ | ||||
| 	std::vector<ui8> getDefaultAllowedSpells() const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & spells & damageSpells & risingSpells & mindSpells; | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| #include "../CTownHandler.h" | ||||
| #include "../CHeroHandler.h" | ||||
| #include "../CDefObjInfoHandler.h" | ||||
| #include "../CSpellHandler.h" | ||||
|  | ||||
| SHeroName::SHeroName() : heroId(-1) | ||||
| { | ||||
| @@ -13,8 +14,8 @@ SHeroName::SHeroName() : heroId(-1) | ||||
| } | ||||
|  | ||||
| PlayerInfo::PlayerInfo(): canHumanPlay(false), canComputerPlay(false), | ||||
| 	aiTactic(EAiTactic::RANDOM), isFactionRandom(false), mainHeroPortrait(-1), hasMainTown(true), | ||||
| 	generateHeroAtMainTown(true), team(255), generateHero(false), p7(0), hasHero(false), customHeroID(-1), powerPlaceholders(-1) | ||||
| 	aiTactic(EAiTactic::RANDOM), isFactionRandom(false), mainHeroPortrait(-1), hasMainTown(false), | ||||
| 	generateHeroAtMainTown(false), team(255), generateHero(false), p7(0), hasHero(false), customHeroID(-1), powerPlaceholders(-1) | ||||
| { | ||||
| 	allowedFactions = VLC->townh->getDefaultAllowedFactions(); | ||||
| } | ||||
| @@ -129,6 +130,7 @@ CMapHeader::CMapHeader() : version(EMapFormat::SOD), height(72), width(72), | ||||
| 	twoLevel(true), difficulty(1), levelLimit(0), howManyTeams(0), areAnyPlayers(false) | ||||
| { | ||||
| 	allowedHeroes = VLC->heroh->getDefaultAllowedHeroes(); | ||||
| 	players.resize(GameConstants::PLAYER_LIMIT); | ||||
| } | ||||
|  | ||||
| CMapHeader::~CMapHeader() | ||||
| @@ -138,7 +140,9 @@ CMapHeader::~CMapHeader() | ||||
|  | ||||
| CMap::CMap() : checksum(0), terrain(nullptr), grailRadious(0) | ||||
| { | ||||
|  | ||||
| 	allowedAbilities = VLC->heroh->getDefaultAllowedAbilities(); | ||||
| 	allowedArtifact = VLC->arth->getDefaultAllowedArtifacts(); | ||||
| 	allowedSpell = VLC->spellh->getDefaultAllowedSpells(); | ||||
| } | ||||
|  | ||||
| CMap::~CMap() | ||||
| @@ -186,6 +190,7 @@ void CMap::removeBlockVisTiles(CGObjectInstance * obj, bool total) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CMap::addBlockVisTiles(CGObjectInstance * obj) | ||||
| { | ||||
| 	for(int fx=0; fx<8; ++fx) | ||||
| @@ -286,3 +291,23 @@ void CMap::eraseArtifactInstance(CArtifactInstance * art) | ||||
| 	assert(artInstances[art->id] == art); | ||||
| 	artInstances[art->id].dellNull(); | ||||
| } | ||||
|  | ||||
| void CMap::addQuest(CGObjectInstance * quest) | ||||
| { | ||||
| 	auto q = dynamic_cast<IQuestObject *>(quest); | ||||
| 	q->quest->qid = quests.size(); | ||||
| 	quests.push_back(q->quest); | ||||
| } | ||||
|  | ||||
| void CMap::initTerrain() | ||||
| { | ||||
| 	terrain = new TerrainTile**[width]; | ||||
| 	for(int i = 0; i < width; ++i) | ||||
| 	{ | ||||
| 		terrain[i] = new TerrainTile*[height]; | ||||
| 		for(int j = 0; j < height; ++j) | ||||
| 		{ | ||||
| 			terrain[i][j] = new TerrainTile[twoLevel ? 2 : 1]; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -116,10 +116,10 @@ struct DLL_LINKAGE PlayerInfo | ||||
| 	/** The list of renamed heroes. */ | ||||
| 	std::vector<SHeroName> heroesNames; | ||||
|  | ||||
| 	/** True if the player has a main town. The default value is true. */ | ||||
| 	/** True if the player has a main town. The default value is false. */ | ||||
| 	bool hasMainTown; | ||||
|  | ||||
| 	/** True if the main hero should be generated at the main town. The default value is true. */ | ||||
| 	/** True if the main hero should be generated at the main town. The default value is false. */ | ||||
| 	bool generateHeroAtMainTown; | ||||
|  | ||||
| 	/** The position of the main town. */ | ||||
| @@ -286,11 +286,9 @@ struct DLL_LINKAGE DisposedHero | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| /// Class which manages map events. | ||||
|  | ||||
| /** | ||||
|  * The map event is an event which gives or takes resources for a specific | ||||
|  * amount of players and can appear regularly or once a time. | ||||
|  * The map event is an event which e.g. gives or takes resources of a specific | ||||
|  * amount to/from players and can appear regularly or once a time. | ||||
|  */ | ||||
| class DLL_LINKAGE CMapEvent | ||||
| { | ||||
| @@ -584,7 +582,7 @@ public: | ||||
| 	/** Specifies the victory condition. The default value is defeat all enemies. */ | ||||
| 	VictoryCondition victoryCondition; | ||||
|  | ||||
| 	/** A list containing information about players. */ | ||||
| 	/** A list containing information about players. The default size of the vector is GameConstants::PLAYER_LIMIT. */ | ||||
| 	std::vector<PlayerInfo> players; | ||||
|  | ||||
| 	/** The number of teams. */ | ||||
| @@ -714,10 +712,22 @@ public: | ||||
| 	 */ | ||||
| 	void addNewArtifactInstance(CArtifactInstance * art); | ||||
|  | ||||
| 	/** | ||||
| 	 * 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); | ||||
|  | ||||
| 	/** | ||||
| 	 * Initializes the terrain of the map by allocating memory. | ||||
| 	 */ | ||||
| 	void initTerrain(); | ||||
|  | ||||
| 	/** the checksum of the map */ | ||||
| 	ui32 checksum; | ||||
|  | ||||
| 	/** a 3-dimensional array of terrain tiles, access is as follows: x, y, level */ | ||||
| 	/** a 3-dimensional array of terrain tiles, access is as follows: x, y, level. where level=1 is underground */ | ||||
| 	TerrainTile*** terrain; | ||||
|  | ||||
| 	/** list of rumors */ | ||||
|   | ||||
							
								
								
									
										386
									
								
								lib/Mapping/CMapEditManager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										386
									
								
								lib/Mapping/CMapEditManager.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,386 @@ | ||||
| #include "StdInc.h" | ||||
| #include "CMapEditManager.h" | ||||
|  | ||||
| #include "../JsonNode.h" | ||||
| #include "../Filesystem/CResourceLoader.h" | ||||
| #include "../CDefObjInfoHandler.h" | ||||
|  | ||||
| const std::string TerrainViewPattern::FLIP_MODE_SAME_IMAGE = "sameImage"; | ||||
| const std::string TerrainViewPattern::FLIP_MODE_DIFF_IMAGES = "diffImages"; | ||||
|  | ||||
| const std::string TerrainViewPattern::RULE_DIRT = "D"; | ||||
| const std::string TerrainViewPattern::RULE_SAND = "S"; | ||||
| const std::string TerrainViewPattern::RULE_TRANSITION = "T"; | ||||
| const std::string TerrainViewPattern::RULE_NATIVE = "N"; | ||||
| const std::string TerrainViewPattern::RULE_ANY = "?"; | ||||
|  | ||||
| TerrainViewPattern::TerrainViewPattern() : minPoints(0), flipMode(FLIP_MODE_SAME_IMAGE), | ||||
| 	terGroup(ETerrainGroup::NORMAL) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| CTerrainViewPatternConfig::CTerrainViewPatternConfig() | ||||
| { | ||||
| 	const JsonNode config(ResourceID("config/terrainViewPatterns.json")); | ||||
| 	const std::map<std::string, ETerrainGroup::ETerrainGroup> terGroups | ||||
| 			= boost::assign::map_list_of("normal", ETerrainGroup::NORMAL)("dirt", ETerrainGroup::DIRT) | ||||
| 			("sand", ETerrainGroup::SAND)("water", ETerrainGroup::WATER)("rock", ETerrainGroup::ROCK); | ||||
| 	BOOST_FOREACH(auto terMapping, terGroups) | ||||
| 	{ | ||||
| 		BOOST_FOREACH(const JsonNode & ptrnNode, config[terMapping.first].Vector()) | ||||
| 		{ | ||||
| 			TerrainViewPattern pattern; | ||||
|  | ||||
| 			// Read pattern data | ||||
| 			const JsonVector & data = ptrnNode["data"].Vector(); | ||||
| 			if(data.size() != 9) | ||||
| 			{ | ||||
| 				throw std::runtime_error("Size of pattern's data vector has to be 9."); | ||||
| 			} | ||||
| 			for(int i = 0; i < data.size(); ++i) | ||||
| 			{ | ||||
| 				std::string cell = data[i].String(); | ||||
| 				boost::algorithm::erase_all(cell, " "); | ||||
| 				std::vector<std::string> rules; | ||||
| 				boost::split(rules, cell, boost::is_any_of(",")); | ||||
| 				BOOST_FOREACH(std::string ruleStr, rules) | ||||
| 				{ | ||||
| 					std::vector<std::string> rule; | ||||
| 					boost::split(rule, ruleStr, boost::is_any_of("-")); | ||||
| 					std::pair<std::string, int> pair; | ||||
| 					pair.first = rule[0]; | ||||
| 					if(rule.size() > 1) | ||||
| 					{ | ||||
| 						pair.second = boost::lexical_cast<int>(rule[1]); | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						pair.second = 0; | ||||
| 					} | ||||
| 					pattern.data[i].push_back(pair); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			// Read mapping | ||||
| 			std::string mappingStr = ptrnNode["mapping"].String(); | ||||
| 			boost::algorithm::erase_all(mappingStr, " "); | ||||
| 			std::vector<std::string> mappings; | ||||
| 			boost::split(mappings, mappingStr, boost::is_any_of(",")); | ||||
| 			BOOST_FOREACH(std::string mapping, mappings) | ||||
| 			{ | ||||
| 				std::vector<std::string> range; | ||||
| 				boost::split(range, mapping, boost::is_any_of("-")); | ||||
| 				pattern.mapping.push_back(std::make_pair(boost::lexical_cast<int>(range[0]), | ||||
| 					boost::lexical_cast<int>(range.size() > 1 ? range[1] : range[0]))); | ||||
| 			} | ||||
|  | ||||
| 			// Read optional attributes | ||||
| 			pattern.id = ptrnNode["id"].String(); | ||||
| 			pattern.minPoints = static_cast<int>(ptrnNode["minPoints"].Float()); | ||||
| 			pattern.flipMode = ptrnNode["flipMode"].String(); | ||||
| 			if(pattern.flipMode.empty()) | ||||
| 			{ | ||||
| 				pattern.flipMode = TerrainViewPattern::FLIP_MODE_SAME_IMAGE; | ||||
| 			} | ||||
|  | ||||
| 			pattern.terGroup = terMapping.second; | ||||
| 			patterns[terMapping.second].push_back(pattern); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| const std::vector<TerrainViewPattern> & CTerrainViewPatternConfig::getPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const | ||||
| { | ||||
| 	return patterns.find(terGroup)->second; | ||||
| } | ||||
|  | ||||
| CMapEditManager::CMapEditManager(const CTerrainViewPatternConfig * terViewPatternConfig, CMap * map, int randomSeed /*= std::time(nullptr)*/) | ||||
| 	: map(map), terViewPatternConfig(terViewPatternConfig) | ||||
| { | ||||
| 	gen.seed(randomSeed); | ||||
| } | ||||
|  | ||||
| void CMapEditManager::clearTerrain() | ||||
| { | ||||
| 	for(int i = 0; i < map->width; ++i) | ||||
| 	{ | ||||
| 		for(int j = 0; j < map->height; ++j) | ||||
| 		{ | ||||
| 			map->terrain[i][j][0].terType = ETerrainType::WATER; | ||||
| 			map->terrain[i][j][0].terView = gen.getInteger(20, 32); | ||||
|  | ||||
| 			if(map->twoLevel) | ||||
| 			{ | ||||
| 				map->terrain[i][j][1].terType = ETerrainType::ROCK; | ||||
| 				map->terrain[i][j][1].terView = 0; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CMapEditManager::drawTerrain(ETerrainType::ETerrainType terType, int posx, int posy, int width, int height, bool underground) | ||||
| { | ||||
| 	bool mapLevel = underground ? 1 : 0; | ||||
| 	for(int i = posx; i < posx + width; ++i) | ||||
| 	{ | ||||
| 		for(int j = posy; j < posy + height; ++j) | ||||
| 		{ | ||||
| 			map->terrain[i][j][mapLevel].terType = terType; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//TODO there are situations where more tiles are affected implicitely | ||||
| 	//TODO add coastal bit to extTileFlags appropriately | ||||
|  | ||||
| 	//updateTerrainViews(posx - 1, posy - 1, width + 2, height + 2, mapLevel); | ||||
| } | ||||
|  | ||||
| void CMapEditManager::updateTerrainViews(int posx, int posy, int width, int height, int mapLevel) | ||||
| { | ||||
| 	for(int i = posx; i < posx + width; ++i) | ||||
| 	{ | ||||
| 		for(int j = posy; j < posy + height; ++j) | ||||
| 		{ | ||||
| 			const std::vector<TerrainViewPattern> & patterns = | ||||
| 					terViewPatternConfig->getPatternsForGroup(getTerrainGroup(map->terrain[i][j][mapLevel].terType)); | ||||
|  | ||||
| 			// Detect a pattern which fits best | ||||
| 			int totalPoints, bestPattern, bestFlip = -1; | ||||
| 			std::string transitionReplacement; | ||||
| 			for(int i = 0; i < patterns.size(); ++i) | ||||
| 			{ | ||||
| 				const TerrainViewPattern & pattern = patterns[i]; | ||||
|  | ||||
| 				for(int flip = 0; flip < 3; ++flip) | ||||
| 				{ | ||||
| 					ValidationResult valRslt = validateTerrainView(i, j, mapLevel, flip > 0 ? getFlippedPattern(pattern, flip) : pattern); | ||||
| 					if(valRslt.result) | ||||
| 					{ | ||||
| 						if(valRslt.points > totalPoints) | ||||
| 						{ | ||||
| 							totalPoints = valRslt.points; | ||||
| 							bestPattern = i; | ||||
| 							bestFlip = flip; | ||||
| 							transitionReplacement = valRslt.transitionReplacement; | ||||
| 						} | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			if(bestPattern == -1) | ||||
| 			{ | ||||
| 				continue; | ||||
| 			} | ||||
|  | ||||
| 			// Get mapping | ||||
| 			const TerrainViewPattern & pattern = patterns[bestPattern]; | ||||
| 			std::pair<int, int> mapping; | ||||
| 			if(transitionReplacement.empty()) | ||||
| 			{ | ||||
| 				mapping = pattern.mapping[0]; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				mapping = transitionReplacement == TerrainViewPattern::RULE_DIRT ? pattern.mapping[0] : pattern.mapping[1]; | ||||
| 			} | ||||
|  | ||||
| 			// Set terrain view | ||||
| 			if(pattern.flipMode == TerrainViewPattern::FLIP_MODE_SAME_IMAGE) | ||||
| 			{ | ||||
| 				map->terrain[i][j][mapLevel].terView = gen.getInteger(mapping.first, mapping.second); | ||||
| 				map->terrain[i][j][mapLevel].extTileFlags = bestFlip; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				int range = (mapping.second - mapping.first) / 4; | ||||
| 				map->terrain[i][j][mapLevel].terView = gen.getInteger(mapping.first + bestFlip * range, | ||||
| 					mapping.first + (bestFlip + 1) * range - 1); | ||||
| 				map->terrain[i][j][mapLevel].extTileFlags =	0; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| ETerrainGroup::ETerrainGroup CMapEditManager::getTerrainGroup(ETerrainType::ETerrainType terType) const | ||||
| { | ||||
| 	switch(terType) | ||||
| 	{ | ||||
| 	case ETerrainType::DIRT: | ||||
| 		return ETerrainGroup::DIRT; | ||||
| 	case ETerrainType::SAND: | ||||
| 		return ETerrainGroup::SAND; | ||||
| 	case ETerrainType::WATER: | ||||
| 		return ETerrainGroup::WATER; | ||||
| 	case ETerrainType::ROCK: | ||||
| 		return ETerrainGroup::ROCK; | ||||
| 	default: | ||||
| 		return ETerrainGroup::NORMAL; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| CMapEditManager::ValidationResult CMapEditManager::validateTerrainView(int posx, int posy, int mapLevel, const TerrainViewPattern & pattern) const | ||||
| { | ||||
| 	ETerrainType::ETerrainType centerTerType = map->terrain[posx][posy][mapLevel].terType; | ||||
| 	int totalPoints = 0; | ||||
| 	std::string transitionReplacement; | ||||
|  | ||||
| 	for(int i = 0; i < 9; ++i) | ||||
| 	{ | ||||
| 		// The center, middle cell can be skipped | ||||
| 		if(i == 4) | ||||
| 		{ | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		// Get terrain group of the current cell | ||||
| 		int cx = posx + (i % 3) - 1; | ||||
| 		int cy = posy + (i / 3) - 1; | ||||
| 		bool isAlien = false; | ||||
| 		ETerrainType::ETerrainType terType; | ||||
| 		if(cx < 0 || cx >= map->width || cy < 0 || cy >= map->height) | ||||
| 		{ | ||||
| 			terType = centerTerType; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			terType = map->terrain[cx][cy][mapLevel].terType; | ||||
| 			if(terType != centerTerType) | ||||
| 			{ | ||||
| 				isAlien = true; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Validate all rules per cell | ||||
| 		int topPoints = -1; | ||||
| 		for(int j = 0; j < pattern.data[i].size(); ++j) | ||||
| 		{ | ||||
| 			const std::pair<std::string, int> & rulePair = pattern.data[i][j]; | ||||
| 			const std::string & rule = rulePair.first; | ||||
| 			bool isNative = (rule == TerrainViewPattern::RULE_NATIVE || rule == TerrainViewPattern::RULE_ANY) && !isAlien; | ||||
| 			auto validationRslt = [&](bool rslt) | ||||
| 			{ | ||||
| 				if(rslt) | ||||
| 				{ | ||||
| 					topPoints = std::max(topPoints, rulePair.second); | ||||
| 				} | ||||
| 				return rslt; | ||||
| 			}; | ||||
|  | ||||
| 			// Validate cell with the ruleset of the pattern | ||||
| 			bool validation; | ||||
| 			if(pattern.terGroup == ETerrainGroup::NORMAL) | ||||
| 			{ | ||||
| 				bool isDirt = (rule == TerrainViewPattern::RULE_DIRT | ||||
| 						|| rule == TerrainViewPattern::RULE_TRANSITION || rule == TerrainViewPattern::RULE_ANY) | ||||
| 						&& isAlien && !isSandType(terType); | ||||
| 				bool isSand = (rule == TerrainViewPattern::RULE_SAND || rule == TerrainViewPattern::RULE_TRANSITION | ||||
| 						|| rule == TerrainViewPattern::RULE_ANY) | ||||
| 						&& isSandType(terType); | ||||
|  | ||||
| 				if(transitionReplacement.empty() && (rule == TerrainViewPattern::RULE_TRANSITION | ||||
| 					|| rule == TerrainViewPattern::RULE_ANY) && (isDirt || isSand)) | ||||
| 				{ | ||||
| 					transitionReplacement = isDirt ? TerrainViewPattern::RULE_DIRT : TerrainViewPattern::RULE_SAND; | ||||
| 				} | ||||
| 				validation = validationRslt((isDirt && transitionReplacement != TerrainViewPattern::RULE_SAND) | ||||
| 						|| (isSand && transitionReplacement != TerrainViewPattern::RULE_DIRT) | ||||
| 						|| isNative); | ||||
| 			} | ||||
| 			else if(pattern.terGroup == ETerrainGroup::DIRT) | ||||
| 			{ | ||||
| 				bool isSand = rule == TerrainViewPattern::RULE_SAND && isSandType(terType); | ||||
| 				bool isDirt = rule == TerrainViewPattern::RULE_DIRT && !isSandType(terType) && !isNative; | ||||
| 				validation = validationRslt(rule == TerrainViewPattern::RULE_ANY || isSand || isDirt || isNative); | ||||
| 			} | ||||
| 			else if(pattern.terGroup == ETerrainGroup::SAND || pattern.terGroup == ETerrainGroup::WATER || | ||||
| 					pattern.terGroup == ETerrainGroup::ROCK) | ||||
| 			{ | ||||
| 				bool isSand = rule == TerrainViewPattern::RULE_SAND && isSandType(terType) && !isNative; | ||||
| 				validation = validationRslt(rule == TerrainViewPattern::RULE_ANY || isSand || isNative); | ||||
| 			} | ||||
| 			if(!validation) | ||||
| 			{ | ||||
| 				return ValidationResult(false); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if(topPoints == -1) | ||||
| 		{ | ||||
| 			return ValidationResult(false); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			totalPoints += topPoints; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if(pattern.minPoints > totalPoints) | ||||
| 	{ | ||||
| 		return ValidationResult(false); | ||||
| 	} | ||||
|  | ||||
| 	return ValidationResult(true, totalPoints, transitionReplacement); | ||||
| } | ||||
|  | ||||
| bool CMapEditManager::isSandType(ETerrainType::ETerrainType terType) const | ||||
| { | ||||
| 	switch(terType) | ||||
| 	{ | ||||
| 	case ETerrainType::WATER: | ||||
| 	case ETerrainType::SAND: | ||||
| 	case ETerrainType::ROCK: | ||||
| 		return true; | ||||
| 	default: | ||||
| 		return false; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| TerrainViewPattern CMapEditManager::getFlippedPattern(const TerrainViewPattern & pattern, int flip) const | ||||
| { | ||||
| 	if(flip == 0) | ||||
| 	{ | ||||
| 		return pattern; | ||||
| 	} | ||||
|  | ||||
| 	TerrainViewPattern ret = pattern; | ||||
| 	if(flip == FLIP_PATTERN_HORIZONTAL || flip == FLIP_PATTERN_BOTH) | ||||
| 	{ | ||||
| 		for(int i = 0; i < 3; ++i) | ||||
| 		{ | ||||
| 			int y = i * 3; | ||||
| 			std::swap(ret.data[y], ret.data[y + 2]); | ||||
| 		} | ||||
| 	} | ||||
| 	if(flip == FLIP_PATTERN_VERTICAL || flip == FLIP_PATTERN_BOTH) | ||||
| 	{ | ||||
| 		for(int i = 0; i < 3; ++i) | ||||
| 		{ | ||||
| 			std::swap(ret.data[i], ret.data[6 + i]); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| void CMapEditManager::insertObject(CGObjectInstance * obj, int posx, int posy, bool underground) | ||||
| { | ||||
| 	obj->pos = int3(posx, posy, underground ? 1 : 0); | ||||
| 	obj->id = map->objects.size(); | ||||
| 	map->objects.push_back(obj); | ||||
| 	if(obj->ID == Obj::TOWN) | ||||
| 	{ | ||||
| 		map->towns.push_back(static_cast<CGTownInstance *>(obj)); | ||||
| 	} | ||||
| 	if(obj->ID == Obj::HERO) | ||||
| 	{ | ||||
| 		map->heroes.push_back(static_cast<CGHeroInstance*>(obj)); | ||||
| 	} | ||||
| 	map->addBlockVisTiles(obj); | ||||
| } | ||||
|  | ||||
| CMapEditManager::ValidationResult::ValidationResult(bool result, int points /*= 0*/, const std::string & transitionReplacement /*= ""*/) | ||||
| 	: result(result), points(points), transitionReplacement(transitionReplacement) | ||||
| { | ||||
|  | ||||
| } | ||||
							
								
								
									
										264
									
								
								lib/Mapping/CMapEditManager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								lib/Mapping/CMapEditManager.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,264 @@ | ||||
|  | ||||
| /* | ||||
|  * CMapEditManager.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 "../CRandomGenerator.h" | ||||
| #include "CMap.h" | ||||
|  | ||||
| class CGObjectInstance; | ||||
|  | ||||
| namespace ETerrainGroup | ||||
| { | ||||
| 	/** | ||||
| 	 * This enumeration lists terrain groups which differ in the terrain view frames alignment. | ||||
| 	 */ | ||||
| 	enum ETerrainGroup | ||||
| 	{ | ||||
| 		NORMAL, | ||||
| 		DIRT, | ||||
| 		SAND, | ||||
| 		WATER, | ||||
| 		ROCK | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * The terrain view pattern describes a specific composition of terrain tiles | ||||
|  * in a 3x3 matrix and notes which terrain view frame numbers can be used. | ||||
|  */ | ||||
| struct TerrainViewPattern | ||||
| { | ||||
| 	/** Constant for the flip mode same image. Pattern will be flipped and the same image will be used(which is given in the mapping). */ | ||||
| 	static const std::string FLIP_MODE_SAME_IMAGE; | ||||
|  | ||||
| 	/** Constant for the flip mode different images. Pattern will be flipped and different images will be used(mapping area is divided into 4 parts) */ | ||||
| 	static const std::string FLIP_MODE_DIFF_IMAGES; | ||||
|  | ||||
| 	/** Constant for the rule dirt, meaning a dirty border is required. */ | ||||
| 	static const std::string RULE_DIRT; | ||||
|  | ||||
| 	/** Constant for the rule sand, meaning a sandy border is required. */ | ||||
| 	static const std::string RULE_SAND; | ||||
|  | ||||
| 	/** Constant for the rule transition, meaning a dirty OR sandy border is required. */ | ||||
| 	static const std::string RULE_TRANSITION; | ||||
|  | ||||
| 	/** Constant for the rule native, meaning a native type is required. */ | ||||
| 	static const std::string RULE_NATIVE; | ||||
|  | ||||
| 	/** Constant for the rule any, meaning a native type, dirty OR sandy border is required. */ | ||||
| 	static const std::string RULE_ANY; | ||||
|  | ||||
| 	/** | ||||
| 	 * Default constructor. | ||||
| 	 */ | ||||
| 	TerrainViewPattern(); | ||||
|  | ||||
| 	/** | ||||
| 	 * The pattern data. | ||||
| 	 * | ||||
| 	 * It can be visualized as a 3x3 matrix: | ||||
| 	 * [ ][ ][ ] | ||||
| 	 * [ ][ ][ ] | ||||
| 	 * [ ][ ][ ] | ||||
| 	 * | ||||
| 	 * The box in the center belongs always to the native terrain type and | ||||
| 	 * is the point of origin. Depending on the terrain type different rules | ||||
| 	 * can be used. Their meaning differs also from type to type. | ||||
| 	 * | ||||
| 	 * std::vector -> several rules can be used in one cell | ||||
| 	 * std::pair   -> combination of the name of the rule and a optional number of points | ||||
| 	 */ | ||||
| 	std::array<std::vector<std::pair<std::string, int> >, 9> data; | ||||
|  | ||||
| 	/** The identifier of the pattern, if it's referenced from a another pattern. */ | ||||
| 	std::string id; | ||||
|  | ||||
| 	/** | ||||
| 	 * This describes the mapping between this pattern and the corresponding range of frames | ||||
| 	 * which should be used for the ter view. | ||||
| 	 * | ||||
| 	 * std::vector -> size=1: typical, size=2: if this pattern should map to two different types of borders | ||||
| 	 * std::pair   -> 1st value: lower range, 2nd value: upper range | ||||
| 	 */ | ||||
| 	std::vector<std::pair<int, int> > mapping; | ||||
|  | ||||
| 	/** The minimum points to reach to to validate the pattern successfully. */ | ||||
| 	int minPoints; | ||||
|  | ||||
| 	/** Describes if flipping is required and which mapping should be used. */ | ||||
| 	std::string flipMode; | ||||
|  | ||||
| 	/** The terrain group to which the pattern belongs to. */ | ||||
| 	ETerrainGroup::ETerrainGroup terGroup; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * The terrain view pattern config loads pattern data from the filesystem. | ||||
|  */ | ||||
| class CTerrainViewPatternConfig | ||||
| { | ||||
| public: | ||||
| 	/** | ||||
| 	 * Constructor. Initializes the patterns data. | ||||
| 	 */ | ||||
| 	CTerrainViewPatternConfig(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the patterns for a specific group of terrain. | ||||
| 	 * | ||||
| 	 * @param terGroup the terrain group e.g. normal for grass, lava,... OR dirt OR sand,... | ||||
| 	 * @return a vector containing patterns | ||||
| 	 */ | ||||
| 	const std::vector<TerrainViewPattern> & getPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const; | ||||
|  | ||||
| private: | ||||
| 	/** The patterns data. */ | ||||
| 	std::map<ETerrainGroup::ETerrainGroup, std::vector<TerrainViewPattern> > patterns; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * The map edit manager provides functionality for drawing terrain and placing | ||||
|  * objects on the map. | ||||
|  * | ||||
|  * TODO add undo / selection functionality for the map editor | ||||
|  */ | ||||
| class CMapEditManager | ||||
| { | ||||
| public: | ||||
| 	/** | ||||
| 	 * Constructor. The map object / terrain data has to be initialized. | ||||
| 	 * | ||||
| 	 * @param terViewPatternConfig the terrain view pattern config | ||||
| 	 * @param map the map object which should be edited | ||||
| 	 * @param randomSeed optional. the seed which is used for generating randomly terrain views | ||||
| 	 */ | ||||
| 	CMapEditManager(const CTerrainViewPatternConfig * terViewPatternConfig, CMap * map, int randomSeed = std::time(nullptr)); | ||||
|  | ||||
| 	/** | ||||
| 	 * Clears the terrain. The free level is filled with water and the | ||||
| 	 * underground level with rock. | ||||
| 	 */ | ||||
| 	void clearTerrain(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Draws terrain. | ||||
| 	 * | ||||
| 	 * @param terType the type of the terrain to draw | ||||
| 	 * @param posx the x coordinate | ||||
| 	 * @param posy the y coordinate | ||||
| 	 * @param width the height of the terrain to draw | ||||
| 	 * @param height the width of the terrain to draw | ||||
| 	 * @param underground true if you want to draw at the underground, false if open | ||||
| 	 */ | ||||
| 	void drawTerrain(ETerrainType::ETerrainType terType, int posx, int posy, int width, int height, bool underground); | ||||
|  | ||||
| 	/** | ||||
| 	 * Inserts an object. | ||||
| 	 * | ||||
| 	 * @param obj the object to insert | ||||
| 	 * @param posx the x coordinate | ||||
| 	 * @param posy the y coordinate | ||||
| 	 * @param underground true if you want to draw at the underground, false if open | ||||
| 	 */ | ||||
| 	void insertObject(CGObjectInstance * obj, int posx, int posy, bool underground); | ||||
|  | ||||
| private: | ||||
| 	/** | ||||
| 	 * The validation result struct represents the result of a pattern validation. | ||||
| 	 */ | ||||
| 	struct ValidationResult | ||||
| 	{ | ||||
| 		/** | ||||
| 		 * Constructor. | ||||
| 		 * | ||||
| 		 * @param result the result of the validation either true or false | ||||
| 		 * @param points optional. the points which were achieved with that pattern | ||||
| 		 * @param transitionReplacement optional. the replacement of a T rule, either D or S | ||||
| 		 */ | ||||
| 		ValidationResult(bool result, int points = 0, const std::string & transitionReplacement = ""); | ||||
|  | ||||
| 		/** The result of the validation. */ | ||||
| 		bool result; | ||||
|  | ||||
| 		/** The points which were achieved with that pattern. */ | ||||
| 		int points; | ||||
|  | ||||
| 		/** The replacement of a T rule, either D or S. */ | ||||
| 		std::string transitionReplacement; | ||||
| 	}; | ||||
|  | ||||
| 	/** | ||||
| 	 * Updates the terrain view ids in the specified area. | ||||
| 	 * | ||||
| 	 * @param posx the x coordinate | ||||
| 	 * @param posy the y coordinate | ||||
| 	 * @param width the height of the terrain to update | ||||
| 	 * @param height the width of the terrain to update | ||||
| 	 * @param mapLevel the map level, 0 for open and 1 for underground | ||||
| 	 */ | ||||
| 	void updateTerrainViews(int posx, int posy, int width, int height, int mapLevel); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the terrain group by the terrain type number. | ||||
| 	 * | ||||
| 	 * @param terType the terrain type | ||||
| 	 * @return the terrain group | ||||
| 	 */ | ||||
| 	ETerrainGroup::ETerrainGroup getTerrainGroup(ETerrainType::ETerrainType terType) const; | ||||
|  | ||||
| 	/** | ||||
| 	 * Validates the terrain view of the given position and with the given pattern. | ||||
| 	 * | ||||
| 	 * @param posx the x position | ||||
| 	 * @param posy the y position | ||||
| 	 * @param mapLevel the map level, 0 for open and 1 for underground | ||||
| 	 * @param pattern the pattern to validate the terrain view with | ||||
| 	 * @return a validation result struct | ||||
| 	 */ | ||||
| 	ValidationResult validateTerrainView(int posx, int posy, int mapLevel, const TerrainViewPattern & pattern) const; | ||||
|  | ||||
| 	/** | ||||
| 	 * Tests whether the given terrain type is a sand type. Sand types are: Water, Sand and Rock | ||||
| 	 * | ||||
| 	 * @param terType the terrain type to test | ||||
| 	 * @return true if the terrain type is a sand type, otherwise false | ||||
| 	 */ | ||||
| 	bool isSandType(ETerrainType::ETerrainType terType) const; | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets a flipped pattern. | ||||
| 	 * | ||||
| 	 * @param pattern the original pattern to flip | ||||
| 	 * @param flip the flip mode value, see FLIP_PATTERN_* constants for details | ||||
| 	 * @return the flipped pattern | ||||
| 	 */ | ||||
| 	TerrainViewPattern getFlippedPattern(const TerrainViewPattern & pattern, int flip) const; | ||||
|  | ||||
| 	/** Constant for flipping a pattern horizontally. */ | ||||
| 	static const int FLIP_PATTERN_HORIZONTAL = 1; | ||||
|  | ||||
| 	/** Constant for flipping a pattern vertically. */ | ||||
| 	static const int FLIP_PATTERN_VERTICAL = 2; | ||||
|  | ||||
| 	/** Constant for flipping a pattern horizontally and vertically. */ | ||||
| 	static const int FLIP_PATTERN_BOTH = 3; | ||||
|  | ||||
| 	/** The map object to edit. */ | ||||
| 	CMap * map; | ||||
|  | ||||
| 	/** The random number generator. */ | ||||
| 	CRandomGenerator gen; | ||||
|  | ||||
| 	/** The terrain view pattern config. */ | ||||
| 	const CTerrainViewPatternConfig * terViewPatternConfig; | ||||
| }; | ||||
| @@ -40,6 +40,6 @@ public: | ||||
| 	template <typename Handler> void serialize(Handler &h, const int Version) | ||||
| 	{ | ||||
| 		h & mapHeader & campaignHeader & scenarioOpts & fileURI & date & playerAmnt & humanPlayers; | ||||
| 		h & actualHumanPlayers; | ||||
| 		h & actualHumanPlayers & isRandomMap; | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -173,7 +173,7 @@ void CMapLoaderH3M::init() | ||||
| 	for(int f = 0; f < map->objects.size(); ++f) | ||||
| 	{ | ||||
| 		if(!map->objects[f]->defInfo) continue; | ||||
| 		addBlockVisibleTiles(map->objects[f]); | ||||
| 		map->addBlockVisTiles(map->objects[f]); | ||||
| 	} | ||||
| 	times.push_back(MapLoadingTime("blocked/visitable tiles", sw.getDiff())); | ||||
|  | ||||
| @@ -231,8 +231,7 @@ void CMapLoaderH3M::readHeader() | ||||
|  | ||||
| void CMapLoaderH3M::readPlayerInfo() | ||||
| { | ||||
| 	mapHeader->players.resize(8); | ||||
| 	for(int i = 0; i < 8; ++i) | ||||
| 	for(int i = 0; i < mapHeader->players.size(); ++i) | ||||
| 	{ | ||||
| 		mapHeader->players[i].canHumanPlay = static_cast<bool>(buffer[pos++]); | ||||
| 		mapHeader->players[i].canComputerPlay = static_cast<bool>(buffer[pos++]); | ||||
| @@ -865,7 +864,7 @@ CArtifactInstance * CMapLoaderH3M::createArtifact(int aid, int spellID /*= -1*/) | ||||
| 		a = new CArtifactInstance(); | ||||
| 	} | ||||
|  | ||||
| 	addNewArtifactInstance(a); | ||||
| 	map->addNewArtifactInstance(a); | ||||
|  | ||||
| 	//TODO make it nicer | ||||
| 	if(a->artType && a->artType->constituents) | ||||
| @@ -873,31 +872,16 @@ CArtifactInstance * CMapLoaderH3M::createArtifact(int aid, int spellID /*= -1*/) | ||||
| 		CCombinedArtifactInstance * comb = dynamic_cast<CCombinedArtifactInstance *>(a); | ||||
| 		BOOST_FOREACH(CCombinedArtifactInstance::ConstituentInfo & ci, comb->constituentsInfo) | ||||
| 		{ | ||||
| 			addNewArtifactInstance(ci.art); | ||||
| 			map->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 ? 2 : 1]; | ||||
| 		} | ||||
| 	} | ||||
| 	map->initTerrain(); | ||||
|  | ||||
| 	// Read terrain | ||||
| 	for(int a = 0; a < 2; ++a) | ||||
| @@ -1276,7 +1260,7 @@ void CMapLoaderH3M::readObjects() | ||||
| 		case Obj::SEER_HUT: | ||||
| 			{ | ||||
| 				nobj = readSeerHut(); | ||||
| 				addQuest(nobj); | ||||
| 				map->addQuest(nobj); | ||||
| 				break; | ||||
| 			} | ||||
| 		case Obj::WITCH_HUT:  | ||||
| @@ -1584,7 +1568,7 @@ void CMapLoaderH3M::readObjects() | ||||
| 	case Obj::QUEST_GUARD: | ||||
| 			{ | ||||
| 				CGQuestGuard * guard = new CGQuestGuard(); | ||||
| 				addQuest(guard); | ||||
| 				map->addQuest(guard); | ||||
| 				readQuest(guard); | ||||
| 				nobj = guard; | ||||
| 				break; | ||||
| @@ -1672,13 +1656,13 @@ void CMapLoaderH3M::readObjects() | ||||
| 		case Obj::BORDERGUARD: | ||||
| 			{ | ||||
| 				nobj = new CGBorderGuard(); | ||||
| 				addQuest(nobj); | ||||
| 				map->addQuest(nobj); | ||||
| 				break; | ||||
| 			} | ||||
| 		case Obj::BORDER_GATE: | ||||
| 			{ | ||||
| 				nobj = new CGBorderGate(); | ||||
| 				addQuest (nobj); | ||||
| 				map->addQuest (nobj); | ||||
| 				break; | ||||
| 			} | ||||
| 		case Obj::EYE_OF_MAGI:  | ||||
| @@ -2244,17 +2228,9 @@ void CMapLoaderH3M::readQuest(IQuestObject * guard) | ||||
| 	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); | ||||
| @@ -2421,16 +2397,8 @@ CGTownInstance * CMapLoaderH3M::readTown(int castleID) | ||||
| 		nt->alignment = buffer[pos]; | ||||
| 		++pos; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		nt->alignment = 0xff; | ||||
| 	} | ||||
| 	pos += 3; | ||||
|  | ||||
| 	nt->builded = 0; | ||||
| 	nt->destroyed = 0; | ||||
| 	nt->garrisonHero = nullptr; | ||||
|  | ||||
| 	return nt; | ||||
| } | ||||
|  | ||||
| @@ -2549,33 +2517,6 @@ void CMapLoaderH3M::readEvents() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| 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; | ||||
|   | ||||
| @@ -225,13 +225,6 @@ private: | ||||
| 	 */ | ||||
| 	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. | ||||
| 	 */ | ||||
| @@ -288,13 +281,6 @@ private: | ||||
| 	 */ | ||||
| 	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. | ||||
| 	 * | ||||
| @@ -318,13 +304,6 @@ private: | ||||
| 	 */ | ||||
| 	void readEvents(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Adds object instance to block visitable tiles. | ||||
| 	 * | ||||
| 	 * @param obj the object to add | ||||
| 	 */ | ||||
| 	void addBlockVisibleTiles(CGObjectInstance * obj); | ||||
|  | ||||
| 	/** | ||||
| 	 * Reverses the input argument. | ||||
| 	 * | ||||
|   | ||||
| @@ -1,8 +1,10 @@ | ||||
| #include "StdInc.h" | ||||
| #include "CMapGenOptions.h" | ||||
|  | ||||
| #include "../GameConstants.h" | ||||
|  | ||||
| CMapGenOptions::CMapGenOptions() : width(72), height(72), hasTwoLevels(true), | ||||
| 	playersCnt(-1), teamsCnt(-1), compOnlyPlayersCnt(0), compOnlyTeamsCnt(-1), | ||||
| 	playersCnt(RANDOM_SIZE), teamsCnt(RANDOM_SIZE), compOnlyPlayersCnt(0), compOnlyTeamsCnt(RANDOM_SIZE), | ||||
| 	waterContent(EWaterContent::RANDOM), monsterStrength(EMonsterStrength::RANDOM) | ||||
| { | ||||
|  | ||||
| @@ -13,7 +15,7 @@ si32 CMapGenOptions::getWidth() const | ||||
| 	return width; | ||||
| } | ||||
|  | ||||
| void CMapGenOptions::setWidth(int value) | ||||
| void CMapGenOptions::setWidth(si32 value) | ||||
| { | ||||
| 	if(value > 0) | ||||
| 	{ | ||||
| @@ -21,7 +23,7 @@ void CMapGenOptions::setWidth(int value) | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		throw std::runtime_error("Map width lower than 1 not allowed."); | ||||
| 		throw std::runtime_error("A map width lower than 1 is not allowed."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -38,7 +40,7 @@ void CMapGenOptions::setHeight(si32 value) | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		throw std::runtime_error("Map height lower than 1 not allowed."); | ||||
| 		throw std::runtime_error("A map height lower than 1 is not allowed."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -59,13 +61,14 @@ si8 CMapGenOptions::getPlayersCnt() const | ||||
|  | ||||
| void CMapGenOptions::setPlayersCnt(si8 value) | ||||
| { | ||||
| 	if((value >= 1 && value <= 8) || value == RANDOM_SIZE) | ||||
| 	if((value >= 1 && value <= GameConstants::PLAYER_LIMIT) || value == RANDOM_SIZE) | ||||
| 	{ | ||||
| 		playersCnt = value; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		throw std::runtime_error("Players count of RMG options should be between 1 and 8 or -1 for random."); | ||||
| 		throw std::runtime_error("Players count of RMG options should be between 1 and " + | ||||
| 			boost::lexical_cast<std::string>(GameConstants::PLAYER_LIMIT) + " or CMapGenOptions::RANDOM_SIZE for random."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -83,7 +86,7 @@ void CMapGenOptions::setTeamsCnt(si8 value) | ||||
| 	else | ||||
| 	{ | ||||
| 		throw std::runtime_error("Teams count of RMG options should be between 0 and <" + | ||||
| 			boost::lexical_cast<std::string>(playersCnt) + "(players count) - 1> or -1 for random."); | ||||
| 			boost::lexical_cast<std::string>(playersCnt) + "(players count) - 1> or CMapGenOptions::RANDOM_SIZE for random."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -94,15 +97,15 @@ si8 CMapGenOptions::getCompOnlyPlayersCnt() const | ||||
|  | ||||
| void CMapGenOptions::setCompOnlyPlayersCnt(si8 value) | ||||
| { | ||||
| 	if(value == RANDOM_SIZE || (value >= 0 && value <= 8 - playersCnt)) | ||||
| 	if(value == RANDOM_SIZE || (value >= 0 && value <= GameConstants::PLAYER_LIMIT - playersCnt)) | ||||
| 	{ | ||||
| 		compOnlyPlayersCnt = value; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		throw std::runtime_error(std::string("Computer only players count of RMG options should be ") + | ||||
| 			"between 0 and <8 - " + boost::lexical_cast<std::string>(playersCnt) + | ||||
| 			"(playersCount)> or -1 for random."); | ||||
| 			"between 0 and <GameConstants::PLAYER_LIMIT - " + boost::lexical_cast<std::string>(playersCnt) + | ||||
| 			"(playersCount)> or CMapGenOptions::RANDOM_SIZE for random."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -113,7 +116,7 @@ si8 CMapGenOptions::getCompOnlyTeamsCnt() const | ||||
|  | ||||
| void CMapGenOptions::setCompOnlyTeamsCnt(si8 value) | ||||
| { | ||||
| 	if(value == RANDOM_SIZE || compOnlyPlayersCnt == RANDOM_SIZE || (value >= 0 && value <= compOnlyPlayersCnt - 1)) | ||||
| 	if(value == RANDOM_SIZE || compOnlyPlayersCnt == RANDOM_SIZE || (value >= 0 && value <= std::max(compOnlyPlayersCnt - 1, 0))) | ||||
| 	{ | ||||
| 		compOnlyTeamsCnt = value; | ||||
| 	} | ||||
| @@ -121,7 +124,7 @@ void CMapGenOptions::setCompOnlyTeamsCnt(si8 value) | ||||
| 	{ | ||||
| 		throw std::runtime_error(std::string("Computer only teams count of RMG options should be ") + | ||||
| 			"between 0 and <" + boost::lexical_cast<std::string>(compOnlyPlayersCnt) + | ||||
| 			"(compOnlyPlayersCnt) - 1> or -1 for random."); | ||||
| 			"(compOnlyPlayersCnt) - 1> or CMapGenOptions::RANDOM_SIZE for random."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -89,61 +89,61 @@ public: | ||||
| 	void setHasTwoLevels(bool value); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the count of the players. The default value is -1 representing a random | ||||
| 	 * Gets the count of the players. The default value is RANDOM_SIZE representing a random | ||||
| 	 * player count. | ||||
| 	 * | ||||
| 	 * @return the count of the players ranging from 1 to 8 or -1 for random | ||||
| 	 * @return the count of the players ranging from 1 to GameConstants::PLAYER_LIMIT or RANDOM_SIZE for random | ||||
| 	 */ | ||||
| 	si8 getPlayersCnt() const; | ||||
|  | ||||
| 	/** | ||||
| 	 * Sets the count of the players. | ||||
| 	 * | ||||
| 	 * @param value the count of the players ranging from 1 to 8, -1 for random | ||||
| 	 * @param value the count of the players ranging from 1 to GameConstants::PLAYER_LIMIT, RANDOM_SIZE for random | ||||
| 	 */ | ||||
| 	void setPlayersCnt(si8 value); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the count of the teams. The default value is -1 representing a random | ||||
| 	 * Gets the count of the teams. The default value is RANDOM_SIZE representing a random | ||||
| 	 * team count. | ||||
| 	 * | ||||
| 	 * @return the count of the teams ranging from 0 to <players count - 1> or -1 for random | ||||
| 	 * @return the count of the teams ranging from 0 to <players count - 1> or RANDOM_SIZE for random | ||||
| 	 */ | ||||
| 	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 | ||||
| 	 * @param value the count of the teams ranging from 0 to <players count - 1>, RANDOM_SIZE for random | ||||
| 	 */ | ||||
| 	void setTeamsCnt(si8 value); | ||||
|  | ||||
| 	/** | ||||
| 	 * 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> or -1 for random | ||||
| 	 * @return the count of the computer only players ranging from 0 to <GameConstants::PLAYER_LIMIT - players count> or RANDOM_SIZE for random | ||||
| 	 */ | ||||
| 	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 | ||||
| 	 * @param value the count of the computer only players ranging from 0 to <GameConstants::PLAYER_LIMIT - players count>, RANDOM_SIZE for random | ||||
| 	 */ | ||||
| 	void setCompOnlyPlayersCnt(si8 value); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the count of the computer only teams. The default value is -1 representing | ||||
| 	 * Gets the count of the computer only teams. The default value is RANDOM_SIZE representing | ||||
| 	 * a random computer only team count. | ||||
| 	 * | ||||
| 	 * @return the count of the computer only teams ranging from 0 to <comp only players - 1> or -1 for random | ||||
| 	 * @return the count of the computer only teams ranging from 0 to <comp only players - 1> or RANDOM_SIZE for random | ||||
| 	 */ | ||||
| 	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 | ||||
| 	 * @param value the count of the computer only teams ranging from 0 to <comp only players - 1>, RANDOM_SIZE for random | ||||
| 	 */ | ||||
| 	void setCompOnlyTeamsCnt(si8 value); | ||||
|  | ||||
| @@ -213,6 +213,8 @@ public: | ||||
| 	template <typename Handler> | ||||
| 	void serialize(Handler & h, const int version) | ||||
| 	{ | ||||
| 		//FIXME: Enum is not a fixed with data type. Add enum class to both enums | ||||
| 		// later. For now it is ok. | ||||
| 		h & width & height & hasTwoLevels & playersCnt & teamsCnt & compOnlyPlayersCnt; | ||||
| 		h & compOnlyTeamsCnt & waterContent & monsterStrength; | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										399
									
								
								lib/RMG/CMapGenerator.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										399
									
								
								lib/RMG/CMapGenerator.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,399 @@ | ||||
| #include "StdInc.h" | ||||
| #include "CMapGenerator.h" | ||||
|  | ||||
| #include "../Mapping/CMap.h" | ||||
| #include "../VCMI_Lib.h" | ||||
| #include "../CGeneralTextHandler.h" | ||||
| #include "../Mapping/CMapEditManager.h" | ||||
| #include "../CObjectHandler.h" | ||||
| #include "../CDefObjInfoHandler.h" | ||||
| #include "../GameConstants.h" | ||||
| #include "../CTownHandler.h" | ||||
| #include "../StringConstants.h" | ||||
|  | ||||
| CMapGenerator::CMapGenerator(const CMapGenOptions & mapGenOptions, const std::map<TPlayerColor, CPlayerSettings> & players, int randomSeed) : | ||||
| 	mapGenOptions(mapGenOptions), randomSeed(randomSeed), players(players) | ||||
| { | ||||
| 	gen.seed(randomSeed); | ||||
| 	validateOptions(); | ||||
| } | ||||
|  | ||||
| CMapGenerator::~CMapGenerator() | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| std::unique_ptr<CMap> CMapGenerator::generate() | ||||
| { | ||||
| 	finalizeMapGenOptions(); | ||||
|  | ||||
| 	//TODO select a template based on the map gen options or adapt it if necessary | ||||
|  | ||||
| 	map = std::unique_ptr<CMap>(new CMap()); | ||||
| 	addHeaderInfo(); | ||||
|  | ||||
| 	terViewPatternConfig = std::unique_ptr<CTerrainViewPatternConfig>(new CTerrainViewPatternConfig()); | ||||
| 	mapMgr = std::unique_ptr<CMapEditManager>(new CMapEditManager(terViewPatternConfig.get(), map.get(), randomSeed)); | ||||
| 	genTerrain(); | ||||
| 	genTowns(); | ||||
|  | ||||
| 	return std::move(map); | ||||
| } | ||||
|  | ||||
| void CMapGenerator::validateOptions() const | ||||
| { | ||||
| 	int playersCnt = 0; | ||||
| 	int compOnlyPlayersCnt = 0; | ||||
| 	BOOST_FOREACH(const tPlayersMap::value_type & pair, players) | ||||
| 	{ | ||||
| 		if(pair.second.getPlayerType() == CPlayerSettings::COMP_ONLY) | ||||
| 		{ | ||||
| 			++compOnlyPlayersCnt; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			++playersCnt; | ||||
| 		} | ||||
| 	} | ||||
| 	if(mapGenOptions.getPlayersCnt() == CMapGenOptions::RANDOM_SIZE) | ||||
| 	{ | ||||
| 		if(playersCnt != GameConstants::PLAYER_LIMIT) | ||||
| 		{ | ||||
| 			throw std::runtime_error(std::string("If the count of players is random size, ") | ||||
| 				+ "the count of the items in the players map should equal GameConstants::PLAYER_LIMIT."); | ||||
| 		} | ||||
| 		if(playersCnt == mapGenOptions.getPlayersCnt()) | ||||
| 		{ | ||||
| 			throw std::runtime_error(std::string("If the count of players is random size, ") | ||||
| 				+ "all items in the players map should be either of player type AI or HUMAN."); | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if(mapGenOptions.getCompOnlyPlayersCnt() != CMapGenOptions::RANDOM_SIZE) | ||||
| 		{ | ||||
| 			if(playersCnt != mapGenOptions.getPlayersCnt() || compOnlyPlayersCnt != mapGenOptions.getCompOnlyPlayersCnt()) | ||||
| 			{ | ||||
| 				throw std::runtime_error(std::string("The count of players and computer only players in the players map ") | ||||
| 					+ "doesn't conform with the specified map gen options."); | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if(playersCnt != mapGenOptions.getPlayersCnt() || (playersCnt == mapGenOptions.getPlayersCnt() | ||||
| 				&& compOnlyPlayersCnt != GameConstants::PLAYER_LIMIT - playersCnt)) | ||||
| 			{ | ||||
| 				throw std::runtime_error(std::string("If the count of players is fixed and the count of comp only players random, ") | ||||
| 					+ "the items in the players map should equal GameConstants::PLAYER_LIMIT."); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if(countHumanPlayers() < 1) | ||||
| 	{ | ||||
| 		throw std::runtime_error("1 human player is required at least"); | ||||
| 	} | ||||
|  | ||||
| 	BOOST_FOREACH(const tPlayersMap::value_type & pair, players) | ||||
| 	{ | ||||
| 		if(pair.first != pair.second.getColor()) | ||||
| 		{ | ||||
| 			throw std::runtime_error("The color of an item in player settings and the key of it has to be the same."); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CMapGenerator::finalizeMapGenOptions() | ||||
| { | ||||
| 	if(mapGenOptions.getPlayersCnt() == CMapGenOptions::RANDOM_SIZE) | ||||
| 	{ | ||||
| 		mapGenOptions.setPlayersCnt(gen.getInteger(countHumanPlayers(), GameConstants::PLAYER_LIMIT)); | ||||
|  | ||||
| 		// Remove AI players only from the end of the players map if necessary | ||||
| 		for(auto itrev = players.end(); itrev != players.begin();) | ||||
| 		{ | ||||
| 			auto it = itrev; | ||||
| 			--it; | ||||
| 			if(players.size() == mapGenOptions.getPlayersCnt()) | ||||
| 			{ | ||||
| 				break; | ||||
| 			} | ||||
| 			const CPlayerSettings & pSettings = it->second; | ||||
| 			if(pSettings.getPlayerType() == CPlayerSettings::AI) | ||||
| 			{ | ||||
| 				players.erase(it); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				--itrev; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if(mapGenOptions.getTeamsCnt() == CMapGenOptions::RANDOM_SIZE) | ||||
| 	{ | ||||
| 		mapGenOptions.setTeamsCnt(gen.getInteger(0, mapGenOptions.getPlayersCnt() - 1)); | ||||
| 	} | ||||
| 	if(mapGenOptions.getCompOnlyPlayersCnt() == CMapGenOptions::RANDOM_SIZE) | ||||
| 	{ | ||||
| 		mapGenOptions.setCompOnlyPlayersCnt(gen.getInteger(0, 8 - mapGenOptions.getPlayersCnt())); | ||||
| 		int totalPlayersCnt = mapGenOptions.getPlayersCnt() + mapGenOptions.getCompOnlyPlayersCnt(); | ||||
|  | ||||
| 		// Remove comp only players only from the end of the players map if necessary | ||||
| 		for(auto itrev = players.end(); itrev != players.begin();) | ||||
| 		{ | ||||
| 			auto it = itrev; | ||||
| 			--it; | ||||
| 			if(players.size() <= totalPlayersCnt) | ||||
| 			{ | ||||
| 				break; | ||||
| 			} | ||||
| 			const CPlayerSettings & pSettings = it->second; | ||||
| 			if(pSettings.getPlayerType() == CPlayerSettings::COMP_ONLY) | ||||
| 			{ | ||||
| 				players.erase(it); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				--itrev; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Add some comp only players if necessary | ||||
| 		int compOnlyPlayersToAdd = totalPlayersCnt - players.size(); | ||||
| 		for(int i = 0; i < compOnlyPlayersToAdd; ++i) | ||||
| 		{ | ||||
| 			CPlayerSettings pSettings; | ||||
| 			pSettings.setPlayerType(CPlayerSettings::COMP_ONLY); | ||||
| 			pSettings.setColor(getNextPlayerColor()); | ||||
| 			players[pSettings.getColor()] = pSettings; | ||||
| 		} | ||||
| 	} | ||||
| 	if(mapGenOptions.getCompOnlyTeamsCnt() == CMapGenOptions::RANDOM_SIZE) | ||||
| 	{ | ||||
| 		mapGenOptions.setCompOnlyTeamsCnt(gen.getInteger(0, std::max(mapGenOptions.getCompOnlyPlayersCnt() - 1, 0))); | ||||
| 	} | ||||
|  | ||||
| 	// There should be at least 2 players (1-player-maps aren't allowed) | ||||
| 	if(mapGenOptions.getPlayersCnt() + mapGenOptions.getCompOnlyPlayersCnt() < 2) | ||||
| 	{ | ||||
| 		CPlayerSettings pSettings; | ||||
| 		pSettings.setPlayerType(CPlayerSettings::AI); | ||||
| 		pSettings.setColor(getNextPlayerColor()); | ||||
| 		players[pSettings.getColor()] = pSettings; | ||||
| 		mapGenOptions.setPlayersCnt(2); | ||||
| 	} | ||||
|  | ||||
| 	// 1 team isn't allowed | ||||
| 	if(mapGenOptions.getTeamsCnt() == 1 && mapGenOptions.getCompOnlyPlayersCnt() == 0) | ||||
| 	{ | ||||
| 		mapGenOptions.setTeamsCnt(0); | ||||
| 	} | ||||
|  | ||||
| 	if(mapGenOptions.getWaterContent() == EWaterContent::RANDOM) | ||||
| 	{ | ||||
| 		mapGenOptions.setWaterContent(static_cast<EWaterContent::EWaterContent>(gen.getInteger(0, 2))); | ||||
| 	} | ||||
| 	if(mapGenOptions.getMonsterStrength() == EMonsterStrength::RANDOM) | ||||
| 	{ | ||||
| 		mapGenOptions.setMonsterStrength(static_cast<EMonsterStrength::EMonsterStrength>(gen.getInteger(0, 2))); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| std::string CMapGenerator::getMapDescription() const | ||||
| { | ||||
| 	const std::string waterContentStr[3] = { "none", "normal", "islands" }; | ||||
| 	const std::string monsterStrengthStr[3] = { "weak", "normal", "strong" }; | ||||
|  | ||||
| 	std::stringstream ss; | ||||
| 	ss << "Map created by the Random Map Generator.\nTemplate was <MOCK>, "; | ||||
| 	ss << "Random seed was " << randomSeed << ", size " << map->width << "x"; | ||||
| 	ss << map->height << ", levels " << (map->twoLevel ? "2" : "1") << ", "; | ||||
| 	ss << "humans " << static_cast<int>(mapGenOptions.getPlayersCnt()) << ", computers "; | ||||
| 	ss << static_cast<int>(mapGenOptions.getCompOnlyPlayersCnt()) << ", water " << waterContentStr[mapGenOptions.getWaterContent()]; | ||||
| 	ss << ", monster " << monsterStrengthStr[mapGenOptions.getMonsterStrength()] << ", second expansion map"; | ||||
|  | ||||
| 	BOOST_FOREACH(const tPlayersMap::value_type & pair, players) | ||||
| 	{ | ||||
| 		const CPlayerSettings & pSettings = pair.second; | ||||
| 		if(pSettings.getPlayerType() == CPlayerSettings::HUMAN) | ||||
| 		{ | ||||
| 			ss << ", " << GameConstants::PLAYER_COLOR_NAMES[pSettings.getColor()] << " is human"; | ||||
| 		} | ||||
| 		if(pSettings.getStartingTown() != CPlayerSettings::RANDOM_TOWN) | ||||
| 		{ | ||||
| 			ss << ", " << GameConstants::PLAYER_COLOR_NAMES[pSettings.getColor()] | ||||
| 				<< " town choice is " << ETownType::names[pSettings.getStartingTown()]; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return ss.str(); | ||||
| } | ||||
|  | ||||
| void CMapGenerator::addPlayerInfo() | ||||
| { | ||||
| 	// Calculate which team numbers exist | ||||
| 	std::array<std::list<int>, 2> teamNumbers; // 0= cpu/human, 1= cpu only | ||||
| 	int teamOffset = 0; | ||||
| 	for(int i = 0; i < 2; ++i) | ||||
| 	{ | ||||
| 		int playersCnt = i == 0 ? mapGenOptions.getPlayersCnt() : mapGenOptions.getCompOnlyPlayersCnt(); | ||||
| 		int teamsCnt = i == 0 ? mapGenOptions.getTeamsCnt() : mapGenOptions.getCompOnlyTeamsCnt(); | ||||
|  | ||||
| 		if(playersCnt == 0) | ||||
| 		{ | ||||
| 			continue; | ||||
| 		} | ||||
| 		int playersPerTeam = playersCnt / | ||||
| 				(teamsCnt == 0 ? playersCnt : teamsCnt); | ||||
| 		int teamsCntNorm = teamsCnt; | ||||
| 		if(teamsCntNorm == 0) | ||||
| 		{ | ||||
| 			teamsCntNorm = playersCnt; | ||||
| 		} | ||||
| 		for(int j = 0; j < teamsCntNorm; ++j) | ||||
| 		{ | ||||
| 			for(int k = 0; k < playersPerTeam; ++k) | ||||
| 			{ | ||||
| 				teamNumbers[i].push_back(j + teamOffset); | ||||
| 			} | ||||
| 		} | ||||
| 		for(int j = 0; j < playersCnt - teamsCntNorm * playersPerTeam; ++j) | ||||
| 		{ | ||||
| 			teamNumbers[i].push_back(j + teamOffset); | ||||
| 		} | ||||
| 		teamOffset += teamsCntNorm; | ||||
| 	} | ||||
|  | ||||
| 	// Team numbers are assigned randomly to every player | ||||
| 	BOOST_FOREACH(const tPlayersMap::value_type & pair, players) | ||||
| 	{ | ||||
| 		const CPlayerSettings & pSettings = pair.second; | ||||
| 		PlayerInfo player; | ||||
| 		player.canComputerPlay = true; | ||||
| 		int j = pSettings.getPlayerType() == CPlayerSettings::COMP_ONLY ? 1 : 0; | ||||
| 		if(j == 0) | ||||
| 		{ | ||||
| 			player.canHumanPlay = true; | ||||
| 		} | ||||
| 		auto itTeam = std::next(teamNumbers[j].begin(), gen.getInteger(0, teamNumbers[j].size() - 1)); | ||||
| 		player.team = *itTeam; | ||||
| 		teamNumbers[j].erase(itTeam); | ||||
| 		map->players[pSettings.getColor()] = player; | ||||
| 	} | ||||
|  | ||||
| 	map->howManyTeams = (mapGenOptions.getTeamsCnt() == 0 ? mapGenOptions.getPlayersCnt() : mapGenOptions.getTeamsCnt()) | ||||
| 			+ (mapGenOptions.getCompOnlyTeamsCnt() == 0 ? mapGenOptions.getCompOnlyPlayersCnt() : mapGenOptions.getCompOnlyTeamsCnt()); | ||||
| } | ||||
|  | ||||
| int CMapGenerator::countHumanPlayers() const | ||||
| { | ||||
| 	return static_cast<int>(std::count_if(players.begin(), players.end(), [](const std::pair<TPlayerColor, CPlayerSettings> & pair) | ||||
| 	{ | ||||
| 		return pair.second.getPlayerType() == CPlayerSettings::HUMAN; | ||||
| 	})); | ||||
| } | ||||
|  | ||||
| void CMapGenerator::genTerrain() | ||||
| { | ||||
| 	map->initTerrain(); //FIXME nicer solution | ||||
| 	mapMgr->clearTerrain(); | ||||
| 	mapMgr->drawTerrain(ETerrainType::GRASS, 10, 10, 20, 30, false); | ||||
| } | ||||
|  | ||||
| void CMapGenerator::genTowns() | ||||
| { | ||||
| 	//FIXME mock gen | ||||
| 	const int3 townPos[2] = { int3(17, 13, 0), int3(25,13, 0) }; | ||||
| 	const TFaction townTypes[2] = { ETownType::CASTLE, ETownType::DUNGEON }; | ||||
|  | ||||
| 	for(auto it = players.begin(); it != players.end(); ++it) | ||||
| 	{ | ||||
| 		TPlayerColor owner = it->first; | ||||
| 		int pos = std::distance(players.begin(), it); | ||||
| 		int side = pos % 2; | ||||
| 		CGTownInstance * town = new CGTownInstance(); | ||||
| 		town->ID = Obj::TOWN; | ||||
| 		town->subID = townTypes[side]; | ||||
| 		town->tempOwner = owner; | ||||
| 		town->defInfo = VLC->dobjinfo->gobjs[town->ID][town->subID]; | ||||
| 		town->builtBuildings.insert(EBuilding::FORT); | ||||
| 		town->builtBuildings.insert(-50); | ||||
| 		mapMgr->insertObject(town, townPos[side].x, townPos[side].y + (pos / 2) * 5, false); | ||||
| 		map->players[owner].allowedFactions.clear(); | ||||
| 		map->players[owner].allowedFactions.insert(townTypes[side]); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CMapGenerator::addHeaderInfo() | ||||
| { | ||||
| 	map->version = EMapFormat::SOD; | ||||
| 	map->width = mapGenOptions.getWidth(); | ||||
| 	map->height = mapGenOptions.getHeight(); | ||||
| 	map->twoLevel = mapGenOptions.getHasTwoLevels(); | ||||
| 	map->name = VLC->generaltexth->allTexts[740]; | ||||
| 	map->description = getMapDescription(); | ||||
| 	map->difficulty = 1; | ||||
| 	addPlayerInfo(); | ||||
| } | ||||
|  | ||||
| TPlayerColor CMapGenerator::getNextPlayerColor() const | ||||
| { | ||||
| 	for(TPlayerColor i = 0; i < GameConstants::PLAYER_LIMIT; ++i) | ||||
| 	{ | ||||
| 		if(players.find(i) == players.end()) | ||||
| 		{ | ||||
| 			return i; | ||||
| 		} | ||||
| 	} | ||||
| 	throw std::runtime_error("Shouldn't happen. No free player color exists."); | ||||
| } | ||||
|  | ||||
| CMapGenerator::CPlayerSettings::CPlayerSettings() : color(0), startingTown(RANDOM_TOWN), playerType(AI) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| int CMapGenerator::CPlayerSettings::getColor() const | ||||
| { | ||||
| 	return color; | ||||
| } | ||||
|  | ||||
|  | ||||
| void CMapGenerator::CPlayerSettings::setColor(int value) | ||||
| { | ||||
| 	if(value >= 0 && value < GameConstants::PLAYER_LIMIT) | ||||
| 	{ | ||||
| 		color = value; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		throw std::runtime_error("The color of the player is not in a valid range."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int CMapGenerator::CPlayerSettings::getStartingTown() const | ||||
| { | ||||
| 	return startingTown; | ||||
| } | ||||
|  | ||||
| void CMapGenerator::CPlayerSettings::setStartingTown(int value) | ||||
| { | ||||
| 	if(value >= -1 && value < static_cast<int>(VLC->townh->towns.size())) | ||||
| 	{ | ||||
| 		startingTown = value; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		throw std::runtime_error("The starting town of the player is not in a valid range."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| CMapGenerator::CPlayerSettings::EPlayerType CMapGenerator::CPlayerSettings::getPlayerType() const | ||||
| { | ||||
| 	return playerType; | ||||
| } | ||||
|  | ||||
| void CMapGenerator::CPlayerSettings::setPlayerType(EPlayerType value) | ||||
| { | ||||
| 	playerType = value; | ||||
| } | ||||
							
								
								
									
										199
									
								
								lib/RMG/CMapGenerator.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								lib/RMG/CMapGenerator.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | ||||
|  | ||||
| /* | ||||
|  * CMapGenerator.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 "../GameConstants.h" | ||||
| #include "CMapGenOptions.h" | ||||
| #include "../CRandomGenerator.h" | ||||
|  | ||||
| class CMap; | ||||
| class CTerrainViewPatternConfig; | ||||
| class CMapEditManager; | ||||
|  | ||||
| /** | ||||
|  * The map generator creates a map randomly. | ||||
|  */ | ||||
| class CMapGenerator | ||||
| { | ||||
| public: | ||||
| 	/** | ||||
| 	 * The player settings class maps the player color, starting town and human player flag. | ||||
| 	 */ | ||||
| 	class CPlayerSettings | ||||
| 	{ | ||||
| 	public: | ||||
| 		enum EPlayerType | ||||
| 		{ | ||||
| 			HUMAN, | ||||
| 			AI, | ||||
| 			COMP_ONLY | ||||
| 		}; | ||||
|  | ||||
| 		/** | ||||
| 		 * Constructor. | ||||
| 		 */ | ||||
| 		CPlayerSettings(); | ||||
|  | ||||
| 		/** | ||||
| 		 * Gets the color of the player. The default value is 0. | ||||
| 		 * | ||||
| 		 * @return the color of the player ranging from 0 to GameConstants::PLAYER_LIMIT - 1 | ||||
| 		 */ | ||||
| 		int getColor() const; | ||||
|  | ||||
| 		/** | ||||
| 		 * Sets the color of the player. | ||||
| 		 * | ||||
| 		 * @param value the color of the player ranging from 0 to GameConstants::PLAYER_LIMIT - 1 | ||||
| 		 */ | ||||
| 		void setColor(int value); | ||||
|  | ||||
| 		/** | ||||
| 		 * Gets the starting town of the player. The default value is RANDOM_TOWN. | ||||
| 		 * | ||||
| 		 * @return the starting town of the player ranging from 0 to town max count or RANDOM_TOWN | ||||
| 		 */ | ||||
| 		int getStartingTown() const; | ||||
|  | ||||
| 		/** | ||||
| 		 * Sets the starting town of the player. | ||||
| 		 * | ||||
| 		 * @param value the starting town of the player ranging from 0 to town max count or RANDOM_TOWN | ||||
| 		 */ | ||||
| 		void setStartingTown(int value); | ||||
|  | ||||
| 		/** | ||||
| 		 * Gets the type of the player. The default value is EPlayerType::AI. | ||||
| 		 * | ||||
| 		 * @return the type of the player | ||||
| 		 */ | ||||
| 		EPlayerType getPlayerType() const; | ||||
|  | ||||
| 		/** | ||||
| 		 * Sets the type of the player. | ||||
| 		 * | ||||
| 		 * @param playerType the type of the player | ||||
| 		 */ | ||||
| 		void setPlayerType(EPlayerType value); | ||||
|  | ||||
| 		/** Constant for a random town selection. */ | ||||
| 		static const int RANDOM_TOWN = -1; | ||||
|  | ||||
| 	private: | ||||
| 		/** The color of the player. */ | ||||
| 		int color; | ||||
|  | ||||
| 		/** The starting town of the player. */ | ||||
| 		int startingTown; | ||||
|  | ||||
| 		/** The type of the player e.g. human, comp only,... */ | ||||
| 		EPlayerType playerType; | ||||
| 	}; | ||||
|  | ||||
| 	/** | ||||
| 	 * Constructor. | ||||
| 	 * | ||||
| 	 * @param mapGenOptions these options describe how to generate the map. | ||||
| 	 * @param players the random gen player settings | ||||
| 	 * @param randomSeed a random seed is required to get random numbers. | ||||
| 	 */ | ||||
| 	CMapGenerator(const CMapGenOptions & mapGenOptions, const std::map<TPlayerColor, CPlayerSettings> & players, int randomSeed); | ||||
|  | ||||
| 	/** | ||||
| 	 * Destructor. | ||||
| 	 */ | ||||
| 	~CMapGenerator(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Generates a map. | ||||
| 	 * | ||||
| 	 * @return the generated map object stored in a unique ptr | ||||
| 	 */ | ||||
| 	std::unique_ptr<CMap> generate(); | ||||
|  | ||||
| private: | ||||
| 	/** | ||||
| 	 * Validates map gen options and players options. On errors exceptions will be thrown. | ||||
| 	 */ | ||||
| 	void validateOptions() const; | ||||
|  | ||||
| 	/** | ||||
| 	 * Finalizes map generation options. Random sizes for various properties are | ||||
| 	 * converted to fixed values. | ||||
| 	 */ | ||||
| 	void finalizeMapGenOptions(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the map description of the generated map. | ||||
| 	 * | ||||
| 	 * @return the map description of the generated map | ||||
| 	 */ | ||||
| 	std::string getMapDescription() const; | ||||
|  | ||||
| 	/** | ||||
| 	 * Adds player information.(teams, colors, etc...) | ||||
| 	 */ | ||||
| 	void addPlayerInfo(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Counts the amount of human players. | ||||
| 	 * | ||||
| 	 * @return the amount of human players ranging from 0 to GameConstants::PLAYER_LIMIT | ||||
| 	 */ | ||||
| 	int countHumanPlayers() const; | ||||
|  | ||||
| 	/** | ||||
| 	 * Generate terrain. | ||||
| 	 */ | ||||
| 	void genTerrain(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Generate towns. | ||||
| 	 */ | ||||
| 	void genTowns(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Adds header info(size, description, etc...) | ||||
| 	 */ | ||||
| 	void addHeaderInfo(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the next free player color. | ||||
| 	 * | ||||
| 	 * @return the next free player color | ||||
| 	 */ | ||||
| 	TPlayerColor getNextPlayerColor() const; | ||||
|  | ||||
| 	/** The map options which describes the size of the map and contain player info. */ | ||||
| 	CMapGenOptions mapGenOptions; | ||||
|  | ||||
| 	/** The generated map. */ | ||||
| 	std::unique_ptr<CMap> map; | ||||
|  | ||||
| 	/** The random number generator. */ | ||||
| 	CRandomGenerator gen; | ||||
|  | ||||
| 	/** The random seed, it is used for the map description. */ | ||||
| 	int randomSeed; | ||||
|  | ||||
| 	/** The terrain view pattern config. */ | ||||
| 	std::unique_ptr<CTerrainViewPatternConfig> terViewPatternConfig; | ||||
|  | ||||
| 	/** The map edit manager. */ | ||||
| 	std::unique_ptr<CMapEditManager> mapMgr; | ||||
|  | ||||
| 	/** The random gen player settings. */ | ||||
| 	std::map<TPlayerColor, CPlayerSettings> players; | ||||
|  | ||||
| 	/** Typedef of the players map, so that boost foreach can be used. */ | ||||
| 	typedef std::map<TPlayerColor, CPlayerSettings> tPlayersMap; | ||||
| }; | ||||
| @@ -42,6 +42,7 @@ struct PlayerSettings | ||||
|  | ||||
| 	std::string name; | ||||
| 	ui8 playerID; //0 - AI, non-0 serves as player id | ||||
| 	bool compOnly; //true if this player is a computer only player; required for RMG | ||||
| 	template <typename Handler> | ||||
| 	void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| @@ -55,13 +56,12 @@ struct PlayerSettings | ||||
| 		h & name; | ||||
| 		h & playerID; | ||||
| 		h & team; | ||||
| 		h & compOnly; | ||||
| 	} | ||||
|  | ||||
| 	PlayerSettings() | ||||
| 	PlayerSettings() : bonus(RANDOM), castle(NONE), heroPortrait(RANDOM), compOnly(false) | ||||
| 	{ | ||||
| 		bonus = RANDOM; | ||||
| 		castle = NONE; | ||||
| 		heroPortrait = RANDOM; | ||||
| 		 | ||||
| 	} | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -31,6 +31,9 @@ namespace GameConstants | ||||
| 	    "demoniac",  "heretic",    "deathknight", "necromancer", "warlock",      "overlord", | ||||
| 	    "barbarian", "battlemage", "beastmaster", "witch",       "planeswalker", "elementalist" | ||||
| 	}; | ||||
| 	const std::string PLAYER_COLOR_NAMES [PLAYER_LIMIT] = { | ||||
| 		"red", "blue", "tan", "green", "orange", "purple", "teal", "pink" | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| namespace EAlignment | ||||
|   | ||||
| @@ -197,7 +197,9 @@ | ||||
|     <ClCompile Include="Mapping\CMap.cpp" /> | ||||
|     <ClCompile Include="Mapping\CMapInfo.cpp" /> | ||||
|     <ClCompile Include="Mapping\CMapService.cpp" /> | ||||
|     <ClCompile Include="Mapping\CMapEditManager.cpp" /> | ||||
|     <ClCompile Include="RMG\CMapGenOptions.cpp" /> | ||||
|     <ClCompile Include="RMG\CMapGenerator.cpp" /> | ||||
|     <ClCompile Include="HeroBonus.cpp" /> | ||||
|     <ClCompile Include="CBattleCallback.cpp" /> | ||||
|     <ClCompile Include="IGameCallback.cpp" /> | ||||
| @@ -239,6 +241,7 @@ | ||||
|     <ClInclude Include="CondSh.h" /> | ||||
|     <ClInclude Include="Connection.h" /> | ||||
|     <ClInclude Include="ConstTransitivePtr.h" /> | ||||
|     <ClInclude Include="CRandomGenerator.h" /> | ||||
|     <ClInclude Include="CScriptingModule.h" /> | ||||
|     <ClInclude Include="CSpellHandler.h" /> | ||||
|     <ClInclude Include="CStopWatch.h" /> | ||||
| @@ -258,7 +261,9 @@ | ||||
|     <ClInclude Include="Mapping\CMap.h" /> | ||||
|     <ClInclude Include="Mapping\CMapInfo.h" /> | ||||
|     <ClInclude Include="Mapping\CMapService.h" /> | ||||
|     <ClInclude Include="Mapping\CMapEditManager.h" /> | ||||
|     <ClInclude Include="RMG\CMapGenOptions.h" /> | ||||
|     <ClInclude Include="RMG\CMapGenerator.h" /> | ||||
|     <ClInclude Include="GameConstants.h" /> | ||||
|     <ClInclude Include="HeroBonus.h" /> | ||||
|     <ClInclude Include="CBattleCallback.h" /> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user