namespace AcDream.Core.Physics.Motion;
///
/// Campaign P P5 (#167 / register TS-35) — retail
/// CPhysicsObj::GetStartConstraintDistance (0x0050ebc0) and
/// GetMaxConstraintDistance (0x0050ec10): the leash's start/max band,
/// keyed by whether the object's OWN current cell is outdoor or indoor.
///
/// Byte-decoded, not guessed — BN elided both getters' return
/// value as a bare this->m_position; expression (the classic x87
/// FPU-return decompile artifact). The actual values were recovered by
/// disassembling the matching binary's raw machine code (see
/// docs/research/2026-07-30-constraint-leash-constants.md §1):
/// outdoor start = 10.0, indoor start = 5.0; outdoor max =
/// 50.0, indoor max = 20.0. Indoor is decided by the object's
/// full cell id's low 16 bits: >= 0x0100 = EnvCell (indoor).
///
/// The retail player-vs-remote branch is INTENTIONALLY OMITTED.
/// The disassembly shows both getters branch on this == player_object
/// AND load byte-identical constants either way — the branch is vestigial
/// (both sides return the same four numbers). Porting that dead branch would
/// only add a phantom "is this the player" parameter with zero behavioral
/// effect, so this class keys purely on the object's own cell id.
///
/// ACE-inversion pin. ACE's PhysicsObj.GetStartConstraintDistance
/// (PhysicsObj.cs:620) maps outdoor → 5, indoor → 10 — the OPPOSITE of
/// the binary. ACE's max mapping (outdoor 50 / indoor 20) matches. Do not
/// "fix" this class to match ACE's start mapping; the disassembly is the
/// oracle here (feedback_acme_oracle: binary wins over ACE on disagreement).
///
///
public static class ConstraintDistance
{
private const float OutdoorStart = 10.0f;
private const float IndoorStart = 5.0f;
private const float OutdoorMax = 50.0f;
private const float IndoorMax = 20.0f;
/// Retail cmp eax, 0x100; jae indoor on the object's own
/// m_position.objcell_id & 0xFFFF — low 16 bits ≥ 0x0100 is an
/// EnvCell (indoor); below that is an outdoor landblock cell index.
public static bool IsIndoorCell(uint objCellId) => (objCellId & 0xFFFFu) >= 0x0100u;
/// Retail CPhysicsObj::GetStartConstraintDistance
/// (0x0050ebc0) — the near edge of the leash's brake band, keyed by the
/// object's own current cell.
public static float GetStartConstraintDistance(uint objCellId) =>
IsIndoorCell(objCellId) ? IndoorStart : OutdoorStart;
/// Retail CPhysicsObj::GetMaxConstraintDistance
/// (0x0050ec10) — the far edge (full clamp), keyed by the object's own
/// current cell.
public static float GetMaxConstraintDistance(uint objCellId) =>
IsIndoorCell(objCellId) ? IndoorMax : OutdoorMax;
}