# Spaceships, Vehicles & Mounts

V5 is one open-world narrative universe stitched from several **cells** — a
modern Urban metropolis, a 1930s/1947/1968 Period city, a Frontier expanse, a
monster-Hunter wilderness, and a hard-vacuum Sci-Fi belt. A universe that wide
needs more than one way to move, and V5 does not pretend one model covers all of
it. The Sci-Fi cell flies **Newtonian spaceships**; the Urban and Period cells
drive **Chaos-simulated cars, bikes, boats, planes, helicopters, trucks, and
armour**; the Frontier and Hunter cells ride **horses** and tow **horse-drawn
wagons**. These are not three flavours of one component — they are **three
independent UE C++ modules**, each with its own physics philosophy, its own data
catalog, and its own automation suite, sharing only the project-wide "data plus
a validator plus a headless test" discipline.

That separation is deliberate and load-bearing. A spaceship in a tense ship-duel
needs a bit-deterministic integrator a rollback predictor can rewind; a sports
car needs the full mechanical fidelity of a wheeled-vehicle solver with torque
curves and a gearbox; a horse needs neither — it needs a bond that deepens, a
stamina budget, and the chance to spook and throw you. This page owns the three
signature locomotion subsystems — `V5Spaceship`, `V5Vehicles`, and `V5HorseAI` —
their data models, their solvers, and the honest line between shipped logic and
authored content. The section hub is
[../V5_ARCHITECTURE.md](../V5_ARCHITECTURE.md).

## What ships, honestly

The **locomotion logic core is real, registered, compiled, and tested.** All
three modules are listed in `V5.uproject` (`V5Vehicles` line 29, `V5Spaceship`
line 74, `V5HorseAI` line 149), all three compile on the on-box UE5.5 engine —
the build tree carries **61, 46, and 25 `.o` objects** respectively under
`V5/ue/Intermediate/Build/Linux/.../<Module>/` — and each ships its own
automation specs (`V5.Spaceship.Systems`, `V5.Spaceship.FlipBurnDeterminism`,
`V5.Vehicles.CatalogCoverage`, `V5.Vehicles.HandlingSaveLoad`,
`V5.Vehicles.CustomizationTier2`, `V5.HorseAI.CatalogAndSystems`,
`V5.HorseAI.BondingTierTransitions`). The Newtonian solver, the intercept
mathematics, the Chaos drivetrain configuration, the bond-tier state machine,
and the gait library are all substantive, domain-specific C++ exercised by those
tests — not CRUD.

Four honest qualifications, each corrected in its section below:

- **The spaceship solver is not PhysX, despite the monolith.**
  `V5_ARCHITECTURE.md` says hard-vacuum flight runs on "PhysX 5 (UE's wrapper)."
  It does not. `V5ShipPhysicsSystems.cpp` is a **hand-written, closed-form
  kinematic integrator** — pure struct-in/struct-out math with no rigid body, no
  `FBodyInstance`, no physics tick (the pawn sets `bCanEverTick = false`). That
  is the honest and, for a rollback-deterministic PvP budget, the better choice
  — but it is not PhysX.
- **Ground vehicles genuinely use Chaos.** `V5Vehicles.Build.cs` really depends
  on `ChaosVehicles` + `PhysicsCore`, `UV5_Vehicle_Base` really derives from
  `UChaosWheeledVehicleMovementComponent`, and `ChaosVehiclesPlugin` is enabled
  in the uproject (line 449) — the Chaos claim is true.
- **There are no `.uasset` binaries.** The 18 ship meshes, 266 vehicle mesh
  recipes, and 12 horse breeds are **catalog/recipe/manifest data validated
  headless** — JSON with source paths, LOD counts, and triangle budgets, plus
  convention strings under `/Game/V5Spaceship/Meshes/` and
  `/Game/V5Vehicles/Meshes/`. The trees are logic and a content skeleton, the
  standard V5 target-artifact convention.
- **Rollback lives in `V5Netcode`, not here.** The monolith's 8-frame spaceship
  PvP rollback prediction is real as a design, and `V5Spaceship` supplies the
  proven-deterministic substrate it needs (see the determinism test), but the
  rollback envelope itself is owned by `V5Netcode`. The ship module makes
  rollback _possible_; it does not implement it.

## The three-module split

