16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-09-01 15:09:18 +02:00

refactor: split Oncommmands from Train

This commit is contained in:
jerrrrycho
2026-07-27 23:39:26 +02:00
parent d9eb705d4a
commit 7a40ec65b5
14 changed files with 7386 additions and 7317 deletions

View File

@@ -98,6 +98,14 @@ set(SOURCES
"world/Traction.cpp" "world/Traction.cpp"
"world/TractionPower.cpp" "world/TractionPower.cpp"
"vehicle/Train.cpp" "vehicle/Train.cpp"
"vehicle/Train_Commands_Auxiliary.cpp"
"vehicle/Train_Commands_Brakes.cpp"
"vehicle/Train_Commands_Controls.cpp"
"vehicle/Train_Commands_Doors.cpp"
"vehicle/Train_Commands_Electrical.cpp"
"vehicle/Train_Commands_Lights.cpp"
"vehicle/Train_Commands_Misc.cpp"
"vehicle/Train_Commands_Radio.cpp"
"world/TrkFoll.cpp" "world/TrkFoll.cpp"
"vehicle/AirCoupler.cpp" "vehicle/AirCoupler.cpp"
"model/AnimModel.cpp" "model/AnimModel.cpp"

View File

@@ -7,7 +7,6 @@ obtain one at
http://mozilla.org/MPL/2.0/. http://mozilla.org/MPL/2.0/.
*/ */
#include "stdafx.h"
#include "vehicle/AirCoupler.h" #include "vehicle/AirCoupler.h"
#include "model/Model3d.h" #include "model/Model3d.h"

View File

@@ -14,7 +14,6 @@ http://mozilla.org/MPL/2.0/.
#include "vehicle/DynObj.h" #include "vehicle/DynObj.h"
#include "Console.h" #include "Console.h"
#include "utilities/Logs.h" #include "utilities/Logs.h"
#include "rendering/renderer.h"
void TButton::Clear(int i) void TButton::Clear(int i)
{ {

View File

@@ -16,7 +16,6 @@ http://mozilla.org/MPL/2.0/.
#include "audio/sound.h" #include "audio/sound.h"
#include "vehicle/DynObj.h" #include "vehicle/DynObj.h"
#include "world/mtable.h" #include "world/mtable.h"
#include "utilities/translation.h"
#include "application/driverhints.h" #include "application/driverhints.h"
auto const EU07_AI_ACCELERATION = 0.05; auto const EU07_AI_ACCELERATION = 0.05;

View File

@@ -17,7 +17,6 @@ http://mozilla.org/MPL/2.0/.
#include "simulation/simulation.h" #include "simulation/simulation.h"
#include "rendering/lightarray.h" #include "rendering/lightarray.h"
#include "vehicle/Camera.h"
#include "vehicle/Train.h" #include "vehicle/Train.h"
#include "vehicle/Driver.h" #include "vehicle/Driver.h"
#include "utilities/Globals.h" #include "utilities/Globals.h"
@@ -32,7 +31,6 @@ http://mozilla.org/MPL/2.0/.
#include "rendering/renderer.h" #include "rendering/renderer.h"
#include "application/uitranscripts.h" #include "application/uitranscripts.h"
#include "input/messaging.h" #include "input/messaging.h"
#include "vehicle/Driver.h"
// Ra: taki zapis funkcjonuje lepiej, ale może nie jest optymalny // Ra: taki zapis funkcjonuje lepiej, ale może nie jest optymalny
#define vWorldFront glm::vec3(0, 0, 1) #define vWorldFront glm::vec3(0, 0, 1)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,586 @@
/*
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/Train.h"
#include "world/Event.h"
#include "simulation/simulationtime.h"
#include "utilities/Logs.h"
#include "model/Model3d.h"
#include "vehicle/Driver.h"
#include <future>
void TTrain::OnCommand_fuelpumptoggle(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_REPEAT)
{
return;
}
if (Train->ggFuelPumpButton.type() == TGaugeType::push)
{
// impulse switch
// currently there's no off button so we always try to turn it on
OnCommand_fuelpumpenable(Train, Command);
}
else
{
// two-state switch
if (Command.action == GLFW_RELEASE)
{
return;
}
if (false == Train->mvControlled->FuelPump.is_enabled)
{
// turn on
OnCommand_fuelpumpenable(Train, Command);
}
else
{
// turn off
OnCommand_fuelpumpdisable(Train, Command);
}
}
}
void TTrain::OnCommand_fuelpumpenable(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_REPEAT)
{
return;
}
if (Train->ggFuelPumpButton.type() == TGaugeType::push)
{
// impulse switch
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggFuelPumpButton.UpdateValue(1.0, Train->dsbSwitch);
Train->mvControlled->FuelPumpSwitch(true);
}
else if (Command.action == GLFW_RELEASE)
{
// visual feedback
Train->ggFuelPumpButton.UpdateValue(0.0, Train->dsbSwitch);
Train->mvControlled->FuelPumpSwitch(false);
}
}
else
{
// two-state switch, only cares about press events
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggFuelPumpButton.UpdateValue(1.0, Train->dsbSwitch);
Train->mvControlled->FuelPumpSwitch(true);
Train->mvControlled->FuelPumpSwitchOff(false);
}
}
}
void TTrain::OnCommand_fuelpumpdisable(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_REPEAT)
{
return;
}
if (Train->ggFuelPumpButton.type() == TGaugeType::push)
{
// impulse switch
// currently there's no disable return type switch
return;
}
else
{
// two-state switch, only cares about press events
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggFuelPumpButton.UpdateValue(0.0, Train->dsbSwitch);
Train->mvControlled->FuelPumpSwitch(false);
Train->mvControlled->FuelPumpSwitchOff(true);
}
}
}
void TTrain::OnCommand_oilpumptoggle(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_REPEAT)
{
return;
}
if (Train->ggOilPumpButton.type() == TGaugeType::push)
{
// impulse switch
// currently there's no off button so we always try to turn it on
OnCommand_oilpumpenable(Train, Command);
}
else
{
// two-state switch
if (Command.action == GLFW_RELEASE)
{
return;
}
if (false == Train->mvControlled->OilPump.is_enabled)
{
// turn on
OnCommand_oilpumpenable(Train, Command);
}
else
{
// turn off
OnCommand_oilpumpdisable(Train, Command);
}
}
}
void TTrain::OnCommand_oilpumpenable(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_REPEAT)
{
return;
}
if (Train->ggOilPumpButton.type() == TGaugeType::push)
{
// impulse switch
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggOilPumpButton.UpdateValue(1.0, Train->dsbSwitch);
Train->mvControlled->OilPumpSwitch(true);
}
else if (Command.action == GLFW_RELEASE)
{
// visual feedback
Train->ggOilPumpButton.UpdateValue(0.0, Train->dsbSwitch);
Train->mvControlled->OilPumpSwitch(false);
}
}
else
{
// two-state switch, only cares about press events
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggOilPumpButton.UpdateValue(1.0, Train->dsbSwitch);
Train->mvControlled->OilPumpSwitch(true);
Train->mvControlled->OilPumpSwitchOff(false);
}
}
}
void TTrain::OnCommand_oilpumpdisable(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_REPEAT)
{
return;
}
if (Train->ggOilPumpButton.type() == TGaugeType::push)
{
// impulse switch
// currently there's no disable return type switch
return;
}
else
{
// two-state switch, only cares about press events
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggOilPumpButton.UpdateValue(0.0, Train->dsbSwitch);
Train->mvControlled->OilPumpSwitch(false);
Train->mvControlled->OilPumpSwitchOff(true);
}
}
}
void TTrain::OnCommand_waterheaterbreakertoggle(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if (false == Train->mvControlled->WaterHeater.breaker)
{
// turn on
OnCommand_waterheaterbreakerclose(Train, Command);
}
else
{
// turn off
OnCommand_waterheaterbreakeropen(Train, Command);
}
}
}
void TTrain::OnCommand_waterheaterbreakerclose(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggWaterHeaterBreakerButton.UpdateValue(1.0, Train->dsbSwitch);
if (true == Train->mvControlled->WaterHeater.breaker)
{
return;
} // already enabled
Train->mvControlled->WaterHeaterBreakerSwitch(true);
}
}
void TTrain::OnCommand_waterheaterbreakeropen(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggWaterHeaterBreakerButton.UpdateValue(0.0, Train->dsbSwitch);
if (false == Train->mvControlled->WaterHeater.breaker)
{
return;
} // already enabled
Train->mvControlled->WaterHeaterBreakerSwitch(false);
}
}
void TTrain::OnCommand_waterheatertoggle(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if (false == Train->mvControlled->WaterHeater.is_enabled)
{
// turn on
OnCommand_waterheaterenable(Train, Command);
}
else
{
// turn off
OnCommand_waterheaterdisable(Train, Command);
}
}
}
void TTrain::OnCommand_waterheaterenable(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggWaterHeaterButton.UpdateValue(1.0, Train->dsbSwitch);
if (true == Train->mvControlled->WaterHeater.is_enabled)
{
return;
} // already enabled
Train->mvControlled->WaterHeaterSwitch(true);
}
}
void TTrain::OnCommand_waterheaterdisable(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggWaterHeaterButton.UpdateValue(0.0, Train->dsbSwitch);
if (false == Train->mvControlled->WaterHeater.is_enabled)
{
return;
} // already disabled
Train->mvControlled->WaterHeaterSwitch(false);
}
}
void TTrain::OnCommand_waterpumpbreakertoggle(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if (false == Train->mvControlled->WaterPump.breaker)
{
// turn on
OnCommand_waterpumpbreakerclose(Train, Command);
}
else
{
// turn off
OnCommand_waterpumpbreakeropen(Train, Command);
}
}
}
void TTrain::OnCommand_waterpumpbreakerclose(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggWaterPumpBreakerButton.UpdateValue(1.0, Train->dsbSwitch);
if (true == Train->mvControlled->WaterPump.breaker)
{
return;
} // already enabled
Train->mvControlled->WaterPumpBreakerSwitch(true);
}
}
void TTrain::OnCommand_waterpumpbreakeropen(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggWaterPumpBreakerButton.UpdateValue(0.0, Train->dsbSwitch);
if (false == Train->mvControlled->WaterPump.breaker)
{
return;
} // already enabled
Train->mvControlled->WaterPumpBreakerSwitch(false);
}
}
void TTrain::OnCommand_waterpumptoggle(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_REPEAT)
{
return;
}
if (Train->ggWaterPumpButton.type() == TGaugeType::push)
{
// impulse switch
// currently there's no off button so we always try to turn it on
OnCommand_waterpumpenable(Train, Command);
}
else
{
// two-state switch
if (Command.action == GLFW_RELEASE)
{
return;
}
if (false == Train->mvControlled->WaterPump.is_enabled)
{
// turn on
OnCommand_waterpumpenable(Train, Command);
}
else
{
// turn off
OnCommand_waterpumpdisable(Train, Command);
}
}
}
void TTrain::OnCommand_waterpumpenable(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_REPEAT)
{
return;
}
if (Train->ggWaterPumpButton.type() == TGaugeType::push)
{
// impulse switch
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggWaterPumpButton.UpdateValue(1.0, Train->dsbSwitch);
Train->mvControlled->WaterPumpSwitch(true);
}
else if (Command.action == GLFW_RELEASE)
{
// visual feedback
Train->ggWaterPumpButton.UpdateValue(0.0, Train->dsbSwitch);
Train->mvControlled->WaterPumpSwitch(false);
}
}
else
{
// two-state switch, only cares about press events
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggWaterPumpButton.UpdateValue(1.0, Train->dsbSwitch);
Train->mvControlled->WaterPumpSwitch(true);
Train->mvControlled->WaterPumpSwitchOff(false);
}
}
}
void TTrain::OnCommand_waterpumpdisable(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_REPEAT)
{
return;
}
if (Train->ggWaterPumpButton.type() == TGaugeType::push)
{
// impulse switch
// currently there's no disable return type switch
return;
}
else
{
// two-state switch, only cares about press events
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggWaterPumpButton.UpdateValue(0.0, Train->dsbSwitch);
Train->mvControlled->WaterPumpSwitch(false);
Train->mvControlled->WaterPumpSwitchOff(true);
}
}
}
void TTrain::OnCommand_watercircuitslinktoggle(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if (false == Train->mvControlled->WaterCircuitsLink)
{
// turn on
OnCommand_watercircuitslinkenable(Train, Command);
}
else
{
// turn off
OnCommand_watercircuitslinkdisable(Train, Command);
}
}
}
void TTrain::OnCommand_watercircuitslinkenable(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggWaterCircuitsLinkButton.UpdateValue(1.0, Train->dsbSwitch);
if (true == Train->mvControlled->WaterCircuitsLink)
{
return;
} // already enabled
Train->mvControlled->WaterCircuitsLinkSwitch(true);
}
}
void TTrain::OnCommand_watercircuitslinkdisable(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggWaterCircuitsLinkButton.UpdateValue(0.0, Train->dsbSwitch);
if (false == Train->mvControlled->WaterCircuitsLink)
{
return;
} // already disabled
Train->mvControlled->WaterCircuitsLinkSwitch(false);
}
}
void TTrain::OnCommand_heatingtoggle(TTrain *Train, command_data const &Command)
{
if (Train->ggTrainHeatingButton.SubModel == nullptr)
{
if (Command.action == GLFW_PRESS)
{
WriteLog("Train Heating switch is missing, or wasn't defined");
}
return;
}
if (Command.action == GLFW_PRESS)
{
// ignore repeats so the switch doesn't flip back and forth if key is held down
if (false == Train->mvControlled->HeatingAllow)
{
// turn on
OnCommand_heatingenable(Train, Command);
}
else
{
// turn off
OnCommand_heatingdisable(Train, Command);
}
}
else if (Command.action == GLFW_RELEASE && Train->ggTrainHeatingButton.type() == TGaugeType::push)
{
// impulse switch
// visual feedback
Train->ggTrainHeatingButton.UpdateValue(0.0, Train->dsbSwitch);
}
}
void TTrain::OnCommand_heatingenable(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
Train->mvOccupied->HeatingSwitch(true);
// visual feedback
Train->ggTrainHeatingButton.UpdateValue(1.0, Train->dsbSwitch);
}
}
void TTrain::OnCommand_heatingdisable(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
Train->mvOccupied->HeatingSwitch(false);
// visual feedback
Train->ggTrainHeatingButton.UpdateValue(Train->ggTrainHeatingButton.type() == TGaugeType::push ? 1.0 : 0.0, Train->dsbSwitch);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,838 @@
/*
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/Train.h"
#include "world/Event.h"
#include "simulation/simulationtime.h"
#include "utilities/Logs.h"
#include "model/Model3d.h"
#include "vehicle/Driver.h"
#include "vehicle/DynObj.h"
#include <future>
#include <algorithm>
auto const EU07_CONTROLLER_BASERETURNDELAY{0.5f};
auto const EU07_CONTROLLER_KEYBOARDETURNDELAY{1.5f};
void TTrain::OnCommand_aidriverenable(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// on press
if (Train->DynamicObject->Mechanik == nullptr)
{
return;
}
if (true == Train->DynamicObject->Mechanik->AIControllFlag)
{
// żeby nie trzeba było rozłączać dla zresetowania
Train->DynamicObject->Mechanik->TakeControl(false);
}
Train->DynamicObject->Mechanik->TakeControl(true);
}
}
void TTrain::OnCommand_aidriverdisable(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS && Train->DynamicObject->Mechanik)
{
// on press
Train->DynamicObject->Mechanik->TakeControl(false);
}
}
void TTrain::OnCommand_jointcontrollerset(TTrain *Train, command_data const &Command)
{
if (Command.action != GLFW_RELEASE)
{
// on press or hold
// value controls brake in range 0-0.5, master controller in range 0.5-1.0
if (Command.param1 >= 0.5)
{
Train->set_master_controller((Command.param1 * 2 - 1) *
(Train->mvControlled->CoupledCtrl ? Train->mvControlled->MainCtrlPosNo + Train->mvControlled->ScndCtrlPosNo : Train->mvControlled->MainCtrlPosNo));
Train->m_mastercontrollerinuse = true;
// when SplitEDPneumaticBrake is active the joint controller's negative range
// commands the dedicated dynamic-brake lever instead of the local pneumatic brake
if (Train->mvControlled->SplitEDPneumaticBrake)
{
Train->mvControlled->DynamicBrakeLevelSet(0.0);
}
else
{
Train->mvOccupied->LocalBrakePosA = 0;
}
}
else
{
auto const negativeRange{std::clamp(1.0 - Command.param1 * 2, 0.0, 1.0)};
if (Train->mvControlled->SplitEDPneumaticBrake)
{
// negative range of jointctrl drives only ED braking, local pneumatic brake stays untouched.
// snap to DBPN discrete stops so the lever animates step-by-step
auto const stepCount{std::max(1, Train->mvControlled->DynamicBrakeCtrlPosNo)};
auto const snapped{std::round(negativeRange * stepCount) / stepCount};
Train->mvControlled->DynamicBrakeLevelSet(snapped);
}
else
{
Train->mvOccupied->LocalBrakePosA = negativeRange;
}
if (Train->mvControlled->MainCtrlPowerPos() > 0)
{
Train->set_master_controller(Train->mvControlled->MainCtrlNoPowerPos());
}
}
}
else
{
// release
Train->m_mastercontrollerinuse = false;
Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_BASERETURNDELAY; // NOTE: keyboard return delay is omitted for other input sources
}
}
void TTrain::OnCommand_mastercontrollerincrease(TTrain *Train, command_data const &Command)
{
if (Command.action != GLFW_RELEASE)
{
// on press or hold
auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake};
// when SplitEDPneumaticBrake is true the joint controller's negative range maps
// to the dedicated dynamic-brake lever (DynamicBrakeCtrl) rather than to LocalBrake
auto const negativeRangeActive{splitMode ? Train->mvControlled->DynamicBrakeCtrlPos > 0.0 : Train->mvOccupied->LocalBrakePosA > 0.0};
if (Train->ggJointCtrl.SubModel != nullptr && negativeRangeActive)
{
if (splitMode)
{
OnCommand_DynamicBrakeControllerDecrease(Train, Command);
Train->m_mastercontrollerinuse = true;
}
else
{
OnCommand_independentbrakedecrease(Train, Command);
}
}
else
{
Train->mvControlled->IncMainCtrl(1);
Train->m_mastercontrollerinuse = true;
}
}
else if (Command.action == GLFW_RELEASE)
{
// release
Train->m_mastercontrollerinuse = false;
Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_KEYBOARDETURNDELAY + EU07_CONTROLLER_BASERETURNDELAY;
}
}
void TTrain::OnCommand_mastercontrollerincreasefast(TTrain *Train, command_data const &Command)
{
if (Command.action != GLFW_RELEASE)
{
// on press or hold
auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake};
auto const negativeRangeActive{splitMode ? Train->mvControlled->DynamicBrakeCtrlPos > 0.0 : Train->mvOccupied->LocalBrakePosA > 0.0};
if (Train->ggJointCtrl.SubModel != nullptr && negativeRangeActive)
{
if (splitMode)
{
OnCommand_DynamicBrakeControllerDecreaseFast(Train, Command);
Train->m_mastercontrollerinuse = true;
}
else
{
OnCommand_independentbrakedecreasefast(Train, Command);
}
}
else
{
Train->mvControlled->IncMainCtrl(Train->mvControlled->MainCtrlPosNo);
Train->m_mastercontrollerinuse = true;
}
}
else
{
// release
Train->m_mastercontrollerinuse = false;
Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_KEYBOARDETURNDELAY + EU07_CONTROLLER_BASERETURNDELAY;
}
}
void TTrain::OnCommand_mastercontrollerdecrease(TTrain *Train, command_data const &Command)
{
if (Command.action != GLFW_RELEASE)
{
// on press or hold
auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake};
if (Train->ggJointCtrl.SubModel != nullptr && Train->mvControlled->IsMainCtrlNoPowerPos())
{
// negative range of jointctrl: ED brake when split, otherwise pneumatic local brake
if (splitMode)
{
OnCommand_DynamicBrakeControllerIncrease(Train, Command);
Train->m_mastercontrollerinuse = true;
}
else
{
OnCommand_independentbrakeincrease(Train, Command);
}
}
else
{
Train->mvControlled->DecMainCtrl(1);
Train->m_mastercontrollerinuse = true;
}
}
else if (Command.action == GLFW_RELEASE)
{
// release
Train->m_mastercontrollerinuse = false;
Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_KEYBOARDETURNDELAY + EU07_CONTROLLER_BASERETURNDELAY;
}
}
void TTrain::OnCommand_mastercontrollerdecreasefast(TTrain *Train, command_data const &Command)
{
if (Command.action != GLFW_RELEASE)
{
// on press or hold
auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake};
if (Train->ggJointCtrl.SubModel != nullptr && Train->mvControlled->IsMainCtrlNoPowerPos())
{
if (splitMode)
{
OnCommand_DynamicBrakeControllerIncreaseFast(Train, Command);
Train->m_mastercontrollerinuse = true;
}
else
{
OnCommand_independentbrakeincreasefast(Train, Command);
}
}
else
{
Train->mvControlled->DecMainCtrl(Train->mvControlled->MainCtrlPowerPos());
Train->m_mastercontrollerinuse = true;
}
}
else
{
// release
Train->m_mastercontrollerinuse = false;
Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_KEYBOARDETURNDELAY + EU07_CONTROLLER_BASERETURNDELAY;
}
}
void TTrain::OnCommand_mastercontrollerset(TTrain *Train, command_data const &Command)
{
if (Command.action != GLFW_RELEASE)
{
// on press or hold
Train->set_master_controller(Command.param1);
Train->m_mastercontrollerinuse = true;
}
else
{
// release
Train->m_mastercontrollerinuse = false;
Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_BASERETURNDELAY; // NOTE: keyboard return delay is omitted for other input sources
}
}
void TTrain::OnCommand_secondcontrollerincrease(TTrain *Train, command_data const &Command)
{
if (Train->mvControlled->EngineType == TEngineType::DieselElectric && true == Train->mvControlled->ShuntModeAllow && true == Train->mvControlled->ShuntMode)
{
if (Command.action != GLFW_RELEASE)
{
Train->mvControlled->AnPos = std::clamp(Train->mvControlled->AnPos + 0.025, 0.0, 1.0);
}
}
else
{
// regular mode
// push or pushtoggle control type
if (Train->ggScndCtrl.is_push())
{
if (Command.action == GLFW_PRESS)
{
// activate on press
Train->mvControlled->IncScndCtrl(1);
}
}
// toggle control type
else
{
if (Command.action != GLFW_RELEASE)
{
Train->mvControlled->IncScndCtrl(1);
}
}
// HACK: potentially animate push or pushtoggle control
if (Train->ggScndCtrl.is_push())
{
auto const activeposition{Train->ggScndCtrl.is_toggle() ? 1.f : 1.f};
auto const neutralposition{Train->ggScndCtrl.is_toggle() ? 0.5f : 0.f};
Train->ggScndCtrl.UpdateValue(Command.action == GLFW_RELEASE ? neutralposition : activeposition, Train->dsbSwitch);
}
// potentially animate tempomat button
if (Train->ggScndCtrlButton.is_push() && Train->mvControlled->ScndCtrlPos <= 1)
{
Train->ggScndCtrlButton.UpdateValue(Command.action == GLFW_RELEASE ? 0.f : 1.f, Train->dsbSwitch);
}
}
}
void TTrain::OnCommand_secondcontrollerincreasefast(TTrain *Train, command_data const &Command)
{
if (Command.action != GLFW_RELEASE)
{
// on press or hold
if (Train->mvControlled->EngineType == TEngineType::DieselElectric && true == Train->mvControlled->ShuntMode)
{
Train->mvControlled->AnPos = 1.0;
}
else
{
Train->mvControlled->IncScndCtrl(2);
}
}
}
void TTrain::OnCommand_notchingrelaytoggle(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if (false == Train->mvOccupied->AutoRelayFlag)
{
// turn on
Train->mvOccupied->AutoRelaySwitch(true);
}
else
{
// turn off
Train->mvOccupied->AutoRelaySwitch(false);
}
}
}
void TTrain::OnCommand_tempomattoggle(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_REPEAT)
{
return;
}
if (Train->ggScndCtrlButton.is_push())
{
// impulse switch
if (Command.action == GLFW_RELEASE)
{
// just move the button(s) back to default position
// visual feedback
Train->ggScndCtrlButton.UpdateValue(0.0, Train->dsbSwitch);
Train->ggScndCtrlOffButton.UpdateValue(0.0, Train->dsbSwitch);
return;
}
// glfw_press
if (Train->mvControlled->ScndCtrlPos == 0)
{
// turn on if it's not active
Train->mvControlled->IncScndCtrl(1);
// visual feedback
Train->ggScndCtrlButton.UpdateValue(1.0, Train->dsbSwitch);
}
else
{
// otherwise turn off
Train->mvControlled->DecScndCtrl(2);
// visual feedback
if (Train->m_controlmapper.contains("tempomatoff_sw:"))
{
Train->ggScndCtrlOffButton.UpdateValue(1.0, Train->dsbSwitch);
}
else
{
Train->ggScndCtrlButton.UpdateValue(1.0, Train->dsbSwitch);
}
}
}
else
{
// two-state switch
if (Command.action == GLFW_RELEASE)
{
return;
}
if (Train->mvControlled->ScndCtrlPos == 0)
{
// turn on
Train->mvControlled->IncScndCtrl(1);
// visual feedback
Train->ggScndCtrlButton.UpdateValue(1.0, Train->dsbSwitch);
}
else
{
// turn off
Train->mvControlled->DecScndCtrl(2);
// visual feedback
Train->ggScndCtrlButton.UpdateValue(0.0, Train->dsbSwitch);
}
}
}
void TTrain::OnCommand_distancecounteractivate(TTrain *Train, command_data const &Command)
{
// NOTE: distance meter activation button is presumed to be of impulse type
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggDistanceCounterButton.UpdateValue(1.0, Train->dsbSwitch);
// activate or start anew
if (Train->mvOccupied->isDoubleClickForMeasureNeeded)
{
// handler tempomatu dla podwojnego kliku
if (Train->trainLenghtMeasureTimer >= 0.f) // jesli zdazylismy w czasie sekundy
Train->m_distancecounter = 0.f; // rozpoczynamy pomiar
else
Train->trainLenghtMeasureTimer = Train->mvOccupied->DistanceCounterDoublePressPeriod; // odpalamy zegarek od nowa
}
else
{
// dla pojedynczego kliku
Train->m_distancecounter = 0.f;
}
}
else if (Command.action == GLFW_RELEASE)
{
// visual feedback
Train->ggDistanceCounterButton.UpdateValue(0.0, Train->dsbSwitch);
}
}
void TTrain::OnCommand_mucurrentindicatorothersourceactivate(TTrain *Train, command_data const &Command)
{
if (Train->ggNextCurrentButton.SubModel == nullptr)
{
if (Command.action == GLFW_PRESS)
{
WriteLog("Current Indicator Source switch is missing, or wasn't defined");
}
return;
}
if (Command.action == GLFW_PRESS)
{
// turn on
Train->ShowNextCurrent = true;
// visual feedback
Train->ggNextCurrentButton.UpdateValue(1.0, Train->dsbSwitch);
}
else if (Command.action == GLFW_RELEASE)
{
// turn off
Train->ShowNextCurrent = false;
// visual feedback
Train->ggNextCurrentButton.UpdateValue(0.0, Train->dsbSwitch);
}
}
void TTrain::OnCommand_secondcontrollerdecrease(TTrain *Train, command_data const &Command)
{
if (Train->mvControlled->EngineType == TEngineType::DieselElectric && true == Train->mvControlled->ShuntMode)
{
if (Command.action != GLFW_RELEASE)
{
Train->mvControlled->AnPos = std::clamp(Train->mvControlled->AnPos - 0.025, 0.0, 1.0);
}
}
else
{
// regular mode
// push or pushtoggle control type
if (Train->ggScndCtrl.is_push())
{
// basic push control can't decrease state, but pushtoggle can
if (true == Train->ggScndCtrl.is_toggle() && Command.action == GLFW_PRESS)
{
// activate on press
Train->mvControlled->DecScndCtrl(1);
}
}
// toggle control type
else
{
if (Command.action != GLFW_RELEASE)
{
Train->mvControlled->DecScndCtrl(1);
}
}
// HACK: potentially animate push or pushtoggle control
if (Train->ggScndCtrl.is_push())
{
auto const activeposition{Train->ggScndCtrl.is_toggle() ? 0.f : 1.f};
auto const neutralposition{Train->ggScndCtrl.is_toggle() ? 0.5f : 0.f};
Train->ggScndCtrl.UpdateValue(Command.action == GLFW_RELEASE ? neutralposition : activeposition, Train->dsbSwitch);
}
// potentially animate tempomat button
if (Train->ggScndCtrlButton.is_push() && Train->mvControlled->ScndCtrlPos <= 1)
{
if (Train->m_controlmapper.contains("tempomatoff_sw:"))
{
Train->ggScndCtrlOffButton.UpdateValue(Command.action == GLFW_RELEASE ? 0.f : 1.f, Train->dsbSwitch);
}
else
{
Train->ggScndCtrlButton.UpdateValue(Command.action == GLFW_RELEASE ? 0.f : 1.f, Train->dsbSwitch);
}
}
}
}
void TTrain::OnCommand_secondcontrollerdecreasefast(TTrain *Train, command_data const &Command)
{
if (Command.action != GLFW_RELEASE)
{
// on press or hold
if (Train->mvControlled->EngineType == TEngineType::DieselElectric && true == Train->mvControlled->ShuntMode)
{
Train->mvControlled->AnPos = 0.0;
}
else
{
Train->mvControlled->DecScndCtrl(2);
}
}
}
void TTrain::OnCommand_secondcontrollerset(TTrain *Train, command_data const &Command)
{
auto const targetposition{std::min<int>(Command.param1, Train->mvControlled->ScndCtrlPosNo)};
// HACK: potentially animate push or pushtoggle control
if (Train->ggScndCtrl.is_push())
{
auto const activeposition{Train->ggScndCtrl.is_toggle() ?
(targetposition < Train->mvControlled->ScndCtrlPos ? 0.f :
targetposition > Train->mvControlled->ScndCtrlPos ? 1.f :
Train->ggScndCtrl.GetDesiredValue()) : // leave the control in its current position if it hits the limit
targetposition == 0 ? 0.f :
1.f};
auto const neutralposition{Train->ggScndCtrl.is_toggle() ? 0.5f : 0.f};
Train->ggScndCtrl.UpdateValue(Command.action == GLFW_RELEASE ? neutralposition : activeposition, Train->dsbSwitch);
}
// update control value
if (Command.action != GLFW_RELEASE)
{
// on press or hold
while (targetposition < Train->mvControlled->GetVirtualScndPos() && true == Train->mvControlled->DecScndCtrl(1))
{
// all work is done in the header
}
while (targetposition > Train->mvControlled->GetVirtualScndPos() && true == Train->mvControlled->IncScndCtrl(1))
{
// all work is done in the header
}
}
}
void TTrain::OnCommand_reverserincrease(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// HACK: master controller position isn't set in occupied vehicle in E(D)MUs
// so we do a manual check in relevant vehicle here
if (false == Train->mvControlled->EIMDirectionChangeAllow())
{
return;
}
if (Train->mvOccupied->DirectionForward() && Train->mvOccupied->DirActive && Train->DynamicObject->Mechanik)
{
// aktualizacja skrajnych pojazdów w składzie
Train->DynamicObject->Mechanik->DirectionChange();
}
}
}
void TTrain::OnCommand_reverserdecrease(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// HACK: master controller position isn't set in occupied vehicle in E(D)MUs
// so we do a manual check in relevant vehicle here
if (false == Train->mvControlled->EIMDirectionChangeAllow())
{
return;
}
if (Train->mvOccupied->DirectionBackward() && Train->mvOccupied->DirActive && Train->DynamicObject->Mechanik)
{
// aktualizacja skrajnych pojazdów w składzie
Train->DynamicObject->Mechanik->DirectionChange();
}
}
}
void TTrain::OnCommand_reverserforwardhigh(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// HACK: master controller position isn't set in occupied vehicle in E(D)MUs
// so we do a manual check in relevant vehicle here
if (false == Train->mvControlled->EIMDirectionChangeAllow())
{
return;
}
// HACK: try to move the reverser one position back, in case it's set to "high forward"
OnCommand_reverserdecrease(Train, Command);
if (Train->mvOccupied->DirActive < 1)
{
while (Train->mvOccupied->DirActive < 1 && true == Train->mvOccupied->DirectionForward())
{
// all work is done in the header
}
// aktualizacja skrajnych pojazdów w składzie
if (Train->mvOccupied->DirActive == 1 && Train->DynamicObject->Mechanik)
{
Train->DynamicObject->Mechanik->DirectionChange();
}
}
OnCommand_reverserincrease(Train, Command);
}
}
void TTrain::OnCommand_reverserforward(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// HACK: master controller position isn't set in occupied vehicle in E(D)MUs
// so we do a manual check in relevant vehicle here
if (false == Train->mvControlled->EIMDirectionChangeAllow())
{
return;
}
// HACK: try to move the reverser one position back, in case it's set to "high forward"
// OnCommand_reverserdecrease( Train, Command );
// visual feedback
Train->ggDirForwardButton.UpdateValue(1.0, Train->dsbSwitch);
if (Train->mvOccupied->DirActive == 0)
{
while (Train->mvOccupied->DirActive < 1 && true == Train->mvOccupied->DirectionForward())
{
// all work is done in the header
}
// aktualizacja skrajnych pojazdów w składzie
if (Train->mvOccupied->DirActive == 1 && Train->DynamicObject->Mechanik)
{
Train->DynamicObject->Mechanik->DirectionChange();
}
}
}
else if (Command.action == GLFW_RELEASE)
{
// release
// visual feedback
Train->ggDirForwardButton.UpdateValue(0.0, Train->dsbSwitch);
}
}
void TTrain::OnCommand_reverserneutral(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// HACK: master controller position isn't set in occupied vehicle in E(D)MUs
// so we do a manual check in relevant vehicle here
if (false == Train->mvControlled->EIMDirectionChangeAllow())
{
return;
}
// visual feedback
Train->ggDirNeutralButton.UpdateValue(1.0, Train->dsbSwitch);
while (Train->mvOccupied->DirActive < 0 && true == Train->mvOccupied->DirectionForward())
{
// all work is done in the header
}
while (Train->mvOccupied->DirActive > 0 && true == Train->mvOccupied->DirectionBackward())
{
// all work is done in the header
}
}
else if (Command.action == GLFW_RELEASE)
{
// release
// visual feedback
Train->ggDirNeutralButton.UpdateValue(0.0, Train->dsbSwitch);
}
}
void TTrain::OnCommand_reverserbackward(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// HACK: master controller position isn't set in occupied vehicle in E(D)MUs
// so we do a manual check in relevant vehicle here
if (false == Train->mvControlled->EIMDirectionChangeAllow())
{
return;
}
Train->ggDirBackwardButton.UpdateValue(1.0, Train->dsbSwitch);
if (Train->mvOccupied->DirActive == 0)
{
while (Train->mvOccupied->DirActive > -1 && true == Train->mvOccupied->DirectionBackward())
{
// all work is done in the header
}
// aktualizacja skrajnych pojazdów w składzie
if (Train->mvOccupied->DirActive == -1 && Train->DynamicObject->Mechanik)
{
Train->DynamicObject->Mechanik->DirectionChange();
}
}
}
else if (Command.action == GLFW_RELEASE)
{
// release
// visual feedback
Train->ggDirBackwardButton.UpdateValue(0.0, Train->dsbSwitch);
}
}
void TTrain::OnCommand_speedcontrolincrease(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// only reacting to press, so the switch doesn't flip back and forth if key is held down
Train->mvOccupied->SpeedCtrlInc();
// visual feedback
Train->ggSpeedControlIncreaseButton.UpdateValue(1.0, Train->dsbSwitch);
}
else if (Command.action == GLFW_RELEASE)
{
// release
// visual feedback
Train->ggSpeedControlIncreaseButton.UpdateValue(0.0, Train->dsbSwitch);
}
};
void TTrain::OnCommand_speedcontroldecrease(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// only reacting to press, so the switch doesn't flip back and forth if key is held down
Train->mvOccupied->SpeedCtrlDec();
// visual feedback
Train->ggSpeedControlDecreaseButton.UpdateValue(1.0, Train->dsbSwitch);
}
else if (Command.action == GLFW_RELEASE)
{
// release
// visual feedback
Train->ggSpeedControlDecreaseButton.UpdateValue(0.0, Train->dsbSwitch);
}
};
void TTrain::OnCommand_speedcontrolpowerincrease(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// only reacting to press, so the switch doesn't flip back and forth if key is held down
Train->mvOccupied->SpeedCtrlPowerInc();
// visual feedback
Train->ggSpeedControlPowerIncreaseButton.UpdateValue(1.0, Train->dsbSwitch);
}
else if (Command.action == GLFW_RELEASE)
{
// release
// visual feedback
Train->ggSpeedControlPowerIncreaseButton.UpdateValue(0.0, Train->dsbSwitch);
}
};
void TTrain::OnCommand_speedcontrolpowerdecrease(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// only reacting to press, so the switch doesn't flip back and forth if key is held down
Train->mvOccupied->SpeedCtrlPowerDec();
// visual feedback
Train->ggSpeedControlPowerDecreaseButton.UpdateValue(1.0, Train->dsbSwitch);
}
else if (Command.action == GLFW_RELEASE)
{
// release
// visual feedback
Train->ggSpeedControlPowerDecreaseButton.UpdateValue(0.0, Train->dsbSwitch);
}
};
void TTrain::OnCommand_speedcontrolbutton(TTrain *Train, command_data const &Command)
{
auto const itemindex = static_cast<int>(Command.command) - static_cast<int>(user_command::speedcontrolbutton0);
auto &item = Train->ggSpeedCtrlButtons[itemindex];
if (Command.action == GLFW_PRESS)
{
// only reacting to press, so the switch doesn't flip back and forth if key is held down
Train->mvOccupied->SpeedCtrlButton(itemindex);
// visual feedback
Train->ggSpeedCtrlButtons[itemindex].UpdateValue(1.0, Train->dsbSwitch);
}
else if (Command.action == GLFW_RELEASE)
{
// release
// visual feedback
Train->ggSpeedCtrlButtons[itemindex].UpdateValue(0.0, Train->dsbSwitch);
}
};

View File

@@ -0,0 +1,851 @@
/*
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/Train.h"
#include "simulation/simulation.h"
#include "world/Event.h"
#include "simulation/simulationtime.h"
#include "utilities/Logs.h"
#include "model/Model3d.h"
#include "vehicle/Driver.h"
#include "vehicle/DynObj.h"
#include "rendering/renderer.h"
#include <future>
void TTrain::OnCommand_doorlocktoggle(TTrain *Train, command_data const &Command)
{
if (Train->ggDoorSignallingButton.SubModel == nullptr)
{
if (Command.action == GLFW_PRESS)
{
WriteLog("Door Lock switch is missing, or wasn't defined");
}
return;
}
if (Command.action == GLFW_PRESS)
{
// only reacting to press, so the sound can loop uninterrupted
if (false == Train->mvOccupied->Doors.lock_enabled)
{
// turn on
// TODO: door lock command to send through consist
Train->mvOccupied->LockDoors(true);
// visual feedback
Train->ggDoorSignallingButton.UpdateValue(1.0, Train->dsbSwitch);
}
else
{
// turn off
// TODO: door lock command to send through consist
Train->mvOccupied->LockDoors(false);
// visual feedback
Train->ggDoorSignallingButton.UpdateValue(0.0, Train->dsbSwitch);
}
}
}
void TTrain::OnCommand_doortoggleleft(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// NOTE: test how the door state check works with consists where the occupied vehicle doesn't have opening doors
if (false == (Train->ggDoorLeftButton.GetDesiredValue() > 0.5 || Train->ggDoorLeftOnButton.GetDesiredValue() > 0.5))
{
// open
OnCommand_dooropenleft(Train, Command);
}
else
{
// close
if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorLeftOffButton.SubModel == nullptr)
{
// OnCommand_doorcloseall( Train, Command );
// if two-button setup lacks dedicated closing button require the user to press appropriate button manually
return;
}
else
{
OnCommand_doorcloseleft(Train, Command);
}
}
}
else if (Command.action == GLFW_RELEASE)
{
if (true == (Train->ggDoorLeftButton.GetDesiredValue() > 0.5 || Train->ggDoorLeftOnButton.GetDesiredValue() > 0.5))
{
// open
if (Train->mvOccupied->Doors.has_autowarning && Train->mvOccupied->DepartureSignal)
{
// complete closing the doors
if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorLeftOffButton.SubModel == nullptr)
{
// OnCommand_doorcloseall( Train, Command );
// if two-button setup lacks dedicated closing button require the user to press appropriate button manually
return;
}
else
{
OnCommand_doorcloseleft(Train, Command);
}
}
else
{
OnCommand_dooropenleft(Train, Command);
}
}
else
{
// close
if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorLeftOffButton.SubModel == nullptr)
{
// OnCommand_doorcloseall( Train, Command );
// if two-button setup lacks dedicated closing button require the user to press appropriate button manually
return;
}
else
{
OnCommand_doorcloseleft(Train, Command);
}
}
// visual feedback
// dedicated closing buttons are presumed to be impulse switches and return automatically to neutral position
// NOTE: temporary arrangement, can be removed when LD system is in place
if (Train->ggDoorLeftOffButton.SubModel)
Train->ggDoorLeftOffButton.UpdateValue(0.0, Train->dsbSwitch);
if (Train->ggDoorLeftOnButton.SubModel)
Train->ggDoorLeftOnButton.UpdateValue(0.0, Train->dsbSwitch);
}
}
void TTrain::OnCommand_doorpermitleft(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_REPEAT)
{
return;
}
if (false == Train->mvOccupied->Doors.permit_presets.empty())
{
return;
}
auto const side{(Train->cab_to_end() == end::front ? side::left : side::right)};
if (Command.action == GLFW_PRESS)
{
if (Train->ggDoorLeftPermitButton.is_push())
{
// impulse switch
Train->mvOccupied->PermitDoors(side);
// visual feedback
Train->ggDoorLeftPermitButton.UpdateValue(1.0, Train->dsbSwitch);
// start potential timer for remote door control
Train->m_doorpermittimers[side] = Train->mvOccupied->DoorsOpenWithPermitAfter;
}
else
{
// two-state switch
auto const newstate{!(Train->ggDoorLeftPermitButton.GetDesiredValue() > 0.5)};
Train->mvOccupied->PermitDoors(side, newstate);
// visual feedback
Train->ggDoorLeftPermitButton.UpdateValue(newstate ? 1.0 : 0.0, Train->dsbSwitch);
}
}
else if (Command.action == GLFW_RELEASE && Train->ggDoorLeftPermitButton.is_push())
{
// impulse switch
// visual feedback
Train->ggDoorLeftPermitButton.UpdateValue(0.0, Train->dsbSwitch);
// reset potential remote door control timer
Train->m_doorpermittimers[side] = -1.f;
}
}
void TTrain::OnCommand_doorpermitright(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_REPEAT)
{
return;
}
if (false == Train->mvOccupied->Doors.permit_presets.empty())
{
return;
}
auto const side{(Train->cab_to_end() == end::front ? side::right : side::left)};
if (Command.action == GLFW_PRESS)
{
if (Train->ggDoorRightPermitButton.type() == TGaugeType::push)
{
// impulse switch
Train->mvOccupied->PermitDoors(side);
// visual feedback
Train->ggDoorRightPermitButton.UpdateValue(1.0, Train->dsbSwitch);
// start potential timer for remote door control
Train->m_doorpermittimers[side] = Train->mvOccupied->DoorsOpenWithPermitAfter;
}
else
{
// two-state switch
auto const newstate{!(Train->ggDoorRightPermitButton.GetDesiredValue() > 0.5)};
Train->mvOccupied->PermitDoors(side, newstate);
// visual feedback
Train->ggDoorRightPermitButton.UpdateValue(newstate ? 1.0 : 0.0, Train->dsbSwitch);
}
}
else if (Command.action == GLFW_RELEASE && Train->ggDoorRightPermitButton.type() == TGaugeType::push)
{
// impulse switch
// visual feedback
Train->ggDoorRightPermitButton.UpdateValue(0.0, Train->dsbSwitch);
// reset potential remote door control timer
Train->m_doorpermittimers[side] = -1.f;
}
}
void TTrain::OnCommand_doorpermitpresetactivatenext(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
Train->mvOccupied->ChangeDoorPermitPreset(1);
// visual feedback
Train->ggDoorPermitPresetButton.UpdateValue(Train->mvOccupied->Doors.permit_preset, Train->dsbSwitch);
}
}
void TTrain::OnCommand_doorpermitpresetactivateprevious(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
Train->mvOccupied->ChangeDoorPermitPreset(-1);
// visual feedback
Train->ggDoorPermitPresetButton.UpdateValue(Train->mvOccupied->Doors.permit_preset, Train->dsbSwitch);
}
}
void TTrain::OnCommand_dooropenleft(TTrain *Train, command_data const &Command)
{
auto const remoteopencontrol{Train->mvOccupied->Doors.open_control == control_t::driver || Train->mvOccupied->Doors.open_control == control_t::mixed};
if (false == remoteopencontrol)
{
return;
}
if (Train->ggDoorLeftOnButton.SubModel == nullptr && Train->ggDoorLeftButton.SubModel == nullptr)
{
return;
}
if (Command.action == GLFW_PRESS)
{
Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::left : side::right, true);
// visual feedback
if (Train->ggDoorLeftOnButton.SubModel != nullptr)
{
// two separate impulse switches
Train->ggDoorLeftOnButton.UpdateValue(1.0, Train->dsbSwitch);
}
else
{
// single two-state switch
Train->ggDoorLeftButton.UpdateValue(1.0, Train->dsbSwitch);
}
}
else if (Command.action == GLFW_RELEASE && Train->ggDoorLeftOnButton.SubModel != nullptr)
{
// visual feedback
// two separate impulse switches
Train->ggDoorLeftOnButton.UpdateValue(0.0, Train->dsbSwitch);
}
}
void TTrain::OnCommand_doorcloseleft(TTrain *Train, command_data const &Command)
{
auto const remoteclosecontrol{Train->mvOccupied->Doors.close_control == control_t::driver || Train->mvOccupied->Doors.close_control == control_t::mixed};
if (false == remoteclosecontrol)
{
return;
}
if (Train->ggDoorLeftOffButton.SubModel == nullptr && Train->ggDoorLeftButton.SubModel == nullptr)
{
return;
}
if (Command.action == GLFW_PRESS)
{
if (Train->mvOccupied->Doors.has_autowarning)
{
// automatic departure signal delays actual door closing until the button is released
Train->mvOccupied->signal_departure(true);
}
else
{
// TODO: move door opening/closing to the update, so the switch animation doesn't hinge on door working
Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::left : side::right, false);
}
// visual feedback
if (Train->ggDoorLeftOffButton.SubModel != nullptr)
{
// two separate switches to open and close the door
Train->ggDoorLeftOffButton.UpdateValue(1.0, Train->dsbSwitch);
}
else
{
// single two-state switch
Train->ggDoorLeftButton.UpdateValue(0.0, Train->dsbSwitch);
}
}
else if (Command.action == GLFW_RELEASE)
{
if (Train->mvOccupied->Doors.has_autowarning)
{
// automatic departure signal delays actual door closing until the button is released
Train->mvOccupied->signal_departure(false);
// now we can actually close the door
Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::left : side::right, false);
}
// visual feedback
// dedicated closing buttons are presumed to be impulse switches and return automatically to neutral position
if (Train->ggDoorLeftOffButton.SubModel)
Train->ggDoorLeftOffButton.UpdateValue(0.0, Train->dsbSwitch);
}
}
void TTrain::OnCommand_doortoggleright(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// NOTE: test how the door state check works with consists where the occupied vehicle doesn't have opening doors
if (false == (Train->ggDoorRightButton.GetDesiredValue() > 0.5 || Train->ggDoorRightOnButton.GetDesiredValue() > 0.5))
{
// open
OnCommand_dooropenright(Train, Command);
}
else
{
// close
if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorRightOffButton.SubModel == nullptr)
{
// OnCommand_doorcloseall( Train, Command );
// if two-button setup lacks dedicated closing button require the user to press appropriate button manually
return;
}
else
{
OnCommand_doorcloseright(Train, Command);
}
}
}
else if (Command.action == GLFW_RELEASE)
{
if (true == (Train->ggDoorRightButton.GetDesiredValue() > 0.5 || Train->ggDoorRightOnButton.GetDesiredValue() > 0.5))
{
// open
if (Train->mvOccupied->Doors.has_autowarning && Train->mvOccupied->DepartureSignal)
{
// complete closing the doors
if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorRightOffButton.SubModel == nullptr)
{
// OnCommand_doorcloseall( Train, Command );
// if two-button setup lacks dedicated closing button require the user to press appropriate button manually
return;
}
else
{
OnCommand_doorcloseright(Train, Command);
}
}
else
{
OnCommand_dooropenright(Train, Command);
}
}
else
{
// close
if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorRightOffButton.SubModel == nullptr)
{
// OnCommand_doorcloseall( Train, Command );
// if two-button setup lacks dedicated closing button require the user to press appropriate button manually
return;
}
else
{
OnCommand_doorcloseright(Train, Command);
}
}
// visual feedback
// dedicated closing buttons are presumed to be impulse switches and return automatically to neutral position
// NOTE: temporary arrangement, can be removed when LD system is in place
if (Train->ggDoorRightOffButton.SubModel)
Train->ggDoorRightOffButton.UpdateValue(0.0, Train->dsbSwitch);
if (Train->ggDoorRightOnButton.SubModel)
Train->ggDoorRightOnButton.UpdateValue(0.0, Train->dsbSwitch);
}
}
void TTrain::OnCommand_dooropenright(TTrain *Train, command_data const &Command)
{
auto const remoteopencontrol{Train->mvOccupied->Doors.open_control == control_t::driver || Train->mvOccupied->Doors.open_control == control_t::mixed};
if (false == remoteopencontrol)
{
return;
}
if (Train->ggDoorRightOnButton.SubModel == nullptr && Train->ggDoorRightButton.SubModel == nullptr)
{
return;
}
if (Command.action == GLFW_PRESS)
{
Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::right : side::left, true);
// visual feedback
if (Train->ggDoorRightOnButton.SubModel != nullptr)
{
// two separate impulse switches
Train->ggDoorRightOnButton.UpdateValue(1.0, Train->dsbSwitch);
}
else
{
// single two-state switch
Train->ggDoorRightButton.UpdateValue(1.0, Train->dsbSwitch);
}
}
else if (Command.action == GLFW_RELEASE && Train->ggDoorRightOnButton.SubModel != nullptr)
{
// visual feedback
// two separate impulse switches
Train->ggDoorRightOnButton.UpdateValue(0.0, Train->dsbSwitch);
}
}
void TTrain::OnCommand_doorcloseright(TTrain *Train, command_data const &Command)
{
auto const remoteclosecontrol{Train->mvOccupied->Doors.close_control == control_t::driver || Train->mvOccupied->Doors.close_control == control_t::mixed};
if (false == remoteclosecontrol)
{
return;
}
if (Train->ggDoorRightOffButton.SubModel == nullptr && Train->ggDoorRightButton.SubModel == nullptr)
{
return;
}
if (Command.action == GLFW_PRESS)
{
if (Train->mvOccupied->Doors.has_autowarning)
{
// automatic departure signal delays actual door closing until the button is released
Train->mvOccupied->signal_departure(true);
}
else
{
Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::right : side::left, false);
}
// visual feedback
if (Train->ggDoorRightOffButton.SubModel != nullptr)
{
// two separate switches to open and close the door
Train->ggDoorRightOffButton.UpdateValue(1.0, Train->dsbSwitch);
}
else
{
// single two-state switch
Train->ggDoorRightButton.UpdateValue(0.0, Train->dsbSwitch);
}
}
else if (Command.action == GLFW_RELEASE)
{
if (Train->mvOccupied->Doors.has_autowarning)
{
// automatic departure signal delays actual door closing until the button is released
Train->mvOccupied->signal_departure(false);
// now we can actually close the door
Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::right : side::left, false);
}
// visual feedback
// dedicated closing buttons are presumed to be impulse switches and return automatically to neutral position
if (Train->ggDoorRightOffButton.SubModel)
Train->ggDoorRightOffButton.UpdateValue(0.0, Train->dsbSwitch);
}
}
void TTrain::OnCommand_dooropenall(TTrain *Train, command_data const &Command)
{
auto const remoteopencontrol{Train->mvOccupied->Doors.open_control == control_t::driver || Train->mvOccupied->Doors.open_control == control_t::mixed};
if (false == remoteopencontrol)
{
return;
}
if (Train->ggDoorAllOnButton.SubModel == nullptr)
{
// TODO: expand definition of cab controls so we can know if the control is present without testing for presence of 3d switch
if (Command.action == GLFW_PRESS)
{
WriteLog("Open All Doors switch is missing, or wasn't defined");
}
return;
}
if (Command.action == GLFW_PRESS)
{
Train->mvOccupied->OperateDoors(side::right, true);
Train->mvOccupied->OperateDoors(side::left, true);
// visual feedback
Train->ggDoorAllOnButton.UpdateValue(1.0, Train->dsbSwitch);
}
else if (Command.action == GLFW_RELEASE)
{
// visual feedback
Train->ggDoorAllOnButton.UpdateValue(0.0);
}
}
void TTrain::OnCommand_doorcloseall(TTrain *Train, command_data const &Command)
{
auto const remoteclosecontrol{Train->mvOccupied->Doors.close_control == control_t::driver || Train->mvOccupied->Doors.close_control == control_t::mixed};
if (false == remoteclosecontrol)
{
return;
}
if (Train->ggDoorAllOffButton.SubModel == nullptr)
{
// TODO: expand definition of cab controls so we can know if the control is present without testing for presence of 3d switch
if (Command.action == GLFW_PRESS)
{
WriteLog("Close All Doors switch is missing, or wasn't defined");
}
return;
}
if (Command.action == GLFW_PRESS)
{
if (Train->mvOccupied->Doors.has_autowarning)
{
Train->mvOccupied->signal_departure(true);
}
if (Train->ggDoorAllOffButton.type() != TGaugeType::push_delayed)
{
// delays the action until the button is released
Train->mvOccupied->OperateDoors(side::right, false);
Train->mvOccupied->OperateDoors(side::left, false);
}
// visual feedback
Train->ggDoorLeftButton.UpdateValue(0.0, Train->dsbSwitch);
Train->ggDoorRightButton.UpdateValue(0.0, Train->dsbSwitch);
if (Train->ggDoorAllOffButton.SubModel)
Train->ggDoorAllOffButton.UpdateValue(1.0, Train->dsbSwitch);
}
else if (Command.action == GLFW_RELEASE)
{
if (Train->mvOccupied->Doors.has_autowarning)
{
Train->mvOccupied->signal_departure(false);
}
if (Train->ggDoorAllOffButton.type() == TGaugeType::push_delayed)
{
// now we can actually close the door
Train->mvOccupied->OperateDoors(side::right, false);
Train->mvOccupied->OperateDoors(side::left, false);
}
// visual feedback
if (Train->ggDoorAllOffButton.SubModel)
Train->ggDoorAllOffButton.UpdateValue(0.0);
}
}
void TTrain::OnCommand_doorsteptoggle(TTrain *Train, command_data const &Command)
{
// TODO: move logic/visualization code to the gauge, on_command() should return hint whether it should invoke a reaction
if (Command.action == GLFW_PRESS)
{
// effect
if (false == Train->ggDoorStepButton.is_delayed())
{
Train->mvOccupied->PermitDoorStep(false == Train->mvOccupied->Doors.step_enabled);
}
// visual feedback
auto const isactive{(Train->ggDoorStepButton.is_push() // always press push button
|| Train->mvOccupied->Doors.step_enabled)}; // for toggle buttons indicate item state
Train->ggDoorStepButton.UpdateValue(isactive ? 1 : 0);
}
else if (Command.action == GLFW_RELEASE)
{
// effect
if (Train->ggDoorStepButton.is_delayed())
{
Train->mvOccupied->PermitDoorStep(false == Train->mvOccupied->Doors.step_enabled);
}
// visual feedback
if (Train->ggDoorStepButton.is_push())
{
Train->ggDoorStepButton.UpdateValue(0);
}
}
}
void TTrain::OnCommand_doormodetoggle(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
Train->mvOccupied->ChangeDoorControlMode(false == Train->mvOccupied->Doors.remote_only);
}
}
void TTrain::OnCommand_mirrorstoggle(TTrain *Train, command_data const &Command)
{
if (Command.action != GLFW_PRESS)
{
return;
}
// only reacting to press, so the sound can loop uninterrupted
if (false == Train->mvOccupied->MirrorForbidden)
{
// turn on
Train->mvOccupied->MirrorForbidden = true;
}
else
{
// turn off
Train->mvOccupied->MirrorForbidden = false;
}
}
void TTrain::OnCommand_nearestcarcouplingincrease(TTrain *Train, command_data const &Command)
{
if (true == Command.freefly && Command.action == GLFW_PRESS)
{
// tryb freefly, press only
auto coupler{-1};
auto *vehicle{Train->DynamicObject->ABuScanNearestObject(Command.location, Train->DynamicObject->GetTrack(), 1, 1500, coupler)};
if (vehicle == nullptr)
vehicle = Train->DynamicObject->ABuScanNearestObject(Command.location, Train->DynamicObject->GetTrack(), -1, 1500, coupler);
if (coupler != -1 && vehicle != nullptr)
{
vehicle->couple(coupler);
}
if (Train->DynamicObject->Mechanik)
{
// aktualizacja flag kierunku w składzie
Train->DynamicObject->Mechanik->CheckVehicles(Connect);
}
}
}
void TTrain::OnCommand_nearestcarcouplingdisconnect(TTrain *Train, command_data const &Command)
{
if (true == Command.freefly && Command.action == GLFW_PRESS)
{
// tryb freefly, press only
auto coupler{-1};
auto *vehicle{Train->DynamicObject->ABuScanNearestObject(Command.location, Train->DynamicObject->GetTrack(), 1, 1500, coupler)};
if (vehicle == nullptr)
vehicle = Train->DynamicObject->ABuScanNearestObject(Command.location, Train->DynamicObject->GetTrack(), -1, 1500, coupler);
if (coupler != -1 && vehicle != nullptr)
{
vehicle->uncouple(coupler);
}
if (Train->DynamicObject->Mechanik)
{
// aktualizacja flag kierunku w składzie
Train->DynamicObject->Mechanik->CheckVehicles(Disconnect);
}
}
}
void TTrain::OnCommand_nearestcarcoupleradapterattach(TTrain *Train, command_data const &Command)
{
if (true == Command.freefly && Command.action == GLFW_PRESS)
{
// tryb freefly, press only
auto *vehicle{std::get<TDynamicObject *>(simulation::Region->find_vehicle(Command.location, 50, false, true))};
if (vehicle == nullptr)
{
return;
}
auto const coupler =
glm::length2(glm::vec3{vehicle->CouplerPosition(end::front)} - Command.location) < glm::length2(glm::vec3{vehicle->CouplerPosition(end::rear)} - Command.location) ? end::front : end::rear;
vehicle->attach_coupler_adapter(coupler);
}
}
void TTrain::OnCommand_nearestcarcoupleradapterremove(TTrain *Train, command_data const &Command)
{
if (true == Command.freefly && Command.action == GLFW_PRESS)
{
// tryb freefly, press only
auto *vehicle{std::get<TDynamicObject *>(simulation::Region->find_vehicle(Command.location, 50, false, true))};
if (vehicle == nullptr)
{
return;
}
auto const coupler =
glm::length2(glm::vec3{vehicle->CouplerPosition(end::front)} - Command.location) < glm::length2(glm::vec3{vehicle->CouplerPosition(end::rear)} - Command.location) ? end::front : end::rear;
vehicle->remove_coupler_adapter(coupler);
}
}
void TTrain::OnCommand_occupiedcarcouplingdisconnect(TTrain *Train, command_data const &Command)
{
// if( false == Train->m_controlmapper.contains( "couplingdisconnect_sw:" ) ) { return; }
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->m_couplingdisconnect = true;
if (Train->iCabn == 0)
{
return;
}
if (Train->DynamicObject)
{
Train->DynamicObject->uncouple(Train->cab_to_end());
if (Train->DynamicObject->Mechanik)
{
// aktualizacja flag kierunku w składzie
Train->DynamicObject->Mechanik->CheckVehicles(Disconnect);
}
}
}
else if (Command.action == GLFW_RELEASE)
{
// visual feedback
Train->m_couplingdisconnect = false;
}
}
void TTrain::OnCommand_occupiedcarcouplingdisconnectback(TTrain *Train, command_data const &Command)
{
// if( false == Train->m_controlmapper.contains( "couplingdisconnect_sw:" ) ) { return; }
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->m_couplingdisconnectback = true;
if (Train->iCabn == 0)
{
return;
}
if (Train->DynamicObject)
{
Train->DynamicObject->uncouple(1 - Train->cab_to_end());
if (Train->DynamicObject->Mechanik)
{
// aktualizacja flag kierunku w składzie
Train->DynamicObject->Mechanik->CheckVehicles(Disconnect);
}
}
}
else if (Command.action == GLFW_RELEASE)
{
// visual feedback
Train->m_couplingdisconnectback = false;
}
}
void TTrain::OnCommand_departureannounce(TTrain *Train, command_data const &Command)
{
if (Train->ggDepartureSignalButton.SubModel == nullptr)
{
if (Command.action == GLFW_PRESS)
{
WriteLog("Departure Signal button is missing, or wasn't defined");
}
return;
}
if (Command.action == GLFW_PRESS)
{
// only reacting to press, so the sound can loop uninterrupted
if (false == Train->mvOccupied->DepartureSignal)
{
// turn on
Train->mvOccupied->signal_departure(true);
// visual feedback
Train->ggDepartureSignalButton.UpdateValue(1.0, Train->dsbSwitch);
}
}
else if (Command.action == GLFW_RELEASE)
{
// turn off
Train->mvOccupied->signal_departure(false);
// visual feedback
Train->ggDepartureSignalButton.UpdateValue(0.0, Train->dsbSwitch);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,211 @@
/*
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/Train.h"
#include "world/Event.h"
#include "simulation/simulationtime.h"
#include "model/Model3d.h"
#include "vehicle/Driver.h"
#include "vehicle/DynObj.h"
#include <future>
void TTrain::OnCommand_alerteracknowledge(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
// visual feedback
Train->ggSecurityResetButton.UpdateValue(1.0, Train->dsbSwitch);
if (Train->mvOccupied->TrainType == dt_EZT || Train->mvOccupied->DirActive != 0)
Train->mvOccupied->SecuritySystem.acknowledge_press();
}
else if (Command.action == GLFW_RELEASE)
{
// visual feedback
Train->ggSecurityResetButton.UpdateValue(0.0);
if (Train->mvOccupied->TrainType == dt_EZT || Train->mvOccupied->DirActive != 0)
Train->mvOccupied->SecuritySystem.acknowledge_release();
}
}
void TTrain::OnCommand_cabsignalacknowledge(TTrain *Train, command_data const &Command)
{
// TODO: visual feedback
if (Command.action == GLFW_PRESS)
{
if (Train->mvOccupied->SecuritySystem.has_separate_acknowledge())
{
Train->mvOccupied->SecuritySystem.cabsignal_reset();
Train->ggSHPResetButton.UpdateValue(1.0, Train->dsbSwitch);
}
}
else if (Command.action == GLFW_RELEASE)
{
Train->ggSHPResetButton.UpdateValue(0.0);
}
}
void TTrain::OnCommand_generictoggle(TTrain *Train, command_data const &Command)
{
auto const itemindex = static_cast<int>(Command.command) - static_cast<int>(user_command::generictoggle0);
auto &item = Train->ggUniversals[itemindex];
/*
if( item.SubModel == nullptr ) {
if( Command.action == GLFW_PRESS ) {
WriteLog( "Train generic item " + std::to_string( itemindex ) + " is missing, or wasn't defined" );
}
return;
}
*/
if (Command.action == GLFW_PRESS)
{
if (item.type() == TGaugeType::push)
{
// impulse switch
// turn on
// visual feedback
item.UpdateValue(1.0);
}
else
{
// two-state switch
if (item.GetDesiredValue() < 0.5)
{
// turn on
// visual feedback
item.UpdateValue(1.0);
}
else
{
// turn off
// visual feedback
item.UpdateValue(0.0);
}
}
}
else if (Command.action == GLFW_RELEASE && item.type() == TGaugeType::push)
{
// impulse switch
// turn off
// visual feedback
item.UpdateValue(0.0);
}
}
void TTrain::OnCommand_cabchangeforward(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
auto const *owner{(Train->DynamicObject->ctOwner != nullptr ? Train->DynamicObject->ctOwner : Train->DynamicObject->Mechanik)};
auto const movedirection{1};
if (false == Train->CabChange(movedirection))
{
auto const exitdirection{(movedirection > 0 ? end::front : end::rear)};
if (TestFlag(Train->mvOccupied->Couplers[exitdirection].CouplingFlag, coupling::gangway))
{
// przejscie do nastepnego pojazdu
auto *targetvehicle = exitdirection == end::front ? Train->DynamicObject->PrevConnected() : Train->DynamicObject->NextConnected();
targetvehicle->MoverParameters->CabOccupied = Train->mvOccupied->Neighbours[exitdirection].vehicle_end ? -1 : 1;
Train->MoveToVehicle(targetvehicle);
}
}
// HACK: match consist door permit state with the preset in the active cab
if (Train->ggDoorPermitPresetButton.SubModel != nullptr)
{
Train->mvOccupied->ChangeDoorPermitPreset(0);
}
// HACK: update lights state
if (Train->mvOccupied->LightsPosNo > 0)
{
Train->DynamicObject->SetLights();
}
}
}
void TTrain::OnCommand_cabchangebackward(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
auto const *owner{(Train->DynamicObject->ctOwner != nullptr ? Train->DynamicObject->ctOwner : Train->DynamicObject->Mechanik)};
auto const movedirection{-1};
if (false == Train->CabChange(movedirection))
{
// current vehicle doesn't extend any farther in this direction, check if we there's one connected we can move to
auto const exitdirection{(movedirection > 0 ? end::front : end::rear)};
if (TestFlag(Train->mvOccupied->Couplers[exitdirection].CouplingFlag, coupling::gangway))
{
// przejscie do nastepnego pojazdu
auto *targetvehicle = exitdirection == end::front ? Train->DynamicObject->PrevConnected() : Train->DynamicObject->NextConnected();
targetvehicle->MoverParameters->CabOccupied = Train->mvOccupied->Neighbours[exitdirection].vehicle_end ? -1 : 1;
Train->MoveToVehicle(targetvehicle);
}
}
// HACK: match consist door permit state with the preset in the active cab
if (Train->ggDoorPermitPresetButton.SubModel != nullptr)
{
Train->mvOccupied->ChangeDoorPermitPreset(0);
}
// HACK: update lights state
if (Train->mvOccupied->LightsPosNo > 0)
{
Train->DynamicObject->SetLights();
}
}
}
void TTrain::OnCommand_vehiclemoveforwards(TTrain *Train, const command_data &Command)
{
if (Command.action == GLFW_RELEASE || !DebugModeFlag)
return;
Train->DynamicObject->move_set(100.0);
}
void TTrain::OnCommand_vehiclemovebackwards(TTrain *Train, const command_data &Command)
{
if (Command.action == GLFW_RELEASE || !DebugModeFlag)
return;
Train->DynamicObject->move_set(-100.0);
}
void TTrain::OnCommand_vehicleboost(TTrain *Train, const command_data &Command)
{
if (Command.action == GLFW_RELEASE || !DebugModeFlag)
return;
double boost = Command.param1 != 0.0 ? Command.param1 : 2.78;
if (Train->DynamicObject == nullptr)
{
return;
}
auto *vehicle{Train->DynamicObject};
while (vehicle)
{
vehicle->MoverParameters->V += vehicle->DirectionGet() * boost;
vehicle = vehicle->Next(); // pozostałe też
}
vehicle = Train->DynamicObject->Prev();
while (vehicle)
{
vehicle->MoverParameters->V += vehicle->DirectionGet() * boost;
vehicle = vehicle->Prev(); // w drugą stronę też
}
}

