mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	- Implemented updating additional terrain types fully(including 2 special cases)
This commit is contained in:
		| @@ -1,4 +1,4 @@ | ||||
| // Defines terrain view patterns. | ||||
| // Defines terrain view/types patterns. | ||||
|  | ||||
| // The following table shows the rules for the 3x3 pattern of all terrain types:  | ||||
| // I) normal(e.g. grass, lava, ...): | ||||
| @@ -8,7 +8,7 @@ | ||||
| // T:		Sand OR dirt border(all Ts in the pattern are replaced by dirt OR sand) | ||||
| // ?:		D,S or N | ||||
| // II) dirt: | ||||
| // N:		Native type | ||||
| // N:		Native type or normal type(grass, lava, ...) | ||||
| // S:		Sand border | ||||
| // ?:		Any border | ||||
| // III) sand: | ||||
| @@ -18,216 +18,271 @@ | ||||
| // S:		Sand border | ||||
| // ?:		Any border | ||||
|  | ||||
| // Additional rule for validiting terrain type: | ||||
| // N!:		Native type always(unlike N for dirt) | ||||
|  | ||||
| // The order of the patterns is important, do not change! | ||||
| [ | ||||
| 	// Extended mixed transitions | ||||
| 	{ | ||||
| 		"id" : "x1", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"T", "N", "N", | ||||
| 			"N", "N", "T", | ||||
| 			"N", "T", "T" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "73,74", "dirt" : "45" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "x2", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"D", "D", "N", | ||||
| 			"D", "N", "N", | ||||
| 			"N", "N", "S" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "75" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "x3", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"S", "S", "N", | ||||
| 			"S", "N", "N", | ||||
| 			"N", "N", "D" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "76" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "x4", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "S", | ||||
| 			"N", "N", "D", | ||||
| 			"S", "D", "D" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "77" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "x5", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "D", | ||||
| 			"N", "N", "D", | ||||
| 			"D", "D", "S" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "78" } | ||||
| 	}, | ||||
| 	// No transition | ||||
| 	{ | ||||
| 		"id" : "n1", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "N", | ||||
| 			"N", "N", "N", | ||||
| 			"N", "N", "N" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "49-72", "dirt" : "21-44", "sand" : "0-23", "water" : "20-32", "rock": "0-7" } | ||||
| 	}, | ||||
| 	// Mixed transitions | ||||
| 	{ | ||||
| 		"id" : "m1", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"T", "N", "N", | ||||
| 			"N", "N", "N", | ||||
| 			"N", "N", "T" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "40, 42", "dirt" : "20" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "m2", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"D", "N", "N", | ||||
| 			"N", "N", "N", | ||||
| 			"N", "N", "S" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "41" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "m3", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "D,N", | ||||
| 			"N", "N", "D", | ||||
| 			"S", "D,N", "D,N" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "43" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "m4", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "S", | ||||
| 			"N", "N", "D", | ||||
| 			"D,N", "D", "D,N" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "44" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "m5", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "D", | ||||
| 			"N", "N", "D", | ||||
| 			"N", "N", "S" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "45" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "m6", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "N", | ||||
| 			"N", "N", "N", | ||||
| 			"D,N", "D", "S" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "46" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "m7", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "?", | ||||
| 			"N", "N", "S", | ||||
| 			"D-1,N", "D-1,N", "?" | ||||
| 		], | ||||
| 		"minPoints" : 1, | ||||
| 		"mapping" : { "normal" : "47" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "m8", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "D-1,N", | ||||
| 			"N", "N", "D-1,N", | ||||
| 			"?", "S", "?" | ||||
| 		], | ||||
| 		"minPoints" : 1, | ||||
| 		"mapping" : { "normal" : "48" } | ||||
| 	}, | ||||
| 	// Standard transitions | ||||
| 	{ | ||||
| 		"id" : "s1", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"T,N-1", "T,N-2", "T,N-3", | ||||
| 			"T,N-2", "N", "N", | ||||
| 			"T", "N", "N" | ||||
| 		], | ||||
| 		"maxPoints" : 3, | ||||
| 		"mapping" : { "normal" : "0-3, 20-23", "dirt" : "0-3", "water" : "0-3", "rock": "4D:8-15" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "s2", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"?", "N", "N", | ||||
| 			"T", "N", "N", | ||||
| 			"?", "N", "N" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "4-7, 24-27", "dirt" : "4-7", "water" : "4-7", "rock": "2D:16-19" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "s3", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"?", "T", "?", | ||||
| 			"N", "N", "N", | ||||
| 			"N", "N", "N" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "8-11, 28-31", "dirt" : "8-11", "water" : "8-11", "rock": "2D:20-23" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "s4", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "N", | ||||
| 			"N", "N", "s3-1,m7-1,m8-1", | ||||
| 			"N", "s2-1,m7-1,m8-1", "T" | ||||
| 		], | ||||
| 		"minPoints" : 2, | ||||
| 		"mapping" : { "normal" : "12-15, 32-35", "dirt" : "12-15", "water" : "12-15", "rock": "4D:24-31" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "s5", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"T", "T", "?", | ||||
| 			"T", "N", "s6-1,m1-1,m2-1,N", | ||||
| 			"?", "s6-1,m1-1,m2-1,N", "N" | ||||
| 		], | ||||
| 		"minPoints" : 1, | ||||
| 		"mapping" : { "normal" : "16-17, 36-37", "dirt" : "16-17", "water" : "16-17", "rock": "4D:32-39" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "s6", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "N", | ||||
| 			"N", "N", "s5-1,N", | ||||
| 			"N", "s5-1,N", "T" | ||||
| 		], | ||||
| 		"minPoints" : 1, | ||||
| 		"mapping" : { "normal" : "18-19, 38-39", "dirt" : "18-19", "water" : "18-19", "rock": "4D:40-47" } | ||||
| 	} | ||||
| ] | ||||
| { | ||||
| 	"terrainView" : | ||||
| 	[ | ||||
| 		// Extended mixed transitions | ||||
| 		{ | ||||
| 			"id" : "x1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"T", "N", "N", | ||||
| 				"N", "N", "T", | ||||
| 				"N", "T", "T" | ||||
| 			], | ||||
| 			"mapping" : { "normal" : "73,74", "dirt" : "45" } | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "x2", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"D", "D", "N", | ||||
| 				"D", "N", "N", | ||||
| 				"N", "N", "S" | ||||
| 			], | ||||
| 			"mapping" : { "normal" : "75" } | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "x3", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"S", "S", "N", | ||||
| 				"S", "N", "N", | ||||
| 				"N", "N", "D" | ||||
| 			], | ||||
| 			"mapping" : { "normal" : "76" } | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "x4", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "S", | ||||
| 				"N", "N", "D", | ||||
| 				"S", "D", "D" | ||||
| 			], | ||||
| 			"mapping" : { "normal" : "77" } | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "x5", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "D", | ||||
| 				"N", "N", "D", | ||||
| 				"D", "D", "S" | ||||
| 			], | ||||
| 			"mapping" : { "normal" : "78" } | ||||
| 		}, | ||||
| 		// No transition | ||||
| 		{ | ||||
| 			"id" : "n1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : { "normal" : "49-72", "dirt" : "21-44", "sand" : "0-23", "water" : "20-32", "rock": "0-7" } | ||||
| 		}, | ||||
| 		// Mixed transitions | ||||
| 		{ | ||||
| 			"id" : "m1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"T", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "T" | ||||
| 			], | ||||
| 			"mapping" : { "normal" : "40, 42", "dirt" : "20" } | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "m2", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"D", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "S" | ||||
| 			], | ||||
| 			"mapping" : { "normal" : "41" } | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "m3", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "D,N", | ||||
| 				"N", "N", "D", | ||||
| 				"S", "D,N", "D,N" | ||||
| 			], | ||||
| 			"mapping" : { "normal" : "43" } | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "m4", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "S", | ||||
| 				"N", "N", "D", | ||||
| 				"D,N", "D", "D,N" | ||||
| 			], | ||||
| 			"mapping" : { "normal" : "44" } | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "m5", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "D", | ||||
| 				"N", "N", "D", | ||||
| 				"N", "N", "S" | ||||
| 			], | ||||
| 			"mapping" : { "normal" : "45" } | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "m6", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"D,N", "D", "S" | ||||
| 			], | ||||
| 			"mapping" : { "normal" : "46" } | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "m7", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "?", | ||||
| 				"N", "N", "S", | ||||
| 				"D-1,N", "D-1,N", "?" | ||||
| 			], | ||||
| 			"minPoints" : 1, | ||||
| 			"mapping" : { "normal" : "47" } | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "m8", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "D-1,N", | ||||
| 				"N", "N", "D-1,N", | ||||
| 				"?", "S", "?" | ||||
| 			], | ||||
| 			"minPoints" : 1, | ||||
| 			"mapping" : { "normal" : "48" } | ||||
| 		}, | ||||
| 		// Standard transitions | ||||
| 		{ | ||||
| 			"id" : "s2", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "N", "N", | ||||
| 				"T", "N", "N", | ||||
| 				"?", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : { "normal" : "4-7, 24-27", "dirt" : "4-7", "water" : "4-7", "rock": "2D:16-19" } | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s3", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "T", "?", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : { "normal" : "8-11, 28-31", "dirt" : "8-11", "water" : "8-11", "rock": "2D:20-23" } | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s4", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "s3-1,m7-1,m8-1", | ||||
| 				"N", "s2-1,m7-1,m8-1", "T" | ||||
| 			], | ||||
| 			"minPoints" : 2, | ||||
| 			"mapping" : { "normal" : "12-15, 32-35", "dirt" : "12-15", "water" : "12-15", "rock": "4D:24-31" } | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s5", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"T", "T", "?", | ||||
| 				"T", "N", "s6-1,m1-1,m2-1,N", | ||||
| 				"?,x1-1,s1-1", "s6-1,m1-1,m2-1,N", "N" | ||||
| 			], | ||||
| 			"minPoints" : 1, | ||||
| 			"mapping" : { "normal" : "16-17, 36-37", "dirt" : "16-17", "water" : "16-17", "rock": "4D:32-39" } | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s6", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "s5-1,N", | ||||
| 				"N", "s5-1,N", "T" | ||||
| 			], | ||||
| 			"minPoints" : 1, | ||||
| 			"mapping" : { "normal" : "18-19, 38-39", "dirt" : "18-19", "water" : "18-19", "rock": "4D:40-47" } | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "?", "?", | ||||
| 				"?", "N", "N", | ||||
| 				"T", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : { "normal" : "0-3, 20-23", "dirt" : "0-3", "water" : "0-3", "rock": "4D:8-15" } | ||||
| 		} | ||||
| 	], | ||||
| 	"terrainType" : | ||||
| 	[ | ||||
| 		{ | ||||
| 			"id" : "n1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N!", "N!", "?", | ||||
| 				"N!", "N!", "?", | ||||
| 				"?", "?", "?" | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "n2", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N!", "N!", "D,S", | ||||
| 				"D,S", "N!", "N!", | ||||
| 				"D,S", "D,S", "N!" | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "n3", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"D,S", "D,S", "N!", | ||||
| 				"D,S", "N!", "N!", | ||||
| 				"N!", "N!", "D,S" | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"T", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "T-1,N", "T-1,N" | ||||
| 			], | ||||
| 			"minPoints" : 1 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s2", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "T", | ||||
| 				"T-1,N", "N", "N", | ||||
| 				"T-1,N", "N", "N" | ||||
| 			], | ||||
| 			"minPoints" : 1 | ||||
| 		}, | ||||
| 	] | ||||
| } | ||||
|   | ||||
| @@ -284,9 +284,10 @@ 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_NATIVE_STRONG = "N!"; | ||||
| const std::string TerrainViewPattern::RULE_ANY = "?"; | ||||
|  | ||||
| TerrainViewPattern::TerrainViewPattern() : diffImages(false), rotationTypesCount(0), minPoints(0), terGroup(ETerrainGroup::NORMAL) | ||||
| TerrainViewPattern::TerrainViewPattern() : diffImages(false), rotationTypesCount(0), minPoints(0) | ||||
| { | ||||
| 	maxPoints = std::numeric_limits<int>::max(); | ||||
| } | ||||
| @@ -300,7 +301,7 @@ bool TerrainViewPattern::WeightedRule::isStandardRule() const | ||||
| { | ||||
| 	return TerrainViewPattern::RULE_ANY == name || TerrainViewPattern::RULE_DIRT == name | ||||
| 		|| TerrainViewPattern::RULE_NATIVE == name || TerrainViewPattern::RULE_SAND == name | ||||
| 		|| TerrainViewPattern::RULE_TRANSITION == name; | ||||
| 		|| TerrainViewPattern::RULE_TRANSITION == name || TerrainViewPattern::RULE_NATIVE_STRONG == name; | ||||
| } | ||||
|  | ||||
| boost::mutex CTerrainViewPatternConfig::smx; | ||||
| @@ -315,70 +316,82 @@ CTerrainViewPatternConfig & CTerrainViewPatternConfig::get() | ||||
| CTerrainViewPatternConfig::CTerrainViewPatternConfig() | ||||
| { | ||||
| 	const JsonNode config(ResourceID("config/terrainViewPatterns.json")); | ||||
| 	const auto & patternsVec = config.Vector(); | ||||
| 	BOOST_FOREACH(const auto & ptrnNode, patternsVec) | ||||
| 	static const std::string patternTypes[] = { "terrainView", "terrainType" }; | ||||
| 	for(int i = 0; i < ARRAY_COUNT(patternTypes); ++i) | ||||
| 	{ | ||||
| 		TerrainViewPattern pattern; | ||||
|  | ||||
| 		// Read pattern data | ||||
| 		const JsonVector & data = ptrnNode["data"].Vector(); | ||||
| 		assert(data.size() == 9); | ||||
| 		for(int i = 0; i < data.size(); ++i) | ||||
| 		const auto & patternsVec = config[patternTypes[i]].Vector(); | ||||
| 		BOOST_FOREACH(const auto & ptrnNode, patternsVec) | ||||
| 		{ | ||||
| 			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) | ||||
| 			TerrainViewPattern pattern; | ||||
|  | ||||
| 			// Read pattern data | ||||
| 			const JsonVector & data = ptrnNode["data"].Vector(); | ||||
| 			assert(data.size() == 9); | ||||
| 			for(int i = 0; i < data.size(); ++i) | ||||
| 			{ | ||||
| 				std::vector<std::string> ruleParts; | ||||
| 				boost::split(ruleParts, ruleStr, boost::is_any_of("-")); | ||||
| 				TerrainViewPattern::WeightedRule rule; | ||||
| 				rule.name = ruleParts[0]; | ||||
| 				assert(!rule.name.empty()); | ||||
| 				if(ruleParts.size() > 1) | ||||
| 				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) | ||||
| 				{ | ||||
| 					rule.points = boost::lexical_cast<int>(ruleParts[1]); | ||||
| 					std::vector<std::string> ruleParts; | ||||
| 					boost::split(ruleParts, ruleStr, boost::is_any_of("-")); | ||||
| 					TerrainViewPattern::WeightedRule rule; | ||||
| 					rule.name = ruleParts[0]; | ||||
| 					assert(!rule.name.empty()); | ||||
| 					if(ruleParts.size() > 1) | ||||
| 					{ | ||||
| 						rule.points = boost::lexical_cast<int>(ruleParts[1]); | ||||
| 					} | ||||
| 					pattern.data[i].push_back(rule); | ||||
| 				} | ||||
| 				pattern.data[i].push_back(rule); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Read various properties | ||||
| 		pattern.id = ptrnNode["id"].String(); | ||||
| 		assert(!pattern.id.empty()); | ||||
| 		pattern.minPoints = static_cast<int>(ptrnNode["minPoints"].Float()); | ||||
| 		pattern.maxPoints = static_cast<int>(ptrnNode["maxPoints"].Float()); | ||||
| 		if(pattern.maxPoints == 0) pattern.maxPoints = std::numeric_limits<int>::max(); | ||||
| 			// Read various properties | ||||
| 			pattern.id = ptrnNode["id"].String(); | ||||
| 			assert(!pattern.id.empty()); | ||||
| 			pattern.minPoints = static_cast<int>(ptrnNode["minPoints"].Float()); | ||||
| 			pattern.maxPoints = static_cast<int>(ptrnNode["maxPoints"].Float()); | ||||
| 			if(pattern.maxPoints == 0) pattern.maxPoints = std::numeric_limits<int>::max(); | ||||
|  | ||||
| 		// Read mapping | ||||
| 		const auto & mappingStruct = ptrnNode["mapping"].Struct(); | ||||
| 		BOOST_FOREACH(const auto & mappingPair, mappingStruct) | ||||
| 		{ | ||||
| 			TerrainViewPattern terGroupPattern = pattern; | ||||
| 			auto mappingStr = mappingPair.second.String(); | ||||
| 			boost::algorithm::erase_all(mappingStr, " "); | ||||
| 			auto colonIndex = mappingStr.find_first_of(":"); | ||||
| 			const auto & flipMode = mappingStr.substr(0, colonIndex); | ||||
| 			terGroupPattern.diffImages = TerrainViewPattern::FLIP_MODE_DIFF_IMAGES == &(flipMode[flipMode.length() - 1]); | ||||
| 			if(terGroupPattern.diffImages) | ||||
| 			// Read mapping | ||||
| 			if(i == 0) | ||||
| 			{ | ||||
| 				terGroupPattern.rotationTypesCount = boost::lexical_cast<int>(flipMode.substr(0, flipMode.length() - 1)); | ||||
| 				assert(terGroupPattern.rotationTypesCount == 2 || terGroupPattern.rotationTypesCount == 4); | ||||
| 				const auto & mappingStruct = ptrnNode["mapping"].Struct(); | ||||
| 				BOOST_FOREACH(const auto & mappingPair, mappingStruct) | ||||
| 				{ | ||||
| 					TerrainViewPattern terGroupPattern = pattern; | ||||
| 					auto mappingStr = mappingPair.second.String(); | ||||
| 					boost::algorithm::erase_all(mappingStr, " "); | ||||
| 					auto colonIndex = mappingStr.find_first_of(":"); | ||||
| 					const auto & flipMode = mappingStr.substr(0, colonIndex); | ||||
| 					terGroupPattern.diffImages = TerrainViewPattern::FLIP_MODE_DIFF_IMAGES == &(flipMode[flipMode.length() - 1]); | ||||
| 					if(terGroupPattern.diffImages) | ||||
| 					{ | ||||
| 						terGroupPattern.rotationTypesCount = boost::lexical_cast<int>(flipMode.substr(0, flipMode.length() - 1)); | ||||
| 						assert(terGroupPattern.rotationTypesCount == 2 || terGroupPattern.rotationTypesCount == 4); | ||||
| 					} | ||||
| 					mappingStr = mappingStr.substr(colonIndex + 1); | ||||
| 					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("-")); | ||||
| 						terGroupPattern.mapping.push_back(std::make_pair(boost::lexical_cast<int>(range[0]), | ||||
| 							boost::lexical_cast<int>(range.size() > 1 ? range[1] : range[0]))); | ||||
| 					} | ||||
|  | ||||
| 					// Add pattern to the patterns map | ||||
| 					const auto & terGroup = getTerrainGroup(mappingPair.first); | ||||
| 					terrainViewPatterns[terGroup].push_back(terGroupPattern); | ||||
| 				} | ||||
| 			} | ||||
| 			mappingStr = mappingStr.substr(colonIndex + 1); | ||||
| 			std::vector<std::string> mappings; | ||||
| 			boost::split(mappings, mappingStr, boost::is_any_of(",")); | ||||
| 			BOOST_FOREACH(std::string mapping, mappings) | ||||
| 			else if(i == 1) | ||||
| 			{ | ||||
| 				std::vector<std::string> range; | ||||
| 				boost::split(range, mapping, boost::is_any_of("-")); | ||||
| 				terGroupPattern.mapping.push_back(std::make_pair(boost::lexical_cast<int>(range[0]), | ||||
| 					boost::lexical_cast<int>(range.size() > 1 ? range[1] : range[0]))); | ||||
| 				terrainTypePatterns[pattern.id] = pattern; | ||||
| 			} | ||||
| 			const auto & terGroup = getTerrainGroup(mappingPair.first); | ||||
| 			terGroupPattern.terGroup = terGroup; | ||||
| 			patterns[terGroup].push_back(terGroupPattern); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -398,14 +411,14 @@ ETerrainGroup::ETerrainGroup CTerrainViewPatternConfig::getTerrainGroup(const st | ||||
| 	return it->second; | ||||
| } | ||||
|  | ||||
| const std::vector<TerrainViewPattern> & CTerrainViewPatternConfig::getPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const | ||||
| const std::vector<TerrainViewPattern> & CTerrainViewPatternConfig::getTerrainViewPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const | ||||
| { | ||||
| 	return patterns.find(terGroup)->second; | ||||
| 	return terrainViewPatterns.find(terGroup)->second; | ||||
| } | ||||
|  | ||||
| boost::optional<const TerrainViewPattern &> CTerrainViewPatternConfig::getPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const | ||||
| boost::optional<const TerrainViewPattern &> CTerrainViewPatternConfig::getTerrainViewPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const | ||||
| { | ||||
| 	const std::vector<TerrainViewPattern> & groupPatterns = getPatternsForGroup(terGroup); | ||||
| 	const std::vector<TerrainViewPattern> & groupPatterns = getTerrainViewPatternsForGroup(terGroup); | ||||
| 	BOOST_FOREACH(const TerrainViewPattern & pattern, groupPatterns) | ||||
| 	{ | ||||
| 		if(id == pattern.id) | ||||
| @@ -416,6 +429,13 @@ boost::optional<const TerrainViewPattern &> CTerrainViewPatternConfig::getPatter | ||||
| 	return boost::optional<const TerrainViewPattern &>(); | ||||
| } | ||||
|  | ||||
| const TerrainViewPattern & CTerrainViewPatternConfig::getTerrainTypePatternById(const std::string & id) const | ||||
| { | ||||
| 	auto it = terrainTypePatterns.find(id); | ||||
| 	assert(it != terrainTypePatterns.end()); | ||||
| 	return it->second; | ||||
| } | ||||
|  | ||||
| CDrawTerrainOperation::CDrawTerrainOperation(CMap * map, const CTerrainSelection & terrainSel, ETerrainType terType, CRandomGenerator * gen) | ||||
| 	: CMapOperation(map), terrainSel(terrainSel), terType(terType), gen(gen) | ||||
| { | ||||
| @@ -459,9 +479,10 @@ void CDrawTerrainOperation::updateTerrainTypes() | ||||
| 		const auto & centerPos = *(positions.begin()); | ||||
| 		auto centerTile = map->getTile(centerPos); | ||||
| 		auto tiles = getInvalidTiles(centerPos); | ||||
| 		auto updateTerrainType = [&](const int3 & pos) | ||||
| 		auto updateTerrainType = [&](const int3 & pos, bool tileRequiresValidation) | ||||
| 		{ | ||||
| 			map->getTile(pos).terType = centerTile.terType; | ||||
| 			if(tileRequiresValidation) positions.insert(pos); | ||||
| 			invalidateTerrainViews(pos); | ||||
| 			logGlobal->debugStream() << boost::format("Update terrain tile at '%s' to type '%i'.") % pos % centerTile.terType; | ||||
| 		}; | ||||
| @@ -469,7 +490,7 @@ void CDrawTerrainOperation::updateTerrainTypes() | ||||
| 		// Fill foreign invalid tiles | ||||
| 		BOOST_FOREACH(const auto & tile, tiles.foreignTiles) | ||||
| 		{ | ||||
| 			updateTerrainType(tile); | ||||
| 			updateTerrainType(tile, true); | ||||
| 		} | ||||
|  | ||||
| 		if(tiles.nativeTiles.find(centerPos) != tiles.nativeTiles.end()) | ||||
| @@ -477,8 +498,7 @@ void CDrawTerrainOperation::updateTerrainTypes() | ||||
| 			// Blow up | ||||
| 			auto rect = extendTileAroundSafely(centerPos); | ||||
| 			std::set<int3> suitableTiles; | ||||
| 			int invalidForeignTilesCnt, invalidNativeTilesCnt; | ||||
| 			invalidForeignTilesCnt = invalidNativeTilesCnt = std::numeric_limits<int>::max(); | ||||
| 			int invalidForeignTilesCnt = std::numeric_limits<int>::max(), invalidNativeTilesCnt = 0; | ||||
| 			rect.forEach([&](const int3 & posToTest) | ||||
| 			{ | ||||
| 				auto & terrainTile = map->getTile(posToTest); | ||||
| @@ -490,16 +510,21 @@ void CDrawTerrainOperation::updateTerrainTypes() | ||||
| 					auto addToSuitableTiles = [&](const int3 & pos) | ||||
| 					{ | ||||
| 						suitableTiles.insert(pos); | ||||
| 						logGlobal->debugStream() << boost::format("Found suitable tile '%s' for main tile '%s'.") % pos % centerPos; | ||||
| 						logGlobal->debugStream() << boost::format(std::string("Found suitable tile '%s' for main tile '%s': ") + | ||||
| 								"Invalid native tiles '%i', invalid foreign tiles '%i'.") % pos % centerPos % testTile.nativeTiles.size() % | ||||
| 								testTile.foreignTiles.size(); | ||||
| 					}; | ||||
|  | ||||
| 					if(testTile.nativeTiles.size() < invalidNativeTilesCnt || | ||||
| 							(testTile.nativeTiles.size() == invalidNativeTilesCnt && testTile.foreignTiles.size() < invalidForeignTilesCnt)) | ||||
| 					int nativeTilesCntNorm = testTile.nativeTiles.empty() ? std::numeric_limits<int>::max() : testTile.nativeTiles.size(); | ||||
| 					if(nativeTilesCntNorm > invalidNativeTilesCnt || | ||||
| 							(nativeTilesCntNorm == invalidNativeTilesCnt && testTile.foreignTiles.size() < invalidForeignTilesCnt)) | ||||
| 					{ | ||||
| 						invalidNativeTilesCnt = nativeTilesCntNorm; | ||||
| 						invalidForeignTilesCnt = testTile.foreignTiles.size(); | ||||
| 						suitableTiles.clear(); | ||||
| 						addToSuitableTiles(posToTest); | ||||
| 					} | ||||
| 					else if(testTile.nativeTiles.size() == invalidNativeTilesCnt && | ||||
| 					else if(nativeTilesCntNorm == invalidNativeTilesCnt && | ||||
| 							testTile.foreignTiles.size() == invalidForeignTilesCnt) | ||||
| 					{ | ||||
| 						addToSuitableTiles(posToTest); | ||||
| @@ -508,20 +533,21 @@ void CDrawTerrainOperation::updateTerrainTypes() | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
| 			bool tileRequiresValidation = invalidForeignTilesCnt > 0; | ||||
| 			if(suitableTiles.size() == 1) | ||||
| 			{ | ||||
| 				updateTerrainType(*suitableTiles.begin()); | ||||
| 				updateTerrainType(*suitableTiles.begin(), tileRequiresValidation); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				const int3 directions[] = { int3(0, -1, 0), int3(-1, 0, 0), int3(0, 1, 0), int3(1, 0, 0), | ||||
| 				static const int3 directions[] = { int3(0, -1, 0), int3(-1, 0, 0), int3(0, 1, 0), int3(1, 0, 0), | ||||
| 											int3(-1, -1, 0), int3(-1, 1, 0), int3(1, 1, 0), int3(1, -1, 0)}; | ||||
| 				for(int i = 0; i < ARRAY_COUNT(directions); ++i) | ||||
| 				{ | ||||
| 					auto it = suitableTiles.find(centerPos + directions[i]); | ||||
| 					if(it != suitableTiles.end()) | ||||
| 					{ | ||||
| 						updateTerrainType(*it); | ||||
| 						updateTerrainType(*it, tileRequiresValidation); | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| @@ -539,7 +565,7 @@ void CDrawTerrainOperation::updateTerrainViews() | ||||
| 	BOOST_FOREACH(const auto & pos, invalidatedTerViews) | ||||
| 	{ | ||||
| 		const auto & patterns = | ||||
| 				CTerrainViewPatternConfig::get().getPatternsForGroup(getTerrainGroup(map->getTile(pos).terType)); | ||||
| 				CTerrainViewPatternConfig::get().getTerrainViewPatternsForGroup(getTerrainGroup(map->getTile(pos).terType)); | ||||
|  | ||||
| 		// Detect a pattern which fits best | ||||
| 		int bestPattern = -1; | ||||
| @@ -556,7 +582,7 @@ void CDrawTerrainOperation::updateTerrainViews() | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		assert(bestPattern != -1); | ||||
| 		//assert(bestPattern != -1); | ||||
| 		if(bestPattern == -1) | ||||
| 		{ | ||||
| 			// This shouldn't be the case | ||||
| @@ -627,7 +653,8 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi | ||||
|  | ||||
| CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainViewInner(const int3 & pos, const TerrainViewPattern & pattern, int recDepth /*= 0*/) const | ||||
| { | ||||
| 	ETerrainType centerTerType = map->getTile(pos).terType; | ||||
| 	auto centerTerType = map->getTile(pos).terType; | ||||
| 	auto centerTerGroup = getTerrainGroup(centerTerType); | ||||
| 	int totalPoints = 0; | ||||
| 	std::string transitionReplacement; | ||||
|  | ||||
| @@ -667,11 +694,14 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi | ||||
| 			{ | ||||
| 				if(recDepth == 0 && map->isInTheMap(currentPos)) | ||||
| 				{ | ||||
| 					const auto & patternForRule = CTerrainViewPatternConfig::get().getPatternById(getTerrainGroup(terType), rule.name); | ||||
| 					if(patternForRule) | ||||
| 					if(terType == centerTerType) | ||||
| 					{ | ||||
| 						auto rslt = validateTerrainView(currentPos, *patternForRule, 1); | ||||
| 						if(rslt.result) topPoints = std::max(topPoints, rule.points); | ||||
| 						const auto & patternForRule = CTerrainViewPatternConfig::get().getTerrainViewPatternById(getTerrainGroup(centerTerType), rule.name); | ||||
| 						if(patternForRule) | ||||
| 						{ | ||||
| 							auto rslt = validateTerrainView(currentPos, *patternForRule, 1); | ||||
| 							if(rslt.result) topPoints = std::max(topPoints, rule.points); | ||||
| 						} | ||||
| 					} | ||||
| 					continue; | ||||
| 				} | ||||
| @@ -690,7 +720,9 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi | ||||
| 			}; | ||||
|  | ||||
| 			// Validate cell with the ruleset of the pattern | ||||
| 			if(pattern.terGroup == ETerrainGroup::NORMAL) | ||||
| 			bool nativeTestOk, nativeTestStrongOk; | ||||
| 			nativeTestOk = nativeTestStrongOk = (rule.name == TerrainViewPattern::RULE_NATIVE_STRONG || rule.name == TerrainViewPattern::RULE_NATIVE)  && !isAlien; | ||||
| 			if(centerTerGroup == ETerrainGroup::NORMAL) | ||||
| 			{ | ||||
| 				bool dirtTestOk = (rule.name == TerrainViewPattern::RULE_DIRT || rule.name == TerrainViewPattern::RULE_TRANSITION) | ||||
| 						&& isAlien && !isSandType(terType); | ||||
| @@ -709,24 +741,22 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					bool nativeTestOk = rule.name == TerrainViewPattern::RULE_NATIVE && !isAlien; | ||||
| 					applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || dirtTestOk || sandTestOk || nativeTestOk); | ||||
| 				} | ||||
| 			} | ||||
| 			else if(pattern.terGroup == ETerrainGroup::DIRT) | ||||
| 			else if(centerTerGroup == ETerrainGroup::DIRT) | ||||
| 			{ | ||||
| 				bool nativeTestOk = rule.name == TerrainViewPattern::RULE_NATIVE && !isSandType(terType); | ||||
| 				nativeTestOk = rule.name == TerrainViewPattern::RULE_NATIVE && !isSandType(terType); | ||||
| 				bool sandTestOk = (rule.name == TerrainViewPattern::RULE_SAND || rule.name == TerrainViewPattern::RULE_TRANSITION) | ||||
| 						&& isSandType(terType); | ||||
| 				applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || sandTestOk || nativeTestOk); | ||||
| 				applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || sandTestOk || nativeTestOk || nativeTestStrongOk); | ||||
| 			} | ||||
| 			else if(pattern.terGroup == ETerrainGroup::SAND) | ||||
| 			else if(centerTerGroup == ETerrainGroup::SAND) | ||||
| 			{ | ||||
| 				applyValidationRslt(true); | ||||
| 			} | ||||
| 			else if(pattern.terGroup == ETerrainGroup::WATER || pattern.terGroup == ETerrainGroup::ROCK) | ||||
| 			else if(centerTerGroup == ETerrainGroup::WATER || centerTerGroup == ETerrainGroup::ROCK) | ||||
| 			{ | ||||
| 				bool nativeTestOk = rule.name == TerrainViewPattern::RULE_NATIVE && !isAlien; | ||||
| 				bool sandTestOk = (rule.name == TerrainViewPattern::RULE_SAND || rule.name == TerrainViewPattern::RULE_TRANSITION) | ||||
| 						&& isAlien; | ||||
| 				applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || sandTestOk || nativeTestOk); | ||||
| @@ -811,20 +841,31 @@ CDrawTerrainOperation::InvalidTiles CDrawTerrainOperation::getInvalidTiles(const | ||||
| 	{ | ||||
| 		if(map->isInTheMap(pos)) | ||||
| 		{ | ||||
| 			auto & ptrConfig = CTerrainViewPatternConfig::get(); | ||||
| 			auto terType = map->getTile(pos).terType; | ||||
| 			// Pattern 2x2 | ||||
| 			const int3 translations[4] = { int3(-1, -1, 0), int3(0, -1, 0), int3(-1, 0, 0), int3(0, 0, 0) }; | ||||
| 			bool valid = true; | ||||
| 			for(int i = 0; i < ARRAY_COUNT(translations); ++i) | ||||
| 			auto valid = validateTerrainView(pos, ptrConfig.getTerrainTypePatternById("n1")).result; | ||||
|  | ||||
| 			// Special validity check for rock & water | ||||
| 			if(valid && centerTerType != terType && (terType == ETerrainType::WATER || terType == ETerrainType::ROCK)) | ||||
| 			{ | ||||
| 				valid = true; | ||||
| 				MapRect square(int3(pos.x + translations[i].x, pos.y + translations[i].y, pos.z), 2, 2); | ||||
| 				square.forEach([&](const int3 & pos) | ||||
| 				static const std::string patternIds[] = { "s1", "s2" }; | ||||
| 				for(int i = 0; i < ARRAY_COUNT(patternIds); ++i) | ||||
| 				{ | ||||
| 					if(map->isInTheMap(pos) && map->getTile(pos).terType != terType) valid = false; | ||||
| 				}); | ||||
| 				if(valid) break; | ||||
| 					valid = !validateTerrainView(pos, ptrConfig.getTerrainTypePatternById(patternIds[i])).result; | ||||
| 					if(!valid) break; | ||||
| 				} | ||||
| 			} | ||||
| 			// Additional validity check for non rock OR water | ||||
| 			else if(!valid && (terType != ETerrainType::WATER && terType != ETerrainType::ROCK)) | ||||
| 			{ | ||||
| 				static const std::string patternIds[] = { "n2", "n3" }; | ||||
| 				for(int i = 0; i < ARRAY_COUNT(patternIds); ++i) | ||||
| 				{ | ||||
| 					valid = validateTerrainView(pos, ptrConfig.getTerrainTypePatternById(patternIds[i])).result; | ||||
| 					if(valid) break; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			if(!valid) | ||||
| 			{ | ||||
| 				if(terType == centerTerType) tiles.nativeTiles.insert(pos); | ||||
|   | ||||
| @@ -42,9 +42,9 @@ struct DLL_LINKAGE MapRect | ||||
| 	template<typename Func> | ||||
| 	void forEach(Func f) const | ||||
| 	{ | ||||
| 		for(int i = x; i < right(); ++i) | ||||
| 		for(int j = y; j < bottom(); ++j) | ||||
| 		{ | ||||
| 			for(int j = y; j < bottom(); ++j) | ||||
| 			for(int i = x; i < right(); ++i) | ||||
| 			{ | ||||
| 				f(int3(i, j, z)); | ||||
| 			} | ||||
| @@ -225,6 +225,7 @@ struct DLL_LINKAGE TerrainViewPattern | ||||
| 		int points; | ||||
| 	}; | ||||
|  | ||||
| 	static const int PATTERN_DATA_SIZE = 9; | ||||
| 	/// 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. | ||||
| @@ -233,8 +234,10 @@ struct DLL_LINKAGE TerrainViewPattern | ||||
| 	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. | ||||
| 	/// Constant for the rule native, meaning a native border is required. | ||||
| 	static const std::string RULE_NATIVE; | ||||
| 	/// Constant for the rule native strong, meaning a native type is required. | ||||
| 	static const std::string RULE_NATIVE_STRONG; | ||||
| 	/// Constant for the rule any, meaning a native type, dirty OR sandy border is required. | ||||
| 	static const std::string RULE_ANY; | ||||
|  | ||||
| @@ -250,7 +253,7 @@ struct DLL_LINKAGE TerrainViewPattern | ||||
| 	/// can be used. Their meaning differs also from type to type. | ||||
| 	/// | ||||
| 	/// std::vector -> several rules can be used in one cell | ||||
| 	std::array<std::vector<WeightedRule>, 9> data; | ||||
| 	std::array<std::vector<WeightedRule>, PATTERN_DATA_SIZE> data; | ||||
|  | ||||
| 	/// The identifier of the pattern, if it's referenced from a another pattern. | ||||
| 	std::string id; | ||||
| @@ -270,8 +273,6 @@ struct DLL_LINKAGE TerrainViewPattern | ||||
|  | ||||
| 	/// The minimum and maximum points to reach to validate the pattern successfully. | ||||
| 	int minPoints, maxPoints; | ||||
|  | ||||
| 	ETerrainGroup::ETerrainGroup terGroup; | ||||
| }; | ||||
|  | ||||
| /// The terrain view pattern config loads pattern data from the filesystem. | ||||
| @@ -280,15 +281,17 @@ class DLL_LINKAGE CTerrainViewPatternConfig : public boost::noncopyable | ||||
| public: | ||||
| 	static CTerrainViewPatternConfig & get(); | ||||
|  | ||||
| 	const std::vector<TerrainViewPattern> & getPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const; | ||||
| 	boost::optional<const TerrainViewPattern &> getPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const; | ||||
| 	const std::vector<TerrainViewPattern> & getTerrainViewPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const; | ||||
| 	boost::optional<const TerrainViewPattern &> getTerrainViewPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const; | ||||
| 	const TerrainViewPattern & getTerrainTypePatternById(const std::string & id) const; | ||||
| 	ETerrainGroup::ETerrainGroup getTerrainGroup(const std::string & terGroup) const; | ||||
|  | ||||
| private: | ||||
| 	CTerrainViewPatternConfig(); | ||||
| 	~CTerrainViewPatternConfig(); | ||||
|  | ||||
| 	std::map<ETerrainGroup::ETerrainGroup, std::vector<TerrainViewPattern> > patterns; | ||||
| 	std::map<ETerrainGroup::ETerrainGroup, std::vector<TerrainViewPattern> > terrainViewPatterns; | ||||
| 	std::map<std::string, TerrainViewPattern> terrainTypePatterns; | ||||
| 	static boost::mutex smx; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -21,7 +21,62 @@ | ||||
| #include "../lib/int3.h" | ||||
| #include "../lib/CRandomGenerator.h" | ||||
|  | ||||
| BOOST_AUTO_TEST_CASE(CMapEditManager_DrawTerrain) | ||||
| BOOST_AUTO_TEST_CASE(CMapEditManager_DrawTerrain_Type) | ||||
| { | ||||
| 	try | ||||
| 	{ | ||||
| 		auto map = make_unique<CMap>(); | ||||
| 		map->width = 100; | ||||
| 		map->height = 100; | ||||
| 		map->initTerrain(); | ||||
| 		auto editManager = map->getEditManager(); | ||||
| 		editManager->clearTerrain(); | ||||
|  | ||||
| 		// 1x1 Blow up | ||||
| 		editManager->getTerrainSelection().select(int3(5, 5, 0)); | ||||
| 		editManager->drawTerrain(ETerrainType::GRASS); | ||||
| 		static const int3 squareCheck[] = { int3(5,5,0), int3(5,4,0), int3(4,4,0), int3(4,5,0) }; | ||||
| 		for(int i = 0; i < ARRAY_COUNT(squareCheck); ++i) | ||||
| 		{ | ||||
| 			BOOST_CHECK(map->getTile(squareCheck[i]).terType == ETerrainType::GRASS); | ||||
| 		} | ||||
|  | ||||
| 		// Concat to square | ||||
| 		editManager->getTerrainSelection().select(int3(6, 5, 0)); | ||||
| 		editManager->drawTerrain(ETerrainType::GRASS); | ||||
| 		BOOST_CHECK(map->getTile(int3(6, 4, 0)).terType == ETerrainType::GRASS); | ||||
| 		editManager->getTerrainSelection().select(int3(6, 5, 0)); | ||||
| 		editManager->drawTerrain(ETerrainType::LAVA); | ||||
| 		BOOST_CHECK(map->getTile(int3(4, 4, 0)).terType == ETerrainType::GRASS); | ||||
| 		BOOST_CHECK(map->getTile(int3(7, 4, 0)).terType == ETerrainType::LAVA); | ||||
|  | ||||
| 		// Special case water,rock | ||||
| 		editManager->getTerrainSelection().selectRange(MapRect(int3(10, 10, 0), 10, 5)); | ||||
| 		editManager->drawTerrain(ETerrainType::GRASS); | ||||
| 		editManager->getTerrainSelection().selectRange(MapRect(int3(15, 17, 0), 10, 5)); | ||||
| 		editManager->drawTerrain(ETerrainType::GRASS); | ||||
| 		editManager->getTerrainSelection().select(int3(21, 16, 0)); | ||||
| 		editManager->drawTerrain(ETerrainType::GRASS); | ||||
| 		BOOST_CHECK(map->getTile(int3(20, 15, 0)).terType == ETerrainType::GRASS); | ||||
|  | ||||
| 		// Special case non water,rock | ||||
| 		static const int3 diagonalCheck[] = { int3(31,42,0), int3(32,42,0), int3(32,43,0), int3(33,43,0), int3(33,44,0), | ||||
| 											  int3(34,44,0), int3(34,45,0), int3(35,45,0), int3(35,46,0), int3(36,46,0), | ||||
| 											  int3(36,47,0), int3(37,47,0)}; | ||||
| 		for(int i = 0; i < ARRAY_COUNT(diagonalCheck); ++i) | ||||
| 		{ | ||||
| 			editManager->getTerrainSelection().select(diagonalCheck[i]); | ||||
| 		} | ||||
| 		editManager->drawTerrain(ETerrainType::GRASS); | ||||
| 		BOOST_CHECK(map->getTile(int3(35, 44, 0)).terType == ETerrainType::WATER); | ||||
| 	} | ||||
| 	catch(const std::exception & e) | ||||
| 	{ | ||||
| 		logGlobal-> errorStream() << e.what(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| BOOST_AUTO_TEST_CASE(CMapEditManager_DrawTerrain_View) | ||||
| { | ||||
| 	try | ||||
| 	{ | ||||
| @@ -49,7 +104,7 @@ BOOST_AUTO_TEST_CASE(CMapEditManager_DrawTerrain) | ||||
| 			auto terGroup = CTerrainViewPatternConfig::get().getTerrainGroup(groupStr); | ||||
|  | ||||
| 			// Get mapping range | ||||
| 			const auto & pattern = CTerrainViewPatternConfig::get().getPatternById(terGroup, id); | ||||
| 			const auto & pattern = CTerrainViewPatternConfig::get().getTerrainViewPatternById(terGroup, id); | ||||
| 			const auto & mapping = (*pattern).mapping; | ||||
|  | ||||
| 			const auto & positionsNode = node["pos"].Vector(); | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							| @@ -18,7 +18,7 @@ | ||||
| 			"pattern" : "normal.s4" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"pos" : [ [ 5,14,0 ], [ 31,13,0 ] ], | ||||
| 			"pos" : [ [ 5,14,0 ], [ 31,13,0 ], [ 17,3,0 ], [ 13,8,0 ] ], | ||||
| 			"pattern" : "normal.s5" | ||||
| 		}, | ||||
| 		{ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user