From bd5968cb4b15a1b4b91865b6470579b3948d17a9 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Mon, 3 Sep 2018 13:26:35 +0200 Subject: [PATCH] minor ai logic enhancements, minor bug fixes --- Driver.cpp | 162 +++++++++++++++++++++------------------------ DynObj.cpp | 3 +- McZapkie/Mover.cpp | 14 ++-- Model3d.cpp | 10 ++- drivermode.cpp | 11 +-- material.cpp | 3 +- 6 files changed, 100 insertions(+), 103 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 55a114cb..94af7998 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -2256,11 +2256,9 @@ double TController::BrakeAccFactor() const void TController::SetDriverPsyche() { - // double maxdist=0.5; //skalowanie dystansu od innego pojazdu, zmienic to!!! if ((Psyche == Aggressive) && (OrderList[OrderPos] == Obey_train)) { ReactionTime = HardReactionTime; // w zaleznosci od charakteru maszynisty - // if (pOccupied) if (mvOccupied->CategoryFlag & 2) { WaitingExpireTime = 1; // tyle ma czekać samochód, zanim się ruszy @@ -2292,48 +2290,6 @@ void TController::SetDriverPsyche() ReactionTime = mvControlling->InitialCtrlDelay + ReactionTime; if (mvOccupied->BrakeCtrlPos > 1) ReactionTime = 0.5 * ReactionTime; - /* - if (mvOccupied->Vel>0.1) //o ile jedziemy - {//sprawdzenie jazdy na widoczność - TCoupling - *c=pVehicles[0]->MoverParameters->Couplers+(pVehicles[0]->DirectionGet()>0?0:1); //sprzęg - z przodu składu - if (c->Connected) //a mamy coś z przodu - if (c->CouplingFlag==0) //jeśli to coś jest podłączone sprzęgiem wirtualnym - {//wyliczanie optymalnego przyspieszenia do jazdy na widoczność (Ra: na pewno tutaj?) - double k=c->Connected->Vel; //prędkość pojazdu z przodu (zakładając, że jedzie w tę - samą stronę!!!) - if (k<=mvOccupied->Vel) //porównanie modułów prędkości [km/h] - {if (pVehicles[0]->fTrackBlockfTrackBlock-0.5*fabs(mvOccupied->V)-fMaxProximityDist); - //bezpieczna odległość za poprzednim - //a=(v2*v2-v1*v1)/(25.92*(d-0.5*v1)) - //(v2*v2-v1*v1)/2 to różnica energii kinetycznych na jednostkę masy - //jeśli v2=50km/h,v1=60km/h,d=200m => k=(192.9-277.8)/(25.92*(200-0.5*16.7)=-0.0171 - [m/s^2] - //jeśli v2=50km/h,v1=60km/h,d=100m => k=(192.9-277.8)/(25.92*(100-0.5*16.7)=-0.0357 - [m/s^2] - //jeśli v2=50km/h,v1=60km/h,d=50m => k=(192.9-277.8)/(25.92*( 50-0.5*16.7)=-0.0786 - [m/s^2] - //jeśli v2=50km/h,v1=60km/h,d=25m => k=(192.9-277.8)/(25.92*( 25-0.5*16.7)=-0.1967 - [m/s^2] - if (d>0) //bo jak ujemne, to zacznie przyspieszać, aby się zderzyć - k=(k*k-mvOccupied->Vel*mvOccupied->Vel)/(25.92*d); //energia kinetyczna dzielona - przez masę i drogę daje przyspieszenie - else - k=0.0; //może lepiej nie przyspieszać -AccPreferred; //hamowanie - //WriteLog(pVehicle->asName+" "+AnsiString(k)); - } - if (dDoorCloseCtrl == control_t::driver) - { // zamykanie drzwi - if (mvOccupied->DoorLeftOpened) - mvOccupied->DoorLeft(false); - if (mvOccupied->DoorRightOpened) - mvOccupied->DoorRight(false); + + if( mvOccupied->Vel > 0.01 ) { + // TBD, TODO: make a dedicated braking procedure out of it for potential reuse + VelDesired = 0.0; + AccDesired = std::min( AccDesired, -1.25 ); // hamuj solidnie + ReactionTime = 0.1; + while( DecSpeed( true ) ) { + ; // zerowanie nastawników } - if (mvOccupied->ActiveDir == 0) - if (mvControlling->Mains) - { - mvControlling->CompressorSwitch(false); - mvControlling->ConverterSwitch(false); - if (mvControlling->EnginePowerSource.SourceType == TPowerSource::CurrentCollector) - { - mvControlling->PantFront(false); - mvControlling->PantRear(false); - } - // line breaker - OK = mvControlling->MainSwitch(false); - } - else - OK = true; - } - else if( mvOccupied->ActiveDir == 0 ) { - // tylko to testujemy dla pojazdu człowieka - OK = mvControlling->Mains; + IncBrake(); + return OK; // don't bother with the rest until we're standing still } - if( AIControllFlag ) { + LastReactionTime = 0.0; + ReactionTime = PrepareTime; + + if( false == AIControllFlag ) { + // tylko to testujemy dla pojazdu człowieka + OK = ( ( mvOccupied->ActiveDir == 0 ) && ( mvControlling->Mains ) ); + } + else { + // jeśli steruje komputer mvOccupied->BrakeReleaser( 0 ); - if( !mvOccupied->DecBrakeLevel() ) { - // tu moze zmieniać na -2, ale to bez znaczenia - if( !mvOccupied->IncLocalBrakeLevel( 1 ) ) { - while( DecSpeed( true ) ) - ; // zerowanie nastawników - while( mvOccupied->ActiveDir > 0 ) - mvOccupied->DirectionBackward(); - while( mvOccupied->ActiveDir < 0 ) - mvOccupied->DirectionForward(); + if( std::abs( fAccGravity ) < 0.01 ) { + // release train brake if on flats... + // TODO: check if we shouldn't leave it engaged instead + while( true == mvOccupied->DecBrakeLevel() ) { + // tu moze zmieniać na -2, ale to bez znaczenia + ; + } + // ...and engage independent brake + while( true == mvOccupied->IncLocalBrakeLevel( 1 ) ) { + ; } } + else { + // on slopes engage train brake + AccDesired = std::min( AccDesired, -0.9 ); + while( true == IncBrake() ) { + ; + } + } + while( DecSpeed( true ) ) { + ; // zerowanie nastawników + } + // set direction to neutral + while( ( mvOccupied->ActiveDir > 0 ) && ( mvOccupied->DirectionBackward() ) ) { ; } + while( ( mvOccupied->ActiveDir < 0 ) && ( mvOccupied->DirectionForward() ) ) { ; } + + if( mvOccupied->DoorCloseCtrl == control_t::driver ) { + // zamykanie drzwi + if( mvOccupied->DoorLeftOpened ) { + mvOccupied->DoorLeft( false ); + } + if( mvOccupied->DoorRightOpened ) { + mvOccupied->DoorRight( false ); + } + } + + if( mvControlling->Mains ) { + mvControlling->CompressorSwitch( false ); + mvControlling->ConverterSwitch( false ); + // line breaker/engine + OK = mvControlling->MainSwitch( false ); + if( mvControlling->EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) { + mvControlling->PantFront( false ); + mvControlling->PantRear( false ); + } + } + else { + OK = true; + } } - OK = OK && (mvOccupied->Vel < 0.01); + if (OK) { // jeśli się zatrzymał iEngineActive = 0; @@ -4823,6 +4808,11 @@ TController::UpdateSituation(double dt) { VelDesired = 0.0; } } + + if( ( OrderCurrentGet() & Wait_for_orders ) != 0 ) { + // wait means sit and wait + VelDesired = 0.0; + } // end of speed caps checks if( ( ( OrderCurrentGet() & Obey_train ) != 0 ) diff --git a/DynObj.cpp b/DynObj.cpp index b0903db6..a3186f51 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -970,7 +970,8 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) } if( ( Mechanik != nullptr ) - && ( Mechanik->GetAction() != TAction::actSleep ) ) { + && ( ( Mechanik->GetAction() != TAction::actSleep ) + || ( MoverParameters->Battery ) ) ) { // rysowanie figurki mechanika btMechanik1.Turn( MoverParameters->ActiveCab > 0 ); btMechanik2.Turn( MoverParameters->ActiveCab < 0 ); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 188a8f2b..b2ce0b5c 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -740,8 +740,7 @@ void TMoverParameters::UpdatePantVolume(double dt) // Ra 2013-12: Niebugocław mówi, że w EZT nie ma potrzeby odcinać kurkiem PantPress = ScndPipePress; // ograniczenie ciśnienia do MaxPress (tylko w pantografach!) - PantPress = std::min( PantPress, EnginePowerSource.CollectorParameters.MaxPress ); - PantPress = std::max( PantPress, 0.0 ); + PantPress = clamp( ScndPipePress, 0.0, EnginePowerSource.CollectorParameters.MaxPress ); PantVolume = (PantPress + 1.0) * 0.1; // objętość, na wypadek odcięcia kurkiem } else @@ -754,8 +753,7 @@ void TMoverParameters::UpdatePantVolume(double dt) * ( TrainType == dt_EZT ? 0.003 : 0.005 ) / std::max( 1.0, PantPress ) * ( 0.45 - ( ( 0.1 / PantVolume / 10 ) - 0.1 ) ) / 0.45; } - PantPress = std::min( (10.0 * PantVolume) - 1.0, EnginePowerSource.CollectorParameters.MaxPress ); // tu by się przydała objętość zbiornika - PantPress = std::max( PantPress, 0.0 ); + PantPress = clamp( ( 10.0 * PantVolume ) - 1.0, 0.0, EnginePowerSource.CollectorParameters.MaxPress ); // tu by się przydała objętość zbiornika } if( !PantCompFlag && ( PantVolume > 0.1 ) ) PantVolume -= dt * 0.0003 * std::max( 1.0, PantPress * 0.5 ); // nieszczelności: 0.0003=0.3l/s @@ -4355,7 +4353,7 @@ double TMoverParameters::TractionForce( double dt ) { case 1: { // manual if( ( ActiveDir != 0 ) - && ( RList[ MainCtrlActualPos ].R > RVentCutOff ) ) { + && ( RList[ MainCtrlActualPos ].R > RVentCutOff ) ) { RventRot += ( RVentnmax - RventRot ) * RVentSpeed * dt; } else { @@ -4367,7 +4365,7 @@ double TMoverParameters::TractionForce( double dt ) { case 2: { // automatic auto const motorcurrent{ std::min( ImaxHi, std::abs( Im ) ) }; if( ( std::abs( Itot ) > RVentMinI ) - && ( RList[ MainCtrlActualPos ].R > RVentCutOff ) ) { + && ( RList[ MainCtrlActualPos ].R > RVentCutOff ) ) { RventRot += ( RVentnmax @@ -8512,8 +8510,8 @@ void TMoverParameters::LoadFIZ_PowerParamsDecode( TPowerParameters &Powerparamet //ciśnienie rozłączające WS extract_value( collectorparameters.MinPress, "MinPress", Line, "3.5" ); //domyślnie 2 bary do załączenia WS //maksymalne ciśnienie za reduktorem - collectorparameters.MaxPress = 5.0 + 0.001 * ( Random( 50 ) - Random( 50 ) ); - extract_value( collectorparameters.MaxPress, "MaxPress", Line, "" ); +// collectorparameters.MaxPress = 5.0 + 0.001 * ( Random( 50 ) - Random( 50 ) ); + extract_value( collectorparameters.MaxPress, "MaxPress", Line, "5.0" ); break; } case TPowerSource::PowerCable: { diff --git a/Model3d.cpp b/Model3d.cpp index 41bd1ccb..2631d0f4 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -431,6 +431,12 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic >> Vertices[i].normal.x >> Vertices[i].normal.y >> Vertices[i].normal.z; + if( glm::length2( Vertices[ i ].normal ) > 0.0f ) { + glm::normalize( Vertices[ i ].normal ); + } + else { + WriteLog( "Bad model: zero length normal vector specified in: \"" + pName + "\", vertex " + std::to_string(i), logtype::model ); + } wsp[i] = i; // wektory normalne "są już policzone" } parser.getTokens(2, false); @@ -464,7 +470,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic /* glm::vec3 *n = new glm::vec3[iNumFaces]; // tablica wektorów normalnych dla trójkątów */ - std::vector facenormals; + std::vector facenormals; facenormals.reserve( facecount ); for( int i = 0; i < facecount; ++i ) { // pętla po trójkątach - będzie szybciej, jak wstępnie przeliczymy normalne trójkątów auto facenormal = @@ -1127,7 +1133,7 @@ TSubModel *TModel3d::AddToNamed(const char *Name, TSubModel *SubModel) TSubModel *sm = Name ? GetFromName(Name) : nullptr; if( ( sm == nullptr ) && ( Name != nullptr ) && ( std::strcmp( Name, "none" ) != 0 ) ) { - ErrorLog( "Bad model: parent for sub-model \"" + SubModel->pName +"\" doesn't exist or is located after in the model data", logtype::model ); + ErrorLog( "Bad model: parent for sub-model \"" + SubModel->pName +"\" doesn't exist or is located later in the model data", logtype::model ); } AddTo(sm, SubModel); // szukanie nadrzędnego return sm; // zwracamy wskaźnik do nadrzędnego submodelu diff --git a/drivermode.cpp b/drivermode.cpp index 54ec80a8..e952a0ae 100644 --- a/drivermode.cpp +++ b/drivermode.cpp @@ -571,12 +571,13 @@ driver_mode::OnKeyDown(int cKey) { simulation::Events.AddToQuery( KeyEvents[ i ], NULL ); } } - else // zapamiętywanie kamery może działać podczas pauzy + else if( Global.ctrlState ) { + // zapamiętywanie kamery może działać podczas pauzy if( FreeFlyModeFlag ) { // w trybie latania można przeskakiwać do ustawionych kamer - if( ( !Global.FreeCameraInit[ i ].x ) - && ( !Global.FreeCameraInit[ i ].y ) - && ( !Global.FreeCameraInit[ i ].z ) ) { + if( ( Global.FreeCameraInit[ i ].x == 0.0 ) + && ( Global.FreeCameraInit[ i ].y == 0.0 ) + && ( Global.FreeCameraInit[ i ].z == 0.0 ) ) { // jeśli kamera jest w punkcie zerowym, zapamiętanie współrzędnych i kątów Global.FreeCameraInit[ i ] = Camera.Pos; Global.FreeCameraInitAngle[ i ].x = Camera.Pitch; @@ -598,7 +599,7 @@ driver_mode::OnKeyDown(int cKey) { Camera.Init( Global.FreeCameraInit[ i ], Global.FreeCameraInitAngle[ i ], TCameraType::tp_Free ); // przestawienie } } - // będzie jeszcze załączanie sprzęgów z [Ctrl] + } } else if( ( cKey >= GLFW_KEY_F1 ) && ( cKey <= GLFW_KEY_F12 ) ) { diff --git a/material.cpp b/material.cpp index f11b97a1..5fedce14 100644 --- a/material.cpp +++ b/material.cpp @@ -38,7 +38,8 @@ opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool c if( ( true == key.empty() ) || ( key == "}" ) ) { return false; } - auto const value { Input.getToken( true, "\n\r\t ,;" ) }; + // NOTE: comma can be part of legacy file names, so we don't treat it as a separator here + auto const value { Input.getToken( true, "\n\r\t ;" ) }; if( Priority != -1 ) { // regular attribute processing mode