17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-05 05:14:27 +01:00

Merge branch 'master' into feat/gl46-migration

This commit is contained in:
2026-10-17 20:57:15 +02:00
21 changed files with 8289 additions and 64 deletions

View File

@@ -19,6 +19,7 @@ http://mozilla.org/MPL/2.0/.
#include "utilities/translation.h"
#include "utilities/Logs.h"
#include "vehicle/Train.h"
#include "vehicle/handover.h"
#include "world/mtable.h"
#include "vehicle/DynObj.h"
#include "world/Event.h"
@@ -5561,6 +5562,12 @@ void TController::TakeControl( bool const Aidriver, bool const Forcevehiclecheck
{ // teraz AI prowadzi
AIControllFlag = AIdriver;
pVehicle->Controller = AIdriver;
// the AI doesn't operate the headlight dimmer, drop the state left by the human driver
// so the lights set by the AI aren't hidden (dimmer in off position) or dimmed
pVehicle->HeadlightsAoff = false;
pVehicle->HeadlightsBoff = false;
pVehicle->DimHeadlights = false;
pVehicle->HighBeamLights = false;
control_lights(); // reinicjalizacja swiatel
mvOccupied->CabActivisation(true);
iDirection = 0; // kierunek jazdy trzeba dopiero zgadnąć
@@ -5598,10 +5605,23 @@ void TController::TakeControl( bool const Aidriver, bool const Forcevehiclecheck
}
else
{ // a teraz użytkownik
if (!is_train() || !is_car()) // gasimy swiatla jesli przejmujemy odstawione
if (eAction == TAction::actSleep || OrderCurrentGet() == Wait_for_orders) // gasimy swiatla jesli przejmujemy odstawione
pVehicle->RaLightsSet(0, 0);
auto const aiwasdriving { AIControllFlag == AIdriver };
if( aiwasdriving ) {
// the horn, sandbox, departure signal and brake releaser the AI may have latched are momentary for the human driver
handover::release_ai_controls( *mvOccupied, *mvControlling );
fWarningDuration = 0.0;
remove_hint( driver_hint::hornon );
// the AI sets the lights directly, leave the selector in matching position so it doesn't revert them later
sync_lights_selector();
}
AIControllFlag = Humandriver;
pVehicle->Controller = Humandriver;
if( aiwasdriving ) {
// same with the headlight dimmer, which is only applied for the human driver
sync_lights_dimmer();
}
if( eAction == TAction::actSleep ) {
eAction = TAction::actUnknown;
}
@@ -6329,6 +6349,57 @@ TController::control_handles() {
} } // enginetype
}
// moves the light preset selector to the position matching the lights set directly by the AI,
// otherwise the next SetLights() call (e.g. from CheckVehicles()) reverts them to the untouched selector position
void
TController::sync_lights_selector() {
if( mvOccupied->LightsPosNo <= 0 ) { return; }
auto const *headvehicle { pVehicles[ end::front ] };
if( headvehicle == nullptr ) { return; }
// same choice of the light table as in TDynamicObject::SetLights()
auto const lightstable { ( mvOccupied->CabOccupied * pVehicle->DirectionGet() >= 0 ? end::front : end::rear ) };
// same choice of the lit vehicle end as in TDynamicObject::RaLightsSet()
auto const headend { ( headvehicle->iDirection > 0 ? end::front : end::rear ) };
auto const position { handover::light_selector_position(
*mvOccupied, lightstable, headvehicle->MoverParameters->iLights[ headend ], headvehicle->LightList( headend ) ) };
if( position == mvOccupied->LightsPos ) { return; }
mvOccupied->LightsPos = position;
// visual feedback
auto *train { simulation::Trains.find( pVehicle->name() ) };
if( train != nullptr ) {
train->ggLightsButton.PutValue( static_cast<float>( position - 1 ) );
}
}
// re-applies the headlight dimmer state after the AI handed the vehicle over to the human driver,
// moving the dimmer out of the off position if it'd hide the head lights set by the AI
void
TController::sync_lights_dimmer() {
if( mvOccupied->dimPositions.empty() ) { return; }
auto const *headvehicle { pVehicles[ end::front ] };
auto const headend { ( headvehicle != nullptr && headvehicle->iDirection > 0 ? end::front : end::rear ) };
auto const headlightson {
headvehicle != nullptr
&& ( headvehicle->MoverParameters->iLights[ headend ] & ( light::headlight_left | light::headlight_right | light::headlight_upper ) ) != 0 };
auto const position { handover::dimmer_position( *mvOccupied, headlightson ) };
if( position != mvOccupied->modernDimmerPosition ) {
mvOccupied->modernDimmerPosition = position;
// visual feedback
auto *train { simulation::Trains.find( pVehicle->name() ) };
if( train != nullptr ) {
train->ggModernLightDimSw.PutValue( static_cast<float>( position ) );
}
}
if( position < 0 || position >= static_cast<int>( mvOccupied->dimPositions.size() ) ) { return; } // SetLightDimmings() doesn't check the range
pVehicle->SetLightDimmings();
}
// activate consist lamp codes
void
TController::control_lights() {

View File

@@ -324,6 +324,8 @@ private:
void control_security_system( double const Timedelta );
void control_handles();
void control_lights();
void sync_lights_selector();
void sync_lights_dimmer();
void control_compartment_lights();
void control_doors();
void UpdateCommand();

76
vehicle/handover.cpp Normal file
View File

@@ -0,0 +1,76 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "vehicle/handover.h"
#include "McZapkie/MOVER.h"
namespace handover {
void release_ai_controls(TMoverParameters &Occupied, TMoverParameters &Controlling) {
// the AI's hornoff action touches the horn only while the AI drives
Occupied.WarningSignal = 0;
// the AI drives the sandbox directly, bypassing the manual and automatic sanding states
if (Controlling.SandDose && false == (Controlling.SandDoseManual || Controlling.SandDoseAuto)) {
Controlling.Sandbox(false);
}
if (Occupied.DepartureSignal) {
Occupied.signal_departure(false);
}
if (Occupied.Hamulec->Releaser()) {
Occupied.BrakeReleaser(0);
}
}
int light_selector_position(TMoverParameters const &Occupied, int const Lightstable, int const Headlights, int const Inventory) {
// the selector size comes from the vehicle definition, the table holds a fixed number of positions
auto const positioncount{std::min(Occupied.LightsPosNo, static_cast<int>(std::size(Occupied.Lights[0])))};
if (positioncount <= 0 || Lightstable < 0 || Lightstable >= static_cast<int>(std::size(Occupied.Lights))) {
return Occupied.LightsPos;
}
auto const &lights{Occupied.Lights[Lightstable]};
auto const lightsmatch{[&lights, Inventory, Headlights](int const Position) { return (lights[Position - 1] & Inventory) == Headlights; }};
if (Occupied.LightsPos >= 1 && Occupied.LightsPos <= positioncount && lightsmatch(Occupied.LightsPos)) {
return Occupied.LightsPos;
}
for (auto position = 1; position <= positioncount; ++position) {
if (lightsmatch(position)) {
return position;
}
}
return Occupied.LightsPos;
}
int dimmer_position(TMoverParameters const &Occupied, bool const Headlightson) {
auto const &positions{Occupied.dimPositions};
auto const current{Occupied.modernDimmerPosition};
auto const count{static_cast<int>(positions.size())};
auto const isoff{[&positions, count](int const Position) { return Position < 0 || Position >= count || positions[Position].isOff; }};
if (false == Occupied.enableModernDimmer || false == Headlightson || false == isoff(current)) {
return current;
}
if (false == isoff(Occupied.modernDimmerDefaultPosition)) {
return Occupied.modernDimmerDefaultPosition;
}
for (auto position = 0; position < count; ++position) {
if (false == (positions[position].isOff || positions[position].isDimmed || positions[position].isHighBeam)) {
return position;
}
}
for (auto position = 0; position < count; ++position) {
if (false == positions[position].isOff) {
return position;
}
}
return current;
}
} // namespace handover

33
vehicle/handover.h Normal file
View File

@@ -0,0 +1,33 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
class TMoverParameters;
// what changes about a vehicle when the AI hands it over to the human driver. the AI operates some
// controls directly, bypassing the cab controls a human uses, and only the AI ever releases them;
// the human gets them in the state matching the cab controls instead.
namespace handover {
// releases what the AI latches, but which is held only while pressed for the human driver:
// the horn, the sandbox, the departure signal and the brake releaser
void release_ai_controls(TMoverParameters &Occupied, TMoverParameters &Controlling);
// position of the light preset selector [1..LightsPosNo] for the human driver: the current one when it
// gives the head lights the AI has set, else the first one which does, else the current one.
// Lightstable is the end of the selector's table in use, Inventory the lights the head end has
int light_selector_position(TMoverParameters const &Occupied, int Lightstable, int Headlights, int Inventory);
// position of the headlight dimmer for the human driver: the current one, unless it's the off position
// which would hide the head lights the AI has lit. then the default one, else the first regular one,
// else any other than off
int dimmer_position(TMoverParameters const &Occupied, bool Headlightson);
} // namespace handover