瀏覽代碼

Implemented road transitions.
* untested
* still unused

AlexVinS 10 年之前
父節點
當前提交
ae2c72ca52
共有 5 個文件被更改,包括 239 次插入21 次删除
  1. 2 0
      lib/VCMI_lib.cbp
  2. 196 1
      lib/mapping/CDrawRoadsOperation.cpp
  3. 21 3
      lib/mapping/CDrawRoadsOperation.h
  4. 12 10
      lib/mapping/CMapEditManager.cpp
  5. 8 7
      lib/mapping/CMapEditManager.h

+ 2 - 0
lib/VCMI_lib.cbp

@@ -255,6 +255,8 @@
 		<Unit filename="mapObjects/ObjectTemplate.h" />
 		<Unit filename="mapping/CCampaignHandler.cpp" />
 		<Unit filename="mapping/CCampaignHandler.h" />
+		<Unit filename="mapping/CDrawRoadsOperation.cpp" />
+		<Unit filename="mapping/CDrawRoadsOperation.h" />
 		<Unit filename="mapping/CMap.cpp" />
 		<Unit filename="mapping/CMap.h" />
 		<Unit filename="mapping/CMapEditManager.cpp" />

+ 196 - 1
lib/mapping/CDrawRoadsOperation.cpp

@@ -11,7 +11,7 @@
 #include "StdInc.h"
 #include "CDrawRoadsOperation.h"
 
-const std::vector<CDrawRoadsOperation::RoadPattern> CDrawRoadsOperation::rules = 
+const std::vector<CDrawRoadsOperation::RoadPattern> CDrawRoadsOperation::patterns = 
 {
 	//single tile. fallback patern
 	{
@@ -129,6 +129,21 @@ const std::vector<CDrawRoadsOperation::RoadPattern> CDrawRoadsOperation::rules =
 	
 };
 
+static bool ruleIsNone(const std::string & rule)
+{
+	return rule == "-";
+}
+
+static bool ruleIsSomething(const std::string & rule)
+{
+	return rule == "+";
+}
+
+static bool ruleIsAny(const std::string & rule)
+{
+	return rule == "?";
+}
+
 ///CDrawRoadsOperation
 CDrawRoadsOperation::CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, ERoadType::ERoadType roadType, CRandomGenerator * gen):
 	CMapOperation(map),terrainSel(terrainSel), roadType(roadType), gen(gen)
@@ -138,7 +153,21 @@ CDrawRoadsOperation::CDrawRoadsOperation(CMap * map, const CTerrainSelection & t
 
 void CDrawRoadsOperation::execute()
 {
+	std::set<int3> invalidated;
 	
+	for(const auto & pos : terrainSel.getSelectedItems())
+	{
+		auto & tile = map->getTile(pos);
+		tile.roadType = roadType;
+		
+		auto rect = extendTileAroundSafely(pos);
+		rect.forEach([&invalidated](const int3 & pos)
+		{
+			invalidated.insert(pos);
+		});
+	}
+	
+	updateTiles(invalidated);	
 }
 
 void CDrawRoadsOperation::undo()
@@ -156,3 +185,169 @@ std::string CDrawRoadsOperation::getLabel() const
 	return "Draw Roads";
 }
 