View File

@@ -0,0 +1,382 @@
/*
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/Train.h"
#include "simulation/simulation.h"
#include "world/Event.h"
#include "simulation/simulationtime.h"
#include "utilities/Logs.h"
#include "model/Model3d.h"
#include "vehicle/Driver.h"
#include "vehicle/DynObj.h"
#include "rendering/renderer.h"
#include <future>
#include <algorithm>
void TTrain::OnCommand_hornlowactivate(TTrain *Train, command_data const &Command)
{
if (Train->ggHornButton.SubModel == nullptr && Train->ggHornLowButton.SubModel == nullptr)
{
if (Command.action == GLFW_PRESS)
{
WriteLog("Horn button is missing, or wasn't defined");
}
return;
}
if (Command.action == GLFW_PRESS)
{
// only need to react to press, sound will continue until stopped
if (false == TestFlag(Train->mvOccupied->WarningSignal, 1))
{
// turn on
Train->mvOccupied->WarningSignal |= 1;
/*
if( true == TestFlag( Train->mvOccupied->WarningSignal, 2 ) ) {
low and high horn are treated as mutually exclusive
Train->mvControlled->WarningSignal &= ~2;
}
*/
// visual feedback
Train->ggHornButton.UpdateValue(-1.0);
Train->ggHornLowButton.UpdateValue(1.0);
}
}
else if (Command.action == GLFW_RELEASE)
{
// turn off
/*
NOTE: we turn off both low and high horn, due to unreliability of release event when shift key is involved
Train->mvOccupied->WarningSignal &= ~( 1 | 2 );
*/
Train->mvOccupied->WarningSignal &= ~1;
// visual feedback
Train->ggHornButton.UpdateValue(0.0);
Train->ggHornLowButton.UpdateValue(0.0);
}
}
void TTrain::OnCommand_hornhighactivate(TTrain *Train, command_data const &Command)
{
if (Train->ggHornButton.SubModel == nullptr && Train->ggHornHighButton.SubModel == nullptr)
{
if (Command.action == GLFW_PRESS)
{
WriteLog("Horn button is missing, or wasn't defined");
}
return;
}
if (Command.action == GLFW_PRESS)
{
// only need to react to press, sound will continue until stopped
if (false == TestFlag(Train->mvOccupied->WarningSignal, 2))
{
// turn on
Train->mvOccupied->WarningSignal |= 2;
/*
if( true == TestFlag( Train->mvOccupied->WarningSignal, 1 ) ) {
low and high horn are treated as mutually exclusive
Train->mvControlled->WarningSignal &= ~1;
}
*/
// visual feedback
Train->ggHornButton.UpdateValue(1.0);
Train->ggHornHighButton.UpdateValue(1.0);
}
}
else if (Command.action == GLFW_RELEASE)
{
// turn off
/*
NOTE: we turn off both low and high horn, due to unreliability of release event when shift key is involved
Train->mvOccupied->WarningSignal &= ~( 1 | 2 );
*/
Train->mvOccupied->WarningSignal &= ~2;
// visual feedback
Train->ggHornButton.UpdateValue(0.0);
Train->ggHornHighButton.UpdateValue(0.0);
}
}
void TTrain::OnCommand_whistleactivate(TTrain *Train, command_data const &Command)
{
if (Train->ggWhistleButton.SubModel == nullptr)
{
if (Command.action == GLFW_PRESS)
{
WriteLog("Whistle button is missing, or wasn't defined");
}
return;
}
if (Command.action == GLFW_PRESS)
{
// only need to react to press, sound will continue until stopped
if (false == TestFlag(Train->mvOccupied->WarningSignal, 4))
{
// turn on
Train->mvOccupied->WarningSignal |= 4;
// visual feedback
Train->ggWhistleButton.UpdateValue(1.0);
}
}
else if (Command.action == GLFW_RELEASE)
{
// turn off
Train->mvOccupied->WarningSignal &= ~4;
// visual feedback
Train->ggWhistleButton.UpdateValue(0.0);
}
}
void TTrain::OnCommand_radiotoggle(TTrain *Train, command_data const &Command)
{
if (Command.action != GLFW_PRESS)
{
return;
}
// NOTE: we ignore the lack of 3d model to allow system reset after receiving radio-stop signal
/*
if( false == Train->m_controlmapper.contains( "radio_sw:" ) ) {
return;
}
*/
// only reacting to press, so the sound can loop uninterrupted
if (false == Train->mvOccupied->Radio)
{
// turn on
OnCommand_radioenable(Train, Command);
}
else
{
// turn off
OnCommand_radiodisable(Train, Command);
}
}
void TTrain::OnCommand_radioenable(TTrain *Train, command_data const &Command)
{
if (Command.action != GLFW_PRESS)
{
return;
}
if (false == Train->mvOccupied->Radio)
{
Train->mvOccupied->Radio = true;
}
}
void TTrain::OnCommand_radiodisable(TTrain *Train, command_data const &Command)
{
if (Command.action != GLFW_PRESS)
{
return;
}
if (Train->mvOccupied->Radio)
{
Train->mvOccupied->Radio = false;
}
}
void TTrain::OnCommand_radiochannelincrease(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
command_data newCommand = Command;
newCommand.param1 = Train->RadioChannel() + 1;
OnCommand_radiochannelset(Train, newCommand);
Train->ggRadioChannelNext.UpdateValue(1.0);
}
else if (Command.action == GLFW_RELEASE)
{
// visual feedback
Train->ggRadioChannelNext.UpdateValue(0.0);
}
}
void TTrain::OnCommand_radiochanneldecrease(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
command_data newCommand = Command;
newCommand.param1 = Train->RadioChannel() - 1;
OnCommand_radiochannelset(Train, newCommand);
Train->ggRadioChannelPrevious.UpdateValue(1.0);
}
else if (Command.action == GLFW_RELEASE)
{
// visual feedback
Train->ggRadioChannelPrevious.UpdateValue(0.0);
}
}
void TTrain::OnCommand_radiochannelset(TTrain *Train, command_data const &Command)
{
if (Command.action != GLFW_RELEASE)
{
// on press or hold
Train->RadioChannel() = std::clamp((int)Command.param1, 1, 10);
Train->ggRadioChannelSelector.UpdateValue(Train->RadioChannel() - 1);
}
}
void TTrain::OnCommand_radiostopsend(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
if (true == Train->mvOccupied->Radio && (Train->mvOccupied->Power24vIsAvailable || Train->mvOccupied->Power110vIsAvailable))
{
simulation::Region->RadioStop(Train->Dynamic()->GetPosition());
}
// visual feedback
Train->ggRadioStop.UpdateValue(1.0);
}
else if (Command.action == GLFW_RELEASE)
{
// visual feedback
Train->ggRadioStop.UpdateValue(0.0);
}
}
void TTrain::OnCommand_radiostopenable(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS && Train->ggRadioStop.GetValue() == 0)
{
if (true == Train->mvOccupied->Radio && (Train->mvOccupied->Power24vIsAvailable || Train->mvOccupied->Power110vIsAvailable))
{
simulation::Region->RadioStop(Train->Dynamic()->GetPosition());
}
// visual feedback
Train->ggRadioStop.UpdateValue(1.0);
}
}
void TTrain::OnCommand_radiostopdisable(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS && Train->ggRadioStop.GetValue() > 0)
{
// visual feedback
Train->ggRadioStop.UpdateValue(0.0);
}
}
void TTrain::OnCommand_radiostoptest(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
if (Train->RadioChannel() == 10 && true == Train->mvOccupied->Radio && (Train->mvOccupied->Power24vIsAvailable || Train->mvOccupied->Power110vIsAvailable))
{
Train->Dynamic()->RadioStop();
}
// visual feedback
Train->ggRadioTest.UpdateValue(1.0);
}
else if (Command.action == GLFW_RELEASE)
{
// visual feedback
Train->ggRadioTest.UpdateValue(0.0);
}
}
void TTrain::OnCommand_radiocall1send(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
if (Train->RadioChannel() != 10 && true == Train->mvOccupied->Radio && (Train->mvOccupied->Power24vIsAvailable || Train->mvOccupied->Power110vIsAvailable))
{
simulation::Events.queue_receivers(radio_message::call1, Train->Dynamic()->GetPosition());
}
// visual feedback
Train->ggRadioCall1.UpdateValue(1.0);
}
else if (Command.action == GLFW_RELEASE)
{
// visual feedback
Train->ggRadioCall1.UpdateValue(0.0);
}
}
void TTrain::OnCommand_radiocall3send(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
if (Train->RadioChannel() != 10 && true == Train->mvOccupied->Radio && (Train->mvOccupied->Power24vIsAvailable || Train->mvOccupied->Power110vIsAvailable))
{
simulation::Events.queue_receivers(radio_message::call3, Train->Dynamic()->GetPosition());
}
// visual feedback
Train->ggRadioCall3.UpdateValue(1.0);
}
else if (Command.action == GLFW_RELEASE)
{
// visual feedback
Train->ggRadioCall3.UpdateValue(0.0);
}
}
void TTrain::OnCommand_radiovolumeincrease(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
command_data newCommand = Command;
newCommand.param1 = Train->m_radiovolume + 0.125;
OnCommand_radiovolumeset(Train, newCommand);
Train->ggRadioVolumeNext.UpdateValue(1.0);
}
else if (Command.action == GLFW_RELEASE)
{
// visual feedback
Train->ggRadioVolumeNext.UpdateValue(0.0);
}
}
void TTrain::OnCommand_radiovolumedecrease(TTrain *Train, command_data const &Command)
{
if (Command.action == GLFW_PRESS)
{
command_data newCommand = Command;
newCommand.param1 = Train->m_radiovolume - 0.125;
OnCommand_radiovolumeset(Train, newCommand);
Train->ggRadioVolumePrevious.UpdateValue(1.0);
}
else if (Command.action == GLFW_RELEASE)
{
// visual feedback
Train->ggRadioVolumePrevious.UpdateValue(0.0);
}
}
void TTrain::OnCommand_radiovolumeset(TTrain *Train, command_data const &Command)
{
if (Command.action != GLFW_RELEASE)
{
// on press or hold
Train->m_radiovolume = std::clamp(Command.param1, 0.0, 1.0);
Train->ggRadioVolumeSelector.UpdateValue(Train->m_radiovolume);
audio::event_volume_change = true;
}
}