| Module          | Real responsibility (verified)                                                                                                                                                                                                                                      | Solver                         |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ |
| **V5Spaceship** | Newtonian flight (main engine + RCS), flight modes (burn/coast/flip-and-burn), gravity zones, loose-object sim, PDC/railgun intercept solver, guided torpedoes, component damage with cascades, boarding clamp, zero-G recoil.                                      | Custom deterministic kinematic |
| **V5Vehicles**  | 44 wheeled/winged/tracked/floating vehicles across six domains, `UChaosWheeledVehicleMovementComponent` configuration from data tuning, 266-entry mesh recipe catalog, per-domain radio profiles, the damage model, and the 200-part Tier-2 customization manifest. | Chaos Vehicles                 |
| **V5HorseAI**   | Per-horse state, four-tier bonding, the gait library with stamina, saddlebag inventory, feed/brush/talk care loop, spook-and-throw, whistle recall, and permadeath. 12 breeds / 4 gaits / 84+ animation clips.                                                      | Custom gait/state machine      |

```mermaid
flowchart TB
    Core[V5Core] --> Ship[V5Spaceship]
    Gameplay[V5Gameplay] --> Ship
    Core --> Veh[V5Vehicles]
    Gameplay --> Veh
    Chaos[ChaosVehicles plugin] --> Veh
    Core --> Horse[V5HorseAI]

    Ship -. deterministic substrate .-> Netcode[V5Netcode rollback]
    Veh -. handling snapshot .-> Persist[V5Persistence]
    Horse -. saddlebag + bond .-> Persist
    Ship -. attribute sets / IMC .-> GAS[V5 GAS + Input]
    Veh -. attribute sets / IMC .-> GAS
    Horse -. mount IMC .-> GAS

    SciFi([Sci-Fi cell]) --> Ship
    Urban([Urban + Period cells]) --> Veh
    Frontier([Frontier + Hunter cells]) --> Horse
```

The three solvers never feed back into one another. A horse-drawn wagon shows
the boundary cleanly: the **wagon body** is a `V5Vehicles` Chaos vehicle
carrying a `HorseTeamSize` of 4 (Frontier) or 2 (Hunter), while the **ridden
mount** is a `V5HorseAI` gait-library pawn. Same animal, two systems, by design.

## Spaceships: a deterministic Newtonian solver

### Ship state and the kinematic integrator

A ship is a value. `FV5ShipNewtonianState`
(`V5Spaceship/Public/V5SpaceshipTypes.h`) carries position, velocity, an
`Attitude` rotator, angular velocity, a `ReactionMassKg` propellant budget, and
the current `EV5ShipFlightMode`; `FV5ShipClassDefinition` fixes `DryMassKg`,
`MaxMainEngineG`, `RCSTorqueDegPerSecond` (18°/s default), and reaction-mass
capacity across four classes — `Skiff`, `Corvette`, `Frigate`, `Capital`.

`UV5_Ship_MainEngine::ApplyMainEngineBurn` (`V5ShipPhysicsSystems.cpp:91`) is
the heart, and it is a genuine kinematic step, not a velocity nudge:

```
a   = Attitude.Vector() · (MaxMainEngineG · 9.80665 · throttle)
pos = pos + v·dt + ½·a·dt²
v   = v + a·dt
reactionMass -= throttle · MaxMainEngineG · dt · 7.5
```

Thrust always points along the ship's facing vector, so you steer by rotating
and burning — there is no lateral "strafe to target." Crucially, **the engine
only fires while it has propellant**: when `ReactionMassKg <= 0`, throttle is
zero, or `dt <= 0`, the function refuses to integrate and drops the ship to
`Coast`. That is a fail-loud seam — a dry tank coasts, it does not silently keep
accelerating.

`UV5_Ship_RCSThruster::ApplyRCS` integrates rotation the same honest way, with
clamped pitch/yaw/roll input scaling `RCSTorqueDegPerSecond` and spending its
own smaller propellant slice. The runtime `AV5_Ship_NewtonianPawn` is a
deliberately inert `APawn` (`bCanEverTick = false`):
`SimulateSubstep(dt, throttle, rcs)` calls the two static solvers, then
`SetActorLocation(State.PositionMeters * 100.0f)` converts solver metres to UE
centimetres. The pawn is a view; the state is the simulation.

### Flight modes: burn, coast, and flip-and-burn

