瀏覽代碼

vcmi: really correct obstacle trigger

Now obstacle trigger really matches H3
Konstantin 2 年之前
父節點
當前提交
9a229d6e48

+ 6 - 5
lib/battle/CBattleInfoCallback.cpp

@@ -798,17 +798,18 @@ std::vector<std::shared_ptr<const CObstacleInstance>> CBattleInfoCallback::battl
 	return obstacles;
 }
 
-std::vector<std::shared_ptr<const CObstacleInstance>> CBattleInfoCallback::getAllAffectedObstaclesByStack(const battle::Unit * unit) const
+std::vector<std::shared_ptr<const CObstacleInstance>> CBattleInfoCallback::getAllAffectedObstaclesByStack(const battle::Unit * unit, const std::set<BattleHex> & passed) const
 {
-	std::vector<std::shared_ptr<const CObstacleInstance>> affectedObstacles = std::vector<std::shared_ptr<const CObstacleInstance>>();
+	auto affectedObstacles = std::vector<std::shared_ptr<const CObstacleInstance>>();
 	RETURN_IF_NOT_BATTLE(affectedObstacles);
 	if(unit->alive())
 	{
-		affectedObstacles = battleGetAllObstaclesOnPos(unit->getPosition(), false);
+		if(!passed.count(unit->getPosition()))
+			affectedObstacles = battleGetAllObstaclesOnPos(unit->getPosition(), false);
 		if(unit->doubleWide())
 		{
-			BattleHex otherHex = unit->occupiedHex(unit->getPosition());
-			if(otherHex.isValid())
+			BattleHex otherHex = unit->occupiedHex();
+			if(otherHex.isValid() && !passed.count(otherHex))
 				for(auto & i : battleGetAllObstaclesOnPos(otherHex, false))
 					if(!vstd::contains(affectedObstacles, i))
 						affectedObstacles.push_back(i);

+ 1 - 1
lib/battle/CBattleInfoCallback.h

@@ -60,7 +60,7 @@ public:
 	boost::optional<int> battleIsFinished() const override; //return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw
 
 	std::vector<std::shared_ptr<const CObstacleInstance>> battleGetAllObstaclesOnPos(BattleHex tile, bool onlyBlocking = true) const override;
-	std::vector<std::shared_ptr<const CObstacleInstance>> getAllAffectedObstaclesByStack(const battle::Unit * unit) const override;
+	std::vector<std::shared_ptr<const CObstacleInstance>> getAllAffectedObstaclesByStack(const battle::Unit * unit, const std::set<BattleHex> & passed) const override;
 
 	const CStack * battleGetStackByPos(BattleHex pos, bool onlyAlive = true) const;
 

+ 1 - 1
lib/battle/IBattleInfoCallback.h

@@ -72,7 +72,7 @@ public:
 
 	//blocking obstacles makes tile inaccessible, others cause special effects (like Land Mines, Moat, Quicksands)
 	virtual std::vector<std::shared_ptr<const CObstacleInstance>> battleGetAllObstaclesOnPos(BattleHex tile, bool onlyBlocking = true) const = 0;
-	virtual std::vector<std::shared_ptr<const CObstacleInstance>> getAllAffectedObstaclesByStack(const battle::Unit * unit) const = 0;
+	virtual std::vector<std::shared_ptr<const CObstacleInstance>> getAllAffectedObstaclesByStack(const battle::Unit * unit, const std::set<BattleHex> & passed) const = 0;
 };
 
 

+ 23 - 11
server/CGameHandler.cpp

@@ -1398,6 +1398,11 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
 
 	//initing necessary tables
 	auto accessibility = getAccesibility(curStack);
+	std::set<BattleHex> passed;
+	//Ignore obstacles on starting position
+	passed.insert(curStack->getPosition());
+	if(curStack->doubleWide())
+		passed.insert(curStack->occupiedHex());
 
 	//shifting destination (if we have double wide stack and we can occupy dest but not be exactly there)
 	if(!stackAtEnd && curStack->doubleWide() && !accessibility.accessible(dest, curStack))
@@ -1590,10 +1595,12 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
 						if(otherHex.isValid() && !obstacle2.empty())
 							obstacleHit = true;
 					}
+					if(!obstacleHit)
+						passed.insert(hex);
 				}
 			}
 
-			if (tiles.size() > 0)
+			if (!tiles.empty())
 			{
 				//commit movement
 				BattleStackMoved sm;
@@ -1609,7 +1616,12 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
 			if (curStack->getPosition() != dest)
 			{
 				if(stackIsMoving && start != curStack->getPosition())
-					stackIsMoving = handleDamageFromObstacle(curStack, stackIsMoving);
+				{
+					stackIsMoving = handleDamageFromObstacle(curStack, stackIsMoving, passed);
+					passed.insert(curStack->getPosition());
+					if(curStack->doubleWide())
+						passed.insert(curStack->occupiedHex());
+				}
 				if (gateStateChanging)
 				{
 					if (curStack->getPosition() == openGateAtHex)
@@ -1637,7 +1649,7 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
 	}
 
 	//handling obstacle on the final field (separate, because it affects both flying and walking stacks)
-	handleDamageFromObstacle(curStack);
+	handleDamageFromObstacle(curStack, false, passed);
 
 	return ret;
 }
@@ -5288,13 +5300,13 @@ void CGameHandler::stackTurnTrigger(const CStack *st)
 	}
 }
 
-bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackIsMoving)
+bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackIsMoving, const std::set<BattleHex> & passed)
 {
 	if(!curStack->alive())
 		return false;
 	bool containDamageFromMoat = false;
-	bool movementStoped = false;
-	for(auto & obstacle : getAllAffectedObstaclesByStack(curStack))
+	bool movementStopped = false;
+	for(auto & obstacle : getAllAffectedObstaclesByStack(curStack, passed))
 	{
 		if(obstacle->obstacleType == CObstacleInstance::SPELL_CREATED)
 		{
@@ -5305,7 +5317,7 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
 			if(!spellObstacle)
 				COMPLAIN_RET("Invalid obstacle instance");
 
-			if(spellObstacle->trigger)
+			if(spellObstacle->triggersEffects())
 			{
 				const bool oneTimeObstacle = spellObstacle->removeOnTrigger;
 
@@ -5369,13 +5381,13 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
 			return false;
 
 		if((obstacle->stopsMovement() && stackIsMoving))
-			movementStoped = true;
+			movementStopped = true;
 	}
 
 	if(stackIsMoving)
-		return curStack->alive() && !movementStoped;
-	else
-		return curStack->alive();
+		return curStack->alive() && !movementStopped;
+	
+	return curStack->alive();
 }
 
 void CGameHandler::handleTimeEvents()

+ 1 - 1
server/CGameHandler.h

@@ -232,7 +232,7 @@ public:
 	bool makeCustomAction(BattleAction &ba);
 	void stackEnchantedTrigger(const CStack * stack);
 	void stackTurnTrigger(const CStack *stack);
-	bool handleDamageFromObstacle(const CStack * curStack, bool stackIsMoving = false); //checks if obstacle is land mine and handles possible consequences
+	bool handleDamageFromObstacle(const CStack * curStack, bool stackIsMoving = false, const std::set<BattleHex> & passed = {}); //checks if obstacle is land mine and handles possible consequences
 
 	void removeObstacle(const CObstacleInstance &obstacle);
 	bool queryReply( QueryID qid, const JsonNode & answer, PlayerColor player );