+bool CDrawRoadsOperation::canApplyPattern(const RoadPattern & pattern) const
+{
+	//TODO: this method should be virtual for river support	
+	return pattern.roadMapping.first >= 0;
+}
+
+void CDrawRoadsOperation::flipPattern(RoadPattern& pattern, int flip) const
+{
+	//todo: use cashing here and also in terrain patterns
+	
+	if(flip == 0)
+	{
+		return;
+	}
+
+
+	if(flip == FLIP_PATTERN_HORIZONTAL || flip == FLIP_PATTERN_BOTH)
+	{
+		for(int i = 0; i < 3; ++i)
+		{
+			int y = i * 3;
+			std::swap(pattern.data[y], pattern.data[y + 2]);
+		}
+	}
+
+	if(flip == FLIP_PATTERN_VERTICAL || flip == FLIP_PATTERN_BOTH)
+	{
+		for(int i = 0; i < 3; ++i)
+		{
+			std::swap(pattern.data[i], pattern.data[6 + i]);
+		}
+	}	
+}
+
+
+bool CDrawRoadsOperation::needUpdateTile(const TerrainTile & tile) const
+{
+	return tile.roadType != ERoadType::NO_ROAD; //TODO: this method should be virtual for river support
+}
+
+void CDrawRoadsOperation::updateTiles(std::set<int3> & invalidated) 
+{
+	for(int3 coord : invalidated)
+	{
+		TerrainTile & tile = map->getTile(coord);
+		ValidationResult result(false);
+		
+		if(!needUpdateTile(tile))
+			continue;
+			
+		int bestPattern = -1;
+		
+		for(int k = 0; k < patterns.size(); ++k)
+		{
+			result = validateTile(patterns[k], coord);
+			
+			if(result.result)
+			{
+				bestPattern = k;
+				break;
+			}
+		}
+		
+		if(bestPattern != -1)
+		{
+			updateTile(tile, patterns[bestPattern], result.flip);
+		}
+		
+	}
+};
+
+bool CDrawRoadsOperation::tileHasSomething(const int3& pos) const
+{
+//TODO: this method should be virtual for river support	
+
+   return map->getTile(pos).roadType != ERoadType::NO_ROAD;	
+}
+
+
+void CDrawRoadsOperation::updateTile(TerrainTile & tile, const RoadPattern & pattern, const int flip)
+{
+  //TODO: this method should be virtual for river support	
+  
+	std::pair<int, int> mapping = pattern.roadMapping;
+  
+	tile.roadDir = gen->nextInt(mapping.first, mapping.second);
+	tile.extTileFlags = (tile.extTileFlags & 0xCF) | (flip << 4); 
+}
+
+CDrawRoadsOperation::ValidationResult CDrawRoadsOperation::validateTile(const RoadPattern & pattern, const int3 & pos)
+{
+	ValidationResult result(false);
+	
+	if(!canApplyPattern(pattern))
+		return result;
+	
+	
+	for(int flip = 0; flip < 4; ++flip)
+	{
+		if((flip == FLIP_PATTERN_BOTH) && !(pattern.hasHFlip && pattern.hasVFlip)) 
+			continue;
+		if((flip == FLIP_PATTERN_HORIZONTAL) && !pattern.hasHFlip) 
+			continue;
+		if((flip == FLIP_PATTERN_VERTICAL) && !(pattern.hasVFlip)) 
+			continue;
+		
+		RoadPattern flipped = pattern;		
+		
+		flipPattern(flipped, flip);
+		
+		bool validated = true;
+		
+		for(int i = 0; i < 9; ++i)
+		{
+			if(4 == i)
+				continue;
+			int cx = pos.x + (i % 3) - 1;
+			int cy = pos.y + (i / 3) - 1;
+			
+			int3 currentPos(cx, cy, pos.z);
+			
+			bool hasSomething;
+			
+			if(!map->isInTheMap(currentPos))
+			{
+				hasSomething = true; //road/river can go out of map
+			}
+			else
+			{
+				hasSomething = tileHasSomething(pos);				
+			}
+			
+			if(ruleIsSomething(flipped.data[i]))
+			{
+				if(!hasSomething)
+				{
+					validated = false;
+					break;
+				}
+			}
+			else if(ruleIsNone(flipped.data[i]))
+			{
+				if(hasSomething)
+				{
+					validated = false;
+					break;
+				}		
+			}
+			else
+			{
+				assert(ruleIsAny(flipped.data[i]));			
+			}		
+			
+		}
+		
+		if(validated)
+		{
+			result.result = true;
+			result.flip = flip;
+			return result;			
+		}		
+	}
+	
+	return result;
+}
+

+ 21 - 3
lib/mapping/CDrawRoadsOperation.h

@@ -27,12 +27,30 @@ private:
 	
 	struct RoadPattern
 	{
-		std::string rules[9];
+		std::string data[9];
 		std::pair<int, int> roadMapping, riverMapping;
-		bool hasHFlip, hasBFlip;
+		bool hasHFlip, hasVFlip;
 	};
 	
