- a cab with only the combined horn lever (horn_bt:) and no separate tone buttons could sound the low
and high tones at once, which the lever can't do; the tones are now exclusive there, and releasing
the other tone's key keeps the lever in place (eu07/maszyna#392),
- a skid ends when the wheel speed crosses the vehicle speed, which never happens with wheels locked
by the brakes once the vehicle has stopped; it stayed flagged as slipping, its braking force capped by
the sliding adhesion, so a few such wagons could push a braked consist around (eu07/maszyna#479).
Like the Vel > 0.1 trap of the skid start, a (nearly) stopped vehicle with wheels turning at its
speed is no longer slipping,
- lit electronic destination signs kept showing the relation after the timetable had ended, until the
battery was switched off (eu07/maszyna#446); they are blanked when the timetable runs out, physical
signs stay up until changed.
What the horn keys do to WarningSignal moves out of the TTrain command handlers into vehicle/horn, which
the unit tests call; the handlers keep the gauges. Tests: tests/unit/test_horn.cpp, both kinds of cabs,
and tests/unit/test_wheelslip.cpp, a wagon which stopped in a skid on slippery rail holds on a slope
like one which stopped on dry rail (without the fix it runs away, ~70 km/h after 30 s).
The dumb3d->glm / utilities-simplification refactor replaced the old custom
clamp() (which tolerated Lo>Hi, returning the upper bound) with std::clamp,
where inverted bounds are undefined behaviour. Only a few sites were patched
afterwards, by hand, with std::minmax plumbing (incl. a stray `static` inside
a per-axle loop). Others silently produced wrong results in the AI braking /
acceleration path.
Add a safe_clamp() helper (normalizes inverted bounds) and use it ONLY where
Lo<=Hi cannot be proven at compile time (config min/max pairs, sign-dependent
expressions, container underflow). Sites with constant bounds or [0, x>=0]
keep std::clamp. Remove the manual std::minmax workarounds and rewrite the
damaged-track jolt code value-first.
- The `TMoverParameters::derail()` function has been renamed to `::Derail()`, with a capital D.
- All derail events now use that function.
- Simplified and unified the logic behind different derail types.
- The `dtrack_freerail` track type is now slightly increasing the chance of derailing on a tight curve, as it was the intention.
- A new `DerailReason` enum has been created which holds all derail types.
- The `DerailReason` field in the `TMoverParameters` class has been removed.
- This was a transient field which is not necessary anymore.
- The logging functionality as such has been moved from `DynObj.cpp` to `Mover.cpp`.