- empty() instead of size() comparisons (cpp:S1155)
- member initialisers in declaration order (cpp:S3229)
- no redundant c_str() when a std::string is accepted (cpp:S7121)
- contains() on associative containers (cpp:S6171)
- const reference instead of a copying range-for (cpp:S6032)
- starts_with() for prefix checks (cpp:S6178)
- no std::move on temporaries (cpp:S5274)
- has_value() on std::optional (cpp:S7172)
- bool literals for bool members (cpp:S5820)
- inline only on the definition (cpp:S3548)
- explicit base access specifier (cpp:S5965)
- explicit element access instead of dereferencing an array (cpp:S7116)
- rely on the C++20 rewritten operator!= (cpp:S6186)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
'DamageFlag & dtrain_bearing > 0' parsed as 'DamageFlag & (dtrain_bearing > 0)',
i.e. DamageFlag & 1, so bearing friction reacted to the wrong damage flag.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
std::unordered_map instances and map types exposed in headers used by
other modules are left as they are.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signatures declared in files touched by PR 206 (Driver.h, EU07.cpp) and
virtual overrides are left unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Applied only where no unqualified name in the block could be captured by
the introduced enumerators.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only local variables and definition parameters are renamed; shadowing
struct fields and enumerators in headers are left for a separate change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Unused names are commented out; parameters used only on some platforms
are marked [[maybe_unused]].
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CabActivisation() passed DirAbsolute (DirActive * CabActive) as the value of the
"Direction" command, which every receiving vehicle stores as its own DirActive.
Every other sender passes DirActive. With the cab at the rear end (CabActive = -1)
the two have opposite signs, so the other units got their reverser flipped
against the controlling one.
It shows whenever a rear cab is activated after the reverser has been set:
- the AI takes over an occupied cab (TakeControl() calls CabActivisation(true)),
e.g. an EN57 inserted with reardriver and a starting velocity: the motor car
drives the train backwards;
- a vehicle without automatic cab activation (SA134) driven by the AI from the
start: the cab is activated by a driver hint after the reverser is set, and
the two units pull against each other.
Fixes#169.
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.