Skip to content

Commit

Permalink
engine-powered compressor sound pitch adjustment, model node angles, …
Browse files Browse the repository at this point in the history
…global settings export and diagnostics, departure permit sound enhancement, radio channel selection ai logic enhancement, door permission ai logic fix
  • Loading branch information
tmj-fstate committed Jul 16, 2020
1 parent 3ea0d5b commit 0d0e299
Show file tree
Hide file tree
Showing 15 changed files with 452 additions and 102 deletions.
24 changes: 20 additions & 4 deletions AnimModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>();
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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" ) );

Expand Down
2 changes: 2 additions & 0 deletions AnimModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ class TAnimModel : public scene::basic_node {
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
Expand Down
95 changes: 53 additions & 42 deletions Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 );
}
Expand Down Expand Up @@ -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 ) ) ) {
Expand All @@ -4107,20 +4122,22 @@ 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( ( 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
// the train conductor, if present, handles door operation also for human-driven trains
if( ( pVehicle->MoverParameters->Doors.close_control == control_t::driver )
|| ( pVehicle->MoverParameters->Doors.close_control == control_t::mixed ) ) {
pVehicle->MoverParameters->OperateDoors( side::right, false );
pVehicle->MoverParameters->OperateDoors( side::left, false );
}
if( pVehicle->MoverParameters->Doors.permit_needed ) {
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
// the train conductor, if present, handles door operation also for human-driven trains
if( ( pVehicle->MoverParameters->Doors.close_control == control_t::driver )
|| ( pVehicle->MoverParameters->Doors.close_control == control_t::mixed ) ) {
pVehicle->MoverParameters->OperateDoors( side::right, false );
pVehicle->MoverParameters->OperateDoors( side::left, false );
}
}
}
if( true == doors_permit_active() ) {
if( true == AIControllFlag ) {
pVehicle->MoverParameters->PermitDoors( side::right, false );
pVehicle->MoverParameters->PermitDoors( side::left, false );
}
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 );
Expand Down Expand Up @@ -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
}
Expand Down
2 changes: 2 additions & 0 deletions Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ class TController {
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
Expand All @@ -482,6 +483,7 @@ class TController {
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
Expand Down
17 changes: 11 additions & 6 deletions DynObj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -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 ) ) {
Expand Down
Loading

0 comments on commit 0d0e299

Please sign in to comment.