# Precipice Slide Pseudocode

Date: 2026-04-30

Phase: L.2c - Movement & Collision Conformance

## Retail Anchors

- Named retail: `CTransition::edge_slide`, `acclient_2013_pseudo_c.txt:273001`
- Named retail: `CTransition::cliff_slide`, `acclient_2013_pseudo_c.txt:272397`
- Named retail: `SPHEREPATH::precipice_slide`, `acclient_2013_pseudo_c.txt:274316`
- ACE cross-check: `Transition.EdgeSlide`, `Transition.CliffSlide`,
  `SpherePath.PrecipiceSlide`
- ACE cross-check: `Polygon.find_crossed_edge`

## Edge-Slide Flow

When a grounded mover has contact state but the next candidate position has no
walkable surface within step-down reach, retail does not immediately accept the
fall or hard-stop. It enters `CTransition::edge_slide`.

```text
edge_slide(transitionState, stepDownHeight, walkableZ):
  if object is not OnWalkable or EdgeSlide is disabled:
    clear walkable
    restore candidate check position
    clear current contact plane
    mark cell array valid
    transitionState = OK
    return handled

  if current collision has a contact plane below walkableZ:
    transitionState = cliff_slide(contact plane)
    clear walkable and restore candidate check position
    clear current contact plane
    return not-final

  if sphere_path.walkable exists:
    transitionState = precipice_slide()
    clear current contact plane and restore candidate check position
    return transitionState == Collided

  if current collision has any contact plane:
    clear walkable
    restore candidate check position
    clear current contact plane
    transitionState = OK
    return handled

  move CheckPos back from failed candidate to the current sphere center
  step_down(stepDownHeight, walkableZ) to rediscover the walkable polygon
  clear current contact plane
  restore the failed candidate check position

  if a walkable polygon was discovered:
    set walkable_check_pos from the candidate sphere in walkable space
    transitionState = precipice_slide()
    return transitionState == Collided

  clear walkable
  mark cell array valid
  transitionState = Collided
  return handled
```

## Precipice Slide

`SPHEREPATH::precipice_slide` is the edge-normal half of edge-slide. The crucial
input is the walkable polygon that the mover just left; without that polygon,
there is no crossed edge to slide along.

```text
precipice_slide():
  normal = zero
  found = walkable.find_crossed_edge(walkable_check_pos, walkable_up, normal)

  if not found:
    clear walkable
    return Collided

  clear walkable
  step_up = false

  normal = walkable_pos.frame.LocalToGlobalVec(normal)

  blockOffset = LandDefs.GetBlockOffset(curr cell, check cell)
  movementOffset = global_sphere.center - global_curr_center.center + blockOffset

  if dot(normal, movementOffset) > 0:
    normal = -normal

  return global_sphere.slide_sphere(transition, normal, global_curr_center.center)
```

## Porting Notes

acdream already had the `Polygon.find_crossed_edge` math inside `BSPQuery`, but
the live diagnostic showed `walkableValid=False` at the failed step-down edge
branch. The port must therefore preserve or rediscover the walkable polygon,
not just pass the `EdgeSlide` flag.

For the first L.2c slice:

- terrain supplies the exact current triangle vertices alongside its plane;
- BSP step-down/find-walkable records world-space polygon vertices when the
  caller supplies the object's world origin;
- the failed step-down edge branch performs the retail back-probe to current
  position before calling precipice slide;
- `CELLARRAY`, full `cell_bsp` ownership, and cross-cell building portals remain
  L.2e work.
