Просмотр исходного кода

Do not place object visible tiles over the top of the map.

Tomasz Zieliński 2 лет назад
Родитель
Сommit
3c87b3934d

+ 5 - 0
lib/mapObjects/CObjectHandler.cpp

@@ -133,6 +133,11 @@ int3 CGObjectInstance::getPosition() const
 	return pos;
 }
 
+int3 CGObjectInstance::getTopVisiblePos() const
+{
+	return pos - appearance->getTopVisibleOffset();
+}
+
 void CGObjectInstance::setOwner(const PlayerColor & ow)
 {
 	tempOwner = ow;

+ 1 - 0
lib/mapObjects/CObjectHandler.h

@@ -159,6 +159,7 @@ public:
 	bool visitableAt(int x, int y) const; //returns true if object is visitable at location (x, y) (h3m pos)
 	int3 visitablePos() const override;
 	int3 getPosition() const override;
+	int3 getTopVisiblePos() const;
 	bool blockingAt(int x, int y) const; //returns true if object is blocking location (x, y) (h3m pos)
 	bool coveringAt(int x, int y) const; //returns true if object covers with picture location (x, y) (h3m pos)
 	std::set<int3> getBlockedPos() const; //returns set of positions blocked by this object

+ 17 - 0
lib/mapObjects/ObjectTemplate.cpp

@@ -524,6 +524,22 @@ bool ObjectTemplate::isVisitableFrom(si8 X, si8 Y) const
 	return dirMap[dy][dx] != 0;
 }
 
+void ObjectTemplate::calculateTopVisibleOffset()
+{
+	for(int y = static_cast<int>(getHeight()) - 1; y >= 0; y--) //Templates start from bottom-right corner
+	{
+		for(int x = 0; x < static_cast<int>(getWidth()); x++)
+		{
+			if (isVisibleAt(x, y))
+			{
+				topVisibleOffset = int3(x, y, 0);
+				return;
+			}
+		}
+	}
+	topVisibleOffset = int3(0, 0, 0);
+}
+
 void ObjectTemplate::calculateVisitableOffset()
 {
 	for(int y = 0; y < static_cast<int>(getHeight()); y++)
@@ -559,6 +575,7 @@ void ObjectTemplate::recalculate()
 	calculateBlockedOffsets();
 	calculateBlockMapOffset();
 	calculateVisitableOffset();
+	calculateTopVisibleOffset();
 
 	if (visitable && visitDir == 0)
 		logMod->warn("Template for %s is visitable but has no visitable directions!", animationFile);

+ 8 - 1
lib/mapObjects/ObjectTemplate.h

@@ -87,7 +87,12 @@ public:
 	inline int3 getBlockMapOffset() const
 	{
 		return blockMapOffset; 
-	}; 
+	};
+
+	inline int3 getTopVisibleOffset() const
+	{
+		return topVisibleOffset;
+	}
 
 	// Checks if object is visitable from certain direction. X and Y must be between -1..+1
 	bool isVisitableFrom(si8 X, si8 Y) const;
@@ -137,6 +142,7 @@ private:
 	std::set<int3> blockedOffsets;
 	int3 blockMapOffset;
 	int3 visitableOffset;
+	int3 topVisibleOffset;
 
 	void recalculate();
 
@@ -146,6 +152,7 @@ private:
 	void calculateBlockedOffsets();
 	void calculateBlockMapOffset();
 	void calculateVisitableOffset();
+	void calculateTopVisibleOffset();
 
 public:
 	template <typename Handler> void serialize(Handler &h, const int version)

+ 6 - 0
lib/rmg/ObjectManager.cpp

@@ -112,6 +112,9 @@ int3 ObjectManager::findPlaceForObject(const rmg::Area & searchArea, rmg::Object
 				continue;
 			
 			obj.setPosition(tile);
+
+			if (obj.getVisibleTop().y < 0)
+				continue;
 			
 			if(!searchArea.contains(obj.getArea()) || !searchArea.overlap(obj.getAccessibleArea()))
 				continue;
@@ -131,6 +134,9 @@ int3 ObjectManager::findPlaceForObject(const rmg::Area & searchArea, rmg::Object
 		for(const auto & tile : searchArea.getTiles())
 		{
 			obj.setPosition(tile);
+
+			if (obj.getVisibleTop().y < 0)
+				continue;
 			
 			if(!searchArea.contains(obj.getArea()) || !searchArea.overlap(obj.getAccessibleArea()))
 				continue;

+ 18 - 0
lib/rmg/RmgObject.cpp

@@ -45,6 +45,11 @@ const Area & Object::Instance::getBlockedArea() const
 	return dBlockedAreaCache;
 }
 
+int3 Object::Instance::getTopTile() const
+{
+	return object().getTopVisiblePos();
+}
+
 int3 Object::Instance::getPosition(bool isAbsolute) const
 {
 	if(isAbsolute)
@@ -284,6 +289,19 @@ const Area & Object::getArea() const
 	return dFullAreaCache;
 }
 
+const int3 Object::getVisibleTop() const
+{
+	int3 topTile(-1, 10000, -1); //Start at the bottom
+	for (const auto& i : dInstances)
+	{
+		if (i.getTopTile().y < topTile.y)
+		{
+			topTile = i.getTopTile();
+		}
+	}
+	return topTile;
+}
+
 void Object::Instance::finalize(RmgMap & map)
 {
 	if(!map.isOnMap(getPosition(true)))

+ 2 - 0
lib/rmg/RmgObject.h

@@ -38,6 +38,7 @@ public:
 		void setTemplate(TerrainId terrain); //cache invalidation
 		void setAnyTemplate(); //cache invalidation
 		
+		int3 getTopTile() const;
 		int3 getPosition(bool isAbsolute = false) const;
 		void setPosition(const int3 & position); //cache invalidation
 		void setPositionRaw(const int3 & position); //no cache invalidation
@@ -75,6 +76,7 @@ public:
 	void setTemplate(const TerrainId & terrain);
 	
 	const Area & getArea() const;  //lazy cache invalidation
+	const int3 getVisibleTop() const;
 	
 	void finalize(RmgMap & map);
 	void clear();