We need to track models to update in a single place. SceneRenderer in
that case. It allows us to make ModelVertexRenderer implementations more
straightforward.
The last node needs to have distance "0" to next node. Do the inverse of
when adding nodes.
Also add some basic tests covering this bug.
Fixes: #4659
Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
cmpPosition was declared but never read anywhere in the function,
likely left over from an earlier refactor — each unit's own position
is already fetched correctly inside the loop via unitPos. CmpPtr
construction is a pure lookup with no side effects, so removing the
unused instance doesn't change behaviour.
In `CCmpPathfinder::CheckBuildingPlacement`, the boundary check for the
vertical grid dimension (`j > m_TerrainOnlyGrid->m_H`) allowed `j` to equal
`m_TerrainOnlyGrid->m_H`. Since grid indices are 0-based (valid row indices
range from `0` to `m_H - 1`), this boundary condition allowed the loop to
execute with an out-of-bounds row index, leading to an invalid memory
read (`m_TerrainOnlyGrid->get(i, j)`) and potential segfaults.
This patch changes the comparison operator to `j >= m_TerrainOnlyGrid->m_H`,
ensuring that spans extending to or past the grid height bound are properly
flagged as out-of-bounds.
range.GetInternalValue() is an i32; multiplying it by 2 before the cast
to i64 could overflow instead of widening, corrupting the divisor. Cast
to i64 first.
38b33b0484 added a visibility filter to TestEntityQuery, active whenever
a query sets preferMirages - which UnitAI's attack range query does.
However, those filters do not work for Gaia, and so the query never
returned anything.
It was only a wrapper around `std::string::substr`. The interface
matches the usecase more. In some places it's better to use
`std::string::ends_with`.
In most places `fmt::format` is used because it's locale indidendant.
For the user reporter the locale dependant form of `fmt::format` is used
because it's shown to the user.
In `CCmpObstruction::ResolveFoundationCollisions`, the nested loop
intended to assign a persistent control group to colliding normal
entities was incorrectly iterating over `normalEnts` instead of
`persistentEnts`.
This caused the function to attempt to clobber default control groups
with other non-persistent groups, completely bypassing the intended
`ControlPersist` logic.
This patch fixes the inner loop to correctly iterate over
`persistentEnts`, ensuring foundations properly inherit persistent
control groups.
Fixes: 9ae084519f
Adds baseRange parameter to parabolic queries for combined
2D + parabolic detection. StandGround and Chase stances now
use attack range (parabolic) with vision as baseRange, allowing
units to attack enemies visible through friendly vision.
Buildings benefit as well via BuildingAI.
Introduce CanEverReachTarget in the Attack component to check whether
a target is geometrically reachable at all, accounting for height
offsets and turreted units inside buildings.
For non-parabolic attacks (e.g. melee), a simple 3D distance check
from the closest approach point is used.
For parabolic attacks (e.g. ranged), the parabolic range formula
is used to determine if the height difference is surmountable
from the closest horizontal distance to the target.
Add GetClosestApproachDistanceToTurretPoint to TurretHolder
to estimate the minimum horizontal distance to a turret point,
using its local offset and the holder's obstruction size.
Passable buildings are not considered obstacles.
Fixes units on the ground trying to attack unreachable units on walls
or towers when the projectile's arc cannot reach the required height.
The parabolic range formula in GetEffectiveParabolicRange was only
computating height differences from manual HeightOffset values,
completely ignoring actual terrain elevation.
This meant units on hills received no tactical advantage
despite the UI stat tooltip correctly showing extended ranges.
Fixes#8889
Split mouse wheel scroll handling into horizontal and vertical. Keep
vertical scroll for zooming and use horizontal to rotate around the y
axis replicating the behaviour of the main game.
Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>