Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Core/GameEngine/Source/GameLogic/AI/AIPathfind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9576,6 +9576,11 @@ Bool Pathfinder::isAttackViewBlockedByObstacle(const Object* attacker, const Coo
}
if (w)
{
#if !RETAIL_COMPATIBLE_CRC
if (w->isContactWeapon())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also add comments to the fix sites?

return false;
#endif

Bool viewBlocked;
if (victim)
viewBlocked = !w->isClearGoalFiringLineOfSightTerrain(attacker, attackerPos, victim);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3399,7 +3399,11 @@ void AIUpdateInterface::privateAttackPosition( const Coord3D *pos, Int maxShotsT
// this fixes an obscure bug with mine-clearing: if you tell someone to clear mines and put the centerpoint
// inside a building, the dozer/worker will just go thru the building to that spot. ick. so if you find that
// this clause (below) is problematic, you'll probably have to find another way to fix this mine-clearing bug. (srj)
#if RETAIL_COMPATIBLE_CRC
if (weapon && weapon->isContactWeapon() && !isPathAvailable(&localPos))
#else
if (weapon && weapon->isContactWeapon() && !weapon->isWithinAttackRange(getObject(), &localPos) && !isPathAvailable(&localPos))
#endif
Comment on lines +3402 to +3406

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

3. Unpathable contact target preserved 🐞 Bug ≡ Correctness

privateAttackPosition now skips the “find a nearby pathable spot” adjustment for contact weapons
if isWithinAttackRange() is true, even when isPathAvailable() is false. Combined with the LOS
bypass, this lets a unit execute a contact attack on an explicitly unpathable goal point (e.g.,
inside blocking geometry) as long as it can get within range outside the obstacle.
Agent Prompt
### Issue description
The new condition in `privateAttackPosition()` bypasses the existing safety behavior for contact weapons (“must be able to path to the target pos”) whenever the attacker is merely within attack range, even if the goal point is unpathable.

### Issue Context
`Weapon::isWithinAttackRange(source, pos)` is distance-only, while the comment/behavior here is about reachability/pathing. For contact weapons, “within range” can still be on the other side of a blocking obstacle.

### Fix Focus Areas
- Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate.cpp[3398-3415]
- GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate.cpp[3553-3561]
- Generals/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp[2056-2070]

### Suggested direction
Only skip the `isPathAvailable()`/fallback relocation when the unit is effectively already at the target point (very small positional epsilon), rather than when it is merely within attack range.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

{
FindPositionOptions fpOptions;
fpOptions.minRadius = 0.0f;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3554,7 +3554,11 @@ void AIUpdateInterface::privateAttackPosition( const Coord3D *pos, Int maxShotsT
// this fixes an obscure bug with mine-clearing: if you tell someone to clear mines and put the centerpoint
// inside a building, the dozer/worker will just go thru the building to that spot. ick. so if you find that
// this clause (below) is problematic, you'll probably have to find another way to fix this mine-clearing bug. (srj)
#if RETAIL_COMPATIBLE_CRC
if (weapon && weapon->isContactWeapon() && !isPathAvailable(&localPos))
#else
if (weapon && weapon->isContactWeapon() && !weapon->isWithinAttackRange(getObject(), &localPos) && !isPathAvailable(&localPos))
#endif
{
FindPositionOptions fpOptions;
fpOptions.minRadius = 0.0f;
Expand Down
Loading