mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-22 22:09:19 +02:00
build 200728. basic train passenger information system, event condition diagnostics enhancement, ai door control logic fix
This commit is contained in:
54
Driver.cpp
54
Driver.cpp
@@ -986,6 +986,12 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
if( mvOccupied->Vel > 0.3 ) {
|
||||
// jeśli jedzie (nie trzeba czekać, aż się drgania wytłumią - drzwi zamykane od 1.0) to będzie zatrzymanie
|
||||
sSpeedTable[ i ].fVelNext = 0;
|
||||
// potentially announce pending stop
|
||||
if( ( m_lastannouncement != announcement_t::approaching )
|
||||
&& ( sSpeedTable[ i ].fDist < 750 )
|
||||
&& ( sSpeedTable[ i ].fDist > 250 ) ) {
|
||||
announce( announcement_t::approaching );
|
||||
}
|
||||
} else if( true == IsAtPassengerStop ) {
|
||||
// jeśli się zatrzymał przy W4, albo stał w momencie zobaczenia W4
|
||||
if( !AIControllFlag ) {
|
||||
@@ -1009,18 +1015,12 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
auto const platformside = static_cast<int>( std::floor( std::abs( sSpeedTable[ i ].evEvent->input_value( 2 ) ) ) ) % 10;
|
||||
auto const exchangetime = simulation::Station.update_load( pVehicles[ 0 ], TrainParams, platformside );
|
||||
WaitingSet( exchangetime );
|
||||
// announce the stop name while at it
|
||||
announce( announcement_t::current );
|
||||
m_lastexchangestop = asNextStop;
|
||||
m_makenextstopannouncement = true;
|
||||
}
|
||||
|
||||
if( false == TrainParams.IsMaintenance() )
|
||||
// && ( ( iDrivigFlags & moveDoorOpened ) == 0 ) )
|
||||
{
|
||||
// drzwi otwierać jednorazowo
|
||||
iDrivigFlags |= moveDoorOpened; // nie wykonywać drugi raz
|
||||
Doors( true, static_cast<int>( std::floor( std::abs( sSpeedTable[ i ].evEvent->input_value( 2 ) ) ) ) % 10 );
|
||||
}
|
||||
|
||||
|
||||
if (TrainParams.DirectionChange()) {
|
||||
// jeśli "@" w rozkładzie, to wykonanie dalszych komend
|
||||
// wykonanie kolejnej komendy, nie dotyczy ostatniej stacji
|
||||
@@ -1053,6 +1053,13 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
}
|
||||
}
|
||||
|
||||
if( ( false == TrainParams.IsMaintenance() )
|
||||
&& ( ( false == TestFlag( iDrivigFlags, moveDoorOpened ) )
|
||||
|| ( true == DoesAnyDoorNeedOpening ) ) ) {
|
||||
iDrivigFlags |= moveDoorOpened; // nie wykonywać drugi raz
|
||||
Doors( true, static_cast<int>( std::floor( std::abs( sSpeedTable[ i ].evEvent->input_value( 2 ) ) ) ) % 10 );
|
||||
}
|
||||
|
||||
if (OrderCurrentGet() & ( Shunt | Loose_shunt )) {
|
||||
OrderNext(Obey_train); // uruchomić jazdę pociągową
|
||||
CheckVehicles(); // zmienić światła
|
||||
@@ -4184,6 +4191,23 @@ TController::doors_permit_active() const {
|
||||
|| IsAnyDoorPermitActive[ side::left ] );
|
||||
}
|
||||
|
||||
void
|
||||
TController::announce( announcement_t const Announcement ) {
|
||||
|
||||
m_lastannouncement = Announcement;
|
||||
|
||||
if( IsCargoTrain ) {
|
||||
// cargo trains aren't likely to have announcement systems, so we can skip the procedure altogether
|
||||
return;
|
||||
}
|
||||
|
||||
auto *vehicle { pVehicles[ end::front ] };
|
||||
while( vehicle ) {
|
||||
vehicle->announce( Announcement );
|
||||
vehicle = vehicle->Next();
|
||||
}
|
||||
}
|
||||
|
||||
void TController::RecognizeCommand()
|
||||
{ // odczytuje i wykonuje komendę przekazaną lokomotywie
|
||||
TCommand *c = &mvOccupied->CommandIn;
|
||||
@@ -4268,6 +4292,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
|
||||
TrainParams.StationIndexInc(); // przejście do następnej
|
||||
iStationStart = TrainParams.StationIndex;
|
||||
asNextStop = TrainParams.NextStop();
|
||||
m_lastannouncement = announcement_t::idle;
|
||||
iDrivigFlags |= movePrimary; // skoro dostał rozkład, to jest teraz głównym
|
||||
// NewCommand = Global.asCurrentSceneryPath + NewCommand;
|
||||
auto lookup =
|
||||
@@ -4294,7 +4319,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
|
||||
NewCommand = TrainParams.Relation2; // relacja docelowa z rozkładu
|
||||
}
|
||||
// jeszcze poustawiać tekstury na wyświetlaczach
|
||||
TDynamicObject *p = pVehicles[0];
|
||||
TDynamicObject *p = pVehicles[end::front];
|
||||
while (p)
|
||||
{
|
||||
p->DestinationSet(NewCommand, TrainParams.TrainName); // relacja docelowa
|
||||
@@ -4726,6 +4751,10 @@ TController::UpdateSituation(double dt) {
|
||||
// zaktualizować wyświetlanie rozkładu
|
||||
iStationStart = TrainParams.StationIndex;
|
||||
fLastStopExpDist = -1.0; // usunąć licznik
|
||||
if( true == m_makenextstopannouncement ) {
|
||||
announce( announcement_t::next );
|
||||
m_makenextstopannouncement = false; // keep next stop announcements suppressed until another scheduled stop
|
||||
}
|
||||
}
|
||||
|
||||
// ABu-160305 testowanie gotowości do jazdy
|
||||
@@ -5960,6 +5989,7 @@ TController::UpdateSituation(double dt) {
|
||||
VelforDriver );
|
||||
}
|
||||
// recalculate potential load exchange duration
|
||||
DoesAnyDoorNeedOpening = false;
|
||||
ExchangeTime = 0.f;
|
||||
if( fStopTime < 0 ) {
|
||||
// czas postoju przed dalszą jazdą (np. na przystanku)
|
||||
@@ -5967,7 +5997,9 @@ TController::UpdateSituation(double dt) {
|
||||
// verify progress of load exchange
|
||||
auto *vehicle { pVehicles[ 0 ] };
|
||||
while( vehicle != nullptr ) {
|
||||
ExchangeTime = std::max( ExchangeTime, vehicle->LoadExchangeTime() );
|
||||
auto const vehicleexchangetime { vehicle->LoadExchangeTime() };
|
||||
DoesAnyDoorNeedOpening |= ( ( vehicleexchangetime > 0 ) && ( vehicle->LoadExchangeSpeed() == 0 ) );
|
||||
ExchangeTime = std::max( ExchangeTime, vehicleexchangetime );
|
||||
vehicle = vehicle->Next();
|
||||
}
|
||||
if( ( ExchangeTime > 0 )
|
||||
|
||||
4
Driver.h
4
Driver.h
@@ -454,6 +454,8 @@ private:
|
||||
int iRadioChannel = 1; // numer aktualnego kanału radiowego
|
||||
int iGuardRadio = 0; // numer kanału radiowego kierownika (0, gdy nie używa radia)
|
||||
sound_source tsGuardSignal{ sound_placement::internal };
|
||||
announcement_t m_lastannouncement{ announcement_t::idle };
|
||||
bool m_makenextstopannouncement{ false };
|
||||
|
||||
// consist
|
||||
// methods
|
||||
@@ -468,6 +470,7 @@ private:
|
||||
bool doors_permit_active() const;
|
||||
void AutoRewident(); // ustawia hamulce w składzie
|
||||
void UpdatePantographs();
|
||||
void announce( announcement_t const Announcement );
|
||||
// members
|
||||
double fLength = 0.0; // długość składu (do wyciągania z ograniczeń)
|
||||
double fMass = 0.0; // całkowita masa do liczenia stycznej składowej grawitacji
|
||||
@@ -482,6 +485,7 @@ private:
|
||||
bool Ready = false; // ABu: stan gotowosci do odjazdu - sprawdzenie odhamowania wagonow
|
||||
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 DoesAnyDoorNeedOpening{ false };
|
||||
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
|
||||
|
||||
144
DynObj.cpp
144
DynObj.cpp
@@ -29,6 +29,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "renderer.h"
|
||||
#include "uitranscripts.h"
|
||||
#include "messaging.h"
|
||||
#include "Driver.h"
|
||||
|
||||
// Ra: taki zapis funkcjonuje lepiej, ale może nie jest optymalny
|
||||
#define vWorldFront Math3D::vector3(0, 0, 1)
|
||||
@@ -2022,7 +2023,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
||||
}
|
||||
} // koniec hamulce
|
||||
else if( ( ActPar.size() >= 3 )
|
||||
&& ( ActPar[ 0 ] == 'W' ) ) {
|
||||
&& ( ActPar.front() == 'W' ) ) {
|
||||
// wheel
|
||||
ActPar.erase( 0, 1 );
|
||||
|
||||
@@ -2032,7 +2033,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
||||
|
||||
while( false == ActPar.empty() ) {
|
||||
// TODO: convert this whole copy and paste mess to something more elegant one day
|
||||
switch( ActPar[ 0 ] ) {
|
||||
switch( ActPar.front() ) {
|
||||
case 'F': {
|
||||
// fixed flat size
|
||||
auto const indexstart { 1 };
|
||||
@@ -2078,14 +2079,14 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
||||
}
|
||||
} // wheel
|
||||
else if( ( ActPar.size() >= 2 )
|
||||
&& ( ActPar[ 0 ] == 'T' ) ) {
|
||||
&& ( ActPar.front() == 'T' ) ) {
|
||||
// temperature
|
||||
ActPar.erase( 0, 1 );
|
||||
|
||||
auto setambient { false };
|
||||
|
||||
while( false == ActPar.empty() ) {
|
||||
switch( ActPar[ 0 ] ) {
|
||||
switch( ActPar.front() ) {
|
||||
case 'A': {
|
||||
// cold start, set all temperatures to ambient level
|
||||
setambient = true;
|
||||
@@ -4304,7 +4305,7 @@ void TDynamicObject::RenderSounds() {
|
||||
// NBMX sygnal odjazdu
|
||||
if( MoverParameters->Doors.has_warning ) {
|
||||
auto const lowvoltagepower { MoverParameters->Power24vIsAvailable || MoverParameters->Power110vIsAvailable };
|
||||
for( auto &departuresignalsound : m_departuresignalsounds ) {
|
||||
for( auto &speaker : m_speakers ) {
|
||||
// TBD, TODO: per-location door state triggers?
|
||||
if( ( MoverParameters->DepartureSignal )
|
||||
&& ( lowvoltagepower )
|
||||
@@ -4316,13 +4317,32 @@ void TDynamicObject::RenderSounds() {
|
||||
) {
|
||||
// for the autonomous doors play the warning automatically whenever a door is closing
|
||||
// MC: pod warunkiem ze jest zdefiniowane w chk
|
||||
departuresignalsound.play( sound_flags::exclusive | sound_flags::looping );
|
||||
speaker.departure_signal.play( sound_flags::exclusive | sound_flags::looping );
|
||||
}
|
||||
else {
|
||||
departuresignalsound.stop();
|
||||
speaker.departure_signal.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
// announcements
|
||||
for( auto &speaker : m_speakers ) {
|
||||
auto const lowvoltagepower { MoverParameters->Power24vIsAvailable || MoverParameters->Power110vIsAvailable };
|
||||
if( lowvoltagepower ) {
|
||||
// speaker is powered up, can play queued announcements
|
||||
if( speaker.announcement.is_playing() ) { continue; }
|
||||
if( speaker.announcement_queue.empty() ) { continue; }
|
||||
// pull first sound from the queue
|
||||
speaker.announcement = speaker.announcement_queue.front();
|
||||
speaker.announcement.owner( this );
|
||||
speaker.announcement.offset( speaker.offset );
|
||||
speaker.announcement.play();
|
||||
speaker.announcement_queue.pop_front();
|
||||
}
|
||||
else {
|
||||
speaker.announcement.stop();
|
||||
speaker.announcement_queue.clear();
|
||||
}
|
||||
}
|
||||
// NBMX Obsluga drzwi, MC: zuniwersalnione
|
||||
std::array<side, 2> const sides { side::right, side::left };
|
||||
for( auto const side : sides ) {
|
||||
@@ -4747,15 +4767,13 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
||||
parser.getTokens();
|
||||
parser >> asModel;
|
||||
replace_slashes( asModel );
|
||||
if( asModel[asModel.size() - 1] == '#' ) // Ra 2015-01: nie podoba mi siê to
|
||||
if( asModel.back() == '#' ) // Ra 2015-01: nie podoba mi siê to
|
||||
{ // model wymaga wielu tekstur wymiennych
|
||||
m_materialdata.multi_textures = 1;
|
||||
asModel.erase( asModel.length() - 1 );
|
||||
}
|
||||
// name can contain leading slash, erase it to avoid creation of double slashes when the name is combined with current directory
|
||||
if( asModel[ 0 ] == '/' ) {
|
||||
asModel.erase( 0, 1 );
|
||||
}
|
||||
erase_leading_slashes( asModel );
|
||||
/*
|
||||
// never really used, may as well get rid of it
|
||||
std::size_t i = asModel.find( ',' );
|
||||
@@ -4871,7 +4889,7 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
||||
// value can be optionally set of values enclosed in "[]" in which case one value will be picked randomly
|
||||
while( ( ( token = parser.getToken<std::string>() ) != "" )
|
||||
&& ( token != "}" ) ) {
|
||||
if( token[ token.size() - 1 ] == ':' ) {
|
||||
if( token.back() == ':' ) {
|
||||
auto loadmodel { deserialize_random_set( parser ) };
|
||||
replace_slashes( loadmodel );
|
||||
LoadModelOverrides.emplace( token.erase( token.size() - 1 ), loadmodel );
|
||||
@@ -5694,14 +5712,12 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
||||
|
||||
else if( token == "departuresignal:" ) {
|
||||
// pliki z sygnalem odjazdu
|
||||
sound_source soundtemplate { sound_placement::general };
|
||||
sound_source soundtemplate { sound_placement::general, 25.f };
|
||||
soundtemplate.deserialize( parser, sound_type::multipart, sound_parameters::range );
|
||||
soundtemplate.owner( this );
|
||||
for( auto &departuresignalsound : m_departuresignalsounds ) {
|
||||
// apply configuration to all defined doors, but preserve their individual offsets
|
||||
auto const soundoffset { departuresignalsound.offset() };
|
||||
departuresignalsound = soundtemplate;
|
||||
departuresignalsound.offset( soundoffset );
|
||||
for( auto &speaker : m_speakers ) {
|
||||
speaker.departure_signal = soundtemplate;
|
||||
speaker.departure_signal.offset( speaker.offset );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5844,6 +5860,38 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
||||
m_wheelflat.owner( this );
|
||||
}
|
||||
|
||||
else if(token == "announcements:") {
|
||||
// announcement sounds
|
||||
// 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
|
||||
std::array<sound_source, static_cast<int>( announcement_t::end )> announcementsounds;
|
||||
std::unordered_map<std::string, announcement_t> const announcements = {
|
||||
{ "near_stop:", announcement_t::approaching },
|
||||
{ "stop:", announcement_t::current },
|
||||
{ "next_stop:", announcement_t::next },
|
||||
{ "destination:", announcement_t::destination } };
|
||||
while( ( ( token = parser.getToken<std::string>() ) != "" )
|
||||
&& ( token != "}" ) ) {
|
||||
if( token.back() == ':' ) {
|
||||
auto const lookup { announcements.find( token ) };
|
||||
auto const announcementtype { (
|
||||
lookup != announcements.end() ?
|
||||
lookup->second :
|
||||
announcement_t::idle ) };
|
||||
// NOTE: we retrieve key value for all keys, not just recognized ones
|
||||
auto announcementsound{ deserialize_random_set( parser ) };
|
||||
replace_slashes( announcementsound );
|
||||
if( announcementtype == announcement_t::idle ) {
|
||||
continue;
|
||||
}
|
||||
sound_source soundtemplate { sound_placement::general, EU07_SOUND_CABANNOUNCEMENTCUTOFFRANGE };
|
||||
soundtemplate.deserialize( announcementsound, sound_type::single );
|
||||
soundtemplate.owner( this );
|
||||
m_announcements[ static_cast<int>( announcementtype ) ] = soundtemplate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while( ( token != "" )
|
||||
&& ( token != "endsounds" ) );
|
||||
|
||||
@@ -5891,10 +5939,11 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
||||
door.step_open.offset( location );
|
||||
m_doorsounds.emplace_back( door );
|
||||
}
|
||||
// potential departure sound, one per door (pair) on vehicle centreline
|
||||
sound_source departuresignalsound { sound_placement::general, 25.f };
|
||||
departuresignalsound.offset( glm::vec3{ 0.f, 3.f, offset } );
|
||||
m_departuresignalsounds.emplace_back( departuresignalsound );
|
||||
m_speakers.emplace_back(
|
||||
speaker_sounds {
|
||||
{ 0.f, 3.f, offset },
|
||||
{},
|
||||
{} } );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7009,6 +7058,57 @@ material_handle TDynamicObject::DestinationFind( std::string Destination ) {
|
||||
return destinationhandle;
|
||||
}
|
||||
|
||||
void TDynamicObject::announce( announcement_t const Announcement ) {
|
||||
|
||||
if( m_speakers.empty() ) { return; }
|
||||
|
||||
auto const *driver { (
|
||||
ctOwner != nullptr ?
|
||||
ctOwner :
|
||||
Mechanik ) };
|
||||
if( driver == nullptr ) { return; }
|
||||
|
||||
auto const &timetable { driver->TrainTimetable() };
|
||||
|
||||
if( m_announcements[ static_cast<int>( Announcement ) ].empty() ) {
|
||||
goto followup;
|
||||
}
|
||||
// if the announcement sound was defined queue playback
|
||||
{
|
||||
sound_source stopnamesound;
|
||||
switch( Announcement ) {
|
||||
case announcement_t::approaching:
|
||||
case announcement_t::next: {
|
||||
stopnamesound = timetable.next_stop_sound();
|
||||
break;
|
||||
}
|
||||
case announcement_t::current: {
|
||||
stopnamesound = timetable.current_stop_sound();
|
||||
break;
|
||||
}
|
||||
case announcement_t::destination: {
|
||||
stopnamesound = timetable.last_stop_sound();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( stopnamesound.empty() ) {
|
||||
goto followup;
|
||||
}
|
||||
for( auto &speaker : m_speakers ) {
|
||||
speaker.announcement_queue.emplace_back( m_announcements[ static_cast<int>( Announcement ) ] );
|
||||
speaker.announcement_queue.emplace_back( stopnamesound );
|
||||
}
|
||||
}
|
||||
followup:
|
||||
// potentially follow up with another announcement
|
||||
if( Announcement == announcement_t::next ) {
|
||||
announce( announcement_t::destination );
|
||||
}
|
||||
}
|
||||
|
||||
void TDynamicObject::OverheadTrack(float o)
|
||||
{ // ewentualne wymuszanie jazdy
|
||||
// bezprądowej z powodu informacji
|
||||
|
||||
21
DynObj.h
21
DynObj.h
@@ -150,6 +150,15 @@ public:
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
enum class announcement_t : int {
|
||||
idle = 0,
|
||||
approaching,
|
||||
current,
|
||||
next,
|
||||
destination,
|
||||
end
|
||||
};
|
||||
|
||||
// parameters for the material object, as currently used by various simulator models
|
||||
struct material_data {
|
||||
|
||||
@@ -395,6 +404,13 @@ private:
|
||||
void position( glm::vec3 const Location );
|
||||
void render( TMoverParameters const &Vehicle, double const Deltatime );
|
||||
};
|
||||
// single source per door (pair) on the centreline
|
||||
struct speaker_sounds {
|
||||
glm::vec3 offset;
|
||||
sound_source departure_signal;
|
||||
sound_source announcement;
|
||||
std::deque<sound_source> announcement_queue; // fifo queue
|
||||
};
|
||||
|
||||
// methods
|
||||
void ABuLittleUpdate(double ObjSqrDist);
|
||||
@@ -476,7 +492,6 @@ private:
|
||||
std::array<coupler_sounds, 2> m_couplersounds; // always front and rear
|
||||
std::vector<pantograph_sounds> m_pantographsounds; // typically 2 but can be less (or more?)
|
||||
std::vector<door_sounds> m_doorsounds; // can expect symmetrical arrangement, but don't count on it
|
||||
std::vector<sound_source> m_departuresignalsounds; // single source per door (pair) on the centreline
|
||||
bool m_doorlocks { false }; // sound helper, current state of door locks
|
||||
sound_source sHorn1 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
||||
sound_source sHorn2 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
||||
@@ -493,6 +508,9 @@ private:
|
||||
exchange_data m_exchange; // state of active load exchange procedure, if any
|
||||
exchange_sounds m_exchangesounds; // sounds associated with the load exchange
|
||||
|
||||
std::vector<speaker_sounds> m_speakers;
|
||||
std::array<sound_source, static_cast<int>( announcement_t::end )> m_announcements;
|
||||
|
||||
coupleradapter_data m_coupleradapter;
|
||||
|
||||
bool renderme; // yB - czy renderowac
|
||||
@@ -702,6 +720,7 @@ private:
|
||||
void OverheadTrack(float o);
|
||||
glm::dvec3 get_future_movement() const;
|
||||
void move_set(double distance);
|
||||
void announce( announcement_t const Announcement );
|
||||
|
||||
double MED[9][8]; // lista zmiennych do debugowania hamulca ED
|
||||
static std::string const MED_labels[ 8 ];
|
||||
|
||||
37
Event.cpp
37
Event.cpp
@@ -74,18 +74,51 @@ basic_event::event_conditions::test() const {
|
||||
}
|
||||
}
|
||||
if( flags & flags::track_busy ) {
|
||||
auto trackbusyresult { true };
|
||||
std::string trackbusylog { "Test: Track busy - " };
|
||||
for( auto *track : tracks ) {
|
||||
if( true == track->IsEmpty() ) {
|
||||
return false;
|
||||
trackbusylog += "[" + track->name() + "]";
|
||||
trackbusyresult = false;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
auto const &vehicles { track->Dynamics };
|
||||
if( trackbusylog.back() == ']' ) {
|
||||
trackbusylog += ", ";
|
||||
}
|
||||
trackbusylog += "[" + vehicles.front()->asName + "] @ [" + track->name() + "]";
|
||||
}
|
||||
}
|
||||
|
||||
WriteLog(
|
||||
trackbusylog
|
||||
+ " - "
|
||||
+ ( trackbusyresult ? "Pass" : "Fail" ) );
|
||||
|
||||
if( false == trackbusyresult ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if( flags & flags::track_free ) {
|
||||
auto trackfreeresult { true };
|
||||
std::string trackfreelog{ "Test: Track free - " };
|
||||
for( auto *track : tracks ) {
|
||||
if( false == track->IsEmpty() ) {
|
||||
return false;
|
||||
auto const &vehicles { track->Dynamics };
|
||||
trackfreelog += "[" + vehicles.front()->asName + "] @ [" + track->name() + "] - ";
|
||||
trackfreeresult = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WriteLog(
|
||||
trackfreelog
|
||||
+ ( trackfreeresult ? "Pass" : "Fail" ) );
|
||||
|
||||
if( false == trackfreeresult ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if( flags & ( flags::text | flags::value1 | flags::value2 ) ) {
|
||||
// porównanie wartości
|
||||
|
||||
@@ -9146,7 +9146,7 @@ bool TMoverParameters::LoadFIZ(std::string chkpath)
|
||||
continue;
|
||||
}
|
||||
|
||||
if( inputline[ 0 ] == ' ' ) {
|
||||
if( !inputline.empty() && inputline.front() == ' ' ) {
|
||||
// guard against malformed config files with leading spaces
|
||||
inputline.erase( 0, inputline.find_first_not_of( ' ' ) );
|
||||
}
|
||||
|
||||
@@ -511,7 +511,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
|
||||
// zapewni to jakąś zgodność wstecz, bo zamiast liczby będzie ciąg, którego
|
||||
// wartość powinna być uznana jako zerowa
|
||||
// parser.getToken(iNumVerts);
|
||||
if (token[0] == '*')
|
||||
if (token.front() == '*')
|
||||
{ // jeśli pierwszy znak jest gwiazdką, poszukać
|
||||
// submodelu o nazwie bez tej gwiazdki i wziąć z
|
||||
// niego wierzchołki
|
||||
|
||||
@@ -1181,7 +1181,7 @@ texture_manager::create( std::string Filename, bool const Loadnow, GLint Formath
|
||||
replace_slashes( Filename );
|
||||
erase_leading_slashes( Filename );
|
||||
// temporary code for legacy assets -- textures with names beginning with # are to be sharpened
|
||||
if( ( Filename[ 0 ] == '#' )
|
||||
if( ( Filename.front() == '#' )
|
||||
|| ( Filename.find( "/#" ) != std::string::npos ) ) {
|
||||
traits += '#';
|
||||
}
|
||||
|
||||
@@ -7926,9 +7926,7 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
||||
// szukaj kabinę jako oddzielny model
|
||||
// name can contain leading slash, erase it to avoid creation of double slashes when the name is combined with current directory
|
||||
replace_slashes( token );
|
||||
if( token[ 0 ] == '/' ) {
|
||||
token.erase( 0, 1 );
|
||||
}
|
||||
erase_leading_slashes( token );
|
||||
TModel3d *kabina = TModelsManager::GetModel(DynamicObject->asBaseDir + token, true);
|
||||
// z powrotem defaultowa sciezka do tekstur
|
||||
Global.asCurrentTexturePath = szTexturePath;
|
||||
|
||||
110
mtable.cpp
110
mtable.cpp
@@ -42,28 +42,65 @@ std::string TTrainParameters::NextStop() const
|
||||
return "[End of route]"; //że niby koniec
|
||||
}
|
||||
|
||||
sound_source
|
||||
TTrainParameters::next_stop_sound() const {
|
||||
if( StationIndex > StationCount ) {
|
||||
return { sound_placement::general };
|
||||
}
|
||||
for( auto stationidx { StationIndex }; stationidx < StationCount + 1; ++stationidx ) {
|
||||
auto &station{ TimeTable[ stationidx ] };
|
||||
if( station.Ah == -1 ) {
|
||||
continue;
|
||||
}
|
||||
// specified arrival time means it's a scheduled stop
|
||||
return station.name_sound;
|
||||
}
|
||||
// shouldn't normally get here, unless the timetable is malformed
|
||||
return { sound_placement::general };
|
||||
}
|
||||
|
||||
sound_source
|
||||
TTrainParameters::last_stop_sound() const {
|
||||
|
||||
return TimeTable[ StationCount ].name_sound;
|
||||
}
|
||||
|
||||
bool TTrainParameters::IsStop() const
|
||||
{ // zapytanie, czy zatrzymywać na następnym punkcie rozkładu
|
||||
if ((StationIndex < StationCount))
|
||||
if ((StationIndex <= StationCount))
|
||||
return TimeTable[StationIndex].Ah >= 0; //-1 to brak postoju
|
||||
else
|
||||
return true; // na ostatnim się zatrzymać zawsze
|
||||
}
|
||||
|
||||
bool TTrainParameters::IsLastStop() const {
|
||||
|
||||
return ( StationIndex >= StationCount );
|
||||
}
|
||||
|
||||
|
||||
bool TTrainParameters::IsMaintenance() const {
|
||||
if( ( StationIndex < StationCount ) )
|
||||
if( ( StationIndex <= StationCount ) )
|
||||
return TimeTable[ StationIndex ].is_maintenance;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
int TTrainParameters::radio_channel() const {
|
||||
if( ( StationIndex < StationCount ) )
|
||||
if( ( StationIndex <= StationCount ) )
|
||||
return TimeTable[ StationIndex ].radio_channel;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
// returns: sound file associated with current station, or -1
|
||||
sound_source TTrainParameters::current_stop_sound() const {
|
||||
if( ( StationIndex <= StationCount ) )
|
||||
return TimeTable[ StationIndex ].name_sound;
|
||||
else
|
||||
return { sound_placement::general };
|
||||
}
|
||||
|
||||
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 );
|
||||
@@ -421,7 +458,7 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax)
|
||||
{
|
||||
auto const stationware { Split( record->StationWare, ',' ) };
|
||||
for( auto const &entry : stationware ) {
|
||||
if( entry[ 0 ] == 'R' ) {
|
||||
if( entry.front() == 'R' ) {
|
||||
auto const entrysplit { split_string_and_number( entry ) };
|
||||
if( ( entrysplit.first == "R" )
|
||||
&& ( entrysplit.second <= 10 ) ) {
|
||||
@@ -507,9 +544,10 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax)
|
||||
TimeTable[1].Ah = TimeTable[1].Dh;
|
||||
TimeTable[1].Am = TimeTable[1].Dm;
|
||||
}
|
||||
// NextStationName:=TimeTable[1].StationName;
|
||||
/* TTVmax:=TimeTable[1].vmax; */
|
||||
}
|
||||
//
|
||||
load_sounds();
|
||||
// potentially offset table times
|
||||
auto const timeoffset { static_cast<int>( Global.ScenarioTimeOffset * 60 ) + iPlus };
|
||||
if( timeoffset != 0 ) // jeżeli jest przesunięcie rozkładu
|
||||
{
|
||||
@@ -534,24 +572,31 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax)
|
||||
return ConversionError == 0;
|
||||
}
|
||||
|
||||
void TMTableTime::UpdateMTableTime(double deltaT)
|
||||
// dodanie czasu (deltaT) w sekundach, z przeliczeniem godziny
|
||||
{
|
||||
mr += deltaT; // dodawanie sekund
|
||||
while (mr >= 60.0) // przeliczenie sekund do właściwego przedziału
|
||||
{
|
||||
mr -= 60.0;
|
||||
++mm;
|
||||
void
|
||||
TTrainParameters::load_sounds() {
|
||||
|
||||
for( auto stationidx = 1; stationidx < StationCount + 1; ++stationidx ) {
|
||||
auto &station { TimeTable[ stationidx ] };
|
||||
if( station.Ah == -1 ) {
|
||||
continue;
|
||||
}
|
||||
while (mm > 59) // przeliczenie minut do właściwego przedziału
|
||||
{
|
||||
mm -= 60;
|
||||
++hh;
|
||||
// specified arrival time means it's a scheduled stop
|
||||
auto const stationname { (
|
||||
ends_with( station.StationName, "_po" ) ?
|
||||
station.StationName.substr( 0, station.StationName.size() - 3 ) :
|
||||
station.StationName ) };
|
||||
|
||||
auto const lookup {
|
||||
FileExists(
|
||||
{ Global.asCurrentSceneryPath + stationname, std::string{ szSoundPath } + "sip/" + stationname },
|
||||
{ ".ogg", ".flac", ".wav" } ) };
|
||||
if( lookup.first.empty() ) {
|
||||
continue;
|
||||
}
|
||||
while (hh > 23) // przeliczenie godzin do właściwego przedziału
|
||||
{
|
||||
hh -= 24;
|
||||
++dd; // zwiększenie numeru dnia
|
||||
// wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie)
|
||||
station.name_sound =
|
||||
sound_source{ sound_placement::general, EU07_SOUND_CABANNOUNCEMENTCUTOFFRANGE }
|
||||
.deserialize( lookup.first + lookup.second, sound_type::single );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,3 +637,24 @@ void TTrainParameters::serialize( dictionary_source *Output ) const {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TMTableTime::UpdateMTableTime(double deltaT)
|
||||
// dodanie czasu (deltaT) w sekundach, z przeliczeniem godziny
|
||||
{
|
||||
mr += deltaT; // dodawanie sekund
|
||||
while (mr >= 60.0) // przeliczenie sekund do właściwego przedziału
|
||||
{
|
||||
mr -= 60.0;
|
||||
++mm;
|
||||
}
|
||||
while (mm > 59) // przeliczenie minut do właściwego przedziału
|
||||
{
|
||||
mm -= 60;
|
||||
++hh;
|
||||
}
|
||||
while (hh > 23) // przeliczenie godzin do właściwego przedziału
|
||||
{
|
||||
hh -= 24;
|
||||
++dd; // zwiększenie numeru dnia
|
||||
}
|
||||
}
|
||||
|
||||
9
mtable.h
9
mtable.h
@@ -12,6 +12,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include <string>
|
||||
|
||||
#include "Classes.h"
|
||||
#include "sound.h"
|
||||
|
||||
namespace Mtable
|
||||
{
|
||||
@@ -38,6 +39,7 @@ struct TMTableLine
|
||||
float tm{ 0.f }; // czas jazdy do tej stacji w min. (z kolumny)
|
||||
bool is_maintenance{ false };
|
||||
int radio_channel{ -1 };
|
||||
sound_source name_sound{ sound_placement::internal };
|
||||
};
|
||||
|
||||
typedef TMTableLine TMTable[MaxTTableSize + 1];
|
||||
@@ -65,7 +67,10 @@ class TTrainParameters
|
||||
std::string ShowRelation() const;
|
||||
double WatchMTable(double DistCounter);
|
||||
std::string NextStop() const;
|
||||
sound_source next_stop_sound() const;
|
||||
sound_source last_stop_sound() const;
|
||||
bool IsStop() const;
|
||||
bool IsLastStop() const;
|
||||
bool IsMaintenance() const;
|
||||
bool IsTimeToGo(double hh, double mm);
|
||||
bool UpdateMTable(double hh, double mm, std::string const &NewName);
|
||||
@@ -80,6 +85,10 @@ class TTrainParameters
|
||||
void serialize( dictionary_source *Output ) const;
|
||||
// returns: radio channel associated with current station, or -1
|
||||
int radio_channel() const;
|
||||
// returns: sound file associated with current station, or -1
|
||||
sound_source current_stop_sound() const;
|
||||
private:
|
||||
void load_sounds();
|
||||
};
|
||||
|
||||
class TMTableTime
|
||||
|
||||
3
sound.h
3
sound.h
@@ -15,6 +15,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
float const EU07_SOUND_GLOBALRANGE { -1.f };
|
||||
float const EU07_SOUND_CABCONTROLSCUTOFFRANGE { 7.5f };
|
||||
float const EU07_SOUND_CABANNOUNCEMENTCUTOFFRANGE{ 30.f };
|
||||
float const EU07_SOUND_BRAKINGCUTOFFRANGE { 100.f };
|
||||
float const EU07_SOUND_RUNNINGNOISECUTOFFRANGE { 200.f };
|
||||
float const EU07_SOUND_HANDHELDRADIORANGE { 3500.f };
|
||||
@@ -50,7 +51,7 @@ class sound_source {
|
||||
|
||||
public:
|
||||
// constructors
|
||||
sound_source( sound_placement const Placement, float const Range = 50.f );
|
||||
sound_source( sound_placement const Placement = sound_placement::general, float const Range = 50.f );
|
||||
|
||||
// destructor
|
||||
~sound_source();
|
||||
|
||||
@@ -459,6 +459,14 @@ len_common_prefix( std::string const &Left, std::string const &Right ) {
|
||||
std::distance( left, std::mismatch( left, left + Left.size(), right ).first ) );
|
||||
}
|
||||
|
||||
// returns true if provided string ends with another provided string
|
||||
bool
|
||||
ends_with( std::string const &String, std::string const &Suffix ) {
|
||||
|
||||
return ( String.size() >= Suffix.size() )
|
||||
&& ( 0 == String.compare( String.size() - Suffix.size(), Suffix.size(), Suffix ) );
|
||||
}
|
||||
|
||||
// helper, restores content of a 3d vector from provided input stream
|
||||
// TODO: review and clean up the helper routines, there's likely some redundant ones
|
||||
glm::dvec3 LoadPoint( cParser &Input ) {
|
||||
|
||||
@@ -216,6 +216,9 @@ std::string substr_path( std::string const &Filename );
|
||||
// returns common prefix of two provided strings
|
||||
std::ptrdiff_t len_common_prefix( std::string const &Left, std::string const &Right );
|
||||
|
||||
// returns true if provided string ends with another provided string
|
||||
bool ends_with( std::string const &String, std::string const &Suffix );
|
||||
|
||||
template <typename Type_>
|
||||
void SafeDelete( Type_ &Pointer ) {
|
||||
delete Pointer;
|
||||
|
||||
Reference in New Issue
Block a user