The signature manoeuvre is the Expanse-style **flip-and-burn**:
`UV5_Ship_FlipAndBurn::StepFlipAndBurn` (`V5ShipPhysicsSystems.cpp:145`) takes a
target velocity, computes the `DeltaV` needed, and if the nose is more than 1°
off the required burn vector it **slerps the attitude** toward it
(`FQuat::Slerp` rate-limited by `RCSTorqueDegPerSecond · dt`), spending RCS
propellant; once aligned, it hands off to a full-throttle main-engine burn. The
result is a ship that physically rotates to face its deceleration vector and
burns to kill velocity — a real two-phase manoeuvre, not an animation.

### Gravity zones and loose objects

`UV5_Ship_GravityZone::EvaluateGravityZone` resolves the three habitat regimes:
**Thrust-G** (down is opposite the thrust vector during a burn), **Spin-G**
(down is radial on a centrifuge ring), and **Zero-G** (no field). Pawn
locomotion reads it to decide whether you walk down the deck, walk around the
ring, or float.

The most charming detail is the loose-object simulation.
`UV5_Ship_LooseObjectSim::SimulateLooseObject` models an unsecured object — the
proverbial coffee cup — as keeping its own momentum while the ship accelerates
underneath it: `relativeVelocity -= shipAcceleration · dt`. Strap it down and it
rides along; leave it loose during a burn and it slides aft, exactly as the spec
asserts (`V5SpaceshipTests.cpp:82`).

### Ship weapons: one intercept solver, three barrels

Ship combat is built on a single, real **lead-prediction solver**.
`SolveIntercept` (`V5ShipPhysicsSystems.cpp:26`) frames "when does a projectile
of speed _s_ launched from the origin meet a target at relative position **P**
moving at relative velocity **V**?" as the quadratic `|P + V·t|² = (s·t)²`,
expands it to `A·t² + B·t + C` with `A = V·V − s²`, `B = 2·P·V`, `C = P·P`,
takes the earliest positive root, and confirms the impact point is in range.
Three weapons reuse it with different constants: the **PDC** fires 7 km/s
bullets out to 8 km and additionally gates on a `TrackingQuality ≥ 0.3`
envelope; the **railgun** throws a 60 km/s slug out to 50 km; and the
**torpedo** is a guided physics body (`SimulateTorpedoStep` accelerates it 80
m/s² toward its target) that is itself a valid PDC target — the spec fires the
PDC at a torpedo's body to prove point-defence works
(`V5SpaceshipTests.cpp:96`). Every failure path returns a human-readable
`FailureReason`, never a silent miss.

### Component damage, boarding, and zero-G recoil

