From 38591a09f2a38a881e32d46977f11b07df338464 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Wed, 19 Sep 2018 19:12:53 +0200 Subject: [PATCH] basic cargo attributes system, minor cargo enhancements and fixes --- DynObj.cpp | 147 +++++++++-------------- DynObj.h | 5 +- Event.cpp | 8 +- McZapkie/MOVER.h | 28 +++-- McZapkie/Mover.cpp | 289 +++++++++++++++++++++++++-------------------- Model3d.cpp | 4 +- driveruipanels.cpp | 4 +- station.cpp | 13 +- 8 files changed, 253 insertions(+), 245 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index 1c9da755..1c8b4267 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -1783,7 +1783,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" asBaseDir = szDynamicPath + BaseDir + "/"; // McZapkie-310302 replace_slashes( asBaseDir ); asName = Name; - std::string asAnimName = ""; // zmienna robocza do wyszukiwania osi i wózków + std::string asAnimName; // zmienna robocza do wyszukiwania osi i wózków // Ra: zmieniamy znaczenie obsady na jednoliterowe, żeby dosadzić kierownika if (DriverType == "headdriver") DriverType = "1"; // sterujący kabiną +1 @@ -1810,7 +1810,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" } */ // utworzenie parametrów fizyki - MoverParameters = new TMoverParameters(iDirection ? fVel : -fVel, Type_Name, asName, Load, LoadType, Cab); + MoverParameters = new TMoverParameters(iDirection ? fVel : -fVel, Type_Name, asName, Cab); iLights = MoverParameters->iLights; // wskaźnik na stan własnych świateł // McZapkie: TypeName musi byc nazwą CHK/MMD pojazdu if (!MoverParameters->LoadFIZ(asBaseDir)) @@ -1822,6 +1822,9 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" } return 0.0; // zerowa długość to brak pojazdu } + // load the cargo now that we know whether the vehicle will allow it + MoverParameters->AssignLoad( LoadType, Load ); + bool driveractive = (fVel != 0.0); // jeśli prędkość niezerowa, to aktywujemy ruch if (!MoverParameters->CheckLocomotiveParameters( driveractive, @@ -2095,7 +2098,8 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" iAxles = std::min( MoverParameters->NAxles, MaxAxles ); // ilość osi */ // wczytywanie z pliku nazwatypu.mmd, w tym model - LoadMMediaFile(asBaseDir, Type_Name, asReplacableSkin); + erase_extension( asReplacableSkin ); + LoadMMediaFile(Type_Name, asReplacableSkin); // McZapkie-100402: wyszukiwanie submodeli sprzegów btCoupler1.Init( "coupler1", mdModel, false ); // false - ma być wyłączony btCoupler2.Init( "coupler2", mdModel, false); @@ -2612,13 +2616,13 @@ void TDynamicObject::update_exchange( double const Deltatime ) { auto const exchangesize = std::min( m_exchange.unload_count, MoverParameters->UnLoadSpeed * m_exchange.speed_factor ); m_exchange.unload_count -= exchangesize; MoverParameters->LoadStatus = 1; - MoverParameters->Load = std::max( 0.f, MoverParameters->Load - exchangesize ); + MoverParameters->LoadAmount = std::max( 0.f, MoverParameters->LoadAmount - exchangesize ); update_load_visibility(); } if( m_exchange.unload_count < 0.01 ) { // finish any potential unloading operation before adding new load // don't load more than can fit - m_exchange.load_count = std::min( m_exchange.load_count, MoverParameters->MaxLoad - MoverParameters->Load ); + m_exchange.load_count = std::min( m_exchange.load_count, MoverParameters->MaxLoad - MoverParameters->LoadAmount ); while( ( m_exchange.load_count > 0.01 ) && ( m_exchange.time >= 1.0 ) ) { @@ -2626,7 +2630,7 @@ void TDynamicObject::update_exchange( double const Deltatime ) { auto const exchangesize = std::min( m_exchange.load_count, MoverParameters->LoadSpeed * m_exchange.speed_factor ); m_exchange.load_count -= exchangesize; MoverParameters->LoadStatus = 2; - MoverParameters->Load = std::min( MoverParameters->MaxLoad, MoverParameters->Load + exchangesize ); // std::max not strictly needed but, eh + MoverParameters->LoadAmount = std::min( MoverParameters->MaxLoad, MoverParameters->LoadAmount + exchangesize ); // std::max not strictly needed but, eh update_load_visibility(); } } @@ -2664,34 +2668,28 @@ void TDynamicObject::LoadUpdate() { // przeładowanie modelu ładunku // Ra: nie próbujemy wczytywać modeli miliony razy podczas renderowania!!! if( ( mdLoad == nullptr ) - && ( MoverParameters->Load > 0 ) ) { + && ( MoverParameters->LoadAmount > 0 ) ) { - if( false == MoverParameters->LoadType.empty() ) { + if( false == MoverParameters->LoadType.name.empty() ) { + // bieżąca ścieżka do tekstur to dynamic/... + Global.asCurrentTexturePath = asBaseDir; - Global.asCurrentTexturePath = asBaseDir; // bieżąca ścieżka do tekstur to dynamic/... - - // try first specialized version of the load model, vehiclename_loadname - auto const specializedloadfilename { asBaseDir + MoverParameters->TypeName + "_" + MoverParameters->LoadType }; - mdLoad = TModelsManager::GetModel( specializedloadfilename, true ); - if( mdLoad == nullptr ) { - // if this fails, try generic load model - auto const genericloadfilename { asBaseDir + MoverParameters->LoadType }; - mdLoad = TModelsManager::GetModel( genericloadfilename, true ); - } + mdLoad = LoadMMediaFile_mdload( MoverParameters->LoadType.name ); + // TODO: discern from vehicle component which merely uses vehicle directory and has no animations, so it can be initialized outright + // and actual vehicles which get their initialization after their animations are set up if( mdLoad != nullptr ) { - // TODO: discern from vehicle component which merely uses vehicle directory and has no animations, so it can be initialized outright - // and actual vehicles which get their initialization after their animations are set up mdLoad->Init(); } // update bindings between lowpoly sections and potential load chunks placed inside them update_load_sections(); - - Global.asCurrentTexturePath = std::string( szTexturePath ); // z powrotem defaultowa sciezka do tekstur + // z powrotem defaultowa sciezka do tekstur + Global.asCurrentTexturePath = std::string( szTexturePath ); } // Ra: w MMD można by zapisać położenie modelu ładunku (np. węgiel) w zależności od załadowania } - else if( MoverParameters->Load == 0 ) { + else if( MoverParameters->LoadAmount == 0 ) { // nie ma ładunku + MoverParameters->AssignLoad( "" ); mdLoad = nullptr; // erase bindings between lowpoly sections and potential load chunks placed inside them update_load_sections(); @@ -2729,7 +2727,7 @@ TDynamicObject::update_load_visibility() { auto loadpercentage { ( MoverParameters->MaxLoad == 0.0 ? 0.0 : - 100.0 * MoverParameters->Load / MoverParameters->MaxLoad ) }; + 100.0 * MoverParameters->LoadAmount / MoverParameters->MaxLoad ) }; auto const sectionloadpercentage { ( SectionLoadVisibility.empty() ? 0.0 : @@ -2758,14 +2756,14 @@ TDynamicObject::update_load_visibility() { void TDynamicObject::update_load_offset() { - if( MoverParameters->LoadMinOffset == 0.f ) { return; } + if( MoverParameters->LoadType.offset_min == 0.f ) { return; } auto const loadpercentage { ( MoverParameters->MaxLoad == 0.0 ? 0.0 : - 100.0 * MoverParameters->Load / MoverParameters->MaxLoad ) }; + 100.0 * MoverParameters->LoadAmount / MoverParameters->MaxLoad ) }; - LoadOffset = interpolate( MoverParameters->LoadMinOffset, 0.f, clamp( 0.0, 1.0, loadpercentage * 0.01 ) ); + LoadOffset = interpolate( MoverParameters->LoadType.offset_min, 0.f, clamp( 0.0, 1.0, loadpercentage * 0.01 ) ); } void @@ -4479,20 +4477,14 @@ TDynamicObject::tracing_offset() const { // McZapkie-250202 // wczytywanie pliku z danymi multimedialnymi (dzwieki) -void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, std::string ReplacableSkin ) { - - replace_slashes( BaseDir ); - Global.asCurrentDynamicPath = BaseDir; - std::string asFileName = BaseDir + TypeName + ".mmd"; - std::string asLoadName; - if( false == MoverParameters->LoadType.empty() ) { - asLoadName = BaseDir + MoverParameters->LoadType; - } +void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string const &ReplacableSkin ) { + Global.asCurrentDynamicPath = asBaseDir; + std::string asFileName = asBaseDir + TypeName + ".mmd"; std::string asAnimName; bool Stop_InternalData = false; pants = NULL; // wskaźnik pierwszego obiektu animującego dla pantografów - cParser parser( TypeName + ".mmd", cParser::buffer_FILE, BaseDir ); + cParser parser( TypeName + ".mmd", cParser::buffer_FILE, asBaseDir ); if( false == parser.ok() ) { ErrorLog( "Failed to load appearance data for vehicle " + MoverParameters->Name ); return; @@ -4526,8 +4518,8 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, } m_materialdata.multi_textures = clamp( m_materialdata.multi_textures, 0, 1 ); // na razie ustawiamy na 1 } - asModel = BaseDir + asModel; // McZapkie 2002-07-20: dynamics maja swoje modele w dynamics/basedir - Global.asCurrentTexturePath = BaseDir; // biezaca sciezka do tekstur to dynamic/... + asModel = asBaseDir + asModel; // McZapkie 2002-07-20: dynamics maja swoje modele w dynamics/basedir + Global.asCurrentTexturePath = asBaseDir; // biezaca sciezka do tekstur to dynamic/... mdModel = TModelsManager::GetModel(asModel, true); if (ReplacableSkin != "none") { @@ -4553,7 +4545,6 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, } else { // otherwise try the basic approach - erase_extension( ReplacableSkin ); int skinindex = 0; do { material_handle material = GfxRenderer.Fetch_Material( ReplacableSkin + "," + std::to_string( skinindex + 1 ), true ); @@ -4598,53 +4589,9 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, m_materialdata.textures_alpha |= 0x08080008; } } - if( !MoverParameters->LoadAccepted.empty() ) { - - if( ( MoverParameters->EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) - && ( asLoadName == "pantstate" ) ) { - // wartość niby "pantstate" - nazwa dla formalności, ważna jest ilość - if( MoverParameters->Load == 1 ) { - MoverParameters->PantFront( true ); - } - else if( MoverParameters->Load == 2 ) { - MoverParameters->PantRear( true ); - } - else if( MoverParameters->Load == 3 ) { - MoverParameters->PantFront( true ); - MoverParameters->PantRear( true ); - } - else if( MoverParameters->Load == 4 ) { - MoverParameters->DoubleTr = -1; - } - else if( MoverParameters->Load == 5 ) { - MoverParameters->DoubleTr = -1; - MoverParameters->PantRear( true ); - } - else if( MoverParameters->Load == 6 ) { - MoverParameters->DoubleTr = -1; - MoverParameters->PantFront( true ); - } - else if( MoverParameters->Load == 7 ) { - MoverParameters->DoubleTr = -1; - MoverParameters->PantFront( true ); - MoverParameters->PantRear( true ); - } - } - else { - // Ra: tu wczytywanie modelu ładunku jest w porządku - if( false == asLoadName.empty() ) { - // try first specialized version of the load model, vehiclename_loadname - auto const specializedloadfilename { BaseDir + TypeName + "_" + MoverParameters->LoadType }; - if( ( true == FileExists( specializedloadfilename + ".e3d" ) ) - || ( true == FileExists( specializedloadfilename + ".t3d" ) ) ) { - mdLoad = TModelsManager::GetModel( specializedloadfilename, true ); - } - if( mdLoad == nullptr ) { - // if this fails, try generic load model - mdLoad = TModelsManager::GetModel( asLoadName, true ); - } - } - } + if( false == MoverParameters->LoadAttributes.empty() ) { + // Ra: tu wczytywanie modelu ładunku jest w porządku + mdLoad = LoadMMediaFile_mdload( MoverParameters->LoadType.name ); } Global.asCurrentTexturePath = szTexturePath; // z powrotem defaultowa sciezka do tekstur do { @@ -4707,8 +4654,8 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, // filename can potentially begin with a slash, and we don't need it asModel.erase( 0, 1 ); } - asModel = BaseDir + asModel; // McZapkie-200702 - dynamics maja swoje modele w dynamic/basedir - Global.asCurrentTexturePath = BaseDir; // biezaca sciezka do tekstur to dynamic/... + asModel = asBaseDir + asModel; // McZapkie-200702 - dynamics maja swoje modele w dynamic/basedir + Global.asCurrentTexturePath = asBaseDir; // biezaca sciezka do tekstur to dynamic/... mdLowPolyInt = TModelsManager::GetModel(asModel, true); } @@ -5925,6 +5872,25 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, m_couplersounds[ side::rear ].dsbBufferClamp_loud.offset( rearcoupleroffset ); } +TModel3d * +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 }; + auto const specializedloadfilename { asBaseDir + MoverParameters->TypeName + "_" + Name }; + if( ( true == FileExists( specializedloadfilename + ".e3d" ) ) + || ( true == FileExists( specializedloadfilename + ".t3d" ) ) ) { + loadmodel = TModelsManager::GetModel( specializedloadfilename, true ); + } + if( loadmodel == nullptr ) { + // if this fails, try generic load model + loadmodel = TModelsManager::GetModel( asBaseDir + Name, true ); + } + return loadmodel; +} + //--------------------------------------------------------------------------- void TDynamicObject::RadioStop() { // zatrzymanie pojazdu @@ -7029,7 +6995,8 @@ vehicle_table::erase_disabled() { && ( true == vehicle->MyTrack->RemoveDynamicObject( vehicle ) ) ) { vehicle->MyTrack = nullptr; } - if( simulation::Train->Dynamic() == vehicle ) { + if( ( simulation::Train != nullptr ) + && ( simulation::Train->Dynamic() == vehicle ) ) { // clear potential train binding // TBD, TODO: manually eject the driver first ? SafeDelete( simulation::Train ); diff --git a/DynObj.h b/DynObj.h index 094a919a..0976e11e 100644 --- a/DynObj.h +++ b/DynObj.h @@ -458,7 +458,7 @@ private: public: void ABuScanObjects(int ScanDir, double ScanDist); - protected: + private: TDynamicObject *ABuFindObject( int &Foundcoupler, double &Distance, TTrack const *Track, int const Direction, int const Mycoupler ); void ABuCheckMyTrack(); @@ -580,7 +580,8 @@ private: Axle0.GetTrack()); }; // McZapkie-260202 - void LoadMMediaFile(std::string BaseDir, std::string TypeName, std::string ReplacableSkin); + void LoadMMediaFile(std::string const &TypeName, std::string const &ReplacableSkin); + TModel3d *LoadMMediaFile_mdload( std::string const &Name ) const; inline double ABuGetDirection() const { // ABu. return (Axle1.GetTrack() == MyTrack ? Axle1.GetDirection() : Axle0.GetDirection()); }; diff --git a/Event.cpp b/Event.cpp index a0fc5c32..9eb39692 100644 --- a/Event.cpp +++ b/Event.cpp @@ -913,15 +913,15 @@ whois_event::run_() { else { // jeśli parametry ładunku targetcell->UpdateValues( - m_activator->MoverParameters->LoadType, // nazwa ładunku - m_activator->MoverParameters->Load, // aktualna ilość + m_activator->MoverParameters->LoadType.name, // nazwa ładunku + m_activator->MoverParameters->LoadAmount, // aktualna ilość m_activator->MoverParameters->MaxLoad, // maksymalna ilość m_input.flags & ( flags::text | flags::value_1 | flags::value_2 ) ); WriteLog( "Type: WhoIs (" + to_string( m_input.flags ) + ") - " - + "[load type: " + m_activator->MoverParameters->LoadType + "], " - + "[current load: " + to_string( m_activator->MoverParameters->Load, 2 ) + "], " + + "[load type: " + m_activator->MoverParameters->LoadType.name + "], " + + "[current load: " + to_string( m_activator->MoverParameters->LoadAmount, 2 ) + "], " + "[max load: " + to_string( m_activator->MoverParameters->MaxLoad, 2 ) + "]" ); } } diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 3b04861b..9dcbaadb 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -944,11 +944,19 @@ public: double MED_EPVC_Time = 7; // czas korekcji sily hamowania EP, gdy nie ma dostepnego ED bool MED_Ncor = 0; // czy korekcja sily hamowania z uwzglednieniem nacisku /*-dla wagonow*/ + struct load_attributes { + std::string name; // name of the cargo + float offset_min { 0.f }; // offset applied to cargo model when load amount is 0 + + load_attributes() = default; + load_attributes( std::string const &Name, float const Offsetmin ) : + name( Name ), offset_min( Offsetmin ) + {} + }; + std::vector LoadAttributes; float MaxLoad = 0.f; /*masa w T lub ilosc w sztukach - ladownosc*/ - std::string LoadAccepted; std::string LoadQuantity; /*co moze byc zaladowane, jednostki miary*/ - double OverLoadFactor = 0.0; /*ile razy moze byc przekroczona ladownosc*/ - float LoadMinOffset { 0.f }; // offset applied to cargo model when load amount is 0 - float LoadSpeed = 0.f; float UnLoadSpeed = 0.f;/*szybkosc na- i rozladunku jednostki/s*/ + double OverLoadFactor = 0.0; /*ile razy moze byc przekroczona ladownosc*/ + float LoadSpeed = 0.f; float UnLoadSpeed = 0.f;/*szybkosc na- i rozladunku jednostki/s*/ int DoorOpenCtrl = 0; int DoorCloseCtrl = 0; /*0: przez pasazera, 1: przez maszyniste, 2: samoczynne (zamykanie)*/ double DoorStayOpen = 0.0; /*jak dlugo otwarte w przypadku DoorCloseCtrl=2*/ bool DoorClosureWarning = false; /*czy jest ostrzeganie przed zamknieciem*/ @@ -1167,9 +1175,10 @@ public: double eAngle = M_PI * 0.5; /*-dla wagonow*/ - float Load = 0.f; /*masa w T lub ilosc w sztukach - zaladowane*/ - std::string LoadType; /*co jest zaladowane*/ - int LoadStatus = 0; //+1=trwa rozladunek,+2=trwa zaladunek,+4=zakończono,0=zaktualizowany model + float LoadAmount = 0.f; /*masa w T lub ilosc w sztukach - zaladowane*/ + load_attributes LoadType; + std::string LoadQuantity; // jednostki miary + int LoadStatus = 0; //+1=trwa rozladunek,+2=trwa zaladunek,+4=zakończono,0=zaktualizowany model double LastLoadChangeTime = 0.0; //raz (roz)ładowania bool DoorBlocked = false; //Czy jest blokada drzwi @@ -1211,7 +1220,7 @@ private: double CouplerDist(int Coupler); public: - TMoverParameters(double VelInitial, std::string TypeNameInit, std::string NameInit, int LoadInitial, std::string LoadTypeInitial, int Cab); + TMoverParameters(double VelInitial, std::string TypeNameInit, std::string NameInit, int Cab); // obsługa sprzęgów double Distance(const TLocation &Loc1, const TLocation &Loc2, const TDimension &Dim1, const TDimension &Dim2); /* double Distance(const vector3 &Loc1, const vector3 &Loc2, const vector3 &Dim1, const vector3 &Dim2); @@ -1375,7 +1384,8 @@ public: bool dizel_Update(double dt); /* funckje dla wagonow*/ - bool LoadingDone(double LSpeed, std::string LoadInit); + bool AssignLoad( std::string const &Name, float const Amount = 0.f ); + bool LoadingDone(double LSpeed, std::string const &Loadname); bool DoorLeft(bool State, range_t const Notify = range_t::consist ); //obsluga drzwi lewych bool DoorRight(bool State, range_t const Notify = range_t::consist ); //obsluga drzwi prawych bool DoorBlockedFlag(void); //sprawdzenie blokady drzwi diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 2e2b7a5f..06d4100e 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -278,21 +278,14 @@ double TMoverParameters::Current(double n, double U) // ************************************************************************************************* // główny konstruktor // ************************************************************************************************* -TMoverParameters::TMoverParameters(double VelInitial, std::string TypeNameInit, - std::string NameInit, int LoadInitial, - std::string LoadTypeInitial, - int Cab) ://: T_MoverParameters(VelInitial, TypeNameInit, - //NameInit, LoadInitial, LoadTypeInitial, Cab) +TMoverParameters::TMoverParameters(double VelInitial, std::string TypeNameInit, std::string NameInit, int Cab) : TypeName( TypeNameInit ), Name( NameInit ), -ActiveCab( Cab ), -Load( LoadInitial ), -LoadType( LoadTypeInitial ) +ActiveCab( Cab ) { WriteLog( "------------------------------------------------------"); - WriteLog("init default physic values for " + NameInit + ", [" + TypeNameInit + "], [" + - LoadTypeInitial + "]"); + WriteLog("init default physic values for " + NameInit + ", [" + TypeNameInit + "]"); Dim = TDimension(); // BrakeLevelSet(-2); //Pascal ustawia na 0, przestawimy na odcięcie (CHK jest jeszcze nie wczytane!) @@ -354,10 +347,6 @@ LoadType( LoadTypeInitial ) } eimc[eimc_p_eped] = 1.5; - // inicjalizacja zmiennych} - // Loc:=LocInitial; //Ra: to i tak trzeba potem przesunąć, po ustaleniu pozycji na torze - // (potrzebna długość) - // Rot:=RotInitial; for (int b = 0; b < 2; ++b) { Couplers[b].AllowedFlag = 3; // domyślnie hak i hamulec, inne trzeba włączyć jawnie w FIZ @@ -409,20 +398,6 @@ LoadType( LoadTypeInitial ) SecuritySystem.RadioStop = false; // domyślnie nie ma SecuritySystem.AwareMinSpeed = 0.1 * Vmax; s_CAtestebrake = false; - // ABu 240105: - // CouplerNr[0]:=1; - // CouplerNr[1]:=0; - - // TO POTEM TU UAKTYWNIC A WYWALIC Z CHECKPARAM} - //{ - // if Pos(LoadTypeInitial,LoadAccepted)>0 then - // begin - //} - - //{ - // end - // else Load:=0; - // } }; double TMoverParameters::Distance(const TLocation &Loc1, const TLocation &Loc2, @@ -3758,27 +3733,25 @@ void TMoverParameters::ComputeConstans(void) // ************************************************************************************************* double TMoverParameters::ComputeMass(void) { - double M; - LoadType = ToLower(LoadType); // po co zakładać jak można mieć na pewno - if (Load > 0) - { // zakładamy, że ładunek jest pisany małymi literami + double M { 0.0 }; + // TODO: unit weight table, pulled from external data file + if( LoadAmount > 0 ) { + if (ToLower(LoadQuantity) == "tonns") - M = Load * 1000; - else if (LoadType == "passengers") - M = Load * 80; - else if (LoadType == "luggage") - M = Load * 100; - else if (LoadType == "cars") - M = Load * 1200; // 800 kilo to miał maluch - else if (LoadType == "containers") - M = Load * 8000; - else if (LoadType == "transformers") - M = Load * 50000; + M = LoadAmount * 1000; + else if (LoadType.name == "passengers") + M = LoadAmount * 80; + else if (LoadType.name == "luggage") + M = LoadAmount * 100; + else if (LoadType.name == "cars") + M = LoadAmount * 1200; // 800 kilo to miał maluch + else if (LoadType.name == "containers") + M = LoadAmount * 8000; + else if (LoadType.name == "transformers") + M = LoadAmount * 50000; else - M = Load * 1000; + M = LoadAmount * 1000; } - else - M = 0; // Ra: na razie tak, ale nie wszędzie masy wirujące się wliczają return Mass + M + Mred; } @@ -6458,58 +6431,105 @@ void TMoverParameters::dizel_Heat( double const dt ) { */ } +bool +TMoverParameters::AssignLoad( std::string const &Name, float const Amount ) { + + if( Name == "pantstate" ) { + if( EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) { + // wartość niby "pantstate" - nazwa dla formalności, ważna jest ilość + auto const pantographsetup { static_cast( Amount ) }; + if( pantographsetup & ( 1 << 2 ) ) { + DoubleTr = -1; + } + if( pantographsetup & ( 1 << 0 ) ) { + if( DoubleTr == 1 ) { PantFront( true ); } + else { PantRear( true ); } + } + if( pantographsetup & ( 1 << 1 ) ) { + if( DoubleTr == 1 ) { PantRear( true ); } + else { PantFront( true ); } + } + return true; + } + else { + return false; + } + } + + // can't mix load types, at least for the time being + if( ( LoadAmount > 0 ) && ( LoadType.name != Name ) ) { return false; } + + if( Name.empty() ) { + // empty the vehicle + LoadType = load_attributes(); + LoadAmount = 0.f; + return true; + } + + for( auto const &loadattributes : LoadAttributes ) { + if( Name == loadattributes.name ) { + LoadType = loadattributes; + LoadAmount = Amount; + return true; + } + } + // didn't find matching load configuration, this type is unsupported + return false; +} + // ************************************************************************************************* // Q: 20160713 // Test zakończenia załadunku / rozładunku // ************************************************************************************************* -bool TMoverParameters::LoadingDone(double LSpeed, std::string LoadInit) -{ - // test zakończenia załadunku/rozładunku - long LoadChange = 0; - bool LD = false; +bool TMoverParameters::LoadingDone(double const LSpeed, std::string const &Loadname) { - // ClearPendingExceptions; // zabezpieczenie dla Trunc() - // LoadingDone:=false; //nie zakończone - if (!LoadInit.empty()) // nazwa ładunku niepusta - { - if (Load > MaxLoad) - LoadChange = abs(long(LSpeed * LastLoadChangeTime / 2.0)); // przeładowanie? - else - LoadChange = abs(long(LSpeed * LastLoadChangeTime)); - if (LSpeed < 0) // gdy rozładunek - { - LoadStatus = 2; // trwa rozładunek (włączenie naliczania czasu) - if (LoadChange != 0) // jeśli coś przeładowano - { - LastLoadChangeTime = 0; // naliczony czas został zużyty - Load -= LoadChange; // zmniejszenie ilości ładunku - CommandIn.Value1 = - CommandIn.Value1 - LoadChange; // zmniejszenie ilości do rozładowania - if (Load < 0) - Load = 0; //ładunek nie może być ujemny - if ((Load == 0) || (CommandIn.Value1 < 0)) // pusto lub rozładowano żądaną ilość - LoadStatus = 4; // skończony rozładunek - if (Load == 0) - LoadType.clear(); // jak nic nie ma, to nie ma też nazwy - } - } - else if (LSpeed > 0) // gdy załadunek - { - LoadStatus = 1; // trwa załadunek (włączenie naliczania czasu) - if (LoadChange != 0) // jeśli coś przeładowano - { - LastLoadChangeTime = 0; // naliczony czas został zużyty - LoadType = LoadInit; // nazwa - Load += LoadChange; // zwiększenie ładunku - CommandIn.Value1 = CommandIn.Value1 - LoadChange; - if ((Load >= MaxLoad * (1.0 + OverLoadFactor)) || (CommandIn.Value1 < 0)) - LoadStatus = 4; // skończony załadunek - } - } - else - LoadStatus = 4; // zerowa prędkość zmiany, to koniec + if( LSpeed == 0.0 ) { + // zerowa prędkość zmiany, to koniec + LoadStatus = 4; + return true; } - return (LoadStatus >= 4); + + if( Loadname.empty() ) { return ( LoadStatus >= 4 ); } + if( Loadname != LoadType.name ) { return ( LoadStatus >= 4 ); } + + // test zakończenia załadunku/rozładunku + // load exchange speed is reduced if the wagon is overloaded + auto const loadchange { static_cast( std::abs( LSpeed * LastLoadChangeTime ) * ( LoadAmount > MaxLoad ? 0.5 : 1.0 ) ) }; + + if( LSpeed < 0 ) { + // gdy rozładunek + LoadStatus = 2; // trwa rozładunek (włączenie naliczania czasu) + if( loadchange > 0 ) // jeśli coś przeładowano + { + LastLoadChangeTime = 0; // naliczony czas został zużyty + LoadAmount -= loadchange; // zmniejszenie ilości ładunku + CommandIn.Value1 -= loadchange; // zmniejszenie ilości do rozładowania + if( ( LoadAmount <= 0 ) || ( CommandIn.Value1 <= 0 ) ) { + // pusto lub rozładowano żądaną ilość + LoadStatus = 4; // skończony rozładunek + LoadAmount = std::max( 0.f, LoadAmount ); //ładunek nie może być ujemny + } + if( LoadAmount == 0.f ) { + AssignLoad(""); // jak nic nie ma, to nie ma też nazwy + } + } + } + else if( LSpeed > 0 ) { + // gdy załadunek + LoadStatus = 1; // trwa załadunek (włączenie naliczania czasu) + if( loadchange > 0 ) // jeśli coś przeładowano + { + LastLoadChangeTime = 0; // naliczony czas został zużyty + LoadAmount += loadchange; // zwiększenie ładunku + CommandIn.Value1 -= loadchange; + if( ( LoadAmount >= MaxLoad * ( 1.0 + OverLoadFactor ) ) || ( CommandIn.Value1 <= 0 ) ) { + LoadStatus = 4; // skończony załadunek + LoadAmount = std::min( MaxLoad * ( 1.0 + OverLoadFactor ), LoadAmount ); + } + } + } + + return ( LoadStatus >= 4 ); } // ************************************************************************************************* @@ -7593,19 +7613,30 @@ void TMoverParameters::LoadFIZ_Param( std::string const &line ) { void TMoverParameters::LoadFIZ_Load( std::string const &line ) { - extract_value( LoadAccepted, "LoadAccepted", line, "" ); - if( true == LoadAccepted.empty() ) { - return; + auto const acceptedloads { Split( extract_value( "LoadAccepted", line ), ',' ) }; + + if( acceptedloads.empty() ) { return; } + + auto const minoffsets { Split( extract_value( "LoadMinOffset", line ), ',' ) }; + auto minoffset { 0.f }; + auto minoffsetsiterator { std::begin( minoffsets ) }; + // NOTE: last (if any) offset parameter retrieved from the list applies to the remainder of the list + // TBD, TODO: include other load parameters in this system + for( auto &load : acceptedloads ) { + if( minoffsetsiterator != std::end( minoffsets ) ) { + minoffset = std::stof( *minoffsetsiterator ); + ++minoffsetsiterator; + } + LoadAttributes.emplace_back( + ToLower( load ), + minoffset ); } - LoadAccepted = ToLower( LoadAccepted ); extract_value( MaxLoad, "MaxLoad", line, "" ); extract_value( LoadQuantity, "LoadQ", line, "" ); extract_value( OverLoadFactor, "OverLoadFactor", line, "" ); extract_value( LoadSpeed, "LoadSpeed", line, "" ); extract_value( UnLoadSpeed, "UnLoadSpeed", line, "" ); - - extract_value( LoadMinOffset, "LoadMinOffset", line, "" ); } void TMoverParameters::LoadFIZ_Dimensions( std::string const &line ) { @@ -8651,11 +8682,6 @@ bool TMoverParameters::CheckLocomotiveParameters(bool ReadyFlag, int Dir) // WriteLogSS("aa ok", BoolToYN(OK)); } - if( ( LoadType.empty() == false ) && ( LoadAccepted.find( LoadType ) == std::string::npos ) ) { - // remove load if the type isn't supported - Load = 0.0; - } - if (BrakeSystem == TBrakeSystem::Individual) if (BrakeSubsystem != TBrakeSubSystem::ss_None) OK = false; //! @@ -8889,16 +8915,16 @@ bool TMoverParameters::CheckLocomotiveParameters(bool ReadyFlag, int Dir) if( LoadFlag > 0 ) { - if( Load < MaxLoad * 0.45 ) { + if( LoadAmount < MaxLoad * 0.45 ) { IncBrakeMult(); IncBrakeMult(); DecBrakeMult(); // TODO: przeinesiono do mover.cpp - if( Load < MaxLoad * 0.35 ) + if( LoadAmount < MaxLoad * 0.35 ) DecBrakeMult(); } else { IncBrakeMult(); // TODO: przeinesiono do mover.cpp - if( Load >= MaxLoad * 0.55 ) + if( LoadAmount >= MaxLoad * 0.55 ) IncBrakeMult(); } } @@ -9479,39 +9505,44 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C OK = true; // true, gdy można usunąć komendę } /*naladunek/rozladunek*/ - else if ( issection( "Load=", Command ) ) + // TODO: have these commands leverage load exchange system instead + else if ( issection( "Load=", Command ) ) { OK = false; // będzie powtarzane aż się załaduje - if( ( Vel < 0.01 ) + if( ( Vel < 0.1 ) // tolerance margin for small vehicle movements in the consist && ( MaxLoad > 0 ) - && ( Load < MaxLoad * ( 1.0 + OverLoadFactor ) ) ) { - // czy można ładowac? - if( Distance( Loc, CommandIn.Location, Dim, Dim ) < 10 ) { - // ten peron/rampa - auto const testload { ToLower( extract_value( "Load", Command ) ) }; - if( LoadAccepted.find( testload ) != std::string::npos ) // nazwa jest obecna w CHK - OK = LoadingDone( Min0R( CValue2, LoadSpeed ), testload ); // zmienia LoadStatus + && ( LoadAmount < MaxLoad * ( 1.0 + OverLoadFactor ) ) + && ( Distance( Loc, CommandIn.Location, Dim, Dim ) < 10 ) ) { // ten peron/rampa + + auto const loadname { ToLower( extract_value( "Load", Command ) ) }; + if( LoadAmount == 0.f ) { + AssignLoad( loadname ); } + OK = LoadingDone( + std::min( CValue2, LoadSpeed ), + loadname ); // zmienia LoadStatus + } + else { + // no loading can be done if conditions aren't met + LastLoadChangeTime = 0.0; } - // if OK then LoadStatus:=0; //nie udalo sie w ogole albo juz skonczone } else if( issection( "UnLoad=", Command ) ) { OK = false; // będzie powtarzane aż się rozładuje - if( ( Vel < 0.01 ) - && ( Load > 0 ) ) { - // czy jest co rozladowac? - if( Distance( Loc, CommandIn.Location, Dim, Dim ) < 10 ) { - // ten peron - auto const testload { ToLower( extract_value( "UnLoad", Command ) ) }; // zgodność nazwy ładunku z CHK - if( LoadType == testload ) { - /*mozna to rozladowac*/ - OK = LoadingDone( -Min0R( CValue2, LoadSpeed ), testload ); - } - } + if( ( Vel < 0.1 ) // tolerance margin for small vehicle movements in the consist + && ( LoadAmount > 0 ) // czy jest co rozladowac? + && ( Distance( Loc, CommandIn.Location, Dim, Dim ) < 10 ) ) { // ten peron + /*mozna to rozladowac*/ + OK = LoadingDone( + -1.f * std::min( CValue2, LoadSpeed ), + ToLower( extract_value( "UnLoad", Command ) ) ); } - // if OK then LoadStatus:=0; - } + else { + // no loading can be done if conditions aren't met + LastLoadChangeTime = 0.0; + } + } else if (Command == "SpeedCntrl") { if ((EngineType == TEngineType::ElectricInductionMotor)) diff --git a/Model3d.cpp b/Model3d.cpp index e72bb784..63f75d55 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -79,12 +79,12 @@ TSubModel::SetLightLevel( float const Level, bool const Includechildren, bool co if( true == Includesiblings ) { auto sibling { this }; while( ( sibling = sibling->Next ) != nullptr ) { - sibling->f4Emision.a = Level; + sibling->SetLightLevel( Level, Includechildren, false ); // no need for all siblings to duplicate the work } } if( ( true == Includechildren ) && ( Child != nullptr ) ) { - Child->SetLightLevel( Level, true, true ); // node's children include child's siblings and children + Child->SetLightLevel( Level, Includechildren, true ); // node's children include child's siblings and children } } diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 174bc700..84b930f6 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -385,8 +385,8 @@ debug_panel::update_section_vehicle( std::vector &Output ) { locale::strings[ locale::string::debug_vehicle_nameloadstatuscouplers ].c_str(), mover.Name.c_str(), std::string( isowned ? locale::strings[ locale::string::debug_vehicle_owned ].c_str() + vehicle.ctOwner->OwnerName() : "" ).c_str(), - mover.Load, - mover.LoadType.c_str(), + mover.LoadAmount, + mover.LoadType.name.c_str(), mover.EngineDescription( 0 ).c_str(), // TODO: put wheel flat reporting in the enginedescription() std::string( mover.WheelFlat > 0.01 ? " Flat: " + to_string( mover.WheelFlat, 1 ) + " mm" : "" ).c_str(), diff --git a/station.cpp b/station.cpp index cf09b863..75f7f267 100644 --- a/station.cpp +++ b/station.cpp @@ -49,20 +49,19 @@ basic_station::update_load( TDynamicObject *First, Mtable::TTrainParameters &Sch auto ¶meters { *vehicle->MoverParameters }; - if( ( true == parameters.LoadType.empty() ) - && ( parameters.LoadAccepted.find( "passengers" ) != std::string::npos ) ) { - // set the type for empty cars - parameters.LoadType = "passengers"; + if( parameters.LoadType.name.empty() ) { + // (try to) set the cargo type for empty cars + parameters.AssignLoad( "passengers" ); } - if( parameters.LoadType == "passengers" ) { + if( parameters.LoadType.name == "passengers" ) { // NOTE: for the time being we're doing simple, random load change calculation // TODO: exchange driven by station parameters and time of the day auto unloadcount = static_cast( - laststop ? parameters.Load : + laststop ? parameters.LoadAmount : firststop ? 0 : std::min( - parameters.Load, + parameters.LoadAmount, Random( parameters.MaxLoad * 0.10 * stationsizemodifier ) ) ); auto loadcount = static_cast( laststop ?