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

engine-powered compressor sound pitch adjustment, model node angles, global settings export and diagnostics, departure permit sound enhancement, radio channel selection ai logic enhancement, door permission ai logic fix

This commit is contained in:
tmj-fstate
2020-07-16 21:32:51 +02:00
parent 3ea0d5b074
commit 0d0e299a29
15 changed files with 451 additions and 101 deletions

View File

@@ -432,6 +432,15 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable
return ( pModel != nullptr ); return ( pModel != nullptr );
} }
bool
TAnimModel::is_keyword( std::string const &Token ) const {
return ( Token == "endmodel" )
|| ( Token == "lights" )
|| ( Token == "lightcolors" )
|| ( Token == "angles" );
}
bool TAnimModel::Load(cParser *parser, bool ter) bool TAnimModel::Load(cParser *parser, bool ter)
{ // rozpoznanie wpisu modelu i ustawienie świateł { // rozpoznanie wpisu modelu i ustawienie świateł
std::string name = parser->getToken<std::string>(); std::string name = parser->getToken<std::string>();
@@ -485,8 +494,7 @@ bool TAnimModel::Load(cParser *parser, bool ter)
if( token == "lights" ) { if( token == "lights" ) {
auto i{ 0 }; auto i{ 0 };
while( ( false == ( token = parser->getToken<std::string>() ).empty() ) while( ( false == ( token = parser->getToken<std::string>() ).empty() )
&& ( token != "lightcolors" ) && ( false == is_keyword( token ) ) ) {
&& ( token != "endmodel" ) ) {
if( i < iNumLights ) { if( i < iNumLights ) {
// stan światła jest liczbą z ułamkiem // stan światła jest liczbą z ułamkiem
@@ -499,8 +507,7 @@ bool TAnimModel::Load(cParser *parser, bool ter)
if( token == "lightcolors" ) { if( token == "lightcolors" ) {
auto i{ 0 }; auto i{ 0 };
while( ( false == ( token = parser->getToken<std::string>() ).empty() ) while( ( false == ( token = parser->getToken<std::string>() ).empty() )
&& ( token != "lights" ) && ( false == is_keyword( token ) ) ) {
&& ( token != "endmodel" ) ) {
if( ( i < iNumLights ) if( ( i < iNumLights )
&& ( token != "-1" ) ) { // -1 leaves the default color intact && ( token != "-1" ) ) { // -1 leaves the default color intact
@@ -513,6 +520,15 @@ bool TAnimModel::Load(cParser *parser, bool ter)
++i; ++i;
} }
} }
if( token == "angles" ) {
parser->getTokens( 3 );
*parser
>> vAngle[ 0 ]
>> vAngle[ 1 ]
>> vAngle[ 2 ];
}
} while( ( false == token.empty() ) } while( ( false == token.empty() )
&& ( token != "endmodel" ) ); && ( token != "endmodel" ) );

View File

@@ -177,6 +177,8 @@ private:
void deserialize_( std::istream &Input ); void deserialize_( std::istream &Input );
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream // export() subclass details, sends basic content of the class in legacy (text) format to provided stream
void export_as_text_( std::ostream &Output ) const; void export_as_text_( std::ostream &Output ) const;
// checks whether provided token is a legacy (text) format keyword
bool is_keyword( std::string const &Token ) const;
// members // members
TAnimContainer *pRoot { nullptr }; // pojemniki sterujące, tylko dla aniomowanych submodeli TAnimContainer *pRoot { nullptr }; // pojemniki sterujące, tylko dla aniomowanych submodeli

View File

@@ -898,6 +898,21 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
} }
else if (iDrivigFlags & moveStopPoint) // jeśli pomijanie W4, to nie sprawdza czasu odjazdu else if (iDrivigFlags & moveStopPoint) // jeśli pomijanie W4, to nie sprawdza czasu odjazdu
{ // tylko gdy nazwa zatrzymania się zgadza { // tylko gdy nazwa zatrzymania się zgadza
if( ( OrderCurrentGet() & ( Obey_train | Bank ) ) != 0 ) {
// check whether the station specifies radio channel change
// NOTE: we don't do it in shunt mode, as shunting operations tend to use dedicated radio channel
// NOTE: there's a risk radio channel change was specified by a station which we skipped during timetable rewind
// we ignore this for the time being as it's not a high priority error
auto const radiochannel { TrainParams.radio_channel() };
if( radiochannel > 0 ) {
if( iGuardRadio != 0 ) {
iGuardRadio = radiochannel;
}
if( AIControllFlag ) {
iRadioChannel = radiochannel;
}
}
}
IsScheduledPassengerStopVisible = true; // block potential timetable rewind if the next stop shows up later in the scan IsScheduledPassengerStopVisible = true; // block potential timetable rewind if the next stop shows up later in the scan
if (false == TrainParams.IsStop()) if (false == TrainParams.IsStop())
{ // jeśli nie ma tu postoju { // jeśli nie ma tu postoju
@@ -3217,8 +3232,8 @@ bool TController::IncSpeed()
return false; return false;
} }
bool OK = true; bool OK = true;
if( ( doors_open() ) if( ( VelDesired > 0.0 ) // to prevent door shuffle on stop
&& ( VelDesired > 0.0 ) ) { // to prevent door shuffle on stop && ( doors_open() || doors_permit_active() ) ) {
// zamykanie drzwi - tutaj wykonuje tylko AI (zmienia fActionTime) // zamykanie drzwi - tutaj wykonuje tylko AI (zmienia fActionTime)
Doors( false ); Doors( false );
} }
@@ -4091,14 +4106,14 @@ void TController::Doors( bool const Open, int const Side ) {
} }
else { else {
// zamykanie // zamykanie
if( ( false == pVehicle->MoverParameters->Doors.permit_needed ) if( ( false == doors_permit_active() )
&& ( false == doors_open() ) ) { && ( false == doors_open() ) ) {
// the doors are already closed and we don't have to revoke control permit, we can skip all hard work // the doors are already closed and we don't have to revoke control permit, we can skip all hard work
iDrivigFlags &= ~moveDoorOpened; iDrivigFlags &= ~moveDoorOpened;
return; return;
} }
if( AIControllFlag ) { if( ( AIControllFlag ) && ( doors_open() ) ) {
if( ( true == mvOccupied->Doors.has_warning ) if( ( true == mvOccupied->Doors.has_warning )
&& ( false == mvOccupied->DepartureSignal ) && ( false == mvOccupied->DepartureSignal )
&& ( true == TestFlag( iDrivigFlags, moveDoorOpened ) ) ) { && ( true == TestFlag( iDrivigFlags, moveDoorOpened ) ) ) {
@@ -4107,20 +4122,22 @@ void TController::Doors( bool const Open, int const Side ) {
} }
} }
if( ( true == doors_open() ) if( ( false == AIControllFlag ) || ( fActionTime > -0.5 ) ) {
&& ( ( fActionTime > -0.5 )
|| ( false == AIControllFlag ) ) ) {
// ai doesn't close the door until it's free to depart, but human driver has free reign to do stupid things // ai doesn't close the door until it's free to depart, but human driver has free reign to do stupid things
if( ( pVehicle->MoverParameters->Doors.close_control == control_t::conductor ) if( true == doors_open() ) {
|| ( ( true == AIControllFlag ) ) ) { if( ( pVehicle->MoverParameters->Doors.close_control == control_t::conductor )
// if the door are controlled by the driver, we let the user operate them unless this user is an ai || ( ( true == AIControllFlag ) ) ) {
// the train conductor, if present, handles door operation also for human-driven trains // if the door are controlled by the driver, we let the user operate them unless this user is an ai
if( ( pVehicle->MoverParameters->Doors.close_control == control_t::driver ) // the train conductor, if present, handles door operation also for human-driven trains
|| ( pVehicle->MoverParameters->Doors.close_control == control_t::mixed ) ) { if( ( pVehicle->MoverParameters->Doors.close_control == control_t::driver )
pVehicle->MoverParameters->OperateDoors( side::right, false ); || ( pVehicle->MoverParameters->Doors.close_control == control_t::mixed ) ) {
pVehicle->MoverParameters->OperateDoors( side::left, false ); pVehicle->MoverParameters->OperateDoors( side::right, false );
pVehicle->MoverParameters->OperateDoors( side::left, false );
}
} }
if( pVehicle->MoverParameters->Doors.permit_needed ) { }
if( true == doors_permit_active() ) {
if( true == AIControllFlag ) {
pVehicle->MoverParameters->PermitDoors( side::right, false ); pVehicle->MoverParameters->PermitDoors( side::right, false );
pVehicle->MoverParameters->PermitDoors( side::left, false ); pVehicle->MoverParameters->PermitDoors( side::left, false );
} }
@@ -4157,19 +4174,14 @@ TController::doors_open() const {
return ( return (
IsAnyDoorOpen[ side::right ] IsAnyDoorOpen[ side::right ]
|| IsAnyDoorOpen[ side::left ] ); || IsAnyDoorOpen[ side::left ] );
/* }
auto *vehicle = pVehicles[ 0 ]; // pojazd na czole składu
while( vehicle != nullptr ) { bool
if( ( false == vehicle->MoverParameters->Doors.instances[side::right].is_closed ) TController::doors_permit_active() const {
|| ( false == vehicle->MoverParameters->Doors.instances[side::left].is_closed ) ) {
// any open door is enough return (
return true; IsAnyDoorPermitActive[ side::right ]
} || IsAnyDoorPermitActive[ side::left ] );
vehicle = vehicle->Next();
}
// if we're still here there's nothing open
return false;
*/
} }
void TController::RecognizeCommand() void TController::RecognizeCommand()
@@ -4275,7 +4287,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
{ ".ogg", ".flac", ".wav" } ); { ".ogg", ".flac", ".wav" } );
if( false == lookup.first.empty() ) { if( false == lookup.first.empty() ) {
// wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie) // wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie)
tsGuardSignal = sound_source( sound_placement::internal, 2 * EU07_SOUND_CABCONTROLSCUTOFFRANGE ).deserialize( lookup.first + lookup.second, sound_type::single ); tsGuardSignal = sound_source( sound_placement::internal, EU07_SOUND_HANDHELDRADIORANGE ).deserialize( lookup.first + lookup.second, sound_type::single );
iGuardRadio = iRadioChannel; iGuardRadio = iRadioChannel;
} }
} }
@@ -4733,6 +4745,7 @@ TController::UpdateSituation(double dt) {
double AbsAccS = 0; double AbsAccS = 0;
IsAnyCouplerStretched = false; IsAnyCouplerStretched = false;
IsAnyDoorOpen[ side::right ] = IsAnyDoorOpen[ side::left ] = false; IsAnyDoorOpen[ side::right ] = IsAnyDoorOpen[ side::left ] = false;
IsAnyDoorPermitActive[ side::right ] = IsAnyDoorPermitActive[ side::left ] = false;
ConsistShade = 0.0; ConsistShade = 0.0;
TDynamicObject *p = pVehicles[0]; // pojazd na czole składu TDynamicObject *p = pVehicles[0]; // pojazd na czole składu
while (p) while (p)
@@ -4777,12 +4790,11 @@ TController::UpdateSituation(double dt) {
|| ( vehicle->Couplers[ end::rear ].stretch_duration > 0.0 ); || ( vehicle->Couplers[ end::rear ].stretch_duration > 0.0 );
// check door state // check door state
auto const switchsides { p->DirectionGet() != iDirection }; auto const switchsides { p->DirectionGet() != iDirection };
IsAnyDoorOpen[ side::right ] = IsAnyDoorOpen[ side::right ] |= ( false == vehicle->Doors.instances[ ( switchsides ? side::left : side::right ) ].is_closed );
IsAnyDoorOpen[ side::right ] IsAnyDoorOpen[ side::left ] |= ( false == vehicle->Doors.instances[ ( switchsides ? side::right : side::left ) ].is_closed );
|| ( false == vehicle->Doors.instances[ ( switchsides ? side::left : side::right ) ].is_closed ); IsAnyDoorPermitActive[ side::right ] |= ( vehicle->Doors.permit_needed && vehicle->Doors.instances[ ( switchsides ? side::left : side::right ) ].open_permit );
IsAnyDoorOpen[ side::left ] = IsAnyDoorPermitActive[ side::left ] |= ( vehicle->Doors.permit_needed && vehicle->Doors.instances[ ( switchsides ? side::right : side::left ) ].open_permit );
IsAnyDoorOpen[ side::left ]
|| ( false == vehicle->Doors.instances[ ( switchsides ? side::right : side::left ) ].is_closed );
// measure lighting level // measure lighting level
// TBD: apply weight (multiplier) to partially lit vehicles? // TBD: apply weight (multiplier) to partially lit vehicles?
ConsistShade += ( p->fShade > 0.0 ? p->fShade : 1.0 ); ConsistShade += ( p->fShade > 0.0 ? p->fShade : 1.0 );
@@ -6012,14 +6024,13 @@ TController::UpdateSituation(double dt) {
fActionTime = -5.0; // niech trochę potrzyma fActionTime = -5.0; // niech trochę potrzyma
} }
else { else {
// if (iGuardRadio==iRadioChannel) //zgodność kanału // radio message
// if (!FreeFlyModeFlag) //obserwator musi być w środku pojazdu
// (albo może mieć radio przenośne) - kierownik mógłby powtarzać przy braku reakcji
// TODO: proper system for sending/receiving radio messages
// place the sound in appropriate cab of the manned vehicle
tsGuardSignal.owner( pVehicle ); tsGuardSignal.owner( pVehicle );
/*
tsGuardSignal.offset( { 0.f, 2.f, pVehicle->MoverParameters->Dim.L * 0.4f * ( pVehicle->MoverParameters->CabOccupied < 0 ? -1 : 1 ) } ); tsGuardSignal.offset( { 0.f, 2.f, pVehicle->MoverParameters->Dim.L * 0.4f * ( pVehicle->MoverParameters->CabOccupied < 0 ? -1 : 1 ) } );
tsGuardSignal.play( sound_flags::exclusive ); tsGuardSignal.play( sound_flags::exclusive );
*/
simulation::radio_message( &tsGuardSignal, iGuardRadio );
// NOTE: we can't rely on is_playing() check as sound playback is based on distance from local camera // NOTE: we can't rely on is_playing() check as sound playback is based on distance from local camera
fActionTime = -5.0; // niech trochę potrzyma fActionTime = -5.0; // niech trochę potrzyma
} }

View File

@@ -465,6 +465,7 @@ private:
void Doors( bool const Open, int const Side = 0 ); void Doors( bool const Open, int const Side = 0 );
// returns true if any vehicle in the consist has an open door // returns true if any vehicle in the consist has an open door
bool doors_open() const; bool doors_open() const;
bool doors_permit_active() const;
void AutoRewident(); // ustawia hamulce w składzie void AutoRewident(); // ustawia hamulce w składzie
void UpdatePantographs(); void UpdatePantographs();
// members // members
@@ -482,6 +483,7 @@ private:
double ConsistShade{ 1.0 }; // averaged amount of sunlight received by the consist double ConsistShade{ 1.0 }; // averaged amount of sunlight received by the consist
TDynamicObject *pVehicles[ 2 ]; // skrajne pojazdy w składzie (niekoniecznie bezpośrednio sterowane) TDynamicObject *pVehicles[ 2 ]; // skrajne pojazdy w składzie (niekoniecznie bezpośrednio sterowane)
bool IsAnyDoorOpen[ 2 ]; // state of door in the consist bool IsAnyDoorOpen[ 2 ]; // state of door in the consist
bool IsAnyDoorPermitActive[ 2 ]; // state of door permit in the consist
bool IsAnyLineBreakerOpen{ false }; // state of line breaker in all powered vehicles under control bool IsAnyLineBreakerOpen{ false }; // state of line breaker in all powered vehicles under control
bool IsAnyConverterOverloadRelayOpen{ false }; // state of converter overload relays in all vehicles under control bool IsAnyConverterOverloadRelayOpen{ false }; // state of converter overload relays in all vehicles under control
bool IsAnyMotorOverloadRelayOpen{ false }; // state of motor overload relays in all vehicles under control bool IsAnyMotorOverloadRelayOpen{ false }; // state of motor overload relays in all vehicles under control

View File

@@ -4096,6 +4096,15 @@ void TDynamicObject::RenderSounds() {
if( MoverParameters->CompressorSpeed > 0.0 ) { if( MoverParameters->CompressorSpeed > 0.0 ) {
// McZapkie! - dzwiek compressor.wav tylko gdy dziala sprezarka // McZapkie! - dzwiek compressor.wav tylko gdy dziala sprezarka
if( MoverParameters->CompressorFlag ) { if( MoverParameters->CompressorFlag ) {
if( MoverParameters->CompressorPower == 3 ) {
// presume the compressor sound is recorded for idle revolutions
// increase the pitch according to increase of engine revolutions
auto const enginefactor { ( MoverParameters->EngineMaxRPM() / MoverParameters->EngineIdleRPM() ) * MoverParameters->EngineRPMRatio() };
sCompressor.pitch(
clamp( // try to keep the sound pitch in semi-reasonable range
enginefactor,
0.5, 2.5 ) );
}
sCompressor.play( sound_flags::exclusive | sound_flags::looping ); sCompressor.play( sound_flags::exclusive | sound_flags::looping );
} }
else { else {
@@ -7269,7 +7278,7 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub
engine.m_amplitudeoffset engine.m_amplitudeoffset
+ engine.m_amplitudefactor * ( + engine.m_amplitudefactor * (
0.25 * ( Vehicle.EnginePower / Vehicle.Power ) 0.25 * ( Vehicle.EnginePower / Vehicle.Power )
+ 0.75 * ( Vehicle.enrot * 60 ) / ( Vehicle.DElist[ Vehicle.MainCtrlPosNo ].RPM ) ); + 0.75 * Vehicle.EngineRPMRatio() );
break; break;
} }
case TEngineType::DieselEngine: { case TEngineType::DieselEngine: {
@@ -7299,11 +7308,7 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub
// calculate potential recent increase of engine revolutions // calculate potential recent increase of engine revolutions
auto const revolutionsperminute { Vehicle.enrot * 60 }; auto const revolutionsperminute { Vehicle.enrot * 60 };
auto const revolutionsdifference { revolutionsperminute - engine_revs_last }; auto const revolutionsdifference { revolutionsperminute - engine_revs_last };
auto const idlerevolutionsthreshold { 1.01 * ( auto const idlerevolutionsthreshold { 1.01 * Vehicle.EngineIdleRPM() };
Vehicle.EngineType == TEngineType::DieselElectric ?
Vehicle.DElist[ 0 ].RPM :
Vehicle.dizel_nmin * 60 ) };
engine_revs_change = std::max( 0.0, engine_revs_change - 2.5 * Deltatime ); engine_revs_change = std::max( 0.0, engine_revs_change - 2.5 * Deltatime );
if( ( revolutionsperminute > idlerevolutionsthreshold ) if( ( revolutionsperminute > idlerevolutionsthreshold )
&& ( revolutionsdifference > 1.0 * Deltatime ) ) { && ( revolutionsdifference > 1.0 * Deltatime ) ) {

View File

@@ -656,10 +656,11 @@ global_settings::ConfigParse(cParser &Parser) {
Parser >> token; Parser >> token;
auto const priority { token }; auto const priority { token };
PythonScreenUpdateRate = ( PythonScreenUpdateRate = (
priority == "normal" ? 200 :
priority == "lower" ? 500 : priority == "lower" ? 500 :
priority == "lowest" ? 1000 : priority == "lowest" ? 1000 :
priority == "off" ? 0 : priority == "off" ? 0 :
200 ); stol_def( priority, 200 ) );
} }
else if( token == "python.updatetime" ) else if( token == "python.updatetime" )
{ {
@@ -954,4 +955,246 @@ global_settings::ConfigParse(cParser &Parser) {
#ifdef _WIN32 #ifdef _WIN32
Console::ModeSet(iFeedbackMode, iFeedbackPort); // tryb pracy konsoli sterowniczej Console::ModeSet(iFeedbackMode, iFeedbackPort); // tryb pracy konsoli sterowniczej
#endif #endif
} }
void
global_settings::export_as_text( std::ostream &Output ) const {
export_as_text( Output, "sceneryfile", SceneryFile );
export_as_text( Output, "humanctrlvehicle", local_start_vehicle );
export_as_text( Output, "fieldofview", FieldOfView );
export_as_text( Output, "width", iWindowWidth );
export_as_text( Output, "height", iWindowHeight );
export_as_text( Output, "heightbase", fDistanceFactor );
export_as_text( Output, "targetfps", targetfps );
export_as_text( Output, "basedrawrange", BaseDrawRange );
export_as_text( Output, "fullscreen", bFullScreen );
export_as_text( Output, "fullscreenmonitor", fullscreen_monitor );
export_as_text( Output, "vsync", VSync );
// NOTE: values are changed dynamically during simulation. cache initial settings and export instead
if( FreeFlyModeFlag ) {
Output
<< "freefly yes "
<< FreeCameraInit[ 0 ].x << " "
<< FreeCameraInit[ 0 ].y << " "
<< FreeCameraInit[ 0 ].z << "\n";
}
else {
export_as_text( Output, "freefly", FreeFlyModeFlag );
}
export_as_text( Output, "wireframe", bWireFrame );
export_as_text( Output, "debugmode", DebugModeFlag );
export_as_text( Output, "soundenabled", bSoundEnabled );
export_as_text( Output, "sound.openal.renderer", AudioRenderer );
export_as_text( Output, "sound.volume", AudioVolume );
export_as_text( Output, "sound.volume.radio", RadioVolume );
export_as_text( Output, "physicslog", WriteLogFlag );
export_as_text( Output, "fullphysics", FullPhysics );
export_as_text( Output, "debuglog", iWriteLogEnabled );
export_as_text( Output, "multiplelogs", MultipleLogs );
export_as_text( Output, "logs.filter", DisabledLogTypes );
Output
<< "mousescale "
<< fMouseXScale << " "
<< fMouseYScale << "\n";
export_as_text( Output, "mousecontrol", InputMouse );
export_as_text( Output, "enabletraction", bEnableTraction );
export_as_text( Output, "loadtraction", bLoadTraction );
export_as_text( Output, "friction", fFriction );
export_as_text( Output, "livetraction", bLiveTraction );
export_as_text( Output, "skyenabled", asSky );
export_as_text( Output, "defaultext", szDefaultExt );
export_as_text( Output, "newaircouplers", bnewAirCouplers );
export_as_text( Output, "anisotropicfiltering", AnisotropicFiltering );
export_as_text( Output, "usevbo", bUseVBO );
export_as_text( Output, "feedbackmode", iFeedbackMode );
export_as_text( Output, "feedbackport", iFeedbackPort );
export_as_text( Output, "multiplayer", iMultiplayer );
export_as_text( Output, "maxtexturesize", iMaxTextureSize );
export_as_text( Output, "maxcabtexturesize", iMaxCabTextureSize );
export_as_text( Output, "movelight", fMoveLight );
export_as_text( Output, "dynamiclights", DynamicLightCount );
if( std::isnormal( ScenarioTimeOverride ) ) {
export_as_text( Output, "scenario.time.override", ScenarioTimeOverride );
}
export_as_text( Output, "scenario.time.offset", ScenarioTimeOffset );
export_as_text( Output, "scenario.time.current", ScenarioTimeCurrent );
export_as_text( Output, "scenario.weather.temperature", AirTemperature );
export_as_text( Output, "scalespeculars", ScaleSpecularValues );
export_as_text( Output, "gfxrenderer", GfxRenderer );
export_as_text( Output, "shadows", RenderShadows );
Output
<< "shadowtune "
<< shadowtune.map_size << " "
<< 0 << " "
<< shadowtune.range << " "
<< 0 << "\n";
export_as_text( Output, "gfx.shadows.cab.range", RenderCabShadowsRange );
export_as_text( Output, "gfx.smoke", Smoke );
export_as_text( Output, "gfx.smoke.fidelity", SmokeFidelity );
export_as_text( Output, "smoothtraction", bSmoothTraction );
export_as_text( Output, "splinefidelity", SplineFidelity );
export_as_text( Output, "rendercab", render_cab );
export_as_text( Output, "createswitchtrackbeds", CreateSwitchTrackbeds );
export_as_text( Output, "gfx.resource.sweep", ResourceSweep );
export_as_text( Output, "gfx.resource.move", ResourceMove );
export_as_text( Output, "gfx.reflections.framerate", 1.0 / ReflectionUpdateInterval );
export_as_text( Output, "timespeed", fTimeSpeed );
export_as_text( Output, "multisampling", iMultisampling );
export_as_text( Output, "latitude", fLatitudeDeg );
export_as_text( Output, "convertmodels", iConvertModels + ( iConvertModels > 0 ? 128 : 0 ) );
export_as_text( Output, "file.binary.terrain", file_binary_terrain );
export_as_text( Output, "inactivepause", bInactivePause );
export_as_text( Output, "slowmotion", iSlowMotionMask );
export_as_text( Output, "hideconsole", bHideConsole );
export_as_text( Output, "rollfix", bRollFix );
export_as_text( Output, "fpsaverage", fFpsAverage );
export_as_text( Output, "fpsdeviation", fFpsDeviation );
for( auto idx = 0; idx < 6; ++idx ) {
Output
<< "calibrate5din "
<< idx << " "
<< fCalibrateIn[ idx ][ 0 ] << " "
<< fCalibrateIn[ idx ][ 1 ] << " "
<< fCalibrateIn[ idx ][ 2 ] << " "
<< fCalibrateIn[ idx ][ 3 ] << " "
<< fCalibrateIn[ idx ][ 4 ] << " "
<< fCalibrateIn[ idx ][ 5 ] << "\n";
}
for( auto idx = 0; idx < 6; ++idx ) {
Output
<< "calibrate5dout "
<< idx << " "
<< fCalibrateOut[ idx ][ 0 ] << " "
<< fCalibrateOut[ idx ][ 1 ] << " "
<< fCalibrateOut[ idx ][ 2 ] << " "
<< fCalibrateOut[ idx ][ 3 ] << " "
<< fCalibrateOut[ idx ][ 4 ] << " "
<< fCalibrateOut[ idx ][ 5 ] << "\n";
}
Output
<< "calibrateoutmaxvalues "
<< fCalibrateOutMax[ 0 ] << " "
<< fCalibrateOutMax[ 1 ] << " "
<< fCalibrateOutMax[ 2 ] << " "
<< fCalibrateOutMax[ 3 ] << " "
<< fCalibrateOutMax[ 4 ] << " "
<< fCalibrateOutMax[ 5 ] << " "
<< fCalibrateOutMax[ 6 ] << "\n";
export_as_text( Output, "calibrateoutdebuginfo", iCalibrateOutDebugInfo );
for( auto idx = 0; idx < 7; ++idx ) {
Output
<< "pwm "
<< idx << " "
<< iPoKeysPWM[ idx ] << "\n";
}
export_as_text( Output, "brakestep", fBrakeStep );
export_as_text( Output, "joinduplicatedevents", bJoinEvents );
export_as_text( Output, "hiddenevents", iHiddenEvents );
export_as_text( Output, "pause", ( iPause & 1 ) != 0 );
export_as_text( Output, "lang", asLang );
export_as_text( Output, "python.updatetime", PythonScreenUpdateRate );
Output
<< "uitextcolor "
<< UITextColor.r * 255 << " "
<< UITextColor.g * 255 << " "
<< UITextColor.b * 255 << "\n";
export_as_text( Output, "ui.bg.opacity", UIBgOpacity );
export_as_text( Output, "input.gamepad", InputGamepad );
#ifdef WITH_UART
if( uart_conf.enable ) {
Output
<< "uart "
<< uart_conf.port << " "
<< uart_conf.baud << " "
<< uart_conf.updatetime << "\n";
}
Output
<< "uarttune "
<< uart_conf.mainbrakemin << " "
<< uart_conf.mainbrakemax << " "
<< uart_conf.localbrakemin << " "
<< uart_conf.localbrakemax << " "
<< uart_conf.tankmax << " "
<< uart_conf.tankuart << " "
<< uart_conf.pipemax << " "
<< uart_conf.pipeuart << " "
<< uart_conf.brakemax << " "
<< uart_conf.brakeuart << " "
<< uart_conf.hvmax << " "
<< uart_conf.hvuart << " "
<< uart_conf.currentmax << " "
<< uart_conf.currentuart << " "
<< uart_conf.lvmax << " "
<< uart_conf.lvuart << "\n";
export_as_text( Output, "uarttachoscale", uart_conf.tachoscale );
Output
<< "uartfeature "
<< uart_conf.mainenable << " "
<< uart_conf.scndenable << " "
<< uart_conf.trainenable << " "
<< uart_conf.localenable << "\n";
export_as_text( Output, "uartdebug", uart_conf.debug );
#endif
#ifdef USE_EXTCAM_CAMERA
export_as_text( Output, "extcam.cmd", extcam_cmd );
export_as_text( Output, "extcam.rec", extcam_rec );
Output
<< "extcam.res "
<< extcam_res.x << " "
<< extcam_res.y << "\n";
#endif
export_as_text( Output, "compresstex", compress_tex );
export_as_text( Output, "gfx.framebuffer.width", gfx_framebuffer_width );
export_as_text( Output, "gfx.framebuffer.height", gfx_framebuffer_height );
export_as_text( Output, "gfx.framebuffer.fidelity", gfx_framebuffer_fidelity );
export_as_text( Output, "gfx.shadowmap.enabled", gfx_shadowmap_enabled );
// TODO: export fpslimit
export_as_text( Output, "randomseed", Global.random_seed );
export_as_text( Output, "gfx.envmap.enabled", gfx_envmap_enabled );
export_as_text( Output, "gfx.postfx.motionblur.enabled", gfx_postfx_motionblur_enabled );
export_as_text( Output, "gfx.postfx.motionblur.shutter", gfx_postfx_motionblur_shutter );
// TODO: export gfx_postfx_motionblur_format
export_as_text( Output, "gfx.postfx.chromaticaberration.enabled", gfx_postfx_chromaticaberration_enabled );
// TODO: export gfx_format_color
// TODO: export gfx_format_depth
export_as_text( Output, "gfx.skiprendering", gfx_skiprendering );
export_as_text( Output, "gfx.skippipeline", gfx_skippipeline );
export_as_text( Output, "gfx.extraeffects", gfx_extraeffects );
export_as_text( Output, "python.enabled", python_enabled );
export_as_text( Output, "python.threadedupload", python_threadedupload );
export_as_text( Output, "python.uploadmain", python_uploadmain );
export_as_text( Output, "python.mipmaps", python_mipmaps );
for( auto const &server : network_servers ) {
Output
<< "network.server "
<< server.first << " " << server.second << "\n";
}
if( false == network_client->first.empty() ) {
Output
<< "network.client "
<< network_client->first << " " << network_client->second << "\n";
}
export_as_text( Output, "execonexit", exec_on_exit );
}
template <>
void
global_settings::export_as_text( std::ostream &Output, std::string const Key, std::string const &Value ) const {
if( Value.empty() ) { return; }
if( Value.find( ' ' ) != std::string::npos ) {
Output << Key << " \"" << Value << "\"\n";
}
else {
Output << Key << " " << Value << "\n";
}
}
template <>
void
global_settings::export_as_text( std::ostream &Output, std::string const Key, bool const &Value ) const {
Output << Key << " " << ( Value ? "yes" : "no" ) << "\n";
}

View File

@@ -28,11 +28,11 @@ struct global_settings {
bool shiftState{ false }; //m7todo: brzydko bool shiftState{ false }; //m7todo: brzydko
bool ctrlState{ false }; bool ctrlState{ false };
bool altState{ false }; bool altState{ false };
std::mt19937 random_engine; std::mt19937 random_engine;
std::mt19937 local_random_engine; std::mt19937 local_random_engine;
bool ready_to_load { false }; bool ready_to_load{ false };
std::time_t starting_timestamp = 0; // starting time, in local timezone std::time_t starting_timestamp = 0; // starting time, in local timezone
uint32_t random_seed = 0; uint32_t random_seed = 0;
TCamera pCamera; // parametry kamery TCamera pCamera; // parametry kamery
TCamera pDebugCamera; TCamera pDebugCamera;
std::array<Math3D::vector3, 10> FreeCameraInit; // pozycje kamery std::array<Math3D::vector3, 10> FreeCameraInit; // pozycje kamery
@@ -56,12 +56,12 @@ struct global_settings {
std::string asCurrentTexturePath{ szTexturePath }; std::string asCurrentTexturePath{ szTexturePath };
std::string asCurrentDynamicPath; std::string asCurrentDynamicPath;
int CurrentMaxTextureSize{ 4096 }; int CurrentMaxTextureSize{ 4096 };
bool GfxFramebufferSRGB { true }; bool GfxFramebufferSRGB{ true };
bool UpdateMaterials { true }; bool UpdateMaterials{ true };
// settings // settings
// filesystem // filesystem
bool bLoadTraction{ true }; bool bLoadTraction{ true };
bool CreateSwitchTrackbeds { true }; bool CreateSwitchTrackbeds{ true };
std::string szTexturesTGA{ ".tga" }; // lista tekstur od TGA std::string szTexturesTGA{ ".tga" }; // lista tekstur od TGA
std::string szTexturesDDS{ ".dds" }; // lista tekstur od DDS std::string szTexturesDDS{ ".dds" }; // lista tekstur od DDS
std::string szDefaultExt{ szTexturesDDS }; std::string szDefaultExt{ szTexturesDDS };
@@ -77,7 +77,7 @@ struct global_settings {
bool RealisticControlMode{ false }; // controls ability to steer the vehicle from outside views bool RealisticControlMode{ false }; // controls ability to steer the vehicle from outside views
bool bEnableTraction{ true }; bool bEnableTraction{ true };
float fFriction{ 1.f }; // mnożnik tarcia - KURS90 float fFriction{ 1.f }; // mnożnik tarcia - KURS90
float FrictionWeatherFactor { 1.f }; float FrictionWeatherFactor{ 1.f };
bool bLiveTraction{ true }; bool bLiveTraction{ true };
float Overcast{ 0.1f }; // NOTE: all this weather stuff should be moved elsewhere float Overcast{ 0.1f }; // NOTE: all this weather stuff should be moved elsewhere
glm::vec3 FogColor = { 0.6f, 0.7f, 0.8f }; glm::vec3 FogColor = { 0.6f, 0.7f, 0.8f };
@@ -91,9 +91,9 @@ struct global_settings {
bool FakeLight{ false }; // toggle between fixed and dynamic daylight bool FakeLight{ false }; // toggle between fixed and dynamic daylight
double fTimeSpeed{ 1.0 }; // przyspieszenie czasu, zmienna do testów double fTimeSpeed{ 1.0 }; // przyspieszenie czasu, zmienna do testów
double fLatitudeDeg{ 52.0 }; // szerokość geograficzna double fLatitudeDeg{ 52.0 }; // szerokość geograficzna
float ScenarioTimeOverride { std::numeric_limits<float>::quiet_NaN() }; // requested scenario start time float ScenarioTimeOverride{ std::numeric_limits<float>::quiet_NaN() }; // requested scenario start time
float ScenarioTimeOffset { 0.f }; // time shift (in hours) applied to train timetables float ScenarioTimeOffset{ 0.f }; // time shift (in hours) applied to train timetables
bool ScenarioTimeCurrent { false }; // automatic time shift to match scenario time with local clock bool ScenarioTimeCurrent{ false }; // automatic time shift to match scenario time with local clock
bool bInactivePause{ true }; // automatyczna pauza, gdy okno nieaktywne bool bInactivePause{ true }; // automatyczna pauza, gdy okno nieaktywne
int iSlowMotionMask{ -1 }; // maska wyłączanych właściwości int iSlowMotionMask{ -1 }; // maska wyłączanych właściwości
bool bHideConsole{ false }; // hunter-271211: ukrywanie konsoli bool bHideConsole{ false }; // hunter-271211: ukrywanie konsoli
@@ -101,16 +101,16 @@ struct global_settings {
bool bJoinEvents{ false }; // czy grupować eventy o tych samych nazwach bool bJoinEvents{ false }; // czy grupować eventy o tych samych nazwach
int iHiddenEvents{ 1 }; // czy łączyć eventy z torami poprzez nazwę toru int iHiddenEvents{ 1 }; // czy łączyć eventy z torami poprzez nazwę toru
// ui // ui
int PythonScreenUpdateRate { 200 }; // delay between python-based screen updates, in milliseconds int PythonScreenUpdateRate{ 200 }; // delay between python-based screen updates, in milliseconds
int iTextMode{ 0 }; // tryb pracy wyświetlacza tekstowego int iTextMode{ 0 }; // tryb pracy wyświetlacza tekstowego
glm::vec4 UITextColor { glm::vec4( 225.f / 255.f, 225.f / 255.f, 225.f / 255.f, 1.f ) }; // base color of UI text glm::vec4 UITextColor{ glm::vec4( 225.f / 255.f, 225.f / 255.f, 225.f / 255.f, 1.f ) }; // base color of UI text
float UIBgOpacity { 0.65f }; // opacity of ui windows float UIBgOpacity{ 0.65f }; // opacity of ui windows
std::string asLang{ "pl" }; // domyślny język - http://tools.ietf.org/html/bcp47 std::string asLang{ "pl" }; // domyślny język - http://tools.ietf.org/html/bcp47
// gfx // gfx
int iWindowWidth{ 800 }; int iWindowWidth{ 800 };
int iWindowHeight{ 600 }; int iWindowHeight{ 600 };
float fDistanceFactor{ 1.f }; // baza do przeliczania odległości dla LoD float fDistanceFactor{ 1.f }; // baza do przeliczania odległości dla LoD
float targetfps { 0.0f }; float targetfps{ 0.0f };
bool bFullScreen{ false }; bool bFullScreen{ false };
bool VSync{ false }; bool VSync{ false };
bool bWireFrame{ false }; bool bWireFrame{ false };
@@ -179,7 +179,7 @@ struct global_settings {
// wartości maksymalne wyjść dla pulpitu // wartości maksymalne wyjść dla pulpitu
double fCalibrateOutMax[ 7 ] = { double fCalibrateOutMax[ 7 ] = {
0, 0, 0, 0, 0, 0, 0 }; 0, 0, 0, 0, 0, 0, 0 };
int iCalibrateOutDebugInfo { -1 }; // numer wyjścia kalibrowanego dla którego wyświetlać informacje podczas kalibracji int iCalibrateOutDebugInfo{ -1 }; // numer wyjścia kalibrowanego dla którego wyświetlać informacje podczas kalibracji
int iPoKeysPWM[ 7 ] = { 0, 1, 2, 3, 4, 5, 6 }; // numery wejść dla PWM int iPoKeysPWM[ 7 ] = { 0, 1, 2, 3, 4, 5, 6 }; // numery wejść dla PWM
#ifdef WITH_UART #ifdef WITH_UART
uart_input::conf_t uart_conf; uart_input::conf_t uart_conf;
@@ -192,14 +192,14 @@ struct global_settings {
// TODO: move these to relevant areas // TODO: move these to relevant areas
bool render_cab = true; bool render_cab = true;
std::chrono::duration<float> minframetime {0.0f}; std::chrono::duration<float> minframetime{ 0.0f };
std::string fullscreen_monitor; std::string fullscreen_monitor;
bool python_enabled = true; bool python_enabled = true;
bool python_mipmaps = true; bool python_mipmaps = true;
bool python_threadedupload = true; bool python_threadedupload = true;
bool python_uploadmain = true; bool python_uploadmain = true;
bool gfx_skiprendering = false; bool gfx_skiprendering = false;
int gfx_framebuffer_width = -1; int gfx_framebuffer_width = -1;
@@ -227,8 +227,29 @@ struct global_settings {
// methods // methods
void LoadIniFile( std::string asFileName ); void LoadIniFile( std::string asFileName );
void ConfigParse( cParser &parser ); void ConfigParse( cParser &parser );
// sends basic content of the class in legacy (text) format to provided stream
void
export_as_text( std::ostream &Output ) const;
template <typename Type_>
void
export_as_text( std::ostream &Output, std::string const Key, Type_ const &Value ) const;
}; };
template <typename Type_>
void
global_settings::export_as_text( std::ostream &Output, std::string const Key, Type_ const &Value ) const {
Output << Key << " " << Value << "\n";
}
template <>
void
global_settings::export_as_text( std::ostream &Output, std::string const Key, std::string const &Value ) const;
template <>
void
global_settings::export_as_text( std::ostream &Output, std::string const Key, bool const &Value ) const;
extern global_settings Global; extern global_settings Global;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -1647,6 +1647,9 @@ public:
double PipeRatio(void);/*ile napelniac*/ double PipeRatio(void);/*ile napelniac*/
double RealPipeRatio(void);/*jak szybko*/ double RealPipeRatio(void);/*jak szybko*/
double BrakeVP(void) const; double BrakeVP(void) const;
double EngineRPMRatio() const; // returns current engine revolutions as percentage of max engine revolutions, in range 0-1
double EngineIdleRPM() const;
double EngineMaxRPM() const;
/*! przesylanie komend sterujacych*/ /*! przesylanie komend sterujacych*/
bool SendCtrlToNext(std::string const CtrlCommand, double const ctrlvalue, double const dir, int const Couplertype = coupling::control ); bool SendCtrlToNext(std::string const CtrlCommand, double const ctrlvalue, double const dir, int const Couplertype = coupling::control );

View File

@@ -1000,6 +1000,34 @@ double TMoverParameters::PipeRatio(void)
return pr; return pr;
} }
double
TMoverParameters::EngineRPMRatio() const {
return clamp( (
EngineType == TEngineType::DieselElectric ? ( ( 60.0 * std::abs( enrot ) ) / DElist[ MainCtrlPosNo ].RPM ) :
EngineType == TEngineType::DieselEngine ? ( std::abs( enrot ) / nmax ) :
1.0 ), // shouldn't ever get here but, eh
0.0, 1.0 );
}
double
TMoverParameters::EngineIdleRPM() const {
return (
EngineType == TEngineType::DieselEngine ? dizel_nmin * 60 :
EngineType == TEngineType::DieselElectric ? DElist[ MainCtrlNoPowerPos() ].RPM :
std::numeric_limits<double>::max() ); // shouldn't ever get here but, eh
}
double
TMoverParameters::EngineMaxRPM() const {
return (
EngineType == TEngineType::DieselEngine ? dizel_nmax * 60 :
EngineType == TEngineType::DieselElectric ? DElist[ MainCtrlPosNo ].RPM :
std::numeric_limits<double>::max() ); // shouldn't ever get here but, eh
}
// ************************************************************************************************* // *************************************************************************************************
// Q: 20160716 // Q: 20160716
// Wykrywanie kolizji // Wykrywanie kolizji
@@ -1959,17 +1987,13 @@ void TMoverParameters::OilPumpCheck( double const Timestep ) {
OilPump.start_type == start_t::manualwithautofallback ? ( OilPump.is_enabled || dizel_startup ) : OilPump.start_type == start_t::manualwithautofallback ? ( OilPump.is_enabled || dizel_startup ) :
false ) ) ); // shouldn't ever get this far but, eh false ) ) ); // shouldn't ever get this far but, eh
auto const maxrevolutions {
EngineType == TEngineType::DieselEngine ?
dizel_nmax :
DElist[ MainCtrlPosNo ].RPM / 60.0 };
auto const minpressure { auto const minpressure {
OilPump.pressure_minimum > 0.f ? OilPump.pressure_minimum > 0.f ?
OilPump.pressure_minimum : OilPump.pressure_minimum :
0.15f }; // arbitrary fallback value 0.15f }; // arbitrary fallback value
OilPump.pressure_target = ( OilPump.pressure_target = (
enrot > 0.1 ? interpolate( minpressure, OilPump.pressure_maximum, static_cast<float>( clamp( enrot / maxrevolutions, 0.0, 1.0 ) ) ) * OilPump.resource_amount : enrot > 0.1 ? interpolate( minpressure, OilPump.pressure_maximum, static_cast<float>( EngineRPMRatio() ) ) * OilPump.resource_amount :
true == OilPump.is_active ? std::min( minpressure + 0.1f, OilPump.pressure_maximum ) : // slight pressure margin to give time to switch off the pump and start the engine true == OilPump.is_active ? std::min( minpressure + 0.1f, OilPump.pressure_maximum ) : // slight pressure margin to give time to switch off the pump and start the engine
0.f ); 0.f );
@@ -4128,14 +4152,10 @@ void TMoverParameters::CompressorCheck(double dt) {
switch( CompressorPower ) { switch( CompressorPower ) {
case 3: { case 3: {
// the compressor is coupled with the diesel engine, engine revolutions affect the output // the compressor is coupled with the diesel engine, engine revolutions affect the output
auto const enginefactor { (
EngineType == TEngineType::DieselElectric ? ( ( 60.0 * std::abs( enrot ) ) / DElist[ MainCtrlPosNo ].RPM ) :
EngineType == TEngineType::DieselEngine ? ( std::abs( enrot ) / nmax ) :
1.0 ) }; // shouldn't ever get here but, eh
CompressedVolume += CompressedVolume +=
CompressorSpeedF CompressorSpeedF
* ( 2.0 * MaxCompressorF - Compressor ) / MaxCompressorF * ( 2.0 * MaxCompressorF - Compressor ) / MaxCompressorF
* enginefactor * EngineRPMRatio()
* dt * dt
* ( CompressorGovernorLock ? 0.0 : 1.0 ); // with the lock active air is vented out * ( CompressorGovernorLock ? 0.0 : 1.0 ); // with the lock active air is vented out
break; break;
@@ -5217,7 +5237,7 @@ double TMoverParameters::TractionForce( double dt ) {
std::max( std::max(
tmp, tmp,
std::min( std::min(
DElist[ MainCtrlPosNo ].RPM, EngineMaxRPM(),
EngineHeatingRPM ) EngineHeatingRPM )
/ 60.0 ); / 60.0 );
} }
@@ -5576,7 +5596,7 @@ double TMoverParameters::TractionForce( double dt ) {
if (EIMCtrlType > 0) //sterowanie cyfrowe if (EIMCtrlType > 0) //sterowanie cyfrowe
{ {
auto eimic_positive = std::max(0.0, eimic_real); auto eimic_positive = std::max(0.0, eimic_real);
auto const rpmratio {60.0 * enrot / DElist[MainCtrlPosNo].RPM}; auto const rpmratio { EngineRPMRatio() };
tempImax = DElist[MainCtrlPosNo].Imax * eimic_positive; tempImax = DElist[MainCtrlPosNo].Imax * eimic_positive;
tempUmax = DElist[MainCtrlPosNo].Umax * std::min(eimic_positive, rpmratio); tempUmax = DElist[MainCtrlPosNo].Umax * std::min(eimic_positive, rpmratio);
tempPmax = DElist[MainCtrlPosNo].GenPower * std::min(eimic_positive, rpmratio); tempPmax = DElist[MainCtrlPosNo].GenPower * std::min(eimic_positive, rpmratio);
@@ -5611,8 +5631,7 @@ double TMoverParameters::TractionForce( double dt ) {
EngineVoltage = ( SST[ MainCtrlPos ].Umax * AnPos ) + ( SST[ MainCtrlPos ].Umin * ( 1.0 - AnPos ) ); EngineVoltage = ( SST[ MainCtrlPos ].Umax * AnPos ) + ( SST[ MainCtrlPos ].Umin * ( 1.0 - AnPos ) );
// NOTE: very crude way to approximate power generated at current rpm instead of instant top output // NOTE: very crude way to approximate power generated at current rpm instead of instant top output
// NOTE, TODO: doesn't take into account potentially increased revolutions if heating is on, fix it // NOTE, TODO: doesn't take into account potentially increased revolutions if heating is on, fix it
auto const rpmratio { 60.0 * enrot / DElist[ MainCtrlPos ].RPM }; tmp = EngineRPMRatio() * ( SST[ MainCtrlPos ].Pmax * AnPos ) + ( SST[ MainCtrlPos ].Pmin * ( 1.0 - AnPos ) );
tmp = rpmratio * ( SST[ MainCtrlPos ].Pmax * AnPos ) + ( SST[ MainCtrlPos ].Pmin * ( 1.0 - AnPos ) );
Ft = tmp * 1000.0 / ( abs( tmpV ) + 1.6 ); Ft = tmp * 1000.0 / ( abs( tmpV ) + 1.6 );
} }
else { else {
@@ -6203,8 +6222,7 @@ double TMoverParameters::TractionForce( double dt ) {
switch( EngineType ) { switch( EngineType ) {
case TEngineType::DieselElectric: { case TEngineType::DieselElectric: {
// rough approximation of extra effort to overcome friction etc // rough approximation of extra effort to overcome friction etc
auto const rpmratio{ 60.0 * enrot / DElist[ MainCtrlPosNo ].RPM }; EnginePower += EngineRPMRatio() * 0.15 * DElist[ MainCtrlPosNo ].GenPower;
EnginePower += rpmratio * 0.15 * DElist[ MainCtrlPosNo ].GenPower;
break; break;
} }
default: { default: {
@@ -7780,11 +7798,7 @@ void TMoverParameters::dizel_Heat( double const dt ) {
auto const engineoff { ( Mains ? 0 : 1 ) }; auto const engineoff { ( Mains ? 0 : 1 ) };
auto const rpm { enrot * 60 }; auto const rpm { enrot * 60 };
// TODO: calculate this once and cache for further use, instead of doing it repeatedly all over the place // TODO: calculate this once and cache for further use, instead of doing it repeatedly all over the place
auto const maxrevolutions { ( auto const revolutionsfactor { EngineRPMRatio() };
EngineType == TEngineType::DieselEngine ? dizel_nmax * 60 :
EngineType == TEngineType::DieselElectric ? DElist[ MainCtrlPosNo ].RPM :
std::numeric_limits<double>::max() ) }; // shouldn't ever get here but, eh
auto const revolutionsfactor { clamp( rpm / maxrevolutions, 0.0, 1.0 ) };
auto const waterpump { WaterPump.is_active ? 1 : 0 }; auto const waterpump { WaterPump.is_active ? 1 : 0 };
auto const gw = engineon * interpolate( gwmin, gwmax, revolutionsfactor ) + waterpump * 1000 + engineoff * 200; auto const gw = engineon * interpolate( gwmin, gwmax, revolutionsfactor ) + waterpump * 1000 + engineoff * 200;

View File

@@ -127,6 +127,15 @@ eu07_application::init( int Argc, char *Argv[] ) {
WriteLog( "Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, " WriteLog( "Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, "
"ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others\n" ); "ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others\n" );
{
WriteLog( "// settings" );
std::stringstream settingspipe;
Global.export_as_text( settingspipe );
WriteLog( settingspipe.str() );
}
WriteLog( "// startup" );
if( ( result = init_glfw() ) != 0 ) { if( ( result = init_glfw() ) != 0 ) {
return result; return result;
} }

View File

@@ -659,7 +659,6 @@ debug_panel::update_section_vehicle( std::vector<text_line> &Output ) {
auto const &mover { *m_input.mover }; auto const &mover { *m_input.mover };
auto const isowned { /* ( vehicle.Mechanik == nullptr ) && */ ( vehicle.ctOwner != nullptr ) && ( vehicle.ctOwner->Vehicle() != m_input.vehicle ) }; auto const isowned { /* ( vehicle.Mechanik == nullptr ) && */ ( vehicle.ctOwner != nullptr ) && ( vehicle.ctOwner->Vehicle() != m_input.vehicle ) };
auto const isplayervehicle { ( m_input.train != nullptr ) && ( m_input.train->Dynamic() == m_input.vehicle ) };
auto const isdieselenginepowered { ( mover.EngineType == TEngineType::DieselElectric ) || ( mover.EngineType == TEngineType::DieselEngine ) }; auto const isdieselenginepowered { ( mover.EngineType == TEngineType::DieselElectric ) || ( mover.EngineType == TEngineType::DieselEngine ) };
auto const isdieselinshuntmode { mover.ShuntMode && mover.EngineType == TEngineType::DieselElectric }; auto const isdieselinshuntmode { mover.ShuntMode && mover.EngineType == TEngineType::DieselElectric };
@@ -699,7 +698,7 @@ debug_panel::update_section_vehicle( std::vector<text_line> &Output ) {
( mover.CompressorGovernorLock ? '!' : '.' ), ( mover.CompressorGovernorLock ? '!' : '.' ),
( mover.StLinSwitchOff ? '-' : ( mover.ControlPressureSwitch ? '!' : ( mover.StLinFlag ? '+' : '.' ) ) ), ( mover.StLinSwitchOff ? '-' : ( mover.ControlPressureSwitch ? '!' : ( mover.StLinFlag ? '+' : '.' ) ) ),
( mover.Heating ? 'H' : ( mover.HeatingAllow ? 'h' : '.' ) ), ( mover.Heating ? 'H' : ( mover.HeatingAllow ? 'h' : '.' ) ),
std::string( isplayervehicle ? locale::strings[ locale::string::debug_vehicle_radio ] + ( mover.Radio ? std::to_string( m_input.train->RadioChannel() ) : "-" ) : "" ).c_str(), std::string( m_input.mechanik ? locale::strings[ locale::string::debug_vehicle_radio ] + ( mover.Radio ? std::to_string( m_input.mechanik->iRadioChannel ) : "-" ) : "" ).c_str(),
std::string( isdieselenginepowered ? locale::strings[ locale::string::debug_vehicle_oilpressure ] + to_string( mover.OilPump.pressure, 2 ) : "" ).c_str(), std::string( isdieselenginepowered ? locale::strings[ locale::string::debug_vehicle_oilpressure ] + to_string( mover.OilPump.pressure, 2 ) : "" ).c_str(),
// power transfers // power transfers
// 3000v // 3000v

View File

@@ -57,6 +57,13 @@ bool TTrainParameters::IsMaintenance() const {
return false; return false;
} }
int TTrainParameters::radio_channel() const {
if( ( StationIndex < StationCount ) )
return TimeTable[ StationIndex ].radio_channel;
else
return -1;
}
bool TTrainParameters::UpdateMTable( scenario_time const &Time, std::string const &NewName ) { bool TTrainParameters::UpdateMTable( scenario_time const &Time, std::string const &NewName ) {
return UpdateMTable( Time.data().wHour, Time.data().wMinute + Time.data().wSecond * 0.0167, NewName ); return UpdateMTable( Time.data().wHour, Time.data().wMinute + Time.data().wSecond * 0.0167, NewName );
@@ -406,9 +413,22 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax)
|| ( s == "2" ) || ( s == "2" )
|| fin.bad() ) ) { || fin.bad() ) ) {
record->StationWare += s; record->StationWare += s;
record->is_maintenance = ( s.find( "pt" ) != std::string::npos );
fin >> s; fin >> s;
} }
// cache relevant station data
record->is_maintenance = ( s.find( "pt" ) != std::string::npos );
{
auto const stationware { Split( record->StationWare, ',' ) };
for( auto const &entry : stationware ) {
if( entry[ 0 ] == 'R' ) {
auto const entrysplit { split_index( entry ) };
if( ( entrysplit.first == "R" )
&& ( entrysplit.second <= 10 ) ) {
record->radio_channel = entrysplit.second;
}
}
}
}
record->TrackNo = atoi(s.c_str()); record->TrackNo = atoi(s.c_str());
fin >> s; fin >> s;
if (s != "|") if (s != "|")

View File

@@ -37,6 +37,7 @@ struct TMTableLine
float Dm{ -1.f }; // godz. i min. odjazdu float Dm{ -1.f }; // godz. i min. odjazdu
float tm{ 0.f }; // czas jazdy do tej stacji w min. (z kolumny) float tm{ 0.f }; // czas jazdy do tej stacji w min. (z kolumny)
bool is_maintenance{ false }; bool is_maintenance{ false };
int radio_channel{ -1 };
}; };
typedef TMTableLine TMTable[MaxTTableSize + 1]; typedef TMTableLine TMTable[MaxTTableSize + 1];
@@ -77,6 +78,8 @@ class TTrainParameters
bool DirectionChange(); bool DirectionChange();
void StationIndexInc(); void StationIndexInc();
void serialize( dictionary_source *Output ) const; void serialize( dictionary_source *Output ) const;
// returns: radio channel associated with current station, or -1
int radio_channel() const;
}; };
class TMTableTime class TMTableTime

View File

@@ -275,9 +275,10 @@ smoke_source::location() const {
break; break;
} }
case owner_type::node: { case owner_type::node: {
// TODO: take into account node rotation auto const rotationx { glm::angleAxis( glm::radians( m_owner.node->Angles().x ), glm::vec3{ 1.f, 0.f, 0.f } ) };
auto const rotation { glm::angleAxis( glm::radians( m_owner.node->Angles().y ), glm::vec3{ 0.f, 1.f, 0.f } ) }; auto const rotationy { glm::angleAxis( glm::radians( m_owner.node->Angles().y ), glm::vec3{ 0.f, 1.f, 0.f } ) };
location = rotation * glm::vec3{ m_offset }; auto const rotationz { glm::angleAxis( glm::radians( m_owner.node->Angles().z ), glm::vec3{ 0.f, 0.f, 1.f } ) };
location = rotationy * rotationx * rotationz * glm::vec3{ m_offset };
location += m_owner.node->location(); location += m_owner.node->location();
break; break;
} }

View File

@@ -17,6 +17,7 @@ float const EU07_SOUND_GLOBALRANGE { -1.f };
float const EU07_SOUND_CABCONTROLSCUTOFFRANGE { 7.5f }; float const EU07_SOUND_CABCONTROLSCUTOFFRANGE { 7.5f };
float const EU07_SOUND_BRAKINGCUTOFFRANGE { 100.f }; float const EU07_SOUND_BRAKINGCUTOFFRANGE { 100.f };
float const EU07_SOUND_RUNNINGNOISECUTOFFRANGE { 200.f }; float const EU07_SOUND_RUNNINGNOISECUTOFFRANGE { 200.f };
float const EU07_SOUND_HANDHELDRADIORANGE { 750.f };
enum class sound_type { enum class sound_type {
single, single,