Systems
Loadout & modules
Five hardpoints, dozens of modules, swappable in the field. The whole loadout replicates as a single integer – every machine builds the module meshes itself.
Hardpoints and module definitions
| Hardpoint | Class | Hangs on |
|---|---|---|
| HP_Arm_L / HP_Arm_R | ARM | arm parts |
| HP_Shoulder_L / HP_Shoulder_R | SHOULDER | launcher parts |
| HP_Back | BACK | torso |
A module fits only a hardpoint of the same class. Each definition carries an id, label, class, weight in tonnes, swap time and the prefabs for the left and right side.
One int for the whole loadout
static const int BITS = 5; // up to 31 modules per hardpoint, 0 = empty
[RplProp(onRplName: "OnLoadoutReplicated")]
protected int m_iLoadout;
int GetModuleAt(int hp)
{
return (m_iLoadout >> (hp * BITS)) & 31;
}
void ServerSetModule(int hp, int module)
{
int mask = 31 << (hp * BITS);
m_iLoadout = (m_iLoadout & ~mask) | (module << (hp * BITS));
Replication.BumpMe();
Rebuild(); // onRplName does not fire on the server itself
}
protected void OnLoadoutReplicated()
{
Rebuild();
}
Build locally on every machine
Module entities have no RplComponent. Each machine compares the replicated loadout with what it has
mounted and spawns or deletes the difference itself. That keeps network entity count low and makes late joiners
correct automatically.
protected void Rebuild()
{
for (int hp = 0; hp < HardpointCount(); hp++)
{
int want = GetModuleAt(hp);
if (m_aMounted[hp] == want)
continue;
if (m_aEntities[hp])
SCR_EntityHelper.DeleteEntityAndChildren(m_aEntities[hp]);
m_aEntities[hp] = null;
m_aMounted[hp] = want;
if (want == 0)
continue;
IEntity part = GetPartFor(hp);
EntitySpawnParams sp = new EntitySpawnParams();
sp.TransformMode = ETransformMode.WORLD;
part.GetWorldTransform(sp.Transform);
IEntity e = GetGame().SpawnEntityPrefab(Resource.Load(PrefabFor(hp, want)), part.GetWorld(), sp);
part.AddChild(e, -1);
e.SetLocalTransform(OffsetFor(hp));
m_aEntities[hp] = e;
// new children report garbage transforms in their first frame: re-scan weapons a bit later
GetGame().GetCallqueue().CallLater(RescanWeapons, 400, false, hp);
}
}
Weight and speed
Payload is the sum of the module weights. Top speed = 60 − 1 km/h per tonne (minimum 5), ×0.75 when
overloaded above 20 t. The leg drive uses it as vmax, and a limiter on the physics owner clamps the
horizontal velocity in case anything else (a jump, a push) exceeds it.
Swapping in the field
The commander requests a swap through the PlayerController. The server checks the seat, that the walker is parked and that a depot is near, then runs a swap timer. Each machine shows a progress bar from a small replicated start counter per hardpoint, so the bar restarts on every machine without sending times.