mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	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".
This commit is contained in:
		| @@ -371,6 +371,11 @@ void HypotheticBattle::addObstacle(const ObstacleChanges & changes) | |||||||
| 	//TODO:HypotheticBattle::addObstacle | 	//TODO:HypotheticBattle::addObstacle | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void HypotheticBattle::updateObstacle(const ObstacleChanges& changes) | ||||||
|  | { | ||||||
|  | 	//TODO:HypotheticBattle::updateObstacle | ||||||
|  | } | ||||||
|  |  | ||||||
| void HypotheticBattle::removeObstacle(uint32_t id) | void HypotheticBattle::removeObstacle(uint32_t id) | ||||||
| { | { | ||||||
| 	//TODO:HypotheticBattle::removeObstacle | 	//TODO:HypotheticBattle::removeObstacle | ||||||
|   | |||||||
| @@ -98,6 +98,7 @@ public: | |||||||
| 	void setWallState(int partOfWall, si8 state) override; | 	void setWallState(int partOfWall, si8 state) override; | ||||||
|  |  | ||||||
| 	void addObstacle(const ObstacleChanges & changes) override; | 	void addObstacle(const ObstacleChanges & changes) override; | ||||||
|  | 	void updateObstacle(const ObstacleChanges& changes) override; | ||||||
| 	void removeObstacle(uint32_t id) override; | 	void removeObstacle(uint32_t id) override; | ||||||
|  |  | ||||||
| 	uint32_t nextUnitId() const override; | 	uint32_t nextUnitId() const override; | ||||||
|   | |||||||
| @@ -1535,6 +1535,9 @@ DLL_LINKAGE void BattleObstaclesChanged::applyBattle(IBattleState * battleState) | |||||||
| 		case BattleChanges::EOperation::ADD: | 		case BattleChanges::EOperation::ADD: | ||||||
| 			battleState->addObstacle(change); | 			battleState->addObstacle(change); | ||||||
| 			break; | 			break; | ||||||
|  | 		case BattleChanges::EOperation::UPDATE: | ||||||
|  | 			battleState->updateObstacle(change); | ||||||
|  | 			break; | ||||||
| 		default: | 		default: | ||||||
| 			logNetwork->error("Unknown obstacle operation %d", (int)change.operation); | 			logNetwork->error("Unknown obstacle operation %d", (int)change.operation); | ||||||
| 			break; | 			break; | ||||||
|   | |||||||
| @@ -809,17 +809,6 @@ void BattleInfo::moveUnit(uint32_t id, BattleHex destination) | |||||||
| 		logGlobal->error("Cannot find stack %d", id); | 		logGlobal->error("Cannot find stack %d", id); | ||||||
| 		return; | 		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; | 	sta->position = destination; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1029,6 +1018,26 @@ void BattleInfo::addObstacle(const ObstacleChanges & changes) | |||||||
| 	obstacles.push_back(obstacle); | 	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) | void BattleInfo::removeObstacle(uint32_t id) | ||||||
| { | { | ||||||
| 	for(int i=0; i < obstacles.size(); ++i) | 	for(int i=0; i < obstacles.size(); ++i) | ||||||
|   | |||||||
| @@ -109,6 +109,7 @@ public: | |||||||
| 	void setWallState(int partOfWall, si8 state) override; | 	void setWallState(int partOfWall, si8 state) override; | ||||||
|  |  | ||||||
| 	void addObstacle(const ObstacleChanges & changes) override; | 	void addObstacle(const ObstacleChanges & changes) override; | ||||||
|  | 	void updateObstacle(const ObstacleChanges& changes) override; | ||||||
| 	void removeObstacle(uint32_t id) override; | 	void removeObstacle(uint32_t id) override; | ||||||
|  |  | ||||||
| 	void addOrUpdateUnitBonus(CStack * sta, const Bonus & value, bool forceAdd); | 	void addOrUpdateUnitBonus(CStack * sta, const Bonus & value, bool forceAdd); | ||||||
|   | |||||||
| @@ -155,8 +155,8 @@ void SpellCreatedObstacle::fromInfo(const ObstacleChanges & info) | |||||||
| { | { | ||||||
| 	uniqueID = info.id; | 	uniqueID = info.id; | ||||||
|  |  | ||||||
| 	if(info.operation != ObstacleChanges::EOperation::ADD) | 	if(info.operation != ObstacleChanges::EOperation::ADD && info.operation != ObstacleChanges::EOperation::UPDATE) | ||||||
| 		logGlobal->error("ADD operation expected"); | 		logGlobal->error("ADD or UPDATE operation expected"); | ||||||
|  |  | ||||||
|     JsonDeserializer deser(nullptr, info.data); |     JsonDeserializer deser(nullptr, info.data); | ||||||
|     deser.serializeStruct("obstacle", *this); |     deser.serializeStruct("obstacle", *this); | ||||||
| @@ -173,6 +173,7 @@ void SpellCreatedObstacle::serializeJson(JsonSerializeFormat & handler) | |||||||
| 	handler.serializeInt("casterSide", casterSide); | 	handler.serializeInt("casterSide", casterSide); | ||||||
|  |  | ||||||
| 	handler.serializeBool("hidden", hidden); | 	handler.serializeBool("hidden", hidden); | ||||||
|  | 	handler.serializeBool("revealed", revealed); | ||||||
| 	handler.serializeBool("passable", passable); | 	handler.serializeBool("passable", passable); | ||||||
| 	handler.serializeBool("trigger", trigger); | 	handler.serializeBool("trigger", trigger); | ||||||
| 	handler.serializeBool("trap", trap); | 	handler.serializeBool("trap", trap); | ||||||
|   | |||||||
| @@ -87,5 +87,6 @@ public: | |||||||
| 	virtual void setWallState(int partOfWall, si8 state) = 0; | 	virtual void setWallState(int partOfWall, si8 state) = 0; | ||||||
|  |  | ||||||
| 	virtual void addObstacle(const ObstacleChanges & changes) = 0; | 	virtual void addObstacle(const ObstacleChanges & changes) = 0; | ||||||
|  | 	virtual void updateObstacle(const ObstacleChanges & changes) = 0; | ||||||
| 	virtual void removeObstacle(uint32_t id) = 0; | 	virtual void removeObstacle(uint32_t id) = 0; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -47,6 +47,7 @@ | |||||||
| #include "../lib/serializer/CTypeList.h" | #include "../lib/serializer/CTypeList.h" | ||||||
| #include "../lib/serializer/Connection.h" | #include "../lib/serializer/Connection.h" | ||||||
| #include "../lib/serializer/Cast.h" | #include "../lib/serializer/Cast.h" | ||||||
|  | #include "../lib/serializer/JsonSerializer.h" | ||||||
|  |  | ||||||
| #ifndef _MSC_VER | #ifndef _MSC_VER | ||||||
| #include <boost/thread/xtime.hpp> | #include <boost/thread/xtime.hpp> | ||||||
| @@ -4857,7 +4858,28 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI | |||||||
| 					battleCast.applyEffects(spellEnv, true); | 					battleCast.applyEffects(spellEnv, true); | ||||||
|  |  | ||||||
| 					if(oneTimeObstacle) | 					if(oneTimeObstacle) | ||||||
|  | 					{ | ||||||
| 						removeObstacle(*obstacle); | 						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); | ||||||
|  | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -47,6 +47,7 @@ public: | |||||||
| 	MOCK_METHOD2(setWallState, void(int, si8)); | 	MOCK_METHOD2(setWallState, void(int, si8)); | ||||||
| 	MOCK_METHOD1(addObstacle, void(const ObstacleChanges &)); | 	MOCK_METHOD1(addObstacle, void(const ObstacleChanges &)); | ||||||
| 	MOCK_METHOD1(removeObstacle, void(uint32_t)); | 	MOCK_METHOD1(removeObstacle, void(uint32_t)); | ||||||
|  | 	MOCK_METHOD1(updateObstacle, void(const ObstacleChanges &)); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user