Function advance_entity

Source
pub fn advance_entity(
    sink: &mut dyn FightSink,
    config: &GameConfig,
    lookups: &ContentLookups,
    fight: &ActiveFight,
    entity: &Entity,
    ability: &Ability,
) -> Result<(), Error>
Expand description

Native: move entity toward the enemy line in a single multi-cell run (one StartMove instead of one per cell — every per-cell seam quantizes to the 100ms game tick and gives the client a chance to stutter).

Movement is fixed-direction (allies always advance +x, enemies −x), so we only ever advance toward the nearest opponent ahead — never chase one we have already reached or passed, which would march us away from the fight forever. Against a mobile opponent we cover half the gap and against a static one the whole gap (see the max_steps comment): both produce one StartMove, so an approach is a single smooth run, not one per cell.

Two mutually-approaching mobile runners meet in the middle without landing on or crossing each other: at fight start both plan on the same tick, each covers its half, and they end adjacent. A Run lowers to an immediate StartMove and the event loop is depth-first LIFO, so the first planner’s handle_start_move sets its move_target reservation BEFORE the second plans this tick; the second’s probe routes every cell through cell_exists_and_free (checks coordinates AND reserved move_target), so when both aim at the same midpoint the second takes the cell beside it.

(The entrance “run onto the screen → run in the fight” seam is a separate, client-side concern — Unity’s run-in tween must flow into the first StartMove instead of force-settling to Idle; no server distance can cover it.)

The walk also stops on the first cell where ability gains a valid target, and never steps onto a cell occupied or reserved by another entity.

Neither team may cross the other’s front line. A mover advances at most to the column directly in front of the opposing team’s frontmost LIVING unit and never onto or past it, so the two sides meet exactly one column apart instead of stacking on the same column (an enemy standing right under the hero). The opposing front is taken over both current cells AND reserved move_targets, so two mutual approachers don’t both land on the same midpoint column on an even gap: the depth-first / LIFO second planner sees the first’s reservation and stops one column short. This is the hard guarantee layered on top of the half-gap / max_steps heuristic and the in-range stop.