mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-23 00:29:19 +02:00
control messaging system, keyboard and gamepad inputs
This commit is contained in:
475
Camera.cpp
475
Camera.cpp
@@ -15,23 +15,19 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Console.h"
|
||||
#include "Timer.h"
|
||||
#include "mover.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// TViewPyramid TCamera::OrgViewPyramid;
|
||||
//={vector3(-1,1,1),vector3(1,1,1),vector3(-1,-1,1),vector3(1,-1,1),vector3(0,0,0)};
|
||||
|
||||
const vector3 OrgCrossPos = vector3(0, -10, 0);
|
||||
|
||||
void TCamera::Init(vector3 NPos, vector3 NAngle)
|
||||
{
|
||||
|
||||
pOffset = vector3(-0.0, 0, 0);
|
||||
vUp = vector3(0, 1, 0);
|
||||
// pOffset= vector3(-0.8,0,0);
|
||||
CrossPos = OrgCrossPos;
|
||||
CrossDist = 10;
|
||||
Velocity = vector3(0, 0, 0);
|
||||
OldVelocity = vector3(0, 0, 0);
|
||||
Pitch = NAngle.x;
|
||||
Yaw = NAngle.y;
|
||||
Roll = NAngle.z;
|
||||
@@ -54,52 +50,445 @@ void TCamera::OnCursorMove(double x, double y)
|
||||
if (Type == tp_Follow) // jeżeli jazda z pojazdem
|
||||
{
|
||||
clamp(Pitch, -M_PI_4, M_PI_4); // ograniczenie kąta spoglądania w dół i w górę
|
||||
// Fix(Yaw,-M_PI,M_PI);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TCamera::OnCommand( command_data const &Command ) {
|
||||
|
||||
double const walkspeed = 1.0;
|
||||
double const runspeed = ( DebugModeFlag ? 50.0 : 7.5 );
|
||||
double const speedmultiplier = ( DebugModeFlag ? 7.5 : 1.0 );
|
||||
|
||||
switch( Command.command ) {
|
||||
|
||||
case user_command::viewturn: {
|
||||
|
||||
OnCursorMove(
|
||||
reinterpret_cast<double const &>( Command.param1 ) * 0.005 * Global::fMouseXScale / Global::ZoomFactor,
|
||||
reinterpret_cast<double const &>( Command.param2 ) * -0.01 * Global::fMouseYScale / Global::ZoomFactor );
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::movevector: {
|
||||
|
||||
auto const movespeed =
|
||||
( Type == tp_Free ?
|
||||
runspeed * speedmultiplier :
|
||||
walkspeed );
|
||||
|
||||
// left-right
|
||||
double const movex = reinterpret_cast<double const &>( Command.param1 );
|
||||
if( movex > 0.0 ) {
|
||||
m_keys.right = true;
|
||||
m_keys.left = false;
|
||||
}
|
||||
else if( movex < 0.0 ) {
|
||||
m_keys.right = false;
|
||||
m_keys.left = true;
|
||||
}
|
||||
else {
|
||||
m_keys.right = false;
|
||||
m_keys.left = false;
|
||||
}
|
||||
// 2/3rd of the stick range enables walk speed, past that we lerp between walk and run speed
|
||||
m_moverate.x =
|
||||
walkspeed
|
||||
+ ( std::max( 0.0, std::abs( movex ) - 0.65 ) / 0.35 ) * ( movespeed - walkspeed );
|
||||
|
||||
// forward-back
|
||||
double const movez = reinterpret_cast<double const &>( Command.param2 );
|
||||
if( movez > 0.0 ) {
|
||||
m_keys.forward = true;
|
||||
m_keys.back = false;
|
||||
}
|
||||
else if( movez < 0.0 ) {
|
||||
m_keys.forward = false;
|
||||
m_keys.back = true;
|
||||
}
|
||||
else {
|
||||
m_keys.forward = false;
|
||||
m_keys.back = false;
|
||||
}
|
||||
m_moverate.z =
|
||||
walkspeed
|
||||
+ ( std::max( 0.0, std::abs( movez ) - 0.65 ) / 0.35 ) * ( movespeed - walkspeed );
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::moveforward: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.forward = true;
|
||||
m_moverate.z =
|
||||
( Type == tp_Free ?
|
||||
walkspeed * speedmultiplier :
|
||||
walkspeed );
|
||||
}
|
||||
else {
|
||||
m_keys.forward = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::moveback: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.back = true;
|
||||
m_moverate.z =
|
||||
( Type == tp_Free ?
|
||||
walkspeed * speedmultiplier :
|
||||
walkspeed );
|
||||
}
|
||||
else {
|
||||
m_keys.back = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::moveleft: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.left = true;
|
||||
m_moverate.x =
|
||||
( Type == tp_Free ?
|
||||
walkspeed * speedmultiplier :
|
||||
walkspeed );
|
||||
}
|
||||
else {
|
||||
m_keys.left = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::moveright: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.right = true;
|
||||
m_moverate.x =
|
||||
( Type == tp_Free ?
|
||||
walkspeed * speedmultiplier :
|
||||
walkspeed );
|
||||
}
|
||||
else {
|
||||
m_keys.right = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::moveup: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.up = true;
|
||||
m_moverate.y =
|
||||
( Type == tp_Free ?
|
||||
walkspeed * speedmultiplier :
|
||||
walkspeed );
|
||||
}
|
||||
else {
|
||||
m_keys.up = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::movedown: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.down = true;
|
||||
m_moverate.y =
|
||||
( Type == tp_Free ?
|
||||
walkspeed * speedmultiplier :
|
||||
walkspeed );
|
||||
}
|
||||
else {
|
||||
m_keys.down = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::moveforwardfast: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.forward = true;
|
||||
m_moverate.z =
|
||||
( Type == tp_Free ?
|
||||
runspeed * speedmultiplier :
|
||||
walkspeed );
|
||||
}
|
||||
else {
|
||||
m_keys.forward = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::movebackfast: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.back = true;
|
||||
m_moverate.z =
|
||||
( Type == tp_Free ?
|
||||
runspeed * speedmultiplier :
|
||||
walkspeed );
|
||||
}
|
||||
else {
|
||||
m_keys.back = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::moveleftfast: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.left = true;
|
||||
m_moverate.x =
|
||||
( Type == tp_Free ?
|
||||
runspeed * speedmultiplier :
|
||||
walkspeed );
|
||||
}
|
||||
else {
|
||||
m_keys.left = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::moverightfast: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.right = true;
|
||||
m_moverate.x =
|
||||
( Type == tp_Free ?
|
||||
runspeed * speedmultiplier :
|
||||
walkspeed );
|
||||
}
|
||||
else {
|
||||
m_keys.right = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::moveupfast: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.up = true;
|
||||
m_moverate.y =
|
||||
( Type == tp_Free ?
|
||||
runspeed * speedmultiplier :
|
||||
walkspeed );
|
||||
}
|
||||
else {
|
||||
m_keys.up = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::movedownfast: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.down = true;
|
||||
m_moverate.y =
|
||||
( Type == tp_Free ?
|
||||
runspeed * speedmultiplier :
|
||||
walkspeed );
|
||||
}
|
||||
else {
|
||||
m_keys.down = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*
|
||||
case user_command::moveforwardfastest: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.forward = true;
|
||||
m_moverate.z =
|
||||
( Type == tp_Free ?
|
||||
8.0 :
|
||||
0.8 );
|
||||
}
|
||||
else {
|
||||
m_keys.forward = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::movebackfastest: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.back = true;
|
||||
m_moverate.z =
|
||||
( Type == tp_Free ?
|
||||
8.0 :
|
||||
0.8 );
|
||||
}
|
||||
else {
|
||||
m_keys.back = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::moveleftfastest: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.left = true;
|
||||
m_moverate.x =
|
||||
( Type == tp_Free ?
|
||||
8.0 :
|
||||
0.8 );
|
||||
}
|
||||
else {
|
||||
m_keys.left = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::moverightfastest: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.right = true;
|
||||
m_moverate.x =
|
||||
( Type == tp_Free ?
|
||||
8.0 :
|
||||
0.8 );
|
||||
}
|
||||
else {
|
||||
m_keys.right = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::moveupfastest: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.up = true;
|
||||
m_moverate.y =
|
||||
( Type == tp_Free ?
|
||||
8.0 :
|
||||
0.8 );
|
||||
}
|
||||
else {
|
||||
m_keys.up = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::movedownfastest: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
m_keys.down = true;
|
||||
m_moverate.y =
|
||||
( Type == tp_Free ?
|
||||
8.0 :
|
||||
0.8 );
|
||||
}
|
||||
else {
|
||||
m_keys.down = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
void TCamera::Update()
|
||||
{
|
||||
// ABu: zmiana i uniezaleznienie predkosci od FPS
|
||||
double a = ( Global::shiftState ? 5.00 : 1.00);
|
||||
if (Global::ctrlState)
|
||||
a = a * 100;
|
||||
// OldVelocity=Velocity;
|
||||
if (FreeFlyModeFlag == true)
|
||||
Type = tp_Free;
|
||||
else
|
||||
Type = tp_Follow;
|
||||
if (Type == tp_Free)
|
||||
{
|
||||
if (Console::Pressed(Global::Keys[k_MechUp]))
|
||||
Velocity.y += a;
|
||||
if (Console::Pressed(Global::Keys[k_MechDown]))
|
||||
Velocity.y -= a;
|
||||
if( FreeFlyModeFlag == true ) { Type = tp_Free; }
|
||||
else { Type = tp_Follow; }
|
||||
|
||||
// check for sent user commands
|
||||
// NOTE: this is a temporary arrangement, for the transition period from old command setup to the new one
|
||||
// ultimately we'll need to track position of camera/driver for all human entities present in the scenario
|
||||
command_data command;
|
||||
// NOTE: currently we're only storing commands for local entity and there's no id system in place,
|
||||
// so we're supplying 'default' entity id of 0
|
||||
while( simulation::Commands.pop( command, static_cast<std::size_t>( command_target::entity ) | 0 ) ) {
|
||||
|
||||
OnCommand( command );
|
||||
}
|
||||
|
||||
auto const deltatime = Timer::GetDeltaRenderTime(); // czas bez pauzy
|
||||
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
double a = 0.8; // default (walk) movement speed
|
||||
if( Type == tp_Free ) {
|
||||
// when not in the cab the speed modifiers are active
|
||||
if( Global::shiftState ) { a = 2.5; }
|
||||
if( Global::ctrlState ) { a *= 10.0; }
|
||||
}
|
||||
|
||||
if( ( Type == tp_Free )
|
||||
|| ( false == Global::ctrlState ) ) {
|
||||
// ctrl is used for mirror view, so we ignore the controls when in vehicle if ctrl is pressed
|
||||
if( Console::Pressed( Global::Keys[ k_MechUp ] ) )
|
||||
Velocity.y = clamp( Velocity.y + a * 10.0 * deltatime, -a, a );
|
||||
if( Console::Pressed( Global::Keys[ k_MechDown ] ) )
|
||||
Velocity.y = clamp( Velocity.y - a * 10.0 * deltatime, -a, a );
|
||||
|
||||
// McZapkie-170402: poruszanie i rozgladanie we free takie samo jak w follow
|
||||
if (Console::Pressed(Global::Keys[k_MechRight]))
|
||||
Velocity.x += a;
|
||||
if (Console::Pressed(Global::Keys[k_MechLeft]))
|
||||
Velocity.x -= a;
|
||||
if (Console::Pressed(Global::Keys[k_MechForward]))
|
||||
Velocity.z -= a;
|
||||
if (Console::Pressed(Global::Keys[k_MechBackward]))
|
||||
Velocity.z += a;
|
||||
// gora-dol
|
||||
// if (Console::Pressed(GLFW_KEY_KP_9)) Pos.y+=0.1;
|
||||
// if (Console::Pressed(GLFW_KEY_KP_3)) Pos.y-=0.1;
|
||||
|
||||
// McZapkie: zeby nie hustalo przy malym FPS:
|
||||
// Velocity= (Velocity+OldVelocity)/2;
|
||||
// matrix4x4 mat;
|
||||
vector3 Vec = Velocity;
|
||||
Vec.RotateY(Yaw);
|
||||
Pos = Pos + Vec * Timer::GetDeltaRenderTime(); // czas bez pauzy
|
||||
Velocity = Velocity / 2; // płynne hamowanie ruchu
|
||||
// double tmp= 10*DeltaTime;
|
||||
// Velocity+= -Velocity*10 * Timer::GetDeltaTime();//( tmp<1 ? tmp : 1 );
|
||||
// Type= tp_Free;
|
||||
if( Console::Pressed( Global::Keys[ k_MechRight ] ) )
|
||||
Velocity.x = clamp( Velocity.x + a * 10.0 * deltatime, -a, a );
|
||||
if( Console::Pressed( Global::Keys[ k_MechLeft ] ) )
|
||||
Velocity.x = clamp( Velocity.x - a * 10.0 * deltatime, -a, a );
|
||||
if( Console::Pressed( Global::Keys[ k_MechForward ] ) )
|
||||
Velocity.z = clamp( Velocity.z - a * 10.0 * deltatime, -a, a );
|
||||
if( Console::Pressed( Global::Keys[ k_MechBackward ] ) )
|
||||
Velocity.z = clamp( Velocity.z + a * 10.0 * deltatime, -a, a );
|
||||
}
|
||||
#else
|
||||
/*
|
||||
m_moverate = 0.8; // default (walk) movement speed
|
||||
if( Type == tp_Free ) {
|
||||
// when not in the cab the speed modifiers are active
|
||||
if( Global::shiftState ) { m_moverate = 2.5; }
|
||||
if( Global::ctrlState ) { m_moverate *= 10.0; }
|
||||
}
|
||||
*/
|
||||
if( ( Type == tp_Free )
|
||||
|| ( false == Global::ctrlState ) ) {
|
||||
// ctrl is used for mirror view, so we ignore the controls when in vehicle if ctrl is pressed
|
||||
if( m_keys.up )
|
||||
Velocity.y = clamp( Velocity.y + m_moverate.y * 10.0 * deltatime, -m_moverate.y, m_moverate.y );
|
||||
if( m_keys.down )
|
||||
Velocity.y = clamp( Velocity.y - m_moverate.y * 10.0 * deltatime, -m_moverate.y, m_moverate.y );
|
||||
|
||||
// McZapkie-170402: poruszanie i rozgladanie we free takie samo jak w follow
|
||||
if( m_keys.right )
|
||||
Velocity.x = clamp( Velocity.x + m_moverate.x * 10.0 * deltatime, -m_moverate.x, m_moverate.x );
|
||||
if( m_keys.left )
|
||||
Velocity.x = clamp( Velocity.x - m_moverate.x * 10.0 * deltatime, -m_moverate.x, m_moverate.x );
|
||||
if( m_keys.forward )
|
||||
Velocity.z = clamp( Velocity.z - m_moverate.z * 10.0 * deltatime, -m_moverate.z, m_moverate.z );
|
||||
if( m_keys.back )
|
||||
Velocity.z = clamp( Velocity.z + m_moverate.z * 10.0 * deltatime, -m_moverate.z, m_moverate.z );
|
||||
}
|
||||
#endif
|
||||
|
||||
if( Type == tp_Free ) {
|
||||
vector3 Vec = Velocity;
|
||||
Vec.RotateY( Yaw );
|
||||
Pos += Vec * 5.0 * deltatime;
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
/*
|
||||
if( deltatime < 1.0 / 20.0 ) {
|
||||
// płynne hamowanie ruchu
|
||||
Velocity -= Velocity * 20.0 * deltatime;
|
||||
}
|
||||
else {
|
||||
// instant stop
|
||||
Velocity.Zero();
|
||||
}
|
||||
if( std::abs( Velocity.x ) < 0.01 ) { Velocity.x = 0.0; }
|
||||
if( std::abs( Velocity.y ) < 0.01 ) { Velocity.y = 0.0; }
|
||||
if( std::abs( Velocity.z ) < 0.01 ) { Velocity.z = 0.0; }
|
||||
*/
|
||||
/*
|
||||
Velocity *= 0.5;
|
||||
if( std::abs( Velocity.x ) < 0.01 ) { Velocity.x = 0.0; }
|
||||
if( std::abs( Velocity.y ) < 0.01 ) { Velocity.y = 0.0; }
|
||||
if( std::abs( Velocity.z ) < 0.01 ) { Velocity.z = 0.0; }
|
||||
*/
|
||||
}
|
||||
|
||||
vector3 TCamera::GetDirection()
|
||||
|
||||
17
Camera.h
17
Camera.h
@@ -11,6 +11,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "dumb3d.h"
|
||||
#include "dynobj.h"
|
||||
#include "command.h"
|
||||
|
||||
using namespace Math3D;
|
||||
|
||||
@@ -25,7 +26,16 @@ enum TCameraType
|
||||
class TCamera
|
||||
{
|
||||
private:
|
||||
vector3 pOffset; // nie używane (zerowe)
|
||||
struct keys {
|
||||
bool forward{ false };
|
||||
bool back{ false };
|
||||
bool left{ false };
|
||||
bool right{ false };
|
||||
bool up{ false };
|
||||
bool down{ false };
|
||||
bool run{ false };
|
||||
} m_keys;
|
||||
glm::dvec3 m_moverate;
|
||||
|
||||
public: // McZapkie: potrzebuje do kiwania na boki
|
||||
double Pitch;
|
||||
@@ -36,7 +46,6 @@ class TCamera
|
||||
vector3 LookAt; // współrzędne punktu, na który ma patrzeć
|
||||
vector3 vUp;
|
||||
vector3 Velocity;
|
||||
vector3 OldVelocity; // lepiej usredniac zeby nie bylo rozbiezne przy malym FPS
|
||||
vector3 CrossPos;
|
||||
double CrossDist;
|
||||
void Init(vector3 NPos, vector3 NAngle);
|
||||
@@ -44,10 +53,10 @@ class TCamera
|
||||
{
|
||||
Pitch = Yaw = Roll = 0;
|
||||
};
|
||||
void OnCursorMove(double x, double y);
|
||||
void OnCursorMove(double const x, double const y);
|
||||
void OnCommand( command_data const &Command );
|
||||
void Update();
|
||||
vector3 GetDirection();
|
||||
// vector3 inline GetCrossPos() { return Pos+GetDirection()*CrossDist+CrossPos; };
|
||||
bool SetMatrix();
|
||||
bool SetMatrix(glm::mat4 &Matrix);
|
||||
void SetCabMatrix( vector3 &p );
|
||||
|
||||
14
Driver.cpp
14
Driver.cpp
@@ -828,12 +828,12 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
#if LOGSTOPS
|
||||
WriteLog(
|
||||
pVehicle->asName + " as " + TrainParams->TrainName
|
||||
+ ": at " + std::to_string(Simulation::Time.data().wHour) + ":" + std::to_string(Simulation::Time.data().wMinute)
|
||||
+ ": at " + std::to_string(simulation::Time.data().wHour) + ":" + std::to_string(simulation::Time.data().wMinute)
|
||||
+ " skipped " + asNextStop); // informacja
|
||||
#endif
|
||||
// przy jakim dystansie (stanie licznika) ma przesunąć na następny postój
|
||||
fLastStopExpDist = mvOccupied->DistCounter + 0.250 + 0.001 * fLength;
|
||||
TrainParams->UpdateMTable( Simulation::Time, asNextStop );
|
||||
TrainParams->UpdateMTable( simulation::Time, asNextStop );
|
||||
TrainParams->StationIndexInc(); // przejście do następnej
|
||||
asNextStop = TrainParams->NextStop(); // pobranie kolejnego miejsca zatrzymania
|
||||
// TableClear(); //aby od nowa sprawdziło W4 z inną nazwą już - to nie
|
||||
@@ -930,7 +930,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
// niezależne od sposobu obsługi drzwi, bo
|
||||
// opóźnia również kierownika
|
||||
}
|
||||
if (TrainParams->UpdateMTable( Simulation::Time, asNextStop) )
|
||||
if (TrainParams->UpdateMTable( simulation::Time, asNextStop) )
|
||||
{ // to się wykona tylko raz po zatrzymaniu na W4
|
||||
if (TrainParams->CheckTrainLatency() < 0.0)
|
||||
iDrivigFlags |= moveLate; // odnotowano spóźnienie
|
||||
@@ -976,7 +976,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
if (TrainParams->StationIndex < TrainParams->StationCount)
|
||||
{ // jeśli są dalsze stacje, czekamy do godziny odjazdu
|
||||
|
||||
if (TrainParams->IsTimeToGo(Simulation::Time.data().wHour, Simulation::Time.data().wMinute))
|
||||
if (TrainParams->IsTimeToGo(simulation::Time.data().wHour, simulation::Time.data().wMinute))
|
||||
{ // z dalszą akcją czekamy do godziny odjazdu
|
||||
/* potencjalny problem z ruszaniem z w4
|
||||
if (TrainParams->CheckTrainLatency() < 0)
|
||||
@@ -995,7 +995,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
#if LOGSTOPS
|
||||
WriteLog(
|
||||
pVehicle->asName + " as " + TrainParams->TrainName
|
||||
+ ": at " + std::to_string(Simulation::Time.data().wHour) + ":" + std::to_string(Simulation::Time.data().wMinute)
|
||||
+ ": at " + std::to_string(simulation::Time.data().wHour) + ":" + std::to_string(simulation::Time.data().wMinute)
|
||||
+ " next " + asNextStop); // informacja
|
||||
#endif
|
||||
if (int(floor(sSpeedTable[i].evEvent->ValueGet(1))) & 1)
|
||||
@@ -1022,7 +1022,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
#if LOGSTOPS
|
||||
WriteLog(
|
||||
pVehicle->asName + " as " + TrainParams->TrainName
|
||||
+ ": at " + std::to_string(Simulation::Time.data().wHour) + ":" + std::to_string(Simulation::Time.data().wMinute)
|
||||
+ ": at " + std::to_string(simulation::Time.data().wHour) + ":" + std::to_string(simulation::Time.data().wMinute)
|
||||
+ " end of route."); // informacja
|
||||
#endif
|
||||
asNextStop = TrainParams->NextStop(); // informacja o końcu trasy
|
||||
@@ -2865,7 +2865,7 @@ bool TController::PutCommand(std::string NewCommand, double NewValue1, double Ne
|
||||
}
|
||||
else
|
||||
{ // inicjacja pierwszego przystanku i pobranie jego nazwy
|
||||
TrainParams->UpdateMTable( Simulation::Time, TrainParams->NextStationName );
|
||||
TrainParams->UpdateMTable( simulation::Time, TrainParams->NextStationName );
|
||||
TrainParams->StationIndexInc(); // przejście do następnej
|
||||
iStationStart = TrainParams->StationIndex;
|
||||
asNextStop = TrainParams->NextStop();
|
||||
|
||||
23
EU07.cpp
23
EU07.cpp
@@ -23,6 +23,8 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others
|
||||
|
||||
#include "Globals.h"
|
||||
#include "Logs.h"
|
||||
#include "keyboardinput.h"
|
||||
#include "gamepadinput.h"
|
||||
#include "Console.h"
|
||||
#include "PyInt.h"
|
||||
#include "World.h"
|
||||
@@ -60,6 +62,13 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others
|
||||
|
||||
TWorld World;
|
||||
|
||||
namespace input {
|
||||
|
||||
keyboard_input Keyboard;
|
||||
gamepad_input Gamepad;
|
||||
|
||||
}
|
||||
|
||||
#ifdef CAN_I_HAS_LIBPNG
|
||||
void screenshot_save_thread( char *img )
|
||||
{
|
||||
@@ -113,12 +122,17 @@ void window_resize_callback(GLFWwindow *window, int w, int h)
|
||||
|
||||
void cursor_pos_callback(GLFWwindow *window, double x, double y)
|
||||
{
|
||||
input::Keyboard.mouse( x, y );
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
World.OnMouseMove(x * 0.005, y * 0.01);
|
||||
#endif
|
||||
glfwSetCursorPos(window, 0.0, 0.0);
|
||||
}
|
||||
|
||||
void key_callback( GLFWwindow *window, int key, int scancode, int action, int mods )
|
||||
{
|
||||
input::Keyboard.key( key, action );
|
||||
|
||||
Global::shiftState = ( mods & GLFW_MOD_SHIFT ) ? true : false;
|
||||
Global::ctrlState = ( mods & GLFW_MOD_CONTROL ) ? true : false;
|
||||
|
||||
@@ -144,6 +158,7 @@ void key_callback( GLFWwindow *window, int key, int scancode, int action, int mo
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default: { break; }
|
||||
}
|
||||
}
|
||||
else if( action == GLFW_RELEASE )
|
||||
@@ -326,6 +341,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
return -1;
|
||||
}
|
||||
input::Gamepad.init();
|
||||
|
||||
Global::pWorld = &World; // Ra: wskaźnik potrzebny do usuwania pojazdów
|
||||
if (!World.Init(window))
|
||||
@@ -335,9 +351,10 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
Console *pConsole = new Console(); // Ra: nie wiem, czy ma to sens, ale jakoś zainicjowac trzeba
|
||||
|
||||
/*
|
||||
if( !joyGetNumDevs() )
|
||||
WriteLog( "No joystick" );
|
||||
*/
|
||||
if( Global::iModifyTGA < 0 ) { // tylko modyfikacja TGA, bez uruchamiania symulacji
|
||||
Global::iMaxTextureSize = 64; //żeby nie zamulać pamięci
|
||||
World.ModifyTGA(); // rekurencyjne przeglądanie katalogów
|
||||
@@ -354,7 +371,8 @@ int main(int argc, char *argv[])
|
||||
&& World.Update()
|
||||
&& GfxRenderer.Render())
|
||||
{
|
||||
glfwPollEvents();
|
||||
glfwPollEvents();
|
||||
input::Gamepad.poll();
|
||||
}
|
||||
Console::Off(); // wyłączenie konsoli (komunikacji zwrotnej)
|
||||
}
|
||||
@@ -364,5 +382,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
glfwTerminate();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -177,9 +177,9 @@ bool TEventLauncher::Render()
|
||||
}
|
||||
else
|
||||
{ // jeśli nie cykliczny, to sprawdzić czas
|
||||
if (Simulation::Time.data().wHour == iHour)
|
||||
if (simulation::Time.data().wHour == iHour)
|
||||
{
|
||||
if (Simulation::Time.data().wMinute == iMinute)
|
||||
if (simulation::Time.data().wMinute == iMinute)
|
||||
{ // zgodność czasu uruchomienia
|
||||
if (UpdatedTime < 10)
|
||||
{
|
||||
|
||||
@@ -2826,7 +2826,7 @@ bool TGround::Init(std::string File)
|
||||
|
||||
cParser timeparser( token );
|
||||
timeparser.getTokens( 2, false, ":" );
|
||||
auto &time = Simulation::Time.data();
|
||||
auto &time = simulation::Time.data();
|
||||
timeparser
|
||||
>> time.wHour
|
||||
>> time.wMinute;
|
||||
|
||||
14
Model3d.cpp
14
Model3d.cpp
@@ -956,22 +956,22 @@ void TSubModel::RaAnimation(TAnimType a)
|
||||
glRotatef(v_Angles.z, 0.0f, 0.0f, 1.0f);
|
||||
break;
|
||||
case at_SecondsJump: // sekundy z przeskokiem
|
||||
glRotatef(Simulation::Time.data().wSecond * 6.0, 0.0, 1.0, 0.0);
|
||||
glRotatef(simulation::Time.data().wSecond * 6.0, 0.0, 1.0, 0.0);
|
||||
break;
|
||||
case at_MinutesJump: // minuty z przeskokiem
|
||||
glRotatef(Simulation::Time.data().wMinute * 6.0, 0.0, 1.0, 0.0);
|
||||
glRotatef(simulation::Time.data().wMinute * 6.0, 0.0, 1.0, 0.0);
|
||||
break;
|
||||
case at_HoursJump: // godziny skokowo 12h/360°
|
||||
glRotatef(Simulation::Time.data().wHour * 30.0 * 0.5, 0.0, 1.0, 0.0);
|
||||
glRotatef(simulation::Time.data().wHour * 30.0 * 0.5, 0.0, 1.0, 0.0);
|
||||
break;
|
||||
case at_Hours24Jump: // godziny skokowo 24h/360°
|
||||
glRotatef(Simulation::Time.data().wHour * 15.0 * 0.25, 0.0, 1.0, 0.0);
|
||||
glRotatef(simulation::Time.data().wHour * 15.0 * 0.25, 0.0, 1.0, 0.0);
|
||||
break;
|
||||
case at_Seconds: // sekundy płynnie
|
||||
glRotatef(Simulation::Time.second() * 6.0, 0.0, 1.0, 0.0);
|
||||
glRotatef(simulation::Time.second() * 6.0, 0.0, 1.0, 0.0);
|
||||
break;
|
||||
case at_Minutes: // minuty płynnie
|
||||
glRotatef(Simulation::Time.data().wMinute * 6.0 + Simulation::Time.second() * 0.1, 0.0, 1.0, 0.0);
|
||||
glRotatef(simulation::Time.data().wMinute * 6.0 + simulation::Time.second() * 0.1, 0.0, 1.0, 0.0);
|
||||
break;
|
||||
case at_Hours: // godziny płynnie 12h/360°
|
||||
glRotatef(2.0 * Global::fTimeAngleDeg, 0.0, 1.0, 0.0);
|
||||
@@ -996,7 +996,7 @@ void TSubModel::RaAnimation(TAnimType a)
|
||||
}
|
||||
break;
|
||||
case at_Wind: // ruch pod wpływem wiatru (wiatr będziemy liczyć potem...)
|
||||
glRotated(1.5 * std::sin(M_PI * Simulation::Time.second() / 6.0), 0.0, 1.0, 0.0);
|
||||
glRotated(1.5 * std::sin(M_PI * simulation::Time.second() / 6.0), 0.0, 1.0, 0.0);
|
||||
break;
|
||||
case at_Sky: // animacja nieba
|
||||
glRotated(Global::fLatitudeDeg, 1.0, 0.0, 0.0); // ustawienie osi OY na północ
|
||||
|
||||
512
Train.cpp
512
Train.cpp
@@ -13,7 +13,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "Train.h"
|
||||
|
||||
#include "Globals.h"
|
||||
@@ -22,12 +21,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Timer.h"
|
||||
#include "Driver.h"
|
||||
#include "Console.h"
|
||||
#include "McZapkie\hamulce.h"
|
||||
#include "McZapkie\MOVER.h"
|
||||
#include "Camera.h"
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
using namespace Timer;
|
||||
|
||||
TCab::TCab()
|
||||
{
|
||||
@@ -391,13 +384,390 @@ PyObject *TTrain::GetTrainState() {
|
||||
PyDict_SetItemString( dict, "actualproximitydist", PyGetFloat( driver->ActualProximityDist ) );
|
||||
PyDict_SetItemString( dict, "trainnumber", PyGetString( driver->TrainName().c_str() ) );
|
||||
// world state data
|
||||
PyDict_SetItemString( dict, "hours", PyGetInt( Simulation::Time.data().wHour ) );
|
||||
PyDict_SetItemString( dict, "minutes", PyGetInt( Simulation::Time.data().wMinute ) );
|
||||
PyDict_SetItemString( dict, "seconds", PyGetInt( Simulation::Time.second() ) );
|
||||
PyDict_SetItemString( dict, "hours", PyGetInt( simulation::Time.data().wHour ) );
|
||||
PyDict_SetItemString( dict, "minutes", PyGetInt( simulation::Time.data().wMinute ) );
|
||||
PyDict_SetItemString( dict, "seconds", PyGetInt( simulation::Time.second() ) );
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
void
|
||||
TTrain::OnCommand( command_data const &Command ) {
|
||||
|
||||
bool const isEztOer =
|
||||
( ( mvControlled->TrainType == dt_EZT )
|
||||
&& ( mvOccupied->BrakeSubsystem == ss_ESt )
|
||||
&& ( mvControlled->Battery == true )
|
||||
&& ( mvControlled->EpFuse == true )
|
||||
&& ( mvControlled->ActiveDir != 0 ) ); // od yB
|
||||
|
||||
switch( Command.command ) {
|
||||
|
||||
case user_command::mastercontrollerincrease: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
if( mvControlled->IncMainCtrl( 1 ) ) {
|
||||
// sound feedback
|
||||
play_sound( dsbNastawnikJazdy );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::mastercontrollerincreasefast: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
if( mvControlled->IncMainCtrl( 2 ) ) {
|
||||
// sound feedback
|
||||
play_sound( dsbNastawnikJazdy );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::mastercontrollerdecrease: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
if( mvControlled->DecMainCtrl( 1 ) ) {
|
||||
// sound feedback
|
||||
play_sound( dsbNastawnikJazdy );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::mastercontrollerdecreasefast: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
if( mvControlled->DecMainCtrl( 2 ) ) {
|
||||
// sound feedback
|
||||
play_sound( dsbNastawnikJazdy );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::secondcontrollerincrease: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
if( mvControlled->ShuntMode ) {
|
||||
mvControlled->AnPos += ( Command.time_delta * 0.75f );
|
||||
if( mvControlled->AnPos > 1 )
|
||||
mvControlled->AnPos = 1;
|
||||
}
|
||||
else if( mvControlled->IncScndCtrl( 1 ) ) {
|
||||
// sound feedback
|
||||
play_sound( dsbNastawnikBocz, dsbNastawnikJazdy );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::secondcontrollerincreasefast: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
if( mvControlled->IncScndCtrl( 2 ) ) {
|
||||
// sound feedback
|
||||
play_sound( dsbNastawnikBocz, dsbNastawnikJazdy );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::secondcontrollerdecrease: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
if( mvControlled->ShuntMode ) {
|
||||
mvControlled->AnPos -= ( Command.time_delta * 0.75f );
|
||||
if( mvControlled->AnPos > 1 )
|
||||
mvControlled->AnPos = 1;
|
||||
}
|
||||
else if( mvControlled->DecScndCtrl( 1 ) ) {
|
||||
// sound feedback
|
||||
play_sound( dsbNastawnikBocz, dsbNastawnikJazdy );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::secondcontrollerdecreasefast: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
if( mvControlled->DecScndCtrl( 2 ) ) {
|
||||
// sound feedback
|
||||
play_sound( dsbNastawnikBocz, dsbNastawnikJazdy );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::independentbrakeincrease: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
if( mvOccupied->LocalBrake != ManualBrake ) {
|
||||
mvOccupied->IncLocalBrakeLevel( 1 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::independentbrakeincreasefast: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
if( mvOccupied->LocalBrake != ManualBrake ) {
|
||||
mvOccupied->IncLocalBrakeLevel( 2 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::independentbrakedecrease: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
if( ( mvOccupied->LocalBrake != ManualBrake )
|
||||
// Ra 1014-06: AI potrafi zahamować pomocniczym mimo jego braku - odhamować jakoś trzeba
|
||||
// TODO: sort AI out so it doesn't do things it doesn't have equipment for
|
||||
|| ( mvOccupied->LocalBrakePos != 0 ) ) {
|
||||
mvOccupied->DecLocalBrakeLevel( 1 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::independentbrakedecreasefast: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
if( ( mvOccupied->LocalBrake != ManualBrake )
|
||||
// Ra 1014-06: AI potrafi zahamować pomocniczym mimo jego braku - odhamować jakoś trzeba
|
||||
// TODO: sort AI out so it doesn't do things it doesn't have equipment for
|
||||
|| ( mvOccupied->LocalBrakePos != 0 ) ) {
|
||||
mvOccupied->DecLocalBrakeLevel( 2 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::independentbrakebailoff: {
|
||||
// TODO: check if this set of conditions can be simplified.
|
||||
// it'd be more flexible to have an attribute indicating whether bail off position is supported
|
||||
if( ( mvControlled->TrainType != dt_EZT )
|
||||
&& ( ( mvControlled->EngineType == ElectricSeriesMotor )
|
||||
|| ( mvControlled->EngineType == DieselElectric )
|
||||
|| ( mvControlled->EngineType == ElectricInductionMotor ) )
|
||||
&& ( mvOccupied->BrakeCtrlPosNo > 0 ) ) {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
// press or hold
|
||||
ggReleaserButton.UpdateValue( 1 );
|
||||
mvOccupied->BrakeReleaser( 1 );
|
||||
}
|
||||
else {
|
||||
// release
|
||||
ggReleaserButton.UpdateValue( 0 );
|
||||
mvOccupied->BrakeReleaser( 0 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::trainbrakeincrease: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
if( mvOccupied->BrakeHandle == FV4a ) {
|
||||
mvOccupied->BrakeLevelAdd( 0.1 /*15.0 * Command.time_delta*/ );
|
||||
}
|
||||
else {
|
||||
if( mvOccupied->BrakeLevelAdd( Global::fBrakeStep ) ) {
|
||||
// nieodpowiedni warunek; true, jeśli można dalej kręcić
|
||||
keybrakecount = 0;
|
||||
if( ( isEztOer ) && ( mvOccupied->BrakeCtrlPos < 3 ) ) {
|
||||
// Ra: uzależnić dźwięk od zmiany stanu EP, nie od klawisza
|
||||
play_sound( dsbPneumaticSwitch );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::trainbrakedecrease: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
if( mvOccupied->BrakeHandle == FV4a ) {
|
||||
mvOccupied->BrakeLevelAdd( -0.1 /*-15.0 * Command.time_delta*/ );
|
||||
}
|
||||
else {
|
||||
// nową wersję dostarczył ZiomalCl ("fixed looped sound in ezt when using NUM_9 key")
|
||||
if( ( mvOccupied->BrakeCtrlPos > -1 )
|
||||
|| ( keybrakecount > 1 ) ) {
|
||||
|
||||
if( ( isEztOer )
|
||||
&& ( mvControlled->Mains )
|
||||
&& ( mvOccupied->BrakeCtrlPos != -1 ) ) {
|
||||
// Ra: uzależnić dźwięk od zmiany stanu EP, nie od klawisza
|
||||
play_sound( dsbPneumaticSwitch );
|
||||
}
|
||||
mvOccupied->BrakeLevelAdd( -Global::fBrakeStep );
|
||||
}
|
||||
else
|
||||
keybrakecount += 1;
|
||||
// koniec wersji dostarczonej przez ZiomalCl
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::trainbrakecharging: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
// sound feedback
|
||||
if( ( isEztOer )
|
||||
&& ( mvControlled->Mains )
|
||||
&& ( mvOccupied->BrakeCtrlPos != -1 ) ) {
|
||||
dsbPneumaticSwitch->Play( 0, 0, 0 );
|
||||
}
|
||||
mvOccupied->BrakeLevelSet( -1 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::trainbrakerelease: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
// sound feedback
|
||||
if( ( isEztOer )
|
||||
&& ( ( mvOccupied->BrakeCtrlPos == 1 )
|
||||
|| ( mvOccupied->BrakeCtrlPos == -1 ) ) ) {
|
||||
dsbPneumaticSwitch->Play( 0, 0, 0 );
|
||||
}
|
||||
mvOccupied->BrakeLevelSet( 0 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::trainbrakefirstservice: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
// sound feedback
|
||||
if( ( isEztOer )
|
||||
&& ( mvControlled->Mains )
|
||||
&& ( mvOccupied->BrakeCtrlPos != 1 ) ) {
|
||||
dsbPneumaticSwitch->Play( 0, 0, 0 );
|
||||
}
|
||||
mvOccupied->BrakeLevelSet( 1 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::trainbrakeservice: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
// sound feedback
|
||||
if( ( isEztOer )
|
||||
&& ( mvControlled->Mains )
|
||||
&& ( ( mvOccupied->BrakeCtrlPos == 1 )
|
||||
|| ( mvOccupied->BrakeCtrlPos == -1 ) ) ) {
|
||||
dsbPneumaticSwitch->Play( 0, 0, 0 );
|
||||
}
|
||||
mvOccupied->BrakeLevelSet(
|
||||
mvOccupied->BrakeCtrlPosNo / 2
|
||||
+ ( mvOccupied->BrakeHandle == FV4a ?
|
||||
1 :
|
||||
0 ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::trainbrakefullservice: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
// sound feedback
|
||||
if( ( isEztOer )
|
||||
&& ( mvControlled->Mains )
|
||||
&& ( ( mvOccupied->BrakeCtrlPos == 1 )
|
||||
|| ( mvOccupied->BrakeCtrlPos == -1 ) ) ) {
|
||||
dsbPneumaticSwitch->Play( 0, 0, 0 );
|
||||
}
|
||||
mvOccupied->BrakeLevelSet( mvOccupied->BrakeCtrlPosNo - 1 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::trainbrakeemergency: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_EB ) );
|
||||
if( mvOccupied->BrakeCtrlPosNo <= 0.1 ) {
|
||||
// hamulec bezpieczeństwa dla wagonów
|
||||
mvOccupied->EmergencyBrakeFlag = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::reverserincrease: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
if( mvOccupied->DirectionForward() ) {
|
||||
// sound feedback
|
||||
play_sound( dsbReverserKey, dsbSwitch );
|
||||
// aktualizacja skrajnych pojazdów w składzie
|
||||
if( ( mvOccupied->ActiveDir )
|
||||
&& ( DynamicObject->Mechanik ) ) {
|
||||
|
||||
DynamicObject->Mechanik->CheckVehicles( Change_direction );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case user_command::reverserdecrease: {
|
||||
|
||||
if( Command.action != GLFW_RELEASE ) {
|
||||
|
||||
if( mvOccupied->DirectionBackward() ) {
|
||||
// sound feedback
|
||||
play_sound( dsbReverserKey, dsbSwitch );
|
||||
// aktualizacja skrajnych pojazdów w składzie
|
||||
if( ( mvOccupied->ActiveDir )
|
||||
&& ( DynamicObject->Mechanik ) ) {
|
||||
|
||||
DynamicObject->Mechanik->CheckVehicles( Change_direction );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TTrain::OnKeyDown(int cKey)
|
||||
{ // naciśnięcie klawisza
|
||||
bool isEztOer;
|
||||
@@ -409,6 +779,7 @@ void TTrain::OnKeyDown(int cKey)
|
||||
|
||||
if (Global::shiftState)
|
||||
{ // wciśnięty [Shift]
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
if (cKey == Global::Keys[k_IncMainCtrlFAST]) // McZapkie-200702: szybkie
|
||||
// przelaczanie na poz.
|
||||
// bezoporowa
|
||||
@@ -419,7 +790,8 @@ void TTrain::OnKeyDown(int cKey)
|
||||
dsbNastawnikJazdy->Play(0, 0, 0);
|
||||
}
|
||||
}
|
||||
else if (cKey == Global::Keys[k_DirectionBackward])
|
||||
#endif
|
||||
if (cKey == Global::Keys[k_DirectionBackward])
|
||||
{
|
||||
if (mvOccupied->Radio == false)
|
||||
if (Global::ctrlState)
|
||||
@@ -429,6 +801,7 @@ void TTrain::OnKeyDown(int cKey)
|
||||
mvOccupied->Radio = true;
|
||||
}
|
||||
}
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
else if (cKey == Global::Keys[k_DecMainCtrlFAST])
|
||||
if (mvControlled->DecMainCtrl(2))
|
||||
{
|
||||
@@ -469,7 +842,7 @@ void TTrain::OnKeyDown(int cKey)
|
||||
}
|
||||
else
|
||||
;
|
||||
else if (cKey == Global::Keys[k_IncLocalBrakeLevelFAST])
|
||||
else if( cKey == Global::Keys[ k_IncLocalBrakeLevelFAST ] )
|
||||
if (mvOccupied->IncLocalBrakeLevel(2))
|
||||
;
|
||||
else
|
||||
@@ -479,6 +852,7 @@ void TTrain::OnKeyDown(int cKey)
|
||||
;
|
||||
else
|
||||
;
|
||||
#endif
|
||||
// McZapkie-240302 - wlaczanie glownego obwodu klawiszem M+shift
|
||||
//-----------
|
||||
// hunter-141211: wyl. szybki zalaczony przeniesiony do TTrain::Update()
|
||||
@@ -1177,7 +1551,8 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
}
|
||||
else // McZapkie-240302 - klawisze bez shifta
|
||||
{
|
||||
if (cKey == Global::Keys[k_IncMainCtrl])
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
if( cKey == Global::Keys[ k_IncMainCtrl ] )
|
||||
{
|
||||
if (mvControlled->IncMainCtrl(1))
|
||||
{
|
||||
@@ -1193,13 +1568,13 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
}
|
||||
else
|
||||
;
|
||||
else if (cKey == Global::Keys[k_IncScndCtrl])
|
||||
if (cKey == Global::Keys[k_IncScndCtrl])
|
||||
// if (MoverParameters->ScndCtrlPos<MoverParameters->ScndCtrlPosNo)
|
||||
// if
|
||||
// (mvControlled->EnginePowerSource.SourceType==CurrentCollector)
|
||||
if (mvControlled->ShuntMode)
|
||||
{
|
||||
mvControlled->AnPos += (GetDeltaTime() / 0.85f);
|
||||
mvControlled->AnPos += (Timer::GetDeltaTime() / 0.85f);
|
||||
if (mvControlled->AnPos > 1)
|
||||
mvControlled->AnPos = 1;
|
||||
}
|
||||
@@ -1218,11 +1593,11 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
}
|
||||
else
|
||||
;
|
||||
else if (cKey == Global::Keys[k_DecScndCtrl])
|
||||
else if( cKey == Global::Keys[ k_DecScndCtrl ] )
|
||||
// if (mvControlled->EnginePowerSource.SourceType==CurrentCollector)
|
||||
if (mvControlled->ShuntMode)
|
||||
{
|
||||
mvControlled->AnPos -= (GetDeltaTime() / 0.55f);
|
||||
mvControlled->AnPos -= (Timer::GetDeltaTime() / 0.55f);
|
||||
if (mvControlled->AnPos < 0)
|
||||
mvControlled->AnPos = 0;
|
||||
}
|
||||
@@ -1244,7 +1619,8 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
}
|
||||
else
|
||||
;
|
||||
else if (cKey == Global::Keys[k_IncLocalBrakeLevel])
|
||||
#endif
|
||||
if( cKey == Global::Keys[ k_IncLocalBrakeLevel ] )
|
||||
{ // Ra 2014-09: w
|
||||
// trybie latania
|
||||
// obsługa jest w
|
||||
@@ -1258,8 +1634,10 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
}
|
||||
else
|
||||
;
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
else if (mvOccupied->LocalBrake != ManualBrake)
|
||||
mvOccupied->IncLocalBrakeLevel(1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (cKey == Global::Keys[k_DecLocalBrakeLevel])
|
||||
@@ -1274,12 +1652,15 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
mvOccupied->DecManualBrakeLevel(1);
|
||||
else
|
||||
;
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
else // Ra 1014-06: AI potrafi zahamować pomocniczym mimo jego braku -
|
||||
// odhamować jakoś trzeba
|
||||
if ((mvOccupied->LocalBrake != ManualBrake) || mvOccupied->LocalBrakePos)
|
||||
mvOccupied->DecLocalBrakeLevel(1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
else if ((cKey == Global::Keys[k_IncBrakeLevel]) && (mvOccupied->BrakeHandle != FV4a))
|
||||
// if (mvOccupied->IncBrakeLevel())
|
||||
if (mvOccupied->BrakeLevelAdd(Global::fBrakeStep)) // nieodpowiedni
|
||||
@@ -1330,14 +1711,16 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
else keybrakecount+=1;
|
||||
*/
|
||||
}
|
||||
else if (cKey == Global::Keys[k_EmergencyBrake])
|
||||
#endif
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
else if( cKey == Global::Keys[ k_EmergencyBrake ] )
|
||||
{
|
||||
// while (mvOccupied->IncBrakeLevel());
|
||||
mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_EB));
|
||||
if (mvOccupied->BrakeCtrlPosNo <= 0.1) // hamulec bezpieczeństwa dla wagonów
|
||||
mvOccupied->EmergencyBrakeFlag = true;
|
||||
}
|
||||
else if (cKey == Global::Keys[k_Brake3])
|
||||
else if( cKey == Global::Keys[ k_Brake3 ] )
|
||||
{
|
||||
if ((isEztOer) && ((mvOccupied->BrakeCtrlPos == 1) || (mvOccupied->BrakeCtrlPos == -1)))
|
||||
{
|
||||
@@ -1350,9 +1733,11 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
// mvOccupied->IncBrakeLevel());
|
||||
mvOccupied->BrakeLevelSet(mvOccupied->BrakeCtrlPosNo - 1);
|
||||
}
|
||||
#endif
|
||||
else if (cKey == Global::Keys[k_Brake2])
|
||||
{
|
||||
if ((isEztOer) && ((mvOccupied->BrakeCtrlPos == 1) || (mvOccupied->BrakeCtrlPos == -1)))
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
if( ( isEztOer ) && ( ( mvOccupied->BrakeCtrlPos == 1 ) || ( mvOccupied->BrakeCtrlPos == -1 ) ) )
|
||||
{
|
||||
dsbPneumaticSwitch->SetVolume(-10);
|
||||
dsbPneumaticSwitch->Play(0, 0, 0);
|
||||
@@ -1363,13 +1748,15 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
// mvOccupied->IncBrakeLevel());
|
||||
mvOccupied->BrakeLevelSet(mvOccupied->BrakeCtrlPosNo / 2 +
|
||||
(mvOccupied->BrakeHandle == FV4a ? 1 : 0));
|
||||
#endif
|
||||
if (Global::ctrlState)
|
||||
mvOccupied->BrakeLevelSet(
|
||||
mvOccupied->Handle->GetPos(bh_NP)); // yB: czy ten stos funkcji nie
|
||||
// powinien być jako oddzielna
|
||||
// funkcja movera?
|
||||
}
|
||||
else if (cKey == Global::Keys[k_Brake1])
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
else if( cKey == Global::Keys[ k_Brake1 ] )
|
||||
{
|
||||
if ((isEztOer) && (mvOccupied->BrakeCtrlPos != 1))
|
||||
{
|
||||
@@ -1380,12 +1767,14 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
// while (mvOccupied->BrakeCtrlPos<1 && mvOccupied->IncBrakeLevel());
|
||||
mvOccupied->BrakeLevelSet(1);
|
||||
}
|
||||
#endif
|
||||
else if (cKey == Global::Keys[k_Brake0])
|
||||
{
|
||||
if (Global::ctrlState)
|
||||
{
|
||||
mvOccupied->BrakeCtrlPos2 = 0; // wyrownaj kapturek
|
||||
}
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
else
|
||||
{
|
||||
if ((isEztOer) &&
|
||||
@@ -1398,7 +1787,9 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
// while (mvOccupied->BrakeCtrlPos<0 && mvOccupied->IncBrakeLevel());
|
||||
mvOccupied->BrakeLevelSet(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
else if (cKey == Global::Keys[k_WaveBrake]) //[Num.]
|
||||
{
|
||||
if ((isEztOer) && (mvControlled->Mains) && (mvOccupied->BrakeCtrlPos != -1))
|
||||
@@ -1410,6 +1801,7 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
// while (mvOccupied->BrakeCtrlPos<-1 && mvOccupied->IncBrakeLevel());
|
||||
mvOccupied->BrakeLevelSet(-1);
|
||||
}
|
||||
#endif
|
||||
else if (cKey == Global::Keys[k_Czuwak])
|
||||
//---------------
|
||||
// hunter-131211: zbicie czuwaka przeniesione do TTrain::Update()
|
||||
@@ -1457,6 +1849,7 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
mvControlled->FuseOn();
|
||||
}
|
||||
}
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
else if (cKey == Global::Keys[k_DirectionForward])
|
||||
// McZapkie-240302 - zmiana kierunku: 'd' do przodu, 'r' do tylu
|
||||
{
|
||||
@@ -1483,6 +1876,7 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
Change_direction); // aktualizacja skrajnych pojazdów w składzie
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (cKey == Global::Keys[k_DirectionBackward]) // r
|
||||
{
|
||||
if (Global::ctrlState)
|
||||
@@ -1494,6 +1888,7 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
mvOccupied->Radio = false;
|
||||
}
|
||||
}
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
else if (mvOccupied->DirectionBackward())
|
||||
{
|
||||
//------------
|
||||
@@ -1516,6 +1911,7 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
DynamicObject->Mechanik->CheckVehicles(
|
||||
Change_direction); // aktualizacja skrajnych pojazdów w składzie
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (cKey == Global::Keys[k_Main])
|
||||
// McZapkie-240302 - wylaczanie glownego obwodu
|
||||
@@ -1634,7 +2030,8 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
}
|
||||
}
|
||||
//-----------
|
||||
else if (cKey == Global::Keys[k_Releaser]) // odluzniacz
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
else if( cKey == Global::Keys[ k_Releaser ] ) // odluzniacz
|
||||
{
|
||||
if (!FreeFlyModeFlag)
|
||||
{
|
||||
@@ -1654,6 +2051,7 @@ if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) ||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (cKey == Global::Keys[k_SmallCompressor]) // Winger 160404: mala
|
||||
// sprezarka wl
|
||||
{ // Ra: bez [Shift] też dać dźwięk
|
||||
@@ -2374,7 +2772,7 @@ if
|
||||
else
|
||||
{
|
||||
// McZapkie: poruszanie sie po kabinie, w updatemechpos zawarte sa wiezy
|
||||
|
||||
/*
|
||||
auto step = 1.0f;
|
||||
auto const camerayaw = Global::pCamera->Yaw;
|
||||
Math3D::vector3 direction( 0.0f, 0.0f, step );
|
||||
@@ -2428,6 +2826,7 @@ if
|
||||
else if (cKey == Global::Keys[k_MechDown])
|
||||
pMechOffset.y -= 0.25; // McZapkie-120302 - siadanie
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// else
|
||||
@@ -2573,14 +2972,14 @@ void TTrain::UpdateMechPosition(double dt)
|
||||
vMechVelocity.y = -vMechVelocity.y;
|
||||
// ABu011104: 5*pMechShake.y, zeby ladnie pudlem rzucalo :)
|
||||
pMechPosition = pMechOffset + vector3( 1.5 * pMechShake.x, 2.0 * pMechShake.y, 1.5 * pMechShake.z );
|
||||
vMechMovement = 0.5 * vMechMovement;
|
||||
// vMechMovement = 0.5 * vMechMovement;
|
||||
}
|
||||
else { // hamowanie rzucania przy spadku FPS
|
||||
pMechShake -= pMechShake * std::min( dt, 1.0 ); // po tym chyba potrafią zostać jakieś ułamki, które powodują zjazd
|
||||
pMechOffset += vMechMovement * dt;
|
||||
vMechVelocity.y = 0.5 * vMechVelocity.y;
|
||||
pMechPosition = pMechOffset + vector3( pMechShake.x, 5 * pMechShake.y, pMechShake.z );
|
||||
vMechMovement = 0.5 * vMechMovement;
|
||||
// vMechMovement = 0.5 * vMechMovement;
|
||||
}
|
||||
// numer kabiny (-1: kabina B)
|
||||
if( DynamicObject->Mechanik ) // może nie być?
|
||||
@@ -2636,6 +3035,30 @@ TTrain::GetWorldMechPosition() {
|
||||
|
||||
bool TTrain::Update( double const Deltatime )
|
||||
{
|
||||
// check for sent user commands
|
||||
// NOTE: this is a temporary arrangement, for the transition period from old command setup to the new one
|
||||
// eventually commands are going to be retrieved directly by the vehicle, filtered through active control stand
|
||||
// and ultimately executed, provided the stand allows it.
|
||||
command_data command;
|
||||
// NOTE: currently we're only storing commands for local vehicle and there's no id system in place,
|
||||
// so we're supplying 'default' vehicle id of 0
|
||||
while( simulation::Commands.pop( command, static_cast<std::size_t>( command_target::vehicle ) | 0 ) ) {
|
||||
|
||||
OnCommand( command );
|
||||
}
|
||||
|
||||
// update driver's position
|
||||
{
|
||||
vector3 Vec = Global::pCamera->Velocity * -2.0;// -7.5 * Timer::GetDeltaRenderTime();
|
||||
Vec.y = -Vec.y;
|
||||
if( mvOccupied->ActiveCab < 0 ) {
|
||||
Vec *= -1.0f;
|
||||
Vec.y = -Vec.y;
|
||||
}
|
||||
Vec.RotateY( Global::pCamera->Yaw );
|
||||
vMechMovement = Vec;
|
||||
}
|
||||
|
||||
DWORD stat;
|
||||
double dt = Deltatime; // Timer::GetDeltaTime();
|
||||
if (DynamicObject->mdKabina)
|
||||
@@ -2648,7 +3071,7 @@ bool TTrain::Update( double const Deltatime )
|
||||
fTachoVelocity = Min0R(fabs(11.31 * mvControlled->WheelDiameter * mvControlled->nrot),
|
||||
mvControlled->Vmax * 1.05);
|
||||
{ // skacze osobna zmienna
|
||||
float ff = Simulation::Time.data().wSecond; // skacze co sekunde - pol sekundy
|
||||
float ff = simulation::Time.data().wSecond; // skacze co sekunde - pol sekundy
|
||||
// pomiar, pol sekundy ustawienie
|
||||
if (ff != fTachoTimer) // jesli w tej sekundzie nie zmienial
|
||||
{
|
||||
@@ -3326,11 +3749,11 @@ bool TTrain::Update( double const Deltatime )
|
||||
// McZapkie-300302: zegarek
|
||||
if (ggClockMInd.SubModel)
|
||||
{
|
||||
ggClockSInd.UpdateValue(Simulation::Time.data().wSecond);
|
||||
ggClockSInd.UpdateValue(simulation::Time.data().wSecond);
|
||||
ggClockSInd.Update();
|
||||
ggClockMInd.UpdateValue(Simulation::Time.data().wMinute);
|
||||
ggClockMInd.UpdateValue(simulation::Time.data().wMinute);
|
||||
ggClockMInd.Update();
|
||||
ggClockHInd.UpdateValue(Simulation::Time.data().wHour + Simulation::Time.data().wMinute / 60.0);
|
||||
ggClockHInd.UpdateValue(simulation::Time.data().wHour + simulation::Time.data().wMinute / 60.0);
|
||||
ggClockHInd.Update();
|
||||
}
|
||||
|
||||
@@ -4462,7 +4885,7 @@ bool TTrain::Update( double const Deltatime )
|
||||
else
|
||||
*/
|
||||
//-----------------
|
||||
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
if ((!FreeFlyModeFlag) &&
|
||||
(!(DynamicObject->Mechanik ? DynamicObject->Mechanik->AIControllFlag : false)))
|
||||
{
|
||||
@@ -4486,6 +4909,7 @@ bool TTrain::Update( double const Deltatime )
|
||||
else
|
||||
mvOccupied->BrakeReleaser(0);
|
||||
} // FFMF
|
||||
#endif
|
||||
|
||||
if (Console::Pressed(Global::Keys[k_Univ1]))
|
||||
{
|
||||
@@ -4742,6 +5166,7 @@ bool TTrain::Update( double const Deltatime )
|
||||
if (mvOccupied->BrakeCtrlPos2 < -1.5)
|
||||
mvOccupied->BrakeCtrlPos2 = -1.5;
|
||||
}
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
else
|
||||
{
|
||||
// mvOccupied->BrakeCtrlPosR+=(mvOccupied->BrakeCtrlPosR>mvOccupied->BrakeCtrlPosNo?0:dt*2);
|
||||
@@ -4749,6 +5174,7 @@ bool TTrain::Update( double const Deltatime )
|
||||
// mvOccupied->BrakeCtrlPos=
|
||||
// floor(mvOccupied->BrakeCtrlPosR+0.499);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((mvOccupied->BrakeHandle == FV4a) && (Console::Pressed(Global::Keys[k_DecBrakeLevel])))
|
||||
@@ -4759,6 +5185,7 @@ bool TTrain::Update( double const Deltatime )
|
||||
if (mvOccupied->BrakeCtrlPos2 < -3)
|
||||
mvOccupied->BrakeCtrlPos2 = -3;
|
||||
}
|
||||
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
|
||||
else
|
||||
{
|
||||
// mvOccupied->BrakeCtrlPosR-=(mvOccupied->BrakeCtrlPosR<-1?0:dt*2);
|
||||
@@ -4766,6 +5193,7 @@ bool TTrain::Update( double const Deltatime )
|
||||
// floor(mvOccupied->BrakeCtrlPosR+0.499);
|
||||
mvOccupied->BrakeLevelAdd(-dt * 2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// bool kEP;
|
||||
@@ -5003,7 +5431,9 @@ bool TTrain::Update( double const Deltatime )
|
||||
ggMainOffButton.UpdateValue(0);
|
||||
ggMainOnButton.UpdateValue(0);
|
||||
ggSecurityResetButton.UpdateValue(0);
|
||||
/*
|
||||
ggReleaserButton.UpdateValue(0);
|
||||
*/
|
||||
ggSandButton.UpdateValue(0);
|
||||
ggAntiSlipButton.UpdateValue(0);
|
||||
ggDepartureSignalButton.UpdateValue(0);
|
||||
@@ -6609,3 +7039,23 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TTrain::play_sound( PSound Sound, PSound Fallbacksound ) {
|
||||
|
||||
if( Sound ) {
|
||||
|
||||
Sound->SetCurrentPosition( 0 );
|
||||
Sound->SetVolume( DSBVOLUME_MAX );
|
||||
Sound->Play( 0, 0, 0 );
|
||||
return;
|
||||
}
|
||||
if( Fallbacksound ) {
|
||||
|
||||
Fallbacksound->SetCurrentPosition( 0 );
|
||||
Fallbacksound->SetVolume( DSBVOLUME_MAX );
|
||||
Fallbacksound->Play( 0, 0, 0 );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
20
Train.h
20
Train.h
@@ -7,24 +7,17 @@ obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef TrainH
|
||||
#define TrainH
|
||||
#pragma once
|
||||
|
||||
//#include "Track.h"
|
||||
//#include "TrkFoll.h"
|
||||
#include "Button.h"
|
||||
#include <string>
|
||||
#include "DynObj.h"
|
||||
#include "Button.h"
|
||||
#include "Gauge.h"
|
||||
#include "Model3d.h"
|
||||
#include "Spring.h"
|
||||
#include "mtable.h"
|
||||
|
||||
#include "AdvSound.h"
|
||||
#include "FadeSound.h"
|
||||
#include "PyInt.h"
|
||||
#include "RealSound.h"
|
||||
#include "Sound.h"
|
||||
#include <string>
|
||||
#include "command.h"
|
||||
|
||||
// typedef enum {st_Off, st_Starting, st_On, st_ShuttingDown} T4State;
|
||||
|
||||
@@ -82,6 +75,7 @@ class TTrain
|
||||
bool Init(TDynamicObject *NewDynamicObject, bool e3d = false);
|
||||
void OnKeyDown(int cKey);
|
||||
void OnKeyUp(int cKey);
|
||||
void OnCommand( command_data const &Command );
|
||||
|
||||
// bool SHP() { fShpTimer= 0; };
|
||||
|
||||
@@ -113,6 +107,9 @@ class TTrain
|
||||
// initializes a button matching provided label. returns: true if the label was found, false
|
||||
// otherwise
|
||||
bool initialize_button(cParser &Parser, std::string const &Label, int const Cabindex);
|
||||
// plays specified sound, or fallback sound if the primary sound isn't presend
|
||||
// NOTE: temporary routine until sound system is sorted out and paired with switches
|
||||
void play_sound( PSound Sound, PSound Fallbacksound = nullptr );
|
||||
|
||||
private: //żeby go nic z zewnątrz nie przestawiało
|
||||
TDynamicObject *DynamicObject; // przestawia zmiana pojazdu [F5]
|
||||
@@ -438,4 +435,3 @@ class TTrain
|
||||
void Silence();
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
55
World.cpp
55
World.cpp
@@ -39,7 +39,7 @@ std::shared_ptr<ui_panel> UIHeader = std::make_shared<ui_panel>( 20, 20 ); // he
|
||||
std::shared_ptr<ui_panel> UITable = std::make_shared<ui_panel>( 20, 100 ); // schedule or scan table
|
||||
std::shared_ptr<ui_panel> UITranscripts = std::make_shared<ui_panel>( 85, 600 ); // voice transcripts
|
||||
|
||||
namespace Simulation {
|
||||
namespace simulation {
|
||||
|
||||
simulation_time Time;
|
||||
|
||||
@@ -82,14 +82,13 @@ simulation_time::init() {
|
||||
void
|
||||
simulation_time::update( double const Deltatime ) {
|
||||
|
||||
// use large enough buffer to hold long time skips
|
||||
auto milliseconds = m_time.wMilliseconds + static_cast<size_t>(std::floor( 1000.0 * Deltatime ));
|
||||
while( milliseconds >= 1000.0 ) {
|
||||
m_milliseconds += ( 1000.0 * Deltatime );
|
||||
while( m_milliseconds >= 1000.0 ) {
|
||||
|
||||
++m_time.wSecond;
|
||||
milliseconds -= 1000;
|
||||
m_milliseconds -= 1000.0;
|
||||
}
|
||||
m_time.wMilliseconds = milliseconds;
|
||||
m_time.wMilliseconds = std::floor( m_milliseconds );
|
||||
while( m_time.wSecond >= 60 ) {
|
||||
|
||||
++m_time.wMinute;
|
||||
@@ -310,7 +309,7 @@ bool TWorld::Init( GLFWwindow *Window ) {
|
||||
|
||||
glfwSetWindowTitle( window, ( Global::AppName + " (" + Global::SceneryFile + ")" ).c_str() ); // nazwa scenerii
|
||||
|
||||
Simulation::Time.init();
|
||||
simulation::Time.init();
|
||||
|
||||
Environment.init();
|
||||
Camera.Init(Global::FreeCameraInit[0], Global::FreeCameraInitAngle[0]);
|
||||
@@ -502,11 +501,11 @@ void TWorld::OnKeyDown(int cKey)
|
||||
// additional time speedup keys in debug mode
|
||||
if( Global::ctrlState ) {
|
||||
// ctrl-f3
|
||||
Simulation::Time.update( 20.0 * 60.0 );
|
||||
simulation::Time.update( 20.0 * 60.0 );
|
||||
}
|
||||
else if( Global::shiftState ) {
|
||||
// shift-f3
|
||||
Simulation::Time.update( 5.0 * 60.0 );
|
||||
simulation::Time.update( 5.0 * 60.0 );
|
||||
}
|
||||
}
|
||||
if( ( false == Global::ctrlState )
|
||||
@@ -972,13 +971,15 @@ bool TWorld::Update()
|
||||
WriteLog("Scenery moved");
|
||||
};
|
||||
#endif
|
||||
|
||||
Timer::UpdateTimers(Global::iPause != 0);
|
||||
|
||||
if( (Global::iPause == false)
|
||||
|| (m_init == false) )
|
||||
{ // jak pauza, to nie ma po co tego przeliczać
|
||||
|| (m_init == false) ) {
|
||||
// jak pauza, to nie ma po co tego przeliczać
|
||||
simulation::Time.update( Timer::GetDeltaTime() );
|
||||
// Ra 2014-07: przeliczenie kąta czasu (do animacji zależnych od czasu)
|
||||
Simulation::Time.update( Timer::GetDeltaTime() );
|
||||
auto const &time = Simulation::Time.data();
|
||||
auto const &time = simulation::Time.data();
|
||||
Global::fTimeAngleDeg = time.wHour * 15.0 + time.wMinute * 0.25 + ( ( time.wSecond + 0.001 * time.wMilliseconds ) / 240.0 );
|
||||
Global::fClockAngleDeg[ 0 ] = 36.0 * ( time.wSecond % 10 ); // jednostki sekund
|
||||
Global::fClockAngleDeg[ 1 ] = 36.0 * ( time.wSecond / 10 ); // dziesiątki sekund
|
||||
@@ -1107,6 +1108,13 @@ bool TWorld::Update()
|
||||
fTime50Hz += dt; // w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek
|
||||
while( fTime50Hz >= 1.0 / 50.0 ) {
|
||||
Console::Update(); // to i tak trzeba wywoływać
|
||||
Update_UI();
|
||||
|
||||
Camera.Velocity *= 0.65;
|
||||
if( std::abs( Camera.Velocity.x ) < 0.01 ) { Camera.Velocity.x = 0.0; }
|
||||
if( std::abs( Camera.Velocity.y ) < 0.01 ) { Camera.Velocity.y = 0.0; }
|
||||
if( std::abs( Camera.Velocity.z ) < 0.01 ) { Camera.Velocity.z = 0.0; }
|
||||
|
||||
fTime50Hz -= 1.0 / 50.0;
|
||||
}
|
||||
|
||||
@@ -1114,8 +1122,6 @@ bool TWorld::Update()
|
||||
|
||||
Update_Camera( dt );
|
||||
|
||||
Update_UI(); // TBD, TODO: move the ui updates to secondary fixed step routines, to reduce workload?
|
||||
|
||||
GfxRenderer.Update( dt );
|
||||
ResourceSweep();
|
||||
|
||||
@@ -1644,7 +1650,7 @@ TWorld::Update_UI() {
|
||||
|
||||
case( GLFW_KEY_F1 ) : {
|
||||
// f1, default mode: current time and timetable excerpt
|
||||
auto const &time = Simulation::Time.data();
|
||||
auto const &time = simulation::Time.data();
|
||||
uitextline1 =
|
||||
"Time: "
|
||||
+ to_string( time.wHour ) + ":"
|
||||
@@ -1695,7 +1701,7 @@ TWorld::Update_UI() {
|
||||
auto const table = tmp->Mechanik->Timetable();
|
||||
if( table == nullptr ) { break; }
|
||||
|
||||
auto const &time = Simulation::Time.data();
|
||||
auto const &time = simulation::Time.data();
|
||||
uitextline1 =
|
||||
"Time: "
|
||||
+ to_string( time.wHour ) + ":"
|
||||
@@ -2023,8 +2029,8 @@ TWorld::Update_UI() {
|
||||
to_string( tmp->MoverParameters->RunningShape.R, 1 ) )
|
||||
+ " An=" + to_string( tmp->MoverParameters->AccN, 2 ); // przyspieszenie poprzeczne
|
||||
|
||||
if( tprev != Simulation::Time.data().wSecond ) {
|
||||
tprev = Simulation::Time.data().wSecond;
|
||||
if( tprev != simulation::Time.data().wSecond ) {
|
||||
tprev = simulation::Time.data().wSecond;
|
||||
Acc = ( tmp->MoverParameters->Vel - VelPrev ) / 3.6;
|
||||
VelPrev = tmp->MoverParameters->Vel;
|
||||
}
|
||||
@@ -2184,8 +2190,7 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz)
|
||||
if (e)
|
||||
if ((e->Type == tp_Multiple) || (e->Type == tp_Lights) ||
|
||||
(e->evJoined != 0)) // tylko jawne albo niejawne Multiple
|
||||
Ground.AddToQuery(e, NULL); // drugi parametr to dynamic wywołujący - tu
|
||||
// brak
|
||||
Ground.AddToQuery(e, NULL); // drugi parametr to dynamic wywołujący - tu brak
|
||||
}
|
||||
break;
|
||||
case 3: // rozkaz dla AI
|
||||
@@ -2229,12 +2234,12 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz)
|
||||
if (*pRozkaz->iPar & 1) // ustawienie czasu
|
||||
{
|
||||
double t = pRozkaz->fPar[1];
|
||||
Simulation::Time.data().wDay = std::floor(t); // niby nie powinno być dnia, ale...
|
||||
simulation::Time.data().wDay = std::floor(t); // niby nie powinno być dnia, ale...
|
||||
if (Global::fMoveLight >= 0)
|
||||
Global::fMoveLight = t; // trzeba by deklinację Słońca przeliczyć
|
||||
Simulation::Time.data().wHour = std::floor(24 * t) - 24.0 * Simulation::Time.data().wDay;
|
||||
Simulation::Time.data().wMinute = std::floor(60 * 24 * t) - 60.0 * (24.0 * Simulation::Time.data().wDay + Simulation::Time.data().wHour);
|
||||
Simulation::Time.data().wSecond = std::floor( 60 * 60 * 24 * t ) - 60.0 * ( 60.0 * ( 24.0 * Simulation::Time.data().wDay + Simulation::Time.data().wHour ) + Simulation::Time.data().wMinute );
|
||||
simulation::Time.data().wHour = std::floor(24 * t) - 24.0 * simulation::Time.data().wDay;
|
||||
simulation::Time.data().wMinute = std::floor(60 * 24 * t) - 60.0 * (24.0 * simulation::Time.data().wDay + simulation::Time.data().wHour);
|
||||
simulation::Time.data().wSecond = std::floor( 60 * 60 * 24 * t ) - 60.0 * ( 60.0 * ( 24.0 * simulation::Time.data().wDay + simulation::Time.data().wHour ) + simulation::Time.data().wMinute );
|
||||
}
|
||||
if (*pRozkaz->iPar & 2)
|
||||
{ // ustawienie flag zapauzowania
|
||||
|
||||
3
World.h
3
World.h
@@ -49,11 +49,12 @@ private:
|
||||
daymonth( WORD &Day, WORD &Month, WORD const Year, WORD const Yearday );
|
||||
|
||||
SYSTEMTIME m_time;
|
||||
double m_milliseconds{ 0.0 };
|
||||
int m_yearday;
|
||||
char m_monthdaycounts[ 2 ][ 13 ];
|
||||
};
|
||||
|
||||
namespace Simulation {
|
||||
namespace simulation {
|
||||
|
||||
extern simulation_time Time;
|
||||
|
||||
|
||||
300
command.cpp
Normal file
300
command.cpp
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
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 "command.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "logs.h"
|
||||
#include "timer.h"
|
||||
|
||||
namespace simulation {
|
||||
|
||||
command_queue Commands;
|
||||
|
||||
}
|
||||
|
||||
// posts specified command for specified recipient
|
||||
void
|
||||
command_queue::push( command_data const &Command, std::size_t const Recipient ) {
|
||||
|
||||
auto lookup = m_commands.emplace( Recipient, commanddata_sequence() );
|
||||
// recipient stack was either located or created, so we can add to it quite safely
|
||||
lookup.first->second.emplace( Command );
|
||||
}
|
||||
|
||||
// retrieves oldest posted command for specified recipient, if any. returns: true on retrieval, false if there's nothing to retrieve
|
||||
bool
|
||||
command_queue::pop( command_data &Command, std::size_t const Recipient ) {
|
||||
|
||||
auto lookup = m_commands.find( Recipient );
|
||||
if( lookup == m_commands.end() ) {
|
||||
// no command stack for this recipient, so no commands
|
||||
return false;
|
||||
}
|
||||
auto &commands = lookup->second;
|
||||
if( true == commands.empty() ) {
|
||||
|
||||
return false;
|
||||
}
|
||||
// we have command stack with command(s) on it, retrieve and pop the first one
|
||||
Command = commands.front();
|
||||
commands.pop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
command_relay::command_relay() {
|
||||
|
||||
m_targets = commandtarget_map{
|
||||
|
||||
{ user_command::mastercontrollerincrease, command_target::vehicle },
|
||||
{ user_command::mastercontrollerincreasefast, command_target::vehicle },
|
||||
{ user_command::mastercontrollerdecrease, command_target::vehicle },
|
||||
{ user_command::mastercontrollerdecreasefast, command_target::vehicle },
|
||||
{ user_command::secondcontrollerincrease, command_target::vehicle },
|
||||
{ user_command::secondcontrollerincreasefast, command_target::vehicle },
|
||||
{ user_command::secondcontrollerdecrease, command_target::vehicle },
|
||||
{ user_command::secondcontrollerdecreasefast, command_target::vehicle },
|
||||
{ user_command::independentbrakeincrease, command_target::vehicle },
|
||||
{ user_command::independentbrakeincreasefast, command_target::vehicle },
|
||||
{ user_command::independentbrakedecrease, command_target::vehicle },
|
||||
{ user_command::independentbrakedecreasefast, command_target::vehicle },
|
||||
{ user_command::independentbrakebailoff, command_target::vehicle },
|
||||
{ user_command::trainbrakeincrease, command_target::vehicle },
|
||||
{ user_command::trainbrakedecrease, command_target::vehicle },
|
||||
{ user_command::trainbrakecharging, command_target::vehicle },
|
||||
{ user_command::trainbrakerelease, command_target::vehicle },
|
||||
{ user_command::trainbrakefirstservice, command_target::vehicle },
|
||||
{ user_command::trainbrakeservice, command_target::vehicle },
|
||||
{ user_command::trainbrakefullservice, command_target::vehicle },
|
||||
{ user_command::trainbrakeemergency, command_target::vehicle },
|
||||
/*
|
||||
const int k_AntiSlipping = 21;
|
||||
const int k_Sand = 22;
|
||||
const int k_Main = 23;
|
||||
*/
|
||||
{ user_command::reverserincrease, command_target::vehicle },
|
||||
{ user_command::reverserdecrease, command_target::vehicle },
|
||||
/*
|
||||
const int k_Fuse = 26;
|
||||
const int k_Compressor = 27;
|
||||
const int k_Converter = 28;
|
||||
const int k_MaxCurrent = 29;
|
||||
const int k_CurrentAutoRelay = 30;
|
||||
const int k_BrakeProfile = 31;
|
||||
const int k_Czuwak = 32;
|
||||
const int k_Horn = 33;
|
||||
const int k_Horn2 = 34;
|
||||
const int k_FailedEngineCutOff = 35;
|
||||
*/
|
||||
{ user_command::viewturn, command_target::entity },
|
||||
{ user_command::movevector, command_target::entity },
|
||||
{ user_command::moveleft, command_target::entity },
|
||||
{ user_command::moveright, command_target::entity },
|
||||
{ user_command::moveforward, command_target::entity },
|
||||
{ user_command::moveback, command_target::entity },
|
||||
{ user_command::moveup, command_target::entity },
|
||||
{ user_command::movedown, command_target::entity },
|
||||
{ user_command::moveleftfast, command_target::entity },
|
||||
{ user_command::moverightfast, command_target::entity },
|
||||
{ user_command::moveforwardfast, command_target::entity },
|
||||
{ user_command::movebackfast, command_target::entity },
|
||||
{ user_command::moveupfast, command_target::entity },
|
||||
{ user_command::movedownfast, command_target::entity }
|
||||
/*
|
||||
{ user_command::moveleftfastest, command_target::entity },
|
||||
{ user_command::moverightfastest, command_target::entity },
|
||||
{ user_command::moveforwardfastest, command_target::entity },
|
||||
{ user_command::movebackfastest, command_target::entity },
|
||||
{ user_command::moveupfastest, command_target::entity },
|
||||
{ user_command::movedownfastest, command_target::entity }
|
||||
*/
|
||||
/*
|
||||
const int k_CabForward = 42;
|
||||
const int k_CabBackward = 43;
|
||||
const int k_Couple = 44;
|
||||
const int k_DeCouple = 45;
|
||||
const int k_ProgramQuit = 46;
|
||||
// const int k_ProgramPause= 47;
|
||||
const int k_ProgramHelp = 48;
|
||||
const int k_OpenLeft = 49;
|
||||
const int k_OpenRight = 50;
|
||||
const int k_CloseLeft = 51;
|
||||
const int k_CloseRight = 52;
|
||||
const int k_DepartureSignal = 53;
|
||||
const int k_PantFrontUp = 54;
|
||||
const int k_PantRearUp = 55;
|
||||
const int k_PantFrontDown = 56;
|
||||
const int k_PantRearDown = 57;
|
||||
const int k_Heating = 58;
|
||||
// const int k_FreeFlyMode= 59;
|
||||
const int k_LeftSign = 60;
|
||||
const int k_UpperSign = 61;
|
||||
const int k_RightSign = 62;
|
||||
const int k_SmallCompressor = 63;
|
||||
const int k_StLinOff = 64;
|
||||
const int k_CurrentNext = 65;
|
||||
const int k_Univ1 = 66;
|
||||
const int k_Univ2 = 67;
|
||||
const int k_Univ3 = 68;
|
||||
const int k_Univ4 = 69;
|
||||
const int k_EndSign = 70;
|
||||
const int k_Active = 71;
|
||||
const int k_Battery = 72;
|
||||
const int k_WalkMode = 73;
|
||||
int const k_DimHeadlights = 74;
|
||||
*/
|
||||
};
|
||||
|
||||
#ifdef _DEBUG
|
||||
m_commandnames = {
|
||||
|
||||
"mastercontrollerincrease",
|
||||
"mastercontrollerincreasefast",
|
||||
"mastercontrollerdecrease",
|
||||
"mastercontrollerdecreasefast",
|
||||
"secondcontrollerincrease",
|
||||
"secondcontrollerincreasefast",
|
||||
"secondcontrollerdecrease",
|
||||
"secondcontrollerdecreasefast",
|
||||
"independentbrakeincrease",
|
||||
"independentbrakeincreasefast",
|
||||
"independentbrakedecrease",
|
||||
"independentbrakedecreasefast",
|
||||
"independentbrakebailoff",
|
||||
"trainbrakeincrease",
|
||||
"trainbrakedecrease",
|
||||
"trainbrakecharging",
|
||||
"trainbrakerelease",
|
||||
"trainbrakefirstservice",
|
||||
"trainbrakeservice",
|
||||
"trainbrakefullservice",
|
||||
"trainbrakeemergency",
|
||||
/*
|
||||
const int k_AntiSlipping = 21;
|
||||
const int k_Sand = 22;
|
||||
const int k_Main = 23;
|
||||
*/
|
||||
"reverserincrease",
|
||||
"reverserdecrease",
|
||||
/*
|
||||
const int k_Fuse = 26;
|
||||
const int k_Compressor = 27;
|
||||
const int k_Converter = 28;
|
||||
const int k_MaxCurrent = 29;
|
||||
const int k_CurrentAutoRelay = 30;
|
||||
const int k_BrakeProfile = 31;
|
||||
const int k_Czuwak = 32;
|
||||
const int k_Horn = 33;
|
||||
const int k_Horn2 = 34;
|
||||
const int k_FailedEngineCutOff = 35;
|
||||
*/
|
||||
"", //"viewturn",
|
||||
"", //"movevector",
|
||||
"", //"moveleft",
|
||||
"", //"moveright",
|
||||
"", //"moveforward",
|
||||
"", //"moveback",
|
||||
"", //"moveup",
|
||||
"", //"movedown",
|
||||
"", //"moveleftfast",
|
||||
"", //"moverightfast",
|
||||
"", //"moveforwardfast",
|
||||
"", //"movebackfast",
|
||||
"", //"moveupfast",
|
||||
"" //"movedownfast"
|
||||
/*
|
||||
"moveleftfastest",
|
||||
"moverightfastest",
|
||||
"moveforwardfastest",
|
||||
"movebackfastest",
|
||||
"moveupfastest",
|
||||
"movedownfastest"
|
||||
*/
|
||||
/*
|
||||
const int k_CabForward = 42;
|
||||
const int k_CabBackward = 43;
|
||||
const int k_Couple = 44;
|
||||
const int k_DeCouple = 45;
|
||||
const int k_ProgramQuit = 46;
|
||||
// const int k_ProgramPause= 47;
|
||||
const int k_ProgramHelp = 48;
|
||||
const int k_OpenLeft = 49;
|
||||
const int k_OpenRight = 50;
|
||||
const int k_CloseLeft = 51;
|
||||
const int k_CloseRight = 52;
|
||||
const int k_DepartureSignal = 53;
|
||||
const int k_PantFrontUp = 54;
|
||||
const int k_PantRearUp = 55;
|
||||
const int k_PantFrontDown = 56;
|
||||
const int k_PantRearDown = 57;
|
||||
const int k_Heating = 58;
|
||||
// const int k_FreeFlyMode= 59;
|
||||
const int k_LeftSign = 60;
|
||||
const int k_UpperSign = 61;
|
||||
const int k_RightSign = 62;
|
||||
const int k_SmallCompressor = 63;
|
||||
const int k_StLinOff = 64;
|
||||
const int k_CurrentNext = 65;
|
||||
const int k_Univ1 = 66;
|
||||
const int k_Univ2 = 67;
|
||||
const int k_Univ3 = 68;
|
||||
const int k_Univ4 = 69;
|
||||
const int k_EndSign = 70;
|
||||
const int k_Active = 71;
|
||||
const int k_Battery = 72;
|
||||
const int k_WalkMode = 73;
|
||||
int const k_DimHeadlights = 74;
|
||||
*/
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
command_relay::post( user_command const Command, std::uint64_t const Param1, std::uint64_t const Param2, int const Action, std::uint16_t const Recipient ) const {
|
||||
|
||||
auto const &lookup = m_targets.find( Command );
|
||||
if( lookup == m_targets.end() ) {
|
||||
// shouldn't be really needed but, eh
|
||||
return;
|
||||
}
|
||||
if( ( lookup->second == command_target::vehicle )
|
||||
&& ( true == FreeFlyModeFlag ) ) {
|
||||
// don't pass vehicle commands if the user isn't in one
|
||||
return;
|
||||
}
|
||||
|
||||
simulation::Commands.push(
|
||||
command_data{
|
||||
Command,
|
||||
Action,
|
||||
Param1,
|
||||
Param2,
|
||||
Timer::GetDeltaTime() },
|
||||
static_cast<std::size_t>( lookup->second ) | Recipient );
|
||||
|
||||
#ifdef _DEBUG
|
||||
if( Action != GLFW_RELEASE ) {
|
||||
// key was pressed or is still held
|
||||
auto const &commandname = m_commandnames.at( static_cast<std::size_t>( Command ) );
|
||||
if( false == commandname.empty() ) {
|
||||
WriteLog( "Command issued: " + commandname );
|
||||
}
|
||||
}
|
||||
/*
|
||||
else {
|
||||
// key was released (but we don't log this)
|
||||
WriteLog( "Key released: " + m_commandnames.at( static_cast<std::size_t>( Command ) ) );
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
196
command.h
Normal file
196
command.h
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
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
|
||||
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
|
||||
enum class user_command {
|
||||
|
||||
mastercontrollerincrease,
|
||||
mastercontrollerincreasefast,
|
||||
mastercontrollerdecrease,
|
||||
mastercontrollerdecreasefast,
|
||||
secondcontrollerincrease,
|
||||
secondcontrollerincreasefast,
|
||||
secondcontrollerdecrease,
|
||||
secondcontrollerdecreasefast,
|
||||
independentbrakeincrease,
|
||||
independentbrakeincreasefast,
|
||||
independentbrakedecrease,
|
||||
independentbrakedecreasefast,
|
||||
independentbrakebailoff,
|
||||
trainbrakeincrease,
|
||||
trainbrakedecrease,
|
||||
trainbrakecharging,
|
||||
trainbrakerelease,
|
||||
trainbrakefirstservice,
|
||||
trainbrakeservice,
|
||||
trainbrakefullservice,
|
||||
trainbrakeemergency,
|
||||
/*
|
||||
const int k_AntiSlipping = 21;
|
||||
const int k_Sand = 22;
|
||||
const int k_Main = 23;
|
||||
*/
|
||||
reverserincrease,
|
||||
reverserdecrease,
|
||||
/*
|
||||
const int k_Fuse = 26;
|
||||
const int k_Compressor = 27;
|
||||
const int k_Converter = 28;
|
||||
const int k_MaxCurrent = 29;
|
||||
const int k_CurrentAutoRelay = 30;
|
||||
const int k_BrakeProfile = 31;
|
||||
const int k_Czuwak = 32;
|
||||
const int k_Horn = 33;
|
||||
const int k_Horn2 = 34;
|
||||
const int k_FailedEngineCutOff = 35;
|
||||
*/
|
||||
viewturn,
|
||||
movevector,
|
||||
moveleft,
|
||||
moveright,
|
||||
moveforward,
|
||||
moveback,
|
||||
moveup,
|
||||
movedown,
|
||||
moveleftfast,
|
||||
moverightfast,
|
||||
moveforwardfast,
|
||||
movebackfast,
|
||||
moveupfast,
|
||||
movedownfast
|
||||
/*
|
||||
moveleftfastest,
|
||||
moverightfastest,
|
||||
moveforwardfastest,
|
||||
movebackfastest,
|
||||
moveupfastest,
|
||||
movedownfastest
|
||||
*/
|
||||
/*
|
||||
const int k_CabForward = 42;
|
||||
const int k_CabBackward = 43;
|
||||
const int k_Couple = 44;
|
||||
const int k_DeCouple = 45;
|
||||
const int k_ProgramQuit = 46;
|
||||
// const int k_ProgramPause= 47;
|
||||
const int k_ProgramHelp = 48;
|
||||
const int k_OpenLeft = 49;
|
||||
const int k_OpenRight = 50;
|
||||
const int k_CloseLeft = 51;
|
||||
const int k_CloseRight = 52;
|
||||
const int k_DepartureSignal = 53;
|
||||
const int k_PantFrontUp = 54;
|
||||
const int k_PantRearUp = 55;
|
||||
const int k_PantFrontDown = 56;
|
||||
const int k_PantRearDown = 57;
|
||||
const int k_Heating = 58;
|
||||
// const int k_FreeFlyMode= 59;
|
||||
const int k_LeftSign = 60;
|
||||
const int k_UpperSign = 61;
|
||||
const int k_RightSign = 62;
|
||||
const int k_SmallCompressor = 63;
|
||||
const int k_StLinOff = 64;
|
||||
const int k_CurrentNext = 65;
|
||||
const int k_Univ1 = 66;
|
||||
const int k_Univ2 = 67;
|
||||
const int k_Univ3 = 68;
|
||||
const int k_Univ4 = 69;
|
||||
const int k_EndSign = 70;
|
||||
const int k_Active = 71;
|
||||
const int k_Battery = 72;
|
||||
const int k_WalkMode = 73;
|
||||
int const k_DimHeadlights = 74;
|
||||
*/
|
||||
|
||||
};
|
||||
|
||||
enum class command_target {
|
||||
|
||||
userinterface,
|
||||
simulation,
|
||||
/*
|
||||
// NOTE: there's no need for consist- and unit-specific commands at this point, but it's a possibility.
|
||||
// since command targets are mutually exclusive these don't reduce ranges for individual vehicles etc
|
||||
consist = 0x4000,
|
||||
unit = 0x8000,
|
||||
*/
|
||||
// values are combined with object id. 0xffff objects of each type should be quite enough ("for everyone")
|
||||
vehicle = 0x10000,
|
||||
signal = 0x20000,
|
||||
entity = 0x40000
|
||||
};
|
||||
|
||||
struct command_data {
|
||||
|
||||
user_command command;
|
||||
int action; // press, repeat or release
|
||||
std::uint64_t param1;
|
||||
std::uint64_t param2;
|
||||
double time_delta;
|
||||
};
|
||||
|
||||
// command_queues: collects and holds commands from input sources, for processing by their intended recipients
|
||||
// NOTE: this won't scale well.
|
||||
// TODO: turn it into a dispatcher and build individual command sequences into the items, where they can be examined without lookups
|
||||
|
||||
class command_queue {
|
||||
|
||||
public:
|
||||
// methods
|
||||
// posts specified command for specified recipient
|
||||
void
|
||||
push( command_data const &Command, std::size_t const Recipient );
|
||||
// retrieves oldest posted command for specified recipient, if any. returns: true on retrieval, false if there's nothing to retrieve
|
||||
bool
|
||||
pop( command_data &Command, std::size_t const Recipient );
|
||||
|
||||
private:
|
||||
// types
|
||||
typedef std::queue<command_data> commanddata_sequence;
|
||||
typedef std::unordered_map<std::size_t, commanddata_sequence> commanddatasequence_map;
|
||||
// members
|
||||
commanddatasequence_map m_commands;
|
||||
|
||||
};
|
||||
|
||||
// NOTE: simulation should be a (light) wrapper rather than namespace so we could potentially instance it,
|
||||
// but realistically it's not like we're going to run more than one simulation at a time
|
||||
namespace simulation {
|
||||
|
||||
extern command_queue Commands;
|
||||
|
||||
}
|
||||
|
||||
// command_relay: composite class component, passes specified command to appropriate command stack
|
||||
|
||||
class command_relay {
|
||||
|
||||
public:
|
||||
// constructors
|
||||
command_relay();
|
||||
// methods
|
||||
// posts specified command for the specified recipient
|
||||
// TODO: replace uint16_t with recipient handle, based on item id
|
||||
void
|
||||
post( user_command const Command, std::uint64_t const Param1, std::uint64_t const Param2, int const Action, std::uint16_t const Recipient ) const;
|
||||
private:
|
||||
// types
|
||||
typedef std::unordered_map<user_command, command_target> commandtarget_map;
|
||||
// members
|
||||
commandtarget_map m_targets;
|
||||
#ifdef _DEBUG
|
||||
std::vector<std::string> m_commandnames;
|
||||
#endif
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
352
gamepadinput.cpp
Normal file
352
gamepadinput.cpp
Normal file
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
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 "gamepadinput.h"
|
||||
#include "logs.h"
|
||||
#include "timer.h"
|
||||
#include "usefull.h"
|
||||
|
||||
glm::vec2 circle_to_square( glm::vec2 const &Point, int const Roundness = 0 ) {
|
||||
|
||||
// Determine the theta angle
|
||||
auto angle = std::atan2( Point.x, Point.y ) + M_PI;
|
||||
|
||||
glm::vec2 squared;
|
||||
// Scale according to which wall we're clamping to
|
||||
// X+ wall
|
||||
if( angle <= M_PI_4 || angle > 7 * M_PI_4 )
|
||||
squared = Point * (float)( 1.0 / std::cos( angle ) );
|
||||
// Y+ wall
|
||||
else if( angle > M_PI_4 && angle <= 3 * M_PI_4 )
|
||||
squared = Point * (float)( 1.0 / std::sin( angle ) );
|
||||
// X- wall
|
||||
else if( angle > 3 * M_PI_4 && angle <= 5 * M_PI_4 )
|
||||
squared = Point * (float)( -1.0 / std::cos( angle ) );
|
||||
// Y- wall
|
||||
else if( angle > 5 * M_PI_4 && angle <= 7 * M_PI_4 )
|
||||
squared = Point * (float)( -1.0 / std::sin( angle ) );
|
||||
|
||||
// Early-out for a perfect square output
|
||||
if( Roundness == 0 )
|
||||
return squared;
|
||||
|
||||
// Find the inner-roundness scaling factor and LERP
|
||||
auto const length = glm::length( Point );
|
||||
auto const factor = std::pow( length, Roundness );
|
||||
return interpolate( Point, squared, factor );
|
||||
}
|
||||
|
||||
gamepad_input::gamepad_input() {
|
||||
|
||||
m_modecommands = {
|
||||
|
||||
{ user_command::mastercontrollerincrease, user_command::mastercontrollerdecrease },
|
||||
{ user_command::trainbrakedecrease, user_command::trainbrakeincrease },
|
||||
{ user_command::secondcontrollerincrease, user_command::secondcontrollerdecrease },
|
||||
{ user_command::independentbrakedecrease, user_command::independentbrakeincrease }
|
||||
};
|
||||
}
|
||||
|
||||
bool
|
||||
gamepad_input::init() {
|
||||
|
||||
// NOTE: we're only checking for joystick_1 and rely for it to stay connected throughout.
|
||||
// not exactly flexible, but for quick hack it'll do
|
||||
auto const name = glfwGetJoystickName( GLFW_JOYSTICK_1 );
|
||||
if( name != nullptr ) {
|
||||
WriteLog( "Connected gamepad: " + std::string( name ) );
|
||||
m_deviceid = GLFW_JOYSTICK_1;
|
||||
}
|
||||
else {
|
||||
// no joystick,
|
||||
WriteLog( "No gamepad detected" );
|
||||
m_axes.clear();
|
||||
m_buttons.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
int count;
|
||||
|
||||
glfwGetJoystickAxes( m_deviceid, &count );
|
||||
m_axes.resize( count );
|
||||
|
||||
glfwGetJoystickButtons( m_deviceid, &count );
|
||||
m_buttons.resize( count );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// checks state of the controls and sends issued commands
|
||||
void
|
||||
gamepad_input::poll() {
|
||||
|
||||
int count; std::size_t idx = 0;
|
||||
// poll button state
|
||||
auto const buttons = glfwGetJoystickButtons( m_deviceid, &count );
|
||||
if( count ) { // safety check in case joystick gets pulled out
|
||||
for( auto &button : m_buttons ) {
|
||||
|
||||
if( button != buttons[ idx ] ) {
|
||||
// button pressed or released, both are important
|
||||
on_button(
|
||||
static_cast<gamepad_button>( idx ),
|
||||
( buttons[ idx ] == 1 ?
|
||||
GLFW_PRESS :
|
||||
GLFW_RELEASE ) );
|
||||
}
|
||||
else {
|
||||
// otherwise we only pass info about button being held down
|
||||
if( button == 1 ) {
|
||||
|
||||
on_button(
|
||||
static_cast<gamepad_button>( idx ),
|
||||
GLFW_REPEAT );
|
||||
}
|
||||
}
|
||||
button = buttons[ idx ];
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_deviceid == -1 ) {
|
||||
// if there's no gamepad we can skip the rest
|
||||
return;
|
||||
}
|
||||
// poll axes state
|
||||
idx = 0;
|
||||
glm::vec2 leftstick, rightstick, triggers;
|
||||
auto const axes = glfwGetJoystickAxes( m_deviceid, &count );
|
||||
if( count ) {
|
||||
// safety check in case joystick gets pulled out
|
||||
if( count >= 2 ) {
|
||||
leftstick = glm::vec2(
|
||||
( std::abs( axes[ gamepad_axes::leftstick_x ] ) > m_deadzone ?
|
||||
axes[ gamepad_axes::leftstick_x ] :
|
||||
0.0f ),
|
||||
( std::abs( axes[ gamepad_axes::leftstick_y ] ) > m_deadzone ?
|
||||
axes[ gamepad_axes::leftstick_y ] :
|
||||
0.0f ) );
|
||||
}
|
||||
if( count >= 4 ) {
|
||||
rightstick = glm::vec2(
|
||||
( std::abs( axes[ gamepad_axes::rightstick_x ] ) > m_deadzone ?
|
||||
axes[ gamepad_axes::rightstick_x ] :
|
||||
0.0f ),
|
||||
( std::abs( axes[ gamepad_axes::rightstick_y ] ) > m_deadzone ?
|
||||
axes[ gamepad_axes::rightstick_y ] :
|
||||
0.0f ) );
|
||||
}
|
||||
if( count >= 6 ) {
|
||||
triggers = glm::vec2(
|
||||
( axes[ gamepad_axes::lefttrigger ] > m_deadzone ?
|
||||
axes[ gamepad_axes::lefttrigger ] :
|
||||
0.0f ),
|
||||
( axes[ gamepad_axes::righttrigger ] > m_deadzone ?
|
||||
axes[ gamepad_axes::righttrigger ] :
|
||||
0.0f ) );
|
||||
}
|
||||
}
|
||||
process_axes( leftstick, rightstick, triggers );
|
||||
}
|
||||
|
||||
void
|
||||
gamepad_input::on_button( gamepad_button const Button, int const Action ) {
|
||||
|
||||
switch( Button ) {
|
||||
// NOTE: this is rigid coupling, down the road we should support more flexible binding of functions with buttons
|
||||
case gamepad_button::a:
|
||||
case gamepad_button::b:
|
||||
case gamepad_button::x:
|
||||
case gamepad_button::y: {
|
||||
|
||||
if( Action == GLFW_RELEASE ) {
|
||||
// if the button was released the stick controls movement
|
||||
m_mode = control_mode::entity;
|
||||
// zero the stick and the accumulator so the input won't bleed between modes
|
||||
m_leftstick = glm::vec2();
|
||||
m_modeaccumulator = 0.0f;
|
||||
}
|
||||
else {
|
||||
// otherwise set control mode to match pressed button
|
||||
m_mode = static_cast<control_mode>( Button );
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gamepad_input::process_axes( glm::vec2 Leftstick, glm::vec2 const &Rightstick, glm::vec2 const &Triggers ) {
|
||||
|
||||
// left stick, look around
|
||||
if( ( Rightstick.x != 0.0f ) || ( Rightstick.y != 0.0f ) ) {
|
||||
// TODO: make toggles for the axis flip
|
||||
auto const deltatime = Timer::GetDeltaRenderTime() * 60.0;
|
||||
double const turnx = Rightstick.x * 10.0 * deltatime;
|
||||
double const turny = -Rightstick.y * 10.0 * deltatime;
|
||||
m_relay.post(
|
||||
user_command::viewturn,
|
||||
reinterpret_cast<std::uint64_t const &>( turnx ),
|
||||
reinterpret_cast<std::uint64_t const &>( turny ),
|
||||
GLFW_PRESS,
|
||||
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
0 );
|
||||
}
|
||||
|
||||
// right stick, either movement or controls, depending on currently active mode
|
||||
if( m_mode == control_mode::entity ) {
|
||||
|
||||
if( ( Leftstick.x != 0.0 || Leftstick.y != 0.0 )
|
||||
|| ( m_leftstick.x != 0.0 || m_leftstick.y != 0.0 ) ) {
|
||||
double const movex = static_cast<double>( Leftstick.x );
|
||||
double const movez = static_cast<double>( Leftstick.y );
|
||||
m_relay.post(
|
||||
user_command::movevector,
|
||||
reinterpret_cast<std::uint64_t const &>( movex ),
|
||||
reinterpret_cast<std::uint64_t const &>( movez ),
|
||||
GLFW_PRESS,
|
||||
0 );
|
||||
}
|
||||
/*
|
||||
Leftstick = circle_to_square( Leftstick );
|
||||
if( Leftstick.y >= 0.0f ) {
|
||||
// forward
|
||||
process_axis(
|
||||
Leftstick.y, m_leftstick.y,
|
||||
1.0,
|
||||
user_command::moveforward,
|
||||
user_command::moveforwardfast,
|
||||
0 );
|
||||
}
|
||||
if( Leftstick.y <= 0.0f ) {
|
||||
// back
|
||||
process_axis(
|
||||
Leftstick.y, m_leftstick.y,
|
||||
-1.0,
|
||||
user_command::moveback,
|
||||
user_command::movebackfast,
|
||||
0 );
|
||||
}
|
||||
if( Leftstick.x >= 0.0f ) {
|
||||
// right
|
||||
process_axis(
|
||||
Leftstick.x, m_leftstick.x,
|
||||
1.0,
|
||||
user_command::moveright,
|
||||
user_command::moverightfast,
|
||||
0 );
|
||||
}
|
||||
if( Leftstick.x <= 0.0f ) {
|
||||
// left
|
||||
process_axis(
|
||||
Leftstick.x, m_leftstick.x,
|
||||
-1.0,
|
||||
user_command::moveleft,
|
||||
user_command::moveleftfast,
|
||||
0 );
|
||||
}
|
||||
*/
|
||||
}
|
||||
else {
|
||||
// vehicle control modes
|
||||
process_mode( Leftstick.y, 0 );
|
||||
}
|
||||
|
||||
m_rightstick = Rightstick;
|
||||
m_leftstick = Leftstick;
|
||||
m_triggers = Triggers;
|
||||
}
|
||||
|
||||
void
|
||||
gamepad_input::process_axis( float const Value, float const Previousvalue, float const Multiplier, user_command Command, std::uint16_t const Recipient ) {
|
||||
|
||||
process_axis( Value, Previousvalue, Multiplier, Command, Command, Recipient );
|
||||
}
|
||||
|
||||
void
|
||||
gamepad_input::process_axis( float const Value, float const Previousvalue, float const Multiplier, user_command Command1, user_command Command2, std::uint16_t const Recipient ) {
|
||||
|
||||
user_command command{ Command1 };
|
||||
if( Value * Multiplier > 0.9 ) {
|
||||
command = Command2;
|
||||
}
|
||||
|
||||
if( Value * Multiplier > 0.0f ) {
|
||||
|
||||
m_relay.post(
|
||||
command,
|
||||
0, 0,
|
||||
GLFW_PRESS,
|
||||
Recipient
|
||||
);
|
||||
}
|
||||
else {
|
||||
// if we had movement before but not now, report this as 'button' release
|
||||
if( Previousvalue != 0.0f ) {
|
||||
m_relay.post(
|
||||
command, // doesn't matter which movement 'mode' we report
|
||||
0, 0,
|
||||
GLFW_RELEASE,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gamepad_input::process_mode( float const Value, std::uint16_t const Recipient ) {
|
||||
|
||||
// TODO: separate multiplier for each mode, to allow different, customizable sensitivity for each control
|
||||
auto const deltatime = Timer::GetDeltaTime() * 15.0;
|
||||
auto const &lookup = m_modecommands.at( static_cast<size_t>( m_mode ) );
|
||||
|
||||
if( Value >= 0.0f ) {
|
||||
if( m_modeaccumulator < 0.0f ) {
|
||||
// reset accumulator if we're going in the other direction i.e. issuing opposite control
|
||||
m_modeaccumulator = 0.0f;
|
||||
}
|
||||
if( Value > m_deadzone ) {
|
||||
m_modeaccumulator += Value * deltatime;
|
||||
while( m_modeaccumulator >= 1.0f ) {
|
||||
// send commands if the accumulator(s) was filled
|
||||
m_relay.post(
|
||||
lookup.first,
|
||||
0, 0,
|
||||
GLFW_PRESS,
|
||||
Recipient );
|
||||
m_modeaccumulator -= 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( m_modeaccumulator > 0.0f ) {
|
||||
// reset accumulator if we're going in the other direction i.e. issuing opposite control
|
||||
m_modeaccumulator = 0.0f;
|
||||
}
|
||||
if( Value < m_deadzone ) {
|
||||
m_modeaccumulator += Value * deltatime;
|
||||
while( m_modeaccumulator <= -1.0f ) {
|
||||
// send commands if the accumulator(s) was filled
|
||||
m_relay.post(
|
||||
lookup.second,
|
||||
0, 0,
|
||||
GLFW_PRESS,
|
||||
Recipient );
|
||||
m_modeaccumulator += 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
86
gamepadinput.h
Normal file
86
gamepadinput.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
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
|
||||
|
||||
#include <vector>
|
||||
#include "command.h"
|
||||
|
||||
class gamepad_input {
|
||||
|
||||
public:
|
||||
// constructors
|
||||
gamepad_input();
|
||||
|
||||
// methods
|
||||
// checks state of the controls and sends issued commands
|
||||
bool
|
||||
init();
|
||||
void
|
||||
poll();
|
||||
|
||||
private:
|
||||
// types
|
||||
enum gamepad_button {
|
||||
a,
|
||||
b,
|
||||
x,
|
||||
y,
|
||||
left_shoulder,
|
||||
right_shoulder,
|
||||
back,
|
||||
start,
|
||||
left_sticker,
|
||||
right_sticker,
|
||||
dpad_up,
|
||||
dpad_right,
|
||||
dpad_down,
|
||||
dpad_left
|
||||
};
|
||||
enum gamepad_axes {
|
||||
leftstick_x,
|
||||
leftstick_y,
|
||||
rightstick_x,
|
||||
rightstick_y,
|
||||
lefttrigger,
|
||||
righttrigger
|
||||
};
|
||||
enum class control_mode {
|
||||
entity = -1,
|
||||
vehicle_mastercontroller,
|
||||
vehicle_trainbrake,
|
||||
vehicle_secondarycontroller,
|
||||
vehicle_independentbrake
|
||||
};
|
||||
typedef std::vector<float> float_sequence;
|
||||
typedef std::vector<char> char_sequence;
|
||||
typedef std::vector< std::pair< user_command, user_command > > commandpair_sequence;
|
||||
|
||||
// methods
|
||||
void on_button( gamepad_button const Button, int const Action );
|
||||
void process_axes( glm::vec2 Leftstick, glm::vec2 const &Rightstick, glm::vec2 const &Triggers );
|
||||
void process_axis( float const Value, float const Previousvalue, float const Multiplier, user_command Command, std::uint16_t const Recipient );
|
||||
void process_axis( float const Value, float const Previousvalue, float const Multiplier, user_command Command1, user_command Command2, /*user_command Command3,*/ std::uint16_t const Recipient );
|
||||
void process_mode( float const Value, std::uint16_t const Recipient );
|
||||
|
||||
// members
|
||||
command_relay m_relay;
|
||||
float_sequence m_axes;
|
||||
char_sequence m_buttons;
|
||||
int m_deviceid{ -1 };
|
||||
control_mode m_mode{ control_mode::entity };
|
||||
commandpair_sequence m_modecommands; // sets of commands issued depending on the active control mode
|
||||
float m_deadzone{ 0.15f }; // TODO: allow to configure this
|
||||
glm::vec2 m_leftstick;
|
||||
glm::vec2 m_rightstick;
|
||||
glm::vec2 m_triggers;
|
||||
double m_modeaccumulator; // used to throttle command input rate for vehicle controls
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
204
keyboardinput.cpp
Normal file
204
keyboardinput.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
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 "keyboardinput.h"
|
||||
#include "logs.h"
|
||||
|
||||
void
|
||||
keyboard_input::recall_bindings() {
|
||||
|
||||
// TODO: implement
|
||||
|
||||
bind();
|
||||
}
|
||||
|
||||
bool
|
||||
keyboard_input::key( int const Key, int const Action ) {
|
||||
|
||||
bool modifier( false );
|
||||
|
||||
if( ( Key == GLFW_KEY_LEFT_SHIFT ) || ( Key == GLFW_KEY_RIGHT_SHIFT ) ) {
|
||||
// update internal state, but don't bother passing these
|
||||
m_shift =
|
||||
( Action == GLFW_RELEASE ?
|
||||
false :
|
||||
true );
|
||||
modifier = true;
|
||||
}
|
||||
if( ( Key == GLFW_KEY_LEFT_CONTROL ) || ( Key == GLFW_KEY_RIGHT_CONTROL ) ) {
|
||||
// update internal state, but don't bother passing these
|
||||
m_ctrl =
|
||||
( Action == GLFW_RELEASE ?
|
||||
false :
|
||||
true );
|
||||
modifier = true;
|
||||
}
|
||||
if( ( Key == GLFW_KEY_LEFT_ALT ) || ( Key == GLFW_KEY_RIGHT_ALT ) ) {
|
||||
// currently we have no interest in these whatsoever
|
||||
return false;
|
||||
}
|
||||
|
||||
// include active modifiers for currently pressed key, except if the key is a modifier itself
|
||||
auto const key =
|
||||
Key
|
||||
| ( modifier ? 0 : ( m_shift ? keymodifier::shift : 0 ) )
|
||||
| ( modifier ? 0 : ( m_ctrl ? keymodifier::control : 0 ) );
|
||||
|
||||
auto const lookup = m_bindings.find( key );
|
||||
if( lookup == m_bindings.end() ) {
|
||||
// no binding for this key
|
||||
return false;
|
||||
}
|
||||
// NOTE: basic keyboard controls don't have any parameters
|
||||
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
m_relay.post( lookup->second, 0, 0, Action, 0 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
keyboard_input::mouse( double Mousex, double Mousey ) {
|
||||
|
||||
m_relay.post(
|
||||
user_command::viewturn,
|
||||
reinterpret_cast<std::uint64_t const &>( Mousex ),
|
||||
reinterpret_cast<std::uint64_t const &>( Mousey ),
|
||||
GLFW_PRESS,
|
||||
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
0 );
|
||||
}
|
||||
|
||||
void
|
||||
keyboard_input::default_bindings() {
|
||||
|
||||
m_commands = {
|
||||
|
||||
{ "mastercontrollerincrease", command_target::vehicle, GLFW_KEY_KP_ADD },
|
||||
{ "mastercontrollerincreasefast", command_target::vehicle, GLFW_KEY_KP_ADD | keymodifier::shift },
|
||||
{ "mastercontrollerdecrease", command_target::vehicle, GLFW_KEY_KP_SUBTRACT },
|
||||
{ "mastercontrollerdecreasefast", command_target::vehicle, GLFW_KEY_KP_SUBTRACT | keymodifier::shift },
|
||||
{ "secondcontrollerincrease", command_target::vehicle, GLFW_KEY_KP_DIVIDE },
|
||||
{ "secondcontrollerincreasefast", command_target::vehicle, GLFW_KEY_KP_DIVIDE | keymodifier::shift },
|
||||
{ "secondcontrollerdecrease", command_target::vehicle, GLFW_KEY_KP_MULTIPLY },
|
||||
{ "secondcontrollerdecreasefast", command_target::vehicle, GLFW_KEY_KP_MULTIPLY | keymodifier::shift },
|
||||
{ "independentbrakeincrease", command_target::vehicle, GLFW_KEY_KP_1 },
|
||||
{ "independentbrakeincreasefast", command_target::vehicle, GLFW_KEY_KP_1 | keymodifier::shift },
|
||||
{ "independentbrakedecrease", command_target::vehicle, GLFW_KEY_KP_7 },
|
||||
{ "independentbrakedecreasefast", command_target::vehicle, GLFW_KEY_KP_7 | keymodifier::shift },
|
||||
{ "independentbrakebailoff", command_target::vehicle, GLFW_KEY_KP_4 },
|
||||
{ "trainbrakeincrease", command_target::vehicle, GLFW_KEY_KP_3 },
|
||||
{ "trainbrakedecrease", command_target::vehicle, GLFW_KEY_KP_9 },
|
||||
{ "trainbrakecharging", command_target::vehicle, GLFW_KEY_KP_DECIMAL },
|
||||
{ "trainbrakerelease", command_target::vehicle, GLFW_KEY_KP_6 },
|
||||
{ "trainbrakefirstservice", command_target::vehicle, GLFW_KEY_KP_8 },
|
||||
{ "trainbrakeservice", command_target::vehicle, GLFW_KEY_KP_5 },
|
||||
{ "trainbrakefullservice", command_target::vehicle, GLFW_KEY_KP_2 },
|
||||
{ "trainbrakeemergency", command_target::vehicle, GLFW_KEY_KP_0 },
|
||||
/*
|
||||
const int k_AntiSlipping = 21;
|
||||
const int k_Sand = 22;
|
||||
const int k_Main = 23;
|
||||
*/
|
||||
{ "reverserincrease", command_target::vehicle, GLFW_KEY_D },
|
||||
{ "reverserdecrease", command_target::vehicle, GLFW_KEY_R },
|
||||
/*
|
||||
const int k_Fuse = 26;
|
||||
const int k_Compressor = 27;
|
||||
const int k_Converter = 28;
|
||||
const int k_MaxCurrent = 29;
|
||||
const int k_CurrentAutoRelay = 30;
|
||||
const int k_BrakeProfile = 31;
|
||||
const int k_Czuwak = 32;
|
||||
const int k_Horn = 33;
|
||||
const int k_Horn2 = 34;
|
||||
const int k_FailedEngineCutOff = 35;
|
||||
*/
|
||||
{ "viewturn", command_target::entity, -1 },
|
||||
{ "movevector", command_target::entity, -1 },
|
||||
{ "moveleft", command_target::entity, GLFW_KEY_LEFT },
|
||||
{ "moveright", command_target::entity, GLFW_KEY_RIGHT },
|
||||
{ "moveforward", command_target::entity, GLFW_KEY_UP },
|
||||
{ "moveback", command_target::entity, GLFW_KEY_DOWN },
|
||||
{ "moveup", command_target::entity, GLFW_KEY_PAGE_UP },
|
||||
{ "movedown", command_target::entity, GLFW_KEY_PAGE_DOWN },
|
||||
{ "moveleftfast", command_target::entity, GLFW_KEY_LEFT | keymodifier::shift },
|
||||
{ "moverightfast", command_target::entity, GLFW_KEY_RIGHT | keymodifier::shift },
|
||||
{ "moveforwardfast", command_target::entity, GLFW_KEY_UP | keymodifier::shift },
|
||||
{ "movebackfast", command_target::entity, GLFW_KEY_DOWN | keymodifier::shift },
|
||||
{ "moveupfast", command_target::entity, GLFW_KEY_PAGE_UP | keymodifier::shift },
|
||||
{ "movedownfast", command_target::entity, GLFW_KEY_PAGE_DOWN | keymodifier::shift }
|
||||
/*
|
||||
{ "moveleftfastest", command_target::entity, GLFW_KEY_LEFT | keymodifier::control },
|
||||
{ "moverightfastest", command_target::entity, GLFW_KEY_RIGHT | keymodifier::control },
|
||||
{ "moveforwardfastest", command_target::entity, GLFW_KEY_UP | keymodifier::control },
|
||||
{ "movebackfastest", command_target::entity, GLFW_KEY_DOWN | keymodifier::control },
|
||||
{ "moveupfastest", command_target::entity, GLFW_KEY_PAGE_UP | keymodifier::control },
|
||||
{ "movedownfastest", command_target::entity, GLFW_KEY_PAGE_DOWN | keymodifier::control }
|
||||
*/
|
||||
/*
|
||||
const int k_CabForward = 42;
|
||||
const int k_CabBackward = 43;
|
||||
const int k_Couple = 44;
|
||||
const int k_DeCouple = 45;
|
||||
const int k_ProgramQuit = 46;
|
||||
// const int k_ProgramPause= 47;
|
||||
const int k_ProgramHelp = 48;
|
||||
const int k_OpenLeft = 49;
|
||||
const int k_OpenRight = 50;
|
||||
const int k_CloseLeft = 51;
|
||||
const int k_CloseRight = 52;
|
||||
const int k_DepartureSignal = 53;
|
||||
const int k_PantFrontUp = 54;
|
||||
const int k_PantRearUp = 55;
|
||||
const int k_PantFrontDown = 56;
|
||||
const int k_PantRearDown = 57;
|
||||
const int k_Heating = 58;
|
||||
// const int k_FreeFlyMode= 59;
|
||||
const int k_LeftSign = 60;
|
||||
const int k_UpperSign = 61;
|
||||
const int k_RightSign = 62;
|
||||
const int k_SmallCompressor = 63;
|
||||
const int k_StLinOff = 64;
|
||||
const int k_CurrentNext = 65;
|
||||
const int k_Univ1 = 66;
|
||||
const int k_Univ2 = 67;
|
||||
const int k_Univ3 = 68;
|
||||
const int k_Univ4 = 69;
|
||||
const int k_EndSign = 70;
|
||||
const int k_Active = 71;
|
||||
const int k_Battery = 72;
|
||||
const int k_WalkMode = 73;
|
||||
int const k_DimHeadlights = 74;
|
||||
*/
|
||||
};
|
||||
|
||||
bind();
|
||||
}
|
||||
|
||||
void
|
||||
keyboard_input::bind() {
|
||||
|
||||
m_bindings.clear();
|
||||
|
||||
int commandcode{ 0 };
|
||||
for( auto const &command : m_commands ) {
|
||||
|
||||
if( command.binding != -1 ) {
|
||||
m_bindings.emplace(
|
||||
command.binding,
|
||||
static_cast<user_command>( commandcode ) );
|
||||
}
|
||||
++commandcode;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
61
keyboardinput.h
Normal file
61
keyboardinput.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
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
|
||||
|
||||
#include <unordered_map>
|
||||
#include "command.h"
|
||||
|
||||
class keyboard_input {
|
||||
|
||||
public:
|
||||
// constructors
|
||||
keyboard_input() { default_bindings(); }
|
||||
|
||||
// methods
|
||||
void
|
||||
recall_bindings();
|
||||
bool
|
||||
key( int const Key, int const Action );
|
||||
void
|
||||
mouse( double const Mousex, double const Mousey );
|
||||
|
||||
private:
|
||||
// types
|
||||
enum keymodifier : int {
|
||||
|
||||
shift = 0x10000,
|
||||
control = 0x20000
|
||||
};
|
||||
|
||||
struct command_setup {
|
||||
|
||||
std::string name;
|
||||
command_target target;
|
||||
int binding;
|
||||
};
|
||||
|
||||
typedef std::vector<command_setup> commandsetup_sequence;
|
||||
typedef std::unordered_map<int, user_command> usercommand_map;
|
||||
|
||||
// methods
|
||||
void
|
||||
default_bindings();
|
||||
void
|
||||
bind();
|
||||
|
||||
// members
|
||||
commandsetup_sequence m_commands;
|
||||
usercommand_map m_bindings;
|
||||
command_relay m_relay;
|
||||
bool m_shift{ false };
|
||||
bool m_ctrl{ false };
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -16,15 +16,15 @@
|
||||
<Filter Include="Source Files\mczapkie">
|
||||
<UniqueIdentifier>{fafd38ab-4c2a-48c8-8e66-ad0d928573b3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\console">
|
||||
<UniqueIdentifier>{2d73d7b2-5252-499c-963a-88fa3cb1af53}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\mczapkie">
|
||||
<UniqueIdentifier>{36684428-8a48-435f-bca4-a24d9bfe2587}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\console">
|
||||
<Filter Include="Header Files\input">
|
||||
<UniqueIdentifier>{cdf75bec-91f7-413c-8b57-9e32cba49148}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\input">
|
||||
<UniqueIdentifier>{2d73d7b2-5252-499c-963a-88fa3cb1af53}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AdvSound.cpp">
|
||||
@@ -157,7 +157,7 @@
|
||||
<Filter>Source Files\mczapkie</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="console\LPT.cpp">
|
||||
<Filter>Source Files\console</Filter>
|
||||
<Filter>Source Files\input</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mczapkie\mctools.cpp">
|
||||
<Filter>Source Files\mczapkie</Filter>
|
||||
@@ -169,13 +169,13 @@
|
||||
<Filter>Source Files\mczapkie</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="console\PoKeys55.cpp">
|
||||
<Filter>Source Files\console</Filter>
|
||||
<Filter>Source Files\input</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Console\MWD.cpp">
|
||||
<Filter>Source Files\console</Filter>
|
||||
<Filter>Source Files\input</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Names.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
@@ -213,6 +213,15 @@
|
||||
<ClCompile Include="moon.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="command.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="keyboardinput.cpp">
|
||||
<Filter>Source Files\input</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gamepadinput.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Globals.h">
|
||||
@@ -291,10 +300,10 @@
|
||||
<Filter>Header Files\mczapkie</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console\PoKeys55.h">
|
||||
<Filter>Header Files\console</Filter>
|
||||
<Filter>Header Files\input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console\LPT.h">
|
||||
<Filter>Header Files\console</Filter>
|
||||
<Filter>Header Files\input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RealSound.h">
|
||||
<Filter>Header Files</Filter>
|
||||
@@ -375,7 +384,7 @@
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console\MWD.h">
|
||||
<Filter>Header Files\console</Filter>
|
||||
<Filter>Header Files\input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="sun.h">
|
||||
<Filter>Header Files</Filter>
|
||||
@@ -413,6 +422,15 @@
|
||||
<ClInclude Include="moon.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="command.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="keyboardinput.h">
|
||||
<Filter>Header Files\input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gamepadinput.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="maszyna.rc">
|
||||
|
||||
6
moon.cpp
6
moon.cpp
@@ -116,7 +116,7 @@ void cMoon::move() {
|
||||
static double radtodeg = 57.295779513; // converts from radians to degrees
|
||||
static double degtorad = 0.0174532925; // converts from degrees to radians
|
||||
|
||||
SYSTEMTIME localtime = Simulation::Time.data(); // time for the calculation
|
||||
SYSTEMTIME localtime = simulation::Time.data(); // time for the calculation
|
||||
|
||||
if( m_observer.hour >= 0 ) { localtime.wHour = m_observer.hour; }
|
||||
if( m_observer.minute >= 0 ) { localtime.wMinute = m_observer.minute; }
|
||||
@@ -284,7 +284,7 @@ void cMoon::irradiance() {
|
||||
static double radtodeg = 57.295779513; // converts from radians to degrees
|
||||
static double degtorad = 0.0174532925; // converts from degrees to radians
|
||||
|
||||
m_body.dayang = ( Simulation::Time.year_day() - 1 ) * 360.0 / 365.0;
|
||||
m_body.dayang = ( simulation::Time.year_day() - 1 ) * 360.0 / 365.0;
|
||||
double sd = sin( degtorad * m_body.dayang ); // sine of the day angle
|
||||
double cd = cos( degtorad * m_body.dayang ); // cosine of the day angle or delination
|
||||
m_body.erv = 1.000110 + 0.034221*cd + 0.001280*sd;
|
||||
@@ -310,7 +310,7 @@ void
|
||||
cMoon::phase() {
|
||||
|
||||
// calculate moon's age in days from new moon
|
||||
float ip = normalize( ( Simulation::Time.julian_day() - 2451550.1f ) / 29.530588853f );
|
||||
float ip = normalize( ( simulation::Time.julian_day() - 2451550.1f ) / 29.530588853f );
|
||||
m_phase = ip * 29.53f;
|
||||
}
|
||||
|
||||
|
||||
6
sun.cpp
6
sun.cpp
@@ -115,7 +115,7 @@ void cSun::move() {
|
||||
static double radtodeg = 57.295779513; // converts from radians to degrees
|
||||
static double degtorad = 0.0174532925; // converts from degrees to radians
|
||||
|
||||
SYSTEMTIME localtime = Simulation::Time.data(); // time for the calculation
|
||||
SYSTEMTIME localtime = simulation::Time.data(); // time for the calculation
|
||||
|
||||
if( m_observer.hour >= 0 ) { localtime.wHour = m_observer.hour; }
|
||||
if( m_observer.minute >= 0 ) { localtime.wMinute = m_observer.minute; }
|
||||
@@ -258,9 +258,9 @@ void cSun::irradiance() {
|
||||
static double degrad = 57.295779513; // converts from radians to degrees
|
||||
static double raddeg = 0.0174532925; // converts from degrees to radians
|
||||
|
||||
auto const &localtime = Simulation::Time.data(); // time for the calculation
|
||||
auto const &localtime = simulation::Time.data(); // time for the calculation
|
||||
|
||||
m_body.dayang = ( Simulation::Time.year_day() - 1 ) * 360.0 / 365.0;
|
||||
m_body.dayang = ( simulation::Time.year_day() - 1 ) * 360.0 / 365.0;
|
||||
double sd = sin( raddeg * m_body.dayang ); // sine of the day angle
|
||||
double cd = cos( raddeg * m_body.dayang ); // cosine of the day angle or delination
|
||||
m_body.erv = 1.000110 + 0.034221*cd + 0.001280*sd;
|
||||
|
||||
Reference in New Issue
Block a user