1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-12-01 23:12:49 +02:00

Stepping into an obstacle, such as moat will now prevent unit from

attacking
This commit is contained in:
Ivan Savenko
2025-05-28 22:43:09 +03:00
parent bb61f2414a
commit ee066397c3
2 changed files with 37 additions and 26 deletions

View File

@@ -143,8 +143,8 @@ bool BattleActionProcessor::doWalkAction(const CBattleInfoCallback & battle, con
return false;
}
int walkedTiles = moveStack(battle, ba.stackNumber, target.at(0).hexValue); //move
if (!walkedTiles)
auto movementResult = moveStack(battle, ba.stackNumber, target.at(0).hexValue); //move
if (movementResult.invalidRequest)
{
gameHandler->complain("Stack failed movement!");
return false;
@@ -229,14 +229,20 @@ bool BattleActionProcessor::doAttackAction(const CBattleInfoCallback & battle, c
}
BattleHex startingPos = stack->getPosition();
int distance = moveStack(battle, ba.stackNumber, attackPos);
const auto movementResult = moveStack(battle, ba.stackNumber, attackPos);
logGlobal->trace("%s will attack %s", stack->nodeName(), destinationStack->nodeName());
if(stack->getPosition() != attackPos && !(stack->doubleWide() && (stack->getPosition() == attackPos.cloneInDirection(stack->destShiftDir(), false))) )
if (movementResult.invalidRequest)
{
gameHandler->complain("Stack failed attack - unable to reach target!");
return false;
}
if(movementResult.obstacleHit)
{
// we were not able to reach destination tile, nor occupy specified hex
// abort attack attempt, but treat this case as legal - we may have stepped onto a quicksands/mine
// abort attack attempt, but treat this case as legal - we have stepped onto a quicksands/mine
return true;
}
@@ -285,7 +291,7 @@ bool BattleActionProcessor::doAttackAction(const CBattleInfoCallback & battle, c
//move can cause death, eg. by walking into the moat, first strike can cause death or paralysis/petrification
if(stack->alive() && !stack->hasBonusOfType(BonusType::NOT_ACTIVE) && destinationStack->alive())
{
makeAttack(battle, stack, destinationStack, (i ? 0 : distance), destinationTile, i==0, false, false);//no distance travelled on second attack
makeAttack(battle, stack, destinationStack, (i ? 0 : movementResult.distance), destinationTile, i==0, false, false);//no distance travelled on second attack
if(!ferocityApplied && stack->hasBonusOfType(BonusType::FEROCITY))
{
@@ -615,10 +621,8 @@ bool BattleActionProcessor::makeBattleActionImpl(const CBattleInfoCallback & bat
return result;
}
int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int stack, BattleHex dest)
BattleActionProcessor::MovementResult BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int stack, BattleHex dest)
{
int ret = 0;
const CStack *curStack = battle.battleGetStackByID(stack);
const CStack *stackAtEnd = battle.battleGetStackByPos(dest);
@@ -632,7 +636,7 @@ int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int sta
auto start = curStack->getPosition();
if (start == dest)
return 0;
return { 0, false, false };
//initing necessary tables
auto accessibility = battle.getAccessibility(curStack);
@@ -654,7 +658,7 @@ int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int sta
if((stackAtEnd && stackAtEnd!=curStack && stackAtEnd->alive()) || !accessibility.accessible(dest, curStack))
{
gameHandler->complain("Given destination is not accessible!");
return 0;
return { 0, false, true };
}
bool canUseGate = false;
@@ -667,8 +671,8 @@ int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int sta
}
std::pair< BattleHexArray, int > path = battle.getPath(start, dest, curStack);
ret = path.second;
int8_t passedHexes = path.second;
bool movementSuccess = true;
int creSpeed = curStack->getMovementRange(0);
@@ -805,15 +809,10 @@ int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int sta
}
}
bool stackIsMoving = true;
while(stackIsMoving)
while(movementSuccess)
{
if (v<tilesToMove)
{
logGlobal->error("Movement terminated abnormally");
break;
}
throw std::runtime_error("Movement terminated abnormally");
bool gateStateChanging = false;
//special handling for opening gate on from starting hex
@@ -865,9 +864,9 @@ int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int sta
//we don't handle obstacle at the destination tile -> it's handled separately in the if at the end
if (curStack->getPosition() != dest)
{
if(stackIsMoving && start != curStack->getPosition())
if(movementSuccess && start != curStack->getPosition())
{
stackIsMoving = battle.handleObstacleTriggersForUnit(*gameHandler->spellEnv, *curStack, passed);
movementSuccess &= battle.handleObstacleTriggersForUnit(*gameHandler->spellEnv, *curStack, passed);
passed.insert(curStack->getPosition());
if(curStack->doubleWide())
passed.insert(curStack->occupiedHex());
@@ -894,8 +893,10 @@ int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int sta
}
}
else
{
//movement finished normally: we reached destination
stackIsMoving = false;
break;
}
}
}
//handle last hex separately for deviation
@@ -908,9 +909,9 @@ int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int sta
if(dest == start) //If dest is equal to start, then we should handle obstacles for it anyway
passed.clear(); //Just empty passed, obstacles will handled automatically
//handling obstacle on the final field (separate, because it affects both flying and walking stacks)
battle.handleObstacleTriggersForUnit(*gameHandler->spellEnv, *curStack, passed);
movementSuccess &= battle.handleObstacleTriggersForUnit(*gameHandler->spellEnv, *curStack, passed);
return ret;
return { passedHexes, !movementSuccess, false };
}
void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const CStack * attacker, const CStack * defender, int distance, const BattleHex & targetHex, bool first, bool ranged, bool counter)