Browse Source

Fix bug: LandMine is not exploding to enemies. (#630)

* The reason is,

the mine has attribute hidden=true;
when enemy unit moves, the code in BattleInfo.cpp MoveUnit() (line 817) will update the revealed to true;
then in the CGameHandler.cpp handleDamageFromObstacle() (line 4846) is checking , and the condition battleIsObstacleVisibleForSide() will return true, so the effect will not be triggerred.

Resolution:
1. Remove the "revealed=true" in moveUnit(), and in handleDamageFromObstacle, remove the "const" restrict for obstacle, and then update revealed to true;
2. After the takeDamage function, add a pack "BattleObstaclesChanged" to update the obstacle to be "revealed=true".
Toney Sui 5 years ago
parent
commit
dca5d86e7a

+ 5 - 0
AI/BattleAI/StackWithBonuses.cpp

@@ -371,6 +371,11 @@ void HypotheticBattle::addObstacle(const ObstacleChanges & changes)
 	//TODO:HypotheticBattle::addObstacle
 }
 
+void HypotheticBattle::updateObstacle(const ObstacleChanges& changes)
+{
+	//TODO:HypotheticBattle::updateObstacle
+}
+
 void HypotheticBattle::removeObstacle(uint32_t id)
 {
 	//TODO:HypotheticBattle::removeObstacle

+ 1 - 0
AI/BattleAI/StackWithBonuses.h

@@ -98,6 +98,7 @@ public:
 	void setWallState(int partOfWall, si8 state) override;
 
 	void addObstacle(const ObstacleChanges & changes) override;
+	void updateObstacle(const ObstacleChanges& changes) override;
 	void removeObstacle(uint32_t id) override;
 
 	uint32_t nextUnitId() const override;

+ 3 - 0
lib/NetPacksLib.cpp

@@ -1535,6 +1535,9 @@ DLL_LINKAGE void BattleObstaclesChanged::applyBattle(IBattleState * battleState)
 		case BattleChanges::EOperation::ADD:
 			battleState->addObstacle(change);
 			break;
+		case BattleChanges::EOperation::UPDATE:
+			battleState->updateObstacle(change);
+			break;
 		default:
 			logNetwork->error("Unknown obstacle operation %d", (int)change.operation);
 			break;

+ 20 - 11
lib/battle/BattleInfo.cpp

@@ -809,17 +809,6 @@ void BattleInfo::moveUnit(uint32_t id, BattleHex destination)
 		logGlobal->error("Cannot find stack %d", id);
 		return;
 	}
-
-	for(auto & oi : obstacles)
-	{
-		if((oi->obstacleType == CObstacleInstance::SPELL_CREATED) && vstd::contains(oi->getAffectedTiles(), destination))
-		{
-			SpellCreatedObstacle * obstacle = dynamic_cast<SpellCreatedObstacle*>(oi.get());
-			assert(obstacle);
-			if(obstacle->casterSide != sta->unitSide() && obstacle->hidden)
-				obstacle->revealed = true;
-		}
-	}
 	sta->position = destination;
 }
 
@@ -1029,6 +1018,26 @@ void BattleInfo::addObstacle(const ObstacleChanges & changes)
 	obstacles.push_back(obstacle);
 }
 