-	static const  std::vector<RoadPattern> rules;
+	struct ValidationResult
+	{
+		ValidationResult(bool result): result(result), flip(0){};
+		bool result;
+		int flip;
+	};
+	
+	static const std::vector<RoadPattern> patterns;
+	
+	void flipPattern(RoadPattern & pattern, int flip) const;
+	
+	void updateTiles(std::set<int3> & invalidated);
+	
+	ValidationResult validateTile(const RoadPattern & pattern, const int3 & pos);
+	void updateTile(TerrainTile & tile, const RoadPattern & pattern, const int flip);
+	
+	bool canApplyPattern(const RoadPattern & pattern) const;
+	bool needUpdateTile(const TerrainTile & tile) const;
+	bool tileHasSomething(const int3 & pos) const;
 	
 	CTerrainSelection terrainSel;
 	ERoadType::ERoadType roadType;

+ 12 - 10
lib/mapping/CMapEditManager.cpp

@@ -133,6 +133,18 @@ std::string CMapOperation::getLabel() const
 	return "";
 }
 
+
+MapRect CMapOperation::extendTileAround(const int3 & centerPos) const
+{
+	return MapRect(int3(centerPos.x - 1, centerPos.y - 1, centerPos.z), 3, 3);
+}
+
+MapRect CMapOperation::extendTileAroundSafely(const int3 & centerPos) const
+{
+	return extendTileAround(centerPos) & MapRect(int3(0, 0, centerPos.z), map->width, map->height);
+}
+
+
 CMapUndoManager::CMapUndoManager() : undoRedoLimit(10)
 {
 
@@ -968,16 +980,6 @@ CDrawTerrainOperation::InvalidTiles CDrawTerrainOperation::getInvalidTiles(const
 	return tiles;
 }
 
-MapRect CDrawTerrainOperation::extendTileAround(const int3 & centerPos) const
-{
-	return MapRect(int3(centerPos.x - 1, centerPos.y - 1, centerPos.z), 3, 3);
-}
-
-MapRect CDrawTerrainOperation::extendTileAroundSafely(const int3 & centerPos) const
-{
-	return extendTileAround(centerPos) & MapRect(int3(0, 0, centerPos.z), map->width, map->height);
-}
-
 CDrawTerrainOperation::ValidationResult::ValidationResult(bool result, const std::string & transitionReplacement /*= ""*/)
 	: result(result), transitionReplacement(transitionReplacement)
 {

+ 8 - 7
lib/mapping/CMapEditManager.h

@@ -113,7 +113,14 @@ public:
 	virtual void redo() = 0;
 	virtual std::string getLabel() const = 0; /// Returns a display-able name of the operation.
 
-protected:
+protected:	
+	MapRect extendTileAround(const int3 & centerPos) const;
+	MapRect extendTileAroundSafely(const int3 & centerPos) const; /// doesn't exceed map size	
+	
+	static const int FLIP_PATTERN_HORIZONTAL = 1;
+	static const int FLIP_PATTERN_VERTICAL = 2;
+	static const int FLIP_PATTERN_BOTH = 3;	
+	
 	CMap * map;
 };
 
@@ -330,8 +337,6 @@ private:
 	void updateTerrainTypes();
 	void invalidateTerrainViews(const int3 & centerPos);
 	InvalidTiles getInvalidTiles(const int3 & centerPos) const;
-	MapRect extendTileAround(const int3 & centerPos) const;
-	MapRect extendTileAroundSafely(const int3 & centerPos) const; /// doesn't exceed map size
 
 	void updateTerrainViews();
 	ETerrainGroup::ETerrainGroup getTerrainGroup(ETerrainType terType) const;
@@ -343,10 +348,6 @@ private:
 	bool isSandType(ETerrainType terType) const;
 	void flipPattern(TerrainViewPattern & pattern, int flip) const;
 
-	static const int FLIP_PATTERN_HORIZONTAL = 1;
-	static const int FLIP_PATTERN_VERTICAL = 2;
-	static const int FLIP_PATTERN_BOTH = 3;
-
 	CTerrainSelection terrainSel;
 	ETerrainType terType;
 	CRandomGenerator * gen;