mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-25 21:38:59 +02:00
Destroyed walls will now remove wall penalty
This commit is contained in:
parent
1d7f004658
commit
3be3c871fb
@ -54,7 +54,7 @@ static void retrieveTurretDamageRange(const CGTownInstance * town, const battle:
|
||||
|
||||
static BattleHex lineToWallHex(int line) //returns hex with wall in given line (y coordinate)
|
||||
{
|
||||
static const BattleHex lineToHex[] = {12, 29, 45, 62, 78, 95, 112, 130, 147, 165, 182};
|
||||
static const BattleHex lineToHex[] = {12, 29, 45, 62, 78, 96, 112, 130, 147, 165, 182};
|
||||
|
||||
return lineToHex[line];
|
||||
}
|
||||
@ -157,8 +157,89 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastSpell(con
|
||||
return ESpellCastProblem::OK;
|
||||
}
|
||||
|
||||
struct Point
|
||||
{
|
||||
int x,y;
|
||||
};
|
||||
|
||||
/// Algorithm to test whether line segment between points line1-line2 will intersect with
|
||||
/// AABB (Axis-Aligned Bounding Box) defined by points aabb1 & aabb2
|
||||
/// Note that in order to avoid floating point rounding errors algorithm uses integers with no divisions
|
||||
static bool intersectionTestSegmentAABB(Point line1, Point line2, Point aabb1, Point aabb2)
|
||||
{
|
||||
// check whether segment is located to the left of our AABB
|
||||
if (line1.x < aabb1.x && line2.x < aabb1.x)
|
||||
return false;
|
||||
|
||||
// check whether segment is located to the right of our AABB
|
||||
if (line1.x > aabb2.x && line2.x > aabb2.x)
|
||||
return false;
|
||||
|
||||
// check whether segment is located on top of our AABB
|
||||
if (line1.y < aabb1.y && line2.y < aabb1.y)
|
||||
return false;
|
||||
|
||||
// check whether segment is located below of our AABB
|
||||
if (line1.y > aabb2.y && line2.y > aabb2.y)
|
||||
return false;
|
||||
|
||||
Point vector { line2.x - line1.x, line2.y - line1.y};
|
||||
|
||||
// compute position of AABB corners relative to our line
|
||||
int tlTest = vector.y*aabb1.x - vector.x*aabb1.y + (line2.x*line1.y-line1.x*line2.y);
|
||||
int trTest = vector.y*aabb2.x - vector.x*aabb1.y + (line2.x*line1.y-line1.x*line2.y);
|
||||
int blTest = vector.y*aabb1.x - vector.x*aabb2.y + (line2.x*line1.y-line1.x*line2.y);
|
||||
int brTest = vector.y*aabb2.x - vector.x*aabb2.y + (line2.x*line1.y-line1.x*line2.y);
|
||||
|
||||
// if all points are on the left of our line then there is no intersection
|
||||
if ( tlTest > 0 && trTest > 0 && blTest > 0 && brTest > 0 )
|
||||
return false;
|
||||
|
||||
// if all points are on the right of our line then there is no intersection
|
||||
if ( tlTest < 0 && trTest < 0 && blTest < 0 && brTest < 0 )
|
||||
return false;
|
||||
|
||||
// if all previous checks failed, this means that there is an intersection between line and AABB
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBattleInfoCallback::battleHasWallPenalty(const IBonusBearer * shooter, BattleHex shooterPosition, BattleHex destHex) const
|
||||
{
|
||||
auto isTileBlocked = [&](BattleHex tile)
|
||||
{
|
||||
EWallPart wallPart = battleHexToWallPart(tile);
|
||||
if (wallPart == EWallPart::INDESTRUCTIBLE_PART_OF_GATE)
|
||||
return false; // does not blocks ranged attacks
|
||||
if (wallPart == EWallPart::INDESTRUCTIBLE_PART)
|
||||
return true; // always blocks ranged attacks
|
||||
|
||||
assert(isWallPartPotentiallyAttackable(wallPart));
|
||||
|
||||
EWallState state = battleGetWallState(wallPart);
|
||||
|
||||
return state != EWallState::DESTROYED;
|
||||
};
|
||||
|
||||
auto needWallPenalty = [&](BattleHex from, BattleHex dest)
|
||||
{
|
||||
Point line1{ from.getX()*10+5, from.getY()*10+5};
|
||||
Point line2{ dest.getX()*10+5, dest.getY()*10+5};
|
||||
|
||||
for (int y = 0; y < GameConstants::BFIELD_HEIGHT; ++y)
|
||||
{
|
||||
BattleHex obstacle = lineToWallHex(y);
|
||||
if (!isTileBlocked(obstacle))
|
||||
continue;
|
||||
|
||||
Point aabb1{ obstacle.getX()*10, obstacle.getY()*10 };
|
||||
Point aabb2{ aabb1.x + 10, aabb1.y + 10 };
|
||||
|
||||
if ( intersectionTestSegmentAABB(line1, line2, aabb1, aabb2))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
RETURN_IF_NOT_BATTLE(false);
|
||||
if(!battleGetSiegeLevel())
|
||||
return false;
|
||||
@ -170,21 +251,9 @@ bool CBattleInfoCallback::battleHasWallPenalty(const IBonusBearer * shooter, Bat
|
||||
return false;
|
||||
|
||||
const int wallInStackLine = lineToWallHex(shooterPosition.getY());
|
||||
const int wallInDestLine = lineToWallHex(destHex.getY());
|
||||
const bool shooterOutsideWalls = shooterPosition < wallInStackLine;
|
||||
|
||||
const bool stackLeft = shooterPosition < wallInStackLine;
|
||||
const bool destRight = destHex > wallInDestLine;
|
||||
|
||||
if (stackLeft && destRight) //shooting from outside to inside
|
||||
{
|
||||
int row = (shooterPosition + destHex) / (2 * GameConstants::BFIELD_WIDTH);
|
||||
if (shooterPosition > destHex && ((destHex % GameConstants::BFIELD_WIDTH - shooterPosition % GameConstants::BFIELD_WIDTH) < 2)) //shooting up high
|
||||
row -= 2;
|
||||
const int wallPos = lineToWallHex(row);
|
||||
if (!isWallPartPotentiallyAttackable(battleHexToWallPart(wallPos))) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return shooterOutsideWalls && needWallPenalty(shooterPosition, destHex);
|
||||
}
|
||||
|
||||
si8 CBattleInfoCallback::battleCanTeleportTo(const battle::Unit * stack, BattleHex destHex, int telportLevel) const
|
||||
|
Loading…
x
Reference in New Issue
Block a user