unit _mover;          {fizyka ruchu dla symulatora lokomotywy}

(*
    MaSzyna EU07 locomotive simulator
    Copyright (C) 2001-2004  Maciej Czapkiewicz and others

*)


(*
(C) McZapkie v.2004.02
Co brakuje:
6. brak pantografow itp  'Nie do konca, juz czesc zrobiona - Winger
7. brak efektu grzania oporow rozruchowych, silnika, osi
9. ulepszyc sprzeg sztywny oraz automatyczny
10. klopoty z EN57
...
n. Inne lokomotywy oprocz elektrowozu pradu stalego
*)
(*
Zrobione:
1. model szeregowego silnika elektrycznego sterowanego reostatem
2. fizyka ruchu - sily oporu, nachylenia, przyspieszenia styczne i normalne,
przyczepnosc/poslizg przy hamowaniu i rozruchu
3. docisk klockow hamulcowych -hamulec reczny oraz pomocniczy hamulec pneumatyczny
4. ubytki cisnienia wskutek hamowania, kompresor - ladowanie zbiornika
5. niektore uszkodzenia i awarie - logika rozmyta
a) silnik elektryczny - za duzy prad, napiecie, obroty
b) sprzegi - zerwanie gdy zbyt duze sily
6. flagi niektorych dzwiekow
7. hamulec zasadniczy - elektropneumatyczny (impulsowanie), pneumatyczny - zmiany cisnienia
zwiekszenie nacisku przy duzych predkosciach w hamulcach Oerlikona
8. sprzegi - sila, tlumiennosc
9. lok. el. - wylacznik glowny, odlacznik uszkodzonych silnikow
10. parametry trakcji
11. opoznienia w zalaczaniu stycznikow
12. trakcja wielokrotna
13. informacja na temat zrodla mocy dla silnikow trakcyjnych, ogrzewania, oswietlenia
14. dumb - uproszczony model lokomotywy (tylko dla AI)
15. ladunki - ilosc, typ, szybkosc na- i rozladunku, funkcje przetestowac!
16. ulepszony model fizyczny silnika elektrycznego (hamowanie silnikiem, ujemne napiecia)
17. poprawione hamulce - parametry cylindrow itp
18. ulepszone hamulce - napelnianie uderzeniowe, stopnie hamowania
19. poprawione hamulce - wyszczegolnenie cisnienia dla stopni hamowania
20. poprawione hamulce elektropneumatyczne
21. poprawione hamowanie przeciwposlizgowe i odluzniacz
22. dodany model mechanicznego napedu recznego (drezyna)
23. poprawiona szybkosc hamowania pomocniczego i przeciwposlizgowego, odlaczanie silnikow, odlaczanie bocznikow
24. wprowadzone systemy zabezpieczenia: SHP, Czuwak, sygnalizacja kabinowa (nie dzialaja w DebugMode).
25. poprawiona predkosc propagacji fali cisnienia (normalizacja przez kwadrat dlugosci) //to jest zdeka liniowe
26. uwzgledniona masa ladunku, przesuniecie w/m toru ruchu
27. lampy/sygnaly przednie/tylne
28. wprowadzona pozycja odciecia hamulca (yB: tja, ale oerlikona....)
29. rozne poprawki: slizganie, wykolejanie itp
30. model silnika spalinowego z przekladnia mechaniczna
31. otwieranie drzwi, sprezarka, przetwornica
32. wylaczanie obliczen dla nieruchomych wagonow
33. Zbudowany model rozdzielacza powietrza roznych systemow
34. Poprawiona pozycja napelniania uderzeniowego i hamulec EP
35. Dodane baterie akumulatorow (KURS90)
36. Hamowanie elektrodynamiczne w ET42 i poprawione w EP09
37. jednokierunkowosc walu kulakowego w EZT (nie do konca)
38. wal kulakowy w ET40
39. poprawiona blokada nastawnika w ET40
...
*)


interface uses mctools,sysutils,hamulce,Oerlikon_ESt;

CONST
   Go=true;
   Hold=false;                 {dla CheckLocomotiveParameters}
   ResArraySize=64;            {dla silnikow elektrycznych}
   MotorParametersArraySize=10;
   maxcc=4;                    {max. ilosc odbierakow pradu}
   LocalBrakePosNo=10;         {ilosc nastaw hamulca pomocniczego}
   MainBrakeMaxPos=10;          {max. ilosc nastaw hamulca zasadniczego}
   ManualBrakePosNo=20;        {ilosc nastaw hamulca recznego}
   LightsSwitchPosNo=16;

   {uszkodzenia toru}
   dtrack_railwear=2;
   dtrack_freerail=4;
   dtrack_thinrail=8;
   dtrack_railbend=16;
   dtrack_plants=32;
   dtrack_nomove=64;
   dtrack_norail=128;

   {uszkodzenia taboru}
   dtrain_thinwheel=1;     {dla lokomotyw}
   dtrain_loadshift=1;     {dla wagonow}
   dtrain_wheelwear=2;
   dtrain_bearing=4;
   dtrain_coupling=8;
   dtrain_ventilator=16;   {dla lokomotywy el.}
   dtrain_loaddamage=16;   {dla wagonow}
   dtrain_engine=32;       {dla lokomotyw}
   dtrain_loaddestroyed=32;{dla wagonow}
   dtrain_axle=64;
   dtrain_out=128;         {wykolejenie}

   {wagi prawdopodobienstwa dla funkcji FuzzyLogic}
   p_elengproblem = 0.01;
   p_elengdamage = 0.1;
   p_coupldmg = 0.02;
   p_derail=0.001;
   p_accn=0.1;
   p_slippdmg=0.001;

   {typ sprzegu}
   ctrain_virtual=0;        //gdy pojazdy na tym samym torze się widzą wzajemnie
   ctrain_coupler=1;        //sprzeg fizyczny
   ctrain_pneumatic=2;      //przewody hamulcowe
   ctrain_controll=4;       //przewody sterujące (ukrotnienie)
   ctrain_power=8;          //przewody zasilające (WN)
   ctrain_passenger=16;     //mostek przejściowy
   ctrain_scndpneumatic=32; //przewody 8 atm (żółte; zasilanie powietrzem)
   ctrain_heating=64;       //przewody ogrzewania WN
   ctrain_depot=128;        //nie rozłączalny podczas zwykłych manewrów (międzyczłonowy), we wpisie wartość ujemna

   {typ hamulca elektrodynamicznego}
   dbrake_none=0;
   dbrake_passive=1;
   dbrake_switch=2;
   dbrake_reversal=4;
   dbrake_automatic=8;

   {status czuwaka/SHP}
   //hunter-091012: rozdzielenie alarmow, dodanie testu czuwaka
   s_waiting=1; //działa
   s_aware=2;   //czuwak miga
   s_active=4;  //SHP świeci
   s_CAalarm=8;    //buczy
   s_SHPalarm=16;  //buczy
   s_CAebrake=32;  //hamuje
   s_SHPebrake=64; //hamuje
   s_CAtest=128;
   
   {dzwieki}
   sound_none=0;
   sound_loud=1;
   sound_couplerstretch=2;
   sound_bufferclamp=4;
   sound_bufferbump=8;
   sound_relay=16;
   sound_manyrelay=32;
   sound_brakeacc=64;

   PhysicActivationFlag: boolean=false;

   //szczególne typy pojazdów (inna obsługa) dla zmiennej TrainType
   //zamienione na flagi bitowe, aby szybko wybierać grupę (np. EZT+SZT)
   dt_Default=0;
   dt_EZT=1;
   dt_ET41=2;
   dt_ET42=4;
   dt_PseudoDiesel=8;
   dt_ET22=$10; //używane od Megapacka
   dt_SN61=$20; //nie używane w warunkach, ale ustawiane z CHK
   dt_EP05=$40;
   dt_ET40=$80;
   dt_181=$100;

//stałe dla asynchronów
  eimc_s_dfic=0;
  eimc_s_dfmax=1;
  eimc_s_p=2;
  eimc_s_cfu=3;
  eimc_s_cim=4;
  eimc_s_icif=5;
  eimc_f_Uzmax=7;
  eimc_f_Uzh=8;
  eimc_f_DU=9;
  eimc_f_I0=10;
  eimc_f_cfu=11;
  eimc_p_F0=13;
  eimc_p_a1=14;
  eimc_p_Pmax=15;
  eimc_p_Fh=16;
  eimc_p_Ph=17;
  eimc_p_Vh0=18;
  eimc_p_Vh1=19;
  eimc_p_Imax=20;
  eimc_p_abed=21;
  eimc_p_eped=22;

//zmienne dla asynchronów
  eimv_FMAXMAX=0;
  eimv_Fmax=1;
  eimv_ks=2;
  eimv_df=3;
  eimv_fp=4;
  eimv_U=5;
  eimv_pole=6;
  eimv_Ic=7;
  eimv_If=8;
  eimv_M=9;
  eimv_Fr=10;
  eimv_Ipoj=11;
  eimv_Pm=12;
  eimv_Pe=13;
  eimv_eta=14;
  eimv_fkr=15;
  eimv_Uzsmax=16;
  eimv_Pmax=17;
  eimv_Fzad=18;
  eimv_Imax=19;
  eimv_Fful=20;

  bom_PS = 1;
  bom_PN = 2;
  bom_EP = 4;
  bom_MED = 8;

TYPE
    {ogolne}
    TLocation = record
                  X,Y,Z: real;    {lokacja}
                end;
    TRotation = record
                  Rx,Ry,Rz: real; {rotacja}
                end;
    TDimension= record
                  W,L,H: real;    {wymiary}
                end;

    TCommand = record
                 Command: string;         {komenda}
                 Value1,Value2: real;     {argumenty komendy}
                 Location: TLocation;
               end;

    {tory}
    TTrackShape= record      {ksztalt odcinka - promien, dlugosc, nachylenie, przechylka}
                  R, Len, dHtrack, dHrail: real;
                end;

    TTrackParam= record     {parametry odcinka - szerokosc, tarcie statyczne, kategoria,  obciazalnosc w t/os, uszkodzenia}
                  Width, friction: real;
                  CategoryFlag, QualityFlag, DamageFlag: byte;
                  Velmax:real; {dla uzytku maszynisty w ai_driver}
                end;
    TTractionParam= record
                      TractionVoltage: real; {napiecie}
                      TractionFreq: real;    {czestotliwosc}
                      TractionMaxCurrent: real; {obciazalnosc}
                      TractionResistivity: real; {rezystancja styku}
                    end;
    {powyzsze parametry zwiazane sa z torem po ktorym aktualnie pojazd jedzie}

    {typy hamulcow zespolonych}
    TBrakeSystem = (Individual, Pneumatic, ElectroPneumatic);
    {podtypy hamulcow zespolonych}
    TBrakeSubSystem = (ss_None, ss_W, ss_K, ss_KK, ss_Hik, ss_ESt, ss_KE, ss_LSt, ss_MT, ss_Dako);
    TBrakeValve = (NoValve, W, W_Lu_VI, W_Lu_L, W_Lu_XR, K, Kg, Kp, Kss, Kkg, Kkp, Kks, Hikg1, Hikss, Hikp1, KE, SW, EStED, NESt3, ESt3, LSt, ESt4, ESt3AL2, EP1, EP2, M483, CV1_L_TR, CV1, CV1_R, Other);
    TBrakeHandle = (NoHandle, West, FV4a, M394, M254, FVel1, FVel6, D2, Knorr, FD1, BS2, testH, St113, MHZ_P, MHZ_T, MHZ_EN57);
    {typy hamulcow indywidualnych}
    TLocalBrake = (NoBrake, ManualBrake, PneumaticBrake, HydraulicBrake);

    TBrakeDelayTable= array[1..4] of real;
    {dla osob/towar: opoznienie hamowania/odhamowania}

    TBrakePressure= record
                      PipePressureVal: real;
                      BrakePressureVal: real;
                      FlowSpeedVal: real;
                      BrakeType: TBrakeSystem;
                    end;
    TBrakePressureTable= array[-2..MainBrakeMaxPos] of TBrakePressure;

    {typy napedow}
    TEngineTypes = (None, Dumb, WheelsDriven, ElectricSeriesMotor, ElectricInductionMotor, DieselEngine, SteamEngine, DieselElectric);
    {postac dostarczanej energii}
    TPowerType = (NoPower, BioPower, MechPower, ElectricPower, SteamPower);
    {rodzaj paliwa}
    TFuelType = (Undefined, Coal, Oil);
    {rodzaj rusztu}
    TGrateType = record
                   FuelType: TFuelType;
                   GrateSurface: real;
                   FuelTransportSpeed: real;
                   IgnitionTemperature: real;
                   MaxTemperature: real;
                 end;
    {rodzaj kotla}
    TBoilerType = record
                    BoilerVolume: real;
                    BoilerHeatSurface: real;
                    SuperHeaterSurface: real;
                    MaxWaterVolume,MinWaterVolume: real;
                    MaxPressure: real;
                  end;
    {rodzaj odbieraka pradu}
    TCurrentCollector = record
                          CollectorsNo: longint; //musi być tu, bo inaczej się kopie
                          MinH,MaxH: real; //zakres ruchu pantografu, nigdzie nie używany
                          CSW: real;       //szerokość części roboczej (styku) ślizgacza
                          MinV,MaxV: real; //minimalne i maksymalne akceptowane napięcie
                          OVP: real;       //czy jest przekaznik nadnapieciowy
                          InsetV: real;    //minimalne napięcie wymagane do załączenia
                          MinPress: real;  //minimalne ciśnienie do załączenia WS
                          MaxPress: real;  //maksymalne ciśnienie za reduktorem
                        end;
    {typy źródeł mocy}
    TPowerSource = (NotDefined, InternalSource, Transducer, Generator, Accumulator, CurrentCollector, PowerCable, Heater);
    {parametry źródeł mocy}
    TPowerParameters = record
                         MaxVoltage: real;
                         MaxCurrent: real;
                         IntR: real;
                         case SourceType: TPowerSource of
                          NotDefined,InternalSource : (PowerType: TPowerType);
                          Transducer : (InputVoltage: real);
                          Generator  : (GeneratorEngine: TEngineTypes);
                          Accumulator: (RAccumulator:record MaxCapacity:real; RechargeSource:TPowerSource end);
                          CurrentCollector: (CollectorParameters: TCurrentCollector);
                          PowerCable : (RPowerCable:record PowerTrans:TPowerType; SteamPressure:real end);
                          Heater : (RHeater:record Grate:TGrateType; Boiler:TBoilerType end);
                       end;

    {dla lokomotyw elektrycznych:}
    TScheme= record
               Relay: byte; {numer pozycji rozruchu samoczynnego}
               R: real;    {opornik rozruchowy}                   {dla dizla napelnienie}
               Bn,Mn:byte; {ilosc galezi i silnikow w galezi}     {dla dizla Mn: czy luz czy nie}
               AutoSwitch: boolean; {czy dana pozycja nastawniana jest recznie czy autom.}
               ScndAct: byte; {jesli ma bocznik w nastawniku, to ktory bocznik na ktorej pozycji}
             end;
    TSchemeTable = array[0..ResArraySize] of TScheme; {tablica rezystorow rozr.}
    TDEScheme= record
               RPM:   real;  {obroty diesla}
               GenPower: real;  {moc maksymalna}
               Umax:  real;  {napiecie maksymalne}
               Imax:  real;  {prad maksymalny}
             end;
    TDESchemeTable = array[0..32] of TDEScheme; {tablica rezystorow rozr.}
    TShuntScheme = record
                Umin: real;
                Umax: real;
                Pmin: real;
                Pmax: real;
                end;
    TShuntSchemeTable = array[0..32] of TShuntScheme;
    TMPTRelay = record {lista przekaznikow bocznikowania}
                Iup: real;
                Idown: real;
                end;
    TMPTRelayTable = array[0..7] of TMPTRelay;

    TMotorParameters = record
                        mfi,mIsat,mfi0:real; // aproksymacja M(I) silnika} {dla dizla mIsat=przekladnia biegu
                        fi,Isat,fi0: real;  // aproksymacja E(n)=fi*n}    {dla dizla fi, mfi: predkosci przelozenia biegu <->
                        AutoSwitch: boolean;
                       end;

    TSecuritySystem= record
                       SystemType:byte; {0: brak, 1: czuwak aktywny, 2: SHP/sygnalizacja kabinowa}
                       AwareDelay:real; //czas powtarzania czuwaka
                       AwareMinSpeed:real; //minimalna prędkość załączenia czuwaka, normalnie 10% Vmax
                       SoundSignalDelay,EmergencyBrakeDelay:real;
                       Status: byte;     {0: wylaczony, 1: wlaczony, 2: czuwak, 4: shp, 8: alarm, 16: hamowanie awaryjne}
                       //SystemTimer, SystemSoundTimer, SystemBrakeTimer: real;
                       SystemTimer, SystemSoundCATimer, SystemSoundSHPTimer, SystemBrakeCATimer, SystemBrakeSHPTimer, SystemBrakeCATestTimer: real; //hunter-091012
                       VelocityAllowed, NextVelocityAllowed: integer; {predkosc pokazywana przez sygnalizacje kabinowa}
                       RadioStop:boolean; //czy jest RadioStop
                     end;

 //Ra: to oddzielnie, bo się kompilatorowi miesza
 TTransmision=
  record  //liczba zebow przekladni}
   NToothM, NToothW : byte;
   Ratio: real;  {NToothW/NToothM}
  end;

 {sprzegi}
 TCouplerType=(NoCoupler,Articulated,Bare,Chain,Screw,Automatic);
 //Ra: T_MoverParameters jako klasa jest już wskaźnikiem na poziomie Pascala
 //P_MoverParameters=^T_MoverParameters
 T_MoverParameters=class;
 TCoupling = record
               {parametry}
               SpringKB,SpringKC,beta:real;   {stala sprezystosci zderzaka/sprzegu, %tlumiennosci }
               DmaxB,FmaxB,DmaxC,FmaxC: real; {tolerancja scisku/rozciagania, sila rozerwania}
               CouplerType: TCouplerType;     {typ sprzegu}
               {zmienne}
               CouplingFlag : byte; {0 - wirtualnie, 1 - sprzegi, 2 - pneumatycznie, 4 - sterowanie, 8 - kabel mocy}
               AllowedFlag : Integer;       //Ra: znaczenie jak wyżej, maska dostępnych
               Render: boolean;             {ABu: czy rysowac jak zaczepiony sprzeg}
               CoupleDist: real;            {ABu: optymalizacja - liczenie odleglosci raz na klatkę, bez iteracji}
               Connected: T_MoverParameters; {co jest podlaczone}
               ConnectedNr: byte;           //Ra: od której strony podłączony do (Connected): 0=przód, 1=tył
               CForce: real;                {sila z jaka dzialal}
               Dist: real;                  {strzalka ugiecia zderzaków}
               CheckCollision: boolean;     {czy sprawdzac sile czy pedy}
             end;

 //TCouplers= array[0..1] of TCoupling;
 //TCouplerNr= array[0..1] of byte; //ABu: nr sprzegu z ktorym polaczony; Ra: wrzucić do TCoupling

    {----------------------------------------------}
    {glowny obiekt}
    T_MoverParameters = class(TObject) //Ra: dodana kreska w celu zrobienia wrappera
               dMoveLen:real;
               filename:string;
               {---opis lokomotywy, wagonu itp}
                    {--opis serii--}
               CategoryFlag: byte;       {1 - pociag, 2 - samochod, 4 - statek, 8 - samolot}
                    {--sekcja stalych typowych parametrow}
               TypeName: string;         {nazwa serii/typu}
               //TrainType: string;       {typ: EZT/elektrowoz - Winger 040304}
               TrainType: integer; {Ra: powinno być szybciej niż string}
               EngineType: TEngineTypes;               {typ napedu}
               EnginePowerSource: TPowerParameters;    {zrodlo mocy dla silnikow}
               SystemPowerSource: TPowerParameters;    {zrodlo mocy dla systemow sterowania/przetwornic/sprezarek}
               HeatingPowerSource: TPowerParameters;   {zrodlo mocy dla ogrzewania}
               AlterHeatPowerSource: TPowerParameters; {alternatywne zrodlo mocy dla ogrzewania}
               LightPowerSource: TPowerParameters;     {zrodlo mocy dla oswietlenia}
               AlterLightPowerSource: TPowerParameters;{alternatywne mocy dla oswietlenia}
               Vmax,Mass,Power: real;    {max. predkosc kontrukcyjna, masa wlasna, moc}
               Mred: real;    {Ra: zredukowane masy wirujące; potrzebne do obliczeń hamowania}
               TotalMass:real; {wyliczane przez ComputeMass}
               HeatingPower, LightPower: real; {moc pobierana na ogrzewanie/oswietlenie}
               BatteryVoltage: real;        {Winger - baterie w elektrykach}
               Battery: boolean; {Czy sa zalavzone baterie}
               EpFuse: boolean; {Czy sa zalavzone baterie}
               Signalling: boolean;         {Czy jest zalaczona sygnalizacja hamowania ostatniego wagonu}
               DoorSignalling: boolean;         {Czy jest zalaczona sygnalizacja blokady drzwi}
               Radio: boolean;         {Czy jest zalaczony radiotelefon}
               NominalBatteryVoltage: real;        {Winger - baterie w elektrykach}
               Dim: TDimension;          {wymiary}
               Cx: real;                 {wsp. op. aerodyn.}
               Floor: real;              //poziom podłogi dla ładunków
               WheelDiameter : real;     {srednica kol napednych}
               WheelDiameterL : real;    //Ra: srednica kol tocznych przednich
               WheelDiameterT : real;    //Ra: srednica kol tocznych tylnych
               TrackW: real;             {nominalna szerokosc toru [m]}
               AxleInertialMoment: real; {moment bezwladnosci zestawu kolowego}
               AxleArangement : string;  {uklad osi np. Bo'Bo' albo 1'C}
               NPoweredAxles : byte;     {ilosc osi napednych liczona z powyzszego}
               NAxles : byte;            {ilosc wszystkich osi j.w.}
               BearingType: byte;        {lozyska: 0 - slizgowe, 1 - toczne}
               ADist, BDist: real;       {odlegosc osi oraz czopow skretu}
               {hamulce:}
               NBpA : byte;              {ilosc el. ciernych na os: 0 1 2 lub 4}
               SandCapacity: integer;    {zasobnik piasku [kg]}
               BrakeSystem: TBrakeSystem;{rodzaj hamulca zespolonego}
               BrakeSubsystem: TBrakeSubsystem;
               BrakeValve: TBrakeValve;
               BrakeHandle: TBrakeHandle;
               BrakeLocHandle: TBrakeHandle;
               MBPM: real; {masa najwiekszego cisnienia}

               Hamulec: TBrake;
               Handle: THandle;
               LocHandle: THandle;
               Pipe, Pipe2: TReservoir;

               LocalBrake: TLocalBrake;  {rodzaj hamulca indywidualnego}
               BrakePressureTable: TBrakePressureTable; {wyszczegolnienie cisnien w rurze}
               BrakePressureActual: TBrakePressure; //wartości ważone dla aktualnej pozycji kranu
               ASBType: byte;            {0: brak hamulca przeciwposlizgowego, 1: reczny, 2: automat}
               TurboTest: byte;
               MaxBrakeForce: real;      {maksymalna sila nacisku hamulca}
               MaxBrakePress: array[0..4] of real; //pomocniczy, proz, sred, lad, pp
               P2FTrans: real;
               TrackBrakeForce: real;    {sila nacisku hamulca szynowego}
               BrakeMethod: byte;        {flaga rodzaju hamulca}
               {max. cisnienie w cyl. ham., stala proporcjonalnosci p-K}
               HighPipePress,LowPipePress,DeltaPipePress: real;
               {max. i min. robocze cisnienie w przewodzie glownym oraz roznica miedzy nimi}
               CntrlPipePress: real; //ciśnienie z zbiorniku sterującym
               BrakeVolume, BrakeVVolume, VeselVolume: real;
               {pojemnosc powietrza w ukladzie hamulcowym, w ukladzie glownej sprezarki [m^3] }
               BrakeCylNo: integer; {ilosc cylindrow ham.}
               BrakeCylRadius, BrakeCylDist: real;
               BrakeCylMult: array[0..2] of real;
               LoadFlag: byte;
               {promien cylindra, skok cylindra, przekladnia hamulcowa}
               BrakeCylSpring: real; {suma nacisku sprezyn powrotnych, kN}
               BrakeSlckAdj: real; {opor nastawiacza skoku tloka, kN}
               BrakeRigEff: real; {sprawnosc przekladni dzwigniowej}
               RapidMult: real; {przelozenie rapidu}
               BrakeValveSize: integer;
               BrakeValveParams: string;
               Spg: real;
               MinCompressor,MaxCompressor,CompressorSpeed:real;
               {cisnienie wlaczania, zalaczania sprezarki, wydajnosc sprezarki}
               BrakeDelay: TBrakeDelayTable; {opoznienie hamowania/odhamowania t/o}
               BrakeCtrlPosNo:byte;     {ilosc pozycji hamulca}
               {nastawniki:}
               MainCtrlPosNo: byte;     {ilosc pozycji nastawnika}
               ScndCtrlPosNo: byte;
               LightsPosNo, LightsDefPos: byte;
               LightsWrap: boolean;
               Lights: array [0..1] of array [1..16] of byte;
               ScndInMain: boolean;     {zaleznosc bocznika od nastawnika}
               MBrake: boolean;     {Czy jest hamulec reczny}
               StopBrakeDecc: real;
               SecuritySystem: TSecuritySystem;

                       {-sekcja parametrow dla lokomotywy elektrycznej}
               RList: TSchemeTable;     {lista rezystorow rozruchowych i polaczen silnikow, dla dizla: napelnienia}
               RlistSize: integer;
               MotorParam: array[0..MotorParametersArraySize] of TMotorParameters;
                                        {rozne parametry silnika przy bocznikowaniach}
                                        {dla lokomotywy spalinowej z przekladnia mechaniczna: przelozenia biegow}
               Transmision : TTransmision;
                // record   {liczba zebow przekladni}
                //  NToothM, NToothW : byte;
                //  Ratio: real;  {NToothW/NToothM}
                // end;
               NominalVoltage: real;   {nominalne napiecie silnika}
               WindingRes : real;
               u: real; //wspolczynnik tarcia yB wywalic!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
               CircuitRes : real;      {rezystancje silnika i obwodu}
               IminLo,IminHi: integer; {prady przelacznika automatycznego rozruchu, uzywane tez przez ai_driver}
               ImaxLo,ImaxHi: integer; {maksymalny prad niskiego i wysokiego rozruchu}
               nmax: real;             {maksymalna dop. ilosc obrotow /s}
               InitialCtrlDelay,       {ile sek. opoznienia po wl. silnika}
               CtrlDelay: real;        { -//-  -//- miedzy kolejnymi poz.}
               CtrlDownDelay: real;    { -//-  -//- przy schodzeniu z poz.} {hunter-101012}
               FastSerialCircuit: byte;{0 - po kolei zamyka styczniki az do osiagniecia szeregowej, 1 - natychmiastowe wejscie na szeregowa} {hunter-111012}
               AutoRelayType: byte;    {0 -brak, 1 - jest, 2 - opcja}
               CoupledCtrl: boolean;   {czy mainctrl i scndctrl sa sprzezone}
               //CouplerNr: TCouplerNr;  {ABu: nr sprzegu podlaczonego w drugim obiekcie}
               IsCoupled: boolean;     {czy jest sprzezony ale jedzie z tylu}
               DynamicBrakeType: byte; {patrz dbrake_*}
               RVentType: byte;        {0 - brak, 1 - jest, 2 - automatycznie wlaczany}
               RVentnmax: real;      {maks. obroty wentylatorow oporow rozruchowych}
               RVentCutOff: real;      {rezystancja wylaczania wentylatorow dla RVentType=2}
               CompressorPower: integer; {0: bezp. z obwodow silnika, 1: z przetwornicy, reczne, 2: w przetwornicy, stale, 5: z silnikowego}
               SmallCompressorPower: integer; {Winger ZROBIC}
               Trafo: boolean;      {pojazd wyposażony w transformator} 

                      {-sekcja parametrow dla lokomotywy spalinowej z przekladnia mechaniczna}
                dizel_Mmax, dizel_nMmax, dizel_Mnmax, dizel_nmax, dizel_nominalfill: real;
                 {parametry aproksymacji silnika spalinowego}
                dizel_Mstand: real; {moment oporow ruchu silnika dla enrot=0}
{                dizel_auto_min, dizel_auto_max: real; {predkosc obrotowa przelaczania automatycznej skrzyni biegow}
                dizel_nmax_cutoff: real; {predkosc obrotowa zadzialania ogranicznika predkosci}
                dizel_nmin: real; {najmniejsza dopuszczalna predkosc obrotowa}
                dizel_minVelfullengage: real; {najmniejsza predkosc przy jezdzie ze sprzeglem bez poslizgu}
                dizel_AIM: real; {moment bezwladnosci walu itp}
                dizel_engageDia, dizel_engageMaxForce, dizel_engagefriction: real; {parametry sprzegla}

                {- dla lokomotyw spalinowo-elektrycznych -}
                AnPos: real; // pozycja sterowania dokladnego (analogowego)
                AnalogCtrl: boolean; //
                AnMainCtrl: boolean; //
                ShuntModeAllow: boolean;
                ShuntMode: boolean;

                Flat: boolean;
                Vhyp: real;
                DElist: TDESchemeTable;
                Vadd: real;
                MPTRelay: TMPTRelayTable;
                RelayType: byte;
                SST: TShuntSchemeTable;
                PowerCorRatio: real; //Wspolczynnik korekcyjny


                {- dla uproszczonego modelu silnika (dumb) oraz dla drezyny}
                Ftmax:real;

                {- dla lokomotyw z silnikami indukcyjnymi -}
                eimc: array [0..25] of real;

                {-dla wagonow}
                MaxLoad: longint;           {masa w T lub ilosc w sztukach - ladownosc}
                LoadAccepted, LoadQuantity: string; {co moze byc zaladowane, jednostki miary}
                OverLoadFactor: real;       {ile razy moze byc przekroczona ladownosc}
                LoadSpeed,UnLoadSpeed: real;{szybkosc na- i rozladunku jednostki/s}
                DoorOpenCtrl,DoorCloseCtrl: byte; {0: przez pasazera, 1: przez maszyniste, 2: samoczynne (zamykanie)}
                DoorStayOpen: real;               {jak dlugo otwarte w przypadku DoorCloseCtrl=2}
                DoorClosureWarning: boolean;      {czy jest ostrzeganie przed zamknieciem}
                DoorOpenSpeed, DoorCloseSpeed: real;      {predkosc otwierania i zamykania w j.u. }
                DoorMaxShiftL,DoorMaxShiftR,DoorMaxPlugShift: real;{szerokosc otwarcia lub kat}
                DoorOpenMethod: byte;             {sposob otwarcia - 1: przesuwne, 2: obrotowe, 3: trójelementowe}
                PlatformSpeed: real;   {szybkosc stopnia}
                PlatformMaxShift: real; {wysuniecie stopnia}
                PlatformOpenMethod: byte; {sposob animacji stopnia}
                ScndS: boolean; {Czy jest bocznikowanie na szeregowej}

                        {--sekcja zmiennych}
                        {--opis konkretnego egzemplarza taboru}
                Loc: TLocation; //pozycja pojazdów do wyznaczenia odległości pomiędzy sprzęgami
                Rot: TRotation;
                Name: string;                       {nazwa wlasna}
                Couplers: array[0..1] of TCoupling;  //urzadzenia zderzno-sprzegowe, polaczenia miedzy wagonami
                HVCouplers: array[0..1] of array[0..1] of real; //przewod WN
                ScanCounter: integer;   {pomocnicze do skanowania sprzegow}
                EventFlag: boolean;                 {!o true jesli cos nietypowego sie wydarzy}
                SoundFlag: byte;                    {!o patrz stale sound_ }
                DistCounter: real;                  {! licznik kilometrow }
                V: real;    //predkosc w [m/s] względem sprzęgów (dodania gdy jedzie w stronę 0)
                Vel: real;  //moduł prędkości w [km/h], używany przez AI
                AccS: real; //efektywne przyspieszenie styczne w [m/s^2] (wszystkie siły)
                AccN: real; //przyspieszenie normalne w [m/s^2]
                AccV: real;
                nrot: real;
                {! rotacja kol [obr/s]}
                EnginePower: real;                  {! chwilowa moc silnikow}
                dL, Fb, Ff : real;                  {przesuniecie, sila hamowania i tarcia}
                FTrain,FStand: real;                {! sila pociagowa i oporow ruchu}
                FTotal: real;                       {! calkowita sila dzialajaca na pojazd}
                UnitBrakeForce: real;               {!s siła hamowania przypadająca na jeden element}
                Ntotal: real;               {!s siła nacisku klockow}
                SlippingWheels,SandDose: boolean;   {! poslizg kol, sypanie piasku}
                Sand: real;                         {ilosc piasku}
                BrakeSlippingTimer:real;            {pomocnicza zmienna do wylaczania przeciwposlizgu}
                dpBrake,dpPipe,dpMainValve,dpLocalValve: real;
                {! przyrosty cisnienia w kroku czasowym}
                ScndPipePress: real;                {cisnienie w przewodzie zasilajacym}
                BrakePress:real;                    {!o cisnienie w cylindrach hamulcowych}
                LocBrakePress:real;                 {!o cisnienie w cylindrach hamulcowych z pomocniczego}
                PipeBrakePress:real;                {!o cisnienie w cylindrach hamulcowych z przewodu}
                PipePress: real;                    {!o cisnienie w przewodzie glownym}
                EqvtPipePress: real;                {!o cisnienie w przewodzie glownym skladu}
                Volume: real;                       {objetosc spr. powietrza w zbiorniku hamulca}
                CompressedVolume:real;              {objetosc spr. powietrza w ukl. zasilania}
                PantVolume:real;                    {objetosc spr. powietrza w ukl. pantografu}
                Compressor: real;                   {! cisnienie w ukladzie zasilajacym}
                CompressorFlag: boolean;             {!o czy wlaczona sprezarka}
                PantCompFlag: boolean;             {!o czy wlaczona sprezarka pantografow}
                CompressorAllow: boolean;            {! zezwolenie na uruchomienie sprezarki  NBMX}
                ConverterFlag: boolean;              {!  czy wlaczona przetwornica NBMX}
                ConverterAllow: boolean;             {zezwolenie na prace przetwornicy NBMX}
                BrakeCtrlPos:integer;               {nastawa hamulca zespolonego}
                BrakeCtrlPosR:real;                 {nastawa hamulca zespolonego - plynna dla FV4a}
                BrakeCtrlPos2:real;                 {nastawa hamulca zespolonego - kapturek dla FV4a}
                LocalBrakePos:byte;                 {nastawa hamulca indywidualnego}
                ManualBrakePos:byte;                 {nastawa hamulca recznego}
                LocalBrakePosA: real;
                BrakeStatus: byte; {0 - odham, 1 - ham., 2 - uszk., 4 - odluzniacz, 8 - antyposlizg, 16 - uzyte EP, 32 - pozycja R, 64 - powrot z R}
                EmergencyBrakeFlag: boolean;        {hamowanie nagle}
                BrakeDelayFlag: byte;               {nastawa opoznienia ham. osob/towar/posp/exp 0/1/2/4}
                BrakeDelays: byte;                   {nastawy mozliwe do uzyskania}
                BrakeOpModeFlag: byte;               {nastawa trybu pracy PS/PN/EP/MED 1/2/4/8}
                BrakeOpModes: byte;                   {nastawy mozliwe do uzyskania}
                DynamicBrakeFlag: boolean;          {czy wlaczony hamulec elektrodymiczny}
//                NapUdWsp: integer;
                LimPipePress: real;                 {stabilizator cisnienia}
                ActFlowSpeed: real;                 {szybkosc stabilizatora}


                DamageFlag: byte;  //kombinacja bitowa stalych dtrain_* }
                EngDmgFlag: byte;  //kombinacja bitowa stalych usterek}
                DerailReason: byte; //przyczyna wykolejenia

                //EndSignalsFlag: byte;  {ABu 060205: zmiany - koncowki: 1/16 - swiatla prz/tyl, 2/31 - blachy prz/tyl}
                //HeadSignalsFlag: byte; {ABu 060205: zmiany - swiatla: 1/2/4 - przod, 16/32/63 - tyl}
                CommandIn: TCommand;
                {komenda przekazywana przez PutCommand}
                {i wykonywana przez RunInternalCommand}
                CommandOut: string;        {komenda przekazywana przez ExternalCommand}
                CommandLast: string; //Ra: ostatnio wykonana komenda do podglądu
                ValueOut: real;            {argument komendy która ma byc przekazana na zewnatrz}

                RunningShape:TTrackShape;{geometria toru po ktorym jedzie pojazd}
                RunningTrack:TTrackParam;{parametry toru po ktorym jedzie pojazd}
                OffsetTrackH, OffsetTrackV: real;  {przesuniecie poz. i pion. w/m osi toru}

                {-zmienne dla lokomotyw}
                Mains: boolean;    {polozenie glownego wylacznika}
                MainCtrlPos: byte; {polozenie glownego nastawnika}
                ScndCtrlPos: byte; {polozenie dodatkowego nastawnika}
                LightsPos: byte;
                ActiveDir: integer; //czy lok. jest wlaczona i w ktorym kierunku:
                //względem wybranej kabiny: -1 - do tylu, +1 - do przodu, 0 - wylaczona
                CabNo: integer; //numer kabiny, z której jest sterowanie: 1 lub -1; w przeciwnym razie brak sterowania - rozrzad
                DirAbsolute: integer; //zadany kierunek jazdy względem sprzęgów (1=w strone 0,-1=w stronę 1)
                ActiveCab: integer; //numer kabiny, w ktorej jest obsada (zwykle jedna na skład)
                LastSwitchingTime: real; {czas ostatniego przelaczania czegos}
                //WarningSignal: byte;     {0: nie trabi, 1,2: trabi}
                DepartureSignal: boolean; {sygnal odjazdu}
                InsideConsist: boolean;
                {-zmienne dla lokomotywy elektrycznej}
                RunningTraction:TTractionParam;{parametry sieci trakcyjnej najblizej lokomotywy}
                enrot, Im, Itot,IHeating,ITraction, TotalCurrent, Mm, Mw, Fw, Ft: real;
                {ilosc obrotow, prad silnika i calkowity, momenty, sily napedne}
                //Ra: Im jest ujemny, jeśli lok jedzie w stronę sprzęgu 1
                //a ujemne powinien być przy odwróconej polaryzacji sieci...
                //w wielu miejscach jest używane abs(Im)
                Imin,Imax: integer;      {prad przelaczania automatycznego rozruchu, prad bezpiecznika}
                Voltage: real;           {aktualne napiecie sieci zasilajacej}
                MainCtrlActualPos: byte; {wskaznik RList}
                ScndCtrlActualPos: byte; {wskaznik MotorParam}
                DelayCtrlFlag: boolean;  //czy czekanie na 1. pozycji na załączenie?
                LastRelayTime: real;     {czas ostatniego przelaczania stycznikow}
                AutoRelayFlag: boolean;  {mozna zmieniac jesli AutoRelayType=2}
                FuseFlag: boolean;       {!o bezpiecznik nadmiarowy}
                ConvOvldFlag: boolean;              {!  nadmiarowy przetwornicy i ogrzewania}
                StLinFlag: boolean;       {!o styczniki liniowe}
                ResistorsFlag: boolean;  {!o jazda rezystorowa}
                RventRot: real;          {!s obroty wentylatorow rozruchowych}
                UnBrake: boolean;       {w EZT - nacisniete odhamowywanie}
                PantPress: real; {Cisnienie w zbiornikach pantografow}
                s_CAtestebrake: boolean; //hunter-091012: zmienna dla testu ca


                {-zmienne dla lokomotywy spalinowej z przekladnia mechaniczna}
                dizel_fill: real; {napelnienie}
                dizel_engagestate: real; {sprzeglo skrzyni biegow: 0 - luz, 1 - wlaczone, 0.5 - wlaczone 50% (z poslizgiem)}
                dizel_engage: real; {sprzeglo skrzyni biegow: aktualny docisk}
                dizel_automaticgearstatus: real; {0 - bez zmiany, -1 zmiana na nizszy +1 zmiana na wyzszy}
                dizel_enginestart: boolean;      {czy trwa rozruch silnika}
                dizel_engagedeltaomega: real;    {roznica predkosci katowych tarcz sprzegla}

                {- zmienne dla lokomotyw z silnikami indukcyjnymi -}
                eimv: array [0..20] of real;

                {-zmienne dla drezyny}
                PulseForce :real;        {przylozona sila}
                PulseForceTimer: real;
                PulseForceCount: integer;

                {dla drezyny, silnika spalinowego i parowego}
                eAngle: real;

                {-dla wagonow}
                Load: longint;      {masa w T lub ilosc w sztukach - zaladowane}
                LoadType: string;   {co jest zaladowane}
                LoadStatus: byte; //+1=trwa rozladunek,+2=trwa zaladunek,+4=zakończono,0=zaktualizowany model
                LastLoadChangeTime: real; //raz (roz)ładowania

                DoorBlocked: boolean;    //Czy jest blokada drzwi
                DoorLeftOpened: boolean;  //stan drzwi
                DoorRightOpened: boolean;
                PantFrontUp: boolean;  //stan patykow 'Winger 160204
                PantRearUp: boolean;
                PantFrontSP: boolean;  //dzwiek patykow 'Winger 010304
                PantRearSP: boolean;
                PantFrontStart: integer;  //stan patykow 'Winger 160204
                PantRearStart: integer;
                PantFrontVolt: real;   //pantograf pod napieciem? 'Winger 160404
                PantRearVolt: real;
                PantSwitchType: string;
                ConvSwitchType: string;

                Heating: boolean; //ogrzewanie 'Winger 020304
                DoubleTr: integer; //trakcja ukrotniona - przedni pojazd 'Winger 160304

                PhysicActivation: boolean;

                {ABu: stale dla wyznaczania sil (i nie tylko) po optymalizacji}
                   FrictConst1:  real;
                   FrictConst2s: real;
                   FrictConst2d: real;
                   TotalMassxg     : real; {TotalMass*g}


                {--funkcje}


                function GetTrainsetVoltage: real;
                function Physic_ReActivation: boolean;

{                function BrakeRatio: real;  }
                function LocalBrakeRatio: real;
                function ManualBrakeRatio: real;
                function PipeRatio: real; {ile napelniac}
                function RealPipeRatio: real; {jak szybko}
                function BrakeVP: real;                
                function DynamicBrakeSwitch(Switch:boolean):boolean;

                {! przesylanie komend sterujacych}
                function SendCtrlBroadcast(CtrlCommand:string; ctrlvalue:real):boolean;
                function SendCtrlToNext(CtrlCommand:string;ctrlvalue,dir:real):boolean;
                function CabActivisation:boolean;
                function CabDeactivisation:boolean;

               {! funkcje zwiekszajace/zmniejszajace nastawniki}
               {! glowny nastawnik:}
                function IncMainCtrl(CtrlSpeed:integer): boolean;
                function DecMainCtrl(CtrlSpeed:integer): boolean;
               {! pomocniczy nastawnik:}
                function IncScndCtrl(CtrlSpeed:integer): boolean;
                function DecScndCtrl(CtrlSpeed:integer): boolean;

                function AddPulseForce(Multipler:integer): boolean; {dla drezyny}

                {wlacza/wylacza sypanie piasku}
                function SandDoseOn : boolean;

               {! zbijanie czuwaka/SHP}
                function SecuritySystemReset:boolean;
                {test czuwaka/SHP}
                procedure SecuritySystemCheck(dt:real);
                function BatterySwitch(State:boolean):boolean;
                function EpFuseSwitch(State:boolean):boolean;

               {! stopnie hamowania - hamulec zasadniczy}
                function IncBrakeLevelOld:boolean;
                function DecBrakeLevelOld:boolean;
               {! stopnie hamowania - hamulec pomocniczy}
                function IncLocalBrakeLevel(CtrlSpeed:byte):boolean;
                function DecLocalBrakeLevel(CtrlSpeed:byte):boolean;
               {! ABu 010205: - skrajne polozenia ham. pomocniczego}
                function IncLocalBrakeLevelFAST:boolean;
                function DecLocalBrakeLevelFAST:boolean;

                {! stopnie hamowania - hamulec reczny}
                function IncManualBrakeLevel(CtrlSpeed:byte):boolean;
                function DecManualBrakeLevel(CtrlSpeed:byte):boolean;

               {! hamulec bezpieczenstwa}
                function EmergencyBrakeSwitch(Switch:boolean): boolean;
               {hamulec przeciwposlizgowy}
                function AntiSlippingBrake: boolean;
               {odluzniacz}
                function BrakeReleaser(state: byte):boolean;
                function SwitchEPBrake(state: byte):boolean;

               {! reczny wlacznik urzadzen antyposlizgowych}
                function AntiSlippingButton: boolean;

               {funkcje dla ukladow pneumatycznych}
                function IncBrakePress(var brake:real;PressLimit,dp:real):boolean;
                function DecBrakePress(var brake:real;PressLimit,dp:real):boolean;
                function BrakeDelaySwitch(BDS:byte): boolean; {! przelaczanie nastawy opoznienia}
                function IncBrakeMult(): boolean; {przelaczanie prozny/ladowny}
                function DecBrakeMult(): boolean;
                {pomocnicze funkcje dla ukladow pneumatycznych}
                procedure UpdateBrakePressure(dt: real);
                procedure UpdatePipePressure(dt:real);
                procedure CompressorCheck(dt:real); {wlacza, wylacza kompresor, laduje zbiornik}
                procedure UpdateScndPipePressure(dt:real);
                //procedure UpdateBatteryVoltage(dt:real);
                function GetDVc(dt:real):real;

               {! funkcje laczace/rozlaczajace sprzegi}
               //Ra: przeniesione do C++

               {funkcje obliczajace sily}
                procedure ComputeConstans; //ABu: wczesniejsze wyznaczenie stalych dla liczenia sil
                //procedure SetCoupleDist;   //ABu: wyznaczenie odleglosci miedzy wagonami
                function ComputeMass:real;
                function Adhesive(staticfriction:real): real;
                function TractionForce(dt:real):real;
                function FrictionForce(R:real;TDamage:byte):real;
                function BrakeForce(Track:TTrackParam):real;
                function CouplerForce(CouplerN:byte; dt:real):real;
                procedure CollisionDetect(CouplerN:byte; dt:real);

                {obrot kol uwzgledniajacy poslizg}
                function ComputeRotatingWheel(WForce,dt,n:real): real;

                {komendy}
                function SetInternalCommand(NewCommand:string; NewValue1,NewValue2:real):boolean;
               {! do wpisywania komend przez zewnetrzne zdarzenia}
                function GetExternalCommand(var Command:string):real;
                function RunCommand(command:string; CValue1,CValue2:real):boolean;
                function RunInternalCommand:boolean;
                procedure PutCommand(NewCommand:string; NewValue1,NewValue2:real; NewLocation:TLocation);

                {--funkcje dla lokomotyw}
               {! kierunek ruchu}
                //function DirectionForward: boolean;
                function DirectionBackward: boolean;
               {! wylacznik glowny}
                function MainSwitch(State:boolean): boolean;
//                procedure SwitchMainKey;
               {! zmiana kabiny i resetowanie ustawien}
                //function ChangeCab(direction:integer): boolean;

               {! wl/wyl przetwornicy}
                function ConverterSwitch(State:boolean):boolean;
                {! wl/wyl sprezarki}
                function CompressorSwitch(State:boolean):boolean;
{                function SmallCompressorSwitch(State:boolean):boolean;}
                {procedure ConverterCheck; ->C++}

                {-funkcje typowe dla lokomotywy elektrycznej}
                {! wlaczanie bezpiecznika nadmiarowego}
                function FuseOn: boolean;
                function FuseFlagCheck: boolean; {sprawdzanei flagi nadmiarowego}
                procedure FuseOff; {wywalanie bezpiecznika nadmiarowego}
                {!o pokazuje bezwgl. wartosc pradu na wybranym amperomierzu}
                function ShowCurrent(AmpN:byte): integer;
                {!o pokazuje bezwgl. wartosc obrotow na obrotomierzu jednego z 3 pojazdow}
                {function ShowEngineRotation(VehN:byte): integer; //Ra 2014-06: przeniesione do C++}
                {funkcje uzalezniajace sile pociagowa od predkosci: v2n, n2r, current, momentum}
                function v2n:real;
                function current(n,U:real): real;
                function Momentum(I:real): real;
                function MomentumF(I, Iw :real; SCP:byte ): real;                
               {! odlaczanie uszkodzonych silnikow}
                function CutOffEngine: boolean;
               {! przelacznik pradu wysokiego rozruchu}
                function MaxCurrentSwitch(State:boolean):boolean;
                {sprawdzanie kontrolki rezystorow rozrochowych NBMX}
                function ResistorsFlagCheck: boolean;

               {! przelacznik pradu automatycznego rozruchu}
                function MinCurrentSwitch(State:boolean):boolean;
               {! przelacznik automatycznego rozruchu}
                function AutoRelaySwitch(State:boolean):boolean;
               {symulacja automatycznego rozruchu}
                function AutoRelayCheck: boolean;

                {-funkcje typowe dla lokomotywy spalinowej z przekladnia mechaniczna}
                function dizel_EngageSwitch(state: real): boolean;
                function dizel_EngageChange(dt: real): boolean;
                function dizel_AutoGearCheck: boolean;
                function dizel_fillcheck(mcp:byte): real;
{                function dizel_rotateengine(Momentum,dt,n,engage:real): real;  }
                function dizel_Momentum(dizel_fill,n,dt:real): real;
                function dizel_Update(dt:real): boolean;

               {-funkcje dla wagonow}
                function LoadingDone(LSpeed: real; LoadInit:string):boolean;

                {! WAZNA FUNKCJA - oblicza sile wypadkowa}
                procedure ComputeTotalForce(dt: real; dt1: real; FullVer: boolean);

                {! BARDZO WAZNA FUNKCJA - oblicza przesuniecie lokomotywy lub wagonu}
                function ComputeMovement(dt:real; dt1:real; Shape:TTrackShape; var Track:TTrackParam; var ElectricTraction:TTractionParam; NewLoc:TLocation; var NewRot:TRotation):real;
                {dt powinno byc 10ms lub mniejsze}
                {NewRot na wejsciu daje aktualna orientacje pojazdu, na wyjsciu daje dodatkowe wychylenia od tej orientacji}

                {! JESZCZE WAZNIEJSZA FUNKCJA - ABu: - mocno zoptymalizowanana ComputeMovement}
                function FastComputeMovement(dt:real; Shape:TTrackShape; var Track:TTrackParam; NewLoc:TLocation; var NewRot:TRotation):real; //Shape:TTrackShape; var Track:TTrackParam; var ElectricTraction:TTractionParam; NewLoc:TLocation; var NewRot:TRotation):real;
                {dt powinno byc 10ms lub mniejsze}
                {NewRot na wejsciu daje aktualna orientacje pojazdu, na wyjsciu daje dodatkowe wychylenia od tej orientacji}


                {dla samochodow}
                function ChangeOffsetH(DeltaOffset:real): boolean;

                {! procedury I/O}
                constructor Init(//LocInitial:TLocation; RotInitial:TRotation;
                                 VelInitial:real; TypeNameInit, NameInit: string; LoadInitial:longint; LoadTypeInitial: string; Cab:integer);
                                                              {wywolac najpierw to}
                function LoadChkFile(chkpath:string):Boolean;   {potem zaladowac z pliku}
                function CheckLocomotiveParameters(ReadyFlag:boolean;Dir:longint): boolean;  {a nastepnie sprawdzic}
                function EngineDescription(what:integer): string;  {opis stanu lokomotywy}

   {obsluga drzwi}
                function DoorLeft(State: Boolean): Boolean;    {obsluga dzwi lewych}
                function DoorRight(State: Boolean): Boolean;
                function DoorBlockedFlag: Boolean; //czy blokada drzwi jest aktualnie załączona

   {obsluga pantografow - Winger 160204}
                function PantFront(State: Boolean): Boolean;
                function PantRear(State: Boolean): Boolean;
   {ogrzewanie - Winger 020304}
               //function Heating(State: Boolean): Boolean;

                //private
                //function TotalMass:real;
{                function GetFTotal(CN:byte): real;
                function GetMass(CN:byte): real;
                procedure SendAVL(AccS,AccN,V,dL:real; CN:byte); }
              end;    {ufff}

function Distance(Loc1,Loc2: TLocation; Dim1,Dim2:TDimension) : real;

{----------------------------------------------------------------}
{========================McZapkie'2001===========================}
{----------------------------------------------------------------}
implementation

const
   Steel2Steel_friction=0.15;  {tarcie statyczne}
   g=9.81;                     {przyspieszenie ziemskie}
   SandSpeed=0.1;              {ile kg/s}
   RVentSpeed=0.4;             {rozpedzanie sie wentylatora obr/s^2}
   RVentMinI=50.0;             {przy jakim pradzie sie wylaczaja}
   CouplerTune:real=0.1;       {skalowanie tlumiennosci}
   Pirazy2=Pi*2;

{------------------------------------------}
{funkcje pomocnicze}

function s2NPW(s:string):byte;
{wylicza ilosc osi napednych ze stringu opisujacego uklad osi}
{np. 2'A' daje 1, Bo'Bo' daje 4, 1'E daje 5 itp}
const A=ord('A')-1;
var k,NPW:byte;
begin
  NPW:=0;
  for k:=1 to Length(s) do
   begin
     if s[k] in ['A'..'Z'] then
      NPW:=NPW+Ord(s[k])-A;
   end;
  s2NPW:=NPW;
end;

function s2NNW(s:string):byte;
{wylicza ilosc osi nienapednych ze stringu opisujacego uklad osi}
{np. 2'A' daje 2, Bo'Bo' daje 0, 1'E daje 1 itp}
const Zero=ord('0');
var k,NNW:byte;
begin
  NNW:=0;
  for k:=1 to Length(s) do
   begin
     if s[k] in ['1'..'9'] then
      NNW:=NNW+Ord(s[k])-Zero;
   end;
  s2NNW:=NNW;
end;

function Distance(Loc1,Loc2:TLocation;Dim1,Dim2:TDimension):real;
//zwraca odległość pomiędzy pojazdami (Loc1) i (Loc2) z uwzględnieneim ich długości (kule!)
var Dist:real;
begin
 Dist:=SQRT(SQR(Loc2.x-Loc1.x)+SQR(Loc1.y-Loc2.y));
 Distance:=Dist-Dim2.L/2.0-Dim1.L/2.0;
{  Distance:=Hypot(Loc2.x-Loc1.x,Loc2.y-Loc1.y)-(Dim2.L+Dim1.L)/2; }
end;

{oblicza zmiane predkosci i przyrost pedu wskutek kolizji}
function ComputeCollision(var v1,v2:real; m1,m2,beta:real;vc:boolean):real;
var CCP,w1,w2,m1m2:real;
begin
  if (v1<v2) and vc then
   CCP:=0
  else
   begin
     m1m2:=m1+m2;
     w1:=((m1-m2)*v1+2*m2*v2)/m1m2;
     w2:=((m2-m1)*v2+2*m1*v1)/m1m2;
     v1:=w1*sqrt(1-beta); {niejawna zmiana predkosci wskutek zderzenia}
     v2:=w2*sqrt(1-beta);
     CCP:=m1*(w2-w1)*(1-beta);
   end;
  ComputeCollision:=CCP;
end;

{-----zderzaki,sprzegi----}

{poprawka dla liczenia sil przy ustawieniu przeciwnym obiektow:}
function DirPatch(Coupler1:byte; Coupler2:byte): real;
begin
  if (Coupler1<>Coupler2) then DirPatch:=1
                        else DirPatch:=-1;
end;


function DirF(CouplerN:byte): real;
begin
  case CouplerN of
   0: DirF:=-1;
   1: DirF:=1
   else DirF:=0;
  end;
end;

{yB: funkcje dodatkowe hamulcowe}

function PR(p1,p2:real): real;
var ph,pl:real;
begin
  ph:=Max0R(p1,p2)+0.1;
  pl:=p1+p2-ph+0.2;
  PR:=(ph-pl)/(1.13*ph-pl);
end;

function SPR(ph,pl:real): real;
begin
  SPR:=0.674*(ph-pl)/(1.13*ph-pl+0.013);
end;

{---------rozwiniecie deklaracji metod obiektu T_MoverParameters--------}

(*
function T_MoverParameters.GetTrainsetVoltage: real;
//ABu: funkcja zwracajaca napiecie dla calego skladu, przydatna dla EZT
var volt: real;
begin
 volt:=0.0;
  if Couplers[1].Connected<>nil then
   if (TestFlag(Couplers[1].CouplingFlag,ctrain_power)) then //czy jest sprzęg WN
    begin //najczęściej silnikowy jest z tyłu
     if (Couplers[1].Connected.PantFrontVolt<>0.0) then
      volt:=Couplers[1].Connected.PantFrontVolt
     else
      if (Couplers[1].Connected.PantRearVolt<>0.0) then
       volt:=Couplers[1].Connected.PantRearVolt;
    end;
  if (volt=0.0) then
   if Couplers[0].Connected<>nil then
    if (TestFlag(Couplers[0].CouplingFlag,ctrain_power)) then //czy jest sprzęg WN
     begin
      if (Couplers[0].Connected.PantFrontVolt<>0.0) then
       volt:=Couplers[0].Connected.PantFrontVolt
      else
       if (Couplers[0].Connected.PantRearVolt<>0.0) then
        volt:=Couplers[0].Connected.PantRearVolt;
     end;
  GetTrainsetVoltage:=volt;
end;
*)

function T_MoverParameters.GetTrainsetVoltage: real;
//ABu: funkcja zwracajaca napiecie dla calego skladu, przydatna dla EZT
//var volt: real;
begin
  GetTrainsetVoltage:=Max0R(HVCouplers[1][1],HVCouplers[0][1]);
end;



function T_MoverParameters.Physic_ReActivation: boolean;
 begin
   if PhysicActivation then
    Physic_Reactivation:=false
   else
    begin
      PhysicActivation:=true;
      LastSwitchingTime:=0;
      Physic_Reactivation:=true;
    end;
 end;


{stosunek obecnego nastawienia sily hamowania do maksymalnej nastawy}
{
function T_MoverParameters.BrakeRatio: real;
 begin
   if BrakeCtrlPosNo>0 then
    begin
      if BrakeCtrlPos<0 then
       BrakeRatio:=1
      else
       BrakeRatio:=1-BrakeCtrlPos/BrakeCtrlPosNo
    end
   else
    BrakeRatio:=0;
 end;
}

function T_MoverParameters.LocalBrakeRatio: real;
var LBR:real;
begin
  if BrakeHandle=MHZ_EN57 then
    if (BrakeOpModeFlag>=bom_EP) then
      LBR:=(Handle as TMHZ_EN57).GetEP(BrakeCtrlPosR)
    else
      LBR:=0  
  else
  if LocalBrakePosNo>0 then
   LBR:=LocalBrakePos/LocalBrakePosNo
  else
   LBR:=0;
// if TestFlag(BrakeStatus,b_antislip) then
//   LBR:=Max0R(LBR,PipeRatio)+0.4;
 LocalBrakeRatio:=LBR;
end;

function T_MoverParameters.ManualBrakeRatio: real;
var MBR:real;
begin
  if ManualBrakePosNo>0 then
   MBR:=ManualBrakePos/ManualBrakePosNo
  else
   MBR:=0;
 ManualBrakeRatio:=MBR;
end;

function T_MoverParameters.PipeRatio: real;
var pr:real;
begin
  if DeltaPipePress>0 then
   if (false) then //SPKS!!
    begin
     if (3*PipePress)>(HighPipePress+LowPipePress+LowPipePress) then
      pr:=(HighPipePress-Min0R(HighPipePress,PipePress))/(DeltaPipePress*4.0/3.0)
     else
      pr:=(HighPipePress-1.0/3.0*DeltaPipePress-Max0R(LowPipePress,PipePress))/(DeltaPipePress*2.0/3.0);
//     if (not TestFlag(BrakeStatus,b_Ractive)) and (BrakeMethod and 1 = 0) and TestFlag(BrakeDelays,bdelay_R) and (Power<1) and (BrakeCtrlPos<1) then
//      pr:=Min0R(0.5,pr);
      //if (Compressor>0.5) then
      // pr:=pr*1.333; //dziwny rapid wywalamy
    end
   else
     pr:=(HighPipePress-Max0R(LowPipePress,Min0R(HighPipePress,PipePress)))/DeltaPipePress
  else
    pr:=0;
  PipeRatio:=pr;
end;

function T_MoverParameters.RealPipeRatio: real;
var rpp:real;
begin
  if DeltaPipePress>0 then
    rpp:=(CntrlPipePress-PipePress)/(DeltaPipePress)
  else
    rpp:=0;
  RealPipeRatio:=rpp;
end;

function T_MoverParameters.BrakeVP: real;
begin
  if BrakeVVolume>0 then
   BrakeVP:=Volume/(10.0*BrakeVVolume)
  else BrakeVP:=0;
end;

{reczne przelaczanie hamulca elektrodynamicznego}
function T_MoverParameters.DynamicBrakeSwitch(Switch:boolean):boolean;
var b:byte;
begin
  if (DynamicBrakeType=dbrake_switch) and (MainCtrlPos=0) then
   begin
     DynamicBrakeFlag:=Switch;
     DynamicBrakeSwitch:=true;
     for b:=0 to 1 do
      with Couplers[b] do
       if TestFlag(CouplingFlag,ctrain_controll) then
        Connected.DynamicBrakeFlag:=DynamicBrakeFlag;
   {end;
   if (DynamicBrakeType=dbrake_passive) and (TrainType=dt_ET42) then
   begin
   DynamicBrakeFlag:=false;
   DynamicBrakeSwitch:=false;}
   end
  else
   DynamicBrakeSwitch:=false;
end;


function T_MoverParameters.SendCtrlBroadcast(CtrlCommand:string;ctrlvalue:real):boolean;
var b:byte; OK:boolean;
begin
  OK:=((CtrlCommand<>CommandIn.Command) and (ctrlvalue<>CommandIn.Value1));
  if OK then
   for b:=0 to 1 do
    with Couplers[b] do
     if TestFlag(CouplingFlag,ctrain_controll) then
      if Connected.SetInternalCommand(CtrlCommand,ctrlvalue,DirF(b)) then
       OK:=Connected.RunInternalCommand or OK;
  SendCtrlBroadcast:=OK;
end;


function T_MoverParameters.SendCtrlToNext(CtrlCommand:string;ctrlvalue,dir:real):boolean;
//wysłanie komendy w kierunku dir (1=przod,-1=tył) do kolejnego pojazdu (jednego)
var
 OK:Boolean;
 d:Integer; //numer sprzęgu w kierunku którego wysyłamy
begin
//Ra: był problem z propagacją, jeśli w składzie jest pojazd wstawiony odwrotnie
//Ra: problem jest również, jeśli AI będzie na końcu składu
 OK:=(dir<>0); // and Mains;
 d:=(1+Sign(dir)) div 2; //dir=-1=>d=0, dir=1=>d=1 - wysyłanie tylko w tył
 if OK then //musi być wybrana niezerowa kabina
  with Couplers[d] do //własny sprzęg od strony (d)
   if TestFlag(CouplingFlag,ctrain_controll) then
    if ConnectedNr<>d then //jeśli ten nastpęny jest zgodny z aktualnym
     begin
      if Connected.SetInternalCommand(CtrlCommand,ctrlvalue,dir) then
       OK:=Connected.RunInternalCommand and OK; //tu jest rekurencja
     end
     else //jeśli następny jest ustawiony przeciwnie, zmieniamy kierunek
      if Connected.SetInternalCommand(CtrlCommand,ctrlvalue,-dir) then
       OK:=Connected.RunInternalCommand and OK; //tu jest rekurencja
 SendCtrlToNext:=OK;
end;

function T_MoverParameters.CabActivisation:boolean;
//załączenie rozrządu
var OK:boolean;
begin
  OK:=(CabNo=0); //numer kabiny, z której jest sterowanie
  if (OK) then
   begin
     CabNo:=ActiveCab; //sterowanie jest z kabiny z obsadą
     DirAbsolute:=ActiveDir*CabNo;
     SendCtrlToNext('CabActivisation',1,CabNo);
   end;
  CabActivisation:=OK;
end;

function T_MoverParameters.CabDeactivisation:boolean;
//wyłączenie rozrządu
var OK:boolean;
begin
 OK:=(CabNo=ActiveCab); //o ile obsada jest w kabinie ze sterowaniem
 if (OK) then
  begin
   CabNo:=0;
   DirAbsolute:=ActiveDir*CabNo;
   DepartureSignal:=false; //nie buczeć z nieaktywnej kabiny
   SendCtrlToNext('CabActivisation',0,ActiveCab); //CabNo==0!
  end;
 CabDeactivisation:=OK;
end;

{
procedure MainCtrlBroadcast(Couplers:TCouplers; MainCtrlPos,MainCtrlActualPos:byte);
var b:byte;
begin

  for b:=0 to 1 do
   with Couplers[b] do
    if TestFlag(CouplingFlag,ctrain_controll) then
     begin
       Connected^.MainCtrlPos:=MainCtrlPos;
       Connected^.MainCtrlActualPos:=MainCtrlActualPos;
     end;
poprawic to!!!
end;

procedure ScndCtrlBroadcast(Couplers:TCouplers; ScndCtrlPos,ScndCtrlActualPos:byte);
var b:byte;
begin
  for b:=0 to 1 do
   with Couplers[b] do
    if TestFlag(CouplingFlag,ctrain_controll) then
     begin
       Connected^.ScndCtrlPos:=ScndCtrlPos;
       Connected^.ScndCtrlActualPos:=ScndCtrlActualPos;
     end;
end;
}

{funkcje zwiekszajace/zmniejszajace nastawniki}

function T_MoverParameters.IncMainCtrl(CtrlSpeed:integer): boolean;
var //b:byte;
    OK:boolean;
begin
 OK:=false;
 if (MainCtrlPosNo>0) and (CabNo<>0) then
  begin
   if MainCtrlPos<MainCtrlPosNo then
    begin
     if (TrainType<>dt_ET22) or ((TrainType=dt_ET22) and (ScndCtrlPos=0)) then //w ET22 nie da się kręcić nastawnikiem przy włączonym boczniku
     case EngineType of
      None, Dumb, DieselElectric, ElectricInductionMotor:
       if ((CtrlSpeed=1) and (TrainType<>dt_EZT)) or ((CtrlSpeed=1) and (TrainType=dt_EZT)and (activedir<>0)) then
        begin //w EZT nie da się załączyć pozycji bez ustawienia kierunku
         inc(MainCtrlPos);
         OK:=true;
        end
       else
        if ((CtrlSpeed>1) and (TrainType<>dt_EZT)) or ((CtrlSpeed>1) and (TrainType=dt_EZT)and (activedir<>0)) then
          OK:=IncMainCtrl(1) and IncMainCtrl(CtrlSpeed-1);
      ElectricSeriesMotor:
       if (CtrlSpeed=1) and (ActiveDir<>0) then
        begin
         inc(MainCtrlPos);
         OK:=true;
          if Imax=ImaxHi then
           if RList[MainCtrlPos].Bn>1 then
            begin
             if(TrainType=dt_ET42)then
              begin
               dec(MainCtrlPos);
               OK:=false;
              end;
             if MaxCurrentSwitch(false) then
               SetFlag(SoundFlag,sound_relay); {wylaczanie wysokiego rozruchu}
 {         if (EngineType=ElectricSeriesMotor) and (MainCtrlPos=1) then
           MainCtrlActualPos:=1;
 }
            end;
            if (CtrlSpeed=1) and (ActiveDir=-1) and (RList[MainCtrlPos].Bn>1) and (TrainType<>dt_pseudodiesel) then
             begin //blokada wejścia na równoległą podczas jazdy do tyłu
                   dec(MainCtrlPos);
                   OK:=false;
                 end;
             {if (TrainType='et40') then
               if Abs(Im)>IminHi then
                 begin
                 dec(MainCtrlPos); //Blokada nastawnika po przekroczeniu minimalnego pradu
                 OK:=false;
                 end; }
         if(DynamicBrakeFlag)then
           if(TrainType=dt_ET42)then
             if MainCtrlPos>20 then
              begin
               dec(MainCtrlPos);
               OK:=false;
              end;
        end
       else
        if (CtrlSpeed>1) and (ActiveDir<>0) {and (ScndCtrlPos=0)} and (TrainType<>dt_ET40) then
         begin //szybkie przejście na bezoporową
           while (RList[MainCtrlPos].R>0) and IncMainCtrl(1) do ;
            //OK:=true ; {takie chamskie, potem poprawie} <-Ra: kto miał to poprawić i po co?
            if  ActiveDir=-1 then
             while (RList[MainCtrlPos].Bn>1) and IncMainCtrl(1) do
             dec(MainCtrlPos);
             OK:=false;
             {if (TrainType=dt_ET40)  then
              while Abs (Im)>IminHi do
                dec(MainCtrlPos);
               OK:=false ;  }
          if(DynamicBrakeFlag)then
            if(TrainType=dt_ET42)then
              while(MainCtrlPos>20)do
                dec(MainCtrlPos);
          OK:=false;
         end;
      DieselEngine:
       if CtrlSpeed=1 then
        begin
         inc(MainCtrlPos);
         OK:=true;
         if MainCtrlPos>0 then
          CompressorAllow:=true
         else
          CompressorAllow:=false;
        end
       else
        if CtrlSpeed>1 then
         begin
           while (MainCtrlPos<MainCtrlPosNo) do
            IncMainCtrl(1);
           OK:=true;
         end;
      WheelsDriven:
       OK:=AddPulseForce(CtrlSpeed);
     end //case EngineType of
    end
   else //MainCtrlPos>=MainCtrlPosNo
    if (CoupledCtrl) then //wspólny wał nastawnika jazdy i bocznikowania
     begin
      if (ScndCtrlPos<ScndCtrlPosNo) then //3<3 -> false
       begin
        inc(ScndCtrlPos);
        OK:=true;
       end
      else OK:=false;
     end;
   if OK then
    begin
     {OK:=}SendCtrlToNext('MainCtrl',MainCtrlPos,CabNo);  {???}
     {OK:=}SendCtrlToNext('ScndCtrl',ScndCtrlPos,CabNo);
    end;
  end
 else {nie ma sterowania}
  OK:=false;
 //if OK then LastRelayTime:=0;

 //hunter-101012: poprawka
 //poprzedni warunek byl niezbyt dobry, bo przez to przy trzymaniu +
 //styczniki tkwily na tej samej pozycji (LastRelayTime byl caly czas 0 i rosl
 //po puszczeniu plusa)

 if OK then
  begin
   if (DelayCtrlFlag) then
    begin
     if (LastRelayTime>=InitialCtrlDelay)and(MainCtrlPos=1) then
      LastRelayTime:=0
    end
   else if (LastRelayTime>CtrlDelay) then
    LastRelayTime:=0;
  end;
 IncMainCtrl:=OK;
end;


function T_MoverParameters.DecMainCtrl(CtrlSpeed:integer): boolean;
var //b:byte;
    OK:boolean;
begin
  OK:=false;
  if (MainCtrlPosNo>0) and (CabNo<>0) then
   begin
      if MainCtrlPos>0 then
       begin
       if ((TrainType<>dt_ET22) or (ScndCtrlPos=0)) then //Ra: ET22 blokuje nastawnik przy boczniku
       begin
         if CoupledCtrl and (ScndCtrlPos>0) then
          begin
            dec(ScndCtrlPos); {wspolny wal}
            OK:=true;
          end
         else
          case EngineType of
            None, Dumb, DieselElectric, ElectricInductionMotor:
             if ((CtrlSpeed=1) and {(ScndCtrlPos=0) and} (EngineType<>DieselElectric)) or ((CtrlSpeed=1)and(EngineType=DieselElectric))then
              begin
                dec(MainCtrlPos);
                OK:=true;
              end
             else
              if CtrlSpeed>1 then
               OK:=DecMainCtrl(1) and DecMainCtrl(2); //CtrlSpeed-1);
            ElectricSeriesMotor:
             if (CtrlSpeed=1) {and (ScndCtrlPos=0)} then
              begin
                dec(MainCtrlPos);
//                if (MainCtrlPos=0) and (ScndCtrlPos=0) and (TrainType<>dt_ET40)and(TrainType<>dt_EP05) then
//                 StLinFlag:=false;
//                if (MainCtrlPos=0) and (TrainType<>dt_ET40) and (TrainType<>dt_EP05) then
//                 MainCtrlActualPos:=0; //yBARC: co to tutaj robi? ;)
                OK:=true;
              end
             else
              if (CtrlSpeed>1) {and (ScndCtrlPos=0)} then
               begin
                 OK:=true;
                  if (RList[MainCtrlPos].R=0)
                   then DecMainCtrl(1);
                  while (RList[MainCtrlPos].R>0) and DecMainCtrl(1) do ; {takie chamskie, potem poprawie}
               end;
            DieselEngine:
             if CtrlSpeed=1 then
              begin
                dec(MainCtrlPos);
                OK:=true;
              end
              else
              if CtrlSpeed>1 then
               begin
                 while (MainCtrlPos>0) or (RList[MainCtrlPos].Mn>0) do
                  DecMainCtrl(1);
                 OK:=true;
               end;
          end;
          end;
       end
      else
       if EngineType=WheelsDriven then
        OK:=AddPulseForce(-CtrlSpeed)
       else
        OK:=false;
      if OK then
       begin
          {OK:=}SendCtrlToNext('MainCtrl',MainCtrlPos,CabNo);  {hmmmm...???!!!}
          {OK:=}SendCtrlToNext('ScndCtrl',ScndCtrlPos,CabNo);
       end;
   end
  else
   OK:=false;
 //if OK then LastRelayTime:=0;
 //hunter-101012: poprawka
 if OK then
  begin
   if DelayCtrlFlag then
    begin
     if (LastRelayTime>=InitialCtrlDelay) then
      LastRelayTime:=0;
    end
   else if (LastRelayTime>CtrlDownDelay) then
    LastRelayTime:=0;
  end;
 DecMainCtrl:=OK;
end;

function T_MoverParameters.IncScndCtrl(CtrlSpeed:integer): boolean;
var //b:byte;
    OK:boolean;
begin
  if (MainCtrlPos=0)and(CabNo<>0)and(TrainType=dt_ET42)and(ScndCtrlPos=0)and(DynamicBrakeFlag)then
   begin
    OK:=DynamicBrakeSwitch(false);
   end
  else
 if (ScndCtrlPosNo>0) and (CabNo<>0) and not ((TrainType=dt_ET42)and((Imax=ImaxHi)or((DynamicBrakeFlag)and(MainCtrlPos>0)))) then
  begin
{      if (RList[MainCtrlPos].R=0) and (MainCtrlPos>0) and (ScndCtrlPos<ScndCtrlPosNo) and (not CoupledCtrl) then}
   if (ScndCtrlPos<ScndCtrlPosNo) and (not CoupledCtrl) and ((EngineType<>DieselElectric) or (not AutoRelayFlag)) then
    begin
      if CtrlSpeed=1 then
       begin
         inc(ScndCtrlPos);
       end
      else
       if CtrlSpeed>1 then
        begin
          ScndCtrlPos:=ScndCtrlPosNo; {takie chamskie, potem poprawie}
        end;
      OK:=true;
    end
   else {nie mozna zmienic}
    OK:=false;
   if OK then
    begin
      {OK:=}SendCtrlToNext('MainCtrl',MainCtrlPos,CabNo);   {???}
      {OK:=}SendCtrlToNext('ScndCtrl',ScndCtrlPos,CabNo);
    end;
  end
 else {nie ma sterowania}
  OK:=false;
 //if OK then LastRelayTime:=0;
 //hunter-101012: poprawka
 if OK then
  if (LastRelayTime>CtrlDelay) then
   LastRelayTime:=0;

 if (OK) and (EngineType=ElectricInductionMotor) then
  if (Vmax<250) then
   ScndCtrlActualPos:=Round(Vel+0.5)
  else
   ScndCtrlActualPos:=Round(Vel/2+0.5); 

 IncScndCtrl:=OK;
end;

function T_MoverParameters.DecScndCtrl(CtrlSpeed:integer): boolean;
var //b:byte;
    OK:boolean;
begin
  if (MainCtrlPos=0)and(CabNo<>0)and(TrainType=dt_ET42)and(ScndCtrlPos=0)and not(DynamicBrakeFlag)and(CtrlSpeed=1)then
   begin
    //Ra: AI wywołuje z CtrlSpeed=2 albo gdy ScndCtrlPos>0
    OK:=DynamicBrakeSwitch(true);
   end
  else
  if (ScndCtrlPosNo>0) and (CabNo<>0) then
   begin
    if (ScndCtrlPos>0) and (not CoupledCtrl) and ((EngineType<>DieselElectric) or (not AutoRelayFlag))then
     begin
      if CtrlSpeed=1 then
       begin
         dec(ScndCtrlPos);
       end
      else
       if CtrlSpeed>1 then
        begin
          ScndCtrlPos:=0; {takie chamskie, potem poprawie}
        end;
      OK:=true;
     end
    else
     OK:=false;
    if OK then
     begin
      {OK:=}SendCtrlToNext('MainCtrl',MainCtrlPos,CabNo);  {???}
      {OK:=}SendCtrlToNext('ScndCtrl',ScndCtrlPos,CabNo);
     end;
   end
  else
   OK:=false;
 //if OK then LastRelayTime:=0;
 //hunter-101012: poprawka
 if OK then
  if (LastRelayTime>CtrlDownDelay) then
   LastRelayTime:=0;

 if (OK) and (EngineType=ElectricInductionMotor) then
   ScndCtrlActualPos:=0;

 DecScndCtrl:=OK;
end;


function T_MoverParameters.DirectionBackward: boolean;
begin
  if (ActiveDir=1) and (MainCtrlPos=0) and (TrainType=dt_EZT) then
    if MinCurrentSwitch(false) then
    begin
      DirectionBackward:=true; //
      Exit;
    end;
  if (MainCtrlPosNo>0) and (ActiveDir>-1) and (MainCtrlPos=0) then
   begin
    if EngineType=WheelsDriven then
     dec(CabNo);
{    else}
    dec(ActiveDir);
    DirAbsolute:=ActiveDir*CabNo;
    if (DirAbsolute<>0) then
     if (Battery) then //jeśli bateria jest już załączona
      BatterySwitch(true); //to w ten oto durny sposób aktywuje się CA/SHP
    DirectionBackward:=true;
    SendCtrltoNext('Direction',ActiveDir,CabNo);
   end
  else
   DirectionBackward:=false;
end;

function T_MoverParameters.MainSwitch(State:boolean): boolean;
begin
 MainSwitch:=false; //Ra: przeniesione z końca
  if ((Mains<>State) and (MainCtrlPosNo>0)) then
   begin
    if (State=false) or ({(MainCtrlPos=0) and} (ScndCtrlPos=0) and ((ConvOvldFlag=false)or(TrainType=dt_EZT)) and (LastSwitchingTime>CtrlDelay) and not TestFlag(DamageFlag,dtrain_out) and not TestFlag(EngDmgFlag,1)) then
     begin
       if Mains then //jeśli był załączony
        SendCtrlToNext('MainSwitch',ord(State),CabNo); //wysłanie wyłączenia do pozostałych?
       Mains:=State;
       if Mains then //jeśli został załączony
        SendCtrlToNext('MainSwitch',ord(State),CabNo); //wyslanie po wlaczeniu albo przed wylaczeniem
       MainSwitch:=true; //wartość zwrotna
       LastSwitchingTime:=0;
       if (EngineType=DieselEngine) and Mains then
        begin
          dizel_enginestart:=State;
        end;
       if ((TrainType=dt_EZT)and(not State)) then
          ConvOvldFlag:=true;
       //if (State=false) then //jeśli wyłączony
       // begin
         //SetFlag(SoundFlag,sound_relay); //hunter-091012: przeniesione do Train.cpp, zeby sie nie zapetlal
         // if (SecuritySystem.Status<>12) then
       //  SecuritySystem.Status:=0; //deaktywacja czuwaka; Ra: a nie baterią?
       // end
       //else
       //if (SecuritySystem.Status<>12) then
       // SecuritySystem.Status:=s_waiting; //aktywacja czuwaka
     end
   end
  //else MainSwitch:=false;
end;

function T_MoverParameters.BatterySwitch(State:boolean):boolean;
begin
 //Ra: ukrotnienie załączania baterii jest jakąś fikcją...
 if (Battery<>State) then
  begin
   Battery:=State;
  end;
 if (Battery=true) then SendCtrlToNext('BatterySwitch',1,CabNo)
  else SendCtrlToNext('BatterySwitch',0,CabNo);
 BatterySwitch:=true;
 if (Battery) and (ActiveCab<>0) {or (TrainType=dt_EZT)} then
  SecuritySystem.Status:=SecuritySystem.Status or s_waiting //aktywacja czuwaka
 else
  SecuritySystem.Status:=0; //wyłączenie czuwaka
end;

function T_MoverParameters.EpFuseSwitch(State:boolean):boolean;
begin
 if (EpFuse<>State) then
  begin
   EpFuse:=State;
   EpFuseSwitch:=true;
  end
 else
  EpFuseSwitch:=false;  
// if (EpFuse=true) then SendCtrlToNext('EpFuseSwitch',1,CabNo)
//  else SendCtrlToNext('EpFuseSwitch',0,CabNo);
end;

{wl/wyl przetwornicy}
function T_MoverParameters.ConverterSwitch(State:boolean):boolean;
begin
 ConverterSwitch:=false; //Ra: normalnie chyba false?
 if (ConverterAllow<>State) then
 begin
   ConverterAllow:=State;
   ConverterSwitch:=true;
   if CompressorPower=2 then
    CompressorAllow:=ConverterAllow;
 end;
 if (ConverterAllow=true) then SendCtrlToNext('ConverterSwitch',1,CabNo)
 else SendCtrlToNext('ConverterSwitch',0,CabNo)
end;

{wl/wyl sprezarki}
function T_MoverParameters.CompressorSwitch(State:boolean):boolean;
begin
 CompressorSwitch:=false; //Ra: normalnie chyba tak?
// if State=true then
//  if ((CompressorPower=2) and (not ConverterAllow)) then
//   State:=false; //yB: to juz niepotrzebne
 if (CompressorAllow<>State)and(CompressorPower<2)then
 begin
   CompressorAllow:=State;
   CompressorSwitch:=true;
 end;
 if (CompressorAllow=true) then SendCtrlToNext('CompressorSwitch',1,CabNo)
 else SendCtrlToNext('CompressorSwitch',0,CabNo)
end;

{wl/wyl malej sprezarki}
{function T_MoverParameters.SmallCompressorSwitch(State:boolean):boolean;
begin
 if State=true then
  if ((SmallCompressorPower=1) then
   State:=false;
 if (SmallCompressorAllow<>State) then
 begin
   SmallCompressorAllow:=State;
   SmallCompressorSwitch:=true;
 end;
end;
}
{sypanie piasku}
function T_MoverParameters.SandDoseOn : boolean;
begin
  if (SandCapacity>0) then
   begin
     SandDoseOn:=true;
     if SandDose then
      SandDose:=false
     else
      if Sand>0 then SandDose:=true;
     if CabNo<>0 then
       SendCtrlToNext('SandDoseOn',1,CabNo);
   end
  else
   SandDoseOn:=false;
end;

(*
//Ra: to jest do przejrzenia i uporządkowania
function T_MoverParameters.SecuritySystemReset : boolean;
//zbijanie czuwaka/SHP
 procedure Reset;
  begin
  with SecuritySystem do
    if not(TestFlag(SystemType,2) and TestFlag(Status,s_active)) then
    SecuritySystem.SystemTimer:=0;
    SecuritySystem.SystemBrakeTimer:=0;
    SecuritySystem.SystemSoundTimer:=0;
    SecuritySystem.Status:=s_waiting; //aktywacja czuwaka
    SecuritySystem.VelocityAllowed:=-1;
  end;
  procedure ResetSHP;
  begin
    SecuritySystem.SystemBrakeTimer:=0;
    SecuritySystem.SystemSoundTimer:=0;
    SecuritySystem.VelocityAllowed:=-1;
    SecuritySystem.Status:=s_waiting;
  end;
begin
  with SecuritySystem do
    begin
    if (Status=3) or (Status=2) or (Status=11) or (Status=26)or(Status=27) then
      begin
        SecuritySystemReset:=true;
        if (Status<s_ebrake) then
         Reset
        else
          if EmergencyBrakeSwitch(false) then
           Reset;
      end;

      if (Status=5) or (Status=13) or (Status=29) or (Status=4) or ((Status=12) and (activedir<>0)) or (Status=28) then  {Wlaczone tylko SHP}
    {  begin
        SecuritySystemReset:=true;
        if (Status<s_ebrake) then
         ResetSHP
        else
          if EmergencyBrakeSwitch(false) then
           ResetSHP;
      end;
      if (Status=7) or (Status=15) or (Status=30) or (Status=31) then  {Wlaczone SHP i CA}
     { begin
        SecuritySystemReset:=true;
        if (Status<s_ebrake) then
         begin
         ResetSHP;
         SecuritySystem.Status:=3;
         end
        else
          if EmergencyBrakeSwitch(false) then
           ResetSHP;
      end
    else
     SecuritySystemReset:=false;
     end;
//  SendCtrlToNext('SecurityReset',0,CabNo);
end;

function T_MoverParameters.SecuritySystemReset : boolean;
//zbijanie czuwaka/SHP
 procedure Reset;
  begin
   SecuritySystem.SystemTimer:=0;
   if TestFlag(SecuritySystem.Status,s_aware) then
    begin
     SecuritySystem.SystemBrakeCATimer:=0;
     SecuritySystem.SystemSoundCATimer:=0;
     SetFlag(SecuritySystem.Status,-s_aware);
     SetFlag(SecuritySystem.Status,-s_CAalarm);
     SetFlag(SecuritySystem.Status,-s_CAebrake);
     EmergencyBrakeFlag:=false;
     SecuritySystem.VelocityAllowed:=-1;
    end
   else if TestFlag(SecuritySystem.Status,s_active) then
    begin
     SecuritySystem.SystemBrakeSHPTimer:=0;
     SecuritySystem.SystemSoundSHPTimer:=0;
     SetFlag(SecuritySystem.Status,-s_active);
     SetFlag(SecuritySystem.Status,-s_SHPalarm);
     SetFlag(SecuritySystem.Status,-s_SHPebrake);
     EmergencyBrakeFlag:=false;
     SecuritySystem.VelocityAllowed:=-1;
    end;
  end;
begin
  with SecuritySystem do
    if (SystemType>0) and (Status>0) and ((status<>12) or ((status=12) and (activedir<>0))) then
    //if (SystemType>0) and (Status>0) then
      begin
        SecuritySystemReset:=true;
        if not (ActiveDir=0) then
         if not TestFlag(Status,s_CAebrake) or not TestFlag(Status,s_SHPebrake) then
          Reset;
        //else
        //  if EmergencyBrakeSwitch(false) then
        //   Reset;
      end
    else
     SecuritySystemReset:=false;
//  SendCtrlToNext('SecurityReset',0,CabNo);
end;

{testowanie czuwaka/SHP}
procedure T_MoverParameters.SecuritySystemCheck(dt:real);
begin
  with SecuritySystem do
   begin
     if (SystemType>0) and (Status>0) then
      begin
        SystemTimer:=SystemTimer+dt;
        if TestFlag(Status,s_aware) or TestFlag(Status,s_active) then //jeśli świeci albo miga
         SystemSoundTimer:=SystemSoundTimer+dt;
        if TestFlag(Status,s_alarm) then //jeśli buczy
         SystemBrakeTimer:=SystemBrakeTimer+dt;
        if TestFlag(SystemType,1) then
         if (SystemTimer>AwareDelay) and (AwareDelay>=0) then  {-1 blokuje}
           if not SetFlag(Status,s_aware) then {juz wlaczony sygnal swietlny}
             if (SystemSoundTimer>SoundSignalDelay) and (SoundSignalDelay>=0) then
               if not SetFlag(Status,s_alarm) then {juz wlaczony sygnal dzwiekowy}
                 if (SystemBrakeTimer>EmergencyBrakeDelay) and (EmergencyBrakeDelay>=0) then
                   SetFlag(Status,s_ebrake);        {przeterminowanie czuwaka, hamowanie awaryjne}
        if TestFlag(SystemType,2) and TestFlag(Status,s_active) then
         if (Vel>VelocityAllowed) and (VelocityAllowed>=0) then
          SetFlag(Status,s_ebrake)
         else
          if ((SystemSoundTimer>SoundSignalDelay) and (SoundSignalDelay>=0)) or ((Vel>NextVelocityAllowed) and (NextVelocityAllowed>=0)) then
            if not SetFlag(Status,s_alarm) then {juz wlaczony sygnal dzwiekowy}
              if (SystemBrakeTimer>EmergencyBrakeDelay) and (EmergencyBrakeDelay>=0) then
               SetFlag(Status,s_ebrake);
        if TestFlag(Status,s_ebrake) then
         if not EmergencyBrakeFlag then
           EmergencyBrakeSwitch(true);
      end;
   end;
end;
*)

//hunter-091012: rozbicie alarmow, dodanie testu czuwaka
function T_MoverParameters.SecuritySystemReset : boolean;
//zbijanie czuwaka/SHP
 procedure Reset;
  begin
   SecuritySystem.SystemTimer:=0;

   if TestFlag(SecuritySystem.Status,s_aware) then
    begin
     SecuritySystem.SystemBrakeCATimer:=0;
     SecuritySystem.SystemSoundCATimer:=0;
     SetFlag(SecuritySystem.Status,-s_aware);
     SetFlag(SecuritySystem.Status,-s_CAalarm);
     SetFlag(SecuritySystem.Status,-s_CAebrake);
//     EmergencyBrakeFlag:=false; //YB-HN
     SecuritySystem.VelocityAllowed:=-1;
    end
   else if TestFlag(SecuritySystem.Status,s_active) then
    begin
     SecuritySystem.SystemBrakeSHPTimer:=0;
     SecuritySystem.SystemSoundSHPTimer:=0;
     SetFlag(SecuritySystem.Status,-s_active);
     SetFlag(SecuritySystem.Status,-s_SHPalarm);
     SetFlag(SecuritySystem.Status,-s_SHPebrake);
//     EmergencyBrakeFlag:=false; //YB-HN
     SecuritySystem.VelocityAllowed:=-1;
    end;
  end;
begin
  with SecuritySystem do
    if (SystemType>0) and (Status>0) then
      begin
        SecuritySystemReset:=true;
        if ((TrainType=dt_EZT)or(ActiveDir<>0)) then //Ra 2014-03: w EZT nie trzeba ustawiać kierunku
         if not TestFlag(Status,s_CAebrake) or not TestFlag(Status,s_SHPebrake) then
          Reset;
        //else
        //  if EmergencyBrakeSwitch(false) then
        //   Reset;
      end
    else
     SecuritySystemReset:=false;
//  SendCtrlToNext('SecurityReset',0,CabNo);
end;

procedure T_MoverParameters.SecuritySystemCheck(dt:real);
begin
//Ra: z CA/SHP w EZT jest ten problem, że w rozrządczym nie ma kierunku, a w silnikowym nie ma obsady
//poza tym jest zdefiniowany we wszystkich 3 członach EN57
  with SecuritySystem do
   begin
     if (not Radio) then
       EmergencyBrakeSwitch(false);
     if (SystemType>0) and (Status>0) and (Battery) then //Ra: EZT ma teraz czuwak w rozrządczym
      begin
       //CA
       if (Vel>=AwareMinSpeed) then  //domyślnie predkość większa od 10% Vmax, albo podanej jawnie w FIZ
       begin
        SystemTimer:=SystemTimer+dt;
        if TestFlag(SystemType,1) and TestFlag(Status,s_aware) then //jeśli świeci albo miga
         SystemSoundCATimer:=SystemSoundCATimer+dt;
        if TestFlag(SystemType,1) and TestFlag(Status,s_CAalarm) then //jeśli buczy
         SystemBrakeCATimer:=SystemBrakeCATimer+dt;
        if TestFlag(SystemType,1) then
         if (SystemTimer>AwareDelay) and (AwareDelay>=0) then  {-1 blokuje}
           if not SetFlag(Status,s_aware) then {juz wlaczony sygnal swietlny}
             if (SystemSoundCATimer>SoundSignalDelay) and (SoundSignalDelay>=0) then
               if not SetFlag(Status,s_CAalarm) then {juz wlaczony sygnal dzwiekowy}
                 if (SystemBrakeCATimer>EmergencyBrakeDelay) and (EmergencyBrakeDelay>=0) then
                   SetFlag(Status,s_CAebrake);


       //SHP
        if TestFlag(SystemType,2) and TestFlag(Status,s_active) then //jeśli świeci albo miga
         SystemSoundSHPTimer:=SystemSoundSHPTimer+dt;
        if TestFlag(SystemType,2) and TestFlag(Status,s_SHPalarm) then //jeśli buczy
         SystemBrakeSHPTimer:=SystemBrakeSHPTimer+dt;
        if TestFlag(SystemType,2) and TestFlag(Status,s_active) then
         if (Vel>VelocityAllowed) and (VelocityAllowed>=0) then
          SetFlag(Status,s_SHPebrake)
         else
          if ((SystemSoundSHPTimer>SoundSignalDelay) and (SoundSignalDelay>=0)) or ((Vel>NextVelocityAllowed) and (NextVelocityAllowed>=0)) then
            if not SetFlag(Status,s_SHPalarm) then {juz wlaczony sygnal dzwiekowy}
              if (SystemBrakeSHPTimer>EmergencyBrakeDelay) and (EmergencyBrakeDelay>=0) then
               SetFlag(Status,s_SHPebrake);

       end; //else SystemTimer:=0;

       //TEST CA
        if TestFlag(Status,s_CAtest) then //jeśli świeci albo miga
         SystemBrakeCATestTimer:=SystemBrakeCATestTimer+dt;
        if TestFlag(SystemType,1) then
           if TestFlag(Status,s_CAtest) then {juz wlaczony sygnal swietlny}
               if (SystemBrakeCATestTimer>EmergencyBrakeDelay) and (EmergencyBrakeDelay>=0) then
                   s_CAtestebrake:=true;

       //wdrazanie hamowania naglego
//        if TestFlag(Status,s_SHPebrake) or TestFlag(Status,s_CAebrake) or (s_CAtestebrake=true) then
//         EmergencyBrakeFlag:=true;  //YB-HN
      end
     else if not (Battery) then
      begin //wyłączenie baterii deaktywuje sprzęt
       EmergencyBrakeSwitch(false);
       //SecuritySystem.Status:=0; //deaktywacja czuwaka
      end;
   end;
end;

{nastawy hamulca}

function T_MoverParameters.IncBrakeLevelOld:boolean;
//var b:byte;
begin
  if (BrakeCtrlPosNo>0) {and (LocalBrakePos=0)} then
   begin
     if BrakeCtrlPos<BrakeCtrlPosNo then
      begin
        inc(BrakeCtrlPos);
//        BrakeCtrlPosR:=BrakeCtrlPos;

//youBy: wywalilem to, jak jest EP, to sa przenoszone sygnaly nt. co ma robic, a nie poszczegolne pozycje;
//       wystarczy spojrzec na Knorra i Oerlikona EP w EN57; mogly ze soba wspolapracowac
{
        if (BrakeSystem=ElectroPneumatic) then
          if (BrakePressureActual.BrakeType=ElectroPneumatic) then
           begin
//             BrakeStatus:=ord(BrakeCtrlPos>0);
             SendCtrlToNext('BrakeCtrl',BrakeCtrlPos,CabNo);
           end
          else SendCtrlToNext('BrakeCtrl',-2,CabNo);
//        else
//         if not TestFlag(BrakeStatus,b_dmg) then
//          BrakeStatus:=b_on;}

//youBy: EP po nowemu

        IncBrakeLevelOld:=true;
        if (BrakePressureActual.PipePressureVal<0)and(BrakePressureTable[BrakeCtrlPos-1].PipePressureVal>0) then
          LimPipePress:=PipePress;

        if (BrakeSystem=ElectroPneumatic) then
          if (BrakeSubSystem<>ss_K) then
           begin
             if (BrakeCtrlPos*BrakeCtrlPos)=1 then
              begin
//                SendCtrlToNext('Brake',BrakeCtrlPos,CabNo);
//                SetFlag(BrakeStatus,b_epused);
              end
             else
              begin
//                SendCtrlToNext('Brake',0,CabNo);
//                SetFlag(BrakeStatus,-b_epused);
              end;
           end;

      end
     else
      begin
        IncBrakeLevelOld:=false;
{        if BrakeSystem=Pneumatic then
         EmergencyBrakeSwitch(true); }
      end;
   end
  else
   IncBrakeLevelOld:=false;
end;

function T_MoverParameters.DecBrakeLevelOld:boolean;
//var b:byte;
begin
  if (BrakeCtrlPosNo>0) {and (LocalBrakePos=0)} then
   begin
     if (BrakeCtrlPos>-1-Byte(BrakeHandle=FV4a)) then
      begin
        dec(BrakeCtrlPos);
//        BrakeCtrlPosR:=BrakeCtrlPos;
////        if EmergencyBrakeFlag then    //yB: czy to jest potrzebne?
////          begin
////             EmergencyBrakeFlag:=false; {!!!}
////             SendCtrlToNext('Emergency_brake',0,CabNo);
////          end;

//youBy: wywalilem to, jak jest EP, to sa przenoszone sygnaly nt. co ma robic, a nie poszczegolne pozycje;
//       wystarczy spojrzec na Knorra i Oerlikona EP w EN57; mogly ze soba wspolapracowac
{
        if (BrakeSystem=ElectroPneumatic) then
          if BrakePressureActual.BrakeType=ElectroPneumatic then
           begin
//             BrakeStatus:=ord(BrakeCtrlPos>0);
             SendCtrlToNext('BrakeCtrl',BrakeCtrlPos,CabNo);
           end
          else SendCtrlToNext('BrakeCtrl',-2,CabNo);
//        else}
//         if (not TestFlag(BrakeStatus,b_dmg) and (not TestFlag(BrakeStatus,b_release))) then
//          BrakeStatus:=b_off;   {luzowanie jesli dziala oraz nie byl wlaczony odluzniacz}

//youBy: EP po nowemu
        DecBrakeLevelOld:=true;
//        if (BrakePressureTable[BrakeCtrlPos].PipePressureVal<0.0)and(BrakePressureTable[BrakeCtrlPos+1].PipePressureVal>0) then
//          LimPipePress:=PipePress;

        if (BrakeSystem=ElectroPneumatic) then
          if (BrakeSubSystem<>ss_K) then
           begin
             if (BrakeCtrlPos*BrakeCtrlPos)=1 then
              begin
//                SendCtrlToNext('Brake',BrakeCtrlPos,CabNo);
//                SetFlag(BrakeStatus,b_epused);
              end
             else
              begin
//                SendCtrlToNext('Brake',0,CabNo);
//                SetFlag(BrakeStatus,-b_epused);
              end;
           end;
(*    for b:=0 to 1 do  {poprawic to!}
     with Couplers[b] do
      if CouplingFlag and ctrain_controll=ctrain_controll then
       Connected^.BrakeCtrlPos:=BrakeCtrlPos;
*)
      end
     else
      DecBrakeLevelOld:=false;
   end
     else
      DecBrakeLevelOld:=false;
end;

function T_MoverParameters.IncLocalBrakeLevelFAST:boolean;
begin
  if (LocalBrakePos<LocalBrakePosNo) then
   begin
     LocalBrakePos:=LocalBrakePosNo;
     IncLocalBrakeLevelFAST:=true;
   end
  else
     IncLocalBrakeLevelFAST:=false;
UnBrake:=true;
end;

function T_MoverParameters.IncLocalBrakeLevel(CtrlSpeed:byte):boolean;
begin
  if (LocalBrakePos<LocalBrakePosNo) {and (BrakeCtrlPos<1)} then
   begin
     while (LocalBrakePos<LocalBrakePosNo) and (CtrlSpeed>0) do
      begin
       inc(LocalBrakePos);
       dec(CtrlSpeed);
      end;
     IncLocalBrakeLevel:=true;
   end
  else
     IncLocalBrakeLevel:=false;
UnBrake:=true;
end;

function T_MoverParameters.IncManualBrakeLevel(CtrlSpeed:byte):boolean;
begin
  if (ManualBrakePos<ManualBrakePosNo) {and (BrakeCtrlPos<1)} then
   begin
     while (ManualBrakePos<ManualBrakePosNo) and (CtrlSpeed>0) do
      begin
       inc(ManualBrakePos);
       dec(CtrlSpeed);
      end;
     IncManualBrakeLevel:=true;
   end
  else
     IncManualBrakeLevel:=false;
end;

function T_MoverParameters.DecLocalBrakeLevelFAST():boolean;
begin
  if LocalBrakePos>0 then
   begin
     LocalBrakePos:=0;
     DecLocalBrakeLevelFAST:=true;
   end
  else
     DecLocalBrakeLevelFAST:=false;
UnBrake:=true;
end;

function T_MoverParameters.DecLocalBrakeLevel(CtrlSpeed:byte):boolean;
begin
  if LocalBrakePos>0 then
   begin
     while (CtrlSpeed>0) and (LocalBrakePos>0) do
      begin
        dec(LocalBrakePos);
        dec(CtrlSpeed);
      end;
     DecLocalBrakeLevel:=true;
   end
  else
     DecLocalBrakeLevel:=false;
UnBrake:=true;
end;

function T_MoverParameters.DecManualBrakeLevel(CtrlSpeed:byte):boolean;
begin
  if ManualBrakePos>0 then
   begin
     while (CtrlSpeed>0) and (ManualBrakePos>0) do
      begin
        dec(ManualBrakePos);
        dec(CtrlSpeed);
      end;
     DecManualBrakeLevel:=true;
   end
  else
     DecManualBrakeLevel:=false;

end;

function T_MoverParameters.EmergencyBrakeSwitch(Switch:boolean): boolean;
begin
  if (BrakeSystem<>Individual) and (BrakeCtrlPosNo>0) then
   begin
     if (not EmergencyBrakeFlag) and Switch then
      begin
        EmergencyBrakeFlag:=Switch;
        EmergencyBrakeSwitch:=true;
      end
     else
      begin
        if (Abs(V)<0.1) and (Switch=false) then  {odblokowanie hamulca bezpieczenistwa tylko po zatrzymaniu}
         begin
           EmergencyBrakeFlag:=Switch;
           EmergencyBrakeSwitch:=true;
         end
        else
         EmergencyBrakeSwitch:=false;
      end;
   end
  else
   EmergencyBrakeSwitch:=false;   {nie ma hamulca bezpieczenstwa gdy nie ma hamulca zesp.}
end;

function T_MoverParameters.AntiSlippingBrake: boolean;
begin
 AntiSlippingBrake:=false; //Ra: przeniesione z końca
  if ASBType=1 then
   begin
     AntiSlippingBrake:=true;  //SPKS!!
     Hamulec.ASB(1);
     BrakeSlippingTimer:=0;
   end
end;

function T_MoverParameters.AntiSlippingButton: boolean;
var OK:boolean;
begin
  OK:=SandDoseOn;
  AntiSlippingButton:=(AntiSlippingBrake or OK);
end;

function T_MoverParameters.BrakeDelaySwitch(BDS:byte): boolean;
begin
//  if BrakeCtrlPosNo>0 then
   if BrakeHandle=MHZ_EN57 then
    begin
      if (BDS<>BrakeOpModeFlag) and ((BDS and BrakeOpModes) > 0) then
       begin
        BrakeOpModeFlag:=BDS;
        BrakeDelaySwitch:=true;
       end
      else
         BrakeDelaySwitch:=false;
    end
   else if Hamulec.SetBDF(BDS) then
    begin
      BrakeDelayFlag:=BDS;
      BrakeDelaySwitch:=true;
      BrakeStatus:=(BrakeStatus and 191);
      //kopowanie nastawy hamulca do kolejnego czlonu - do przemyślenia
      if CabNo<>0 then
       SendCtrlToNext('BrakeDelay',BrakeDelayFlag,CabNo);
    end
  else
   BrakeDelaySwitch:=false;
end;

function T_MoverParameters.IncBrakeMult(): boolean;
begin
  if (LoadFlag>0) and (MBPM<2) and (LoadFlag<3) then
   begin
    if (MaxBrakePress[2]>0) and (LoadFlag=1) then
      LoadFlag:=2
    else
      LoadFlag:=3;
    IncBrakeMult:=true;
    if BrakeCylMult[2]>0 then BrakeCylMult[0]:=BrakeCylMult[2];
   end
  else
 IncBrakeMult:=false;
end;

function T_MoverParameters.DecBrakeMult(): boolean;
begin
  if (LoadFlag>1) and (MBPM<2) then
   begin
    if (MaxBrakePress[2]>0) and (LoadFlag=3) then
      LoadFlag:=2
    else
      LoadFlag:=1;
    DecBrakeMult:=true;
    if BrakeCylMult[1]>0 then BrakeCylMult[0]:=BrakeCylMult[1];
   end
  else
 DecBrakeMult:=false;
end;

function T_MoverParameters.BrakeReleaser(state: byte): boolean;
var OK:boolean;
begin
  Hamulec.Releaser(state);
  if CabNo<>0 then //rekurencyjne wysłanie do następnego
   OK:=SendCtrlToNext('BrakeReleaser',state,CabNo);
  BrakeReleaser:=OK;
end;

function T_MoverParameters.SwitchEPBrake(state: byte):boolean;
var
  OK:boolean;
  temp: real;
begin
  OK:=false;
  if (BrakeHandle = St113) and (ActiveCab<>0) then
   begin
    if(state>0)then
      temp:=(Handle as TSt113).GetCP
    else
      temp:=0;
    Hamulec.SetEPS(temp);
    SendCtrlToNext('Brake',temp,CabNo);
   end;
//  OK:=SetFlag(BrakeStatus,((2*State-1)*b_epused));
//  SendCtrlToNext('Brake',(state*(2*BrakeCtrlPos-1)),CabNo);
  SwitchEPBrake:=OK;
end;

{uklady pneumatyczne}

function T_MoverParameters.IncBrakePress(var brake:real;PressLimit,dp:real):boolean;
begin
//  if (DynamicBrakeType<>dbrake_switch) and (DynamicBrakeType<>dbrake_none) and ((BrakePress>2.0) or (PipePress<3.7{(LowPipePress+0.5)})) then
    if (DynamicBrakeType<>dbrake_switch) and (DynamicBrakeType<>dbrake_none) and (BrakePress>2.0) and (TrainType<>dt_EZT) then //yB radzi nie sprawdzać ciśnienia w przewodzie
    //hunter-301211: dla EN57 silnikow nie odlaczamy
     begin
       DynamicBrakeFlag:=true;                 {uruchamianie hamulca ED albo odlaczanie silnikow}
       if (DynamicBrakeType=dbrake_automatic) and (abs(Im)>60) then            {nie napelniaj wiecej, jak na EP09}
         dp:=0.0;
     end;
    if brake+dp<PressLimit then
     begin
       brake:=brake+dp;
       IncBrakePress:=true;
     end
    else
     begin
       IncBrakePress:=false;
       brake:=PressLimit;
     end;
end;

function T_MoverParameters.DecBrakePress(var brake:real;PressLimit,dp:real):boolean;
begin
    if brake-dp>PressLimit then
     begin
       brake:=brake-dp;
       DecBrakePress:=true;
     end
    else
     begin
       DecBrakePress:=false;
       brake:=PressLimit;
     end;
//  if (DynamicBrakeType<>dbrake_switch) and ((BrakePress<0.1) and (PipePress>0.45{(LowPipePress+0.06)})) then
    if (DynamicBrakeType<>dbrake_switch) and (BrakePress<0.1) then //yB radzi nie sprawdzać ciśnienia w przewodzie
     DynamicBrakeFlag:=false;                {wylaczanie hamulca ED i/albo zalaczanie silnikow}
end;

procedure T_MoverParameters.UpdateBrakePressure(dt:real);
const LBDelay=5.0; {stala czasowa hamulca}
var Rate,Speed,dp,sm:real;
begin
  dpLocalValve:=0;
  dpBrake:=0;

  BrakePress:=Hamulec.GetBCP;
//  BrakePress:=(Hamulec as TEst4).ImplsRes.pa;
  Volume:=Hamulec.GetBRP;

end;  {updatebrakepressure}


function T_MoverParameters.GetDVc(dt:real):real;
var c:T_MoverParameters;dv1,dv2,dv:real;
begin
  dv1:=0;
  dv2:=0;
//sprzeg 1
  if Couplers[0].Connected<>nil then
    if TestFlag(Couplers[0].CouplingFlag,ctrain_pneumatic) then
     begin                                        //*0.85
      c:=Couplers[0].Connected; //skrot           //0.08           //e/D * L/D = e/D^2 * L
      dv1:=0.5*dt*PF(PipePress,c.PipePress,(Spg)/(1+0.015/Spg*Dim.L));
      if (dv1*dv1>0.00000000000001) then c.Physic_Reactivation;
      c.Pipe.Flow(-dv1);
     end;
//sprzeg 2
  if Couplers[1].Connected<>nil then
    if TestFlag(Couplers[1].CouplingFlag,ctrain_pneumatic) then
     begin
      c:=Couplers[1].Connected; //skrot
      dv2:=0.5*dt*PF(PipePress,c.PipePress,(Spg)/(1+0.015/Spg*Dim.L));
      if (dv2*dv2>0.00000000000001) then c.Physic_Reactivation;
      c.Pipe.Flow(-dv2);
     end;
  if (Couplers[1].Connected<>nil)and(Couplers[0].Connected<>nil) then
    if (TestFlag(Couplers[0].CouplingFlag,ctrain_pneumatic))and(TestFlag(Couplers[1].CouplingFlag,ctrain_pneumatic))then
     begin
      dv:=0.05*dt*PF(Couplers[0].Connected.PipePress,Couplers[1].Connected.PipePress,(Spg*0.85)/(1+0.03*Dim.L))*0;
      Couplers[0].Connected.Pipe.Flow(+dv);
      Couplers[1].Connected.Pipe.Flow(-dv);
     end;
//suma
  GetDVc:=dv2+dv1;
end;

procedure T_MoverParameters.UpdatePipePressure(dt:real);
const LBDelay=100;kL=0.5;
var {b: byte;} dV{,PWSpeed}{,PPP}:real; c: T_MoverParameters;
     temp: real;
     b: byte;
begin

  PipePress:=Pipe.P;
//  PPP:=PipePress;

  dpMainValve:=0;

if (BrakeCtrlPosNo>1) {and(ActiveCab<>0)}then
with BrakePressureTable[BrakeCtrlPos] do
   begin
          if(EngineType<>ElectricInductionMotor)then
           dpLocalValve:=LocHandle.GetPF(Max0R(LocalBrakePos/LocalBrakePosNo,LocalBrakePosA), Hamulec.GetBCP, ScndPipePress, dt, 0)
          else
           dpLocalValve:=LocHandle.GetPF(LocalBrakePosA, Hamulec.GetBCP, ScndPipePress, dt, 0);
          if(BrakeHandle=FV4a)and((PipePress<2.75)and((Hamulec.GetStatus and b_rls)=0))and(BrakeSubsystem=ss_LSt)and(TrainType<>dt_EZT)then
            temp:=PipePress+0.00001
            else
            temp:=ScndPipePress;
          Handle.SetReductor(BrakeCtrlPos2);

          if (BrakeOpModeFlag<>bom_PS) then
            if (BrakeOpModeFlag<bom_EP) or (Handle.GetPos(bh_EB)-0.5<BrakeCtrlPosR) or (BrakeHandle<>MHZ_EN57) then
              dpMainValve:=Handle.GetPF(BrakeCtrlPosR, PipePress, temp, dt, EqvtPipePress)
            else
              dpMainValve:=Handle.GetPF(0, PipePress, temp, dt, EqvtPipePress);
              
          if (dpMainValve<0){and(PipePressureVal>0.01)} then             {50}
            if Compressor>ScndPipePress then
               begin
              CompressedVolume:=CompressedVolume+dpMainValve/1500;
              Pipe2.Flow(dpMainValve/3);
               end
              else
              Pipe2.Flow(dpMainValve);
end;

//      if(EmergencyBrakeFlag)and(BrakeCtrlPosNo=0)then         {ulepszony hamulec bezp.}
      if(EmergencyBrakeFlag)or TestFlag(SecuritySystem.Status,s_SHPebrake) or TestFlag(SecuritySystem.Status,s_CAebrake) or (s_CAtestebrake=true) or (TestFlag(EngDmgFlag,32)){ or (not Battery)}then         {ulepszony hamulec bezp.}
        dpMainValve:=dpMainValve/1+PF(0,PipePress,0.15)*dt;
                                                //0.2*Spg
      Pipe.Flow(-dpMainValve);
      Pipe.Flow(-(PipePress)*0.001*dt);
//      if Heating then
//        Pipe.Flow(PF(PipePress,0,d2A(7))*dt);
//      if ConverterFlag then
//        Pipe.Flow(PF(PipePress,0,d2A(12))*dt);
      dpMainValve:=dpMainValve/(Dim.L*Spg*20);

      CntrlPipePress:=Hamulec.GetVRP; //ciśnienie komory wstępnej rozdzielacza

      case BrakeValve of
      W:
      begin
          if (BrakeLocHandle<>NoHandle) then
           begin
            LocBrakePress:=LocHandle.GetCP;
           (Hamulec as TWest).SetLBP(LocBrakePress);
           end;
          if MBPM<2 then
           (Hamulec as TWest).PLC(MaxBrakePress[LoadFlag])
          else
           (Hamulec as TWest).PLC(TotalMass);
         end;
      LSt,EStED:
         begin
        LocBrakePress:=LocHandle.GetCP;
        for b:=0 to 1 do
         if((TrainType and (dt_ET41 or dt_ET42))>0)and(Couplers[b].Connected<>nil)then //nie podoba mi się to rozwiązanie, chyba trzeba dodać jakiś wpis do fizyki na to
          if((Couplers[b].Connected.TrainType and (dt_ET41 or dt_ET42))>0)and((Couplers[b].CouplingFlag and 36) = 36)then
           LocBrakePress:=Max0R(Couplers[b].Connected.LocHandle.GetCP,LocBrakePress);

         if(DynamicBrakeFlag)and(EngineType=ElectricInductionMotor)then
          begin
           (Hamulec as TLSt).SetLBP(LocBrakePress);
//           if(Vel>10)then LocBrakePress:=0 else
//           if(Vel>5)then LocBrakePress:=(10-Vel)/5*LocBrakePress
          end
         else
         (Hamulec as TLSt).SetLBP(LocBrakePress);
        if (BrakeValve = EStED) then
          if MBPM<2 then
           (Hamulec as TEStED).PLC(MaxBrakePress[LoadFlag])
          else
           (Hamulec as TEStED).PLC(TotalMass);

       end;
      CV1_L_TR:
      begin
        LocBrakePress:=LocHandle.GetCP;
        (Hamulec as TCV1L_TR).SetLBP(LocBrakePress);
     end;
       EP2:      (Hamulec as TEStEP2).PLC(TotalMass);
       ESt3AL2,NESt3,ESt4,ESt3:
       begin
          if MBPM<2 then
            (Hamulec as TNESt3).PLC(MaxBrakePress[LoadFlag])
          else
            (Hamulec as TNESt3).PLC(TotalMass);
          LocBrakePress:=LocHandle.GetCP;
          (Hamulec as TNESt3).SetLBP(LocBrakePress);
        end;
     KE:
      begin
         LocBrakePress:=LocHandle.GetCP;
        (Hamulec as TKE).SetLBP(LocBrakePress);
         if MBPM<2 then
          (Hamulec as TKE).PLC(MaxBrakePress[LoadFlag])
        else
          (Hamulec as TKE).PLC(TotalMass);
         end;
     end;

      if (BrakeHandle = FVel6) and (ActiveCab<>0) then
      begin
        if (Battery) and (ActiveDir<>0) and (EpFuse) then //tu powinien byc jeszcze bezpiecznik EP i baterie -
          temp:=(Handle as TFVel6).GetCP
        else
          temp:=0;  
        Hamulec.SetEPS(temp);
        SendCtrlToNext('Brake',temp,CabNo); //Ra 2014-11: na tym się wysypuje, ale nie wiem, w jakich warunkach
       end;

      Pipe.Act;
      PipePress:=Pipe.P;
      if (BrakeStatus and 128)=128 then //jesli hamulec wyłączony
        temp:=0  //odetnij
       else
        temp:=1; //połącz
      Pipe.Flow(temp*Hamulec.GetPF(temp*PipePress,dt,Vel)+GetDVc(dt));

      if ASBType=128 then
          Hamulec.ASB(Byte(SlippingWheels));

      dpPipe:=0;

//yB: jednokrokowe liczenie tego wszystkiego
      Pipe.Act;
      PipePress:=Pipe.P;

      dpMainValve:=dpMainValve/(100*dt); //normalizacja po czasie do syczenia;


  if PipePress<-1 then
     begin
    PipePress:=-1;
    Pipe.CreatePress(-1);
    Pipe.Act;
     end;

  if CompressedVolume<0 then
   CompressedVolume:=0;
end;  {updatepipepressure}


procedure T_MoverParameters.CompressorCheck(dt:real);
begin
 //if (CompressorSpeed>0.0) then //ten warunek został sprawdzony przy wywołaniu funkcji
 if (VeselVolume>0) then
  begin
   if MaxCompressor-MinCompressor<0.0001 then
    begin
{     if Mains and (MainCtrlPos>1) then}
     if CompressorAllow and Mains and (MainCtrlPos>0) then
      begin
        if (Compressor<MaxCompressor) then
         if (EngineType=DieselElectric) and (CompressorPower>0) then
          CompressedVolume:=CompressedVolume+dt*CompressorSpeed*(2*MaxCompressor-Compressor)/MaxCompressor*(DEList[MainCtrlPos].rpm/DEList[MainCtrlPosNo].rpm)
         else
          begin
           CompressedVolume:=CompressedVolume+dt*CompressorSpeed*(2*MaxCompressor-Compressor)/MaxCompressor;
           TotalCurrent:=TotalCurrent+0.0015*Voltage; //tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę
          end
        else
         begin
           CompressedVolume:=CompressedVolume*0.8;
           SetFlag(SoundFlag,sound_relay);
           SetFlag(SoundFlag,sound_loud);
         end;
      end;
    end
   else
    begin
     if (CompressorFlag) then //jeśli sprężarka załączona
      begin //sprawdzić możliwe warunki wyłączenia sprężarki
       if (CompressorPower=5) then //jeśli zasilanie z sąsiedniego członu
        begin //zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1)
         if (Couplers[1].Connected<>NIL) then
          CompressorFlag:=Couplers[1].Connected.CompressorAllow and Couplers[1].Connected.ConverterFlag and Couplers[1].Connected.Mains
         else
          CompressorFlag:=false; //bez tamtego członu nie zadziała
        end
       else if (CompressorPower=4) then //jeśli zasilanie z poprzedniego członu
        begin //zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1)
         if (Couplers[0].Connected<>NIL) then
          CompressorFlag:=Couplers[0].Connected.CompressorAllow and Couplers[0].Connected.ConverterFlag and Couplers[0].Connected.Mains
         else
          CompressorFlag:=false; //bez tamtego członu nie zadziała
        end
       else
        CompressorFlag:=(CompressorAllow) and ((ConverterFlag) or (CompressorPower=0)) and (Mains);
      if (Compressor>MaxCompressor) then //wyłącznik ciśnieniowy jest niezależny od sposobu zasilania
       CompressorFlag:=false;
      end
     else //jeśli nie załączona
      if (Compressor<MinCompressor) and (LastSwitchingTime>CtrlDelay) then //jeśli nie załączona, a ciśnienie za małe
       begin //załączenie przy małym ciśnieniu
        if (CompressorPower=5) then //jeśli zasilanie z następnego członu
         begin //zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1)
          if (Couplers[1].Connected<>NIL) then
           CompressorFlag:=Couplers[1].Connected.CompressorAllow and Couplers[1].Connected.ConverterFlag and Couplers[1].Connected.Mains
          else
           CompressorFlag:=false; //bez tamtego członu nie zadziała
         end
        else if (CompressorPower=4) then //jeśli zasilanie z poprzedniego członu
         begin //zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1)
          if (Couplers[0].Connected<>NIL) then
           CompressorFlag:=Couplers[0].Connected.CompressorAllow and Couplers[0].Connected.ConverterFlag and Couplers[0].Connected.Mains
          else
           CompressorFlag:=false; //bez tamtego członu nie zadziała
         end
        else
         CompressorFlag:=(CompressorAllow) and ((ConverterFlag) or (CompressorPower=0)) and (Mains);
        if (CompressorFlag) then //jeśli została załączona
         LastSwitchingTime:=0; //to trzeba ograniczyć ponowne włączenie
       end;
//          for b:=0 to 1 do //z Megapacka
//    with Couplers[b] do
//     if TestFlag(CouplingFlag,ctrain_scndpneumatic) then
//      Connected.CompressorFlag:=CompressorFlag;
     if CompressorFlag then
      if (EngineType=DieselElectric) and (CompressorPower>0) then
       CompressedVolume:=CompressedVolume+dt*CompressorSpeed*(2*MaxCompressor-Compressor)/MaxCompressor*(DEList[MainCtrlPos].rpm/DEList[MainCtrlPosNo].rpm)
      else
       begin
        CompressedVolume:=CompressedVolume+dt*CompressorSpeed*(2*MaxCompressor-Compressor)/MaxCompressor;
        if (CompressorPower=5)and(Couplers[1].Connected<>NIL) then
         Couplers[1].Connected.TotalCurrent:=Couplers[1].Connected.TotalCurrent+0.0015*Couplers[1].Connected.Voltage //tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę
        else if (CompressorPower=4)and(Couplers[0].Connected<>NIL) then
         Couplers[0].Connected.TotalCurrent:=Couplers[0].Connected.TotalCurrent+0.0015*Couplers[0].Connected.Voltage //tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę
        else
         TotalCurrent:=TotalCurrent+0.0015*Voltage; //tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę
       end
    end;
  end;
end;
{Ra 2014-07: do C++
procedure T_MoverParameters.ConverterCheck;
begin //sprawdzanie przetwornicy
if (ConverterAllow=true)and(Mains=true) then
 ConverterFlag:=true
 else
 ConverterFlag:=false;
end;
}
//youBy - przewod zasilajacy
procedure T_MoverParameters.UpdateScndPipePressure(dt: real);
const Spz=0.5067;
var c:T_MoverParameters;dv1,dv2,dv:real;
begin
  dv1:=0;
  dv2:=0;

//sprzeg 1
  if Couplers[0].Connected<>nil then
   if TestFlag(Couplers[0].CouplingFlag,ctrain_scndpneumatic) then
    begin
      c:=Couplers[0].Connected; //skrot
       dv1:=0.5*dt*PF(ScndPipePress,c.ScndPipePress,Spz*0.75);
       if (dv1*dv1>0.00000000000001) then c.Physic_Reactivation;
       c.Pipe2.Flow(-dv1);
    end;
//sprzeg 2
  if Couplers[1].Connected<>nil then
   if TestFlag(Couplers[1].CouplingFlag,ctrain_scndpneumatic) then
     begin
       c:=Couplers[1].Connected; //skrot
       dv2:=0.5*dt*PF(ScndPipePress,c.ScndPipePress,Spz*0.75);
       if (dv2*dv2>0.00000000000001) then c.Physic_Reactivation;
       c.Pipe2.Flow(-dv2);
      end;
  if(Couplers[1].Connected<>nil)and(Couplers[0].Connected<>nil)then
    if (TestFlag(Couplers[0].CouplingFlag,ctrain_scndpneumatic))and(TestFlag(Couplers[1].CouplingFlag,ctrain_scndpneumatic))then
     begin
      dv:=0.00025*dt*PF(Couplers[0].Connected.ScndPipePress,Couplers[1].Connected.ScndPipePress,Spz*0.25);
      Couplers[0].Connected.Pipe2.Flow(+dv);
      Couplers[1].Connected.Pipe2.Flow(-dv);
      end;

  Pipe2.Flow(Hamulec.GetHPFlow(ScndPipePress, dt));

  if ((Compressor>ScndPipePress) and (CompressorSpeed>0.0001)) or (TrainType=dt_EZT) then
   begin
    dV:=PF(Compressor,ScndPipePress,Spz)*dt;
    CompressedVolume:=CompressedVolume+dV/1000;
    Pipe2.Flow(-dV);
   end;

  Pipe2.Flow(dv1+dv2);
  Pipe2.Act;
  ScndPipePress:=Pipe2.P;

  if ScndPipePress<-1 then
   begin
    ScndPipePress:=-1;
    Pipe2.CreatePress(-1);
    Pipe2.Act;
   end;


end;


{lokomotywy}

function T_MoverParameters.ComputeRotatingWheel(WForce,dt,n:real): real;
var newn,eps:real;
begin
  if (n=0) and (WForce*Sign(V)<0) then
   newn:=0
  else
   begin
     eps:=WForce*WheelDiameter/(2.0*AxleInertialMoment);
     newn:=n+eps*dt;
     if (newn*n<=0) and (eps*n<0) then
      newn:=0;
   end;
  ComputeRotatingWheel:=newn;
end;

{----------------------}
{LOKOMOTYWA ELEKTRYCZNA}

function T_MoverParameters.FuseFlagCheck: boolean;
var b:byte;
begin
 FuseFlagCheck:=false;
 if Power>0.01 then FuseFlagCheck:=FuseFlag
 else               {pobor pradu jezeli niema mocy}
  for b:=0 to 1 do
   with Couplers[b] do
    if TestFlag(CouplingFlag,ctrain_controll) then
     if Connected.Power>0.01 then
      FuseFlagCheck:=Connected.FuseFlagCheck();
end;

function T_MoverParameters.FuseOn: boolean;
begin
 FuseOn:=false;
 if (MainCtrlPos=0) and (ScndCtrlPos=0) and (TrainType<>dt_ET40) and ((Mains) or (TrainType<>dt_EZT)) and (not TestFlag(EngDmgFlag,1)) then
  begin //w ET40 jest blokada nastawnika, ale czy działa dobrze?
   SendCtrlToNext('FuseSwitch',1,CabNo);
   if ((EngineType=ElectricSeriesMotor)or((EngineType=DieselElectric))) and FuseFlag then
    begin
     FuseFlag:=false;  {wlaczenie ponowne obwodu}
     FuseOn:=true;
     SetFlag(SoundFlag,sound_relay); SetFlag(SoundFlag,sound_loud);
    end;
  end;
end;

procedure T_MoverParameters.FuseOff;
begin
 if not FuseFlag then
  begin
   FuseFlag:=true;
   EventFlag:=true;
   SetFlag(SoundFlag,sound_relay);
   SetFlag(SoundFlag,sound_loud);
  end;
end;


function T_MoverParameters.ShowCurrent(AmpN:byte): integer;
var b,Bn:byte;
    Grupowy: boolean;
begin
  ClearPendingExceptions;
  ShowCurrent:=0;
  Grupowy:=(DelayCtrlFlag) and (TrainType=dt_et22); //przerzucanie walu grupowego w ET22;
  Bn:=RList[MainCtrlActualPos].Bn; //ile równoległych gałęzi silników

  if (DynamicBrakeType=dbrake_automatic) and (DynamicBrakeFlag) then
   Bn:=2;
  if Power>0.01 then
   begin
     if AmpN>0 then //podać prąd w gałęzi
      begin
       if (Bn<AmpN)or((Grupowy) and (AmpN=Bn-1)) then
         ShowCurrent:=0
        else //normalne podawanie pradu
         ShowCurrent:=Trunc(Abs(Im));
      end
     else //podać całkowity
       ShowCurrent:=Trunc(Abs(Itot));
    end
  else               {pobor pradu jezeli niema mocy}
   for b:=0 to 1 do
    with Couplers[b] do
     if TestFlag(CouplingFlag,ctrain_controll) then
      if Connected.Power>0.01 then
       ShowCurrent:=Connected.ShowCurrent(AmpN);
end;

{Ra 2014-06: przeniesione do C++
function T_MoverParameters.ShowEngineRotation(VehN:byte): integer;
var b:Byte; //,Bn:byte;
begin
  ClearPendingExceptions;
  ShowEngineRotation:=0;
  case VehN of
   1: ShowEngineRotation:=Trunc(Abs(enrot));
   2: for b:=0 to 1 do
       with Couplers[b] do
        if TestFlag(CouplingFlag,ctrain_controll) then
         if Connected.Power>0.01 then
          ShowEngineRotation:=Trunc(Abs(Connected.enrot));
   3: if Couplers[1].Connected<>nil then
       if TestFlag(Couplers[1].CouplingFlag,ctrain_controll) then
        if Couplers[1].Connected.Couplers[1].Connected<>nil then
         if TestFlag(Couplers[1].Connected.Couplers[1].CouplingFlag,ctrain_controll) then
          if Couplers[1].Connected.Couplers[1].Connected.Power>0.01 then
           ShowEngineRotation:=Trunc(Abs(Couplers[1].Connected.Couplers[1].Connected.enrot));
  end;
end;
}

{funkcje uzalezniajace sile pociagowa od predkosci: V2n, n2R, Current, Momentum}
{----------------}

function T_MoverParameters.V2n:real;
{przelicza predkosc liniowa na obrotowa}
const dmgn=0.5;
var n,deltan:real;
begin
  n:=V/(Pi*WheelDiameter); //predkosc obrotowa wynikajaca z liniowej [obr/s]
  deltan:=n-nrot; //"pochodna" prędkości obrotowej
  if SlippingWheels then
   if Abs(deltan)<0.01 then
    SlippingWheels:=false; {wygaszenie poslizgu}
  if SlippingWheels then   {nie ma zwiazku z predkoscia liniowa V}
   begin                   {McZapkie-221103: uszkodzenia kol podczas poslizgu}
     if deltan>dmgn then
      if FuzzyLogic(deltan,dmgn,p_slippdmg) then
        if SetFlag(DamageFlag,dtrain_wheelwear)   {podkucie}
          then EventFlag:=true;
     if deltan<-dmgn then
      if FuzzyLogic(-deltan,dmgn,p_slippdmg) then
        if SetFlag(DamageFlag,dtrain_thinwheel)  {wycieranie sie obreczy}
          then EventFlag:=true;
     n:=nrot;               {predkosc obrotowa nie zalezy od predkosci liniowej}
   end;
  V2n:=n;
end;

function T_MoverParameters.Current(n,U:real): real;
{wazna funkcja - liczy prad plynacy przez silniki polaczone szeregowo lub rownolegle}
{w zaleznosci od polozenia nastawnikow MainCtrl i ScndCtrl oraz predkosci obrotowej n}
{a takze wywala bezpiecznik nadmiarowy gdy za duzy prad lub za male napiecie}
{jest takze mozliwosc uszkodzenia silnika wskutek nietypowych parametrow}
const ep09resED=5.8; {TODO: dobrac tak aby sie zgadzalo ze wbudzeniem}
var //Rw,
    R,MotorCurrent:real;
    Rz,Delta,Isf:real;
    Mn: integer;
    Bn: real;
    SP: byte;
    U1: real; //napiecie z korekta
begin
  MotorCurrent:=0;
//i dzialanie hamulca ED w EP09
  if (DynamicBrakeType=dbrake_automatic) then
   begin
    if (((Hamulec as TLSt).GetEDBCP<0.25)and(Vadd<1))or(BrakePress>2.1) then
      DynamicBrakeFlag:=false
    else if (BrakePress>0.25) and ((Hamulec as TLSt).GetEDBCP>0.25) then
      DynamicBrakeFlag:=true;
    DynamicBrakeFlag:=DynamicBrakeFlag and ConverterFlag;   
   end;
//wylacznik cisnieniowy yBARC - to jest chyba niepotrzebne tutaj
//  if BrakePress>2 then
//   begin
//    StLinFlag:=true;
//    DelayCtrlFlag:=(TrainType<>dt_EZT); //EN57 nie ma czekania na 1. pozycji
//    DynamicBrakeFlag:=false;
//   end;
  if(BrakeSubSystem=ss_LSt)then
    if(DynamicBrakeFlag)then
     (Hamulec as TLSt).SetED(Abs(Im/350)) //hamulec ED na EP09 dziala az do zatrzymania lokomotywy
    else
     (Hamulec as TLSt).SetED(0);

  ResistorsFlag:=(RList[MainCtrlActualPos].R>0.01){ and (not DelayCtrlFlag)};
  ResistorsFlag:=ResistorsFlag or ((DynamicBrakeFlag=true) and (DynamicBrakeType=dbrake_automatic));

  if(TrainType=dt_ET22)and(DelayCtrlFlag)and(MainCtrlActualPos>1)then
    Bn:=1-1/RList[MainCtrlActualPos].Bn
  else
    Bn:=1;
  R:=RList[MainCtrlActualPos].R*Bn+CircuitRes;

  if (TrainType<>dt_EZT)or(Imin<>IminLo)or(not ScndS) then //yBARC - boczniki na szeregu poprawnie
   Mn:=RList[MainCtrlActualPos].Mn
  else
   Mn:=RList[MainCtrlActualPos].Mn*RList[MainCtrlActualPos].Bn;
//z Megapacka
//  if DynamicBrakeFlag and (TrainType=dt_ET42) then { KURS90 azeby mozna bylo hamowac przy opuszczonych pantografach }
//  SP:=ScndCtrlActualPos;
//   if(ScndInMain)then
//    if not (RList[MainCtrlActualPos].ScndAct=255) then
//     SP:=RList[MainCtrlActualPos].ScndAct;
//    with MotorParam[SP] do
//  begin
//  Rz:=WindingRes+R;
//  MotorCurrent:=-fi*n/Rz;
//  end;
  if DynamicBrakeFlag and (not FuseFlag) and (DynamicBrakeType=dbrake_automatic) and ConverterFlag and Mains then     {hamowanie EP09}
   with MotorParam[0] do //TUHEX
     begin
       MotorCurrent:=-Max0R(fi*(Vadd/(Vadd+Isat)-fi0),0)*n*2/ep09resED; {TODO: zrobic bardziej uniwersalne nie tylko dla EP09}
//       if abs(MotorCurrent)>500 then
//        MotorCurrent:=sign(MotorCurrent)*500 {TODO: zrobic bardziej finezyjnie}
     end
  else
  if (RList[MainCtrlActualPos].Bn=0) {or FuseFlag} or (not StLinFlag) {or DelayCtrlFlag} then
  //if (RList[MainCtrlActualPos].Bn=0) or FuseFlag or StLinFlag or DelayCtrlFlag or ((TrainType=dt_ET42)and(not(ConverterFlag)and not(DynamicBrakeFlag)))  then //z Megapacka
    MotorCurrent:=0                    {wylaczone}
  else                                 {wlaczone}
   begin
   SP:=ScndCtrlActualPos;
   if(ScndCtrlActualPos<255)then  {tak smiesznie bede wylaczal }
    begin
     if(ScndInMain)then
      if not (RList[MainCtrlActualPos].ScndAct=255) then
       SP:=RList[MainCtrlActualPos].ScndAct;
      with MotorParam[SP] do
       begin
        Rz:=Mn*WindingRes+R;
        if DynamicBrakeFlag then     {hamowanie}
         begin
           if DynamicBrakeType>1 then
            begin
              //if DynamicBrakeType<>dbrake_automatic then
              // MotorCurrent:=-fi*n/Rz  {hamowanie silnikiem na oporach rozruchowych}
(*               begin
                 U:=0;
                 Isf:=Isat;
                 Delta:=SQR(Isf*Rz+Mn*fi*n-U)+4*U*Isf*Rz;
                 MotorCurrent:=(U-Isf*Rz-Mn*fi*n+SQRT(Delta))/(2*Rz)
               end*)
            if (DynamicBrakeType=dbrake_switch) and (TrainType=dt_ET42) then
             begin //z Megapacka
             Rz:=WindingRes+R;
             MotorCurrent:=-fi*n/Rz;  //{hamowanie silnikiem na oporach rozruchowych}
               end;
            end
           else
             MotorCurrent:=0;        {odciecie pradu od silnika}
         end
        else
         begin
          U1:=U+Mn*n*fi0*fi;
          Isf:=Sign(U1)*Isat;
          Delta:=SQR(Isf*Rz+Mn*fi*n-U1)+4*U1*Isf*Rz;
          if Mains then
           begin
            if U>0 then
             MotorCurrent:=(U1-Isf*Rz-Mn*fi*n+SQRT(Delta))/(2.0*Rz)
            else
             MotorCurrent:=(U1-Isf*Rz-Mn*fi*n-SQRT(Delta))/(2.0*Rz)
           end
          else
           MotorCurrent:=0;
         end;{else DBF}
       end;{with}
    end{255}
   else
    MotorCurrent:=0;
   end;
{  if Abs(CabNo)<2 then Im:=MotorCurrent*ActiveDir*CabNo
   else Im:=0;
}

  if (DynamicBrakeType=dbrake_switch) and ((BrakePress>2.0) or (PipePress<3.6)) then
   begin
    Im:=0;
    MotorCurrent:=0;
    //Im:=0;
    Itot:=0;
   end
  else
   Im:=MotorCurrent;
  Current:=Im; {prad brany do liczenia sily trakcyjnej}
{  EnginePower:=Im*Im*RList[MainCtrlActualPos].Bn*RList[MainCtrlActualPos].Mn*WindingRes;}
  EnginePower:=Abs(Itot)*(1+RList[MainCtrlActualPos].Mn)*Abs(U);

  {awarie}
  MotorCurrent:=Abs(Im); {zmienna pomocnicza}
  if Motorcurrent>0 then
  begin
    if FuzzyLogic(Abs(n),nmax*1.1,p_elengproblem) then
     if MainSwitch(false) then
       EventFlag:=true;                                      {zbyt duze obroty - wywalanie wskutek ognia okreznego}
    if TestFlag(DamageFlag,dtrain_engine) then
     if FuzzyLogic(MotorCurrent,ImaxLo/10.0,p_elengproblem) then
      if MainSwitch(false) then
       EventFlag:=true;                                      {uszkodzony silnik (uplywy)}
    if (FuzzyLogic(Abs(Im),Imax*2,p_elengproblem) or FuzzyLogic(Abs(n),nmax*1.11,p_elengproblem)) then
{       or FuzzyLogic(Abs(U/Mn),2*NominalVoltage,1)) then } {poprawic potem}
     if (SetFlag(DamageFlag,dtrain_engine)) then
       EventFlag:=true;
  {! dorobic grzanie oporow rozruchowych i silnika}
  end;
end;

function T_MoverParameters.Momentum(I:real): real;
{liczy moment sily wytwarzany przez silnik elektryczny}
var SP: byte;
begin
   SP:=ScndCtrlActualPos;
   if (ScndInMain) then
    if not (RList[MainCtrlActualPos].ScndAct=255) then
     SP:=RList[MainCtrlActualPos].ScndAct;
    with MotorParam[SP] do
//     Momentum:=mfi*I*(1-1.0/(Abs(I)/mIsat+1));
     Momentum:=mfi*I*(Abs(I)/(Abs(I)+mIsat)-mfi0);
end;

function T_MoverParameters.MomentumF(I, Iw :real; SCP: byte): real;
begin
//umozliwia dokladne sterowanie wzbudzeniem
  with MotorParam[SCP] do
   MomentumF:=mfi*I*Max0R(Abs(Iw)/(Abs(Iw)+mIsat)-mfi0,0);
end;

function T_MoverParameters.dizel_Momentum(dizel_fill,n,dt:real): real;
{liczy moment sily wytwarzany przez silnik spalinowy}
var Moment, enMoment, eps, newn, friction: real;
begin
{  friction:=dizel_engagefriction*(11-2*random)/10; }
  friction:=dizel_engagefriction;
  if enrot>0 then
   begin
     Moment:=dizel_Mmax*dizel_fill-(dizel_Mmax-dizel_Mnmax*dizel_fill)*sqr(enrot/(dizel_nmax-dizel_nMmax*dizel_fill))-dizel_Mstand;
{     Moment:=Moment*(1+sin(eAngle*4))-dizel_Mstand*(1+cos(eAngle*4));}
   end
   else Moment:=-dizel_Mstand;
  if enrot<dizel_nmin/10.0 then
   if (eAngle<Pi/2.0) then Moment:=Moment-dizel_Mstand; {wstrzymywanie przy malych obrotach}
  //!! abs
  if abs(abs(n)-enrot)<0.1 then
   begin
    if (Moment)>(dizel_engageMaxForce*dizel_engage*dizel_engageDia*friction*2) then {zerwanie przyczepnosci sprzegla}
     enrot:=enrot+dt*Moment/dizel_AIM
    else
     begin
       dizel_engagedeltaomega:=0;
       enrot:=abs(n);                          {jest przyczepnosc tarcz}
     end
(*
     end
   end
  else
   begin
     if (enrot=0) and (Moment<0) then
      newn:=0
     else
      begin
         //!! abs
         dizel_engagedeltaomega:=enrot-n;     {sliganie tarcz}
         enMoment:=Moment-sign(dizel_engagedeltaomega)*dizel_engageMaxForce*dizel_engage*dizel_engageDia*friction;
         Moment:=sign(dizel_engagedeltaomega)*dizel_engageMaxForce*dizel_engage*dizel_engageDia*friction;
         dizel_engagedeltaomega:=abs(enrot-abs(n));
         eps:=enMoment/dizel_AIM;
         newn:=enrot+eps*dt;
         if (newn*enrot<=0) and (eps*enrot<0) then
          newn:=0;
      end;
     enrot:=newn;
   end;
  dizel_Momentum:=Moment;
  if (enrot=0) and (not dizel_enginestart) then
   Mains:=false;
end;

function T_MoverParameters.CutOffEngine: boolean; {wylacza uszkodzony silnik}
begin
 CutOffEngine:=false; //Ra: wartość domyślna, sprawdzić to trzeba
 if (NPoweredAxles>0) and (CabNo=0) and (EngineType=ElectricSeriesMotor) then
  begin
   if SetFlag(DamageFlag,-dtrain_engine) then
    begin
     NPoweredAxles:=NPoweredAxles div 2;
     CutOffEngine:=true;
    end;
  end
end;

{przelacznik pradu wysokiego rozruchu}
function T_MoverParameters.MaxCurrentSwitch(State:boolean):boolean;
begin
  MaxCurrentSwitch:=false;
  if (EngineType=ElectricSeriesMotor) then
   if (ImaxHi>ImaxLo) then
   begin
     if State and (Imax=ImaxLo) and (RList[MainCtrlPos].Bn<2) and not ((TrainType=dt_ET42)and(MainctrlPos>0)) then
      begin
        Imax:=ImaxHi;
        MaxCurrentSwitch:=true;
        if CabNo<>0 then
         SendCtrlToNext('MaxCurrentSwitch',1,CabNo);
      end;
     if (not State) then
     if (Imax=ImaxHi) then
     if not ((TrainType=dt_ET42)and(MainctrlPos>0)) then
      begin
        Imax:=ImaxLo;
        MaxCurrentSwitch:=true;
        if CabNo<>0 then
         SendCtrlToNext('MaxCurrentSwitch',0,CabNo);
      end;
   end;
end;


{przelacznik pradu automatycznego rozruchu}
function T_MoverParameters.MinCurrentSwitch(State:boolean):boolean;
begin
  MinCurrentSwitch:=false;
  if ((EngineType=ElectricSeriesMotor) and (IminHi>IminLo)) or (TrainType=dt_EZT) then
   begin
     if State and (Imin=IminLo) then
      begin
        Imin:=IminHi;
        MinCurrentSwitch:=true;
        if CabNo<>0 then
         SendCtrlToNext('MinCurrentSwitch',1,CabNo);
      end;
     if (not State) and (Imin=IminHi) then
      begin
        Imin:=IminLo;
        MinCurrentSwitch:=true;
        if CabNo<>0 then
         SendCtrlToNext('MinCurrentSwitch',0,CabNo);
      end;
   end;
end;


{reczne przelaczanie samoczynnego rozruchu}
function T_MoverParameters.AutoRelaySwitch(State:boolean):boolean;
 begin
   if (AutoRelayType=2) and (AutoRelayFlag<>State) then
    begin
      AutoRelayFlag:=State;
      AutoRelaySwitch:=true;
      SendCtrlToNext('AutoRelaySwitch',ord(State),CabNo);
    end
   else
    AutoRelaySwitch:=false;
 end;

function T_MoverParameters.AutoRelayCheck: boolean;
var OK:boolean; b:byte;
begin
//  if ((TrainType=dt_EZT{) or (TrainType=dt_ET22)}) and (Imin=IminLo)) or ((ActiveDir<0) and (TrainType<>dt_PseudoDiesel')) then
//     if RList[MainCtrlActualPos].Bn>1 then
//      begin
//        dec(MainCtrlActualPos);
//        AutoRelayCheck:=false;
//        Exit;
//      end;
//yB: wychodzenie przy odcietym pradzie
  if (ScndCtrlActualPos=255)then
   begin
    AutoRelayCheck:=false;
    MainCtrlActualPos:=0;
   end
  else
  //if (not Mains) or (FuseFlag) or (StLinFlag) then   //hunter-111211: wylacznik cisnieniowy
  //if ((not Mains) or (FuseFlag)) and not((DynamicBrakeFlag) and (TrainType=dt_ET42)) then
  if ((not Mains) or (FuseFlag)  or (StLinFlag)) and not((DynamicBrakeFlag) and (TrainType=dt_ET42)) then  //hunter-111211: wylacznik cisnieniowy
   begin
     AutoRelayCheck:=false;
     MainCtrlActualPos:=0;
     ScndCtrlActualPos:=0;
   end
  else
   begin
    OK:=false;
    if DelayCtrlFlag and (MainCtrlPos=1) and (MainCtrlActualPos=1) and (LastRelayTime>InitialCtrlDelay) then
     begin
       DelayCtrlFlag:=false;
       SetFlag(SoundFlag,sound_relay); SetFlag(SoundFlag,sound_loud);
     end;
    //if (TrainType<>dt_EZT) then //Ra: w EZT można dać od razu na S albo R, wał kułakowy sobie dokręci
    if (LastRelayTime>CtrlDelay) and not DelayCtrlFlag then
     begin
      if (MainCtrlPos=0) and (TrainType<>dt_ET40) and (TrainType<>dt_EP05) then
        DelayCtrlFlag:=true;  //(TrainType<>dt_EZT); //EN57 nie ma czekania na 1. pozycji
      if (MainCtrlPos=0) and ((TrainType=dt_ET40)or(TrainType=dt_EP05)) and (MainCtrlActualPos=0) then
      DelayCtrlFlag:=true; //(TrainType<>dt_EZT); //EN57 nie ma czekania na 1. pozycji

      if (((RList[MainCtrlActualPos].R=0) and ((not CoupledCtrl) or ((Imin=IminLo) and (ScndS=true)))) or (MainCtrlActualPos=RListSize))
          and ((ScndCtrlActualPos>0) or (ScndCtrlPos>0)) then
        begin   {zmieniaj scndctrlactualpos}
          if (not AutoRelayFlag) or (not MotorParam[ScndCtrlActualPos].AutoSwitch) then
           begin                                                {scnd bez samoczynnego rozruchu}
             OK:=true;
             if (ScndCtrlActualPos<ScndCtrlPos) then
              inc(ScndCtrlActualPos)
             else
              if (ScndCtrlActualPos>ScndCtrlPos) and (TrainType<>dt_EZT) then
               dec(ScndCtrlActualPos)

              else
              if (ScndCtrlActualPos>ScndCtrlPos) and (TrainType=dt_EZT) then

               Exit       {utkniecie walu kulakowego}
             else OK:=false;
           end
          else
           begin                                                {scnd z samoczynnym rozruchem}
             if (ScndCtrlPos<ScndCtrlActualPos) and (TrainType<>dt_EZT) then
              begin
                dec(ScndCtrlActualPos);
                OK:=true;
              end
              else
              if (ScndCtrlPos<ScndCtrlActualPos) and (TrainType=dt_EZT) then
              begin
                Exit;    {utkniecie walu kulakowego}
              end
             else
              if (ScndCtrlPos>ScndCtrlActualPos) then
               if Abs(Im)<Imin then
                if MotorParam[ScndCtrlActualPos].AutoSwitch then
                 begin
                   inc(ScndCtrlActualPos);
                   OK:=true
                 end;
           end;
        end
       else
        begin          {zmieniaj mainctrlactualpos}
          if ((TrainType=dt_EZT) and (Scnds=true) and (Imin=IminLo)) then
           if RList[MainCtrlActualPos+1].Bn>1 then
            begin
              AutoRelayCheck:=false;
              Exit;
           end;
          if (not AutoRelayFlag) or (not RList[MainCtrlActualPos].AutoSwitch) then
           begin                                                {main bez samoczynnego rozruchu}
             OK:=true;
             if RList[MainCtrlActualPos].Relay<MainCtrlPos then
                if ((RList[MainCtrlActualPos].Mn>RList[MainCtrlPos].Mn)and (RList[MainCtrlActualPos+1].Mn<RList[MainCtrlActualPos].Mn) and (TrainType=dt_ET22) and (LastRelayTime<InitialCtrlDelay))then
                 begin
                 Itot:=0;
                 Im:=0;
                 OK:=false;             {odciecie pradu, przy przelaczaniu silnikow w ET22}
                 end
                 else
                 //if (RList[MainCtrlActualPos].R=0) and (RList[MainCtrlPos].R>0) and (TrainType=dt_ET22) and (LastRelayTime<InitialCtrlDelay) then

              begin
                inc(MainCtrlActualPos);
                //---------
                //hunter-111211: poprawki
                if MainCtrlActualPos>0 then
                 //if (RList[MainCtrlActualPos].R=0) and ((RList[MainCtrlActualPos].ScndAct=0) or (RList[MainCtrlActualPos].ScndAct=255)) then  {dzwieki przechodzenia na bezoporowa}
                 if (RList[MainCtrlActualPos].R=0) and (not (MainCtrlActualPos=MainCtrlPosNo)) then  //wejscie na bezoporowa
                  begin
                   SetFlag(SoundFlag,sound_manyrelay); SetFlag(SoundFlag,sound_loud);
                  end
                 else if (RList[MainCtrlActualPos].R>0) and (RList[MainCtrlActualPos-1].R=0) then //wejscie na drugi uklad
                  begin
                   SetFlag(SoundFlag,sound_manyrelay);
                  end;

              end
             else if (RList[MainCtrlActualPos].Relay>MainCtrlPos) and (TrainType<>dt_EZT) then
              begin
              if not ((RList[MainCtrlActualPos].Mn<RList[MainCtrlPos].Mn) and (RList[MainCtrlActualPos-1].Mn>RList[MainCtrlActualPos].Mn)and (TrainType=dt_ET22) and (LastRelayTime<InitialCtrlDelay))then
              begin
                dec(MainCtrlActualPos);
                if MainCtrlActualPos>0 then  //hunter-111211: poprawki
                 //if (RList[MainCtrlActualPos+1].R=0) and ((RList[MainCtrlActualPos+1].ScndAct=0) or (RList[MainCtrlActualPos+1].ScndAct=255)) then  {dzwieki schodzenia z bezoporowej}
                 if RList[MainCtrlActualPos].R=0 then  {dzwieki schodzenia z bezoporowej}
                  begin
                   SetFlag(SoundFlag,sound_manyrelay);
                  end;
              end
             else
               begin
                 Itot:=0;
                 Im:=0;
                 OK:=false;           {odciecie pradu, przy przelaczaniu silnikow w ET22}
                 end;
              end
              else if (RList[MainCtrlActualPos].Relay>MainCtrlPos) and (TrainType=dt_EZT) and (MainCtrlPos>0) then     //K90
              begin
              Exit;      {utkniecie walu kulakowego}
              end
             else if  (TrainType=dt_EZT) and (MainCtrlPos=0) then
              MainCtrlActualPos:=0
              else
              if (RList[MainCtrlActualPos].R>0) and (ScndCtrlActualPos>0) and (TrainType<>dt_EZT) then
               Dec(ScndCtrlActualPos) {boczniki nie dzialaja na poz. oporowych}
              else
              if (ScndCtrlPos<ScndCtrlActualPos) and (TrainType=dt_EZT) then
               Exit {boczniki nie dzialaja na poz. oporowych}
              else
               OK:=false;
           end
          else                                                  {main z samoczynnym rozruchem}
           begin
             OK:=false;
             if (MainCtrlPos<RList[MainCtrlActualPos].Relay) and (TrainType<>dt_EZT) then
             begin
             if not ((RList[MainCtrlActualPos].Mn<RList[MainCtrlPos].Mn)and (RList[MainCtrlActualPos-1].Mn>RList[MainCtrlActualPos].Mn) and (TrainType=dt_ET22) and (LastRelayTime<InitialCtrlDelay))then
              begin
                dec(MainCtrlActualPos);
                OK:=true;
                if MainCtrlActualPos>0 then
                   if (RList[MainCtrlActualPos+1].R=0) and ((RList[MainCtrlActualPos+1].ScndAct=0) or (RList[MainCtrlActualPos+1].ScndAct=255)) then  {dzwieki schodzenia z bezoporowej}
                    begin
                    SetFlag(SoundFlag,sound_manyrelay);
                    end;
              end
             else
               begin
               Itot:=0;
               Im:=0;
               OK:=false;      {odciecie pradu, przy przelaczaniu silnikow w ET22}
               end;
     end
             else
             if (MainCtrlPos<RList[MainCtrlActualPos].Relay) and (MainCtrlPos>0) and (TrainType=dt_EZT)  then
              begin
                AutoRelayCheck:=false;
                Exit;    {utkniecie walu}
              end
             else
             if (TrainType=dt_EZT) and (MainCtrlPos=0) then
              begin
                MainCtrlActualPos:=0;
                ScndCtrlActualPos:=0;
              end
              else
             if ((ScndCtrlPos<ScndCtrlActualPos) and (TrainType=dt_EZT)) then
              begin
                Exit;  {utkniecie walu}
              end
             else
              if (MainCtrlPos>RList[MainCtrlActualPos].Relay)  or ((MainCtrlActualPos<RListSize) and (MainCtrlPos=RList[MainCtrlActualPos+1].Relay)) then
              begin
              if ((RList[MainCtrlActualPos].Mn>RList[MainCtrlPos].Mn) and(RList[MainCtrlActualPos+1].Mn<RList[MainCtrlActualPos].Mn) and (TrainType=dt_ET22) and (LastRelayTime<InitialCtrlDelay))then
               begin
               Itot:=0;
               Im:=0;
               OK:=false; {odciecie pradu, przy przelaczaniu silnikow w ET22}
              end
             else
               if Abs(Im)<Imin then
                 begin
                   inc(MainCtrlActualPos);

                   OK:=true;
                   if MainCtrlActualPos>0 then
                    if (RList[MainCtrlActualPos].R=0) and ((RList[MainCtrlActualPos].ScndAct=0) or (RList[MainCtrlActualPos].ScndAct=255)) then  {dzwieki przechodzenia na bezoporowa}
                     begin
                      SetFlag(SoundFlag,sound_manyrelay); SetFlag(SoundFlag,sound_loud);
                     end;
                 end;
               end;
           end;
        end;
     end
    else  {DelayCtrlFlag}
     if ((MainCtrlPos>1) and (MainCtrlActualPos>0) and DelayCtrlFlag) then
      begin
       //if (TrainType<>dt_EZT) then //Ra: w EZT można dać od razu na S albo R, wał kułakowy sobie dokręci
       MainCtrlActualPos:=0; //Ra: tu jest chyba wyłączanie przy zbyt szybkim wejściu na drugą pozycję
       OK:=true;
      end
      else
     if ((MainCtrlPos=0) and (TrainType=dt_EZT)) then
      begin
        MainCtrlActualPos:=0;
        ScndCtrlActualPos:=0; {zejscie walu kulakowego do 0 po ustawieniu nastawnika na 0}
        OK:=true;
      end
     else
      if (MainCtrlPos=1) and (MainCtrlActualPos=0) then
       MainCtrlActualPos:=1
      else
       if (MainCtrlPos=0) and (MainCtrlActualPos>0) and (TrainType<>dt_EZT) and (TrainType<>dt_ET40) and (TrainType<>dt_EP05) then
        begin
         dec(MainCtrlActualPos);
         OK:=true;
        end;
       if (MainCtrlPos=0) and (MainCtrlActualPos>0) and ((TrainType=dt_ET40)or(TrainType=dt_EP05)) and (LastRelayTime>(InitialCtrlDelay*2)) then
        begin
         dec(MainCtrlActualPos);
         OK:=true; {wal kulakowy w ET40}
        end;
    if OK then LastRelayTime:=0;
    AutoRelayCheck:=OK;
  end;
end;
*)
   end
  else
   begin
     if (enrot=0) and (Moment<0) then
      newn:=0
     else
      begin
         //!! abs
         dizel_engagedeltaomega:=enrot-n;     {sliganie tarcz}
         enMoment:=Moment-sign(dizel_engagedeltaomega)*dizel_engageMaxForce*dizel_engage*dizel_engageDia*friction;
         Moment:=sign(dizel_engagedeltaomega)*dizel_engageMaxForce*dizel_engage*dizel_engageDia*friction;
         dizel_engagedeltaomega:=abs(enrot-abs(n));
         eps:=enMoment/dizel_AIM;
         newn:=enrot+eps*dt;
         if (newn*enrot<=0) and (eps*enrot<0) then
          newn:=0;
      end;
     enrot:=newn;
   end;
  dizel_Momentum:=Moment;
  if (enrot=0) and (not dizel_enginestart) then
   Mains:=false;
end;

function T_MoverParameters.CutOffEngine: boolean; {wylacza uszkodzony silnik}
begin
 CutOffEngine:=false; //Ra: wartość domyślna, sprawdzić to trzeba
 if (NPoweredAxles>0) and (CabNo=0) and (EngineType=ElectricSeriesMotor) then
  begin
   if SetFlag(DamageFlag,-dtrain_engine) then
    begin
     NPoweredAxles:=NPoweredAxles div 2;
     CutOffEngine:=true;
    end;
  end
end;

{przelacznik pradu wysokiego rozruchu}
function T_MoverParameters.MaxCurrentSwitch(State:boolean):boolean;
begin
  MaxCurrentSwitch:=false;
  if (EngineType=ElectricSeriesMotor) then
   if (ImaxHi>ImaxLo) then
   begin
     if State and (Imax=ImaxLo) and (RList[MainCtrlPos].Bn<2) and not ((TrainType=dt_ET42)and(MainctrlPos>0)) then
      begin
        Imax:=ImaxHi;
        MaxCurrentSwitch:=true;
        if CabNo<>0 then
         SendCtrlToNext('MaxCurrentSwitch',1,CabNo);
      end;
     if (not State) then
     if (Imax=ImaxHi) then
     if not ((TrainType=dt_ET42)and(MainctrlPos>0)) then
      begin
        Imax:=ImaxLo;
        MaxCurrentSwitch:=true;
        if CabNo<>0 then
         SendCtrlToNext('MaxCurrentSwitch',0,CabNo);
      end;
   end;
end;


{przelacznik pradu automatycznego rozruchu}
function T_MoverParameters.MinCurrentSwitch(State:boolean):boolean;
begin
  MinCurrentSwitch:=false;
  if ((EngineType=ElectricSeriesMotor) and (IminHi>IminLo)) or (TrainType=dt_EZT) then
   begin
     if State and (Imin=IminLo) then
      begin
        Imin:=IminHi;
        MinCurrentSwitch:=true;
        if CabNo<>0 then
         SendCtrlToNext('MinCurrentSwitch',1,CabNo);
      end;
     if (not State) and (Imin=IminHi) then
      begin
        Imin:=IminLo;
        MinCurrentSwitch:=true;
        if CabNo<>0 then
         SendCtrlToNext('MinCurrentSwitch',0,CabNo);
      end;
   end;
end;


{reczne przelaczanie samoczynnego rozruchu}
function T_MoverParameters.AutoRelaySwitch(State:boolean):boolean;
 begin
   if (AutoRelayType=2) and (AutoRelayFlag<>State) then
    begin
      AutoRelayFlag:=State;
      AutoRelaySwitch:=true;
      SendCtrlToNext('AutoRelaySwitch',ord(State),CabNo);
    end
   else
    AutoRelaySwitch:=false;
 end;

function T_MoverParameters.AutoRelayCheck: boolean;
var OK:boolean; //b:byte;
 ARFASI, ARFASI2 :boolean; //sprawdzenie wszystkich warunkow (AutoRelayFlag, AutoSwitch, Im<Imin)
begin
 //Ra 2014-06: dla SN61 nie działa prawidłowo
 //rozlaczanie stycznikow liniowych
  if (not Mains) or (FuseFlag) or (MainCtrlPos=0) or ((BrakePress>2.1)and(TrainType<>dt_EZT)) or (ActiveDir=0) then   //hunter-111211: wylacznik cisnieniowy
   begin
     StLinFlag:=false; //yBARC - rozlaczenie stycznikow liniowych
     AutoRelayCheck:=false;
     if not DynamicBrakeFlag then
      begin
       Im:=0;
       Itot:=0;
       ResistorsFlag:=false;
      end; 
   end;

   ARFASI2:=(not AutoRelayFlag) or ((MotorParam[ScndCtrlActualPos].AutoSwitch) and (Abs(Im)<Imin)); //wszystkie warunki w jednym
   ARFASI :=(not AutoRelayFlag) or ((RList[MainCtrlActualPos].AutoSwitch) and (Abs(Im)<Imin)) or ((not RList[MainCtrlActualPos].AutoSwitch) and (RList[MainCtrlActualPos].Relay<MainCtrlPos)); //wszystkie warunki w jednym
           //brak PSR                   na tej pozycji działa PSR i prąd poniżej progu                         na tej pozycji nie działa PSR i pozycja walu ponizej
          //                         chodzi w tym wszystkim o to, żeby można było zatrzymać rozruch na jakiejś pozycji wpisując Autoswitch=0 i wymuszać
          //                         przejście dalej przez danie nastawnika na dalszą pozycję - tak to do tej pory działało i na tym się opiera fizyka ET22-2k

//////  LocalBrakePos:=byte(ARFASI)+2*byte(ARFASI2);

   begin
    if (StLinFlag) then
     begin
       if (RList[MainCtrlActualPos].R=0)and ((ScndCtrlActualPos>0) or (ScndCtrlPos>0)) and (not(CoupledCtrl)or(RList[MainCtrlActualPos].Relay=MainCtrlPos))then
        begin //zmieniaj scndctrlactualpos
           begin                                                {scnd bez samoczynnego rozruchu}
             if (ScndCtrlActualPos<ScndCtrlPos) then
              begin
               if (LastRelayTime>CtrlDelay)and(ARFASI2) then
                begin
                 inc(ScndCtrlActualPos);
                 OK:=true;
                end
              end
             else
              if ScndCtrlActualPos>ScndCtrlPos then
               begin
                if (LastRelayTime>CtrlDownDelay)and(TrainType<>dt_EZT) then
                 begin
                  dec(ScndCtrlActualPos);
                  OK:=true;
                 end
               end
             else OK:=false;
           end;
        end
       else
        begin //zmieniaj mainctrlactualpos
          if ((ActiveDir<0) and (TrainType<>dt_PseudoDiesel)) then
           if RList[MainCtrlActualPos+1].Bn>1 then
            begin
              AutoRelayCheck:=false;
              Exit; //Ra: to powoduje, że EN57 nie wyłącza się przy IminLo
            end;
           begin //main bez samoczynnego rozruchu
             if (RList[MainCtrlActualPos].Relay<MainCtrlPos)or(RList[MainCtrlActualPos+1].Relay=MainCtrlPos)or((TrainType=dt_ET22)and(DelayCtrlFlag)) then
              begin
               if (RList[MainCtrlPos].R=0) and (MainCtrlPos>0) and (not (MainCtrlPos=MainCtrlPosNo)) and (FastSerialCircuit=1) then
                begin
                 inc(MainCtrlActualPos);
//                 MainCtrlActualPos:=MainCtrlPos; //hunter-111012: szybkie wchodzenie na bezoporowa (303E)
                 OK:=true;
                 SetFlag(SoundFlag,sound_manyrelay); SetFlag(SoundFlag,sound_loud);
                end
               else if (LastRelayTime>CtrlDelay)and(ARFASI) then
                begin
                 if (TrainType=dt_ET22)and(MainCtrlPos>1)and((RList[MainCtrlActualPos].Bn<RList[MainCtrlActualPos+1].Bn)or(DelayCtrlFlag))then //et22 z walem grupowym
                  if (not DelayCtrlFlag) then //najpierw przejscie
                   begin
                    inc(MainCtrlActualPos);
                    DelayCtrlFlag:=true; //tryb przejscia
                    OK:=true;
                   end
                  else if(LastRelayTime>4*CtrlDelay) then //przejscie
                   begin
                    DelayCtrlFlag:=false;
                    OK:=true;                    
                   end
                  else 
                 else //nie ET22 z wałem grupowym
                  begin
                   inc(MainCtrlActualPos);
                   OK:=true;
                  end;
                 //---------
                 //hunter-111211: poprawki
                 if MainCtrlActualPos>0 then
                  if (RList[MainCtrlActualPos].R=0) and (not (MainCtrlActualPos=MainCtrlPosNo)) then  //wejscie na bezoporowa
                   begin
                    SetFlag(SoundFlag,sound_manyrelay); SetFlag(SoundFlag,sound_loud);
                   end
                  else if (RList[MainCtrlActualPos].R>0) and (RList[MainCtrlActualPos-1].R=0) then //wejscie na drugi uklad
                   begin
                    SetFlag(SoundFlag,sound_manyrelay);
                   end;
                end
              end
             else if RList[MainCtrlActualPos].Relay>MainCtrlPos then
              begin
               if (RList[MainCtrlPos].R=0) and (MainCtrlPos>0) and (not (MainCtrlPos=MainCtrlPosNo)) and (FastSerialCircuit=1) then
                begin
                 dec(MainCtrlActualPos);
//                 MainCtrlActualPos:=MainCtrlPos; //hunter-111012: szybkie wchodzenie na bezoporowa (303E)
                 OK:=true;
                 SetFlag(SoundFlag,sound_manyrelay);
                end
               else if (LastRelayTime>CtrlDownDelay) then
                begin
                 if (TrainType<>dt_EZT) then //tutaj powinien być tryb sterowania wałem
                  begin
                   dec(MainCtrlActualPos);
                   OK:=true;
                  end;
                 if MainCtrlActualPos>0 then  //hunter-111211: poprawki
                  if RList[MainCtrlActualPos].R=0 then  {dzwieki schodzenia z bezoporowej}
                   begin
                    SetFlag(SoundFlag,sound_manyrelay);
                   end;
                end
              end
             else
              if (RList[MainCtrlActualPos].R>0) and (ScndCtrlActualPos>0) then
               begin
                if (LastRelayTime>CtrlDownDelay) then
                 begin
                  Dec(ScndCtrlActualPos); {boczniki nie dzialaja na poz. oporowych}
                  OK:=true;
                 end
               end
              else
               OK:=false;
           end;
        end;
     end
    else  {not StLinFlag}
     begin
      OK:=false;
      //ybARC - tutaj sa wszystkie warunki, jakie musza byc spelnione, zeby mozna byla zalaczyc styczniki liniowe
      if ((MainCtrlPos=1)or((TrainType=dt_EZT)and(MainCtrlPos>0)))and(not FuseFlag)and(Mains)and((BrakePress<1.0)or(TrainType=dt_EZT))and(MainCtrlActualPos=0)and(ActiveDir<>0) then
       begin
         DelayCtrlFlag:=true;
         if (LastRelayTime>=InitialCtrlDelay) then
          begin
           StLinFlag:=true; //ybARC - zalaczenie stycznikow liniowych
           MainCtrlActualPos:=1;
           DelayCtrlFlag:=false;
           SetFlag(SoundFlag,sound_relay); SetFlag(SoundFlag,sound_loud);
           OK:=true;
          end;
       end
      else
       DelayCtrlFlag:=false;

      if (not StLinFlag)and((MainCtrlActualPos>0)or(ScndCtrlActualPos>0)) then
       if (TrainType=dt_EZT)and(CoupledCtrl)then //EN57 wal jednokierunkowy calosciowy
        begin
         if(MainCtrlActualPos=1)then
          begin
           MainCtrlActualPos:=0;
           OK:=true;
          end
         else
         if(LastRelayTime>CtrlDownDelay)then
          begin
           if(MainCtrlActualPos<RListSize)then
            inc(MainCtrlActualPos) //dojdz do konca
           else if(ScndCtrlActualPos<ScndCtrlPosNo)then
            inc(ScndCtrlActualPos) //potem boki
           else
            begin                  //i sie przewroc na koniec
             MainCtrlActualPos:=0;
             ScndCtrlActualPos:=0;
            end;
           OK:=true;
          end
        end
       else if(CoupledCtrl)then //wal kulakowy dwukierunkowy
        begin
         if (LastRelayTime>CtrlDownDelay) then
          begin
           if (ScndCtrlActualPos>0) then
            dec(ScndCtrlActualPos)
           else dec(MainCtrlActualPos);
           OK:=true;
          end
        end
       else
        begin
         MainCtrlActualPos:=0;
         ScndCtrlActualPos:=0;
         OK:=true;
        end;

     end;
    if OK then LastRelayTime:=0;
    AutoRelayCheck:=OK;
   end;
end;

function T_MoverParameters.ResistorsFlagCheck:boolean;  {sprawdzanie wskaznika oporow}
var b:byte;
begin
  ResistorsFlagCheck:=false;
  if Power>0.01 then ResistorsFlagCheck:=ResistorsFlag
  else               {pobor pradu jezeli niema mocy}
   for b:=0 to 1 do
    with Couplers[b] do
     if TestFlag(CouplingFlag,ctrain_controll) then
      if Connected.Power>0.01 then
       ResistorsFlagCheck:=Connected.ResistorsFlagCheck();
end;

function T_MoverParameters.dizel_EngageSwitch(state: real): boolean;
{zmienia parametr do ktorego dazy sprzeglo}
begin
 if (EngineType=DieselEngine) and (state<=1) and (state>=0) and (state<>dizel_engagestate) then
  begin
    dizel_engagestate:=state;
    dizel_EngageSwitch:=true
  end
 else
  dizel_EngageSwitch:=false;
end;

function T_MoverParameters.dizel_EngageChange(dt: real): boolean;
{zmienia parametr do ktorego dazy sprzeglo}
const engagedownspeed=0.9; engageupspeed=0.5;
var engagespeed:real; //OK:boolean;
begin
 dizel_EngageChange:=false;
 if dizel_engage-dizel_engagestate>0 then
  engagespeed:=engagedownspeed
 else
  engagespeed:=engageupspeed;
 if dt>0.2 then
  dt:=0.1;
 if abs(dizel_engage-dizel_engagestate)<0.11 then
  begin
    if (dizel_engage<>dizel_engagestate) then
     begin
       dizel_EngageChange:=true;
       dizel_engage:=dizel_engagestate;
     end
    //else OK:=false; //już jest false
  end
 else
  begin
    dizel_engage:=dizel_engage+engagespeed*dt*(dizel_engagestate-dizel_engage);
    //OK:=false;
  end;
 //dizel_EngageChange:=OK;
end;

(*
function T_MoverParameters.dizel_rotateengine(Momentum,dt,n,engage:real): real;
{oblicza obroty silnika}
var newn,eps:real;
begin
  if (Momentum<0) and (n=0) and (enrot=0) then
   newn:=0
  else
   begin
     if (enrot<dizel_nmin/16) and (Momentum>0) then
       Momentum:=0                                         {nie dziala przy b. malych obrotach}
     else
     if enrot<dizel_nmin/4 then
      begin
       if (eAngle>Pi/2) then Momentum:=Momentum-2*dizel_Mstand
      end
     else
     if enrot<dizel_nmin then
      if (eAngle>Pi) then Momentum:=Momentum-dizel_Mstand; {wstrzymywanie przy malych obrotach}

     eps:=Momentum/dizel_AIM;
     if engage<0.9 then {niepelny docisk - poslizg}
      begin
        newn:=(1-engage)*(enrot+eps*dt)+engage*(n+eps*dt);
        if (newn*enrot<=0) and (eps*enrot<0) then
         newn:=0;
      end
     else
      newn:=n; {bez poslizgu sprzegla}
   end;
  dizel_rotateengine:=newn;
{todo: uwzglednianie AIM przy ruszaniu}
end;
*)

function T_MoverParameters.dizel_fillcheck(mcp:byte): real;
{oblicza napelnienie, uzwglednia regulator obrotow}
var realfill,nreg: real;
begin
  realfill:=0;
  nreg:=0;
  if Mains and (MainCtrlPosNo>0) then
   begin
     if dizel_enginestart and (LastSwitchingTime>=0.9*InitialCtrlDelay) then {wzbogacenie przy rozruchu}
      realfill:=1
     else
      realfill:=RList[mcp].R;                                               {napelnienie zalezne od MainCtrlPos}
     if dizel_nmax_cutoff>0 then
      begin
       case RList[MainCtrlPos].Mn of
        0,1: nreg:=dizel_nmin;
        2:   if(dizel_automaticgearstatus=0)then
              nreg:=dizel_nmax
             else
              nreg:=dizel_nmin;
        else realfill:=0; {sluczaj}
       end;
       if enrot>nreg then
        realfill:=realfill*(3.9-3.0*abs(enrot)/nreg);
       if enrot>dizel_nmax_cutoff then
       realfill:=realfill*(9.8-9.0*abs(enrot)/dizel_nmax_cutoff);
       if enrot<dizel_nmin then
        realfill:=realfill*(1+(dizel_nmin-abs(enrot))/dizel_nmin);
      end;
   end;
  if realfill<0 then
   realfill:=0;
  if realfill>1 then
   realfill:=1;
  dizel_fillcheck:=realfill;
end;

function T_MoverParameters.dizel_AutoGearCheck: boolean;
{automatycznie zmienia biegi gdy predkosc przekroczy widelki}
var OK: boolean;
begin
  OK:=false;
  if MotorParam[ScndCtrlActualPos].AutoSwitch and Mains then
   begin
     if (RList[MainCtrlPos].Mn=0) then
      begin
        if (dizel_engagestate>0) then
         dizel_EngageSwitch(0);
        if (MainCtrlPos=0) and (ScndCtrlActualPos>0) then
         dizel_automaticgearstatus:=-1
      end
     else
      begin
        if MotorParam[ScndCtrlActualPos].AutoSwitch and (dizel_automaticgearstatus=0) then {sprawdz czy zmienic biegi}
         begin
            if (Vel>MotorParam[ScndCtrlActualPos].mfi) and (ScndCtrlActualPos<ScndCtrlPosNo) then
             begin
              dizel_automaticgearstatus:=1;
              OK:=true
             end
            else
             if (Vel<MotorParam[ScndCtrlActualPos].fi) and (ScndCtrlActualPos>0) then
              begin
               dizel_automaticgearstatus:=-1;
               OK:=true
              end;
         end;
      end;
     if (dizel_engage<0.1) and (dizel_automaticgearstatus<>0) then
      begin
        if dizel_automaticgearstatus=1 then
         inc(ScndCtrlActualPos)
        else
         dec(ScndCtrlActualPos);
        dizel_automaticgearstatus:=0;
{}        dizel_EngageSwitch(1.0);   {}
        OK:=true;
      end
   end;
  if Mains then
   begin
        if (dizel_automaticgearstatus=0) then  {ustaw cisnienie w silowniku sprzegla}
        case RList[MainCtrlPos].Mn of
          1: dizel_EngageSwitch(0.5);
          2: dizel_EngageSwitch(1.0);
         else dizel_EngageSwitch(0.0)
         end
        else
         dizel_EngageSwitch(0.0);
        if not (MotorParam[ScndCtrlActualPos].mIsat>0) then
         dizel_EngageSwitch(0.0);  //wylacz sprzeglo na pozycjach neutralnych
        if not AutoRelayFlag then
         ScndCtrlActualPos:=ScndCtrlPos;
   end;
  dizel_AutoGearCheck:=OK;
end;

function T_MoverParameters.dizel_Update(dt:real): boolean;
{odświeża informacje o silniku}
//var OK:boolean;
const fillspeed=2;
begin
  //dizel_Update:=false;
  if dizel_enginestart and (LastSwitchingTime>=InitialCtrlDelay) then
    begin
      dizel_enginestart:=false;
      LastSwitchingTime:=0;
      enrot:=dizel_nmin/2.0; {TODO: dac zaleznie od temperatury i baterii}
    end;
  {OK:=}dizel_EngageChange(dt);
//  if AutoRelayFlag then Poprawka na SM03
  dizel_Update:=dizel_AutoGearCheck;
{  dizel_fill:=(dizel_fill+dizel_fillcheck(MainCtrlPos))/2; }
  dizel_fill:=dizel_fill+fillspeed*dt*(dizel_fillcheck(MainCtrlPos)-dizel_fill);
  //dizel_Update:=OK;
end;


{przyczepnosc}
function T_MoverParameters.Adhesive(staticfriction:real): real;
//var Adhesion: real;
begin
  {Adhesion:=0;
  case SlippingWheels of
   true:
      if SandDose then
       Adhesion:=0.48
      else
       Adhesion:=staticfriction*0.2;
   false:
      if SandDose then
       Adhesion:=Max0R(staticfriction*(100+Vel)/(50+Vel)*1.1,0.48)
      else
       Adhesion:=staticfriction*(100+Vel)/(50+Vel)
  end;
  Adhesion:=Adhesion*(11-2*random)/10;
  Adhesive:=Adhesion;}

  //ABu: male przerobki, tylko czy to da jakikolwiek skutek w FPS?
  //     w kazdym razie zaciemni kod na pewno :)
  if SlippingWheels=false then
     begin
        if SandDose then
           Adhesive:=(Max0R(staticfriction*(100.0+Vel)/((50.0+Vel)*11.0),0.048))*(11.0-2.0*random)
        else
           Adhesive:=(staticfriction*(100.0+Vel)/((50.0+Vel)*10))*(11.0-2.0*random);
     end
  else
     begin
        if SandDose then
           Adhesive:=(0.048)*(11-2*random)
        else
           Adhesive:=(staticfriction*0.02)*(11-2*random);
     end;
end;


{SILY}

function T_MoverParameters.TractionForce(dt:real):real;
const kv=0.2; ksum=0.05;
var PosRatio,dmoment,dtrans,tmp,tmpV: real;
    i: byte;
{oblicza sile trakcyjna lokomotywy (dla elektrowozu tez calkowity prad)}
begin
  Ft:=0;
  dtrans:=0;
  dmoment:=0;
//  tmpV:=Abs(nrot*WheelDiameter/2);
//youBy
  if (EngineType=DieselElectric) then
    begin
     tmp:=DEList[MainCtrlPos].rpm/60.0;
     if (Heating) and (HeatingPower>0) and (MainCtrlPosNo>MainCtrlPos) then
     begin
       i:=MainCtrlPosNo;
       while (DEList[i-2].rpm/60.0>tmp) do
         i:=i-1;
       tmp:=DEList[i].rpm/60.0
     end;
     if enrot<>tmp*Byte(ConverterFlag) then
       if ABS(tmp*Byte(ConverterFlag) - enrot) < 0.001 then
         enrot:=tmp*Byte(ConverterFlag)
       else
         if (enrot<DEList[0].rpm*0.01) and (ConverterFlag) then
           enrot:=enrot + (tmp*Byte(ConverterFlag) - enrot)*dt/5.0
         else
           enrot:=enrot + (tmp*Byte(ConverterFlag) - enrot)*1.5*dt;
    end
  else
  if EngineType<>DieselEngine then
   enrot:=Transmision.Ratio*nrot
  else //dla DieselEngine
   begin
     if (ShuntMode) then //dodatkowa przekładnia np. dla 2Ls150
      dtrans:=AnPos*Transmision.Ratio*MotorParam[ScndCtrlActualPos].mIsat
     else
      dtrans:=Transmision.Ratio*MotorParam[ScndCtrlActualPos].mIsat;
     dmoment:=dizel_Momentum(dizel_fill,ActiveDir*1*dtrans*nrot,dt); {oblicza tez enrot}
   end;
  eAngle:=eAngle+enrot*dt;
  if eAngle>Pirazy2 then                                                       
   //eAngle:=Pirazy2-eAngle; <- ABu: a nie czasem tak, jak nizej?
   eAngle:=eAngle-Pirazy2;

  //hunter-091012: przeniesione z if ActiveDir<>0 (zeby po zejsciu z kierunku dalej spadala predkosc wentylatorow)
  if (EngineType=ElectricSeriesMotor) then
   begin
        case RVentType of {wentylatory rozruchowe}
        1: if (ActiveDir<>0) and (RList[MainCtrlActualPos].R>RVentCutOff) then
            RventRot:=RventRot+(RVentnmax-RventRot)*RVentSpeed*dt
           else
            RventRot:=RventRot*(1-RVentSpeed*dt);
        2: if (Abs(Itot)>RVentMinI) and (RList[MainCtrlActualPos].R>RVentCutOff) then
            RventRot:=RventRot+(RVentnmax*Abs(Itot)/(ImaxLo*RList[MainCtrlActualPos].Bn)-RventRot)*RVentSpeed*dt
           else
           if (DynamicBrakeType=dbrake_automatic) and (DynamicBrakeFlag) then
            RventRot:=RventRot+(RVentnmax*Im/ImaxLo-RventRot)*RVentSpeed*dt           
           else
            begin
              RventRot:=RventRot*(1-RVentSpeed*dt);
              if RventRot<0.1 then RventRot:=0;
            end;
        end; {case}
   end; {if}

  if ActiveDir<>0 then
   case EngineType of
    Dumb:
     begin
       PosRatio:=(MainCtrlPos+ScndCtrlPos)/(MainCtrlPosNo+ScndCtrlPosNo+0.01);
       if Mains and (ActiveDir<>0) and (CabNo<>0) then
        begin
          if Vel>0.1 then
           begin
             Ft:=Min0R(1000.0*Power/Abs(V),Ftmax)*PosRatio;
           end
          else Ft:=Ftmax*PosRatio;
          Ft:=Ft*DirAbsolute; //ActiveDir*CabNo;
        end
       else Ft:=0;
       EnginePower:=1000*Power*PosRatio;
     end;
    WheelsDriven:
      begin
        if EnginePowerSource.SourceType=InternalSource then
         if EnginePowerSource.PowerType=BioPower then
          Ft:=sign(sin(eAngle))*PulseForce*Transmision.Ratio;
        PulseForceTimer:=PulseForceTimer+dt;
        if PulseForceTimer>CtrlDelay then
         begin
           PulseForce:=0;
           if PulseForceCount>0 then
            dec(PulseForceCount);
         end;
        EnginePower:=Ft*(1+Vel);
      end;
    ElectricSeriesMotor:
      begin
{        enrot:=Transmision.Ratio*nrot; }
        //yB: szereg dwoch sekcji w ET42
        if(TrainType=dt_ET42)and(Imax=ImaxHi)then
          Voltage:=Voltage/2.0;
        Mm:=Momentum(Current(enrot,Voltage)); {oblicza tez prad p/slinik}
        if(TrainType=dt_ET42)then
         begin
           if(Imax=ImaxHi)then
             Voltage:=Voltage*2;
           if(DynamicBrakeFlag)and(Abs(Im)>300)then
             FuseOff;
         end;
        if (DynamicBrakeType=dbrake_automatic)and(DynamicBrakeFlag) then
         begin
          if ((Vadd+Abs(Im))>760)or((Hamulec as TLSt).GetEDBCP<0.25) then
           begin
            Vadd:=Vadd-500*dt;
            if(Vadd<1)then
             Vadd:=0;
           end
          else if (DynamicBrakeFlag)and((Vadd+Abs(Im))<740) then
           begin
            Vadd:=Vadd+70*dt;
            Vadd:=Min0R(Max0R(Vadd,60),400);
           end;
          if(Vadd>0)then Mm:=MomentumF(Im,Vadd,0);
         end; 

        if(TrainType=dt_ET22)and(DelayCtrlFlag)then //szarpanie przy zmianie układu w byku
          Mm:=Mm*RList[MainCtrlActualPos].Bn/(RList[MainCtrlActualPos].Bn+1); //zrobione w momencie, żeby nie dawac elektryki w przeliczaniu sił

        if (Abs(Im)>Imax) then
         Vhyp:=Vhyp+dt//*(Abs(Im)/Imax-0.9)*10 //zwieksz czas oddzialywania na PN
        else
         Vhyp:=0;
        if (Vhyp>CtrlDelay/2) then  //jesli czas oddzialywania przekroczony
//         dec(MainCtrlActualPos);
         FuseOff;                     {wywalanie bezpiecznika z powodu przetezenia silnikow}
        if (Mains) then //nie wchodzić w funkcję bez potrzeby
         if (Abs(Voltage)<EnginePowerSource.CollectorParameters.MinV) or (Abs(Voltage)*EnginePowerSource.CollectorParameters.OVP>EnginePowerSource.CollectorParameters.MaxV) then
          if MainSwitch(false) then
           EventFlag:=true; //wywalanie szybkiego z powodu niewłaściwego napięcia

        if (((DynamicBrakeType=dbrake_automatic)or(DynamicBrakeType=dbrake_switch)) and (DynamicBrakeFlag)) then
         Itot:=Im*2   {2x2 silniki w EP09}
        else if (TrainType=dt_EZT)and(Imin=IminLo)and(ScndS) then //yBARC - boczniki na szeregu poprawnie
         Itot:=Im
        else
         Itot:=Im*RList[MainCtrlActualPos].Bn;   {prad silnika * ilosc galezi}
        Mw:=Mm*Transmision.Ratio;
        Fw:=Mw*2.0/WheelDiameter;
        Ft:=Fw*NPoweredAxles;                {sila trakcyjna}
      end;
   DieselEngine: begin
                   EnginePower:=dmoment*enrot;
                   if MainCtrlPos>1 then
                    dmoment:=dmoment-dizel_Mstand*(0.2*enrot/nmax);  {dodatkowe opory z powodu sprezarki}
                   Mm:=dizel_engage*dmoment;
                   Mw:=Mm*dtrans;           {dmoment i dtrans policzone przy okazji enginerotation}
                   Fw:=Mw*2.0/WheelDiameter;
                   Ft:=Fw*NPoweredAxles;                {sila trakcyjna}
                   Ft:=Ft*DirAbsolute; //ActiveDir*CabNo;

                 end;
   DieselElectric:    //youBy
     begin
//       tmpV:=V*CabNo*ActiveDir;
         tmpV:=nrot*Pirazy2*0.5*WheelDiameter*DirAbsolute; //*CabNo*ActiveDir;
       //jazda manewrowa
       if (ShuntMode) then
        begin
         Voltage:=(SST[MainCtrlPos].Umax * AnPos) + (SST[MainCtrlPos].Umin * (1 - AnPos));
         tmp:=(SST[MainCtrlPos].Pmax * AnPos) + (SST[MainCtrlPos].Pmin * (1 - AnPos));
         Ft:=tmp * 1000.0 / (abs(tmpV)+1.6);
         PosRatio:=1;
        end
       else  //jazda ciapongowa
      begin

       tmp:=Min0R(DEList[MainCtrlPos].genpower,Power-HeatingPower*byte(Heating));

        PosRatio:=DEList[MainCtrlPos].genpower / DEList[MainCtrlPosNo].genpower;  {stosunek mocy teraz do mocy max}
        if (MainCtrlPos>0) and (ConverterFlag) then
          if tmpV < (Vhyp*(Power-HeatingPower*byte(Heating))/DEList[MainCtrlPosNo].genpower) then //czy na czesci prostej, czy na hiperboli
            Ft:=(Ftmax - ((Ftmax - 1000.0 * DEList[MainCtrlPosNo].genpower / (Vhyp+Vadd)) * (tmpV/Vhyp) / PowerCorRatio)) * PosRatio //posratio - bo sila jakos tam sie rozklada
            //Ft:=(Ftmax - (Ftmax - (1000.0 * DEList[MainCtrlPosNo].genpower / (Vhyp+Vadd) / PowerCorRatio)) * (tmpV/Vhyp)) * PosRatio //wersja z Megapacka
          else //na hiperboli                             //1.107 - wspolczynnik sredniej nadwyzki Ft w symku nad charakterystyka
            Ft:=1000.0 * tmp / (tmpV+Vadd) / PowerCorRatio //tu jest zawarty stosunek mocy
        else Ft:=0; //jak nastawnik na zero, to sila tez zero

      PosRatio:=tmp/DEList[MainCtrlPosNo].genpower;

      end;
        if (FuseFlag) then Ft:=0 else
        Ft:=Ft*DirAbsolute; //ActiveDir * CabNo; //zwrot sily i jej wartosc
        Fw:=Ft/NPoweredAxles; //sila na obwodzie kola
        Mw:=Fw*WheelDiameter / 2.0; // moment na osi kola
        Mm:=Mw/Transmision.Ratio; // moment silnika trakcyjnego


       with MotorParam[ScndCtrlPos] do
         if ABS(Mm) > fi then
           Im:=NPoweredAxles * ABS(ABS(Mm) / mfi + mIsat)
         else
           Im:=NPoweredAxles * sqrt(ABS(Mm * Isat));

       if (ShuntMode) then
       begin
         EnginePower:=Voltage * Im/1000.0;
         if (EnginePower > tmp) then
         begin
           EnginePower:=tmp*1000.0;
           Voltage:=EnginePower/Im;
         end;
         if (EnginePower < tmp) then
         Ft:=Ft * EnginePower / tmp;
       end
       else
       begin
        if (ABS(Im) > DEList[MainCtrlPos].Imax) then
        begin //nie ma nadmiarowego, tylko Imax i zwarcie na pradnicy
          Ft:=Ft/Im*DEList[MainCtrlPos].Imax;Im:=DEList[MainCtrlPos].Imax;
        end;

        if (Im > 0) then //jak pod obciazeniem
          if (Flat) then //ograniczenie napiecia w pradnicy - plaszczak u gory
            Voltage:=1000.0 * tmp / ABS(Im)
          else  //charakterystyka pradnicy obcowzbudnej (elipsa) - twierdzenie Pitagorasa
          begin
            Voltage:=sqrt(ABS(sqr(DEList[MainCtrlPos].Umax)-sqr(DEList[MainCtrlPos].Umax*Im/DEList[MainCtrlPos].Imax)))*(MainCtrlPos-1)+
                     (1-Im/DEList[MainCtrlPos].Imax)*DEList[MainCtrlPos].Umax*(MainCtrlPosNo-MainCtrlPos);
            Voltage:=Voltage/(MainCtrlPosNo-1);
            Voltage:=Min0R(Voltage,(1000.0 * tmp / ABS(Im)));
            if Voltage<(Im*0.05) then Voltage:=Im*0.05;
          end;
        if (Voltage > DEList[MainCtrlPos].Umax) or (Im = 0) then //gdy wychodzi za duze napiecie
          Voltage:=DEList[MainCtrlPos].Umax * byte(ConverterFlag);     //albo przy biegu jalowym (jest cos takiego?)

        EnginePower:=Voltage * Im / 1000.0;

        if (tmpV>2) and (EnginePower<tmp) then
          Ft:=Ft*EnginePower/tmp;

       end;

         if (Imax>1) and (Im>Imax) then FuseOff;
         if FuseFlag then Voltage:=0;

     //przekazniki bocznikowania, kazdy inny dla kazdej pozycji
         if (MainCtrlPos = 0) or (ShuntMode) then
           ScndCtrlPos:=0
         else if AutoRelayFlag then
          case RelayType of
          0: begin
              if (Im <= (MPTRelay[ScndCtrlPos].Iup*PosRatio)) and (ScndCtrlPos<ScndCtrlPosNo) then
                inc(ScndCtrlPos);
              if (Im >= (MPTRelay[ScndCtrlPos].Idown*PosRatio)) and (ScndCtrlPos>0) then
                dec(ScndCtrlPos);
             end;
          1: begin
              if (MPTRelay[ScndCtrlPos].Iup<Vel) and (ScndCtrlPos<ScndCtrlPosNo) then
                inc(ScndCtrlPos);
              if (MPTRelay[ScndCtrlPos].Idown>Vel) and (ScndCtrlPos>0) then
                dec(ScndCtrlPos);
             end;
          2: begin
              if (MPTRelay[ScndCtrlPos].Iup<Vel) and (ScndCtrlPos<ScndCtrlPosNo) and (EnginePower<(tmp*0.99)) then
                inc(ScndCtrlPos);
              if (MPTRelay[ScndCtrlPos].Idown<Im) and (ScndCtrlPos>0) then
                dec(ScndCtrlPos);
             end;
          41:
            begin
              if (MainCtrlPos=MainCtrlPosNo) and (tmpV*3.6>MPTRelay[ScndCtrlPos].Iup) and (ScndCtrlPos<ScndCtrlPosNo)then
                begin inc(ScndCtrlPos); enrot:=enrot*0.73; end;
              if (Im>MPTRelay[ScndCtrlPos].Idown)and (ScndCtrlPos>0) then
                dec(ScndCtrlPos);
            end;
          45:
             begin
              //wzrastanie
              if (MainCtrlPos>11) and (ScndCtrlPos<ScndCtrlPosNo) then
               if (ScndCtrlPos=0) then
                if (MPTRelay[ScndCtrlPos].Iup>Im) then
                 inc(ScndCtrlPos)
                else
               else
                if (MPTRelay[ScndCtrlPos].Iup<Vel) then
                 inc(ScndCtrlPos);

              //malenie
              if(ScndCtrlPos>0)and(MainCtrlPos<12)then
              if (ScndCtrlPos=ScndCtrlPosNo)then
                if (MPTRelay[ScndCtrlPos].Idown<Im)then
                 dec(ScndCtrlPos)
                else
               else
                if (MPTRelay[ScndCtrlPos].Idown>Vel)then
                 dec(ScndCtrlPos);
              if (MainCtrlPos<11)and(ScndCtrlPos>2) then ScndCtrlPos:=2;
              if (MainCtrlPos<9)and(ScndCtrlPos>0) then ScndCtrlPos:=0;
             end;
          46:
             begin
              //wzrastanie
              if (MainCtrlPos>9) and (ScndCtrlPos<ScndCtrlPosNo) then
               if (ScndCtrlPos) mod 2 = 0 then
                if (MPTRelay[ScndCtrlPos].Iup>Im) then
                 inc(ScndCtrlPos)
                else
               else
                if (MPTRelay[ScndCtrlPos-1].Iup>Im) and (MPTRelay[ScndCtrlPos].Iup<Vel) then
                 inc(ScndCtrlPos);

              //malenie
              if (MainCtrlPos<10) and (ScndCtrlPos>0)then
               if (ScndCtrlPos) mod 2 = 0 then
                if (MPTRelay[ScndCtrlPos].Idown<Im)then
                 dec(ScndCtrlPos)
                else
               else
                if (MPTRelay[ScndCtrlPos+1].Idown<Im) and (MPTRelay[ScndCtrlPos].Idown>Vel)then
                 dec(ScndCtrlPos);
              if (MainCtrlPos<9)and(ScndCtrlPos>2) then ScndCtrlPos:=2;
              if (MainCtrlPos<6)and(ScndCtrlPos>0) then ScndCtrlPos:=0;
             end;
        end;
     end;
   ElectricInductionMotor:
     begin
      if (Mains) then //nie wchodzić w funkcję bez potrzeby
        if (Abs(Voltage)<EnginePowerSource.CollectorParameters.MinV) or (Abs(Voltage)>EnginePowerSource.CollectorParameters.MaxV+200) then
         begin
          MainSwitch(false);
         end; 
        tmpV:=abs(nrot)*(Pi*WheelDiameter)*3.6;//*DirAbsolute*eimc[eimc_s_p]; - do przemyslenia dzialanie pp
       if (MainS) then
        begin

         dtrans:=(Hamulec as TLSt).GetEDBCP;
         if ((DoorLeftOpened)or(DoorRightOpened)) then
           DynamicBrakeFlag:=true
         else if ((dtrans<0.25) and (LocHandle.GetCP<0.25) and (AnPos<0.01)) or ((dtrans<0.25) and (ShuntModeAllow) and (LocalBrakePos=0)) then
           DynamicBrakeFlag:=false
         else if (((BrakePress>0.25) and (dtrans>0.25) or (LocHandle.GetCP>0.25))) or (AnPos>0.02) then
           DynamicBrakeFlag:=true;
         dtrans:=(Hamulec as TLSt).GetEDBCP*eimc[eimc_p_abed]; //stala napedu
         if(DynamicBrakeFlag)then
          begin
           if eimv[eimv_Fmax]*sign(V)*DirAbsolute<-1 then
            begin
             PosRatio:=-sign(V)*DirAbsolute*eimv[eimv_Fr]/(eimc[eimc_p_Fh]*Max0R(dtrans/MaxBrakePress[0],AnPos){dizel_fill});
            end
           else
             PosRatio:=0;
           PosRatio:=round(20*Posratio)/20;
           if PosRatio<19.5/20 then PosRatio:=PosRatio*0.9;
//           if PosRatio<0 then
//             PosRatio:=2+PosRatio-2;
           (Hamulec as TLSt).SetED(Max0R(0.0,Min0R(PosRatio,1)));
//           (Hamulec as TLSt).SetLBP(LocBrakePress*(1-PosRatio));
           PosRatio:=-Max0R(Min0R(dtrans/MaxBrakePress[0],1),AnPos)*Max0R(0,Min0R(1,(Vel-eimc[eimc_p_Vh0])/(eimc[eimc_p_Vh1]-eimc[eimc_p_Vh0])));
           eimv[eimv_Fzad]:=-Max0R(LocalBrakeRatio,dtrans/MaxBrakePress[0]);
           tmp:=5;
          end
         else
          begin
           PosRatio:=(MainCtrlPos/MainCtrlPosNo);
           eimv[eimv_Fzad]:=PosRatio;
           if(Flat)and(eimc[eimc_p_F0]*eimv[eimv_Fful]>0)then
             PosRatio:=Min0R(PosRatio*eimc[eimc_p_F0]/eimv[eimv_Fful],1);
           if ScndCtrlActualPos>0 then
            if (Vmax<250) then
             PosRatio:=Min0R(PosRatio,Max0R(-1,0.5*(ScndCtrlActualPos-Vel)))
            else
             PosRatio:=Min0R(PosRatio,Max0R(-1,0.5*(ScndCtrlActualPos*2-Vel)));
           PosRatio:=1.0*(PosRatio*0+1)*PosRatio;
           (Hamulec as TLSt).SetED(0);
//           (Hamulec as TLSt).SetLBP(LocBrakePress);
           if (PosRatio>dizel_fill) then tmp:=1 else tmp:=4; //szybkie malenie, powolne wzrastanie
          end;
//         if SlippingWheels then begin PosRatio:=0; tmp:=10; SandDoseOn; end;//przeciwposlizg

//         if(Flat)then //PRZECIWPOŚLIZG
         dmoment:=eimv[eimv_Fful];
//         else
//           dmoment:=eimc[eimc_p_F0]*0.99;
         if (abs((PosRatio+9.66*dizel_fill)*dmoment*100)>0.95*Adhesive(RunningTrack.friction)*TotalMassxg) then begin PosRatio:=0; tmp:=4; SandDoseOn; end;//przeciwposlizg
         if (abs((PosRatio+9.80*dizel_fill)*dmoment*100)>0.95*Adhesive(RunningTrack.friction)*TotalMassxg) then begin PosRatio:=0; tmp:=9; SandDoseOn; end;//przeciwposlizg
         if (SlippingWheels) then begin PosRatio:=-PosRatio*0; tmp:=9; SandDoseOn; end;//przeciwposlizg

         dizel_fill:=dizel_fill+Max0R(Min0R(PosRatio-dizel_fill,0.1),-0.1)*2*(tmp{2{+4*byte(PosRatio<dizel_fill)})*dt; //wartość zadana/procent czegoś

         if(DynamicBrakeFlag)then tmp:=eimc[eimc_f_Uzh] else tmp:=eimc[eimc_f_Uzmax];

         eimv[eimv_Uzsmax]:=Min0R(Voltage-eimc[eimc_f_DU],tmp);
         eimv[eimv_fkr]:=eimv[eimv_Uzsmax]/eimc[eimc_f_cfu];
         if(dizel_fill<0)then
           eimv[eimv_Pmax]:=eimc[eimc_p_Ph]
         else
           eimv[eimv_Pmax]:=Min0R(eimc[eimc_p_Pmax],0.001*Voltage*(eimc[eimc_p_Imax]-eimc[eimc_f_I0])*Pirazy2*eimc[eimc_s_cim]/eimc[eimc_s_p]/eimc[eimc_s_cfu]);
         eimv[eimv_FMAXMAX]:=0.001*SQR(Min0R(eimv[eimv_fkr]/Max0R(abs(enrot)*eimc[eimc_s_p]+eimc[eimc_s_dfmax]*eimv[eimv_ks],eimc[eimc_s_dfmax]),1)*eimc[eimc_f_cfu]/eimc[eimc_s_cfu])*(eimc[eimc_s_dfmax]*eimc[eimc_s_dfic]*eimc[eimc_s_cim])*Transmision.Ratio*NPoweredAxles*2/WheelDiameter;
         if(dizel_fill<0)then
          begin
           eimv[eimv_Fful]:=Min0R(eimc[eimc_p_Ph]*3.6/Vel,Min0R(eimc[eimc_p_Fh],eimv[eimv_FMAXMAX]));
           eimv[eimv_Fmax]:=-sign(V)*(DirAbsolute)*Min0R(eimc[eimc_p_Ph]*3.6/Vel,Min0R(-eimc[eimc_p_Fh]*dizel_fill,eimv[eimv_FMAXMAX]));//*Min0R(1,(Vel-eimc[eimc_p_Vh0])/(eimc[eimc_p_Vh1]-eimc[eimc_p_Vh0]))
          end
         else
          begin
           eimv[eimv_Fful]:=Min0R(Min0R(3.6*eimv[eimv_Pmax]/Max0R(Vel,1),eimc[eimc_p_F0]-Vel*eimc[eimc_p_a1]),eimv[eimv_FMAXMAX]);
//           if(not Flat)then
             eimv[eimv_Fmax]:=eimv[eimv_Fful]*dizel_fill
//           else
//             eimv[eimv_Fmax]:=Min0R(eimc[eimc_p_F0]*dizel_fill,eimv[eimv_Fful]);
          end;


         eimv[eimv_ks]:=eimv[eimv_Fmax]/eimv[eimv_FMAXMAX];
         eimv[eimv_df]:=eimv[eimv_ks]*eimc[eimc_s_dfmax];
         eimv[eimv_fp]:=DirAbsolute*enrot*eimc[eimc_s_p]+eimv[eimv_df]; //do przemyslenia dzialanie pp z tmpV
//         eimv[eimv_U]:=Max0R(eimv[eimv_Uzsmax],Min0R(eimc[eimc_f_cfu]*eimv[eimv_fp],eimv[eimv_Uzsmax]));
//         eimv[eimv_pole]:=eimv[eimv_U]/(eimv[eimv_fp]*eimc[eimc_s_cfu]);
         if(abs(eimv[eimv_fp])<=eimv[eimv_fkr])then
           eimv[eimv_pole]:=eimc[eimc_f_cfu]/eimc[eimc_s_cfu]
         else
           eimv[eimv_pole]:=eimv[eimv_Uzsmax]/eimc[eimc_s_cfu]/abs(eimv[eimv_fp]);
         eimv[eimv_U]:=eimv[eimv_pole]*eimv[eimv_fp]*eimc[eimc_s_cfu];
         eimv[eimv_Ic]:=(eimv[eimv_fp]-DirAbsolute*enrot*eimc[eimc_s_p])*eimc[eimc_s_dfic]*eimv[eimv_pole];
         eimv[eimv_If]:=eimv[eimv_Ic]*eimc[eimc_s_icif];
         eimv[eimv_M]:=eimv[eimv_pole]*eimv[eimv_Ic]*eimc[eimc_s_cim];
         eimv[eimv_Ipoj]:=(eimv[eimv_Ic]*NPoweredAxles*eimv[eimv_U])/(Voltage-eimc[eimc_f_DU])+eimc[eimc_f_I0];
         eimv[eimv_Pm]:=ActiveDir*eimv[eimv_M]*NPoweredAxles*enrot*Pirazy2/1000;
         eimv[eimv_Pe]:=eimv[eimv_Ipoj]*Voltage/1000;
         eimv[eimv_eta]:=eimv[eimv_Pm]/eimv[eimv_Pe];

         Im:=eimv[eimv_If];
         if (eimv[eimv_Ipoj]>=0) then
           Vadd:=Vadd*(1-2*dt)
         else if (Voltage<EnginePowerSource.CollectorParameters.MaxV) then
           Vadd:=Vadd*(1-dt)
         else
           Vadd:=Max0R(Vadd*(1-0.2*dt),0.007*(Voltage-(EnginePowerSource.CollectorParameters.MaxV-100)));
         Itot:=eimv[eimv_Ipoj]*(0.01+Min0R(0.99,0.99-Vadd));


         EnginePower:=Abs(eimv[eimv_Ic]*eimv[eimv_U]*NPoweredAxles)/1000;
         tmpV:=eimv[eimv_fp];
         if ((abs(eimv[eimv_If])>1) or (abs(tmpV)>0.1))and(RlistSize>0) then
          begin
           i:=0;
           while (i<RlistSize-1)and(DEList[i+1].RPM<abs(tmpV))do inc(i);
           RventRot:=(abs(tmpV)-DEList[i].RPM)/(DEList[i+1].RPM-DEList[i].RPM)*(DEList[i+1].GenPower-DEList[i].GenPower)+DEList[i].GenPower;
          end
         else RVentRot:=0;

         Mm:=eimv[eimv_M]*DirAbsolute;
         Mw:=Mm*Transmision.Ratio;
         Fw:=Mw*2.0/WheelDiameter;
         Ft:=Fw*NPoweredAxles;
         eimv[eimv_Fr]:=DirAbsolute*Ft/1000;
//       RventRot;
        end
       else
        begin
         Im:=0;Mm:=0;Mw:=0;Fw:=0;Ft:=0;Itot:=0;dizel_fill:=0;EnginePower:=0;
         for i:=1 to 20 do
            eimv[i]:=0;
         (Hamulec as TLSt).SetED(0);RventRot:=0.0;//(Hamulec as TLSt).SetLBP(LocBrakePress);
        end;
     end;
   None: begin end;
   end {case EngineType}
  else if EngineType=ElectricInductionMotor then
   begin
    Im:=0;Mm:=0;Mw:=0;Fw:=0;Ft:=0;Itot:=0;dizel_fill:=0;EnginePower:=0;
    for i:=1 to 20 do
       eimv[i]:=0;
    (Hamulec as TLSt).SetED(0);RventRot:=0.0;//(Hamulec as TLSt).SetLBP(LocBrakePress);
   end;
  TractionForce:=Ft
end;

function T_MoverParameters.BrakeForce(Track:TTrackParam):real;
var K,Fb,NBrakeAxles,sm:real;
//const OerlikonForceFactor=1.5;
begin
  K:=0;
  if NPoweredAxles>0 then
   NBrakeAxles:=NPoweredAxles
  else
   NBrakeAxles:=NAxles;
  case LocalBrake of
   NoBrake :      K:=0;
   ManualBrake :  K:=MaxBrakeForce*ManualBrakeRatio;
   HydraulicBrake : K:=MaxBrakeForce*LocalBrakeRatio;
   PneumaticBrake:if Compressor<MaxBrakePress[3] then
                   K:=MaxBrakeForce*LocalBrakeRatio/2.0
                  else
                   K:=0;
  end;
  if MBrake=true then
  begin
   K:=MaxBrakeForce*ManualBrakeRatio;
   end;

                 //0.03

  u:=((BrakePress*P2FTrans)-BrakeCylSpring)*BrakeCylMult[0]-BrakeSlckAdj;
  if (u*BrakeRigEff>Ntotal)then //histereza na nacisku klockow
    Ntotal:=u*BrakeRigEff
  else
   begin
    u:=(BrakePress*P2FTrans)*BrakeCylMult[0]-BrakeSlckAdj;   
    if (u*(2-1*BrakeRigEff)<Ntotal)then //histereza na nacisku klockow
     Ntotal:=u*(2-1*BrakeRigEff);
   end;
   
  if (NBrakeAxles*NBpA>0) then
    begin
      if Ntotal>0 then         {nie luz}
        K:=K+Ntotal;                     {w kN}
      K:=K*BrakeCylNo/(NBrakeAxles*NBpA);            {w kN na os}
    end;
  if (BrakeSystem=Pneumatic)or(BrakeSystem=ElectroPneumatic) then
  begin
    u:=Hamulec.GetFC(Vel, K);
  UnitBrakeForce:=u*K*1000;                     {sila na jeden klocek w N}
   end
  else
    UnitBrakeForce:=K*1000;
  if (NBpA*UnitBrakeForce>TotalMassxg*Adhesive(RunningTrack.friction)/NAxles) and (Abs(V)>0.001) then
   {poslizg}
   begin
{     Fb:=Adhesive(Track.friction)*Mass*g;  }
     SlippingWheels:=true;
   end;
{  else
   begin
{     SlippingWheels:=false;}
//     if (LocalBrake=ManualBrake)or(MBrake=true)) and (BrakePress<0.3) then
//      Fb:=UnitBrakeForce*NBpA {ham. reczny dziala na jedna os}
//     else  //yB: to nie do konca ma sens, ponieważ ręczny w wagonie działa na jeden cylinder hamulcowy/wózek, dlatego potrzebne są oddzielnie liczone osie
      Fb:=UnitBrakeForce*NBrakeAxles*Max0R(1,NBpA);

//  u:=((BrakePress*P2FTrans)-BrakeCylSpring*BrakeCylMult[BCMFlag]/BrakeCylNo-0.83*BrakeSlckAdj/(BrakeCylNo))*BrakeCylNo;
 {  end; }
  BrakeForce:=Fb;
end;

function T_MoverParameters.CouplerForce(CouplerN:byte;dt:real):real;
//wyliczenie siły na sprzęgu
var tempdist,newdist,distDelta,CF,dV,absdv,Fmax,BetaAvg:real; CNext:byte;
const MaxDist=405.0; {ustawione + 5 m, bo skanujemy do 400 m }
      MinDist=0.5;   {ustawione +.5 m, zeby nie rozlaczac przy malych odleglosciach}
      MaxCount=1500;
begin
  CF:=0;
  //distDelta:=0; //Ra: value never used
  CNext:=Couplers[CouplerN].ConnectedNr;
{  if Couplers[CouplerN].CForce=0 then  {nie bylo uzgadniane wiec policz}
   with Couplers[CouplerN] do
    begin
      CheckCollision:=false;
      newdist:=CoupleDist; //odległość od sprzęgu sąsiada
      //newdist:=Distance(Loc,Connected^.Loc,Dim,Connected^.Dim);
      if (CouplerN=0) then
         begin
            //ABu: bylo newdist+10*((...
            tempdist:=((Connected.dMoveLen*DirPatch(0,ConnectedNr))-dMoveLen);
            newdist:=newdist+10.0*tempdist;
            //tempdist:=tempdist+CoupleDist; //ABu: proby szybkiego naprawienia bledu
         end
      else
         begin
            //ABu: bylo newdist+10*((...
            tempdist:=((dMoveLen-(Connected.dMoveLen*DirPatch(1,ConnectedNr))));
            newdist:=newdist+10.0*tempdist;
            //tempdist:=tempdist+CoupleDist; //ABu: proby szybkiego naprawienia bledu
         end;

      //blablabla
      //ABu: proby znalezienia problemu ze zle odbijajacymi sie skladami
      //***if (Couplers[CouplerN].CouplingFlag=ctrain_virtual) and (newdist>0) then
      if (Couplers[CouplerN].CouplingFlag=ctrain_virtual) and (CoupleDist>0) then
       begin
         CF:=0;              {kontrola zderzania sie - OK}
         inc(ScanCounter);
         if (newdist>MaxDist) or ((ScanCounter>MaxCount)and(newdist>MinDist)) then
         //***if (tempdist>MaxDist) or ((ScanCounter>MaxCount)and(tempdist>MinDist)) then
          begin {zerwij kontrolnie wirtualny sprzeg}
            //Connected.Couplers[CNext].Connected:=nil; //Ra: ten podłączony niekoniecznie jest wirtualny
            Connected:=nil;
            ScanCounter:=Random(500);
          end;
       end
      else
       begin
         if CouplingFlag=ctrain_virtual then
          begin
            BetaAvg:=beta;
            Fmax:=(FmaxC+FmaxB)*CouplerTune;
          end
         else            {usrednij bo wspolny sprzeg}
          begin
            BetaAvg:=(beta+Connected.Couplers[CNext].beta)/2.0;
            Fmax:=(FmaxC+FmaxB+Connected.Couplers[CNext].FmaxC+Connected.Couplers[CNext].FmaxB)*CouplerTune/2.0;
          end;
         dV:=V-DirPatch(CouplerN,CNext)*Connected.V;
         absdv:=abs(dV);
         if (newdist<-0.001) and (Dist>=-0.001) and (absdv>0.010) then {090503: dzwieki pracy zderzakow}
          begin
            if SetFlag(SoundFlag,sound_bufferclamp) then
             if absdV>0.5 then
              SetFlag(SoundFlag,sound_loud);
          end
         else
         if (newdist>0.002) and (Dist<=0.002) and (absdv>0.005) then {090503: dzwieki pracy sprzegu}
          begin
            if CouplingFlag>0 then
             if SetFlag(SoundFlag,sound_couplerstretch) then
              if absdV>0.1 then
              SetFlag(SoundFlag,sound_loud);
          end;
         distDelta:=abs(newdist)-abs(Dist);  //McZapkie-191103: poprawka na histereze
         Dist:=newdist;
         if Dist>0 then
          begin
            if distDelta>0 then
              CF:=(-(SpringKC+Connected.Couplers[CNext].SpringKC)*Dist/2.0)*DirF(CouplerN)-Fmax*dV*betaAvg
             else
              CF:=(-(SpringKC+Connected.Couplers[CNext].SpringKC)*Dist/2.0)*DirF(CouplerN)*betaAvg-Fmax*dV*betaAvg;
                {liczenie sily ze sprezystosci sprzegu}
            if Dist>(DmaxC+Connected.Couplers[CNext].DmaxC) then {zderzenie}
            //***if tempdist>(DmaxC+Connected^.Couplers[CNext].DmaxC) then {zderzenie}
             CheckCollision:=true;
          end;
         if Dist<0 then
          begin
            if distDelta>0 then
              CF:=(-(SpringKB+Connected.Couplers[CNext].SpringKB)*Dist/2.0)*DirF(CouplerN)-Fmax*dV*betaAvg
            else
              CF:=(-(SpringKB+Connected.Couplers[CNext].SpringKB)*Dist/2.0)*DirF(CouplerN)*betaAvg-Fmax*dV*betaAvg;
                {liczenie sily ze sprezystosci zderzaka}
           if -Dist>(DmaxB+Connected.Couplers[CNext].DmaxB) then  {zderzenie}
            //***if -tempdist>(DmaxB+Connected^.Couplers[CNext].DmaxB)/10 then  {zderzenie}
             begin
               CheckCollision:=true;
               if (CouplerType=Automatic) and (CouplingFlag=0) then  {sprzeganie wagonow z samoczynnymi sprzegami}
                //CouplingFlag:=ctrain_coupler+ctrain_pneumatic+ctrain_controll+ctrain_passenger+ctrain_scndpneumatic;
                CouplingFlag:=ctrain_coupler+ctrain_pneumatic+ctrain_controll; //EN57
             end;
          end;
       end;
      if (CouplingFlag<>ctrain_virtual)
      then         {uzgadnianie prawa Newtona}
       Connected.Couplers[1-CouplerN].CForce:=-CF;
    end;
  CouplerForce:=CF;
end;

procedure T_MoverParameters.CollisionDetect(CouplerN:byte; dt:real);
var CCF,Vprev,VprevC:real; VirtualCoupling:boolean;
begin
     CCF:=0;
     with Couplers[CouplerN] do
      if (Connected<>nil) then
      begin
        VirtualCoupling:=(CouplingFlag=ctrain_virtual);
        Vprev:=V;
        VprevC:=Connected.V;
        case CouplerN of
         0 : CCF:=ComputeCollision(V,Connected.V,TotalMass,Connected.TotalMass,(beta+Connected.Couplers[ConnectedNr].beta)/2.0,VirtualCoupling)/(dt{+0.01}); //yB: ej ej ej, a po
         1 : CCF:=ComputeCollision(Connected.V,V,Connected.TotalMass,TotalMass,(beta+Connected.Couplers[ConnectedNr].beta)/2.0,VirtualCoupling)/(dt{+0.01}); //czemu tu jest +0.01??
        end;
        AccS:=AccS+(V-Vprev)/dt; //korekta przyspieszenia o siły wynikające ze zderzeń?
        Connected.AccS:=Connected.AccS+(Connected.V-VprevC)/dt;
        if (Dist>0) and (not VirtualCoupling) then
         if FuzzyLogic(Abs(CCF),5*(FmaxC+1),p_coupldmg) then
          begin                            {! zerwanie sprzegu}
            if SetFlag(DamageFlag,dtrain_coupling) then
             EventFlag:=true;
            if (Couplers[CouplerN].CouplingFlag and ctrain_pneumatic>0) then
             EmergencyBrakeFlag:=true;   {hamowanie nagle - zerwanie przewodow hamulcowych}
            CouplingFlag:=0;
            case CouplerN of             {wyzerowanie flag podlaczenia ale ciagle sa wirtualnie polaczone}
             0 : Connected.Couplers[1].CouplingFlag:=0;
             1 : Connected.Couplers[0].CouplingFlag:=0;
            end
          end ;
      end;
end;

procedure T_MoverParameters.ComputeConstans;
var BearingF,RollF,HideModifier: real;
 Curvature: real; //Ra 2014-07: odwrotność promienia
begin
 TotalCurrent:=0; //Ra 2014-04: tu zerowanie, aby EZT mogło pobierać prąd innemu członowi
  TotalMass:=ComputeMass;
  TotalMassxg:=TotalMass*g; {TotalMass*g}
  BearingF:=2*(DamageFlag and dtrain_bearing);

  HideModifier:=0;//Byte(Couplers[0].CouplingFlag>0)+Byte(Couplers[1].CouplingFlag>0);
  with Dim do
   begin
    if BearingType=0 then
     RollF:=0.05          {slizgowe}
    else
     RollF:=0.015;        {toczne}
    RollF:=RollF+BearingF/200.0;

(*    if NPoweredAxles>0 then
     RollF:=RollF*1.5;    {dodatkowe lozyska silnikow}*)
    if (NPoweredAxles>0) then //drobna optymalka
     begin
       RollF:=RollF+0.025;
{       if(Ft*Ft<1)then
         HideModifier:=HideModifier-3; }
     end;
    Ff:=TotalMassxg*(BearingF+RollF*V*V/10.0)/1000.0;
    {dorobic liczenie temperatury lozyska!}
    FrictConst1:=((TotalMassxg*RollF)/10000.0)+(Cx*W*H);
    Curvature:=abs(RunningShape.R); //zero oznacza nieskończony promień
    if (Curvature>0.0) then Curvature:=1.0/Curvature;
    //opór składu na łuku (youBy): +(500*TrackW/R)*TotalMassxg*0.001 do FrictConst2s/d
    FrictConst2s:= (TotalMassxg*((500.0*TrackW*Curvature)+ 2.5 - HideModifier + 2*BearingF/dtrain_bearing))*0.001;
    FrictConst2d:= (TotalMassxg*((500.0*TrackW*Curvature)+ 2.0 - HideModifier + BearingF/dtrain_bearing))*0.001;
   end;
end;

(* poprawione opory ruchu czekajace na lepsze cx w chk
procedure T_MoverParameters.ComputeConstans2(R:real);
var BearingF,RollF,HideModifier: real;
begin
  TotalMass:=ComputeMass;
  TotalMassxg:=TotalMass*g; {TotalMass*g}
  BearingF:=2*(DamageFlag and dtrain_bearing);

  HideModifier:=Byte(Couplers[0].CouplingFlag>0)+Byte(Couplers[1].CouplingFlag>0);
  with Dim do
   begin
    if BearingType=0 then
     RollF:=10          {slizgowe}
    else
     RollF:=8;        {toczne}
    if NPoweredAxles>0 then
     RollF:=RollF+2;    {dodatkowe lozyska silnikow}

    RollF:=RollF+BearingF/100.0; //stala do ustalenia

    {dorobic liczenie temperatury lozyska!}
    //stale do wzoru CNTK
    FrictConst1:=(Cx*W*H)*(6.0-2.5*HideModifier)/100; //dwa czola, kazde ma +2.5 (lokomotywa i wagon)  //V2
    FrictConst2s:=Totalmass*0.001*0.15;                                                                //V1
    if(R<TrackW)then //jakakolwiek wartosc dodatnia, np. szerokosc albo rozstaw
      FrictConst2d:=RollF*TotalMassxg*0.001+NAxles*150;                                                //V0 na prostej
    else
      FrictConst2d:=(RollF+500*TrackW/R)*TotalMassxg*0.001+NAxles*150;                                 //V0 na luku
   end;
end; *)


function T_MoverParameters.FrictionForce(R:real;TDamage:byte):real;
begin
//ABu 240205: chyba juz ekstremalnie zoptymalizowana funkcja liczaca sily tarcia
   if (abs(V)>0.01) then
      FrictionForce:=(FrictConst1*V*V)+FrictConst2d
   else
      FrictionForce:=(FrictConst1*V*V)+FrictConst2s;
end;

(* poprawione opory ruchu czekajace na lepsze cx w chk
function T_MoverParameters.FrictionForce2(R:real;TDamage:byte):real;
begin
//ABu 240205: chyba juz ekstremalnie zoptymalizowana funkcja liczaca sily tarcia
    FrictionForce2:=(FrictConst1*Vel*Vel)+(FrictConst2s*Vel)+FrictConst2d;
end; *)

function T_MoverParameters.AddPulseForce(Multipler:integer): boolean; {dla drezyny}
begin
  if (EngineType=WheelsDriven) and (EnginePowerSource.SourceType=InternalSource) and (EnginePowerSource.PowerType=BioPower) then
   begin
     ActiveDir:=CabNo;
     DirAbsolute:=ActiveDir*CabNo;
     if Vel>0 then
       PulseForce:=Min0R(1000.0*Power/(Abs(V)+0.1),Ftmax)
      else PulseForce:=Ftmax;
     if PulseForceCount>1000.0 then
      PulseForce:=0
     else
       PulseForce:=PulseForce*Multipler;
     PulseForceCount:=PulseForceCount+Abs(Multipler);
     AddPulseForce:=(PulseForce>0);
   end
  else AddPulseForce:=false;
end;


function T_MoverParameters.LoadingDone(LSpeed:real; LoadInit:string): boolean;
//test zakończenia załadunku/rozładunku
var LoadChange:longint;
begin
 ClearPendingExceptions; //zabezpieczenie dla Trunc()
 //LoadingDone:=false; //nie zakończone
 if (LoadInit<>'') then //nazwa ładunku niepusta
  begin
   if Load>MaxLoad then
    LoadChange:=Abs(Trunc(LSpeed*LastLoadChangeTime/2.0)) //przeładowanie?
   else
    LoadChange:=Abs(Trunc(LSpeed*LastLoadChangeTime));
   if LSpeed<0 then //gdy rozładunek
    begin
     LoadStatus:=2; //trwa rozładunek (włączenie naliczania czasu)
     if LoadChange<>0 then //jeśli coś przeładowano
      begin
       LastLoadChangeTime:=0; //naliczony czas został zużyty
       Load:=Load-LoadChange; //zmniejszenie ilości ładunku
       CommandIn.Value1:=CommandIn.Value1-LoadChange; //zmniejszenie ilości do rozładowania
       if Load<0 then
        Load:=0; //ładunek nie może być ujemny
       if (Load=0) or (CommandIn.Value1<0) then //pusto lub rozładowano żądaną ilość
        LoadStatus:=4; //skończony rozładunek
       if Load=0 then LoadType:=''; //jak nic nie ma, to nie ma też nazwy
      end
    end
   else if LSpeed>0 then //gdy załadunek
    begin
     LoadStatus:=1; //trwa załadunek (włączenie naliczania czasu)
     if LoadChange<>0 then //jeśli coś przeładowano
      begin
       LastLoadChangeTime:=0; //naliczony czas został zużyty
       LoadType:=LoadInit; //nazwa
       Load:=Load+LoadChange; //zwiększenie ładunku
       CommandIn.Value1:=CommandIn.Value1-LoadChange;
       if (Load>=MaxLoad*(1+OverLoadFactor)) or (CommandIn.Value1<0) then
        LoadStatus:=4; //skończony załadunek
      end
    end
   else LoadStatus:=4; //zerowa prędkość zmiany, to koniec
  end;
 LoadingDone:=(LoadStatus>=4);
end;

{-------------------------------------------------------------------}
{WAZNA FUNKCJA - oblicza siłę wypadkową}
procedure T_MoverParameters.ComputeTotalForce(dt: real; dt1: real; FullVer: boolean);
var b: byte;
begin
  if PhysicActivation then
   begin
  {  EventFlag:=false;                                             {jesli cos sie zlego wydarzy to ustawiane na true}
  {  SoundFlag:=0;                                                 {jesli ma byc jakis dzwiek to zapalany jet odpowiedni bit}
  {to powinno byc zerowane na zewnatrz}

    //juz zoptymalizowane:
    FStand:=FrictionForce(RunningShape.R,RunningTrack.DamageFlag); //siła oporów ruchu
    Vel:=Abs(V)*3.6; //prędkość w km/h
    nrot:=V2n(); //przeliczenie prędkości liniowej na obrotową

    if TestFlag(BrakeMethod,bp_MHS) and (PipePress<3.0) and (Vel>45) and TestFlag(BrakeDelayFlag,bdelay_M) then //ustawione na sztywno na 3 bar
      FStand:=Fstand+{(RunningTrack.friction)*}TrackBrakeForce; //doliczenie hamowania hamulcem szynowym
                   //w charakterystykach jest wartość siły hamowania zamiast nacisku
//    if(FullVer=true) then
//    begin //ABu: to dla optymalizacji, bo chyba te rzeczy wystarczy sprawdzac 1 raz na klatke?
       LastSwitchingTime:=LastSwitchingTime+dt1;
       if EngineType=ElectricSeriesMotor then
          LastRelayTime:=LastRelayTime+dt1;
//    end;
       if Mains and {(Abs(CabNo)<2) and} (EngineType=ElectricSeriesMotor) then //potem ulepszyc! pantogtrafy!
       begin //Ra 2014-03: uwzględnienie kierunku jazdy w napięciu na silnikach, a powinien być zdefiniowany nawrotnik
          if CabNo=0 then
             Voltage:=RunningTraction.TractionVoltage*ActiveDir
          else
             Voltage:=RunningTraction.TractionVoltage*DirAbsolute; //ActiveDir*CabNo;
          end {bo nie dzialalo}
       else if (EngineType=ElectricInductionMotor) or (((Couplers[0].CouplingFlag and ctrain_power)=ctrain_power) or ((Couplers[1].CouplingFlag and ctrain_power)=ctrain_power)) then //potem ulepszyc! pantogtrafy!
          Voltage:=Max0R(Max0R(RunningTraction.TractionVoltage,HVCouplers[0][1]),HVCouplers[1][1])
       else
          Voltage:=0;
	//end;

    if Power>0 then
       FTrain:=TractionForce(dt)
    else
       FTrain:=0;
    Fb:=BrakeForce(RunningTrack);
    if Max0R(Abs(FTrain),Fb)>TotalMassxg*Adhesive(RunningTrack.friction) then    {poslizg}
     SlippingWheels:=true;
    if SlippingWheels then
     begin
  {     TrainForce:=TrainForce-Fb; }
       nrot:=ComputeRotatingWheel((FTrain-Fb*Sign(V)-Fstand)/NAxles-Sign(nrot*Pi*WheelDiameter-V)*Adhesive(RunningTrack.friction)*TotalMass,dt,nrot);
       FTrain:=sign(FTrain)*TotalMassxg*Adhesive(RunningTrack.friction);
       Fb:=Min0R(Fb,TotalMassxg*Adhesive(RunningTrack.friction));
     end;
  {  else SlippingWheels:=false; }
  {  FStand:=0; }
    for b:=0 to 1 do
     if (Couplers[b].Connected<>nil) {and (Couplers[b].CouplerType<>Bare) and (Couplers[b].CouplerType<>Articulated)} then
      begin //doliczenie sił z innych pojazdów
        Couplers[b].CForce:=CouplerForce(b,dt);
        FTrain:=FTrain+Couplers[b].CForce
      end
     else Couplers[b].CForce:=0;
    //FStand:=Fb+FrictionForce(RunningShape.R,RunningTrack.DamageFlag);
    FStand:=Fb+FStand;
    FTrain:=FTrain+TotalMassxg*RunningShape.dHtrack; //doliczenie składowej stycznej grawitacji
    {!niejawne przypisanie zmiennej!}
    FTotal:=FTrain-Sign(V)*FStand;
   end;

   {McZapkie-031103: sprawdzanie czy warto liczyc fizyke i inne updaty}
   {ABu 300105: cos tu mieszalem , dziala teraz troche lepiej, wiec zostawiam
        zakomentowalem PhysicActivationFlag bo cos nie dzialalo i fizyka byla
        liczona zawsze.}
   //if PhysicActivationFlag then
   // begin
     if (CabNo=0) and (Vel<0.0001) and (abs(AccS)<0.0001) and (TrainType<>dt_EZT) then
      begin
        if not PhysicActivation then
         begin
          if Couplers[0].Connected<>nil then
           if (Couplers[0].Connected.Vel>0.0001) or (Abs(Couplers[0].Connected.AccS)>0.0001) then
            Physic_ReActivation;
          if Couplers[1].Connected<>nil then
          if (Couplers[1].Connected.Vel>0.0001) or (Abs(Couplers[1].Connected.AccS)>0.0001) then
            Physic_ReActivation;
         end;
        if LastSwitchingTime>5 then //10+Random(100) then
         PhysicActivation:=false; {zeby nie brac pod uwage braku V po uruchomieniu programu}
      end
     else
      PhysicActivation:=true;
   // end;

end;

{------------------------------------------------------------}
{OBLICZENIE PRZEMIESZCZENIA}
function T_MoverParameters.ComputeMovement(dt:real; dt1:real; Shape:TTrackShape; var Track:TTrackParam; var ElectricTraction:TTractionParam; NewLoc:TLocation; var NewRot:TRotation):real;
var b:byte;
    Vprev,AccSprev:real;
//    Iheat:real; prad ogrzewania
    hvc: real;
const Vepsilon=1e-5; Aepsilon=1e-3; //ASBSpeed=0.8;
begin
    TotalCurrent:=0;
    hvc:=Max0R(Max0R(PantFrontVolt,PantRearVolt),ElectricTraction.TractionVoltage*0.9);
    for b:=0 to 1 do //przekazywanie napiec
     if ((Couplers[b].CouplingFlag and ctrain_power) = ctrain_power)or(((Couplers[b].CouplingFlag and ctrain_heating) = ctrain_heating)and(Heating)) then
      begin
        HVCouplers[1-b][1]:=Max0R(Abs(hvc),Couplers[b].Connected.HVCouplers[Couplers[b].ConnectedNr][1]-HVCouplers[b][0]*0.02);
      end
     else
        HVCouplers[1-b][1]:=Abs(hvc)-HVCouplers[b][0]*0.02;//Max0R(Abs(Voltage),0);
//      end;

    hvc:=HVCouplers[0][1]+HVCouplers[1][1];

    if (Abs(PantFrontVolt)+Abs(PantRearVolt)<1) and (hvc>1)then  //bez napiecia, ale jest cos na sprzegach:
     begin
      for b:=0 to 1 do //przekazywanie pradow
       if ((Couplers[b].CouplingFlag and ctrain_power) = ctrain_power)or(((Couplers[b].CouplingFlag and ctrain_heating) = ctrain_heating)and(Heating)) then //jesli spiety
        begin
          HVCouplers[b][0]:=Couplers[b].Connected.HVCouplers[1-Couplers[b].ConnectedNr][0]+Itot*HVCouplers[b][1]/hvc; //obciążenie rozkladane stosownie do napiec
        end
       else //pierwszy pojazd
        begin
          HVCouplers[b][0]:=Itot*HVCouplers[b][1]/hvc;
        end;
     end
    else
     begin
      if ((Couplers[0].CouplingFlag and ctrain_power) = ctrain_power)or(((Couplers[0].CouplingFlag and ctrain_heating) = ctrain_heating)and(Heating)) then
        TotalCurrent:=TotalCurrent+Couplers[0].Connected.HVCouplers[1-Couplers[0].ConnectedNr][0];
      if ((Couplers[1].CouplingFlag and ctrain_power) = ctrain_power)or(((Couplers[1].CouplingFlag and ctrain_heating) = ctrain_heating)and(Heating)) then
        TotalCurrent:=TotalCurrent+Couplers[1].Connected.HVCouplers[1-Couplers[1].ConnectedNr][0];
      HVCouplers[0][0]:=0;
      HVCouplers[1][0]:=0;
     end;

  ClearPendingExceptions;
  if not TestFlag(DamageFlag,dtrain_out) then
   begin //Ra: to przepisywanie tu jest bez sensu
     RunningShape:=Shape;
     RunningTrack:=Track;
     RunningTraction:=ElectricTraction;
     with ElectricTraction do
      if not DynamicBrakeFlag then
       RunningTraction.TractionVoltage:=TractionVoltage{-Abs(TractionResistivity*(Itot+HVCouplers[0][0]+HVCouplers[1][0]))}
      else
       RunningTraction.TractionVoltage:=TractionVoltage-Abs(TractionResistivity*Itot*0); //zasadniczo ED oporowe nie zmienia napięcia w sieci
   end;
  if CategoryFlag=4 then
   OffsetTrackV:=TotalMass/(Dim.L*Dim.W*1000.0)
  else
   if TestFlag(CategoryFlag,1) and TestFlag(RunningTrack.CategoryFlag,1) then
    if TestFlag(DamageFlag,dtrain_out) then
     begin
       OffsetTrackV:=-0.2; OffsetTrackH:=sign(RunningShape.R)*0.2;
     end;
  Loc:=NewLoc;
  Rot:=NewRot;
  with NewRot do begin Rx:=0; Ry:=0; Rz:=0; end;
  if dL=0 then {oblicz przesuniecie}
   begin
     Vprev:=V;
     AccSprev:=AccS;
     {dt:=ActualTime-LastUpdatedTime;}                               {przyrost czasu}
     {przyspieszenie styczne}
     AccS:=(FTotal/TotalMass+AccSprev)/2.0; //prawo Newtona ale z wygladzaniem (średnia z poprzednim)

     if TestFlag(DamageFlag,dtrain_out) then
      AccS:=-Sign(V)*g*Random;
     {przyspieszenie normalne}
     if Abs(Shape.R)>0.01 then
      AccN:=SQR(V)/Shape.R+g*Shape.dHrail/TrackW
     else AccN:=g*Shape.dHrail/TrackW;

     {szarpanie}
     if FuzzyLogic((10+Track.DamageFlag)*Mass*Vel/Vmax,500000,p_accn) then {Ra: czemu tu masa bez ładunku?}
       AccV:=sqrt((1+Track.DamageFlag)*random(Trunc(50*Mass/1000000.0))*Vel/(Vmax*(10+(Track.QualityFlag and 31))))
     else
      AccV:=AccV/2.0;
     if AccV>1.0 then
      AccN:=AccN+(7-random(5))*(100.0+Track.DamageFlag/2.0)*AccV/2000.0;

     {wykolejanie na luku oraz z braku szyn}
     if TestFlag(CategoryFlag,1) then
      begin
       if FuzzyLogic((AccN/g)*(1+0.1*(Track.DamageFlag and dtrack_freerail)),TrackW/Dim.H,1)
       or TestFlag(Track.DamageFlag,dtrack_norail) then
        if SetFlag(DamageFlag,dtrain_out) then
         begin
           EventFlag:=true;
           MainS:=false;
           RunningShape.R:=0;
           if (TestFlag(Track.DamageFlag,dtrack_norail)) then
            DerailReason:=1 //Ra: powód wykolejenia: brak szyn
           else
            DerailReason:=2; //Ra: powód wykolejenia: przewrócony na łuku
         end;
     {wykolejanie na poszerzeniu toru}
        if FuzzyLogic(Abs(Track.Width-TrackW),TrackW/10.0,1) then
         if SetFlag(DamageFlag,dtrain_out) then
          begin
            EventFlag:=true;
            MainS:=false;
            RunningShape.R:=0;
            DerailReason:=3; //Ra: powód wykolejenia: za szeroki tor
          end;
      end;
     {wykolejanie wkutek niezgodnosci kategorii toru i pojazdu}
     if not TestFlag(RunningTrack.CategoryFlag,CategoryFlag) then
      if SetFlag(DamageFlag,dtrain_out) then
        begin
          EventFlag:=true;
          MainS:=false;
          DerailReason:=4; //Ra: powód wykolejenia: nieodpowiednia trajektoria
        end;

     V:=V+(3*AccS-AccSprev)*dt/2.0;                                  {przyrost predkosci}

     if TestFlag(DamageFlag,dtrain_out) then
      if Vel<1 then
       begin
         V:=0;
         AccS:=0;
       end;

     if (V*Vprev<=0) and (Abs(FStand)>Abs(FTrain)) then            {tlumienie predkosci przy hamowaniu}
       begin     {zahamowany}
         V:=0;
         //AccS:=0; //Ra 2014-03: ale siła grawitacji działa, więc nie może być zerowe
       end;
   (*
     else
      if (Abs(V)<Vepsilon) and (Abs(AccS)<Aepsilon) then
       begin
         V:=0;
         AccS:=0;
       end;
   *)
   { dL:=(V+AccS*dt/2)*dt;                                      {przyrost dlugosci czyli przesuniecie}
     dL:=(3*V-Vprev)*dt/2.0;                                       {metoda Adamsa-Bashfortha}
    {ale jesli jest kolizja (zas. zach. pedu) to...}
    for b:=0 to 1 do
     if Couplers[b].CheckCollision then
      CollisionDetect(b,dt);  {zmienia niejawnie AccS, V !!!}
(*
    for b:=0 to 1 do
     begin
       Couplers[b].CForce:=0;  {!}
       SendAVL(AccS,AccN,V,dL,0);
     end;
*)
   end; {liczone dL, predkosc i przyspieszenie}

   {Ra: reszta przeniesiona do Mover.cpp}
end; {ComputeMovement}

{blablabla}
{OBLICZENIE PRZEMIESZCZENIA}
function T_MoverParameters.FastComputeMovement(dt:real; Shape:TTrackShape; var Track:TTrackParam;NewLoc:TLocation; var NewRot:TRotation):real; //;var ElectricTraction:TTractionParam; NewLoc:TLocation; var NewRot:TRotation):real;
var b:byte;
    Vprev,AccSprev:real;
const Vepsilon=1e-5; Aepsilon=1e-3; //ASBSpeed=0.8;
begin
  ClearPendingExceptions;
  Loc:=NewLoc;
  Rot:=NewRot;
  with NewRot do begin Rx:=0; Ry:=0; Rz:=0; end;
  if dL=0 then {oblicz przesuniecie}
   begin
     Vprev:=V;
     AccSprev:=AccS;
     {dt:=ActualTime-LastUpdatedTime;}                               {przyrost czasu}
     {przyspieszenie styczne}
     AccS:=(FTotal/TotalMass+AccSprev)/2.0; //prawo Newtona ale z wygladzaniem (średnia z poprzednim)

     if TestFlag(DamageFlag,dtrain_out) then
      AccS:=-Sign(V)*g*Random;
     {przyspieszenie normalne}
//     if Abs(Shape.R)>0.01 then
//      AccN:=SQR(V)/Shape.R+g*Shape.dHrail/TrackW
//     else AccN:=g*Shape.dHrail/TrackW;

     {szarpanie}
     if FuzzyLogic((10+Track.DamageFlag)*Mass*Vel/Vmax,500000,p_accn) then
       AccV:=sqrt((1+Track.DamageFlag)*random(Trunc(50*Mass/1000000.0))*Vel/(Vmax*(10+(Track.QualityFlag and 31))))
     else
      AccV:=AccV/2.0;
     if AccV>1.0 then
      AccN:=AccN+(7-random(5))*(100.0+Track.DamageFlag/2.0)*AccV/2000.0;

//     {wykolejanie na luku oraz z braku szyn}
//     if TestFlag(CategoryFlag,1) then
//      begin
//       if FuzzyLogic((AccN/g)*(1+0.1*(Track.DamageFlag and dtrack_freerail)),TrackW/Dim.H,1)
//       or TestFlag(Track.DamageFlag,dtrack_norail) then
//        if SetFlag(DamageFlag,dtrain_out) then
//         begin
//           EventFlag:=true;
//           MainS:=false;
//           RunningShape.R:=0;
//         end;
//     {wykolejanie na poszerzeniu toru}
//        if FuzzyLogic(Abs(Track.Width-TrackW),TrackW/10,1) then
//         if SetFlag(DamageFlag,dtrain_out) then
//          begin
//            EventFlag:=true;
//            MainS:=false;
//            RunningShape.R:=0;
//          end;
//      end;
//     {wykolejanie wkutek niezgodnosci kategorii toru i pojazdu}
//     if not TestFlag(RunningTrack.CategoryFlag,CategoryFlag) then
//      if SetFlag(DamageFlag,dtrain_out) then
//        begin
//          EventFlag:=true;
//          MainS:=false;
//        end;

     V:=V+(3.0*AccS-AccSprev)*dt/2.0;                                  {przyrost predkosci}

     if TestFlag(DamageFlag,dtrain_out) then
      if Vel<1 then
       begin
         V:=0;
         AccS:=0; //Ra 2014-03: ale siła grawitacji działa, więc nie może być zerowe
       end;

     if (V*Vprev<=0) and (Abs(FStand)>Abs(FTrain)) then            {tlumienie predkosci przy hamowaniu}
       begin     {zahamowany}
         V:=0;
         AccS:=0;
       end;
     dL:=(3*V-Vprev)*dt/2.0;                                       {metoda Adamsa-Bashfortha}
    {ale jesli jest kolizja (zas. zach. pedu) to...}
    for b:=0 to 1 do
     if Couplers[b].CheckCollision then
      CollisionDetect(b,dt);  {zmienia niejawnie AccS, V !!!}
   end; {liczone dL, predkosc i przyspieszenie}

   {Ra: reszta przeniesiona do Mover.cpp}
end; {FastComputeMovement}



function T_MoverParameters.ComputeMass: real;
var M:real;
begin
 if Load>0 then
  begin //zakładamy, że ładunek jest pisany małymi literami
   if LoadQuantity='tonns' then
    M:=Load*1000
   else if (LoadType='passengers') then
    M:=Load*80
   else if LoadType='luggage' then
    M:=Load*100
   else if LoadType='cars' then
    M:=Load*800
   else if LoadType='containers' then
    M:=Load*8000
   else if LoadType='transformers' then
    M:=Load*50000
   else
    M:=Load*1000;
  end
 else
  M:=0;
 {Ra: na razie tak, ale nie wszędzie masy wirujące się wliczają}
 ComputeMass:=Mass+M+Mred;
end;



{-----------------------------------------------------------------}
{funkcje wejscia/wyjscia}

{przekazywanie komend i parametrow}

function T_MoverParameters.SetInternalCommand(NewCommand:string; NewValue1,NewValue2:real):boolean;
begin
  if (CommandIn.Command=Newcommand) and (commandIn.Value1=NewValue1) and (commandIn.Value2=NewValue2) then
   SetInternalCommand:=false
  else
   with CommandIn do
    begin
     Command:=NewCommand;
     Value1:=NewValue1;
     Value2:=NewValue2;
     SetInternalCommand:=true;
     LastLoadChangeTime:=0; //zerowanie czasu (roz)ładowania
    end;
end;

function T_MoverParameters.GetExternalCommand(var Command:string):real;
begin
  Command:=CommandOut;
  GetExternalCommand:=ValueOut;
end;

function T_MoverParameters.DoorBlockedFlag:Boolean;
begin
 //if (DoorBlocked=true) and (Vel<5.0) then
 DoorBlockedFlag:=false;
 if (DoorBlocked=true) and (Vel>=5.0) then
  DoorBlockedFlag:=true
end;

function T_MoverParameters.RunCommand(command:string; CValue1,CValue2:real):boolean;
//wysłanie komendy otrzymanej z kierunku CValue2 (względem sprzęgów: 1=przod,-1=tył)
// Ra: Jest tu problem z rekurencją. Trzeba by oddzielić wykonywanie komend od mechanizmu
// ich propagacji w składzie. Osobnym problemem może być propagacja tylko w jedną stronę.
// Jeśli jakiś człon jest wstawiony odwrotnie, to również odwrotnie musi wykonywać
// komendy związane z kierunkami (PantFront, PantRear, DoorLeft, DoorRight).
// Komenda musi być zdefiniowana tutaj, a jeśli się wywołuje funkcję, to ona nie może
// sama przesyłać do kolejnych pojazdów. Należy też się zastanowić, czy dla uzyskania
// jakiejś zmiany (np. IncMainCtrl) lepiej wywołać funkcję, czy od razu wysłać komendę.
var OK:boolean; testload:string;
Begin
{$B+} {cholernie mi sie nie podoba ta dyrektywa!!!}
  OK:=false;
  ClearPendingExceptions();

  {test komend sterowania ukrotnionego}
  if command='MainCtrl' then
   begin
     if MainCtrlPosNo>=Trunc(CValue1) then
      MainCtrlPos:=Trunc(CValue1);
     OK:=SendCtrlToNext(command,CValue1,CValue2);
   end
  else if command='ScndCtrl' then
   begin
     if (EngineType=ElectricInductionMotor) then
       if (ScndCtrlPos=0) and (Trunc(CValue1)>0) then
        if (Vmax<250) then
         ScndCtrlActualPos:=Round(Vel+0.5)
        else
         ScndCtrlActualPos:=Round(Vel/2+0.5)
       else if (Trunc(CValue1)=0) then
        ScndCtrlActualPos:=0;
     if ScndCtrlPosNo>=Trunc(CValue1) then
      ScndCtrlPos:=Trunc(CValue1);
     OK:=SendCtrlToNext(command,CValue1,CValue2);
   end
(*  else if command='BrakeCtrl' then
   begin
     if BrakeCtrlPosNo>=Trunc(CValue1) then
      begin
        BrakeCtrlPos:=Trunc(CValue1);
        OK:=SendCtrlToNext(command,CValue1,CValue2);
      end;
   end *)
  else if command='Brake' then //youBy - jak sie EP hamuje, to trza sygnal wyslac...
   begin
     Hamulec.SetEPS(CValue1);
     //fBrakeCtrlPos:=BrakeCtrlPos; //to powinnno być w jednym miejscu, aktualnie w C++!!!
     BrakePressureActual:=BrakePressureTable[BrakeCtrlPos];
     OK:=SendCtrlToNext(command,CValue1,CValue2);
   end //youby - odluzniacz hamulcow, przyda sie
  else if command='BrakeReleaser' then
   begin
     OK:=BrakeReleaser(Round(CValue1)); //samo się przesyła dalej
     //OK:=SendCtrlToNext(command,CValue1,CValue2); //to robiło kaskadę 2^n
   end
  else if command='MainSwitch' then
   begin
     if CValue1=1 then
      begin
        Mains:=true;
        if (EngineType=DieselEngine) and Mains then
          dizel_enginestart:=true;
      end
     else Mains:=false;
     OK:=SendCtrlToNext(command,CValue1,CValue2);
   end
  else if command='Direction' then
   begin
     ActiveDir:=Trunc(CValue1);
     DirAbsolute:=ActiveDir*CabNo;
     OK:=SendCtrlToNext(command,CValue1,CValue2);
   end
  else if command='CabActivisation' then
   begin
//  OK:=Power>0.01;
    case Trunc(CValue1*CValue2) of //CValue2 ma zmieniany znak przy niezgodności sprzęgów
      1 : CabNo:= 1;
     -1 : CabNo:=-1;
    else CabNo:=0; //gdy CValue1==0
    end;
    DirAbsolute:=ActiveDir*CabNo;
    OK:=SendCtrlToNext(command,CValue1,CValue2);
   end
  else if command='AutoRelaySwitch' then
   begin
     if (CValue1=1) and (AutoRelayType=2) then AutoRelayFlag:=true
     else AutoRelayFlag:=false;
     OK:=SendCtrlToNext(command,CValue1,CValue2);
   end
  else if command='FuseSwitch' then
   begin
      if ((EngineType=ElectricSeriesMotor)or(EngineType=DieselElectric)) and FuseFlag and (CValue1=1) and
         (MainCtrlActualPos=0) and (ScndCtrlActualPos=0) and Mains then
{      if (EngineType=ElectricSeriesMotor) and (CValue1=1) and
         (MainCtrlActualPos=0) and (ScndCtrlActualPos=0) and Mains then}
        FuseFlag:=false;  {wlaczenie ponowne obwodu}
     // if ((EngineType=ElectricSeriesMotor)or(EngineType=DieselElectric)) and not FuseFlag and (CValue1=0) and Mains then
     //   FuseFlag:=true;
      OK:=SendCtrlToNext(command,CValue1,CValue2);
   end
  else if command='ConverterSwitch' then         {NBMX}
   begin
     if (CValue1=1) then ConverterAllow:=true
     else if (CValue1=0) then ConverterAllow:=false;
     OK:=SendCtrlToNext(command,CValue1,CValue2);
   end
  else if command='BatterySwitch' then         {NBMX}
   begin
     if (CValue1=1) then Battery:=true
     else if (CValue1=0) then Battery:=false;
     if (Battery) and (ActiveCab<>0) {or (TrainType=dt_EZT)} then
      SecuritySystem.Status:=SecuritySystem.Status or s_waiting //aktywacja czuwaka
     else
      SecuritySystem.Status:=0; //wyłączenie czuwaka
     OK:=SendCtrlToNext(command,CValue1,CValue2);
   end
//   else if command='EpFuseSwitch' then         {NBMX}
//   begin
//     if (CValue1=1) then EpFuse:=true
//     else if (CValue1=0) then EpFuse:=false;
//     OK:=SendCtrlToNext(command,CValue1,CValue2);
//   end
  else if command='CompressorSwitch' then         {NBMX}
   begin
     if (CValue1=1) then CompressorAllow:=true
     else if (CValue1=0) then CompressorAllow:=false;
     OK:=SendCtrlToNext(command,CValue1,CValue2);
   end
  else if command='DoorOpen' then         {NBMX}
   begin //Ra: uwzględnić trzeba jeszcze zgodność sprzęgów
    if (CValue2>0) then
     begin //normalne ustawienie pojazdu
      if (CValue1=1) OR (CValue1=3) then
       DoorLeftOpened:=true;
      if (CValue1=2) OR (CValue1=3) then
       DoorRightOpened:=true;
     end
    else
     begin //odwrotne ustawienie pojazdu
      if (CValue1=2) OR (CValue1=3) then
       DoorLeftOpened:=true;
      if (CValue1=1) OR (CValue1=3) then
       DoorRightOpened:=true;
     end;
    OK:=SendCtrlToNext(command,CValue1,CValue2);
   end
  else if command='DoorClose' then         {NBMX}
   begin //Ra: uwzględnić trzeba jeszcze zgodność sprzęgów
    if (CValue2>0) then
     begin //normalne ustawienie pojazdu
      if (CValue1=1) OR (CValue1=3) then
       DoorLeftOpened:=false;
      if (CValue1=2) OR (CValue1=3) then
       DoorRightOpened:=false;
     end
    else
     begin //odwrotne ustawienie pojazdu
      if (CValue1=2) OR (CValue1=3) then
       DoorLeftOpened:=false;
      if (CValue1=1) OR (CValue1=3) then
       DoorRightOpened:=false;
     end;
    OK:=SendCtrlToNext(command,CValue1,CValue2);
   end
  else if command='PantFront' then         {Winger 160204}
   begin //Ra: uwzględnić trzeba jeszcze zgodność sprzęgów
   //Czemu EZT ma być traktowane inaczej? Ukrotnienie ma, a człon może być odwrócony
     if (TrainType=dt_EZT) then
     begin //'ezt'
       if (CValue1=1) then
        begin
        PantFrontUp:=true;
        PantFrontStart:=0;
        end
       else if (CValue1=0) then
        begin
        PantFrontUp:=false;
        PantFrontStart:=1;
        end;
     end
     else
     begin //nie 'ezt' - odwrotne ustawienie pantografów: ^-.-^ zamiast ^-.^-
       if (CValue1=1) then
        if (TestFlag(Couplers[1].CouplingFlag,ctrain_controll)and(CValue2= 1))
         or(TestFlag(Couplers[0].CouplingFlag,ctrain_controll)and(CValue2=-1))
         then
         begin
          PantFrontUp:=true;
          PantFrontStart:=0;
         end
        else
         begin
          PantRearUp:=true;
          PantRearStart:=0;
         end
       else if (CValue1=0) then
        if (TestFlag(Couplers[1].CouplingFlag,ctrain_controll)and(CValue2= 1))
         or(TestFlag(Couplers[0].CouplingFlag,ctrain_controll)and(CValue2=-1))
        then
        begin
          PantFrontUp:=false;
          PantFrontStart:=1;
         end
        else
         begin
          PantRearUp:=false;
          PantRearStart:=1;
         end;
     end;
     OK:=SendCtrlToNext(command,CValue1,CValue2);
   end
  else if command='PantRear' then         {Winger 160204, ABu 310105 i 030305}
   begin //Ra: uwzględnić trzeba jeszcze zgodność sprzęgów
     if (TrainType=dt_EZT) then
     begin {'ezt'}
      if (CValue1=1) then
        begin
        PantRearUp:=true;
        PantRearStart:=0;
        end
       else if (CValue1=0) then
        begin
        PantRearUp:=false;
        PantRearStart:=1;
        end;
     end
     else
     begin {nie 'ezt'}
      if (CValue1=1) then
       {if ostatni polaczony sprz. sterowania}
       if (TestFlag(Couplers[1].CouplingFlag,ctrain_controll)and(CValue2= 1))
        or(TestFlag(Couplers[0].CouplingFlag,ctrain_controll)and(CValue2=-1))
       then
        begin
         PantRearUp:=true;
         PantRearStart:=0;
        end
       else
        begin
         PantFrontUp:=true;
         PantFrontStart:=0;
        end
      else if (CValue1=0) then
       if (TestFlag(Couplers[1].CouplingFlag,ctrain_controll)and(CValue2= 1))
        or(TestFlag(Couplers[0].CouplingFlag,ctrain_controll)and(CValue2=-1))
       then
        begin
         PantRearUp:=false;
         PantRearStart:=1;
        end
       else
        begin
         PantFrontUp:=false;
         PantFrontStart:=1;
        end;
     end;
     OK:=SendCtrlToNext(command,CValue1,CValue2);
   end
  else if command='MaxCurrentSwitch' then
   begin
      OK:=MaxCurrentSwitch(CValue1=1);
   end
  else if command='MinCurrentSwitch' then
   begin
      OK:=MinCurrentSwitch(CValue1=1);
   end
{test komend oddzialywujacych na tabor}
  else if command='SetDamage' then
   begin
     if CValue2=1 then OK:=SetFlag(DamageFlag,Trunc(CValue1));
     if CValue2=-1 then OK:=SetFlag(DamageFlag,-Trunc(CValue1));
   end
  else if command='Emergency_brake' then
   begin
     if EmergencyBrakeSwitch(Trunc(CValue1)=1) then //YB: czy to jest potrzebne?
       OK:=true
     else OK:=false;
   end
  else if command='BrakeDelay' then
   begin
      BrakeDelayFlag:=Trunc(CValue1);
      OK:=true;
   end
  else if command='SandDoseOn' then
   begin
     if SandDoseOn then
       OK:=true
     else OK:=false;
   end
  else if command='CabSignal' then {SHP,Indusi}
   begin //Ra: to powinno działać tylko w członie obsadzonym
     if {(TrainType=dt_EZT)or} (ActiveCab<>0) and (Battery) and TestFlag(SecuritySystem.SystemType,2) then //jeśli kabina jest obsadzona (silnikowy w EZT?)
      with SecuritySystem do
       begin
        VelocityAllowed:=Trunc(CValue1);
        NextVelocityAllowed:=Trunc(CValue2);
        SystemSoundSHPTimer:=0; //hunter-091012
        SetFlag(Status,s_active);
       end;
     //else OK:=false;
    OK:=true; //true, gdy można usunąć komendę
   end
 {naladunek/rozladunek}
  else if Pos('Load=',command)=1 then
   begin
    OK:=false; //będzie powtarzane aż się załaduje
    if (Vel=0) and (MaxLoad>0) and (Load<MaxLoad*(1+OverLoadFactor)) then //czy można ładowac?
     if Distance(Loc,CommandIn.Location,Dim,Dim)<10 then //ten peron/rampa
      begin
       testload:=LowerCase(DUE(command));
       if Pos(testload,LoadAccepted)>0 then //nazwa jest obecna w CHK
        OK:=LoadingDone(Min0R(CValue2,LoadSpeed),testload); //zmienia LoadStatus
      end;
    //if OK then LoadStatus:=0; //nie udalo sie w ogole albo juz skonczone
   end
  else if Pos('UnLoad=',command)=1 then
   begin
    OK:=false; //będzie powtarzane aż się rozładuje
    if (Vel=0) and (Load>0) then //czy jest co rozladowac?
     if Distance(Loc,CommandIn.Location,Dim,Dim)<10 then //ten peron
      begin
       testload:=DUE(command); //zgodność nazwy ładunku z CHK
       if LoadType=testload then {mozna to rozladowac}
        OK:=LoadingDone(-Min0R(CValue2,LoadSpeed),testload);
      end;
    //if OK then LoadStatus:=0;
   end;
  RunCommand:=OK; //dla true komenda będzie usunięta, dla false wykonana ponownie
{$B-}
End;

function T_MoverParameters.RunInternalCommand:boolean;
var OK:boolean;
begin
  if CommandIn.Command<>'' then
   begin
     OK:=RunCommand(CommandIn.Command,CommandIn.Value1,CommandIn.Value2);
     if OK then
      with CommandIn do
       begin
         Command:=''; {kasowanie bo rozkaz wykonany}
         Value1:=0;
         Value2:=0;
         Location.x:=0; Location.y:=0; Location.z:=0;
         if not PhysicActivation then
          Physic_ReActivation;
      end;
   end
  else
   OK:=false;
  RunInternalCommand:=OK;
end;

procedure T_MoverParameters.PutCommand(NewCommand:string; NewValue1,NewValue2:real; NewLocation:TLocation);
begin
 CommandLast:=NewCommand; //zapamiętanie komendy
  with CommandIn do
   begin
     Command:=NewCommand;
     Value1:=NewValue1;
     Value2:=NewValue2;
     Location:=NewLocation;
   end;                         {czy uruchomic tu RunInternalCommand? nie wiem}
end;

{dla samochodow - kolej nie wężykuje}
function T_MoverParameters.ChangeOffsetH(DeltaOffset:real):boolean;
begin
  if TestFlag(CategoryFlag,2) and TestFlag(RunningTrack.CategoryFlag,2) then
   begin
     OffsetTrackH:=OffsetTrackH+DeltaOffset;
//     if abs(OffsetTrackH)>(RunningTrack.Width/1.95-TrackW/2.0) then
     if abs(OffsetTrackH)>(0.5*(RunningTrack.Width-Dim.W)-0.05) then //Ra: może pół pojazdu od brzegu?
      ChangeOffsetH:=false  {kola na granicy drogi}
     else
      ChangeOffsetH:=true;
   end
  else ChangeOffsetH:=false;
end;

{inicjalizacja}

constructor T_MoverParameters.Init(//LocInitial:TLocation; RotInitial:TRotation;
                                  VelInitial:real; TypeNameInit, NameInit: string; LoadInitial:longint; LoadTypeInitial: string; Cab:integer);
                                 {predkosc pocz. w km/h, ilosc ladunku, typ ladunku, numer kabiny}
var b,k:integer;
begin
  {inicjalizacja stalych}
  dMoveLen:=0;
  CategoryFlag:=1;
  EngineType:=None;
  for b:=0 to ResArraySize do
   begin
     RList[b].Relay:=0;
     RList[b].R:=0;
     RList[b].Bn:=0;
     RList[b].Mn:=0;
     RList[b].AutoSwitch:=false;
   end;
  WheelDiameter:=1.0;
  BrakeCtrlPosNo:=0;
  LightsPosNo:=0;
  LightsDefPos:=1;
  for k:=-1 to MainBrakeMaxPos do
   with BrakePressureTable[k] do
    begin
      PipePressureVal:=0;
      BrakePressureVal:=0;
      FlowSpeedVal:=0;
    end;
   with BrakePressureTable[-2] do  {pozycja odciecia}
    begin
      PipePressureVal:=-1;
      BrakePressureVal:=-1;
      FlowSpeedVal:=0;
    end;
  Transmision.Ratio:=1;
  NBpA:=0;
  DynamicBrakeType:=0;
  ASBType:=0;
  AutoRelayType:=0;
  for b:=0 to 1 do //Ra: kto tu zrobił "for b:=1 to 2 do" ???
   with Couplers[b] do
    begin
      CouplerType:=NoCoupler;
      SpringkB:=1; SpringkC:=1;
      DmaxB:=0.1; FmaxB:=1000;
      DmaxC:=0.1; FmaxC:=1000;
    end;
  Power:=0;
  MaxLoad:=0; LoadAccepted:='';
  LoadSpeed:=0; UnLoadSpeed:=0;
  HeatingPower:=0; LightPower:=0;
  with HeatingPowerSource do
   begin
     MaxVoltage:=0; MaxCurrent:=0; IntR:=0.001;
     SourceType:=NotDefined; PowerType:=NoPower; RPowerCable.PowerTrans:=NoPower;
   end;
  with AlterHeatPowerSource do
   begin
     MaxVoltage:=0; MaxCurrent:=0; IntR:=0.001;
     SourceType:=NotDefined; PowerType:=NoPower; RPowerCable.PowerTrans:=NoPower;
   end;
  with LightPowerSource do
   begin
     MaxVoltage:=0; MaxCurrent:=0; IntR:=0.001;
     SourceType:=NotDefined; PowerType:=NoPower; RPowerCable.PowerTrans:=NoPower;
   end;
  with AlterLightPowerSource do
   begin
     MaxVoltage:=0; MaxCurrent:=0; IntR:=0.001;
     SourceType:=NotDefined; PowerType:=NoPower; RPowerCable.PowerTrans:=NoPower;
   end;
  TypeName:=TypeNameInit;
  HighPipePress:=0;
  LowPipePress:=0;
  DeltaPipePress:=0;
  BrakeCylNo:=0;
  BrakeCylRadius:=0;
  BrakeCylDist:=0;
  for b:=0 to 3 do
    BrakeCylMult[b]:=0;
  VeselVolume:=0;
  BrakeVolume:=0;
  RapidMult:=1;
  dizel_Mmax:=1; dizel_nMmax:=1; dizel_Mnmax:=2; dizel_nmax:=2; dizel_nominalfill:=0;
  dizel_Mstand:=0;
  dizel_nmax_cutoff:=0;
  dizel_nmin:=0;
  dizel_minVelfullengage:=0;
  dizel_AIM:=1;
  dizel_engageDia:=0.5; dizel_engageMaxForce:=6000; dizel_engagefriction:=0.5;
  DoorOpenCtrl:=0; DoorCloseCtrl:=0;
  DoorStayOpen:=0;
  DoorClosureWarning:=false;
  DoorOpenSpeed:=1; DoorCloseSpeed:=1;
  DoorMaxShiftL:=0.5; DoorMaxShiftR:=0.5;
  DoorOpenMethod:=2;
  DepartureSignal:=false;
  InsideConsist:=false;
  CompressorPower:=1;
  SmallCompressorPower:=0;
  for b:=0 to 25 do
    eimc[b]:=0;
  eimc[eimc_p_eped]:=1.5;
  StopBrakeDecc:=0;  

  ScndInMain:=false;

  Vhyp:=1;
  Vadd:=1;
  PowerCorRatio:=1;

  {inicjalizacja zmiennych}
  //Loc:=LocInitial; //Ra: to i tak trzeba potem przesunąć, po ustaleniu pozycji na torze (potrzebna długość)
  //Rot:=RotInitial;
  for b:=0 to 1 do
   with Couplers[b] do
    begin
      AllowedFlag:=3; //domyślnie hak i hamulec, inne trzeba włączyć jawnie w FIZ
      CouplingFlag:=0;
      Connected:=nil;
      ConnectedNr:=0; //Ra: to nie ma znaczenia jak nie podłączony
      Render:=false;
      CForce:=0;
      Dist:=0;
      CheckCollision:=false;
    end;
  ScanCounter:=0;
  BrakeCtrlPos:=-2; //to nie ma znaczenia, konstruktor w Mover.cpp zmienia na -2
  BrakeDelayFlag:=0;
  BrakeStatus:=b_off;
  EmergencyBrakeFlag:=false;
  MainCtrlPos:=0;
  ScndCtrlPos:=0;
  MainCtrlActualPos:=0;
  ScndCtrlActualPos:=0;
  LightsPos:=0;
  Heating:=false;
  Mains:=false;
  ActiveDir:=0; //kierunek nie ustawiony
  CabNo:=0; //sterowania nie ma, ustawiana przez CabActivization()
  ActiveCab:=Cab;  //obsada w podanej kabinie
  DirAbsolute:=0;
  SlippingWheels:=false;
  SandDose:=false;
  FuseFlag:=false;
  ConvOvldFlag:=false;   //hunter-251211
  StLinFlag:=false;
  ResistorsFlag:=false;
  Rventrot:=0;
  enrot:=0;
  nrot:=0;
  Itot:=0;
  EnginePower:=0;
  BrakePress:=0;
  Compressor:=0;
  ConverterFlag:=false;
  CompressorAllow:=false;
  DoorLeftOpened:=false;
  DoorRightOpened:=false;
  battery:=false;
  EpFuse:=true;
  Signalling:=false;
  Radio:=true;
  DoorSignalling:=false;
  UnBrake:=false;
//Winger 160204
  PantVolume:=0.48; //aby podniesione pantografy opadły w krótkim czasie przy wyłączonej sprężarce
  PantFrontUp:=false;
  PantRearUp:=false;
  PantFrontStart:=0;
  PantRearStart:=0;
  PantFrontSP:=true;
  PantRearSP:=true;
  DoubleTr:=1;
  BrakeSlippingTimer:=0;
  dpBrake:=0; dpPipe:=0; dpMainValve:=0; dpLocalValve:=0;
  MBPM:=1;
  DynamicBrakeFlag:=false;
  BrakeSystem:=Individual;
  BrakeSubsystem:=ss_None;
  Ft:=0; Ff:=0; Fb:=0;
  Ftotal:=0; FStand:=0; FTrain:=0;
  AccS:=0; AccN:=0; AccV:=0;
  EventFlag:=false; SoundFlag:=0;
  Vel:=Abs(VelInitial); V:=VelInitial/3.6;
  LastSwitchingTime:=0;
  LastRelayTime:=0;
  DistCounter:=0;
  PulseForce:=0;
  PulseForceTimer:=0;
  PulseForceCount:=0;
  eAngle:=1.5;
  dizel_fill:=0;
  dizel_engagestate:=0;
  dizel_engage:=0;
  dizel_automaticgearstatus:=0;
  dizel_enginestart:=false;
  dizel_engagedeltaomega:=0;
  PhysicActivation:=true;
  for b:=1 to 20 do
    eimv[b]:=0;

  with RunningShape do
   begin
     R:=0; Len:=1; dHtrack:=0; dHrail:=0;
   end;
 RunningTrack.CategoryFlag:=CategoryFlag;
  with RunningTrack do
   begin
     Width:=TrackW; friction:=Steel2Steel_friction;
     QualityFlag:=20;
     DamageFlag:=0;
     Velmax:=100; {dla uzytku maszynisty w ai_driver}
   end;
  with RunningTraction do
   begin
      TractionVoltage:=0;
      TractionFreq:=0;
      TractionMaxCurrent:=0;
      TractionResistivity:=1;
   end;
  OffsetTrackH:=0; OffsetTrackV:=0;
  with CommandIn do
   begin
     Command:='';
     Value1:=0; Value2:=0;
     Location.x:=0; Location.y:=0; Location.z:=0;
   end;

   {czesciowo stale, czesciowo zmienne}
   with SecuritySystem do
    begin
      SystemType:=0;
      AwareDelay:=-1; SoundSignalDelay:=-1; EmergencyBrakeDelay:=-1;
      Status:=0;
      SystemTimer:=0; SystemBrakeCATimer:=0; SystemBrakeSHPTimer:=0; //hunter-091012
      VelocityAllowed:=-1; NextVelocityAllowed:=-1;
      RadioStop:=false; //domyślnie nie ma
      AwareMinSpeed:=0.1*Vmax;
    end;
    //ABu 240105:
    //CouplerNr[0]:=1;
    //CouplerNr[1]:=0;

{TO POTEM TU UAKTYWNIC A WYWALIC Z CHECKPARAM}
{
  if Pos(LoadTypeInitial,LoadAccepted)>0 then
   begin
}
     LoadType:=LoadTypeInitial;
     Load:=LoadInitial;
     LoadStatus:=0;
     LastLoadChangeTime:=0;
{
   end
  else Load:=0;
 }

  Name:=NameInit;
 DerailReason:=0; //Ra: powód wykolejenia
 TotalCurrent:=0;
 ShuntModeAllow:=false;
 ShuntMode:=false;
end;

function T_MoverParameters.EngineDescription(what:integer): string;  {opis stanu lokomotywy}
var outstr: string;
begin
  outstr:='';
  case what of
   0: begin
        if DamageFlag=255 then
         outstr:='Totally destroyed!'
        else
         begin
           if TestFlag(DamageFlag,dtrain_thinwheel) then
            if Power>0.1 then
             outstr:='Thin wheel,'
            else
             outstr:='Load shifted,';
           if TestFlag(DamageFlag,dtrain_wheelwear) then
             outstr:='Wheel wear,';
           if TestFlag(DamageFlag,dtrain_bearing) then
             outstr:='Bearing damaged,';
           if TestFlag(DamageFlag,dtrain_coupling) then
             outstr:='Coupler broken,';
           if TestFlag(DamageFlag,dtrain_loaddamage) then
            if Power>0.1 then
             outstr:='Ventilator damaged,'
            else
             outstr:='Load damaged,';
           if TestFlag(DamageFlag,dtrain_loaddestroyed) then
            if Power>0.1 then
             outstr:='Engine damaged,'
            else
             outstr:='Load destroyed!,';
           if TestFlag(DamageFlag,dtrain_axle) then
             outstr:='Axle broken,';
           if TestFlag(DamageFlag,dtrain_out) then
             outstr:='DERAILED!';
           if outstr='' then
            outstr:='OK!';
         end;
      end;
   else outstr:='Invalid qualifier';
  end;
  EngineDescription:=outstr;
end;

function T_MoverParameters.CheckLocomotiveParameters(ReadyFlag:boolean;Dir:longint): boolean;
var //k:integer;
    OK:boolean;
    b:byte;
    bcmsno: byte;
    bcmss: byte;
const
    DefBrakeTable:array[1..8]of Byte=(15,4,25,25,13,3,12,2);
begin
  OK:=true;
  AutoRelayFlag:=(AutoRelayType=1);
  Sand:=SandCapacity;
  if (Pos('o',AxleArangement)>0) and (EngineType=ElectricSeriesMotor) then
   OK:=(RList[1].Bn*RList[1].Mn=NPoweredAxles); {test poprawnosci ilosci osi indywidualnie napedzanych}
  if (Pos(LoadType,LoadAccepted)=0) and (LoadType<>'') then
   begin
     Load:=0;
     OK:=false;
   end;
  if BrakeSystem=Individual then
   if BrakeSubSystem<>ss_None then
    OK:=false; {!}

 if(BrakeVVolume=0)and(MaxBrakePress[3]>0)and(BrakeSystem<>Individual)then
   BrakeVVolume:=MaxBrakePress[3]/(5-MaxBrakePress[3])*(BrakeCylRadius*BrakeCylRadius*BrakeCylDist*BrakeCylNo*pi)*1000;
 if BrakeVVolume=0 then BrakeVVolume:=0.01;

//  Hamulec.Free;
//(i_mbp, i_bcr, i_bcd, i_brc: real; i_bcn, i_BD, i_mat, i_ba, i_nbpa: byte)

case BrakeValve of
  W, K : begin
          Hamulec := TWest.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA);
          if(MBPM<2)then //jesli przystawka wazaca
           (Hamulec as TWest).SetLP(0,MaxBrakePress[3],0)
          else
           (Hamulec as TWest).SetLP(Mass, MBPM, MaxBrakePress[1]);
         end;
  KE :   begin
          Hamulec := TKE.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA);
         (Hamulec as TKE).SetRM(RapidMult);
          if(MBPM<2)then //jesli przystawka wazaca
           (Hamulec as TKE).SetLP(0,MaxBrakePress[3],0)
         else
           (Hamulec as TKE).SetLP(Mass, MBPM, MaxBrakePress[1])
         end;
  NEst3, ESt3, ESt3AL2, ESt4:
         begin
          Hamulec := TNESt3.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA);
         (Hamulec as TNEst3).SetSize(BrakeValveSize,BrakeValveParams);
          if(MBPM<2)then //jesli przystawka wazaca
           (Hamulec as TNESt3).SetLP(0,MaxBrakePress[3],0)
         else
           (Hamulec as TNESt3).SetLP(Mass, MBPM, MaxBrakePress[1])
         end;
{  ESt3, ESt3AL2: if (MaxBrakePress[1])>0 then
         begin
          Hamulec := TESt3AL2.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA);
          if(MBPM<2)then
         (Hamulec as TESt3AL2).SetLP(0,MaxBrakePress[3],0)
         else
         (Hamulec as TESt3AL2).SetLP(Mass, MBPM, MaxBrakePress[1])
         end
        else
          Hamulec := TESt3.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA);}
  LSt   :begin
          Hamulec :=  TLSt.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA);
          (Hamulec as TLSt).SetRM(RapidMult);
         end;
  EStED :begin
          Hamulec :=  TEStED.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA);
          (Hamulec as TEStED).SetRM(RapidMult);
          if(MBPM<2)then //jesli przystawka wazaca
           (Hamulec as TEStED).SetLP(0,MaxBrakePress[3],0)
          else
           (Hamulec as TEStED).SetLP(Mass, MBPM, MaxBrakePress[1]);
         end;
  EP2:begin
         Hamulec :=TEStEP2.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA);
         (Hamulec as TEStEP2).SetLP(Mass, MBPM, MaxBrakePress[1]);
        end;
{  ESt4  :if (BrakeDelays and bdelay_R)=bdelay_R then
           Hamulec:=TESt4R.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA)
         else
           Hamulec:= TESt.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA);}
  CV1  :  Hamulec:= TCV1.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA);
  CV1_L_TR:Hamulec:= TCV1L_TR.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA)
else
  Hamulec :=  TBrake.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA);
end;
Hamulec.SetASBP(MaxBrakePress[4]);

case BrakeHandle of
  FV4a: Handle := TFV4aM.Create;
  MHZ_EN57: Handle := TMHZ_EN57.Create;  
  FVel6: Handle := TFVel6.Create;
  testH: Handle := Ttest.Create;
  M394: Handle := TM394.Create;
  Knorr: Handle := TH14K1.Create;
  St113: Handle := TSt113.Create;
else
  Handle := THandle.Create;
end;

case BrakeLocHandle of
  FD1:
   begin
    LocHandle := TFD1.Create;
    LocHandle.Init(MaxBrakePress[0]);
    if(TrainType=dt_EZT)then
      (LocHandle as TFD1).SetSpeed(3.5);
   end;
  Knorr:
   begin
    LocHandle := TH1405.Create;
    LocHandle.Init(MaxBrakePress[0]);
   end;
else
  LocHandle := THandle.Create;
end;

//ustalanie srednicy przewodu glownego (lokomotywa lub napędowy
  if (TestFlag(BrakeDelays,bdelay_G))and((not TestFlag(BrakeDelays,bdelay_R)) or (Power>1))then
    Spg:=0.792
  else
    Spg:=0.507;

  Pipe:= TReservoir.Create;
  Pipe2:= TReservoir.Create;  //zabezpieczenie, bo sie PG wywala... :(
  Pipe.CreateCap((Max0R(Dim.L,14)+0.5)*Spg*1); //dlugosc x przekroj x odejscia i takie tam
  Pipe2.CreateCap((Max0R(Dim.L,14)+0.5)*Spg*1);

   if LightsPosNo>0 then LightsPos:=LightsDefPos;

{to dac potem do init}
  if ReadyFlag then     {gotowy do drogi}
   begin
     CompressedVolume:=VeselVolume*MinCompressor*(9.8+Random)/10;
     ScndPipePress:=CompressedVolume/VeselVolume;
     PipePress:=CntrlPipePress;
     BrakePress:=0;
     LocalBrakePos:=0;
//     if (BrakeSystem=Pneumatic) and (BrakeCtrlPosNo>0) then
      if CabNo=0 then
//       BrakeCtrlPos:=-2; //odcięcie na zespolonym; Ra: hamulec jest poprawiany w DynObj.cpp
       BrakeCtrlPos:=Trunc(Handle.GetPos(bh_NP))
     else
       BrakeCtrlPos:=Trunc(Handle.GetPos(bh_RP));
     MainSwitch(false);
     PantFront(true);
     PantRear(true);
     MainSwitch(true);
     ActiveDir:=0; //Dir; //nastawnik kierunkowy - musi być ustawiane osobno!
     DirAbsolute:=ActiveDir*CabNo; //kierunek jazdy względem sprzęgów
     LimPipePress:=CntrlPipePress;
   end
  else
   begin                {zahamowany}
     Volume:=BrakeVVolume*MaxBrakePress[3];
     CompressedVolume:=VeselVolume*MinCompressor*0.55;
     ScndPipePress:=5.1;
     PipePress:=LowPipePress;
     PipeBrakePress:=MaxBrakePress[3]*0.5;
     BrakePress:=MaxBrakePress[3]*0.5;
     LocalBrakePos:=0;
//     if (BrakeSystem=Pneumatic) and (BrakeCtrlPosNo>0) then
//      BrakeCtrlPos:=-2; //Ra: hamulec jest poprawiany w DynObj.cpp
     BrakeCtrlPos:=Trunc(Handle.GetPos(bh_NP));
     LimPipePress:=LowPipePress;
   end;
  ActFlowSpeed:=0;
  BrakeCtrlPosR:=BrakeCtrlPos;

  if(BrakeLocHandle=Knorr)then
    LocalBrakePos:=5;

  Pipe.CreatePress(PipePress);
  Pipe2.CreatePress(ScndPipePress);
  Pipe.Act;Pipe2.Act;

  EqvtPipePress:=PipePress;

////  fv4ac:=Pipe.P;
////  fv4ar:=Pipe.P;

  Handle.Init(PipePress);

  ComputeConstans();


  if(LoadFlag>0)then
     begin
    if(Load<MaxLoad*0.45)then
     begin
      IncBrakeMult();IncBrakeMult();DecBrakeMult();
      if(Load<MaxLoad*0.35)then
        DecBrakeMult();
     end;
    if(Load>=MaxLoad*0.45)then
     begin
      IncBrakeMult();
      if(Load>=MaxLoad*0.55)then
        IncBrakeMult();
     end;
  end;

//taki mini automat - powinno byc ladnie dobrze :)
    BrakeDelayFlag:=bdelay_P;
  if(TestFlag(BrakeDelays,bdelay_G))and not(TestFlag(BrakeDelays,bdelay_R))then
    BrakeDelayFlag:=bdelay_G;
  if(TestFlag(BrakeDelays,bdelay_R))and not(TestFlag(BrakeDelays,bdelay_G))then
    BrakeDelayFlag:=bdelay_R;

//ustawianie PS/PN/EP/MED
  BrakeOpModeFlag:=bom_PN;
  if (BrakeOpModes and bom_PS)>0 then BrakeOpModeFlag:=bom_PS;
//  if (BrakeOpModes and bom_EP)>0 then BrakeOpModeFlag:=bom_EP;
//  if (BrakeOpModes and bom_MED)>0 then BrakeOpModeFlag:=bom_MED;
//
//yB: jesli pojazdy nie maja zadeklarowanych czasow, to wsadz z przepisow +-16,(6)%
  for b:=1 to 4 do
   begin
     if BrakeDelay[b]=0 then
       BrakeDelay[b]:=DefBrakeTable[b];
     BrakeDelay[b]:=BrakeDelay[b]*(2.5+Random)/3.0;
   end;

  if(TrainType=dt_ET22)then
    CompressorPower:=0;

//  Hamulec.Init(10*PipePress, 10*HighPipePress-0.15, 10*LowPipePress-0.15, 10*BrakePress, BrakeDelayFlag);
  Hamulec.Init(PipePress, HighPipePress, LowPipePress, BrakePress, BrakeDelayFlag);
//  Hamulec.Init(0, 0, -1.5, 0, BrakeDelayFlag);
//  PipePress:=PipePress;
  ScndPipePress:=Compressor;
  CheckLocomotiveParameters:=OK;
end;

function T_MoverParameters.DoorLeft(State: Boolean):Boolean;
begin
 if (DoorLeftOpened<>State) and (DoorBlockedFlag=false) and (Battery=true) then
 begin
  DoorLeft:=true;
  DoorLeftOpened:=State;
  if (State=true) then
   begin
    if (CabNo>0) then
     SendCtrlToNext('DoorOpen',1,CabNo) //1=lewe, 2=prawe
    else
     SendCtrlToNext('DoorOpen',2,CabNo); //zamiana
    CompressedVolume:=CompressedVolume-0.003;
   end
  else
   begin
    if (CabNo>0) then
     SendCtrlToNext('DoorClose',1,CabNo)
    else
     SendCtrlToNext('DoorClose',2,CabNo);
   end;
  end
  else
    DoorLeft:=false;
end;

function T_MoverParameters.DoorRight(State: Boolean):Boolean;
begin
 if (DoorRightOpened<>State) and (DoorBlockedFlag=false) and (Battery=true) then
  begin
  DoorRight:=true;
  DoorRightOpened:=State;
  if (State=true) then
   begin
    if (CabNo>0) then
     SendCtrlToNext('DoorOpen',2,CabNo) //1=lewe, 2=prawe
    else
     SendCtrlToNext('DoorOpen',1,CabNo); //zamiana
    CompressedVolume:=CompressedVolume-0.003;
   end
  else
   begin
    if (CabNo>0) then
     SendCtrlToNext('DoorClose',2,CabNo)
    else
     SendCtrlToNext('DoorClose',1,CabNo);
   end;
 end
 else
  DoorRight:=false;
end;

//Winger 160204 - pantografy
function T_MoverParameters.PantFront(State: Boolean):Boolean;
var pf1: Real;
begin
if (battery=true){ and ((TrainType<>dt_ET40)or ((TrainType=dt_ET40) and (EnginePowerSource.CollectorsNo>1)))}then
begin
 PantFront:=true;
 if (State=true) then pf1:=1
  else pf1:=0;
 if (PantFrontUp<>State) then
  begin
  PantFrontUp:=State;
  if (State=true) then
   begin
    PantFrontStart:=0;
    SendCtrlToNext('PantFront',1,CabNo);
   end
  else
   begin
      PantFront:=false;
      PantFrontStart:=1;
      SendCtrlToNext('PantFront',0,CabNo);
{Ra: nie ma potrzeby opuszczać obydwu na raz, jak mozemy każdy osobno
      if (TrainType=dt_EZT) and (ActiveCab=1) then
       begin
        PantRearUp:=false;
        PantRearStart:=1;
        SendCtrlToNext('PantRear',0,CabNo);
       end;
}
   end;
 end
 else
 SendCtrlToNext('PantFront',pf1,CabNo);
end
end;

function T_MoverParameters.PantRear(State: Boolean):Boolean;
var pf1: Real;
begin
if battery=true then
 begin
 PantRear:=true;
 if (State=true) then pf1:=1
 else pf1:=0;
 if (PantRearUp<>State) then
  begin
  PantRearUp:=State;
  if (State=true) then
   begin
     PantRearStart:=0;
     SendCtrlToNext('PantRear',1,CabNo);
   end
  else
   begin
     PantRear:=false;
     PantRearStart:=1;
     SendCtrlToNext('PantRear',0,CabNo);
   end;
 end
 else
  SendCtrlToNext('PantRear',pf1,CabNo);
 end
end;



{function T_MoverParameters.Heating(State: Boolean):Boolean;
begin
 if (Heating<>State) then
  begin
  Heating:=State;
{  if (State=true) then
   begin
//     SendCtrlToNext('PantRear',1,CabNo);
   end
  else
   begin
//    SendCtrlToNext('PantRear',0,CabNo);
   end; }
{   end
{ else
  SendCtrlToNext('PantRear',0,CabNo); }
{end;}

function T_MoverParameters.LoadChkFile(chkpath:string):Boolean;
const param_ok=1; wheels_ok=2; dimensions_ok=4;
var
  lines,s: string;
  bl,i,k:integer;
  b,OKflag:byte;
  fin: text;
  OK: boolean;
procedure BrakeValveDecode(s:string);
begin
   if s='W' then
     BrakeValve:=W
   else if s='W_Lu_L' then
     BrakeValve:=W_Lu_L
   else if s='W_Lu_XR' then
     BrakeValve:=W_Lu_XR
   else if s='W_Lu_VI' then
     BrakeValve:=W_Lu_VI
   else if s='K' then
     BrakeValve:=W
   else if s='Kkg' then
     BrakeValve:=Kkg
   else if s='Kkp' then
     BrakeValve:=Kkp
   else if s='Kks' then
     BrakeValve:=Kks
   else if s='Hikp1' then
     BrakeValve:=Hikp1
   else if s='Hikss' then
     BrakeValve:=Hikss
   else if s='Hikg1' then
     BrakeValve:=Hikg1
   else if s='KE' then
     BrakeValve:=KE
   else if s='EStED' then
     BrakeValve:=EStED
   else if Pos('ESt',s)>0 then
     BrakeValve:=ESt3
   else if s='LSt' then
     BrakeValve:=LSt
   else if s='EP2' then
     BrakeValve:=EP2
   else if s='EP1' then
     BrakeValve:=EP1
   else if s='CV1' then
     BrakeValve:=CV1
   else if s='CV1_L_TR' then
     BrakeValve:=CV1_L_TR
   else
     BrakeValve:=Other;
end;
procedure BrakeSubsystemDecode;
begin
  case BrakeValve of
    W,W_Lu_L,W_Lu_VI,W_Lu_XR: BrakeSubsystem:=ss_W;
    ESt3,ESt3AL2,ESt4,EP2,EP1: BrakeSubsystem:=ss_ESt;                                                
    KE: BrakeSubsystem:=ss_KE;
    CV1, CV1_L_TR: BrakeSubsystem:=ss_Dako;
    LSt, EStED: BrakeSubsystem:=ss_LSt;
  else
    BrakeSubsystem:=ss_None;
  end;
end;
function EngineDecode(s:string):TEngineTypes;
 begin
   if s='ElectricSeriesMotor' then
    EngineDecode:=ElectricSeriesMotor
   else if s='DieselEngine' then
    EngineDecode:=DieselEngine
   else if s='SteamEngine' then
    EngineDecode:=SteamEngine
   else if s='WheelsDriven' then
    EngineDecode:=WheelsDriven
   else if s='Dumb' then
    EngineDecode:=Dumb
   else if s='DieselElectric' then
    EngineDecode:=DieselElectric    //youBy: spal-ele
   else if s='DumbDE' then
    EngineDecode:=DieselElectric    //youBy: spal-ele
   else if s='ElectricInductionMotor' then
    EngineDecode:=ElectricInductionMotor
{   else if s='EZT' then {dla kibla}
 {   EngineDecode:=EZT      }
   else EngineDecode:=None;
 end;
function PowerSourceDecode(s:string):TPowerSource;
 begin
   if s='Transducer' then PowerSourceDecode:=Transducer
   else if s='Generator' then PowerSourceDecode:=Generator
   else if s='Accu' then PowerSourceDecode:=Accumulator
   else if s='CurrentCollector' then PowerSourceDecode:=CurrentCollector
   else if s='PowerCable' then PowerSourceDecode:=PowerCable
   else if s='Heater' then PowerSourceDecode:=Heater
   else if s='Internal' then PowerSourceDecode:=InternalSource
   else PowerSourceDecode:=NotDefined;
 end;
function PowerDecode(s:string): TPowerType;
 begin
   if s='BioPower' then PowerDecode:=BioPower
   else if s='BioPower' then PowerDecode:=BioPower
   else if s='MechPower' then PowerDecode:=MechPower
   else if s='ElectricPower' then PowerDecode:=ElectricPower
   else if s='SteamPower' then PowerDecode:=SteamPower
   else PowerDecode:=NoPower;
 end;
 procedure PowerParamDecode(lines,prefix:string; var PowerParamDecode:TPowerParameters);
  begin
    with PowerParamDecode do
     begin
       case SourceType of
        NotDefined : PowerType:=PowerDecode(DUE(ExtractKeyWord(lines,prefix+'PowerType=')));
        InternalSource : PowerType:=PowerDecode(DUE(ExtractKeyWord(lines,prefix+'PowerType=')));
        Transducer : InputVoltage:=s2rE(DUE(ExtractKeyWord(lines,prefix+'TransducerInputV=')));
        Generator  : GeneratorEngine:=EngineDecode(DUE(ExtractKeyWord(lines,prefix+'GeneratorEngine=')));
        Accumulator: begin
                       RAccumulator.MaxCapacity:=s2r(DUE(ExtractKeyWord(lines,prefix+'Cap=')));
                       s:=DUE(ExtractKeyWord(lines,prefix+'RS='));
                       RAccumulator.RechargeSource:=PowerSourceDecode(s);
                     end;
        CurrentCollector: begin
                            with CollectorParameters do
                             begin
                               CollectorsNo:=s2lE(DUE(ExtractKeyWord(lines,'CollectorsNo=')));
                               MinH:=s2rE(DUE(ExtractKeyWord(lines,'MinH=')));
                               MaxH:=s2rE(DUE(ExtractKeyWord(lines,'MaxH=')));
                               CSW:=s2rE(DUE(ExtractKeyWord(lines,'CSW='))); //szerokość części roboczej
                               MaxV:=s2rE(DUE(ExtractKeyWord(lines,'MaxVoltage=')));
                               s:=ExtractKeyWord(lines,'OverVoltProt='); //przekaźnik nadnapięciowy
                               if s='Yes' then
                                OVP:=1
                               else
                                OVP:=0; 
                               s:=ExtractKeyWord(lines,'MinV='); //napięcie rozłączające WS
                               if s='' then
                                MinV:=0.5*MaxV //gdyby parametr nie podany
                               else
                                MinV:=s2rE(DUE(s));
                               s:=ExtractKeyWord(lines,'InsetV='); //napięcie wymagane do załączenia WS
                               if s='' then
                                InsetV:=0.6*MaxV //gdyby parametr nie podany
                               else
                                InsetV:=s2rE(DUE(s));
                               s:=ExtractKeyWord(lines,'MinPress='); //ciśnienie rozłączające WS
                               if s='' then
                                MinPress:=2.0 //domyślnie 2 bary do załączenia WS
                               else
                                MinPress:=s2rE(DUE(s));
                               s:=ExtractKeyWord(lines,'MaxPress='); //maksymalne ciśnienie za reduktorem
                               if s='' then
                                MaxPress:=5.0+0.001*(random(50)-random(50))
                               else
                                MaxPress:=s2rE(DUE(s));
                             end;
                          end;
        PowerCable : begin
                       RPowerCable.PowerTrans:=PowerDecode(DUE(ExtractKeyWord(lines,prefix+'PowerTrans=')));
                       if RPowerCable.PowerTrans=SteamPower then
                        RPowerCable.SteamPressure:=s2r(DUE(ExtractKeyWord(lines,prefix+'SteamPress=')));
                     end;
        Heater : begin
                   {jeszcze nie skonczone!}
                 end;
       end;
       if (SourceType<>Heater) and (SourceType<>InternalSource) then
        if not ((SourceType=PowerCable) and (RPowerCable.PowerTrans=SteamPower)) then
        begin
{          PowerTrans:=ElectricPower; }
          MaxVoltage:=s2rE(DUE(ExtractKeyWord(lines,prefix+'MaxVoltage=')));
          MaxCurrent:=s2r(DUE(ExtractKeyWord(lines,prefix+'MaxCurrent=')));
          IntR:=s2r(DUE(ExtractKeyWord(lines,prefix+'IntR=')));
        end;
     end;
  end;
begin
  //OK:=true;
  OKflag:=0;
  LineCount:=0;
  ConversionError:=666;
  Mass:=0;
  filename:=chkpath+TypeName+'.fiz';//'.chk';
  assignfile(fin,filename);
{$I-}
  reset(fin);
{$I+}
  if IOresult<>0 then
   begin
     OK:=false;
     ConversionError:=-8;
   end
  else
   begin
     ConversionError:=0;
     while not (eof(fin) or (ConversionError<>0)) do
      begin
        readln(fin,lines);
        inc(LineCount);
        if Pos('/',lines)=0 then {nie komentarz}
        begin
          if Pos('Param.',lines)>0 then      {stale parametry}
            begin
              SetFlag(OKFlag,param_ok);
              s:=DUE(ExtractKeyWord(lines,'Category='));
              if s='train' then
               CategoryFlag:=1
              else if s='road' then
               CategoryFlag:=2
              else if s='ship' then
               CategoryFlag:=4
              else if s='airplane' then
               CategoryFlag:=8
              else if s='unimog' then
               CategoryFlag:=3
              else
               ConversionError:=-7;
              s:=ExtractKeyWord(lines,'M=');
              Mass:=s2rE(DUE(s));         {w kg}
              s:=ExtractKeyWord(lines,'Mred='); {zredukowane masy wirujące}
              if s='' then
               Mred:=0
              else
               Mred:=s2rE(DUE(s));         {w kg}
              s:=ExtractKeyWord(lines,'Vmax=');
              Vmax:=s2rE(DUE(s));     {w km/h}
              s:=ExtractKeyWord(lines,'PWR=');
              Power:=s2r(DUE(s));         {w kW}
              s:=ExtractKeyWord(lines,'HeatingP=');
              HeatingPower:=s2r(DUE(s));  {w kW}
              s:=ExtractKeyWord(lines,'LightP=');
              LightPower:=s2r(DUE(s));    {w kW}
              s:=ExtractKeyWord(lines,'SandCap=');
              SandCapacity:=s2i(DUE(s));  {w kg}
              TrainType:=dt_Default;
              s:=Ups(DUE(ExtractKeyWord(lines,'Type='))); //wielkimi
              if s='EZT' then
               begin
                TrainType:=dt_EZT;
                IminLo:=1;IminHi:=2;Imin:=1; //wirtualne wartości dla rozrządczego
               end
              else if s='ET41' then TrainType:=dt_ET41
              else if s='ET42' then TrainType:=dt_ET42
              else if s='ET22' then TrainType:=dt_ET22
              else if s='ET40' then TrainType:=dt_ET40
              else if s='EP05' then TrainType:=dt_EP05
              else if s='SN61' then TrainType:=dt_SN61
              else if s='PSEUDODIESEL' then TrainType:=dt_PseudoDiesel
              else if s='181' then TrainType:=dt_181
              else if s='182' then TrainType:=dt_181; {na razie tak}
            end
          else if Pos('Load:',lines)>0 then      {stale parametry}
            begin
              LoadAccepted:=LowerCase(DUE(ExtractKeyWord(lines,'LoadAccepted=')));
              if LoadAccepted<>'' then
               begin
                 s:=ExtractKeyWord(lines,'MaxLoad=');
                 MaxLoad:=s2lE(DUE(s));
                 LoadQuantity:=DUE(ExtractKeyWord(lines,'LoadQ='));
                 s:=ExtractKeyWord(lines,'OverLoadFactor=');
                 OverLoadFactor:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'LoadSpeed=');
                 LoadSpeed:=s2rE(DUE(s));
                 s:=ExtractKeyWord(lines,'UnLoadSpeed=');
                 UnLoadSpeed:=s2rE(DUE(s));
               end;
            end
          else if Pos('Dimensions:',lines)>0 then      {wymiary}
           begin
            with Dim do
             begin
              SetFlag(OKFlag,dimensions_ok);
              s:=ExtractKeyWord(lines,'L=');
              L:=s2rE(DUE(s));
              s:=ExtractKeyWord(lines,'H=');
              H:=s2rE(DUE(s));
              s:=ExtractKeyWord(lines,'W=');
              W:=s2rE(DUE(s));
              s:=ExtractKeyWord(lines,'Cx=');
              Cx:=s2r(DUE(s));
              if Cx=0 then Cx:=0.3;
              s:=ExtractKeyWord(lines,'Floor=');
              if s='' then
               begin
                if (H<=2.0) then
                 Floor:=H //gdyby nie było parametru, lepsze to niż zero
                else
                 Floor:=0.0; //zgodność wsteczna
               end
              else
               Floor:=s2rE(DUE(s));
             end;
           end
          else if Pos('Wheels:',lines)>0 then      {kola}
            begin
{              SetFlag(OKFlag,wheels_ok);}
              s:=ExtractKeyWord(lines,'D='); //średnica osi napędzających
              WheelDiameter:=s2rE(DUE(s));
              s:=ExtractKeyWord(lines,'Dl='); //średnica przednich osi tocznych
              if s='' then
               WheelDiameterL:=WheelDiameter //gdyby nie było parametru, lepsze to niż zero
              else
               WheelDiameterL:=s2rE(DUE(s));
              s:=ExtractKeyWord(lines,'Dt='); //średnica tylnych osi tocznych
              if s='' then
               WheelDiameterT:=WheelDiameter //gdyby nie było parametru, lepsze to niż zero
              else
               WheelDiameterT:=s2rE(DUE(s));
              s:=ExtractKeyWord(lines,'Tw=');
              TrackW:=s2rE(DUE(s));
              s:=ExtractKeyWord(lines,'AIM=');
              AxleInertialMoment:=s2r(DUE(s));
              if AxleInertialMoment<=0 then AxleInertialMoment:=1;
              AxleArangement:=DUE(ExtractKeyWord(lines,'Axle='));
              NPoweredAxles:=s2NPW(AxleArangement);
              NAxles:=NPoweredAxles+s2NNW(AxleArangement);
              if NAxles=0 then ConversionError:=-1;
              s:=DUE(ExtractKeyWord(lines,'BearingType='));
              if s='Roll' then BearingType:=1
              else BearingType:=0;
              s:=ExtractKeyWord(lines,'Ad=');
              ADist:=s2rE(DUE(s));
              s:=ExtractKeyWord(lines,'Bd=');
              BDist:=s2r(DUE(s));
            end
          else if Pos('Brake:',lines)>0 then      {hamulce}
            begin
              BrakeValveParams:=DUE(ExtractKeyWord(lines,'BrakeValve='));
              BrakeValveDecode(BrakeValveParams);
              BrakeSubSystemDecode;
              s:=ExtractKeyWord(lines,'NBpA=');
              NBpA:=s2b(DUE(s));
              s:=ExtractKeyWord(lines,'MBF=');
              MaxBrakeForce:=s2r(DUE(s));
              s:=ExtractKeyWord(lines,'Size=');
              BrakeValveSize:=s2i(DUE(s));
              s:=ExtractKeyWord(lines,'TBF=');
              TrackBrakeForce:=s2r(DUE(s))*1000;
              s:=ExtractKeyWord(lines,'MaxBP=');
              MaxBrakePress[3]:=s2r(DUE(s));
              if MaxBrakePress[3]>0 then
               begin
                 s:=ExtractKeyWord(lines,'BCN=');
                 BrakeCylNo:=s2iE(DUE(s));
                 if BrakeCylNo>0 then
                  begin
                   s:=ExtractKeyWord(lines,'MaxLBP=');
                   MaxBrakePress[0]:=s2r(DUE(s));
                   if MaxBrakePress[0]<0.01 then
                   MaxBrakePress[0]:=MaxBrakePress[3];
                   s:=DUE(ExtractKeyWord(lines,'TareMaxBP='));
                   MaxBrakePress[1]:=s2r(s);
                   s:=DUE(ExtractKeyWord(lines,'MedMaxBP='));
                   MaxBrakePress[2]:=s2r(s);
                   s:=ExtractKeyWord(lines,'MaxASBP=');
                   MaxBrakePress[4]:=s2r(DUE(s));
                   if MaxBrakePress[4]<0.01 then
                   MaxBrakePress[4]:=0;
                   s:=ExtractKeyWord(lines,'BCR=');
                   BrakeCylRadius:=s2rE(DUE(s));
                   s:=ExtractKeyWord(lines,'BCD=');
                   BrakeCylDist:=s2r(DUE(s));
                   s:=ExtractKeyWord(lines,'BCS=');
                   BrakeCylSpring:=s2r(DUE(s));
                   s:=ExtractKeyWord(lines,'BSA=');
                   BrakeSlckAdj:=s2r(DUE(s));
                   s:=ExtractKeyWord(lines,'BRE=');
                   if s<>'' then
                     BrakeRigEff:=s2r(DUE(s))
                   else
                     BrakeRigEff:=1;
                   s:=ExtractKeyWord(lines,'BCM=');
                   BrakeCylMult[0]:=s2r(DUE(s));
                   s:=ExtractKeyWord(lines,'BCMlo=');
                   BrakeCylMult[1]:=s2r(DUE(s));
                   s:=ExtractKeyWord(lines,'BCMHi=');
                   BrakeCylMult[2]:=s2r(DUE(s));
                   P2FTrans:=100*Pi*SQR(BrakeCylRadius); {w kN/bar}
                   if (BrakeCylMult[1]>0) or (MaxBrakePress[1]>0) then LoadFlag:=1 else LoadFlag:=0;
                   BrakeVolume:=Pi*SQR(BrakeCylRadius)*BrakeCylDist*BrakeCylNo;
                   s:=ExtractKeyWord(lines,'BVV=');
                   BrakeVVolume:=s2R(DUE(s));

                   s:=DUE(ExtractKeyWord(lines,'BM='));
                   if s='P10-Bg'    then BrakeMethod:=bp_P10Bg else
                   if s='P10-Bgu'   then BrakeMethod:=bp_P10Bgu else
                   if s='FR513'     then BrakeMethod:=bp_FR513 else
                   if s='FR510'     then BrakeMethod:=bp_FR510 else
                   if s='Cosid'     then BrakeMethod:=bp_Cosid else
                   if s='P10yBg'    then BrakeMethod:=bp_P10yBg else
                   if s='P10yBgu'   then BrakeMethod:=bp_P10yBgu else
                   if s='Disk1'     then BrakeMethod:=bp_D1 else
                   if s='Disk1+Mg'  then BrakeMethod:=bp_D1+bp_MHS else
                   if s='Disk2'     then BrakeMethod:=bp_D2 else                                                         
                                         BrakeMethod:=0;

                   s:=ExtractKeyWord(lines,'RM=');
                   if s<>'' then
                     RapidMult:=s2r(DUE(s))
                   else
                     RapidMult:=1;


                  end
                 else ConversionError:=-5;
               end
              else
               P2FTrans:=0;
              s:=ExtractKeyWord(lines,'HiPP=');
              if s<>'' then CntrlPipePress:=s2r(DUE(s))
               else CntrlPipePress:=5+0.001*(random(10)-random(10)); //Ra 2014-07: trochę niedokładności
              HighPipePress:=CntrlPipePress;
              s:=ExtractKeyWord(lines,'LoPP=');
              if s<>'' then LowPipePress:=s2r(DUE(s))
               else LowPipePress:=Min0R(HighPipePress,3.5);
              DeltaPipePress:=HighPipePress-LowPipePress;
              s:=ExtractKeyWord(lines,'Vv=');
              VeselVolume:=s2r(DUE(s));
              if VeselVolume=0 then
               VeselVolume:=0.01;
              s:=ExtractKeyWord(lines,'MinCP=');
              MinCompressor:=s2r(DUE(s));
              s:=ExtractKeyWord(lines,'MaxCP=');
              MaxCompressor:=s2r(DUE(s));
              s:=ExtractKeyWord(lines,'CompressorSpeed=');
              CompressorSpeed:=s2r(DUE(s));
              s:=DUE(ExtractKeyWord(lines,'CompressorPower='));
              if s='Converter' then
               CompressorPower:=2
              else if s='Engine' then
               CompressorPower:=3
              else if s='Coupler1' then
               CompressorPower:=4 //włączana w silnikowym EZT z przodu
              else if s='Coupler2' then
               CompressorPower:=5 //włączana w silnikowym EZT z tyłu
              else if s='Main' then
               CompressorPower:=0;
            end
          else if Pos('Doors:',lines)>0 then      {drzwi}
            begin
              s:=DUE(ExtractKeyWord(lines,'OpenCtrl='));
              if s='DriverCtrl' then DoorOpenCtrl:=1
              else
               DoorOpenCtrl:=0;
              s:=DUE(ExtractKeyWord(lines,'CloseCtrl='));
              if s='DriverCtrl' then DoorCloseCtrl:=1
              else
               if s='AutomaticCtrl' then DoorCloseCtrl:=2
                else
                 DoorCloseCtrl:=0;
              if DoorCloseCtrl=2 then
               begin
                 s:=ExtractKeyWord(lines,'DoorStayOpen=');
                 DoorStayOpen:=s2rE(DUE(s));
               end;
              s:=ExtractKeyWord(lines,'OpenSpeed=');
              DoorOpenSpeed:=s2r(DUE(s));
              s:=ExtractKeyWord(lines,'CloseSpeed=');
              DoorCloseSpeed:=s2r(DUE(s));
              s:=ExtractKeyWord(lines,'DoorMaxShiftL=');
              DoorMaxShiftL:=s2r(DUE(s));
              s:=ExtractKeyWord(lines,'DoorMaxShiftR=');
              DoorMaxShiftR:=s2r(DUE(s));
              s:=DUE(ExtractKeyWord(lines,'DoorOpenMethod='));
              if s='Shift' then DoorOpenMethod:=1 //przesuw
              else if s='Fold' then DoorOpenMethod:=3 //3 submodele się obracają
              else if s='Plug' then DoorOpenMethod:=4 //odskokowo-przesuwne
              else
               DoorOpenMethod:=2; //obrót
              s:=DUE(ExtractKeyWord(lines,'DoorClosureWarning='));
              if s='Yes' then
               DoorClosureWarning:=true
              else
               DoorClosureWarning:=false;
               s:=DUE(ExtractKeyWord(lines,'DoorBlocked='));
              if s='Yes' then DoorBlocked:=true
              else
                DoorBlocked:=false;
              s:=ExtractKeyWord(lines,'DoorMaxShiftPlug=');
              DoorMaxPlugShift:=s2r(DUE(s));
              s:=ExtractKeyWord(lines,'PlatformSpeed=');
              PlatformSpeed:=s2r(DUE(s));
              s:=ExtractKeyWord(lines,'PlatformMaxSpeed=');
              PlatformMaxShift:=s2r(DUE(s));
              s:=DUE(ExtractKeyWord(lines,'PlatformOpenMethod='));
              if s='Shift' then PlatformOpenMethod:=1 //przesuw
              else
               PlatformOpenMethod:=2; //obrót
            end
          else if (Pos('BuffCoupl.',lines)>0) or (Pos('BuffCoupl1.',lines)>0) then  {zderzaki i sprzegi}
            begin
             with Couplers[0] do
              begin
                s:=DUE(ExtractKeyWord(lines,'CType='));
                if s='Automatic' then
                 CouplerType:=Automatic
                else
                if s='Screw' then
                 CouplerType:=Screw
                else
                if s='Chain' then
                 CouplerType:=Chain
                else
                if s='Bare' then
                 CouplerType:=Bare
                else
                if s='Articulated' then
                 CouplerType:=Articulated
                else
                 CouplerType:=NoCoupler;
                s:=ExtractKeyWord(lines,'AllowedFlag=');
                if s<>'' then AllowedFlag:=s2i(DUE(s));
                if (AllowedFlag<0) then AllowedFlag:=(-AllowedFlag) OR ctrain_depot;
                if (CouplerType<>NoCoupler) and (CouplerType<>Bare) and (CouplerType<>Articulated) then
                 begin
                   s:=ExtractKeyWord(lines,'kC=');
                   SpringKC:=s2rE(DUE(s))*1000;
                   s:=ExtractKeyWord(lines,'DmaxC=');
                   DmaxC:=s2rE(DUE(s));
                   s:=ExtractKeyWord(lines,'FmaxC=');
                   FmaxC:=s2rE(DUE(s))*1000;
                   s:=ExtractKeyWord(lines,'kB=');
                   SpringKB:=s2rE(DUE(s))*1000;
                   s:=ExtractKeyWord(lines,'DmaxB=');
                   DmaxB:=s2rE(DUE(s));
                   s:=ExtractKeyWord(lines,'FmaxB=');
                   FmaxB:=s2rE(DUE(s))*1000;
                   s:=ExtractKeyWord(lines,'beta=');
                   beta:=s2r(DUE(s));
                 end
                else
                 if (CouplerType=Bare) then {Ra: czemu masy bez ładunków?}
                  begin
                    SpringKC:=50*Mass+Ftmax/0.05;
                    DmaxC:=0.05;
                    FmaxC:=100*Mass+2*Ftmax;
                    SpringKB:=60*Mass+Ftmax/0.05;
                    DmaxB:=0.05;
                    FmaxB:=50*Mass+2*Ftmax;
                    beta:=0.3;
                  end
                else
                 if (CouplerType=Articulated) then
                  begin
                    SpringKC:=60*Mass+1000;
                    DmaxC:=0.05;
                    FmaxC:=20000000+2*Ftmax;
                    SpringKB:=70*Mass+1000;
                    DmaxB:=0.05;
                    FmaxB:=4000000+2*Ftmax;
                    beta:=0.55;
                  end;
                end;
                if (Pos('BuffCoupl.',lines)>0) then
                 begin
                   Couplers[1].SpringKC:=Couplers[0].SpringKC;
                   Couplers[1].DmaxC:=Couplers[0].DmaxC;
                   Couplers[1].FmaxC:=Couplers[0].FmaxC;
                   Couplers[1].SpringKB:=Couplers[0].SpringKB;
                   Couplers[1].DmaxB:=Couplers[0].DmaxB;
                   Couplers[1].FmaxB:=Couplers[0].FmaxB;
                   Couplers[1].beta:=Couplers[0].beta;
                   Couplers[1].CouplerType:=Couplers[0].CouplerType;
                   Couplers[1].AllowedFlag:=Couplers[0].AllowedFlag;
                 end;
{                CouplerTune:=(1+Mass)/100000; }
              end
          else if (Pos('BuffCoupl2.',lines)>0) then  {zderzaki i sprzegi jesli sa rozne}
            with Couplers[1] do
              begin
                s:=DUE(ExtractKeyWord(lines,'CType='));
                if s='Automatic' then
                 CouplerType:=Automatic
                else
                if s='Screw' then
                 CouplerType:=Screw
                else
                if s='Chain' then
                 CouplerType:=Chain
                else
                if s='Bare' then
                 CouplerType:=Bare
                else
                if s='Articulated' then
                 CouplerType:=Articulated
                else
                 CouplerType:=NoCoupler;
                s:=ExtractKeyWord(lines,'AllowedFlag=');
                if s<>'' then AllowedFlag:=s2i(DUE(s));
                if (AllowedFlag<0) then AllowedFlag:=(-AllowedFlag) OR ctrain_depot;
                if (CouplerType<>NoCoupler) and (CouplerType<>Bare) and (CouplerType<>Articulated) then
                 begin
                   s:=ExtractKeyWord(lines,'kC=');
                   SpringKC:=s2rE(DUE(s))*1000;
                   s:=ExtractKeyWord(lines,'DmaxC=');
                   DmaxC:=s2rE(DUE(s));
                   s:=ExtractKeyWord(lines,'FmaxC=');
                   FmaxC:=s2rE(DUE(s))*1000;
                   s:=ExtractKeyWord(lines,'kB=');
                   SpringKB:=s2rE(DUE(s))*1000;
                   s:=ExtractKeyWord(lines,'DmaxB=');
                   DmaxB:=s2rE(DUE(s));
                   s:=ExtractKeyWord(lines,'FmaxB=');
                   FmaxB:=s2rE(DUE(s))*1000;
                   s:=ExtractKeyWord(lines,'beta=');
                   beta:=s2r(DUE(s));
                 end
                else
                 if (CouplerType=Bare) then
                  begin
                    SpringKC:=50*Mass+1000;
                    DmaxC:=0.05;
                    FmaxC:=20*Mass+2*Ftmax;
                    SpringKB:=60*Mass+1000;
                    DmaxB:=0.05;
                    FmaxB:=10*Mass+2*Ftmax;
                    beta:=0.3;
                  end
                else
                 if (CouplerType=Articulated) then
                  begin
                    SpringKC:=60*Mass+1000;
                    DmaxC:=0.05;
                    FmaxC:=20000000+2*Ftmax;
                    SpringKB:=70*Mass+1000;;
                    DmaxB:=0.05;
                    FmaxB:=4000000+2*Ftmax;
                    beta:=0.55;
                  end;
{                CouplerTune:=(1+Mass)/100000; }
              end
          else if Pos('TurboPos:',lines)>0 then      {turbo zalezne od pozycji nastawnika}
           begin
            s:=ExtractKeyWord(lines,'TurboPos=');
            TurboTest:=s2b(DUE(s));
           end
          else if Pos('Cntrl.',lines)>0 then      {nastawniki}
            begin
              s:=DUE(ExtractKeyWord(lines,'BrakeSystem='));
              if s='Pneumatic' then BrakeSystem:=Pneumatic
               else if s='ElectroPneumatic' then BrakeSystem:=ElectroPneumatic
                else BrakeSystem:=Individual;
              if BrakeSystem<>Individual then
               begin
                 s:=ExtractKeyWord(lines,'BCPN=');
                 BrakeCtrlPosNo:=s2b(DUE(s));

                 for b:=1 to 4 do
                  begin
                    s:=ExtractKeyWord(lines,'BDelay'+Cut_Space(b2s(b),CutLeft)+'=');
                    BrakeDelay[b]:=s2b(DUE(s));
                  end;

                 s:=DUE(ExtractKeyWord(lines,'BrakeDelays='));
                 if s='GPR' then BrakeDelays:=bdelay_G+bdelay_P+bdelay_R
                 else if s='PR' then BrakeDelays:=bdelay_P+bdelay_R
                 else if s='GP' then BrakeDelays:=bdelay_G+bdelay_P
                 else if s='R' then begin BrakeDelays:=bdelay_R; BrakeDelayFlag:=bdelay_R; end
                 else if s='P' then begin BrakeDelays:=bdelay_P; BrakeDelayFlag:=bdelay_P; end
                 else if s='G' then begin BrakeDelays:=bdelay_G; BrakeDelayFlag:=bdelay_G; end
                 else if s='GPR+Mg' then BrakeDelays:=bdelay_G+bdelay_P+bdelay_R+bdelay_M
                 else if s='PR+Mg' then BrakeDelays:=bdelay_P+bdelay_R+bdelay_M;

                 s:=DUE(ExtractKeyWord(lines,'BrakeOpModes='));
                 if s='PN' then BrakeOpModes:=bom_PS+bom_PN
                 else if s='PNEPMED' then BrakeOpModes:=bom_PS+bom_PN+bom_EP+bom_MED;

{                 else if s='DPR+Mg' then begin Brakedelays:=bdelay_R; BrakeMethod:=3; end
                 else if s='DGPR+Mg' then begin Brakedelays:=bdelay_G+bdelay_R; BrakeMethod:=3; end
                 else if s='DGPR' then begin Brakedelays:=bdelay_G+bdelay_R; BrakeMethod:=1; end
                 else if s='DPR' then begin Brakedelays:=bdelay_R; BrakeMethod:=1; end
                 else if s='DGP' then begin Brakedelays:=bdelay_G; BrakeMethod:=1; end;}
//                  else if s='GPR' then Brakedelays=bdelay_G+bdelay_R

                 s:=DUE(ExtractKeyWord(lines,'BrakeHandle='));
                      if s='FV4a' then BrakeHandle:=FV4a
                 else if s='test' then BrakeHandle:=testH
                 else if s='D2' then BrakeHandle:=D2
                 else if s='MHZ_EN57' then BrakeHandle:=MHZ_EN57                 
                 else if s='M394' then BrakeHandle:=M394
                 else if s='Knorr' then BrakeHandle:=Knorr
                 else if s='Westinghouse' then BrakeHandle:=West
                 else if s='FVel6' then BrakeHandle:=FVel6
                 else if s='St113' then BrakeHandle:=St113;

                 s:=DUE(ExtractKeyWord(lines,'LocBrakeHandle='));
                      if s='FD1' then BrakeLocHandle:=FD1
                 else if s='Knorr' then BrakeLocHandle:=Knorr
                 else if s='Westinghouse' then BrakeLocHandle:=West;

                 s:=DUE(ExtractKeyWord(lines,'MaxBPMass='));
                 if s<>'' then
                   MBPM:=s2rE(s)*1000;


                 if BrakeCtrlPosNo>0 then
                  begin
                    s:=DUE(ExtractKeyWord(lines,'ASB='));
                    if s='Manual' then ASBType:=1 else
                     if s='Automatic' then ASBType:=2;
                  end
                 else
                  begin
                    s:=DUE(ExtractKeyWord(lines,'ASB='));
                    if s='Yes' then ASBType:=128;
                  end;
               end;
              s:=DUE(ExtractKeyWord(lines,'LocalBrake='));
              if s='ManualBrake' then LocalBrake:=ManualBrake
               else
                if s='PneumaticBrake' then LocalBrake:=PneumaticBrake
                  else
                    if s='HydraulicBrake' then LocalBrake:=HydraulicBrake
                      else LocalBrake:=NoBrake;
              s:=DUE(ExtractKeyWord(lines,'ManualBrake='));
              if s='Yes' then MBrake:=true
              else MBrake:=false;
             s:=DUE(ExtractKeyWord(lines,'DynamicBrake='));
             if s='Passive' then DynamicBrakeType:=dbrake_passive
              else
               if s='Switch' then DynamicBrakeType:=dbrake_switch
                else
                 if s='Reversal' then DynamicBrakeType:=dbrake_reversal
                  else
                   if s='Automatic' then DynamicBrakeType:=dbrake_automatic
                    else DynamicBrakeType:=dbrake_none;
              s:=ExtractKeyWord(lines,'MCPN=');
              MainCtrlPosNo:=s2b(DUE(s));
              s:=ExtractKeyWord(lines,'SCPN=');
              ScndCtrlPosNo:=s2b(DUE(s));
              s:=ExtractKeyWord(lines,'SCIM=');
              ScndinMain:=boolean(s2b(DUE(s)));
              s:=DUE(ExtractKeyWord(lines,'AutoRelay='));
              if s='Optional' then
               AutoRelayType:=2
              else
               if s='Yes' then
                AutoRelayType:=1
               else
                AutoRelayType:=0;
              s:=DUE(ExtractKeyWord(lines,'CoupledCtrl='));
              if s='Yes' then
               CoupledCtrl:=true    {wspolny wal}
              else CoupledCtrl:=false;
              s:=DUE(ExtractKeyWord(lines,'ScndS='));
              if s='Yes' then
               ScndS:=true    {brak pozycji rownoleglej przy niskiej nastawie PSR}
              else ScndS:=false;
              s:=ExtractKeyWord(lines,'IniCDelay=');
              InitialCtrlDelay:=s2r(DUE(s));
              s:=ExtractKeyWord(lines,'SCDelay=');
              CtrlDelay:=s2r(DUE(s));
              s:=ExtractKeyWord(lines,'SCDDelay=');
              if s<>'' then CtrlDownDelay:=s2r(DUE(s)) else CtrlDownDelay:=CtrlDelay; //hunter-101012: jesli nie ma SCDDelay;
              s:=DUE(ExtractKeyWord(lines,'FSCircuit=')); //hunter-111012: dla siodemek 303E
              if s='Yes' then
               FastSerialCircuit:=1
              else
               FastSerialCircuit:=0;
              s:=ExtractKeyWord(lines,'SBD=');
              StopBrakeDecc:=s2r(DUE(s));

              if BrakeCtrlPosNo>0 then
               for i:=0 to BrakeCtrlPosNo+1 do
                begin
                  s:=ReadWord(fin);
                  k:=s2iE(s);
                  if ConversionError=0 then
                   with BrakePressureTable[k] do
                    begin
                      read(fin,PipePressureVal,BrakePressureVal,FlowSpeedVal);
                      s:=ReadWord(fin);
                      if s='Pneumatic' then BrakeType:=Pneumatic
                       else if s='ElectroPneumatic' then BrakeType:=ElectroPneumatic
                        else BrakeType:=Individual;
{                      readln(fin); }
                    end;
                end;
            end
          else if Pos('Light:',lines)>0 then      {zrodlo mocy dla oswietlenia}
            begin
              s:=DUE(ExtractKeyWord(lines,'Light='));
              if s<>'' then
               begin
                 LightPowerSource.SourceType:=PowerSourceDecode(s);
                 PowerParamDecode(lines,'L',LightPowerSource);
                 s:=DUE(ExtractKeyWord(lines,'AlterLight='));
                 if s<>'' then
                  begin
                    AlterLightPowerSource.SourceType:=PowerSourceDecode(s);
                    PowerParamDecode(lines,'AlterL',AlterLightPowerSource)
                  end
                 else AlterLightPowerSource.SourceType:=NotDefined;
               end ;
               s:=ExtractKeyWord(lines,'Volt=');
                 if s<>'' then
                 NominalVoltage:=s2r(DUE(s));

             s:=ExtractKeyWord(lines,'LMaxVoltage=');
                 if s<>'' then
                 begin
                 BatteryVoltage:=s2r(DUE(s));
                 NominalBatteryVoltage:=s2r(DUE(s));
               end;
              //else LightPowerSource.SourceType:=NotDefined;
            end
          else if Pos('Security:',lines)>0 then
           begin
            //if (TrainType<>dt_EZT)or(Power>1) then //dla EZT tylko w silnikowym
             with SecuritySystem do
              begin
               s:=DUE(ExtractKeyWord(lines,'AwareSystem='));
               if Pos('Active',s)>0 then
                SetFlag(SystemType,1);
               if Pos('CabSignal',s)>0 then
                SetFlag(SystemType,2);
               s:=ExtractKeyWord(lines,'AwareDelay=');
               if s<>'' then
                AwareDelay:=s2r(DUE(s));
               s:=ExtractKeyWord(lines,'AwareMinSpeed=');
               if s<>'' then
                AwareMinSpeed:=s2r(DUE(s))
               else
                AwareMinSpeed:=0.1*Vmax; //domyślnie 10% Vmax
               s:=ExtractKeyWord(lines,'SoundSignalDelay=');
               if s<>'' then
                 SoundSignalDelay:=s2r(DUE(s));
                s:=ExtractKeyWord(lines,'EmergencyBrakeDelay=');
               if s<>'' then
                EmergencyBrakeDelay:=s2r(DUE(s));
               s:=ExtractKeyWord(lines,'RadioStop=');
               if s<>'' then
                if Pos('Yes',s)>0 then
                 RadioStop:=true;
              end
            end
          else if Pos('Clima:',lines)>0 then      {zrodlo mocy dla ogrzewania itp}
            begin
              s:=DUE(ExtractKeyWord(lines,'Heating='));
              if s<>'' then
               begin
                 HeatingPowerSource.SourceType:=PowerSourceDecode(s);
                 PowerParamDecode(lines,'H',HeatingPowerSource);
                 s:=DUE(ExtractKeyWord(lines,'AlterHeating='));
                 if s<>'' then
                  begin
                    AlterHeatPowerSource.SourceType:=PowerSourceDecode(s);
                    PowerParamDecode(lines,'AlterH',AlterHeatPowerSource)
                  end
                 else AlterHeatPowerSource.SourceType:=NotDefined;
               end
              else HeatingPowerSource.SourceType:=NotDefined;
            end
          else if Pos('Power:',lines)>0 then      {zrodlo mocy dla silnikow trakcyjnych itp}
            begin
              s:=DUE(ExtractKeyWord(lines,'EnginePower='));
              if s<>'' then
               begin
                 EnginePowerSource.SourceType:=PowerSourceDecode(s);
                 PowerParamDecode(lines,'',EnginePowerSource);
                 if (EnginePowerSource.SourceType=Generator) and (EnginePowerSource.GeneratorEngine=WheelsDriven) then
                  ConversionError:=-666;  {perpetuum mobile?}
                 if (Power=0) then //jeśli nie ma mocy, np. rozrządcze EZT
                  EnginePowerSource.SourceType:=NotDefined; //to silnik nie ma zasilania
               end
              else EnginePowerSource.SourceType:=NotDefined;
              //if EnginePowerSource.SourceType=NotDefined then
               begin
                 s:=DUE(ExtractKeyWord(lines,'SystemPower='));
                 if s<>'' then
                  begin
                    SystemPowerSource.SourceType:=PowerSourceDecode(s);
                    PowerParamDecode(lines,'',SystemPowerSource);
                  end
                 else SystemPowerSource.SourceType:=NotDefined;
               end
              //else SystemPowerSource.SourceType:=InternalSource;
            end
          else if Pos('Engine:',lines)>0 then    {stale parametry silnika}
          begin
           EngineType:=EngineDecode(DUE(ExtractKeyWord(lines,'EngineType=')));
           case EngineType of
             ElectricSeriesMotor:
               begin
                 s:=ExtractKeyWord(lines,'Volt=');
                 NominalVoltage:=s2r(DUE(s));
                 s:=DUE(ExtractKeyWord(lines,'Trans='));
                 Transmision.NToothW:=s2b(copy(s,Pos(':',s)+1,Length(s)));
                 Transmision.NToothM:=s2b(copy(s,1,Pos(':',s)-1));
                 if s<>'' then
                    with Transmision do
                     if NToothM>0 then
                      Ratio:=NToothW/NToothM
                     else Ratio:=1;
                 s:=ExtractKeyWord(lines,'WindingRes=');
                 WindingRes:=s2r(DUE(s));
                 if WindingRes=0 then WindingRes:=0.01;
                 s:=ExtractKeyWord(lines,'nmax=');
                 nmax:=s2rE(DUE(s))/60.0;
               end;
             WheelsDriven:
               begin
                 s:=DUE(ExtractKeyWord(lines,'Trans='));
                 Transmision.NToothW:=s2b(copy(s,Pos(':',s)+1,Length(s)));
                 Transmision.NToothM:=s2b(copy(s,1,Pos(':',s)-1));
                 if s<>'' then
                    with Transmision do
                     if NToothM>0 then
                      Ratio:=NToothW/NToothM
                     else Ratio:=1;
                 s:=ExtractKeyWord(lines,'Ftmax=');
                 Ftmax:=s2rE(DUE(s));
               end;
             Dumb:
               begin
                 s:=ExtractKeyWord(lines,'Ftmax=');
                 Ftmax:=s2rE(DUE(s));
               end;
             DieselEngine:
               begin
                 s:=DUE(ExtractKeyWord(lines,'Trans='));
                 Transmision.NToothW:=s2b(copy(s,Pos(':',s)+1,Length(s)));
                 Transmision.NToothM:=s2b(copy(s,1,Pos(':',s)-1));
                 if s<>'' then
                    with Transmision do
                     if NToothM>0 then
                      Ratio:=NToothW/NToothM
                     else Ratio:=1;
                 s:=ExtractKeyWord(lines,'nmin=');
                 dizel_nmin:=s2r(DUE(s))/60.0;
                 s:=ExtractKeyWord(lines,'nmax=');
                 nmax:=s2rE(DUE(s))/60.0;
                 s:=ExtractKeyWord(lines,'nmax_cutoff=');
                 dizel_nmax_cutoff:=s2r(DUE(s))/60.0;
                 s:=ExtractKeyWord(lines,'AIM=');
                 dizel_AIM:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'ShuntMode=');
                 if s<>'' then
                  begin //dodatkowa przekładnia dla SM03 (2Ls150)
                   ShuntModeAllow:=true;
                   ShuntMode:=false;
                   AnPos:=s2rE(DUE(s)); //dodatkowe przełożenie
                   if (AnPos<1.0) then //"rozruch wysoki" ma dawać większą siłę
                    AnPos:=1.0/AnPos; //im większa liczba, tym wolniej jedzie
                  end;
               end;
             DieselElectric: //youBy
               begin
                 s:=DUE(ExtractKeyWord(lines,'Trans='));
                 Transmision.NToothW:=s2b(copy(s,Pos(':',s)+1,Length(s)));
                 Transmision.NToothM:=s2b(copy(s,1,Pos(':',s)-1));
                 if s<>'' then
                    with Transmision do
                     if NToothM>0 then
                      Ratio:=NToothW/NToothM
                     else Ratio:=1;
                 s:=ExtractKeyWord(lines,'Ftmax=');
                 Ftmax:=s2rE(DUE(s));
                 s:=ExtractKeyWord(lines,'Flat=');
                 Flat:=Boolean(s2b(DUE(s)));
                 s:=ExtractKeyWord(lines,'Vhyp=');
                 Vhyp:=s2rE(DUE(s))/3.6;
                 s:=ExtractKeyWord(lines,'Vadd=');
                 Vadd:=s2rE(DUE(s))/3.6;
                 s:=ExtractKeyWord(lines,'Cr=');
                 PowerCorRatio:=s2rE(DUE(s));
                 s:=ExtractKeyWord(lines,'RelayType=');
                 RelayType:=s2b(DUE(s));
                 s:=ExtractKeyWord(lines,'ShuntMode=');
                 ShuntModeAllow:=Boolean(s2b(DUE(s)));
                 if (ShuntModeAllow) then
                 begin
                   ShuntModeAllow:=true;
                   ShuntMode:=false;
                   AnPos:=0;
                   ImaxHi:=2;
                   ImaxLo:=1;
                 end;
               end;
             ElectricInductionMotor:
               begin
                 rventnmax:=1;
                 s:=ExtractKeyWord(lines,'Volt=');
                 NominalVoltage:=s2r(DUE(s));
                 s:=DUE(ExtractKeyWord(lines,'Trans='));
                 Transmision.NToothW:=s2b(copy(s,Pos(':',s)+1,Length(s)));
                 Transmision.NToothM:=s2b(copy(s,1,Pos(':',s)-1));
                 if s<>'' then
                    with Transmision do
                     if NToothM>0 then
                      Ratio:=NToothW/NToothM
                     else Ratio:=1;
                 s:=ExtractKeyWord(lines,'dfic='); eimc[eimc_s_dfic]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'dfmax='); eimc[eimc_s_dfmax]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'p='); eimc[eimc_s_p]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'cfu='); eimc[eimc_s_cfu]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'cim='); eimc[eimc_s_cim]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'icif='); eimc[eimc_s_icif]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'Uzmax='); eimc[eimc_f_Uzmax]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'Uzh='); eimc[eimc_f_Uzh]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'DU='); eimc[eimc_f_DU]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'I0='); eimc[eimc_f_I0]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'fcfu='); eimc[eimc_f_cfu]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'F0='); eimc[eimc_p_F0]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'a1='); eimc[eimc_p_a1]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'Pmax='); eimc[eimc_p_Pmax]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'Fh='); eimc[eimc_p_Fh]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'Ph='); eimc[eimc_p_Ph]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'Vh0='); eimc[eimc_p_Vh0]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'Vh1='); eimc[eimc_p_Vh1]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'Imax='); eimc[eimc_p_Imax]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'abed='); if DUE(s)<>'' then eimc[eimc_p_abed]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'edep='); if DUE(s)<>'' then eimc[eimc_p_eped]:=s2r(DUE(s));
                 s:=ExtractKeyWord(lines,'Flat='); if DUE(s)='Yes' then Flat:=true else Flat:=false;
               end;

           else ConversionError:=-13; {not implemented yet!}
           end;
          end
           { Typy przelacznika 'Winger 010304 }
          else if Pos('Switches:',lines)>0 then
          begin
           s:=DUE(ExtractKeyWord(lines,'Pantograph='));
           PantSwitchType:=s;
           s:=DUE(ExtractKeyWord(lines,'Converter='));
           ConvSwitchType:=s;
           {case PantSwitchType of
             Continuos:
               begin
               PantSwitchType:='continuos';
               end;
             Impulse:
               begin
               PantSwitchType:='impulse';
               end;     }
          end

          else if Pos('MotorParamTable:',lines)>0 then
           case EngineType of
            ElectricSeriesMotor:
             begin
               for k:=0 to ScndCtrlPosNo do
                begin
                  with MotorParam[k] do
                  read(fin, bl, mfi,mIsat, fi,Isat);
                  if AutoRelayType=0 then
                   MotorParam[k].AutoSwitch:=false
                  else begin
                         readln(fin,i);
                         MotorParam[k].AutoSwitch:=Boolean(i);
                       end;
                  if bl<>k then
                   ConversionError:=-2
                end;
             end;
//youBy
            DieselElectric:
             begin
//               WW_MPTRelayNo:= ScndCtrlPosNo;
               for k:=0 to ScndCtrlPosNo do
                begin
                  with MotorParam[k] do
                  readln(fin, bl, mfi, mIsat, fi, Isat, MPTRelay[k].Iup, MPTRelay[k].Idown);
                  if bl<>k then
                   ConversionError:=-2
                end;
             end;

            DieselEngine:
             begin
               s:=ExtractKeyWord(lines,'minVelfullengage=');
               dizel_minVelfullengage:=s2r(DUE(s));
               s:=ExtractKeyWord(lines,'engageDia=');
               dizel_engageDia:=s2r(DUE(s));
               s:=ExtractKeyWord(lines,'engageMaxForce=');
               dizel_engageMaxForce:=s2r(DUE(s));
               s:=ExtractKeyWord(lines,'engagefriction=');
               dizel_engagefriction:=s2r(DUE(s));

               for k:=0 to ScndCtrlPosNo do
                begin
                  with MotorParam[k] do
                  read(fin, bl, mIsat, fi,mfi);
                  if AutoRelayType=0 then
                   MotorParam[k].AutoSwitch:=false
                  else begin
                         readln(fin,i);
                         MotorParam[k].AutoSwitch:=Boolean(i);
                       end;
                  if bl<>k then
                   ConversionError:=-2
                end;
             end
            else ConversionError:=-3;
           end
          //dwa dodatkowe parametry korekcyjne
          else if Pos('MotorParamTable0:',lines)>0 then
             begin
               for k:=0 to ScndCtrlPosNo do
                begin
                  with MotorParam[k] do
                  read(fin, bl, mfi,mIsat,mfi0, fi,Isat,fi0);
                  if AutoRelayType=0 then
                   MotorParam[k].AutoSwitch:=False
                  else begin
                         readln(fin,i);
                         MotorParam[k].AutoSwitch:=Boolean(i);
                       end;
                  if bl<>k then
                   ConversionError:=-2
                end;
             end

          else if Pos('Circuit:',lines)>0 then
           begin
             s:=ExtractKeyWord(lines,'CircuitRes=');
             CircuitRes:=s2r(DUE(s));
             s:=ExtractKeyWord(lines,'IminLo=');
             IminLo:=s2iE(DUE(s));
             s:=ExtractKeyWord(lines,'IminHi=');
             IminHi:=s2i(DUE(s));
             s:=ExtractKeyWord(lines,'ImaxLo=');
             ImaxLo:=s2iE(DUE(s));
             s:=ExtractKeyWord(lines,'ImaxHi=');
             ImaxHi:=s2i(DUE(s));
             Imin:=IminLo;
             Imax:=ImaxLo;
           end
          else if Pos('RList:',lines)>0 then
           begin
             s:=DUE(ExtractKeyWord(lines,'RVent='));
             if s='Automatic' then RventType:=2
             else
             if s='Yes' then RventType:=1
             else
              RventType:=0;
             if RventType>0 then
              begin
                s:=ExtractKeyWord(lines,'RVentnmax=');
                RVentnmax:=s2rE(DUE(s))/60.0;
                s:=ExtractKeyWord(lines,'RVentCutOff=');
                RVentCutOff:=s2r(DUE(s));
              end;
             RListSize:=s2b(DUE(ExtractKeyWord(lines,'Size=')));
             if RListSize>ResArraySize then
              ConversionError:=-4
             else
              for k:=0 to RListSize do
               begin
                 read(fin, RList[k].Relay, RList[k].R, RList[k].Bn, RList[k].Mn);
{                 if AutoRelayType=0 then
                  RList[k].AutoSwitch:=false
                 else begin  }  {to sie przyda do pozycji przejsciowych}
                 read(fin,i);
                 RList[k].AutoSwitch:=Boolean(i);
                 if(ScndInMain)then
                  begin
                   readln(fin,i);
                   RList[k].ScndAct:=i;
                  end
                 else readln(fin);
               end;
           end
          else if Pos('DList:',lines)>0 then  {dla spalinowego silnika}
           begin
             s:=ExtractKeyWord(lines,'Mmax=');
             dizel_Mmax:=s2rE(DUE(s));
             s:=ExtractKeyWord(lines,'nMmax=');
             dizel_nMmax:=s2rE(DUE(s));
             s:=ExtractKeyWord(lines,'Mnmax=');
             dizel_Mnmax:=s2rE(DUE(s));
             s:=ExtractKeyWord(lines,'nmax=');
             dizel_nmax:=s2rE(DUE(s));
             s:=ExtractKeyWord(lines,'nominalfill=');
             dizel_nominalfill:=s2rE(DUE(s));
             s:=ExtractKeyWord(lines,'Mstand=');
             dizel_Mstand:=s2rE(DUE(s));
             RListSize:=s2b(DUE(ExtractKeyWord(lines,'Size=')));
             if RListSize>ResArraySize then
              ConversionError:=-4
             else
              for k:=0 to RListSize do
               begin
                 readln(fin, RList[k].Relay, RList[k].R, RList[k].Mn);
               end;
           end
//youBy
          else if (Pos('WWList:',lines)>0) then  {dla spal-ele}
          begin
            RListSize:=s2b(DUE(ExtractKeyWord(lines,'Size=')));
            for k:=0 to RListSize do
            begin
              if not (ShuntModeAllow) then
                readln(fin, DEList[k].rpm, DEList[k].genpower, DEList[k].Umax, DEList[k].Imax)
              else
              begin
                readln(fin, DEList[k].rpm, DEList[k].genpower, DEList[k].Umax, DEList[k].Imax, SST[k].Umin, SST[k].Umax, SST[k].Pmax);
                SST[k].Pmin:=sqrt(sqr(SST[k].Umin)/47.6);
                SST[k].Pmax:=Min0R(SST[k].Pmax,sqr(SST[k].Umax)/47.6);
              end;
            end;
          end
          else if (Pos('ffList:',lines)>0) then  {dla asynchronow}
          begin
            RListSize:=s2b(DUE(ExtractKeyWord(lines,'Size=')));
            for k:=0 to RListSize do
                readln(fin, DEList[k].rpm, DEList[k].genpower)
          end
          else if (Pos('LightsList:',lines)>0) then  {dla asynchronow}
          begin
            LightsPosNo:=s2b(DUE(ExtractKeyWord(lines,'Size=')));
            LightsWrap:=('Yes')=(DUE(ExtractKeyWord(lines,'Wrap=')));
            LightsDefPos:=s2b(DUE(ExtractKeyWord(lines,'Default=')));
            for k:=1 to LightsPosNo do
                readln(fin, Lights[0][k], Lights[1][k])
          end;

        end;
      end; {koniec filtru importu parametrow}
     if ConversionError=0 then
      OK:=true
     else
      OK:=false;
   end; {otwarty plik}
  if OK then
   if OKflag<>param_ok{+wheels_ok}+dimensions_ok then
    begin
      OK:=false;
      ConversionError:=-OKflag; {brakowalo jakiejs waznej linii z parametrami}
    end;
  if OK and (Mass<=0) then
   begin
     OK:=false;
     ConversionError:=-666;
   end;
  LoadChkFile:=OK;
  if ConversionError<>-8 then
   close(fin);
end; {loadchkfile}


END.