+void BattleInfo::updateObstacle(const ObstacleChanges& changes)
+{
+	std::shared_ptr<SpellCreatedObstacle> changedObstacle = std::make_shared<SpellCreatedObstacle>();
+	changedObstacle->fromInfo(changes);
+
+	for(int i = 0; i < obstacles.size(); ++i)
+	{
+		if(obstacles[i]->uniqueID == changes.id) // update this obstacle
+		{
+			SpellCreatedObstacle * spellObstacle = dynamic_cast<SpellCreatedObstacle *>(obstacles[i].get());
+			assert(spellObstacle);
+
+			// Currently we only support to update the "revealed" property
+			spellObstacle->revealed = changedObstacle->revealed;
+			
+			break;
+		}
+	}
+}
+
 void BattleInfo::removeObstacle(uint32_t id)
 {
 	for(int i=0; i < obstacles.size(); ++i)

+ 1 - 0
lib/battle/BattleInfo.h

@@ -109,6 +109,7 @@ public:
 	void setWallState(int partOfWall, si8 state) override;
 
 	void addObstacle(const ObstacleChanges & changes) override;
+	void updateObstacle(const ObstacleChanges& changes) override;
 	void removeObstacle(uint32_t id) override;
 
 	void addOrUpdateUnitBonus(CStack * sta, const Bonus & value, bool forceAdd);

+ 3 - 2
lib/battle/CObstacleInstance.cpp

@@ -155,8 +155,8 @@ void SpellCreatedObstacle::fromInfo(const ObstacleChanges & info)
 {
 	uniqueID = info.id;
 
-	if(info.operation != ObstacleChanges::EOperation::ADD)
-		logGlobal->error("ADD operation expected");
+	if(info.operation != ObstacleChanges::EOperation::ADD && info.operation != ObstacleChanges::EOperation::UPDATE)
+		logGlobal->error("ADD or UPDATE operation expected");
 
     JsonDeserializer deser(nullptr, info.data);
     deser.serializeStruct("obstacle", *this);
@@ -173,6 +173,7 @@ void SpellCreatedObstacle::serializeJson(JsonSerializeFormat & handler)
 	handler.serializeInt("casterSide", casterSide);
 
 	handler.serializeBool("hidden", hidden);
+	handler.serializeBool("revealed", revealed);
 	handler.serializeBool("passable", passable);
 	handler.serializeBool("trigger", trigger);
 	handler.serializeBool("trap", trap);

+ 1 - 0
lib/battle/IBattleState.h

@@ -87,5 +87,6 @@ public:
 	virtual void setWallState(int partOfWall, si8 state) = 0;
 
 	virtual void addObstacle(const ObstacleChanges & changes) = 0;
+	virtual void updateObstacle(const ObstacleChanges & changes) = 0;
 	virtual void removeObstacle(uint32_t id) = 0;
 };

+ 22 - 0
server/CGameHandler.cpp

@@ -47,6 +47,7 @@
 #include "../lib/serializer/CTypeList.h"
 #include "../lib/serializer/Connection.h"
 #include "../lib/serializer/Cast.h"
+#include "../lib/serializer/JsonSerializer.h"
 
 #ifndef _MSC_VER
 #include <boost/thread/xtime.hpp>
@@ -4857,7 +4858,28 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
 					battleCast.applyEffects(spellEnv, true);
 
 					if(oneTimeObstacle)
+					{
 						removeObstacle(*obstacle);
+					}
+					else
+					{
+						// For the hidden spell created obstacles, e.g. QuickSand, it should be revealed after taking damage
+						ObstacleChanges changeInfo;
+						changeInfo.id = spellObstacle->uniqueID;
+						changeInfo.operation = ObstacleChanges::EOperation::UPDATE;
+
+						SpellCreatedObstacle changedObstacle;
+						changedObstacle.uniqueID = spellObstacle->uniqueID;
+						changedObstacle.revealed = true;
+
+						changeInfo.data.clear();
+						JsonSerializer ser(nullptr, changeInfo.data);
+						ser.serializeStruct("obstacle", changedObstacle);
+
+						BattleObstaclesChanged bocp;
+						bocp.changes.emplace_back(changeInfo);
+						sendAndApply(&bocp);
+					}
 				}
 			}
 		}

+ 1 - 0
test/mock/mock_battle_IBattleState.h

@@ -47,6 +47,7 @@ public:
 	MOCK_METHOD2(setWallState, void(int, si8));
 	MOCK_METHOD1(addObstacle, void(const ObstacleChanges &));
 	MOCK_METHOD1(removeObstacle, void(uint32_t));
+	MOCK_METHOD1(updateObstacle, void(const ObstacleChanges &));
 };