diff --git a/Driver.cpp b/Driver.cpp index 9c82e860..39c1d15b 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -1408,9 +1408,12 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN // if (v==0.0) fAcc=-0.9; //hamowanie jeśli stop continue; // i tyle wystarczy } - else // event trzyma tylko jeśli VelNext=0, nawet po przejechaniu (nie powinno - // dotyczyć samochodów?) - a = (v == 0.0 ? -1.0 : fAcc); // ruszanie albo hamowanie + else // event trzyma tylko jeśli VelNext=0, nawet po przejechaniu (nie powinno dotyczyć samochodów?) + a = (v > 0.0 ? + fAcc : + mvOccupied->Vel < 0.01 ? + 0.0 : // already standing still so no need to bother with brakes + -2.0 ); // ruszanie albo hamowanie if ((a < fAcc) && (v == std::min(v, fNext))) { // mniejsze przyspieszenie to mniejsza możliwość rozpędzenia się albo konieczność hamowania @@ -4950,10 +4953,12 @@ TController::UpdateSituation(double dt) { // za radą yB ustawiamy pozycję 3 kranu (ruszanie kranem w innych miejscach // powino zostać wyłączone) // WriteLog("Zahamowanie składu"); - mvOccupied->BrakeLevelSet( - mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ? - 1 : - 3 ); + if( mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ) { + mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_EPB ) ); + } + else { + BrakeCtrlPosition = 3; + } double p = mvOccupied->BrakePressureActual.PipePressureVal; if( p < 3.9 ) { // tu może być 0 albo -1 nawet diff --git a/DynObj.cpp b/DynObj.cpp index d17294c3..41856d78 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -4332,6 +4332,20 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co mdLowPolyInt = TModelsManager::GetModel(asModel, true); } + else if(token == "loads:") { + // default load visualization models overrides + // content provided as "key: value" pairs together enclosed in "{}" + // value can be optionally set of values enclosed in "[]" in which case one value will be picked randomly + while( ( ( token = parser.getToken() ) != "" ) + && ( token != "}" ) ) { + if( token[ token.size() - 1 ] == ':' ) { + auto loadmodel { deserialize_random_set( parser ) }; + replace_slashes( loadmodel ); + LoadModelOverrides.emplace( token.erase( token.size() - 1 ), loadmodel ); + } + } + } + else if( token == "brakemode:" ) { // Ra 15-01: gałka nastawy hamulca parser.getTokens(); @@ -5644,8 +5658,17 @@ TDynamicObject::LoadMMediaFile_mdload( std::string const &Name ) const { if( Name.empty() ) { return nullptr; } - // try first specialized version of the load model, vehiclename_loadname TModel3d *loadmodel { nullptr }; + + // check if we don't have model override for this load type + auto const lookup { LoadModelOverrides.find( Name ) }; + if( lookup != LoadModelOverrides.end() ) { + loadmodel = TModelsManager::GetModel( asBaseDir + lookup->second, true ); + // if the override was succesfully loaded call it a day + if( loadmodel != nullptr ) { return loadmodel; } + } + // regular routine if there's no override or it couldn't be loaded + // try first specialized version of the load model, vehiclename_loadname auto const specializedloadfilename { asBaseDir + MoverParameters->TypeName + "_" + Name }; if( ( true == FileExists( specializedloadfilename + ".e3d" ) ) || ( true == FileExists( specializedloadfilename + ".t3d" ) ) ) { diff --git a/DynObj.h b/DynObj.h index 2ae80db9..f683cce9 100644 --- a/DynObj.h +++ b/DynObj.h @@ -202,6 +202,7 @@ public: bool JointCabs{ false }; // flag for vehicles with multiple virtual 'cabs' sharing location and 3d model(s) float fShade; // zacienienie: 0:normalnie, -1:w ciemności, +1:dodatkowe światło (brak koloru?) float LoadOffset { 0.f }; + std::unordered_map LoadModelOverrides; // potential overrides of default load visualization models glm::vec3 InteriorLight { 0.9f * 255.f / 255.f, 0.9f * 216.f / 255.f, 0.9f * 176.f / 255.f }; // tungsten light. TODO: allow definition of light type? float InteriorLightLevel { 0.0f }; // current level of interior lighting struct vehicle_section { diff --git a/audiorenderer.h b/audiorenderer.h index 22ec13f7..260d0850 100644 --- a/audiorenderer.h +++ b/audiorenderer.h @@ -172,9 +172,7 @@ openal_source::bind( sound_source *Controller, uint32_sequence Sounds, Iterator_ First, Last, [&]( audio::buffer_handle const &bufferhandle ) { auto const &buffer { audio::renderer.buffer( bufferhandle ) }; - buffers.emplace_back( buffer.id ); - if( false == buffer.caption.empty() ) { - ui::Transcripts.Add( buffer.caption ); } } ); + buffers.emplace_back( buffer.id ); } ); if( id != audio::null_resource ) { ::alSourceQueueBuffers( id, static_cast( buffers.size() ), buffers.data() ); diff --git a/driveruipanels.cpp b/driveruipanels.cpp index bcd5c623..8efa947d 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -211,7 +211,7 @@ scenario_panel::render() { auto const assignmentheader { locale::strings[ locale::string::driver_scenario_assignment ] }; if( ( false == owner->assignment().empty() ) && ( true == ImGui::CollapsingHeader( assignmentheader.c_str() ) ) ) { - ImGui::TextWrapped( owner->assignment().c_str() ); + ImGui::TextWrapped( "%s", owner->assignment().c_str() ); ImGui::Separator(); } } @@ -1003,10 +1003,8 @@ transcripts_panel::update() { text_lines.clear(); for( auto const &transcript : ui::Transcripts.aLines ) { - if( Global.fTimeAngleDeg >= transcript.fShow ) { - // NOTE: legacy transcript lines use | as new line mark - text_lines.emplace_back( ExchangeCharInString( transcript.asText, '|', ' ' ), colors::white ); - } + if( Global.fTimeAngleDeg + ( transcript.fShow - Global.fTimeAngleDeg > 180 ? 360 : 0 ) < transcript.fShow ) { continue; } + text_lines.emplace_back( ExchangeCharInString( transcript.asText, '|', ' ' ), colors::white ); } } @@ -1035,7 +1033,7 @@ transcripts_panel::render() { if( true == ImGui::Begin( panelname.c_str(), &is_open, flags ) ) { // header section for( auto const &line : text_lines ) { - ImGui::TextWrapped( line.data.c_str() ); + ImGui::TextWrapped( "%s", line.data.c_str() ); } } ImGui::End(); diff --git a/simulationenvironment.cpp b/simulationenvironment.cpp index 2bc27b25..f105faa2 100644 --- a/simulationenvironment.cpp +++ b/simulationenvironment.cpp @@ -92,6 +92,17 @@ world_environment::update() { // NOTE: sun light receives extra padding to prevent moon from kicking in too soon auto const sunlightlevel = m_sun.getIntensity() + 0.05f * ( 1.f - twilightfactor ); auto const moonlightlevel = m_moon.getIntensity() * 0.65f; // scaled down by arbitrary factor, it's pretty bright otherwise + + // ...update skydome to match the current sun position as well... + // twilight factor can be reset later down, so we do it here while it's still reflecting state of the sun + // turbidity varies from 2-3 during the day based on overcast, 3-4 after sunset to deal with sunlight bleeding too much into the sky from below horizon + m_skydome.SetTurbidity( + 2.f + + clamp( Global.Overcast, 0.f, 1.f ) + + interpolate( 0.f, 1.f, clamp( twilightfactor * 1.5f, 0.f, 1.f ) ) ); + m_skydome.SetOvercastFactor( Global.Overcast ); + m_skydome.Update( m_sun.getDirection() ); + float keylightintensity; glm::vec3 keylightcolor; if( moonlightlevel > sunlightlevel ) { @@ -117,9 +128,6 @@ world_environment::update() { glm::vec3( 235.0f / 255.0f, 140.0f / 255.0f, 36.0f / 255.0f ), duskfactor ); } - // ...update skydome to match the current sun position as well... - m_skydome.SetOvercastFactor( Global.Overcast ); - m_skydome.Update( m_sun.getDirection() ); // ...retrieve current sky colour and brightness... auto const skydomecolour = m_skydome.GetAverageColor(); auto const skydomehsv = colors::RGBtoHSV( skydomecolour ); diff --git a/skydome.cpp b/skydome.cpp index 020ead60..c09a0d37 100644 --- a/skydome.cpp +++ b/skydome.cpp @@ -169,7 +169,7 @@ bool CSkyDome::SetSunPosition( glm::vec3 const &Direction ) { void CSkyDome::SetTurbidity( float const Turbidity ) { - m_turbidity = clamp( Turbidity, 1.0f, 512.0f ); + m_turbidity = clamp( Turbidity, 1.f, 4.f ); } void CSkyDome::SetExposure( bool const Linearexposure, float const Expfactor ) { diff --git a/sound.cpp b/sound.cpp index 702c31f7..f3306e78 100644 --- a/sound.cpp +++ b/sound.cpp @@ -861,6 +861,13 @@ sound_source::update_counter( sound_handle const Sound, int const Value ) { // sound( Sound ).playing = std::max( 0, sound( Sound ).playing + Value ); sound( Sound ).playing += Value; + if( ( m_properties.gain > 0.f ) + && ( sound( Sound ).playing == 1 ) ) { + auto const &buffer { audio::renderer.buffer( sound( Sound ).buffer ) }; + if( false == buffer.caption.empty() ) { + ui::Transcripts.Add( buffer.caption ); + } + } assert( sound( Sound ).playing >= 0 ); } diff --git a/uitranscripts.cpp b/uitranscripts.cpp index d3abb0fe..02664a4a 100644 --- a/uitranscripts.cpp +++ b/uitranscripts.cpp @@ -17,11 +17,12 @@ TTranscripts::AddLine( std::string const &txt, float show, float hide, bool it ) if( show == hide ) { return; } // komentarz jest ignorowany + // TODO: replace the timeangledeg mess with regular time points math show = Global.fTimeAngleDeg + show / 240.0; // jeśli doba to 360, to 1s będzie równe 1/240 hide = Global.fTimeAngleDeg + hide / 240.0; TTranscript transcript; - transcript.asText = txt; + transcript.asText = ExchangeCharInString( txt, '|', ' ' ); // NOTE: legacy transcript lines use | as new line mark transcript.fShow = show; transcript.fHide = hide; transcript.bItalic = it; @@ -64,12 +65,25 @@ TTranscripts::Add( std::string const &txt, bool backgorund ) { void TTranscripts::Update() { + // HACK: detect day change + if( fRefreshTime - Global.fTimeAngleDeg > 180 ) { + fRefreshTime -= 360; + } + if( Global.fTimeAngleDeg < fRefreshTime ) { return; } // nie czas jeszcze na zmiany - while( ( false == aLines.empty() ) - && ( Global.fTimeAngleDeg >= aLines.front().fHide ) ) { - // remove expired lines - aLines.pop_front(); + // remove expired lines + while( false == aLines.empty() ) { + // HACK: detect day change + if( aLines.front().fHide - Global.fTimeAngleDeg > 180 ) { + aLines.front().fShow -= 360; + aLines.front().fHide -= 360; + } + if( Global.fTimeAngleDeg <= aLines.front().fHide ) { + // no expired lines yet + break; + } + aLines.pop_front(); // this line expired, discard it and start anew with the next one } // update next refresh time if( false == aLines.empty() ) { fRefreshTime = aLines.front().fHide; }