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,8 +18,13 @@ | ||||
| // 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! | ||||
| [ | ||||
| { | ||||
| 	"terrainView" : | ||||
| 	[ | ||||
| 		// Extended mixed transitions | ||||
| 		{ | ||||
| 			"id" : "x1", | ||||
| @@ -166,17 +171,6 @@ | ||||
| 			"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" : | ||||
| @@ -214,7 +208,7 @@ | ||||
| 			[ | ||||
| 				"T", "T", "?", | ||||
| 				"T", "N", "s6-1,m1-1,m2-1,N", | ||||
| 			"?", "s6-1,m1-1,m2-1,N", "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" } | ||||
| @@ -229,5 +223,66 @@ | ||||
| 			], | ||||
| 			"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,7 +316,10 @@ CTerrainViewPatternConfig & CTerrainViewPatternConfig::get() | ||||
| CTerrainViewPatternConfig::CTerrainViewPatternConfig() | ||||
| { | ||||
| 	const JsonNode config(ResourceID("config/terrainViewPatterns.json")); | ||||
| 	const auto & patternsVec = config.Vector(); | ||||
| 	static const std::string patternTypes[] = { "terrainView", "terrainType" }; | ||||
| 	for(int i = 0; i < ARRAY_COUNT(patternTypes); ++i) | ||||
| 	{ | ||||
| 		const auto & patternsVec = config[patternTypes[i]].Vector(); | ||||
| 		BOOST_FOREACH(const auto & ptrnNode, patternsVec) | ||||
| 		{ | ||||
| 			TerrainViewPattern pattern; | ||||
| @@ -352,6 +356,8 @@ CTerrainViewPatternConfig::CTerrainViewPatternConfig() | ||||
| 			if(pattern.maxPoints == 0) pattern.maxPoints = std::numeric_limits<int>::max(); | ||||
|  | ||||
| 			// Read mapping | ||||
| 			if(i == 0) | ||||
| 			{ | ||||
| 				const auto & mappingStruct = ptrnNode["mapping"].Struct(); | ||||
| 				BOOST_FOREACH(const auto & mappingPair, mappingStruct) | ||||
| 				{ | ||||
| @@ -376,9 +382,16 @@ CTerrainViewPatternConfig::CTerrainViewPatternConfig() | ||||
| 						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); | ||||
| 			terGroupPattern.terGroup = terGroup; | ||||
| 			patterns[terGroup].push_back(terGroupPattern); | ||||
| 					terrainViewPatterns[terGroup].push_back(terGroupPattern); | ||||
| 				} | ||||
| 			} | ||||
| 			else if(i == 1) | ||||
| 			{ | ||||
| 				terrainTypePatterns[pattern.id] = pattern; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -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,12 +694,15 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi | ||||
| 			{ | ||||
| 				if(recDepth == 0 && map->isInTheMap(currentPos)) | ||||
| 				{ | ||||
| 					const auto & patternForRule = CTerrainViewPatternConfig::get().getPatternById(getTerrainGroup(terType), rule.name); | ||||
| 					if(terType == centerTerType) | ||||
| 					{ | ||||
| 						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; | ||||
| 				} | ||||
| 				else | ||||
| @@ -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; | ||||
| 				}); | ||||
| 					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); | ||||
|   | ||||
| @@ -41,10 +41,10 @@ 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 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