1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

vcmi: really correct obstacle trigger

Now obstacle trigger really matches H3
This commit is contained in:
Konstantin
2023-03-27 16:11:17 +03:00
parent 8c1d6c8e13
commit 9a229d6e48
5 changed files with 32 additions and 19 deletions

View File

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

View File

@@ -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 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>> 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; const CStack * battleGetStackByPos(BattleHex pos, bool onlyAlive = true) const;

View File

@@ -72,7 +72,7 @@ public:
//blocking obstacles makes tile inaccessible, others cause special effects (like Land Mines, Moat, Quicksands) //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>> 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;
}; };

View File

@@ -1398,6 +1398,11 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
//initing necessary tables //initing necessary tables
auto accessibility = getAccesibility(curStack); 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) //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)) if(!stackAtEnd && curStack->doubleWide() && !accessibility.accessible(dest, curStack))
@@ -1590,10 +1595,12 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
if(otherHex.isValid() && !obstacle2.empty()) if(otherHex.isValid() && !obstacle2.empty())
obstacleHit = true; obstacleHit = true;
} }
if(!obstacleHit)
passed.insert(hex);
} }
} }
if (tiles.size() > 0) if (!tiles.empty())
{ {
//commit movement //commit movement
BattleStackMoved sm; BattleStackMoved sm;
@@ -1609,7 +1616,12 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
if (curStack->getPosition() != dest) if (curStack->getPosition() != dest)
{ {
if(stackIsMoving && start != curStack->getPosition()) 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 (gateStateChanging)
{ {
if (curStack->getPosition() == openGateAtHex) 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) //handling obstacle on the final field (separate, because it affects both flying and walking stacks)
handleDamageFromObstacle(curStack); handleDamageFromObstacle(curStack, false, passed);
return ret; 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()) if(!curStack->alive())
return false; return false;
bool containDamageFromMoat = false; bool containDamageFromMoat = false;
bool movementStoped = false; bool movementStopped = false;
for(auto & obstacle : getAllAffectedObstaclesByStack(curStack)) for(auto & obstacle : getAllAffectedObstaclesByStack(curStack, passed))
{ {
if(obstacle->obstacleType == CObstacleInstance::SPELL_CREATED) if(obstacle->obstacleType == CObstacleInstance::SPELL_CREATED)
{ {
@@ -5305,7 +5317,7 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
if(!spellObstacle) if(!spellObstacle)
COMPLAIN_RET("Invalid obstacle instance"); COMPLAIN_RET("Invalid obstacle instance");
if(spellObstacle->trigger) if(spellObstacle->triggersEffects())
{ {
const bool oneTimeObstacle = spellObstacle->removeOnTrigger; const bool oneTimeObstacle = spellObstacle->removeOnTrigger;
@@ -5369,12 +5381,12 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
return false; return false;
if((obstacle->stopsMovement() && stackIsMoving)) if((obstacle->stopsMovement() && stackIsMoving))
movementStoped = true; movementStopped = true;
} }
if(stackIsMoving) if(stackIsMoving)
return curStack->alive() && !movementStoped; return curStack->alive() && !movementStopped;
else
return curStack->alive(); return curStack->alive();
} }

View File

@@ -232,7 +232,7 @@ public:
bool makeCustomAction(BattleAction &ba); bool makeCustomAction(BattleAction &ba);
void stackEnchantedTrigger(const CStack * stack); void stackEnchantedTrigger(const CStack * stack);
void stackTurnTrigger(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); void removeObstacle(const CObstacleInstance &obstacle);
bool queryReply( QueryID qid, const JsonNode & answer, PlayerColor player ); bool queryReply( QueryID qid, const JsonNode & answer, PlayerColor player );