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

build 210424. soundproofing enhancement, battery sound, heating command propagation, memory cell command retrieval logic enhancement, coupling mode logic enhancement, motor overload relay threshold cab control animation fix, cab control fallback sound activation fixes,

This commit is contained in:
tmj-fstate
2021-04-24 19:37:16 +02:00
parent 66bd63336b
commit 3775d20e0c
17 changed files with 276 additions and 112 deletions

View File

@@ -1676,11 +1676,15 @@ TController::TableUpdateEvent( double &Velocity, TCommandType &Command, TSpeedPo
else if( Point.evEvent->is_command() ) {
// jeśli prędkość jest zerowa, a komórka zawiera komendę
eSignNext = Point.evEvent; // dla informacji
// make sure the command isn't for someone else
// TBD, TODO: revise this check for bank/loose_shunt; we might want to ignore obstacles with no owner in these modes
if( Point.fDist < Obstacle.distance ) {
if( true == TestFlag( iDrivigFlags, moveStopHere ) ) {
// jeśli ma stać, dostaje komendę od razu
Command = TCommandType::cm_Command; // komenda z komórki, do wykonania po zatrzymaniu
}
else if( Point.fDist <= fMaxProximityDist ) {
// NOTE: human drivers are likely to stop wherever and expect things to still work, so we give them more leeway
else if( Point.fDist <= ( AIControllFlag ? fMaxProximityDist : std::max( 250.0, fMaxProximityDist ) ) ) {
// jeśli ma dociągnąć, to niech dociąga
// (moveStopCloser dotyczy dociągania do W4, nie semafora)
Command = TCommandType::cm_Command; // komenda z komórki, do wykonania po zatrzymaniu
@@ -1688,6 +1692,7 @@ TController::TableUpdateEvent( double &Velocity, TCommandType &Command, TSpeedPo
}
}
}
}
} // jeśli nie ma zawalidrogi
return false;
@@ -1928,9 +1933,13 @@ TController::~TController()
// zamiana kodu rozkazu na opis
std::string TController::Order2Str(TOrders Order) const {
if( Order & Change_direction ) {
if( ( ( Order & Change_direction ) != 0 )
&& ( Order != Change_direction ) ) {
// może być nałożona na inną i wtedy ma priorytet
return "Change_direction";
return
Order2Str( Change_direction )
+ " + "
+ Order2Str( static_cast<TOrders>( Order & ~Change_direction ) );
}
switch( Order ) {
case Wait_for_orders: return "Wait_for_orders";
@@ -1953,11 +1962,15 @@ std::array<char, 64> orderbuffer;
std::string TController::OrderCurrent() const
{ // pobranie aktualnego rozkazu celem wyświetlenia
auto const order { OrderCurrentGet() };
// generally prioritize direction change...
if( order & Change_direction ) {
// ...but not in the middle of coupling operation
if( false == TestFlag( iDrivigFlags, moveConnect ) ) {
return locale::strings[ locale::string::driver_scenario_changedirection ];
}
}
switch( OrderList[ OrderPos ] ) {
switch( static_cast<TOrders>( order & ~Change_direction ) ) {
case Wait_for_orders: { return locale::strings[ locale::string::driver_scenario_waitfororders ]; }
case Prepare_engine: { return locale::strings[ locale::string::driver_scenario_prepareengine ]; }
case Release_engine: { return locale::strings[ locale::string::driver_scenario_releaseengine ]; }
@@ -4927,17 +4940,20 @@ TController::PrepareDirection() {
locale::string::driver_hint_directionbackward );
}
void TController::JumpToNextOrder()
void TController::JumpToNextOrder( bool const Ignoremergedchangedirection )
{ // wykonanie kolejnej komendy z tablicy rozkazów
if (OrderList[OrderPos] != Wait_for_orders)
{
if (OrderList[OrderPos] & Change_direction) // jeśli zmiana kierunku
if (OrderList[OrderPos] != Change_direction) // ale nałożona na coś
{
OrderList[OrderPos] = TOrders(OrderList[OrderPos] & ~Change_direction); // usunięcie zmiany kierunku z innej komendy
if( ( ( OrderList[ OrderPos ] & Change_direction ) != 0 ) // jeśli zmiana kierunku
&& ( OrderList[ OrderPos ] != Change_direction ) ) { // ale nałożona na coś
if( false == Ignoremergedchangedirection ) {
// usunięcie zmiany kierunku z innej komendy
OrderList[ OrderPos ] = TOrders( OrderList[ OrderPos ] & ~Change_direction );
OrderCheck();
return;
}
}
if (OrderPos < maxorders - 1)
++OrderPos;
else
@@ -6701,9 +6717,9 @@ TController::UpdateConnect() {
// podłączanie do składu
if (iDrivigFlags & moveConnect) {
// sprzęgi sprawdzamy w pierwszej kolejności, bo jak połączony, to koniec
auto *vehicle { pVehicles[ end::front ] };
auto *vehicle { iCouplingVehicle.value().first };
auto const couplingend { iCouplingVehicle.value().second };
auto *vehicleparameters { vehicle->MoverParameters };
auto const couplingend { ( vehicle->DirectionGet() > 0 ? end::front : end::rear ) };
if( vehicleparameters->Couplers[ couplingend ].CouplingFlag != iCoupler ) {
auto const &neighbour { vehicleparameters->Neighbours[ couplingend ] };
if( neighbour.vehicle != nullptr ) {
@@ -6736,17 +6752,27 @@ TController::UpdateConnect() {
CheckVehicles( Connect ); // sprawdzić światła nowego składu
iCoupler = 0; // dalsza jazda manewrowa już bez łączenia
iCouplingVehicle.reset();
iDrivigFlags &= ~moveConnect; // zdjęcie flagi doczepiania
JumpToNextOrder(); // wykonanie następnej komendy
JumpToNextOrder( true ); // wykonanie następnej komendy
}
} // moveConnect
else {
if( Obstacle.distance <= 20.0 ) {
// początek podczepiania, z wyłączeniem sprawdzania fTrackBlock
if( Obstacle.distance <= 20.0 ) {
if( !iCouplingVehicle ) {
// write down which vehicle should be coupled with the target consist,
// so we don't lose track of it if the user does something unexpected
iCouplingVehicle = {
pVehicles[ end::front ],
( pVehicles[ end::front ]->DirectionGet() > 0 ?
end::front :
end::rear ) };
iDrivigFlags |= moveConnect;
}
}
}
}
int
TController::unit_count( int const Threshold ) const {
@@ -6885,9 +6911,7 @@ TController::UpdateDisconnect() {
// 5th stage: clean up and move on to next order
if( iDirection == iDirectionOrder ) {
iDrivigFlags &= ~movePress; // koniec dociskania
while( ( OrderCurrentGet() & Disconnect ) != 0 ) {
JumpToNextOrder(); // zmieni światła
}
JumpToNextOrder( true ); // zmieni światła
TableClear(); // skanowanie od nowa
iDrivigFlags &= ~moveStartHorn; // bez trąbienia przed ruszeniem
}
@@ -6957,6 +6981,11 @@ TController::handle_orders() {
break;
}
default: {
// special case, change_direction potentially received during partially completed coupling operation
// this is unlikely to happen for the AI, but can happen for a (slower) human user
if( TestFlag( iDrivigFlags, moveConnect ) ) {
UpdateConnect();
}
break;
}
} // switch OrderList[OrderPos]
@@ -7949,13 +7978,18 @@ TController::check_route_ahead( double const Range ) {
void
TController::check_route_behind( double const Range ) {
if( VelNext != 0.0 ) { return; }
if( VelNext != 0.0 ) { return; } // not if we can move ahead
if( TestFlag( iDrivigFlags, moveConnect ) ) { return; } // not if we're in middle of coupling operation
if( !( OrderCurrentGet() & ~( Shunt | Loose_shunt | Connect ) ) ) {
if( ( OrderCurrentGet() & ~( Shunt | Loose_shunt | Connect ) ) == 0 ) {
// jedzie w Shunt albo Connect, albo Wait_for_orders
// w trybie Connect skanować do tyłu tylko jeśli przed kolejnym sygnałem nie ma taboru do podłączenia
if( ( ( OrderCurrentGet() & Connect ) == 0 )
|| ( Obstacle.distance > std::min( 2000.0, FirstSemaphorDist ) ) ) {
auto const couplinginprogress {
( TestFlag( OrderCurrentGet(), Connect ) )
&& ( ( Obstacle.distance < std::min( 2000.0, FirstSemaphorDist ) )
|| ( TestFlag( iDrivigFlags, moveConnect ) ) ) };
if( couplinginprogress ) { return; }
auto const comm { BackwardScan( Range ) };
if( comm != TCommandType::cm_Unknown ) {
// jeśli w drugą można jechać
@@ -7972,7 +8006,6 @@ TController::check_route_behind( double const Range ) {
}
}
}
}
void
TController::UpdateBrakingHelper() {

View File

@@ -383,6 +383,7 @@ private:
int iDirection = 0; // kierunek jazdy względem sprzęgów pojazdu, w którym siedzi AI (1=przód,-1=tył)
int iDirectionOrder = 0; //żadany kierunek jazdy (służy do zmiany kierunku)
std::optional<int> iDirectionBackup; // consist direction to be restored after coupling/uncoupling and similar direction-changing operations
std::optional<std::pair<TDynamicObject*,int>> iCouplingVehicle; // <vehicle, coupler> to be coupled with another consist in current coupling operation
int iVehicleCount = -2; // wartość neutralna // ilość pojazdów do odłączenia albo zabrania ze składu (-1=wszystkie)
int iCoupler = 0; // maska sprzęgu, jaką należy użyć przy łączeniu (po osiągnięciu trybu Connect), 0 gdy jazda bez łączenia
int iDriverFailCount = 0; // licznik błędów AI
@@ -446,7 +447,7 @@ public:
std::string OrderCurrent() const;
private:
void RecognizeCommand(); // odczytuje komende przekazana lokomotywie
void JumpToNextOrder();
void JumpToNextOrder( bool const Skipmergedchangedirection = false );
void JumpToFirstOrder();
void OrderPush( TOrders NewOrder );
void OrderNext( TOrders NewOrder );

View File

@@ -4122,6 +4122,14 @@ void TDynamicObject::RenderSounds() {
sHeater.stop();
}
// battery sound
if( MoverParameters->Battery ) {
m_batterysound.play( sound_flags::exclusive | sound_flags::looping );
}
else {
m_batterysound.stop();
}
// brake system and braking sounds:
// brake cylinder piston
@@ -5763,6 +5771,12 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
sHeater.owner( this );
}
else if( token == "battery:" ) {
// train heating device
m_batterysound.deserialize( parser, sound_type::single );
m_batterysound.owner( this );
}
else if( token == "turbo:" ) {
// pliki z turbogeneratorem
m_powertrainsounds.engine_turbo.deserialize( parser, sound_type::multipart, sound_parameters::range );
@@ -6484,7 +6498,7 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
// other engine compartment sounds
auto const nullvector { glm::vec3() };
std::vector<sound_source *> enginesounds = {
&sConverter, &sCompressor, &sCompressorIdle, &sSmallCompressor, &sHeater
&sConverter, &sCompressor, &sCompressorIdle, &sSmallCompressor, &sHeater, &m_batterysound
};
for( auto sound : enginesounds ) {
if( sound->offset() == nullvector ) {

View File

@@ -480,6 +480,7 @@ private:
sound_source sCompressorIdle { sound_placement::engine };
sound_source sSmallCompressor { sound_placement::engine };
sound_source sHeater { sound_placement::engine };
sound_source m_batterysound { sound_placement::engine };
// braking sounds
sound_source dsbPneumaticRelay { sound_placement::external };
sound_source rsBrake { sound_placement::external, EU07_SOUND_BRAKINGCUTOFFRANGE }; // moved from cab

View File

@@ -538,10 +538,10 @@ updatevalues_event::run_() {
auto const location { targetcell->location() };
for( auto vehicle : targetcell->Track->Dynamics ) {
if( vehicle->Mechanik ) {
WriteLog( " Vehicle: [" + vehicle->name() + "]" );
targetcell->PutCommand(
vehicle->Mechanik,
&location );
WriteLog( " Vehicle: [" + vehicle->name() + "]" );
}
}
}
@@ -775,10 +775,9 @@ putvalues_event::run_() {
m_input.location.z,
m_input.location.y };
std::string vehiclename;
if( m_activator->Mechanik ) {
// przekazanie rozkazu do AI
vehiclename = m_activator->Mechanik->Vehicle()->name();
WriteLog( " Vehicle: [" + m_activator->Mechanik->Vehicle()->name() + "]" );
m_activator->Mechanik->PutCommand(
m_input.data_text,
m_input.data_value_1,
@@ -790,7 +789,7 @@ putvalues_event::run_() {
// send the command to consist owner,
// we're acting on presumption there's hardly ever need to issue command to unmanned vehicle
// and the intended recipient moved between vehicles after the event was queued
vehiclename = m_activator->ctOwner->Vehicle()->name();
WriteLog( " Vehicle: [" + m_activator->ctOwner->Vehicle()->name() + "]" );
m_activator->ctOwner->PutCommand(
m_input.data_text,
m_input.data_value_1,
@@ -799,15 +798,13 @@ putvalues_event::run_() {
}
else {
// przekazanie do pojazdu
vehiclename = m_activator->name();
WriteLog( " Vehicle: [" + m_activator->name() +"]" );
m_activator->MoverParameters->PutCommand(
m_input.data_text,
m_input.data_value_1,
m_input.data_value_2,
loc );
}
WriteLog( " Vehicle: [" + vehiclename + "]" );
}
// export_as_text() subclass details
@@ -944,10 +941,10 @@ copyvalues_event::run_() {
auto const location { targetcell->location() };
for( auto vehicle : targetcell->Track->Dynamics ) {
if( vehicle->Mechanik ) {
WriteLog( " Vehicle: [" + vehicle->name() + "]" );
targetcell->PutCommand(
vehicle->Mechanik,
&location );
WriteLog( " Vehicle: [" + vehicle->name() + "]" );
}
}
}

View File

@@ -141,9 +141,33 @@ void TGauge::Load( cParser &Parser, TDynamicObject const *Owner, double const mu
>> endscale;
}
// new, variable length section
while( true == Load_mapping( Parser ) ) {
{
scratch_data scratchpad;
while( true == Load_mapping( Parser, scratchpad ) ) {
; // all work done by while()
}
// post-deserialization cleanup
// set provided custom soundproofing to assigned sounds (for sounds without their own custom soundproofing)
if( scratchpad.soundproofing ) {
if( !m_soundfxincrease.soundproofing() ) {
m_soundfxincrease.soundproofing() = scratchpad.soundproofing;
}
if( !m_soundfxdecrease.soundproofing() ) {
m_soundfxdecrease.soundproofing() = scratchpad.soundproofing;
}
if( !m_soundfxon.soundproofing() ) {
m_soundfxon.soundproofing() = scratchpad.soundproofing;
}
if( !m_soundfxoff.soundproofing() ) {
m_soundfxoff.soundproofing() = scratchpad.soundproofing;
}
for( auto &soundfxrecord : m_soundfxvalues ) {
if( !soundfxrecord.second.soundproofing() ) {
soundfxrecord.second.soundproofing() = scratchpad.soundproofing;
}
}
}
}
}
// bind defined sounds with the button owner
@@ -207,7 +231,7 @@ void TGauge::Load( cParser &Parser, TDynamicObject const *Owner, double const mu
};
bool
TGauge::Load_mapping( cParser &Input ) {
TGauge::Load_mapping( cParser &Input, TGauge::scratch_data &Scratchpad ) {
// token can be a key or block end
auto const key { Input.getToken<std::string>( true, "\n\r\t ,;" ) };
@@ -236,8 +260,21 @@ TGauge::Load_mapping( cParser &Input ) {
else if( key == "soundoff:" ) {
m_soundfxoff.deserialize( Input, sound_type::single );
}
else if( key.compare( 0, std::min<std::size_t>( key.size(), 5 ), "sound" ) == 0 ) {
// sounds assigned to specific gauge values, defined by key soundFoo: where Foo = value
else if( key == "soundproofing:" ) {
// custom soundproofing in format [ p1, p2, p3, p4, p5, p6 ]
Input.getTokens( 6, false, "\n\r\t ,;[]" );
std::array<float, 6> soundproofing;
Input
>> soundproofing[ 0 ]
>> soundproofing[ 1 ]
>> soundproofing[ 2 ]
>> soundproofing[ 3 ]
>> soundproofing[ 4 ]
>> soundproofing[ 5 ];
Scratchpad.soundproofing = soundproofing;
}
else if( starts_with( key, "sound" ) ) {
// sounds assigned to specific gauge values, defined by key soundX: where X = value
auto const indexstart { key.find_first_of( "-1234567890" ) };
auto const indexend { key.find_first_not_of( "-1234567890", indexstart ) };
if( indexstart != std::string::npos ) {
@@ -290,13 +327,19 @@ TGauge::UpdateValue( float fNewDesired, sound_source *Fallbacksound ) {
// HACK: crude way to discern controls with continuous and quantized value range
if( currentvalue < fNewDesired ) {
// shift up
if( false == m_soundfxincrease.empty() ) {
m_soundfxincrease.play( m_soundtype );
return;
}
}
else if( currentvalue > fNewDesired ) {
// shift down
if( false == m_soundfxdecrease.empty() ) {
m_soundfxdecrease.play( m_soundtype );
return;
}
else if( Fallbacksound != nullptr ) {
}
if( Fallbacksound != nullptr ) {
// ...and if that fails too, try the provided fallback sound from legacy system
Fallbacksound->play( m_soundtype );
}

View File

@@ -71,10 +71,14 @@ public:
*SubModelOn { nullptr }; // optional submodel visible when the state input is set
private:
// types
struct scratch_data {
std::optional< std::array<float, 6> > soundproofing;
};
// methods
// imports member data pair from the config file
bool
Load_mapping( cParser &Input );
Load_mapping( cParser &Input, TGauge::scratch_data &Scratchpad );
void
UpdateValue( float fNewDesired, sound_source *Fallbacksound );
float

View File

@@ -1046,7 +1046,7 @@ public:
double EngineHeatingRPM { 0.0 }; // guaranteed engine revolutions with heating enabled
double LightPower = 0.0; /*moc pobierana na ogrzewanie/oswietlenie*/
double BatteryVoltage = 0.0; /*Winger - baterie w elektrykach*/
bool Battery = false; /*Czy sa zalavzone baterie*/
bool Battery = false; /*Czy sa zalaczone baterie*/
start_t BatteryStart = start_t::manual;
bool EpFuse = true; /*Czy sa zalavzone baterie*/
bool Signalling = false; /*Czy jest zalaczona sygnalizacja hamowania ostatniego wagonu*/
@@ -1805,6 +1805,8 @@ public:
bool ConverterSwitch( bool State, range_t const Notify = range_t::consist );/*! wl/wyl przetwornicy*/
bool CompressorSwitch( bool State, range_t const Notify = range_t::consist );/*! wl/wyl sprezarki*/
bool ChangeCompressorPreset( int const Change, range_t const Notify = range_t::consist );
bool HeatingSwitch( bool const State, range_t const Notify = range_t::consist );
void HeatingSwitch_( bool const State );
/*-funkcje typowe dla lokomotywy elektrycznej*/
void LowVoltagePowerCheck( double const Deltatime );

View File

@@ -647,10 +647,12 @@ bool TMoverParameters::ChangeCab(int direction)
// rozruch wysoki (true) albo niski (false)
bool
TMoverParameters::CurrentSwitch(bool const State) {
// Ra: przeniosłem z Train.cpp, nie wiem czy ma to sens
if( MaxCurrentSwitch( State ) ) {
if (TrainType != dt_EZT)
return (MinCurrentSwitch(State));
if( TrainType != dt_EZT ) {
( MinCurrentSwitch( State ) );
}
return true;
}
// TBD, TODO: split off shunt mode toggle into a separate command? It doesn't make much sense to have these two together like that
// dla 2Ls150
@@ -3641,6 +3643,33 @@ bool TMoverParameters::ChangeCompressorPreset( int const State, range_t const No
return ( CompressorListPos != initialstate );
}
bool TMoverParameters::HeatingSwitch( bool const State, range_t const Notify ) {
bool const initialstate { HeatingAllow };
HeatingSwitch_( State );
if( Notify != range_t::local ) {
// pass the command to other vehicles
// TBD: pass the requested state, or the actual state?
SendCtrlToNext(
"HeatingSwitch",
( State ? 1 : 0 ),
CabActive,
( Notify == range_t::unit ?
coupling::control | coupling::permanent :
coupling::control ) );
}
return ( HeatingAllow != initialstate );
}
void TMoverParameters::HeatingSwitch_( bool const State ) {
// TBD, TODO: activation dependencies?
HeatingAllow = State;
}
// *************************************************************************************************
// Q: 20160711
// zwiększenie nastawy hamulca
@@ -6550,12 +6579,14 @@ bool TMoverParameters::MaxCurrentSwitch(bool State)
if (State && (Imax == ImaxLo) && (RList[MainCtrlPos].Bn < 2) &&
!((TrainType == dt_ET42) && (MainCtrlPos > 0)))
{
Imax = ImaxHi;
MCS = true;
if (CabActive != 0)
SendCtrlToNext("MaxCurrentSwitch", 1, CabActive);
}
if (!State)
if (Imax == ImaxHi)
if (!((TrainType == dt_ET42) && (MainCtrlPos > 0)))
{
@@ -11771,6 +11802,11 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
MainSwitch_( CValue1 > 0.0 );
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
}
else if (Command == "HeatingSwitch")
{
HeatingSwitch_( CValue1 > 0.0 );
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
}
else if (Command == "Direction")
{
DirActive = static_cast<int>(floor(CValue1));

View File

@@ -4859,7 +4859,7 @@ void TTrain::OnCommand_heatingenable( TTrain *Train, command_data const &Command
if( Command.action == GLFW_PRESS ) {
Train->mvControlled->HeatingAllow = true;
Train->mvOccupied->HeatingSwitch( true );
// visual feedback
Train->ggTrainHeatingButton.UpdateValue( 1.0, Train->dsbSwitch );
}
@@ -4869,7 +4869,7 @@ void TTrain::OnCommand_heatingdisable( TTrain *Train, command_data const &Comman
if( Command.action == GLFW_PRESS ) {
Train->mvControlled->HeatingAllow = false;
Train->mvOccupied->HeatingSwitch( false );
// visual feedback
Train->ggTrainHeatingButton.UpdateValue(
( Train->ggTrainHeatingButton.type() == TGaugeType::push ?
@@ -7101,7 +7101,7 @@ bool TTrain::Update( double const Deltatime )
}
ggMainCtrl.Update();
}
if (ggMainCtrlAct.SubModel)
if (ggMainCtrlAct.SubModel != nullptr )
{
if (mvControlled->CoupledCtrl)
ggMainCtrlAct.UpdateValue(
@@ -7110,7 +7110,7 @@ bool TTrain::Update( double const Deltatime )
ggMainCtrlAct.UpdateValue(double(mvControlled->MainCtrlActualPos));
ggMainCtrlAct.Update();
}
if (ggScndCtrl.SubModel) {
if (ggScndCtrl.SubModel != nullptr ) {
// Ra: od byte odejmowane boolean i konwertowane potem na double?
ggScndCtrl.UpdateValue(
double( mvControlled->ScndCtrlPos
@@ -7118,26 +7118,34 @@ bool TTrain::Update( double const Deltatime )
dsbNastawnikBocz );
ggScndCtrl.Update();
}
if( ggScndCtrlButton.SubModel != nullptr ) {
if( ggScndCtrlButton.is_toggle() ) {
ggScndCtrlButton.UpdateValue(
( ( mvControlled->ScndCtrlPos > 0 ) ? 1.f : 0.f ),
dsbSwitch );
}
ggScndCtrlButton.Update( lowvoltagepower );
}
if( ggScndCtrlOffButton.SubModel != nullptr ) {
ggScndCtrlOffButton.Update( lowvoltagepower );
}
if( ggDistanceCounterButton.SubModel != nullptr ) {
ggDistanceCounterButton.Update();
if (ggDirKey.SubModel) {
if (mvControlled->TrainType != dt_EZT)
}
if (ggDirKey.SubModel != nullptr ) {
if( mvControlled->TrainType != dt_EZT ) {
ggDirKey.UpdateValue(
double( mvControlled->DirActive ),
dsbReverserKey );
else
}
else {
ggDirKey.UpdateValue(
double( mvControlled->DirActive ) + double( mvControlled->Imin == mvControlled->IminHi ),
dsbReverserKey );
}
ggDirKey.Update();
}
if (ggBrakeCtrl.SubModel)
if (ggBrakeCtrl.SubModel != nullptr )
{
#ifdef _WIN32
if (DynamicObject->Mechanik ?

View File

@@ -1147,24 +1147,24 @@ TController::cue_action( locale::string const Action, float const Actionparamete
// consist heating
case locale::string::driver_hint_consistheatingon: {
if( AIControllFlag ) {
mvControlling->HeatingAllow = true;
mvOccupied->HeatingSwitch( true );
}
remove_hint( locale::string::driver_hint_consistheatingoff );
hint(
Action,
[this](float const Parameter) -> bool {
return ( mvControlling->HeatingAllow == true ); } );
return ( mvOccupied->HeatingAllow == true ); } );
break;
}
case locale::string::driver_hint_consistheatingoff: {
if( AIControllFlag ) {
mvControlling->HeatingAllow = false;
mvOccupied->HeatingSwitch( false );
}
remove_hint( locale::string::driver_hint_consistheatingon );
hint(
Action,
[this](float const Parameter) -> bool {
return ( mvControlling->HeatingAllow == false ); } );
return ( mvOccupied->HeatingAllow == false ); } );
break;
}

View File

@@ -1088,7 +1088,7 @@ debug_panel::update_section_ai( std::vector<text_line> &Output ) {
// biezaca komenda dla AI
auto textline =
"Current order: [" + std::to_string( mechanik.OrderPos ) + "] "
+ mechanik.OrderCurrent();
+ mechanik.Order2Str( mechanik.OrderCurrentGet() );
if( mechanik.fStopTime < 0.0 ) {
textline += "\n stop time: " + to_string( std::abs( mechanik.fStopTime ), 1 );

View File

@@ -171,10 +171,23 @@ sound_source::deserialize_mapping( cParser &Input ) {
else if( key == "soundend:" ) {
sound( sound_id::end ).buffer = audio::renderer.fetch_buffer( deserialize_random_set( Input, "\n\r\t ,;" ) );
}
else if( key.compare( 0, std::min<std::size_t>( key.size(), 5 ), "sound" ) == 0 ) {
else if( key == "soundproofing:" ) {
// custom soundproofing in format [ p1, p2, p3, p4, p5, p6 ]
Input.getTokens( 6, false, "\n\r\t ,;[]" );
std::array<float, 6> soundproofing;
Input
>> soundproofing[ 0 ]
>> soundproofing[ 1 ]
>> soundproofing[ 2 ]
>> soundproofing[ 3 ]
>> soundproofing[ 4 ]
>> soundproofing[ 5 ];
m_soundproofing = soundproofing;
}
else if( starts_with( key, "sound" ) ) {
// sound chunks, defined with key soundX where X = activation threshold
auto const indexstart { key.find_first_of( "1234567890" ) };
auto const indexend { key.find_first_not_of( "1234567890", indexstart ) };
auto const indexstart { key.find_first_of( "-1234567890" ) };
auto const indexend { key.find_first_not_of( "-1234567890", indexstart ) };
if( indexstart != std::string::npos ) {
// NOTE: we'll sort the chunks at the end of deserialization
m_soundchunks.emplace_back(
@@ -202,10 +215,10 @@ sound_source::deserialize_mapping( cParser &Input ) {
Input.getToken<float>( false, "\n\r\t ,;" ),
0.0f, 1.0f );
}
else if( key.compare( 0, std::min<std::size_t>( key.size(), 5 ), "pitch" ) == 0 ) {
else if( starts_with( key, "pitch" ) ) {
// sound chunk pitch, defined with key pitchX where X = activation threshold
auto const indexstart { key.find_first_of( "1234567890" ) };
auto const indexend { key.find_first_not_of( "1234567890", indexstart ) };
auto const indexstart { key.find_first_of( "-1234567890" ) };
auto const indexend { key.find_first_not_of( "-1234567890", indexstart ) };
if( indexstart != std::string::npos ) {
auto const index { std::stoi( key.substr( indexstart, indexend - indexstart ) ) };
auto const pitch { Input.getToken<float>( false, "\n\r\t ,;" ) };
@@ -962,12 +975,14 @@ sound_source::update_soundproofing() {
auto const isambient { ( ( m_placement == sound_placement::external ) && ( m_owner == nullptr ) && ( m_range < -1 ) ? 1 : 0 ) };
auto const placement { ( isambient ? sound_placement::external_ambient : m_placement ) };
if( m_owner != nullptr ) {
m_properties.soundproofing =
m_owner->soundproofing(
static_cast<int>( placement ),
( m_owner != listenervehicle ?
auto const listenerlocation { (
m_owner != listenervehicle ?
4 : // part of two-stage calculation owner->outside->listener, or single stage owner->outside one
occupiedcab ) );
occupiedcab ) };
m_properties.soundproofing = (
m_soundproofing ? // custom soundproofing has higher priority than that of the owner
m_soundproofing.value()[ listenerlocation + 1 ] : // cab indices start from -1 so we have to account for this
m_owner->soundproofing( static_cast<int>( placement ), listenerlocation ) );
}
if( ( listenervehicle ) && ( listenervehicle != m_owner ) ) {
// if the listener is located in another vehicle, calculate additional proofing of the sound coming from outside

10
sound.h
View File

@@ -116,6 +116,11 @@ public:
start( float const Offset );
float const &
start() const;
// custom soundproofing setter/getter
auto &
soundproofing();
auto const &
soundproofing() const;
// returns true if there isn't any sound buffer associated with the object, false otherwise
bool
empty() const;
@@ -231,6 +236,7 @@ private:
std::vector<soundchunk_pair> m_soundchunks; // table of samples activated when associated variable is within certain range
bool m_soundchunksempty { true }; // helper, cached check whether sample table is linked with any actual samples
int m_crossfaderange {}; // range of transition from one chunk to another
std::optional< std::array<float, 6> > m_soundproofing; // custom soundproofing parameters
};
// owner setter/getter
@@ -245,6 +251,10 @@ inline std::string const & sound_source::name() const { return m_name; }
// playback starting point shift setter/getter
inline void sound_source::start( float const Offset ) { m_startoffset = Offset; }
inline float const & sound_source::start() const { return m_startoffset; }
// custom soundproofing setter/getter
inline auto & sound_source::soundproofing() { return m_soundproofing; }
inline auto const & sound_source::soundproofing() const { return m_soundproofing; }
// collection of sound sources present in the scene
class sound_table : public basic_table<sound_source> {

View File

@@ -393,15 +393,15 @@ init() {
"Wylaczyc przetwornice",
"Odblokowac przekaznik nadmiarowy przetwornicy",
"Odblokowac przekaznik roznicowy obwodu glownego",
"Odblokowac przekaznik nadmiarowy motorow trakcyjnych",
"Odblokowac przekaznik nadmiarowy silnikow trakcyjnych",
"Zamknac wylacznik szybki",
"Otworzyc wylacznik szybki",
"Zalaczyc sprezarke",
"Wylaczyc sprezarke",
"Zalaczyc wentylatory przednich motorow trakcyjnych",
"Wylaczyc wentylatory przednich motorow trakcyjnych",
"Zalaczyc wentylatory tylnych motorow trakcyjnych",
"Wylaczyc wentylatory tylnych motorow trakcyjnych",
"Zalaczyc wentylatory przednich silnikow trakcyjnych",
"Wylaczyc wentylatory przednich silnikow trakcyjnych",
"Zalaczyc wentylatory tylnych silnikow trakcyjnych",
"Wylaczyc wentylatory tylnych silnikow trakcyjnych",
"Zalaczyc hamulec sprezynowy",
"Zwolnic hamules sprezynowy",
"Zalaczyc hamulec reczny",

View File

@@ -77,7 +77,7 @@ ui_layer::init( GLFWwindow *Window ) {
static ImWchar const glyphranges[] = {
0x0020, 0x00FF, // ascii + extension
0x0100, 0x017F, // latin extended-a
// 0x0100, 0x017F, // latin extended-a
0x2070, 0x2079, // superscript
0x2500, 0x256C, // box drawings
0,

View File

@@ -1,5 +1,5 @@
#pragma once
#define VERSION_MAJOR 21
#define VERSION_MINOR 408
#define VERSION_MINOR 424
#define VERSION_REVISION 0