16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-22 23:19:19 +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 );
}
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)
{ // rozpoznanie wpisu modelu i ustawienie świateł
std::string name = parser->getToken<std::string>();
@@ -485,8 +494,7 @@ bool TAnimModel::Load(cParser *parser, bool ter)
if( token == "lights" ) {
auto i{ 0 };
while( ( false == ( token = parser->getToken<std::string>() ).empty() )
&& ( token != "lightcolors" )
&& ( token != "endmodel" ) ) {
&& ( false == is_keyword( token ) ) ) {
if( i < iNumLights ) {
// stan światła jest liczbą z ułamkiem
@@ -499,8 +507,7 @@ bool TAnimModel::Load(cParser *parser, bool ter)
if( token == "lightcolors" ) {
auto i{ 0 };
while( ( false == ( token = parser->getToken<std::string>() ).empty() )
&& ( token != "lights" )
&& ( token != "endmodel" ) ) {
&& ( false == is_keyword( token ) ) ) {
if( ( i < iNumLights )
&& ( token != "-1" ) ) { // -1 leaves the default color intact
@@ -513,6 +520,15 @@ bool TAnimModel::Load(cParser *parser, bool ter)
++i;
}
}
if( token == "angles" ) {
parser->getTokens( 3 );
*parser
>> vAngle[ 0 ]
>> vAngle[ 1 ]
>> vAngle[ 2 ];
}
} while( ( false == token.empty() )
&& ( token != "endmodel" ) );

View File

@@ -177,6 +177,8 @@ private:
void deserialize_( std::istream &Input );
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
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
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
{ // 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
if (false == TrainParams.IsStop())
{ // jeśli nie ma tu postoju
@@ -3217,8 +3232,8 @@ bool TController::IncSpeed()
return false;
}
bool OK = true;
if( ( doors_open() )
&& ( VelDesired > 0.0 ) ) { // to prevent door shuffle on stop
if( ( VelDesired > 0.0 ) // to prevent door shuffle on stop
&& ( doors_open() || doors_permit_active() ) ) {
// zamykanie drzwi - tutaj wykonuje tylko AI (zmienia fActionTime)
Doors( false );
}
@@ -4091,14 +4106,14 @@ void TController::Doors( bool const Open, int const Side ) {
}
else {
// zamykanie
if( ( false == pVehicle->MoverParameters->Doors.permit_needed )
if( ( false == doors_permit_active() )
&& ( false == doors_open() ) ) {
// the doors are already closed and we don't have to revoke control permit, we can skip all hard work
iDrivigFlags &= ~moveDoorOpened;
return;
}
if( AIControllFlag ) {
if( ( AIControllFlag ) && ( doors_open() ) ) {
if( ( true == mvOccupied->Doors.has_warning )
&& ( false == mvOccupied->DepartureSignal )
&& ( true == TestFlag( iDrivigFlags, moveDoorOpened ) ) ) {
@@ -4107,10 +4122,9 @@ void TController::Doors( bool const Open, int const Side ) {
}
}
if( ( true == doors_open() )
&& ( ( fActionTime > -0.5 )
|| ( false == AIControllFlag ) ) ) {
if( ( false == AIControllFlag ) || ( fActionTime > -0.5 ) ) {
// ai doesn't close the door until it's free to depart, but human driver has free reign to do stupid things
if( true == doors_open() ) {
if( ( pVehicle->MoverParameters->Doors.close_control == control_t::conductor )
|| ( ( true == AIControllFlag ) ) ) {
// if the door are controlled by the driver, we let the user operate them unless this user is an ai
@@ -4120,7 +4134,10 @@ void TController::Doors( bool const Open, int const Side ) {
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::left, false );
}
@@ -4157,19 +4174,14 @@ TController::doors_open() const {
return (
IsAnyDoorOpen[ side::right ]
|| IsAnyDoorOpen[ side::left ] );
/*
auto *vehicle = pVehicles[ 0 ]; // pojazd na czole składu
while( vehicle != nullptr ) {
if( ( false == vehicle->MoverParameters->Doors.instances[side::right].is_closed )
|| ( false == vehicle->MoverParameters->Doors.instances[side::left].is_closed ) ) {
// any open door is enough
return true;
}
vehicle = vehicle->Next();
}
// if we're still here there's nothing open
return false;
*/
bool
TController::doors_permit_active() const {
return (
IsAnyDoorPermitActive[ side::right ]
|| IsAnyDoorPermitActive[ side::left ] );
}
void TController::RecognizeCommand()
@@ -4275,7 +4287,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
{ ".ogg", ".flac", ".wav" } );
if( false == lookup.first.empty() ) {
// 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;
}
}
@@ -4733,6 +4745,7 @@ TController::UpdateSituation(double dt) {
double AbsAccS = 0;
IsAnyCouplerStretched = false;
IsAnyDoorOpen[ side::right ] = IsAnyDoorOpen[ side::left ] = false;
IsAnyDoorPermitActive[ side::right ] = IsAnyDoorPermitActive[ side::left ] = false;
ConsistShade = 0.0;
TDynamicObject *p = pVehicles[0]; // pojazd na czole składu
while (p)
@@ -4777,12 +4790,11 @@ TController::UpdateSituation(double dt) {
|| ( vehicle->Couplers[ end::rear ].stretch_duration > 0.0 );
// check door state
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::left ] =
IsAnyDoorOpen[ side::left ]
|| ( false == vehicle->Doors.instances[ ( switchsides ? side::right : side::left ) ].is_closed );
IsAnyDoorOpen[ side::right ] |= ( false == vehicle->Doors.instances[ ( switchsides ? side::left : side::right ) ].is_closed );
IsAnyDoorOpen[ side::left ] |= ( false == vehicle->Doors.instances[ ( switchsides ? side::right : side::left ) ].is_closed );
IsAnyDoorPermitActive[ side::right ] |= ( vehicle->Doors.permit_needed && vehicle->Doors.instances[ ( switchsides ? side::left : side::right ) ].open_permit );
IsAnyDoorPermitActive[ side::left ] |= ( vehicle->Doors.permit_needed && vehicle->Doors.instances[ ( switchsides ? side::right : side::left ) ].open_permit );
// measure lighting level
// TBD: apply weight (multiplier) to partially lit vehicles?
ConsistShade += ( p->fShade > 0.0 ? p->fShade : 1.0 );
@@ -6012,14 +6024,13 @@ TController::UpdateSituation(double dt) {
fActionTime = -5.0; // niech trochę potrzyma
}
else {
// if (iGuardRadio==iRadioChannel) //zgodność kanału
// 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
// radio message
tsGuardSignal.owner( pVehicle );
/*
tsGuardSignal.offset( { 0.f, 2.f, pVehicle->MoverParameters->Dim.L * 0.4f * ( pVehicle->MoverParameters->CabOccupied < 0 ? -1 : 1 ) } );
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
fActionTime = -5.0; // niech trochę potrzyma
}

View File

@@ -465,6 +465,7 @@ private:
void Doors( bool const Open, int const Side = 0 );
// returns true if any vehicle in the consist has an open door
bool doors_open() const;
bool doors_permit_active() const;
void AutoRewident(); // ustawia hamulce w składzie
void UpdatePantographs();
// members
@@ -482,6 +483,7 @@ private:
double ConsistShade{ 1.0 }; // averaged amount of sunlight received by the consist
TDynamicObject *pVehicles[ 2 ]; // skrajne pojazdy w składzie (niekoniecznie bezpośrednio sterowane)
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 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

View File

@@ -4096,6 +4096,15 @@ void TDynamicObject::RenderSounds() {
if( MoverParameters->CompressorSpeed > 0.0 ) {
// McZapkie! - dzwiek compressor.wav tylko gdy dziala sprezarka
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 );
}
else {
@@ -7269,7 +7278,7 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub
engine.m_amplitudeoffset
+ engine.m_amplitudefactor * (
0.25 * ( Vehicle.EnginePower / Vehicle.Power )
+ 0.75 * ( Vehicle.enrot * 60 ) / ( Vehicle.DElist[ Vehicle.MainCtrlPosNo ].RPM ) );
+ 0.75 * Vehicle.EngineRPMRatio() );
break;
}
case TEngineType::DieselEngine: {
@@ -7299,11 +7308,7 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub
// calculate potential recent increase of engine revolutions
auto const revolutionsperminute { Vehicle.enrot * 60 };
auto const revolutionsdifference { revolutionsperminute - engine_revs_last };
auto const idlerevolutionsthreshold { 1.01 * (
Vehicle.EngineType == TEngineType::DieselElectric ?
Vehicle.DElist[ 0 ].RPM :
Vehicle.dizel_nmin * 60 ) };
auto const idlerevolutionsthreshold { 1.01 * Vehicle.EngineIdleRPM() };
engine_revs_change = std::max( 0.0, engine_revs_change - 2.5 * Deltatime );
if( ( revolutionsperminute > idlerevolutionsthreshold )
&& ( revolutionsdifference > 1.0 * Deltatime ) ) {

View File

@@ -656,10 +656,11 @@ global_settings::ConfigParse(cParser &Parser) {
Parser >> token;
auto const priority { token };
PythonScreenUpdateRate = (
priority == "normal" ? 200 :
priority == "lower" ? 500 :
priority == "lowest" ? 1000 :
priority == "off" ? 0 :
200 );
stol_def( priority, 200 ) );
}
else if( token == "python.updatetime" )
{
@@ -955,3 +956,245 @@ global_settings::ConfigParse(cParser &Parser) {
Console::ModeSet(iFeedbackMode, iFeedbackPort); // tryb pracy konsoli sterowniczej
#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

@@ -227,8 +227,29 @@ struct global_settings {
// methods
void LoadIniFile( std::string asFileName );
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;
//---------------------------------------------------------------------------

View File

@@ -1647,6 +1647,9 @@ public:
double PipeRatio(void);/*ile napelniac*/
double RealPipeRatio(void);/*jak szybko*/
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*/
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;
}
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
// Wykrywanie kolizji
@@ -1959,17 +1987,13 @@ void TMoverParameters::OilPumpCheck( double const Timestep ) {
OilPump.start_type == start_t::manualwithautofallback ? ( OilPump.is_enabled || dizel_startup ) :
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 {
OilPump.pressure_minimum > 0.f ?
OilPump.pressure_minimum :
0.15f }; // arbitrary fallback value
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
0.f );
@@ -4128,14 +4152,10 @@ void TMoverParameters::CompressorCheck(double dt) {
switch( CompressorPower ) {
case 3: {
// 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 +=
CompressorSpeedF
* ( 2.0 * MaxCompressorF - Compressor ) / MaxCompressorF
* enginefactor
* EngineRPMRatio()
* dt
* ( CompressorGovernorLock ? 0.0 : 1.0 ); // with the lock active air is vented out
break;
@@ -5217,7 +5237,7 @@ double TMoverParameters::TractionForce( double dt ) {
std::max(
tmp,
std::min(
DElist[ MainCtrlPosNo ].RPM,
EngineMaxRPM(),
EngineHeatingRPM )
/ 60.0 );
}
@@ -5576,7 +5596,7 @@ double TMoverParameters::TractionForce( double dt ) {
if (EIMCtrlType > 0) //sterowanie cyfrowe
{
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;
tempUmax = DElist[MainCtrlPosNo].Umax * 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 ) );
// 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
auto const rpmratio { 60.0 * enrot / DElist[ MainCtrlPos ].RPM };
tmp = rpmratio * ( SST[ MainCtrlPos ].Pmax * AnPos ) + ( SST[ MainCtrlPos ].Pmin * ( 1.0 - AnPos ) );
tmp = EngineRPMRatio() * ( SST[ MainCtrlPos ].Pmax * AnPos ) + ( SST[ MainCtrlPos ].Pmin * ( 1.0 - AnPos ) );
Ft = tmp * 1000.0 / ( abs( tmpV ) + 1.6 );
}
else {
@@ -6203,8 +6222,7 @@ double TMoverParameters::TractionForce( double dt ) {
switch( EngineType ) {
case TEngineType::DieselElectric: {
// rough approximation of extra effort to overcome friction etc
auto const rpmratio{ 60.0 * enrot / DElist[ MainCtrlPosNo ].RPM };
EnginePower += rpmratio * 0.15 * DElist[ MainCtrlPosNo ].GenPower;
EnginePower += EngineRPMRatio() * 0.15 * DElist[ MainCtrlPosNo ].GenPower;
break;
}
default: {
@@ -7780,11 +7798,7 @@ void TMoverParameters::dizel_Heat( double const dt ) {
auto const engineoff { ( Mains ? 0 : 1 ) };
auto const rpm { enrot * 60 };
// TODO: calculate this once and cache for further use, instead of doing it repeatedly all over the place
auto const maxrevolutions { (
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 revolutionsfactor { EngineRPMRatio() };
auto const waterpump { WaterPump.is_active ? 1 : 0 };
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, "
"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 ) {
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 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 isdieselinshuntmode { mover.ShuntMode && mover.EngineType == TEngineType::DieselElectric };
@@ -699,7 +698,7 @@ debug_panel::update_section_vehicle( std::vector<text_line> &Output ) {
( mover.CompressorGovernorLock ? '!' : '.' ),
( mover.StLinSwitchOff ? '-' : ( mover.ControlPressureSwitch ? '!' : ( mover.StLinFlag ? '+' : '.' ) ) ),
( 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(),
// power transfers
// 3000v

View File

@@ -57,6 +57,13 @@ bool TTrainParameters::IsMaintenance() const {
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 ) {
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" )
|| fin.bad() ) ) {
record->StationWare += s;
record->is_maintenance = ( s.find( "pt" ) != std::string::npos );
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());
fin >> s;
if (s != "|")

View File

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

View File

@@ -275,9 +275,10 @@ smoke_source::location() const {
break;
}
case owner_type::node: {
// TODO: take into account node rotation
auto const rotation { 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 rotationx { glm::angleAxis( glm::radians( m_owner.node->Angles().x ), glm::vec3{ 1.f, 0.f, 0.f } ) };
auto const rotationy { glm::angleAxis( glm::radians( m_owner.node->Angles().y ), glm::vec3{ 0.f, 1.f, 0.f } ) };
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();
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_BRAKINGCUTOFFRANGE { 100.f };
float const EU07_SOUND_RUNNINGNOISECUTOFFRANGE { 200.f };
float const EU07_SOUND_HANDHELDRADIORANGE { 750.f };
enum class sound_type {
single,