Damage is per-component and **cascading**.
`UV5_Ship_DamageModel::ApplyComponentDamage` subtracts HP from the hit
component, then walks every component to emit `CascadingEffects`: an engine
below 50% reduces thrust and at 0 goes offline; comms below 50% emits
`effect.comms.torpedo_guidance_degraded` (shoot out the comms array and the
enemy's torpedoes go dumb); weapons degrade PDC tracking; a dead reactor
triggers an emergency shutdown; a battered airlock flags `boarding_vulnerable`.
Boarding then has teeth: `UV5_Ship_Boarding::EvaluateBoardingClamp` only permits
a magnetic clamp within 25 m **and** near-zero relative drift (≤0.5 m/s), and
only marks the airlock breach-ready within 5° alignment. Finally
`UV5_Ship_ZeroGCombat::ApplyRecoilTumble` enforces Newton's third law on foot:
firing in vacuum pushes the shooter back (`v − dir·impulse/mass`) and induces a
tumble about `dir × up`. These map onto the `V5_AttributeSet_Spaceship` GAS
attributes and the `IMC_SciFi_RCS` / `IMC_SciFi_ZeroG` input contexts in
[./gas-animation-input.md](./gas-animation-input.md).

### Determinism: the rollback substrate

The catalog (`ship_catalog.json`, validated by `UV5_Ship_Catalog`) enforces
exactly **3 player-controllable classes** (Skiff/Corvette/Frigate — Capital
ships are NPC-scale) and **18 ship meshes** under the canonical content path.
But the load-bearing guarantee is determinism:
`V5.Spaceship.FlipBurnDeterminism` (`V5SpaceshipTests.cpp:121`) runs a 3600-step
flip-and-burn **twice from the same initial state** and asserts the final
position, velocity, and attitude match to within 0.001. That bit-stability is
precisely what the
[netcode rollback model](./netcode-authority-and-determinism.md) needs to rewind
and resimulate eight frames of ship-duel without desync, and why the solver is
hand-written rather than handed to a physics engine whose float path varies by
platform.

## Vehicles: real Chaos, 44 strong

### The handling-tuning model and the Chaos configuration

A V5 vehicle's behaviour is a `FV5VehicleHandlingTuning` struct
(`V5VehicleTypes.h`): top speed, 0–60 time, brake deceleration, steering
responsiveness, mass, wheel count, an optional `HorseTeamSize`, engine torque,
max RPM, fuel capacity, forward gears, and era flags (`bManualChoke`,
`bDrumBrakes`, `bDetachableTrailer`, `bFiveStarWantedSpawn`, `bHeistable`,
`bRadioCapable`). The runtime that brings it to life is the real thing:
`UV5_Vehicle_Base : UChaosWheeledVehicleMovementComponent`, and
`ConfigureChaosMovementFromTuning` (`V5VehicleBase.cpp:113`) translates the data
into genuine Chaos setup objects — it builds a four-key
`EngineSetup.TorqueCurve`, sets `EngineIdleRPM` (950, or 700 with a manual
choke), picks `DifferentialType` (rear-wheel for motorcycles, all-wheel
otherwise), lerps a `ForwardGearRatios` ladder from 3.2 down to 0.72, and
lengthens `GearChangeTime` to 0.75 s for manual-choke era cars. Drag drops to
0.04 for fixed-wing aircraft; downforce rises to 0.8 for sports cars. This is
exactly the per-class tuning the design promises (period autos get high CoG,
drum brakes, narrow tyres) expressed as real Chaos parameters.

`GetEffectiveTuning` then layers customization and damage on top: engine and
wheel scalars (clamped to sane bands) multiply the base numbers, and a
knocked-out engine forces top speed and torque to zero — so the same tuning
struct flows through customization, damage, and back into Chaos every time any
of them changes.

### The catalog: 44 classes, 266 mesh recipes

`MakeV5VehicleDefinitions` (`V5VehicleNativeTuning.cpp`) builds **44 native
vehicle specs**, each paired with one of 44 `UClass` subclasses declared in
`V5VehicleVariants.h` — 24 Modern (cars, bikes, a bicycle, emergency-service
sedans, four helicopters, two planes, three boats, two trucks, tank, APC, attack
helo, VTOL), 12 Period across the 1930s/1947/1968 eras, five Frontier (wagon,
stagecoach, riverboat, passenger and cargo trains), and three Hunter.
`V5.Vehicles.CatalogCoverage` asserts `Definitions.Num() == 44` and spot-checks
that the helo civilian/news/ police variants and the heist-able cargo train are
all registered. Subclassing is meaningful:
`UV5_Vehicle_Modern_Sedan_PoliceVariant` derives from the sedan and inherits its
handling while gaining an emergency-override radio profile.

The mesh catalog is the honest content-skeleton seam.
`vehicle_mesh_catalog.json` (validated by `ValidateMeshCatalogJson`) expands
mesh _groups_ into **266 mesh recipe entries** — 120 Urban, 84 Period, 38
Frontier, 24 Hunter — each carrying a source path under
`/Game/V5Vehicles/Meshes/`, an LOD count (≥4 enforced), a triangle budget, and
dimensions. These are recipes, not `.uasset` binaries: the spec asserts the
counts and the path discipline, the validate-headless pattern the rest of V5
uses.

### Customization and damage

`UV5_Vehicle_Damage` is a real, composable model.
`ApplyImpactDamage(joules, zone)` normalizes impact energy against a 120 kJ
reference into body deformation and, for engine hits or impacts above 260 kJ,
degrades `EngineCondition` until a knock-out; `ApplyTireDamage` tracks four
named tyre sockets; and `ApplyChaosDestructionImpulse` is a genuine engine seam
— when the target component is simulating physics it calls
`AddImpulseAtLocation(dir · strength, location)`, the real ChaosDestruction hook
the design names. `V5.Vehicles.HandlingSaveLoad` constructs a real Chaos
movement component, applies a 20 MJ engine impact, and confirms effective top
speed collapses to zero.

The Year-1 **Tier-2 customization** manifest is a validator-gated body shop:
`BuildYear1Tier2Manifest` authors exactly **200 parts** across four domain
groups (50 each: Modern plus three Period eras) — 64 paints, 32 wheels, 32
suspensions, 32 engines, 32 decals, 8 licence plates — every part
Workshop-shareable through `/v5/workshop/vehicle-blueprints/share`.
`ValidateYear1Tier2Manifest` checks every count plus per-part scalar bands and
unique ids, so any drift goes red. A `CalculateHandlingChecksum` (`HashCombine`
over the effective tuning and customization scalars) lets
[./persistence-online-and-crossplay.md](./persistence-online-and-crossplay.md)
save and restore a tuned car and prove the handling round-tripped intact.

## Mounts: the horse as a bonded companion

### Bonding tiers and the gait library

`V5HorseAI` is the one locomotion system with a _relationship_. A horse is an
`FV5HorseState` (bond tier, bond XP, stamina, health, hunger, mood, plus
ability-unlock flags), and `UV5_Horse_Bonding` runs a four-tier ladder — **Wild
→ Familiar (100 XP) → Trusted (300 XP) → Bonded (600 XP)** — where each tier
unlocks behaviour: Trusted grants rear-on-command, side-step, and drift-stop;
Bonded grants calm-under-fire and whistle-recall.
`V5.HorseAI.BondingTierTransitions` walks the whole ladder and asserts each
unlock fires at its threshold.

The gait library is stamina-bounded. `UV5_Horse_GaitLibrary::ApplyGait` enforces
two real rules: a **Wild** horse refuses anything above a Walk, and any gait
whose stamina cost exceeds remaining stamina **forces a slow-down to Walk** with
recovery — you cannot gallop a spent horse. Canter resolves to 15 mph
(`V5.HorseAI.CatalogAndSystems` asserts it), and the applied gait selects a
breed-and-role animation clip from the catalog, which enforces **12 breeds, 4
gaits, and at least 84 clips** (7 roles per breed). Each breed's pawn spec binds
a `skeleton.quadruped.horse` rig, feeding the MetaHuman→Quadruped retarget path
in [./gas-animation-input.md](./gas-animation-input.md).

### Care, spook, recall, and permadeath

The companion loop is four interacting systems. **Care**
(`UV5_Horse_FeedBrushTalk::ApplyCareInteraction`) feeds, brushes, talks to, and
vet-treats the horse — each interaction adjusts hunger/mood/health and awards
bond XP, routing through the bonding ladder so caring for a horse is literally
how you bond it. **Spook** (`UV5_Horse_SpookCalm::EvaluateThreat`) computes
panic as threat plus a gunfire bonus minus a bond-scaled reduction (Wild absorbs
5, Bonded 70); a Wild horse at high panic **throws its rider**, a Bonded one
stays calm. **Recall** (`UV5_Horse_Whistle::RequestRecall`) lets a bonded horse
come when whistled within 300 m, with honest refusal tags (`out_of_range`,
`unbonded`, `threat_blocked` unless calm-under-fire) and a real arrival ETA from
a tier-scaled trot speed.

And **permadeath** gives the bond stakes. `UV5_Horse_Permadeath::ResolveDamage`
applies lethal damage and, when both the horse's flag and the difficulty setting
permit, marks the horse dead and lost — but leaves the **saddlebag recoverable
at the carcass**. The saddlebag (`UV5_Horse_SaddleBagInventory`) is a real
persistent container — 12 weapon slots, 6 outfit slots,
ammo/medicine/food/supplies — whose carry-over is restricted beyond 50 m, the
mechanic that makes losing a bonded horse costly rather than a respawn. None of
this touches Chaos; it is a custom state machine, which is why
`V5HorseAI.Build.cs` lists no physics dependency.

## How it connects to neighbouring systems

These three subsystems plug into the same spine as the rest of V5. The
deterministic ship solver feeds the rollback model and authority rules in
[./netcode-authority-and-determinism.md](./netcode-authority-and-determinism.md);
the handling snapshot, the saddlebag, and the bond tier persist through
[./persistence-online-and-crossplay.md](./persistence-online-and-crossplay.md);
and the ship/vehicle/mount GAS attribute sets and the `IMC_SciFi_RCS`,
`IMC_Frontier_Mount`, and `IMC_Hunter_Mount` input contexts are wired in
[./gas-animation-input.md](./gas-animation-input.md). Which subsystem is even
_loaded_ is a cell decision — the streaming, per-cell module activation, and
Game-Feature gating that decide it live in
[./modes-streaming-procgen.md](./modes-streaming-procgen.md). The Period-era
cars, the horse-bonding and hunting economy, and the bureau/contract framing
that give all of this narrative weight belong to
[./hunter-period-systems-and-bureau-spine.md](./hunter-period-systems-and-bureau-spine.md).
For the design source this page grounds and corrects, see
[../V5_ARCHITECTURE.md](../V5_ARCHITECTURE.md).
