mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
4359 lines
184 KiB
C++
4359 lines
184 KiB
C++
//---------------------------------------------------------------------------
|
|
/*
|
|
MaSzyna EU07 locomotive simulator
|
|
Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others
|
|
|
|
*/
|
|
|
|
|
|
#include "system.hpp"
|
|
#include "classes.hpp"
|
|
#pragma hdrstop
|
|
|
|
#include "DynObj.h"
|
|
|
|
#include "Timer.h"
|
|
#include "Usefull.h"
|
|
//McZapkie-260202
|
|
#include "Globals.h"
|
|
#include "Texture.h"
|
|
#include "AirCoupler.h"
|
|
|
|
#include "TractionPower.h"
|
|
#include "Ground.h" //bo Global::pGround->bDynamicRemove
|
|
#include "Event.h"
|
|
#include "Driver.h"
|
|
#include "Camera.h" //bo likwidujemy trzęsienie
|
|
#include "Console.h"
|
|
#include "Traction.h"
|
|
#pragma package(smart_init)
|
|
|
|
//Ra: taki zapis funkcjonuje lepiej, ale może nie jest optymalny
|
|
#define vWorldFront vector3(0,0,1)
|
|
#define vWorldUp vector3(0,1,0)
|
|
#define vWorldLeft CrossProduct(vWorldUp,vWorldFront)
|
|
|
|
//Ra: bo te poniżej to się powielały w każdym module odobno
|
|
//vector3 vWorldFront=vector3(0,0,1);
|
|
//vector3 vWorldUp=vector3(0,1,0);
|
|
//vector3 vWorldLeft=CrossProduct(vWorldUp,vWorldFront);
|
|
|
|
#define M_2PI 6.283185307179586476925286766559;
|
|
const float maxrot=(M_PI/3.0); //60°
|
|
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TAnimPant::AKP_4E()
|
|
{//ustawienie wymiarów dla pantografu AKP-4E
|
|
vPos=vector3(0,0,0); //przypisanie domyśnych współczynników do pantografów
|
|
fLenL1=1.22; //1.176289 w modelach
|
|
fLenU1=1.755; //1.724482197 w modelach
|
|
fHoriz=0.535; //0.54555075 przesunięcie ślizgu w długości pojazdu względem osi obrotu dolnego ramienia
|
|
fHeight=0.07; //wysokość ślizgu ponad oś obrotu
|
|
fWidth=0.635; //połowa szerokości ślizgu, 0.635 dla AKP-1 i AKP-4E
|
|
fAngleL0=DegToRad(2.8547285515689267247882521833308);
|
|
fAngleL=fAngleL0; //początkowy kąt dolnego ramienia
|
|
//fAngleU0=acos((1.22*cos(fAngleL)+0.535)/1.755); //górne ramię
|
|
fAngleU0=acos((fLenL1*cos(fAngleL)+fHoriz)/fLenU1); //górne ramię
|
|
fAngleU=fAngleU0; //początkowy kąt
|
|
//PantWys=1.22*sin(fAngleL)+1.755*sin(fAngleU); //wysokość początkowa
|
|
PantWys=fLenL1*sin(fAngleL)+fLenU1*sin(fAngleU)+fHeight; //wysokość początkowa
|
|
PantTraction=PantWys;
|
|
hvPowerWire=NULL;
|
|
fWidthExtra=0.381; //(2.032m-1.027)/2
|
|
//poza obszarem roboczym jest aproksymacja łamaną o 5 odcinkach
|
|
fHeightExtra[0]= 0.0; //+0.0762
|
|
fHeightExtra[1]=-0.01; //+0.1524
|
|
fHeightExtra[2]=-0.03; //+0.2286
|
|
fHeightExtra[3]=-0.07; //+0.3048
|
|
fHeightExtra[4]=-0.15; //+0.3810
|
|
};
|
|
//---------------------------------------------------------------------------
|
|
int __fastcall TAnim::TypeSet(int i,int fl)
|
|
{//ustawienie typu animacji i zależnej od niego ilości animowanych submodeli
|
|
fMaxDist=-1.0; //normalnie nie pokazywać
|
|
switch (i)
|
|
{//maska 0x000F: ile używa wskaźników na submodele (0 gdy jeden, wtedy bez tablicy)
|
|
//maska 0x00F0: 0-osie,1-drzwi,2-obracane,3-zderzaki,4-wózki,5-pantografy,6-tłoki
|
|
//maska 0xFF00: ile używa liczb float dla współczynników i stanu
|
|
case 0: iFlags=0x000; break; //0-oś
|
|
case 1: iFlags=0x010; break; //1-drzwi
|
|
case 2: iFlags=0x020;
|
|
fParam=fl?new float[fl]:NULL;
|
|
iFlags+=fl<<8;
|
|
break; //2-wahacz, dźwignia itp.
|
|
case 3: iFlags=0x030; break; //3-zderzak
|
|
case 4: iFlags=0x040; break; //4-wózek
|
|
case 5: //5-pantograf - 5 submodeli
|
|
iFlags=0x055;
|
|
fParamPants=new TAnimPant();
|
|
fParamPants->AKP_4E();
|
|
break;
|
|
case 6: iFlags=0x068; break; //6-tłok i rozrząd - 8 submodeli
|
|
default: iFlags=0;
|
|
}
|
|
yUpdate=NULL;
|
|
return iFlags&15; //ile wskaźników rezerwować dla danego typu animacji
|
|
};
|
|
__fastcall TAnim::TAnim()
|
|
{//potrzebne to w ogóle?
|
|
iFlags=-1; //nieznany typ - destruktor nic nie usuwa
|
|
};
|
|
__fastcall TAnim::~TAnim()
|
|
{//usuwanie animacji
|
|
switch (iFlags&0xF0)
|
|
{//usuwanie struktur, zależnie ile zostało stworzonych
|
|
case 0x20: //2-wahacz, dźwignia itp.
|
|
delete fParam;
|
|
break;
|
|
case 0x50: //5-pantograf
|
|
delete fParamPants;
|
|
break;
|
|
case 0x60: //6-tłok i rozrząd
|
|
break;
|
|
}
|
|
};
|
|
void __fastcall TAnim::Parovoz()
|
|
{//animowanie tłoka i rozrządu parowozu
|
|
};
|
|
//---------------------------------------------------------------------------
|
|
TDynamicObject* __fastcall TDynamicObject::FirstFind(int &coupler_nr)
|
|
{//szukanie skrajnego połączonego pojazdu w pociagu
|
|
//od strony sprzegu (coupler_nr) obiektu (start)
|
|
TDynamicObject* temp=this;
|
|
for (int i=0;i<300;i++) //ograniczenie do 300 na wypadek zapętlenia składu
|
|
{
|
|
if (!temp)
|
|
return NULL; //Ra: zabezpieczenie przed ewentaulnymi błędami sprzęgów
|
|
if (temp->MoverParameters->Couplers[coupler_nr].CouplingFlag==0)
|
|
return temp; //nic nie ma już dalej podłączone
|
|
if (coupler_nr==0)
|
|
{//jeżeli szukamy od sprzęgu 0
|
|
if (temp->PrevConnected) //jeśli mamy coś z przodu
|
|
{
|
|
if (temp->PrevConnectedNo==0) //jeśli pojazd od strony sprzęgu 0 jest odwrócony
|
|
coupler_nr=1-coupler_nr; //to zmieniamy kierunek sprzęgu
|
|
temp=temp->PrevConnected; //ten jest od strony 0
|
|
}
|
|
else
|
|
return temp; //jeśli jednak z przodu nic nie ma
|
|
}
|
|
else
|
|
{
|
|
if (temp->NextConnected)
|
|
{if (temp->NextConnectedNo==1) //jeśli pojazd od strony sprzęgu 1 jest odwrócony
|
|
coupler_nr=1-coupler_nr; //to zmieniamy kierunek sprzęgu
|
|
temp=temp->NextConnected; //ten pojazd jest od strony 1
|
|
}
|
|
else
|
|
return temp; //jeśli jednak z tyłu nic nie ma
|
|
}
|
|
}
|
|
return NULL; //to tylko po wyczerpaniu pętli
|
|
};
|
|
|
|
//---------------------------------------------------------------------------
|
|
float __fastcall TDynamicObject::GetEPP()
|
|
{//szukanie skrajnego połączonego pojazdu w pociagu
|
|
//od strony sprzegu (coupler_nr) obiektu (start)
|
|
TDynamicObject* temp=this;
|
|
int coupler_nr=0;
|
|
float eq=0,am=0;
|
|
|
|
for (int i=0;i<300;i++) //ograniczenie do 300 na wypadek zapętlenia składu
|
|
{
|
|
if (!temp)
|
|
break; //Ra: zabezpieczenie przed ewentaulnymi błędami sprzęgów
|
|
eq+=temp->MoverParameters->PipePress*temp->MoverParameters->Dim.L;
|
|
am+=temp->MoverParameters->Dim.L;
|
|
if ((temp->MoverParameters->Couplers[coupler_nr].CouplingFlag&2)!=2)
|
|
break; //nic nie ma już dalej podłączone
|
|
if (coupler_nr==0)
|
|
{//jeżeli szukamy od sprzęgu 0
|
|
if (temp->PrevConnected) //jeśli mamy coś z przodu
|
|
{
|
|
if (temp->PrevConnectedNo==0) //jeśli pojazd od strony sprzęgu 0 jest odwrócony
|
|
coupler_nr=1-coupler_nr; //to zmieniamy kierunek sprzęgu
|
|
temp=temp->PrevConnected; //ten jest od strony 0
|
|
}
|
|
else
|
|
break; //jeśli jednak z przodu nic nie ma
|
|
}
|
|
else
|
|
{
|
|
if (temp->NextConnected)
|
|
{if (temp->NextConnectedNo==1) //jeśli pojazd od strony sprzęgu 1 jest odwrócony
|
|
coupler_nr=1-coupler_nr; //to zmieniamy kierunek sprzęgu
|
|
temp=temp->NextConnected; //ten pojazd jest od strony 1
|
|
}
|
|
else
|
|
break; //jeśli jednak z tyłu nic nie ma
|
|
}
|
|
}
|
|
|
|
temp=this;
|
|
coupler_nr=1;
|
|
for (int i=0;i<300;i++) //ograniczenie do 300 na wypadek zapętlenia składu
|
|
{
|
|
if (!temp)
|
|
break; //Ra: zabezpieczenie przed ewentaulnymi błędami sprzęgów
|
|
eq+=temp->MoverParameters->PipePress*temp->MoverParameters->Dim.L;
|
|
am+=temp->MoverParameters->Dim.L;
|
|
if ((temp->MoverParameters->Couplers[coupler_nr].CouplingFlag&2)!=2)
|
|
break; //nic nie ma już dalej podłączone
|
|
if (coupler_nr==0)
|
|
{//jeżeli szukamy od sprzęgu 0
|
|
if (temp->PrevConnected) //jeśli mamy coś z przodu
|
|
{
|
|
if (temp->PrevConnectedNo==0) //jeśli pojazd od strony sprzęgu 0 jest odwrócony
|
|
coupler_nr=1-coupler_nr; //to zmieniamy kierunek sprzęgu
|
|
temp=temp->PrevConnected; //ten jest od strony 0
|
|
}
|
|
else
|
|
break; //jeśli jednak z przodu nic nie ma
|
|
}
|
|
else
|
|
{
|
|
if (temp->NextConnected)
|
|
{if (temp->NextConnectedNo==1) //jeśli pojazd od strony sprzęgu 1 jest odwrócony
|
|
coupler_nr=1-coupler_nr; //to zmieniamy kierunek sprzęgu
|
|
temp=temp->NextConnected; //ten pojazd jest od strony 1
|
|
}
|
|
else
|
|
break; //jeśli jednak z tyłu nic nie ma
|
|
}
|
|
}
|
|
eq-=MoverParameters->PipePress*MoverParameters->Dim.L;
|
|
am-=MoverParameters->Dim.L;
|
|
return eq/am;
|
|
};
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
TDynamicObject* __fastcall TDynamicObject::GetFirstDynamic(int cpl_type)
|
|
{//Szukanie skrajnego połączonego pojazdu w pociagu
|
|
//od strony sprzegu (cpl_type) obiektu szukajacego
|
|
//Ra: wystarczy jedna funkcja do szukania w obu kierunkach
|
|
return FirstFind(cpl_type); //używa referencji
|
|
};
|
|
|
|
/*
|
|
TDynamicObject* __fastcall TDynamicObject::GetFirstCabDynamic(int cpl_type)
|
|
{//ZiomalCl: szukanie skrajnego obiektu z kabiną
|
|
TDynamicObject* temp=this;
|
|
int coupler_nr=cpl_type;
|
|
for (int i=0;i<300;i++) //ograniczenie do 300 na wypadek zapętlenia składu
|
|
{
|
|
if (!temp)
|
|
return NULL; //Ra: zabezpieczenie przed ewentaulnymi błędami sprzęgów
|
|
if (temp->MoverParameters->CabNo!=0&&temp->MoverParameters->SandCapacity!=0)
|
|
return temp; //nic nie ma już dalej podłączone
|
|
if (temp->MoverParameters->Couplers[coupler_nr].CouplingFlag==0)
|
|
return NULL;
|
|
if (coupler_nr==0)
|
|
{//jeżeli szukamy od sprzęgu 0
|
|
if (temp->PrevConnectedNo==0) //jeśli pojazd od strony sprzęgu 0 jest odwrócony
|
|
coupler_nr=1-coupler_nr; //to zmieniamy kierunek sprzęgu
|
|
if (temp->PrevConnected)
|
|
temp=temp->PrevConnected; //ten jest od strony 0
|
|
}
|
|
else
|
|
{
|
|
if (temp->NextConnectedNo==1) //jeśli pojazd od strony sprzęgu 1 jest odwrócony
|
|
coupler_nr=1-coupler_nr; //to zmieniamy kierunek sprzęgu
|
|
if (temp->NextConnected)
|
|
temp=temp->NextConnected; //ten pojazd jest od strony 1
|
|
}
|
|
}
|
|
return NULL; //to tylko po wyczerpaniu pętli
|
|
};
|
|
*/
|
|
|
|
void TDynamicObject::ABuSetModelShake(vector3 mShake)
|
|
{
|
|
modelShake=mShake;
|
|
};
|
|
|
|
int __fastcall TDynamicObject::GetPneumatic(bool front, bool red)
|
|
{
|
|
int x,y,z; //1=prosty, 2=skośny
|
|
if (red)
|
|
{
|
|
if (front)
|
|
{
|
|
x=btCPneumatic1.GetStatus();
|
|
y=btCPneumatic1r.GetStatus();
|
|
}
|
|
else
|
|
{
|
|
x=btCPneumatic2.GetStatus();
|
|
y=btCPneumatic2r.GetStatus();
|
|
}
|
|
}
|
|
else
|
|
if (front)
|
|
{
|
|
x=btPneumatic1.GetStatus();
|
|
y=btPneumatic1r.GetStatus();
|
|
}
|
|
else
|
|
{
|
|
x=btPneumatic2.GetStatus();
|
|
y=btPneumatic2r.GetStatus();
|
|
}
|
|
z=0; //brak węży?
|
|
if ((x==1)&&(y==1)) z=3; //dwa proste
|
|
if ((x==2)&&(y==0)) z=1; //lewy skośny, brak prawego
|
|
if ((x==0)&&(y==2)) z=2; //brak lewego, prawy skośny
|
|
|
|
return z;
|
|
}
|
|
|
|
void __fastcall TDynamicObject::SetPneumatic(bool front,bool red)
|
|
{
|
|
int x=0,ten,tamten;
|
|
ten=GetPneumatic(front,red); //1=lewy skos,2=prawy skos,3=dwa proste
|
|
if (front)
|
|
if (PrevConnected) //pojazd od strony sprzęgu 0
|
|
tamten=PrevConnected->GetPneumatic((PrevConnectedNo==0?true:false),red);
|
|
if (!front)
|
|
if (NextConnected) //pojazd od strony sprzęgu 1
|
|
tamten=NextConnected->GetPneumatic((NextConnectedNo==0?true:false),red);
|
|
if (ten==tamten) //jeśli układ jest symetryczny
|
|
switch (ten)
|
|
{
|
|
case 1: x=2; break; //mamy lewy skos, dać lewe skosy
|
|
case 2: x=3; break; //mamy prawy skos, dać prawe skosy
|
|
case 3: //wszystkie cztery na prosto
|
|
if (MoverParameters->Couplers[front?0:1].Render) x=1; else x=4;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (ten==2) x=4;
|
|
if (ten==1) x=1;
|
|
if (ten==3) if (tamten==1) x=4; else x=1;
|
|
}
|
|
if (front)
|
|
{if (red) cp1=x; else sp1=x;} //który pokazywać z przodu
|
|
else
|
|
{if (red) cp2=x; else sp2=x;} //który pokazywać z tyłu
|
|
}
|
|
|
|
void TDynamicObject::UpdateAxle(TAnim *pAnim)
|
|
{//animacja osi
|
|
pAnim->smAnimated->SetRotate(float3(1,0,0),*pAnim->dWheelAngle);
|
|
};
|
|
|
|
void TDynamicObject::UpdateBoogie(TAnim *pAnim)
|
|
{//animacja wózka
|
|
pAnim->smAnimated->SetRotate(float3(1,0,0),*pAnim->dWheelAngle);
|
|
};
|
|
|
|
void TDynamicObject::UpdateDoorTranslate(TAnim *pAnim)
|
|
{//animacja drzwi - przesuw
|
|
//WriteLog("Dla drzwi nr:", i);
|
|
//WriteLog("Wspolczynnik", DoorSpeedFactor[i]);
|
|
//Ra: te współczynniki są bez sensu, bo modyfikują wektor przesunięcia
|
|
//w efekcie drzwi otwierane na zewnątrz będą odlatywac dowolnie daleko :)
|
|
//ograniczyłem zakres ruchu funkcją max
|
|
if (pAnim->smAnimated)
|
|
{
|
|
if (pAnim->iNumber&1)
|
|
pAnim->smAnimated->SetTranslate(vector3(0,0,Max0R(dDoorMoveR*pAnim->fSpeed,dDoorMoveR)));
|
|
else
|
|
pAnim->smAnimated->SetTranslate(vector3(0,0,Max0R(dDoorMoveL*pAnim->fSpeed,dDoorMoveL)));
|
|
}
|
|
};
|
|
|
|
void TDynamicObject::UpdateDoorRotate(TAnim *pAnim)
|
|
{//animacja drzwi - obrót
|
|
if (pAnim->smAnimated)
|
|
{//if (MoverParameters->DoorOpenMethod==2) //obrotowe albo dwójłomne (trzeba kombinowac submodelami i ShiftL=90,R=180)
|
|
if (pAnim->iNumber&1)
|
|
pAnim->smAnimated->SetRotate(float3(1,0,0),dDoorMoveR);
|
|
else
|
|
pAnim->smAnimated->SetRotate(float3(1,0,0),dDoorMoveL);
|
|
}
|
|
};
|
|
|
|
void TDynamicObject::UpdateDoorFold(TAnim *pAnim)
|
|
{//animacja drzwi - obrót
|
|
if (pAnim->smAnimated)
|
|
{//if (MoverParameters->DoorOpenMethod==2) //obrotowe albo dwójłomne (trzeba kombinowac submodelami i ShiftL=90,R=180)
|
|
if (pAnim->iNumber&1)
|
|
{pAnim->smAnimated->SetRotate(float3(0,0,1),dDoorMoveR);
|
|
TSubModel *sm=pAnim->smAnimated->ChildGet(); //skrzydło mniejsze
|
|
if (sm)
|
|
{sm->SetRotate(float3(0,0,1),-dDoorMoveR-dDoorMoveR); //skrzydło większe
|
|
sm=sm->ChildGet();
|
|
if (sm)
|
|
sm->SetRotate(float3(0,1,0),dDoorMoveR); //podnóżek?
|
|
}
|
|
}
|
|
else
|
|
{pAnim->smAnimated->SetRotate(float3(0,0,1),dDoorMoveL);
|
|
//SubModel->SetRotate(float3(0,1,0),fValue*360.0);
|
|
TSubModel *sm=pAnim->smAnimated->ChildGet(); //skrzydło mniejsze
|
|
if (sm)
|
|
{sm->SetRotate(float3(0,0,1),-dDoorMoveL-dDoorMoveL); //skrzydło większe
|
|
sm=sm->ChildGet();
|
|
if (sm)
|
|
sm->SetRotate(float3(0,1,0),dDoorMoveL); //podnóżek?
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
void TDynamicObject::UpdatePant(TAnim *pAnim)
|
|
{//animacja pantografu - 4 obracane ramiona, ślizg piąty
|
|
float a,b,c;
|
|
a=RadToDeg(pAnim->fParamPants->fAngleL-pAnim->fParamPants->fAngleL0);
|
|
b=RadToDeg(pAnim->fParamPants->fAngleU-pAnim->fParamPants->fAngleU0);
|
|
c=a+b;
|
|
if (pAnim->smElement[0]) pAnim->smElement[0]->SetRotate(float3(-1,0,0),a); //dolne ramię
|
|
if (pAnim->smElement[1]) pAnim->smElement[1]->SetRotate(float3(1,0,0),a);
|
|
if (pAnim->smElement[2]) pAnim->smElement[2]->SetRotate(float3(1,0,0),c); //górne ramię
|
|
if (pAnim->smElement[3]) pAnim->smElement[3]->SetRotate(float3(-1,0,0),c);
|
|
if (pAnim->smElement[4]) pAnim->smElement[4]->SetRotate(float3(-1,0,0),b); //ślizg
|
|
};
|
|
|
|
void TDynamicObject::UpdateLeverDouble(TAnim *pAnim)
|
|
{//animacja gałki zależna od double
|
|
pAnim->smAnimated->SetRotate(float3(1,0,0),pAnim->fSpeed**pAnim->fDoubleBase);
|
|
};
|
|
void TDynamicObject::UpdateLeverFloat(TAnim *pAnim)
|
|
{//animacja gałki zależna od float
|
|
pAnim->smAnimated->SetRotate(float3(1,0,0),pAnim->fSpeed**pAnim->fFloatBase);
|
|
};
|
|
void TDynamicObject::UpdateLeverInt(TAnim *pAnim)
|
|
{//animacja gałki zależna od int
|
|
pAnim->smAnimated->SetRotate(float3(1,0,0),pAnim->fSpeed**pAnim->iIntBase);
|
|
};
|
|
void TDynamicObject::UpdateLeverEnum(TAnim *pAnim)
|
|
{//ustawienie kąta na wartość wskazaną przez int z tablicy fParam
|
|
//pAnim->fParam[0]; - dodać lepkość
|
|
pAnim->smAnimated->SetRotate(float3(1,0,0),pAnim->fParam[*pAnim->iIntBase]);
|
|
};
|
|
|
|
|
|
//ABu 29.01.05 przeklejone z render i renderalpha: *********************
|
|
void __inline TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
|
|
{//ABu290105: pozbierane i uporzadkowane powtarzajace sie rzeczy z Render i RenderAlpha
|
|
//dodatkowy warunek, if (ObjSqrDist<...) zeby niepotrzebnie nie zmianiec w obiektach,
|
|
//ktorych i tak nie widac
|
|
//NBMX wrzesien, MC listopad: zuniwersalnione
|
|
btnOn=false; //czy przywrócić stan domyślny po renderowaniu
|
|
|
|
if (mdLoad) //tymczasowo ładunek na poziom podłogi
|
|
if (vFloor.z>0.0)
|
|
mdLoad->GetSMRoot()->SetTranslate(modelShake+vFloor);
|
|
|
|
if (ObjSqrDist<160000) //gdy bliżej niż 400m
|
|
{
|
|
for (int i=0;i<iAnimations;++i) //wykonanie kolejnych animacji
|
|
if (ObjSqrDist<pAnimations[i].fMaxDist)
|
|
if (pAnimations[i].yUpdate) //jeśli zdefiniowana funkcja
|
|
pAnimations[i].yUpdate(pAnimations+i); //aktualizacja animacji (położenia submodeli
|
|
if (ObjSqrDist<2500) //gdy bliżej niż 50m
|
|
{
|
|
//ABu290105: rzucanie pudlem
|
|
//te animacje wymagają bananów w modelach!
|
|
mdModel->GetSMRoot()->SetTranslate(modelShake);
|
|
if (mdKabina)
|
|
mdKabina->GetSMRoot()->SetTranslate(modelShake);
|
|
if (mdLoad)
|
|
mdLoad->GetSMRoot()->SetTranslate(modelShake+vFloor);
|
|
if (mdLowPolyInt)
|
|
mdLowPolyInt->GetSMRoot()->SetTranslate(modelShake);
|
|
if (mdPrzedsionek)
|
|
mdPrzedsionek->GetSMRoot()->SetTranslate(modelShake);
|
|
//ABu: koniec rzucania
|
|
//ABu011104: liczenie obrotow wozkow
|
|
ABuBogies();
|
|
//Mczapkie-100402: rysowanie lub nie - sprzegow
|
|
//ABu-240105: Dodatkowy warunek: if (...).Render, zeby rysowal tylko jeden
|
|
//z polaczonych sprzegow
|
|
if ((TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_coupler))
|
|
&&(MoverParameters->Couplers[0].Render))
|
|
{btCoupler1.TurnOn(); btnOn=true;}
|
|
//else btCoupler1.TurnOff();
|
|
if ((TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_coupler))
|
|
&&(MoverParameters->Couplers[1].Render))
|
|
{btCoupler2.TurnOn(); btnOn=true;}
|
|
//else btCoupler2.TurnOff();
|
|
//********************************************************************************
|
|
//przewody powietrzne j.w., ABu: decyzja czy rysowac tylko na podstawie 'render' - juz nie
|
|
//przewody powietrzne, yB: decyzja na podstawie polaczen w t3d
|
|
if (Global::bnewAirCouplers)
|
|
{
|
|
SetPneumatic(false,false); //wczytywanie z t3d ulozenia wezykow
|
|
SetPneumatic(true,false); //i zapisywanie do zmiennej
|
|
SetPneumatic(true,true); //ktore z nich nalezy
|
|
SetPneumatic(false,true); //wyswietlic w tej klatce
|
|
|
|
if (TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_pneumatic))
|
|
{
|
|
switch (cp1)
|
|
{
|
|
case 1: btCPneumatic1.TurnOn(); break;
|
|
case 2: btCPneumatic1.TurnxOn(); break;
|
|
case 3: btCPneumatic1r.TurnxOn(); break;
|
|
case 4: btCPneumatic1r.TurnOn(); break;
|
|
}
|
|
btnOn=true;
|
|
}
|
|
//else
|
|
//{
|
|
// btCPneumatic1.TurnOff();
|
|
// btCPneumatic1r.TurnOff();
|
|
//}
|
|
|
|
if (TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_pneumatic))
|
|
{
|
|
switch (cp2)
|
|
{
|
|
case 1: btCPneumatic2.TurnOn(); break;
|
|
case 2: btCPneumatic2.TurnxOn(); break;
|
|
case 3: btCPneumatic2r.TurnxOn(); break;
|
|
case 4: btCPneumatic2r.TurnOn(); break;
|
|
}
|
|
btnOn=true;
|
|
}
|
|
//else
|
|
//{
|
|
// btCPneumatic2.TurnOff();
|
|
// btCPneumatic2r.TurnOff();
|
|
//}
|
|
|
|
//przewody zasilajace, j.w. (yB)
|
|
if (TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_scndpneumatic))
|
|
{
|
|
switch (sp1)
|
|
{
|
|
case 1: btPneumatic1.TurnOn(); break;
|
|
case 2: btPneumatic1.TurnxOn(); break;
|
|
case 3: btPneumatic1r.TurnxOn(); break;
|
|
case 4: btPneumatic1r.TurnOn(); break;
|
|
}
|
|
btnOn=true;
|
|
}
|
|
//else
|
|
//{
|
|
// btPneumatic1.TurnOff();
|
|
// btPneumatic1r.TurnOff();
|
|
//}
|
|
|
|
if (TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_scndpneumatic))
|
|
{
|
|
switch (sp2)
|
|
{
|
|
case 1: btPneumatic2.TurnOn(); break;
|
|
case 2: btPneumatic2.TurnxOn(); break;
|
|
case 3: btPneumatic2r.TurnxOn(); break;
|
|
case 4: btPneumatic2r.TurnOn(); break;
|
|
}
|
|
btnOn=true;
|
|
}
|
|
//else
|
|
//{
|
|
// btPneumatic2.TurnOff();
|
|
// btPneumatic2r.TurnOff();
|
|
//}
|
|
}
|
|
//*********************************************************************************/
|
|
else //po staremu ABu'oewmu
|
|
{
|
|
//przewody powietrzne j.w., ABu: decyzja czy rysowac tylko na podstawie 'render'
|
|
if (TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_pneumatic))
|
|
{
|
|
if (MoverParameters->Couplers[0].Render)
|
|
btCPneumatic1.TurnOn();
|
|
else
|
|
btCPneumatic1r.TurnOn();
|
|
btnOn=true;
|
|
}
|
|
//else
|
|
//{
|
|
// btCPneumatic1.TurnOff();
|
|
// btCPneumatic1r.TurnOff();
|
|
//}
|
|
|
|
if (TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_pneumatic))
|
|
{
|
|
if (MoverParameters->Couplers[1].Render)
|
|
btCPneumatic2.TurnOn();
|
|
else
|
|
btCPneumatic2r.TurnOn();
|
|
btnOn=true;
|
|
}
|
|
//else
|
|
//{
|
|
// btCPneumatic2.TurnOff();
|
|
// btCPneumatic2r.TurnOff();
|
|
//}
|
|
|
|
//przewody powietrzne j.w., ABu: decyzja czy rysowac tylko na podstawie 'render' //yB - zasilajace
|
|
if (TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_scndpneumatic))
|
|
{
|
|
if (MoverParameters->Couplers[0].Render)
|
|
btPneumatic1.TurnOn();
|
|
else
|
|
btPneumatic1r.TurnOn();
|
|
btnOn=true;
|
|
}
|
|
//else
|
|
//{
|
|
// btPneumatic1.TurnOff();
|
|
// btPneumatic1r.TurnOff();
|
|
//}
|
|
|
|
if (TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_scndpneumatic))
|
|
{
|
|
if (MoverParameters->Couplers[1].Render)
|
|
btPneumatic2.TurnOn();
|
|
else
|
|
btPneumatic2r.TurnOn();
|
|
btnOn=true;
|
|
}
|
|
//else
|
|
//{
|
|
// btPneumatic2.TurnOff();
|
|
// btPneumatic2r.TurnOff();
|
|
//}
|
|
}
|
|
//*************************************************************/// koniec wezykow
|
|
// uginanie zderzakow
|
|
for (int i=0; i<2; i++)
|
|
{
|
|
double dist=MoverParameters->Couplers[i].Dist/2.0;
|
|
if (smBuforLewy[i])
|
|
if (dist<0)
|
|
smBuforLewy[i]->SetTranslate(vector3(dist,0,0));
|
|
if (smBuforPrawy[i])
|
|
if (dist<0)
|
|
smBuforPrawy[i]->SetTranslate(vector3(dist,0,0));
|
|
}
|
|
}
|
|
|
|
//Winger 160204 - podnoszenie pantografow
|
|
|
|
//przewody sterowania ukrotnionego
|
|
if (TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_controll))
|
|
{btCCtrl1.TurnOn(); btnOn=true;}
|
|
//else btCCtrl1.TurnOff();
|
|
if (TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_controll))
|
|
{btCCtrl2.TurnOn(); btnOn=true;}
|
|
//else btCCtrl2.TurnOff();
|
|
//McZapkie-181103: mostki przejsciowe
|
|
if (TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_passenger))
|
|
{btCPass1.TurnOn(); btnOn=true;}
|
|
//else btCPass1.TurnOff();
|
|
if (TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_passenger))
|
|
{btCPass2.TurnOn(); btnOn=true;}
|
|
//else btCPass2.TurnOff();
|
|
if (MoverParameters->Battery)
|
|
{//sygnaly konca pociagu
|
|
if (btEndSignals1.Active())
|
|
{
|
|
if (TestFlag(iLights[0],2)
|
|
||TestFlag(iLights[0],32))
|
|
{btEndSignals1.TurnOn(); btnOn=true;}
|
|
//else btEndSignals1.TurnOff();
|
|
}
|
|
else
|
|
{
|
|
if (TestFlag(iLights[0],2))
|
|
{btEndSignals11.TurnOn(); btnOn=true;}
|
|
//else btEndSignals11.TurnOff();
|
|
if (TestFlag(iLights[0],32))
|
|
{btEndSignals13.TurnOn(); btnOn=true;}
|
|
//else btEndSignals13.TurnOff();
|
|
}
|
|
if (btEndSignals2.Active())
|
|
{
|
|
if (TestFlag(iLights[1],2)
|
|
||TestFlag(iLights[1],32))
|
|
{btEndSignals2.TurnOn(); btnOn=true;}
|
|
//else btEndSignals2.TurnOff();
|
|
}
|
|
else
|
|
{
|
|
if (TestFlag(iLights[1],2))
|
|
{btEndSignals21.TurnOn(); btnOn=true;}
|
|
//else btEndSignals21.TurnOff();
|
|
if (TestFlag(iLights[1],32))
|
|
{btEndSignals23.TurnOn(); btnOn=true;}
|
|
//else btEndSignals23.TurnOff();
|
|
}
|
|
}
|
|
//tablice blaszane:
|
|
if (TestFlag(iLights[0],64))
|
|
{btEndSignalsTab1.TurnOn(); btnOn=true;}
|
|
//else btEndSignalsTab1.TurnOff();
|
|
if (TestFlag(iLights[1],64))
|
|
{btEndSignalsTab2.TurnOn(); btnOn=true;}
|
|
//else btEndSignalsTab2.TurnOff();
|
|
//McZapkie-181002: krecenie wahaczem (korzysta z kata obrotu silnika)
|
|
if (iAnimType[ANIM_LEVERS])
|
|
for (int i=0;i<4;++i)
|
|
if (smWahacze[i])
|
|
smWahacze[i]->SetRotate(float3(1,0,0),fWahaczeAmp*cos(MoverParameters->eAngle));
|
|
if (Mechanik&&(Controller!=Humandriver))
|
|
{//rysowanie figurki mechanika
|
|
if (smMechanik0) //mechanik od strony sprzęgu 0
|
|
if (smMechanik1) //jak jest drugi, to pierwszego jedynie pokazujemy
|
|
smMechanik0->iVisible=MoverParameters->ActiveCab>0;
|
|
else
|
|
{//jak jest tylko jeden, to do drugiej kabiny go obracamy
|
|
smMechanik0->iVisible=(MoverParameters->ActiveCab!=0);
|
|
smMechanik0->SetRotate(float3(0,0,1),MoverParameters->ActiveCab>=0?0:180); //obrót względem osi Z
|
|
}
|
|
if (smMechanik1) //mechanik od strony sprzęgu 1
|
|
smMechanik1->iVisible=MoverParameters->ActiveCab<0;
|
|
}
|
|
//ABu: Przechyly na zakretach
|
|
//Ra: przechyłkę załatwiamy na etapie przesuwania modelu
|
|
//if (ObjSqrDist<80000) ABuModelRoll(); //przechyłki od 400m
|
|
}
|
|
if (MoverParameters->Battery)
|
|
{//sygnały czoła pociagu //Ra: wyświetlamy bez ograniczeń odległości, by były widoczne z daleka
|
|
if (TestFlag(iLights[0],1))
|
|
{btHeadSignals11.TurnOn(); btnOn=true;}
|
|
//else btHeadSignals11.TurnOff();
|
|
if (TestFlag(iLights[0],4))
|
|
{btHeadSignals12.TurnOn(); btnOn=true;}
|
|
//else btHeadSignals12.TurnOff();
|
|
if (TestFlag(iLights[0],16))
|
|
{btHeadSignals13.TurnOn(); btnOn=true;}
|
|
//else btHeadSignals13.TurnOff();
|
|
if (TestFlag(iLights[1],1))
|
|
{btHeadSignals21.TurnOn(); btnOn=true;}
|
|
//else btHeadSignals21.TurnOff();
|
|
if (TestFlag(iLights[1],4))
|
|
{btHeadSignals22.TurnOn(); btnOn=true;}
|
|
//else btHeadSignals22.TurnOff();
|
|
if (TestFlag(iLights[1],16))
|
|
{btHeadSignals23.TurnOn(); btnOn=true;}
|
|
//else btHeadSignals23.TurnOff();
|
|
}
|
|
}
|
|
//ABu 29.01.05 koniec przeklejenia *************************************
|
|
|
|
double __fastcall ABuAcos(const vector3 &calc_temp)
|
|
{ //Odpowiednik funkcji Arccos, bo cos mi tam nie dzialalo.
|
|
return atan2(-calc_temp.x,calc_temp.z); //Ra: tak prościej
|
|
}
|
|
|
|
TDynamicObject* __fastcall TDynamicObject::ABuFindNearestObject(TTrack *Track,TDynamicObject *MyPointer,int &CouplNr)
|
|
{//zwraca wskaznik do obiektu znajdujacego sie na torze (Track), którego sprzęg jest najblizszy kamerze
|
|
//służy np. do łączenia i rozpinania sprzęgów
|
|
//WE: Track - tor, na ktorym odbywa sie poszukiwanie
|
|
// MyPointer - wskaznik do obiektu szukajacego
|
|
//WY: CouplNr - który sprzęg znalezionego obiektu jest bliższy kamerze
|
|
|
|
//Uwaga! Jesli CouplNr==-2 to szukamy njblizszego obiektu, a nie sprzegu!!!
|
|
|
|
if ((Track->iNumDynamics)>0)
|
|
{//o ile w ogóle jest co przeglądać na tym torze
|
|
//vector3 poz; //pozycja pojazdu XYZ w scenerii
|
|
//vector3 kon; //wektor czoła względem środka pojazdu wzglęem początku toru
|
|
vector3 tmp; //wektor pomiędzy kamerą i sprzęgiem
|
|
double dist; //odległość
|
|
for (int i=0;i<Track->iNumDynamics;i++)
|
|
{
|
|
if (CouplNr==-2)
|
|
{//wektor [kamera-obiekt] - poszukiwanie obiektu
|
|
tmp=Global::GetCameraPosition()-Track->Dynamics[i]->vPosition;
|
|
dist=tmp.x*tmp.x+tmp.y*tmp.y+tmp.z*tmp.z; //odległość do kwadratu
|
|
if (dist<100.0) //10 metrów
|
|
return Track->Dynamics[i];
|
|
}
|
|
else //jeśli (CouplNr) inne niz -2, szukamy sprzęgu
|
|
{//wektor [kamera-sprzeg0], potem [kamera-sprzeg1]
|
|
//Powinno byc wyliczone, ale nie zaszkodzi drugi raz:
|
|
//(bo co, jesli nie wykonuje sie obrotow wozkow?) - Ra: ale zawsze są liczone współrzędne sprzęgów
|
|
//Track->Dynamics[i]->modelRot.z=ABuAcos(Track->Dynamics[i]->Axle0.pPosition-Track->Dynamics[i]->Axle1.pPosition);
|
|
//poz=Track->Dynamics[i]->vPosition; //pozycja środka pojazdu
|
|
//kon=vector3( //położenie przodu względem środka
|
|
// -((0.5*Track->Dynamics[i]->MoverParameters->Dim.L)*sin(Track->Dynamics[i]->modelRot.z)),
|
|
// 0, //yyy... jeśli duże pochylenie i długi pojazd, to może być problem
|
|
// +((0.5*Track->Dynamics[i]->MoverParameters->Dim.L)*cos(Track->Dynamics[i]->modelRot.z))
|
|
//);
|
|
tmp=Global::GetCameraPosition()-Track->Dynamics[i]->vCoulpler[0]; //Ra: pozycje sprzęgów też są zawsze liczone
|
|
dist=tmp.x*tmp.x+tmp.y*tmp.y+tmp.z*tmp.z; //odległość do kwadratu
|
|
if (dist<25.0) //5 metrów
|
|
{
|
|
CouplNr=0;
|
|
return Track->Dynamics[i];
|
|
}
|
|
tmp=Global::GetCameraPosition()-Track->Dynamics[i]->vCoulpler[1];
|
|
dist=tmp.x*tmp.x+tmp.y*tmp.y+tmp.z*tmp.z; //odległość do kwadratu
|
|
if (dist<25.0) //5 metrów
|
|
{
|
|
CouplNr=1;
|
|
return Track->Dynamics[i];
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
TDynamicObject* __fastcall TDynamicObject::ABuScanNearestObject(TTrack *Track,double ScanDir,double ScanDist,int &CouplNr)
|
|
{//skanowanie toru w poszukiwaniu obiektu najblizszego kamerze
|
|
//double MyScanDir=ScanDir; //Moja orientacja na torze. //Ra: nie używane
|
|
if (ABuGetDirection()<0) ScanDir=-ScanDir;
|
|
TDynamicObject* FoundedObj;
|
|
FoundedObj=ABuFindNearestObject(Track,this,CouplNr); //zwraca numer sprzęgu znalezionego pojazdu
|
|
if (FoundedObj==NULL)
|
|
{
|
|
double ActDist; //Przeskanowana odleglosc.
|
|
double CurrDist=0; //Aktualna dlugosc toru.
|
|
if (ScanDir>=0) ActDist=Track->Length()-RaTranslationGet(); //???-przesunięcie wózka względem Point1 toru
|
|
else ActDist=RaTranslationGet(); //przesunięcie wózka względem Point1 toru
|
|
while (ActDist<ScanDist)
|
|
{
|
|
ActDist+=CurrDist;
|
|
if (ScanDir>0) //do przodu
|
|
{
|
|
if (Track->iNextDirection)
|
|
{
|
|
Track=Track->CurrentNext();
|
|
ScanDir=-ScanDir;
|
|
}
|
|
else
|
|
Track=Track->CurrentNext();
|
|
}
|
|
else //do tyłu
|
|
{
|
|
if (Track->iPrevDirection)
|
|
Track=Track->CurrentPrev();
|
|
else
|
|
{
|
|
Track=Track->CurrentPrev();
|
|
ScanDir=-ScanDir;
|
|
}
|
|
}
|
|
if (Track!=NULL)
|
|
{ //jesli jest kolejny odcinek toru
|
|
CurrDist=Track->Length();
|
|
FoundedObj=ABuFindNearestObject(Track, this, CouplNr);
|
|
if (FoundedObj!=NULL)
|
|
ActDist=ScanDist;
|
|
}
|
|
else //Jesli nie ma, to wychodzimy.
|
|
ActDist=ScanDist;
|
|
}
|
|
} //Koniec szukania najblizszego toru z jakims obiektem.
|
|
return FoundedObj;
|
|
}
|
|
|
|
//ABu 01.11.04 poczatek wyliczania przechylow pudla **********************
|
|
void __fastcall TDynamicObject::ABuModelRoll()
|
|
{//ustawienie przechyłki pojazdu i jego zawartości
|
|
// Ra: przechyłkę załatwiamy na etapie przesuwania modelu
|
|
}
|
|
|
|
//ABu 06.05.04 poczatek wyliczania obrotow wozkow **********************
|
|
|
|
void __fastcall TDynamicObject::ABuBogies()
|
|
{//Obracanie wozkow na zakretach. Na razie uwzględnia tylko zakręty,
|
|
//bez zadnych gorek i innych przeszkod.
|
|
if ((smBogie[0]!=NULL)&&(smBogie[1]!=NULL))
|
|
{
|
|
//modelRot.z=ABuAcos(Axle0.pPosition-Axle1.pPosition); //kąt obrotu pojazdu [rad]
|
|
//bogieRot[0].z=ABuAcos(Axle0.pPosition-Axle3.pPosition);
|
|
bogieRot[0].z=Axle0.vAngles.z;
|
|
bogieRot[0]=RadToDeg(modelRot-bogieRot[0]); //mnożenie wektora przez stałą
|
|
smBogie[0]->SetRotateXYZ(bogieRot[0]);
|
|
//bogieRot[1].z=ABuAcos(Axle2.pPosition-Axle1.pPosition);
|
|
bogieRot[1].z=Axle1.vAngles.z;
|
|
bogieRot[1]=RadToDeg(modelRot-bogieRot[1]);
|
|
smBogie[1]->SetRotateXYZ(bogieRot[1]);
|
|
}
|
|
};
|
|
//ABu 06.05.04 koniec wyliczania obrotow wozkow ************************
|
|
|
|
//ABu 16.03.03 sledzenie toru przed obiektem: **************************
|
|
void __fastcall TDynamicObject::ABuCheckMyTrack()
|
|
{//Funkcja przypisujaca obiekt prawidlowej tablicy Dynamics,
|
|
//bo gdzies jest jakis blad i wszystkie obiekty z danego
|
|
//pociagu na poczatku stawiane sa na jednym torze i wpisywane
|
|
//do jednej tablicy. Wykonuje sie tylko raz - po to 'ABuChecked'
|
|
TTrack* OldTrack=MyTrack;
|
|
TTrack* NewTrack=Axle0.GetTrack();
|
|
if ((NewTrack!=OldTrack)&&OldTrack)
|
|
{
|
|
OldTrack->RemoveDynamicObject(this);
|
|
NewTrack->AddDynamicObject(this);
|
|
}
|
|
iAxleFirst=0; //pojazd powiązany z przednią osią - Axle0
|
|
}
|
|
|
|
//Ra: w poniższej funkcji jest problem ze sprzęgami
|
|
TDynamicObject* __fastcall TDynamicObject::ABuFindObject(TTrack *Track,int ScanDir,Byte &CouplFound,double &dist)
|
|
{//Zwraca wskaźnik najbliższego obiektu znajdującego się
|
|
//na torze w określonym kierunku, ale tylko wtedy, kiedy
|
|
//obiekty mogą się zderzyć, tzn. nie mijają się.
|
|
|
|
//WE: Track - tor, na ktorym odbywa sie poszukiwanie,
|
|
// MyPointer - wskaznik do obiektu szukajacego. //Ra: zamieniłem na "this"
|
|
// ScanDir - kierunek szukania na torze (+1:w stronę Point2, -1:w stronę Point1)
|
|
// MyScanDir - kierunek szukania obiektu szukajacego (na jego torze); Ra: nie potrzebne
|
|
// MyCouplFound - nr sprzegu obiektu szukajacego; Ra: nie potrzebne
|
|
|
|
//WY: wskaznik do znalezionego obiektu.
|
|
// CouplFound - nr sprzegu znalezionego obiektu
|
|
if (Track->iNumDynamics>0)
|
|
{//sens szukania na tym torze jest tylko, gdy są na nim pojazdy
|
|
double ObjTranslation; //pozycja najblizszego obiektu na torze
|
|
double MyTranslation; //pozycja szukającego na torze
|
|
double MinDist=Track->Length(); //najmniejsza znaleziona odleglość (zaczynamy od długości toru)
|
|
double TestDist; //robocza odległość od kolejnych pojazdów na danym odcinku
|
|
int iMinDist=-1; //indeks wykrytego obiektu
|
|
//if (Track->iNumDynamics>1)
|
|
// iMinDist+=0; //tymczasowo pułapka
|
|
if (MyTrack==Track) //gdy szukanie na tym samym torze
|
|
MyTranslation=RaTranslationGet(); //położenie wózka względem Point1 toru
|
|
else //gdy szukanie na innym torze
|
|
if (ScanDir>0)
|
|
MyTranslation=0; //szukanie w kierunku Point2 (od zera) - jesteśmy w Point1
|
|
else
|
|
MyTranslation=MinDist; //szukanie w kierunku Point1 (do zera) - jesteśmy w Point2
|
|
if (ScanDir>=0)
|
|
{//jeśli szukanie w kierunku Point2
|
|
for (int i=0;i<Track->iNumDynamics;i++)
|
|
{//pętla po pojazdach
|
|
if (Track->Dynamics[i]!=this) //szukający się nie liczy
|
|
{
|
|
TestDist=(Track->Dynamics[i]->RaTranslationGet())-MyTranslation; //odległogłość tamtego od szukającego
|
|
if ((TestDist>0)&&(TestDist<=MinDist))
|
|
{//gdy jest po właściwej stronie i bliżej niż jakiś wcześniejszy
|
|
CouplFound=(Track->Dynamics[i]->RaDirectionGet()>0)?1:0; //to, bo (ScanDir>=0)
|
|
if (Track->iCategoryFlag&254) //trajektoria innego typu niż tor kolejowy
|
|
{//dla torów nie ma sensu tego sprawdzać, rzadko co jedzie po jednej szynie i się mija
|
|
//Ra: mijanie samochodów wcale nie jest proste
|
|
// Przesuniecie wzgledne pojazdow. Wyznaczane, zeby sprawdzic,
|
|
// czy pojazdy faktycznie sie zderzaja (moga byc przesuniete
|
|
// w/m siebie tak, ze nie zachodza na siebie i wtedy sie mijaja).
|
|
double RelOffsetH; //wzajemna odległość poprzeczna
|
|
if (CouplFound) //my na tym torze byśmy byli w kierunku Point2
|
|
//dla CouplFound=1 są zwroty zgodne - istotna różnica przesunięć
|
|
RelOffsetH=(MoverParameters->OffsetTrackH-Track->Dynamics[i]->MoverParameters->OffsetTrackH);
|
|
else
|
|
//dla CouplFound=0 są zwroty przeciwne - przesunięcia sumują się
|
|
RelOffsetH=(MoverParameters->OffsetTrackH+Track->Dynamics[i]->MoverParameters->OffsetTrackH);
|
|
if (RelOffsetH<0) RelOffsetH=-RelOffsetH;
|
|
if (RelOffsetH+RelOffsetH>MoverParameters->Dim.W+Track->Dynamics[i]->MoverParameters->Dim.W)
|
|
continue; //odległość większa od połowy sumy szerokości - kolizji nie będzie
|
|
//jeśli zahaczenie jest niewielkie, a jest miejsce na poboczu, to zjechać na pobocze
|
|
}
|
|
iMinDist=i; //potencjalna kolizja
|
|
MinDist=TestDist; //odleglość pomiędzy aktywnymi osiami pojazdów
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else //(ScanDir<0)
|
|
{
|
|
for (int i=0;i<Track->iNumDynamics;i++)
|
|
{
|
|
if (Track->Dynamics[i]!=this)
|
|
{
|
|
TestDist=MyTranslation-(Track->Dynamics[i]->RaTranslationGet()); //???-przesunięcie wózka względem Point1 toru
|
|
if ((TestDist>0)&&(TestDist<MinDist))
|
|
{
|
|
CouplFound=(Track->Dynamics[i]->RaDirectionGet()>0)?0:1; //odwrotnie, bo (ScanDir<0)
|
|
if (Track->iCategoryFlag&254) //trajektoria innego typu niż tor kolejowy
|
|
{//dla torów nie ma sensu tego sprawdzać, rzadko co jedzie po jednej szynie i się mija
|
|
//Ra: mijanie samochodów wcale nie jest proste
|
|
// Przesunięcie względne pojazdów. Wyznaczane, żeby sprawdzić,
|
|
// czy pojazdy faktycznie się zderzają (mogą być przesunięte
|
|
// w/m siebie tak, że nie zachodzą na siebie i wtedy sie mijają).
|
|
double RelOffsetH; //wzajemna odległość poprzeczna
|
|
if (CouplFound) //my na tym torze byśmy byli w kierunku Point1
|
|
//dla CouplFound=1 są zwroty zgodne - istotna różnica przesunięć
|
|
RelOffsetH=(MoverParameters->OffsetTrackH-Track->Dynamics[i]->MoverParameters->OffsetTrackH);
|
|
else
|
|
//dla CouplFound=0 są zwroty przeciwne - przesunięcia sumują się
|
|
RelOffsetH=(MoverParameters->OffsetTrackH+Track->Dynamics[i]->MoverParameters->OffsetTrackH);
|
|
if (RelOffsetH<0) RelOffsetH=-RelOffsetH;
|
|
if (RelOffsetH+RelOffsetH>MoverParameters->Dim.W+Track->Dynamics[i]->MoverParameters->Dim.W)
|
|
continue; //odległość większa od połowy sumy szerokości - kolizji nie będzie
|
|
}
|
|
iMinDist=i; //potencjalna kolizja
|
|
MinDist=TestDist; //odleglość pomiędzy aktywnymi osiami pojazdów
|
|
}
|
|
}
|
|
}
|
|
}
|
|
dist+=MinDist; //doliczenie odległości przeszkody albo długości odcinka do przeskanowanej odległości
|
|
return (iMinDist>=0)?Track->Dynamics[iMinDist]:NULL;
|
|
}
|
|
dist+=Track->Length(); //doliczenie długości odcinka do przeskanowanej odległości
|
|
return NULL; //nie ma pojazdów na torze, to jest NULL
|
|
}
|
|
|
|
int TDynamicObject::DettachStatus(int dir)
|
|
{//sprawdzenie odległości sprzęgów rzeczywistych od strony (dir): 0=przód,1=tył
|
|
//Ra: dziwne, że ta funkcja nie jest używana
|
|
if (!MoverParameters->Couplers[dir].CouplingFlag)
|
|
return 0; //jeśli nic nie podłączone, to jest OK
|
|
return (MoverParameters->DettachStatus(dir)); //czy jest w odpowiedniej odległości?
|
|
}
|
|
|
|
int TDynamicObject::Dettach(int dir)
|
|
{//rozłączenie sprzęgów rzeczywistych od strony (dir): 0=przód,1=tył
|
|
//zwraca maskę bitową aktualnych sprzegów (0 jeśli rozłączony)
|
|
if (ctOwner)
|
|
{//jeśli pojazd ma przypisany obiekt nadzorujący skład, to póki są wskaźniki
|
|
TDynamicObject *d=this;
|
|
while (d)
|
|
{
|
|
d->ctOwner=NULL; //usuwanie właściciela
|
|
d=d->Prev();
|
|
}
|
|
d=Next();
|
|
while (d)
|
|
{
|
|
d->ctOwner=NULL; //usuwanie właściciela
|
|
d=d->Next(); //i w drugą stronę
|
|
}
|
|
}
|
|
if (MoverParameters->Couplers[dir].CouplingFlag) //odczepianie, o ile coś podłączone
|
|
MoverParameters->Dettach(dir);
|
|
return MoverParameters->Couplers[dir].CouplingFlag; //sprzęg po rozłączaniu (czego się nie da odpiąć
|
|
}
|
|
|
|
void TDynamicObject::CouplersDettach(double MinDist,int MyScanDir)
|
|
{//funkcja rozłączajaca podłączone sprzęgi, jeśli odległość przekracza (MinDist)
|
|
//MinDist - dystans minimalny, dla ktorego mozna rozłączać
|
|
if (MyScanDir>0)
|
|
{
|
|
if (PrevConnected) //pojazd od strony sprzęgu 0
|
|
{
|
|
if (MoverParameters->Couplers[0].CoupleDist>MinDist) //sprzęgi wirtualne zawsze przekraczają
|
|
{
|
|
if ((PrevConnectedNo?PrevConnected->NextConnected:PrevConnected->PrevConnected)==this)
|
|
{//Ra: nie rozłączamy znalezionego, jeżeli nie do nas podłączony (może jechać w innym kierunku)
|
|
PrevConnected->MoverParameters->Couplers[PrevConnectedNo].Connected=NULL;
|
|
if (PrevConnectedNo==0)
|
|
{
|
|
PrevConnected->PrevConnectedNo=2; //sprzęg 0 nie podłączony
|
|
PrevConnected->PrevConnected=NULL;
|
|
}
|
|
else if (PrevConnectedNo==1)
|
|
{
|
|
PrevConnected->NextConnectedNo=2; //sprzęg 1 nie podłączony
|
|
PrevConnected->NextConnected=NULL;
|
|
}
|
|
}
|
|
//za to zawsze odłączamy siebie
|
|
PrevConnected=NULL;
|
|
PrevConnectedNo=2; //sprzęg 0 nie podłączony
|
|
MoverParameters->Couplers[0].Connected=NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (NextConnected) //pojazd od strony sprzęgu 1
|
|
{
|
|
if (MoverParameters->Couplers[1].CoupleDist>MinDist) //sprzęgi wirtualne zawsze przekraczają
|
|
{
|
|
if ((NextConnectedNo?NextConnected->NextConnected:NextConnected->PrevConnected)==this)
|
|
{//Ra: nie rozłączamy znalezionego, jeżeli nie do nas podłączony (może jechać w innym kierunku)
|
|
NextConnected->MoverParameters->Couplers[NextConnectedNo].Connected=NULL;
|
|
if (NextConnectedNo==0)
|
|
{
|
|
NextConnected->PrevConnectedNo=2; //sprzęg 0 nie podłączony
|
|
NextConnected->PrevConnected=NULL;
|
|
}
|
|
else if (NextConnectedNo==1)
|
|
{
|
|
NextConnected->NextConnectedNo=2; //sprzęg 1 nie podłączony
|
|
NextConnected->NextConnected=NULL;
|
|
}
|
|
}
|
|
NextConnected=NULL;
|
|
NextConnectedNo=2; //sprzęg 1 nie podłączony
|
|
MoverParameters->Couplers[1].Connected=NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void TDynamicObject::ABuScanObjects(int ScanDir,double ScanDist)
|
|
{//skanowanie toru w poszukiwaniu kolidujących pojazdów
|
|
//ScanDir - określa kierunek poszukiwania zależnie od zwrotu prędkości pojazdu
|
|
// ScanDir=1 - od strony Coupler0, ScanDir=-1 - od strony Coupler1
|
|
int MyScanDir=ScanDir; //zapamiętanie kierunku poszukiwań na torze początkowym, względem sprzęgów
|
|
TTrackFollower *FirstAxle=(MyScanDir>0?&Axle0:&Axle1); //można by to trzymać w trainset
|
|
TTrack *Track=FirstAxle->GetTrack(); //tor na którym "stoi" skrajny wózek (może być inny niż tor pojazdu)
|
|
if (FirstAxle->GetDirection()<0) //czy oś jest ustawiona w stronę Point1?
|
|
ScanDir=-ScanDir; //jeśli tak, to kierunek szukania będzie przeciwny (teraz względem toru)
|
|
Byte MyCouplFound; //numer sprzęgu do podłączenia w obiekcie szukajacym
|
|
MyCouplFound=(MyScanDir<0)?1:0;
|
|
Byte CouplFound; //numer sprzęgu w znalezionym obiekcie (znaleziony wypełni)
|
|
TDynamicObject *FoundedObj; //znaleziony obiekt
|
|
double ActDist=0; //przeskanowana odleglość; odległość do zawalidrogi
|
|
FoundedObj=ABuFindObject(Track,ScanDir,CouplFound,ActDist); //zaczynamy szukać na tym samym torze
|
|
|
|
/*
|
|
if (FoundedObj) //jak coś znajdzie, to śledzimy
|
|
{//powtórzenie wyszukiwania tylko do zastawiania pułepek podczas testów
|
|
if (ABuGetDirection()<0) ScanDir=ScanDir; //ustalenie kierunku względem toru
|
|
FoundedObj=ABuFindObject(Track,this,ScanDir,CouplFound);
|
|
}
|
|
*/
|
|
|
|
if (DebugModeFlag)
|
|
if (FoundedObj) //kod służący do logowania błędów
|
|
if (CouplFound==0)
|
|
{
|
|
if (FoundedObj->PrevConnected)
|
|
if (FoundedObj->PrevConnected!=this) //odświeżenie tego samego się nie liczy
|
|
WriteLog("0! Coupler warning on "+asName+":"+AnsiString(MyCouplFound)+" - "+FoundedObj->asName+":0 connected to "+FoundedObj->PrevConnected->asName+":"+AnsiString(FoundedObj->PrevConnectedNo));
|
|
}
|
|
else
|
|
{
|
|
if (FoundedObj->NextConnected)
|
|
if (FoundedObj->NextConnected!=this) //odświeżenie tego samego się nie liczy
|
|
WriteLog("0! Coupler warning on "+asName+":"+AnsiString(MyCouplFound)+" - "+FoundedObj->asName+":1 connected to "+FoundedObj->NextConnected->asName+":"+AnsiString(FoundedObj->NextConnectedNo));
|
|
}
|
|
|
|
|
|
if (FoundedObj==NULL) //jeśli nie ma na tym samym, szukamy po okolicy
|
|
{//szukanie najblizszego toru z jakims obiektem
|
|
//praktycznie przeklejone z TraceRoute()...
|
|
//double CurrDist=0; //aktualna dlugosc toru
|
|
if (ScanDir>=0) //uwzględniamy kawalek przeanalizowanego wcześniej toru
|
|
ActDist=Track->Length()-FirstAxle->GetTranslation(); //odległość osi od Point2 toru
|
|
else
|
|
ActDist=FirstAxle->GetTranslation(); //odległość osi od Point1 toru
|
|
while (ActDist<ScanDist)
|
|
{
|
|
//ActDist+=CurrDist; //odległość już przeanalizowana
|
|
if (ScanDir>0) //w kierunku Point2 toru
|
|
{
|
|
if (Track?Track->iNextDirection:false) //jeśli następny tor jest podpięty od Point2
|
|
ScanDir=-ScanDir; //to zmieniamy kierunek szukania na tym torze
|
|
Track=Track->CurrentNext(); //potem dopiero zmieniamy wskaźnik
|
|
}
|
|
else //w kierunku Point1
|
|
{
|
|
if (Track?!Track->iPrevDirection:true) //jeśli poprzedni tor nie jest podpięty od Point2
|
|
ScanDir=-ScanDir; //to zmieniamy kierunek szukania na tym torze
|
|
Track=Track->CurrentPrev(); //potem dopiero zmieniamy wskaźnik
|
|
}
|
|
if (Track)
|
|
{//jesli jest kolejny odcinek toru
|
|
//CurrDist=Track->Length(); //doliczenie tego toru do przejrzanego dystandu
|
|
FoundedObj=ABuFindObject(Track,ScanDir,CouplFound,ActDist); //przejrzenie pojazdów tego toru
|
|
if (FoundedObj)
|
|
{
|
|
//ActDist=ScanDist; //wyjście z pętli poszukiwania
|
|
break;
|
|
}
|
|
}
|
|
else //jeśli toru nie ma, to wychodzimy
|
|
{
|
|
ActDist=ScanDist+1.0; //koniec przeglądania torów
|
|
break;
|
|
}
|
|
}
|
|
} // Koniec szukania najbliższego toru z jakimś obiektem.
|
|
//teraz odczepianie i jeśli coś się znalazło, doczepianie.
|
|
if (MyScanDir>0?PrevConnected:NextConnected)
|
|
if ((MyScanDir>0?PrevConnected:NextConnected)!=FoundedObj)
|
|
CouplersDettach(1.0,MyScanDir); //odłączamy, jeśli dalej niż metr
|
|
// i łączenie sprzęgiem wirtualnym
|
|
if (FoundedObj)
|
|
{//siebie można bezpiecznie podłączyć jednostronnie do znalezionego
|
|
MoverParameters->Attach(MyCouplFound,CouplFound,FoundedObj->MoverParameters,ctrain_virtual);
|
|
//MoverParameters->Couplers[MyCouplFound].Render=false; //wirtualnego nie renderujemy
|
|
if (MyCouplFound==0)
|
|
{
|
|
PrevConnected=FoundedObj; //pojazd od strony sprzęgu 0
|
|
PrevConnectedNo=CouplFound;
|
|
}
|
|
else
|
|
{
|
|
NextConnected=FoundedObj; //pojazd od strony sprzęgu 1
|
|
NextConnectedNo=CouplFound;
|
|
}
|
|
if (FoundedObj->MoverParameters->Couplers[CouplFound].CouplingFlag==ctrain_virtual)
|
|
{//Ra: wpinamy się wirtualnym tylko jeśli znaleziony ma wirtualny sprzęg
|
|
FoundedObj->MoverParameters->Attach(CouplFound,MyCouplFound,this->MoverParameters,ctrain_virtual);
|
|
if (CouplFound==0) //jeśli widoczny sprzęg 0 znalezionego
|
|
{
|
|
if (DebugModeFlag)
|
|
if (FoundedObj->PrevConnected)
|
|
if (FoundedObj->PrevConnected!=this)
|
|
WriteLog("1! Coupler warning on "+asName+":"+AnsiString(MyCouplFound)+" - "+FoundedObj->asName+":0 connected to "+FoundedObj->PrevConnected->asName+":"+AnsiString(FoundedObj->PrevConnectedNo));
|
|
FoundedObj->PrevConnected=this;
|
|
FoundedObj->PrevConnectedNo=MyCouplFound;
|
|
}
|
|
else //jeśli widoczny sprzęg 1 znalezionego
|
|
{
|
|
if (DebugModeFlag)
|
|
if (FoundedObj->NextConnected)
|
|
if (FoundedObj->NextConnected!=this)
|
|
WriteLog("1! Coupler warning on "+asName+":"+AnsiString(MyCouplFound)+" - "+FoundedObj->asName+":1 connected to "+FoundedObj->NextConnected->asName+":"+AnsiString(FoundedObj->NextConnectedNo));
|
|
FoundedObj->NextConnected=this;
|
|
FoundedObj->NextConnectedNo=MyCouplFound;
|
|
}
|
|
}
|
|
//Ra: jeśli dwa samochody się mijają na odcinku przed zawrotką, to odległość między nimi nie może być liczona w linii prostej!
|
|
fTrackBlock=MoverParameters->Couplers[MyCouplFound].CoupleDist; //odległość do najbliższego pojazdu w linii prostej
|
|
if (Track->iCategoryFlag>1) //jeśli samochód
|
|
if (ActDist>MoverParameters->Dim.L+FoundedObj->MoverParameters->Dim.L) //przeskanowana odległość większa od długości pojazdów
|
|
//else if (ActDist<ScanDist) //dla samochodów musi być uwzględniona droga do zawrócenia
|
|
fTrackBlock=ActDist; //ta odległość jest wiecej warta
|
|
//if (fTrackBlock<500.0)
|
|
// WriteLog("Collision of "+AnsiString(fTrackBlock)+"m detected by "+asName+":"+AnsiString(MyCouplFound)+" with "+FoundedObj->asName);
|
|
}
|
|
else //nic nie znalezione, to nie ma przeszkód
|
|
fTrackBlock=10000.0;
|
|
}
|
|
//----------ABu: koniec skanowania pojazdow
|
|
|
|
__fastcall TDynamicObject::TDynamicObject()
|
|
{
|
|
modelShake=vector3(0,0,0);
|
|
fTrackBlock=10000.0; //brak przeszkody na drodze
|
|
btnOn=false;
|
|
vUp=vWorldUp;
|
|
vFront=vWorldFront;
|
|
vLeft=vWorldLeft;
|
|
iNumAxles=0;
|
|
MoverParameters=NULL;
|
|
Mechanik=NULL;
|
|
MechInside=false;
|
|
//McZapkie-270202
|
|
Controller=AIdriver;
|
|
bDisplayCab=false; //030303
|
|
bBrakeAcc=false;
|
|
NextConnected=PrevConnected=NULL;
|
|
NextConnectedNo=PrevConnectedNo=2; //ABu: Numery sprzegow. 2=nie podłączony
|
|
CouplCounter=50; //będzie sprawdzać na początku
|
|
asName="";
|
|
bEnabled=true;
|
|
MyTrack=NULL;
|
|
//McZapkie-260202
|
|
dRailLength=25.0;
|
|
for (int i=0;i<MaxAxles;i++)
|
|
dRailPosition[i]=0.0;
|
|
for (int i=0;i<MaxAxles;i++)
|
|
dWheelsPosition[i]=0.0; //będzie wczytane z MMD
|
|
iAxles=0;
|
|
dWheelAngle[0]=0.0;
|
|
dWheelAngle[1]=0.0;
|
|
dWheelAngle[2]=0.0;
|
|
//Winger 160204 - pantografy
|
|
//PantVolume = 3.5;
|
|
NoVoltTime=0;
|
|
dDoorMoveL=0.0;
|
|
dDoorMoveR=0.0;
|
|
//for (int i=0;i<8;i++)
|
|
//{
|
|
// DoorSpeedFactor[i]=random(150);
|
|
// DoorSpeedFactor[i]=(DoorSpeedFactor[i]+100)/100;
|
|
//}
|
|
mdModel=NULL;
|
|
mdKabina=NULL;
|
|
ReplacableSkinID[0]=0;
|
|
ReplacableSkinID[1]=0;
|
|
ReplacableSkinID[2]=0;
|
|
ReplacableSkinID[3]=0;
|
|
ReplacableSkinID[4]=0;
|
|
iAlpha=0x30300030; //tak gdy tekstury wymienne nie mają przezroczystości
|
|
//smWiazary[0]=smWiazary[1]=NULL;
|
|
smWahacze[0]=smWahacze[1]=smWahacze[2]=smWahacze[3]=NULL;
|
|
fWahaczeAmp=0;
|
|
smBrakeMode=NULL;
|
|
smLoadMode=NULL;
|
|
mdLoad=NULL;
|
|
mdLowPolyInt=NULL;
|
|
mdPrzedsionek=NULL;
|
|
smMechanik0=smMechanik1=NULL;
|
|
smBuforLewy[0]=smBuforLewy[1]=NULL;
|
|
smBuforPrawy[0]=smBuforPrawy[1]=NULL;
|
|
enginevolume=0;
|
|
smBogie[0]=smBogie[1]=NULL;
|
|
bogieRot[0]=bogieRot[1]=vector3(0,0,0);
|
|
modelRot=vector3(0,0,0);
|
|
eng_vol_act=0.8;
|
|
eng_dfrq=0;
|
|
eng_frq_act=1;
|
|
eng_turbo=0;
|
|
cp1=cp2=sp1=sp2=0;
|
|
iDirection=1; //stoi w kierunku tradycyjnym (0, gdy jest odwrócony)
|
|
iAxleFirst=0; //numer pierwszej osi w kierunku ruchu (przełączenie następuje, gdy osie sa na tym samym torze)
|
|
iInventory=0; //flagi bitowe posiadanych submodeli (zaktualizuje się po wczytaniu MMD)
|
|
RaLightsSet(0,0); //początkowe zerowanie stanu świateł
|
|
//Ra: domyślne ilości animacji dla zgodności wstecz (gdy brak ilości podanych w MMD)
|
|
iAnimType[ANIM_WHEELS ]=8; //0-osie (8)
|
|
iAnimType[ANIM_DOORS ]=8; //1-drzwi (8)
|
|
iAnimType[ANIM_LEVERS ]=4; //2-wahacze (4) - np. nogi konia
|
|
iAnimType[ANIM_BUFFERS]=4; //3-zderzaki (4)
|
|
iAnimType[ANIM_BOOGIES]=2; //4-wózki (2)
|
|
iAnimType[ANIM_PANTS ]=2; //5-pantografy (2)
|
|
iAnimType[ANIM_STEAMS ]=0; //6-tłoki (napęd parowozu)
|
|
iAnimations=0; //na razie nie ma żadnego
|
|
pAnimations=NULL;
|
|
pAnimated=NULL;
|
|
fShade=0.0; //standardowe oświetlenie na starcie
|
|
iHornWarning=1; //numer syreny do użycia po otrzymaniu sygnału do jazdy
|
|
asDestination="none"; //stojący nigdzie nie jedzie
|
|
pValveGear=NULL; //Ra: tymczasowo
|
|
iCabs=0; //maski bitowe modeli kabin
|
|
smBrakeSet=NULL; //nastawa hamulca (wajcha)
|
|
smLoadSet=NULL; //nastawa ładunku (wajcha)
|
|
smWiper=NULL; //wycieraczka (poniekąd też wajcha)
|
|
fScanDist=300.0; //odległość skanowania, zwiększana w trybie łączenia
|
|
ctOwner=NULL; //na początek niczyj
|
|
iOverheadMask=0; //maska przydzielana przez AI pojazdom posiadającym pantograf, aby wymuszały jazdę bezprądową
|
|
tmpTraction.TractionVoltage=0; //Ra 2F1H: prowizorka, trzeba przechować napięcie, żeby nie wywalało WS pod izolatorem
|
|
fAdjustment=0.0; //korekcja odległości pomiędzy wózkami (np. na łukach)
|
|
}
|
|
|
|
__fastcall TDynamicObject::~TDynamicObject()
|
|
{//McZapkie-250302 - zamykanie logowania parametrow fizycznych
|
|
SafeDelete(Mechanik);
|
|
SafeDelete(MoverParameters);
|
|
//Ra: wyłączanie dźwięków powinno być dodane w ich destruktorach, ale się sypie
|
|
/* to też się sypie
|
|
for (int i=0;i<MaxAxles;++i)
|
|
rsStukot[i].Stop(); //dzwieki poszczegolnych osi
|
|
rsSilnik.Stop();
|
|
rsWentylator.Stop();
|
|
rsPisk.Stop();
|
|
rsDerailment.Stop();
|
|
sPantUp.Stop();
|
|
sPantDown.Stop();
|
|
sBrakeAcc.Stop(); //dzwiek przyspieszacza
|
|
rsDiesielInc.Stop();
|
|
rscurve.Stop();
|
|
*/
|
|
delete[] pAnimations; //obiekty obsługujące animację
|
|
delete[] pAnimated; //lista animowanych submodeli
|
|
}
|
|
|
|
double __fastcall TDynamicObject::Init(
|
|
AnsiString Name, //nazwa pojazdu, np. "EU07-424"
|
|
AnsiString BaseDir, //z którego katalogu wczytany, np. "PKP/EU07"
|
|
AnsiString asReplacableSkin, //nazwa wymiennej tekstury
|
|
AnsiString Type_Name, //nazwa CHK/MMD, np. "303E"
|
|
TTrack *Track, //tor początkowy wstwawienia (początek składu)
|
|
double fDist, //dystans względem punktu 1
|
|
AnsiString DriverType, //typ obsady
|
|
double fVel, //prędkość początkowa
|
|
AnsiString TrainName, //nazwa składu, np. "PE2307" albo Vmax, jeśli pliku nie ma a są cyfry
|
|
float Load, //ilość ładunku
|
|
AnsiString LoadType, //nazwa ładunku
|
|
bool Reversed, //true, jeśli ma stać odwrotnie w składzie
|
|
AnsiString MoreParams //dodatkowe parametry wczytywane w postaci tekstowej
|
|
)
|
|
{//Ustawienie początkowe pojazdu
|
|
iDirection=(Reversed?0:1); //Ra: 0, jeśli ma być wstawiony jako obrócony tyłem
|
|
asBaseDir="dynamic\\"+BaseDir+"\\"; //McZapkie-310302
|
|
asName=Name;
|
|
AnsiString asAnimName=""; //zmienna robocza do wyszukiwania osi i wózków
|
|
//Ra: zmieniamy znaczenie obsady na jednoliterowe, żeby dosadzić kierownika
|
|
if (DriverType=="headdriver") DriverType="1"; //sterujący kabiną +1
|
|
else if (DriverType=="reardriver") DriverType="2"; //sterujący kabiną -1
|
|
//else if (DriverType=="connected") DriverType="c"; //tego trzeba się pozbyć na rzecz ukrotnienia
|
|
else if (DriverType=="passenger") DriverType="p"; //to do przemyślenia
|
|
else if (DriverType=="nobody") DriverType=""; //nikt nie siedzi
|
|
int Cab=0; //numer kabiny z obsadą (nie można zająć obu)
|
|
if (DriverType.Pos("1")) //od przodu składu
|
|
Cab=1;//iDirection?1:-1; //iDirection=1 gdy normalnie, =0 odwrotnie
|
|
else if (DriverType.Pos("2")) //od tyłu składu
|
|
Cab=-1;//iDirection?-1:1;
|
|
else if (DriverType=="p")
|
|
{
|
|
if (random(6)<3) Cab=1; else Cab=-1; //losowy przydział kabiny
|
|
}
|
|
/* to nie ma uzasadnienia
|
|
else
|
|
{//obsada nie rozpoznana
|
|
Cab=0; //McZapkie-010303: w przyszlosci dac tez pomocnika, palacza, konduktora itp.
|
|
Error("Unknown DriverType description: "+DriverType);
|
|
DriverType="nobody";
|
|
}
|
|
*/
|
|
//utworzenie parametrów fizyki
|
|
MoverParameters=new TMoverParameters(iDirection?fVel:-fVel,Type_Name,asName,Load,LoadType,Cab);
|
|
iLights=MoverParameters->iLights; //wskaźnik na stan własnych świateł (zmienimy dla rozrządczych EZT)
|
|
//McZapkie: TypeName musi byc nazwą CHK/MMD pojazdu
|
|
if (!MoverParameters->LoadChkFile(asBaseDir))
|
|
{//jak wczytanie CHK się nie uda, to błąd
|
|
if (ConversionError==-8)
|
|
ErrorLog("Missed file: "+BaseDir+"\\"+Type_Name+".fiz");
|
|
Error("Cannot load dynamic object "+asName+" from:\r\n"+BaseDir+"\\"+Type_Name+".fiz\r\nError "+ConversionError+" in line "+LineCount);
|
|
return 0.0; //zerowa długość to brak pojazdu
|
|
}
|
|
bool driveractive=(fVel!=0.0); //jeśli prędkość niezerowa, to aktywujemy ruch
|
|
if (!MoverParameters->CheckLocomotiveParameters(driveractive,(fVel>0?1:-1)*Cab*(iDirection?1:-1))) //jak jedzie lub obsadzony to gotowy do drogi
|
|
{
|
|
Error("Parameters mismatch: dynamic object "+asName+" from\n"+BaseDir+"\\"+Type_Name);
|
|
return 0.0; //zerowa długość to brak pojazdu
|
|
}
|
|
MoverParameters->BrakeLevelSet(MoverParameters->BrakeCtrlPos); //poprawienie hamulca po ewentualnym przestawieniu przez Pascal
|
|
|
|
//dodatkowe parametry yB
|
|
MoreParams+="."; //wykonuje o jedną iterację za mało, więc trzeba mu dodać kropkę na koniec
|
|
int kropka=MoreParams.Pos("."); //znajdź kropke
|
|
AnsiString ActPar; //na parametry
|
|
while (kropka>0) //jesli sa kropki jeszcze
|
|
{
|
|
int dlugosc=MoreParams.Length();
|
|
ActPar=MoreParams.SubString(1,kropka-1).UpperCase(); //pierwszy parametr;
|
|
MoreParams=MoreParams.SubString(kropka+1,dlugosc-kropka); //reszta do dalszej obrobki
|
|
kropka=MoreParams.Pos(".");
|
|
|
|
if(ActPar.SubString(1,1)=="B") //jesli hamulce
|
|
{ //sprawdzanie kolejno nastaw
|
|
WriteLog("Wpis hamulca: " + ActPar);
|
|
if (ActPar.Pos("G")>0) {MoverParameters->BrakeDelaySwitch(bdelay_G);}
|
|
if (ActPar.Pos("P")>0) {MoverParameters->BrakeDelaySwitch(bdelay_P);}
|
|
if (ActPar.Pos("R")>0) {MoverParameters->BrakeDelaySwitch(bdelay_R);}
|
|
if (ActPar.Pos("M")>0) {MoverParameters->BrakeDelaySwitch(bdelay_R); MoverParameters->BrakeDelaySwitch(bdelay_R+bdelay_M);}
|
|
//wylaczanie hamulca
|
|
if (ActPar.Pos("<>")>0) //wylaczanie na probe hamowania naglego
|
|
{
|
|
MoverParameters->BrakeStatus|=128; //wylacz
|
|
}
|
|
if (ActPar.Pos("0")>0) //wylaczanie na sztywno
|
|
{
|
|
MoverParameters->BrakeStatus|=128; //wylacz
|
|
MoverParameters->Hamulec->ForceEmptiness();
|
|
MoverParameters->BrakeReleaser(1); //odluznij automatycznie
|
|
}
|
|
if (ActPar.Pos("E")>0) //oprozniony
|
|
{
|
|
MoverParameters->Hamulec->ForceEmptiness();
|
|
MoverParameters->BrakeReleaser(1); //odluznij automatycznie
|
|
MoverParameters->Pipe->CreatePress(0);
|
|
MoverParameters->Pipe2->CreatePress(0);
|
|
}
|
|
if (ActPar.Pos("Q")>0) //oprozniony
|
|
{
|
|
// MoverParameters->Hamulec->ForceEmptiness(); //TODO: sprawdzic, dlaczego pojawia sie blad przy uzyciu tej linijki w lokomotywie
|
|
MoverParameters->BrakeReleaser(1); //odluznij automatycznie
|
|
MoverParameters->Pipe->CreatePress(0.0);
|
|
MoverParameters->PipePress=0.0;
|
|
MoverParameters->Pipe2->CreatePress(0.0);
|
|
MoverParameters->ScndPipePress=0.0;
|
|
MoverParameters->PantVolume=1;
|
|
MoverParameters->PantPress=0;
|
|
MoverParameters->CompressedVolume=0;
|
|
}
|
|
|
|
if (ActPar.Pos("1")>0) //wylaczanie 10%
|
|
{
|
|
if (random(10)<1) //losowanie 1/10
|
|
{
|
|
MoverParameters->BrakeStatus|=128; //wylacz
|
|
MoverParameters->Hamulec->ForceEmptiness();
|
|
MoverParameters->BrakeReleaser(1); //odluznij automatycznie
|
|
}
|
|
}
|
|
if (ActPar.Pos("X")>0) //agonalny wylaczanie 20%, usrednienie przekladni
|
|
{
|
|
if (random(100)<20) //losowanie 20/100
|
|
{
|
|
MoverParameters->BrakeStatus|=128; //wylacz
|
|
MoverParameters->Hamulec->ForceEmptiness();
|
|
MoverParameters->BrakeReleaser(1); //odluznij automatycznie
|
|
}
|
|
if (MoverParameters->BrakeCylMult[2]*MoverParameters->BrakeCylMult[1]>0.01) //jesli jest nastawiacz mechaniczny PL
|
|
{
|
|
float rnd=random(100);
|
|
if (rnd<20) //losowanie 20/100 usrednienie
|
|
{
|
|
MoverParameters->BrakeCylMult[2]=MoverParameters->BrakeCylMult[1]=(MoverParameters->BrakeCylMult[2]+MoverParameters->BrakeCylMult[1])/2;
|
|
}
|
|
else
|
|
if (rnd<70) //losowanie 70/100-20/100 oslabienie
|
|
{
|
|
MoverParameters->BrakeCylMult[1]=MoverParameters->BrakeCylMult[1]*0.50;
|
|
MoverParameters->BrakeCylMult[2]=MoverParameters->BrakeCylMult[2]*0.75;
|
|
}
|
|
else
|
|
if (rnd<80) //losowanie 80/100-70/100 tylko prozny
|
|
{
|
|
MoverParameters->BrakeCylMult[2]=MoverParameters->BrakeCylMult[1];
|
|
}
|
|
else //tylko ladowny
|
|
{
|
|
MoverParameters->BrakeCylMult[1]=MoverParameters->BrakeCylMult[2];
|
|
}
|
|
}
|
|
}
|
|
//nastawianie ladunku
|
|
if (ActPar.Pos("T")>0) //prozny
|
|
{ MoverParameters->DecBrakeMult(); MoverParameters->DecBrakeMult(); } //dwa razy w dol
|
|
if (ActPar.Pos("H")>0) //ladowny I (dla P-Ł dalej prozny)
|
|
{ MoverParameters->IncBrakeMult(); MoverParameters->IncBrakeMult(); MoverParameters->DecBrakeMult(); } //dwa razy w gore i obniz
|
|
if (ActPar.Pos("F")>0) //ladowny II
|
|
{ MoverParameters->IncBrakeMult(); MoverParameters->IncBrakeMult(); } //dwa razy w gore
|
|
if (ActPar.Pos("N")>0) //parametr neutralny
|
|
{ }
|
|
} //koniec hamulce
|
|
else if(ActPar.SubString(1,1)=="") //tu mozna wpisac inny prefiks i inne rzeczy
|
|
{
|
|
//jakies inne prefiksy
|
|
}
|
|
|
|
} //koniec while kropka
|
|
|
|
if (MoverParameters->CategoryFlag&2) //jeśli samochód
|
|
{//ustawianie samochodow na poboczu albo na środku drogi
|
|
if (Track->fTrackWidth<3.5) //jeśli droga wąska
|
|
MoverParameters->OffsetTrackH=0.0; //to stawiamy na środku, niezależnie od stanu ruchu
|
|
else
|
|
if (driveractive) //od 3.5m do 8.0m jedzie po środku pasa, dla szerszych w odległości 1.5m
|
|
MoverParameters->OffsetTrackH=Track->fTrackWidth<=8.0?-Track->fTrackWidth*0.25:-1.5;
|
|
else //jak stoi, to kołem na poboczu i pobieramy szerokość razem z poboczem, ale nie z chodnikiem
|
|
MoverParameters->OffsetTrackH=-0.5*(Track->WidthTotal()-MoverParameters->Dim.W)+0.05;
|
|
iHornWarning=0; //nie będzie trąbienia po podaniu zezwolenia na jazdę
|
|
if (fDist<0.0) //-0.5*MoverParameters->Dim.L) //jeśli jest przesunięcie do tyłu
|
|
if (!Track->CurrentPrev()) //a nie ma tam odcinka i trzeba by coś wygenerować
|
|
fDist=-fDist; //to traktujemy, jakby przesunięcie było w drugą stronę
|
|
}
|
|
//w wagonie tez niech jedzie
|
|
//if (MoverParameters->MainCtrlPosNo>0 &&
|
|
// if (MoverParameters->CabNo!=0)
|
|
if (DriverType!="")
|
|
{//McZapkie-040602: jeśli coś siedzi w pojeździe
|
|
if (Name==AnsiString(Global::asHumanCtrlVehicle)) //jeśli pojazd wybrany do prowadzenia
|
|
{
|
|
if (DebugModeFlag?false:MoverParameters->EngineType!=Dumb) //jak nie Debugmode i nie jest dumbem
|
|
Controller=Humandriver; //wsadzamy tam sterującego
|
|
else //w przeciwnym razie trzeba włączyć pokazywanie kabiny
|
|
bDisplayCab=true;
|
|
}
|
|
//McZapkie-151102: rozkład jazdy czytany z pliku *.txt z katalogu w którym jest sceneria
|
|
if (DriverType.Pos("1")||DriverType.Pos("2"))
|
|
{//McZapkie-110303: mechanik i rozklad tylko gdy jest obsada
|
|
//MoverParameters->ActiveCab=MoverParameters->CabNo; //ustalenie aktywnej kabiny (rozrząd)
|
|
Mechanik=new TController(Controller,this,Aggressive);
|
|
if (TrainName.IsEmpty()) //jeśli nie w składzie
|
|
{
|
|
Mechanik->DirectionInitial(); //załączenie rozrządu (wirtualne kabiny) itd.
|
|
Mechanik->PutCommand("Timetable:",iDirection?-fVel:fVel,0,NULL); //tryb pociągowy z ustaloną prędkością (względem sprzęgów)
|
|
}
|
|
//if (TrainName!="none")
|
|
// Mechanik->PutCommand("Timetable:"+TrainName,fVel,0,NULL);
|
|
}
|
|
else
|
|
if (DriverType=="p")
|
|
{//obserwator w charakterze pasażera
|
|
//Ra: to jest niebezpieczne, bo w razie co będzie pomagał hamulcem bezpieczeństwa
|
|
Mechanik=new TController(Controller,this,Easyman,false);
|
|
}
|
|
}
|
|
// McZapkie-250202
|
|
iAxles=(MaxAxles<MoverParameters->NAxles)?MaxAxles:MoverParameters->NAxles; //ilość osi
|
|
//wczytywanie z pliku nazwatypu.mmd, w tym model
|
|
LoadMMediaFile(asBaseDir,Type_Name,asReplacableSkin);
|
|
//McZapkie-100402: wyszukiwanie submodeli sprzegów
|
|
btCoupler1.Init("coupler1",mdModel,false); //false - ma być wyłączony
|
|
btCoupler2.Init("coupler2",mdModel,false);
|
|
btCPneumatic1.Init("cpneumatic1",mdModel);
|
|
btCPneumatic2.Init("cpneumatic2",mdModel);
|
|
btCPneumatic1r.Init("cpneumatic1r",mdModel);
|
|
btCPneumatic2r.Init("cpneumatic2r",mdModel);
|
|
btPneumatic1.Init("pneumatic1",mdModel);
|
|
btPneumatic2.Init("pneumatic2",mdModel);
|
|
btPneumatic1r.Init("pneumatic1r",mdModel);
|
|
btPneumatic2r.Init("pneumatic2r",mdModel);
|
|
btCCtrl1.Init("cctrl1",mdModel,false);
|
|
btCCtrl2.Init("cctrl2",mdModel,false);
|
|
btCPass1.Init("cpass1",mdModel,false);
|
|
btCPass2.Init("cpass2",mdModel,false);
|
|
//sygnaly
|
|
//ABu 060205: Zmiany dla koncowek swiecacych:
|
|
btEndSignals11.Init("endsignal13",mdModel,false);
|
|
btEndSignals21.Init("endsignal23",mdModel,false);
|
|
btEndSignals13.Init("endsignal12",mdModel,false);
|
|
btEndSignals23.Init("endsignal22",mdModel,false);
|
|
iInventory|=btEndSignals11.Active() ?0x01:0; //informacja, czy ma poszczególne światła
|
|
iInventory|=btEndSignals21.Active() ?0x02:0;
|
|
iInventory|=btEndSignals13.Active() ?0x04:0;
|
|
iInventory|=btEndSignals23.Active() ?0x08:0;
|
|
//ABu: to niestety zostawione dla kompatybilnosci modeli:
|
|
btEndSignals1.Init("endsignals1",mdModel,false);
|
|
btEndSignals2.Init("endsignals2",mdModel,false);
|
|
btEndSignalsTab1.Init("endtab1",mdModel,false);
|
|
btEndSignalsTab2.Init("endtab2",mdModel,false);
|
|
iInventory|=btEndSignals1.Active() ?0x10:0;
|
|
iInventory|=btEndSignals2.Active() ?0x20:0;
|
|
iInventory|=btEndSignalsTab1.Active()?0x40:0; //tabliczki blaszane
|
|
iInventory|=btEndSignalsTab2.Active()?0x80:0;
|
|
//ABu Uwaga! tu zmienic w modelu!
|
|
btHeadSignals11.Init("headlamp13",mdModel,false); //lewe
|
|
btHeadSignals12.Init("headlamp11",mdModel,false); //górne
|
|
btHeadSignals13.Init("headlamp12",mdModel,false); //prawe
|
|
btHeadSignals21.Init("headlamp23",mdModel,false);
|
|
btHeadSignals22.Init("headlamp21",mdModel,false);
|
|
btHeadSignals23.Init("headlamp22",mdModel,false);
|
|
TurnOff(); //resetowanie zmiennych submodeli
|
|
//wyszukiwanie zderzakow
|
|
if (mdModel) //jeśli ma w czym szukać
|
|
for (int i=0;i<2;i++)
|
|
{
|
|
asAnimName=AnsiString("buffer_left0")+(i+1);
|
|
smBuforLewy[i]=mdModel->GetFromName(asAnimName.c_str());
|
|
if (smBuforLewy[i])
|
|
smBuforLewy[i]->WillBeAnimated(); //ustawienie flagi animacji
|
|
asAnimName=AnsiString("buffer_right0")+(i+1);
|
|
smBuforPrawy[i]=mdModel->GetFromName(asAnimName.c_str());
|
|
if (smBuforPrawy[i])
|
|
smBuforPrawy[i]->WillBeAnimated();
|
|
}
|
|
for (int i=0;i<iAxles;i++) //wyszukiwanie osi (0 jest na końcu, dlatego dodajemy długość?)
|
|
dRailPosition[i]=(Reversed?-dWheelsPosition[i]:(dWheelsPosition[i]+MoverParameters->Dim.L))+fDist;
|
|
//McZapkie-250202 end.
|
|
Track->AddDynamicObject(this); //wstawiamy do toru na pozycję 0, a potem przesuniemy
|
|
//McZapkie: zmieniono na ilosc osi brane z chk
|
|
//iNumAxles=(MoverParameters->NAxles>3 ? 4 : 2 );
|
|
iNumAxles=2;
|
|
//McZapkie-090402: odleglosc miedzy czopami skretu lub osiami
|
|
fAxleDist=Max0R(MoverParameters->BDist,MoverParameters->ADist);
|
|
if (fAxleDist<0.2) fAxleDist=0.2; //żeby się dało wektory policzyć
|
|
if (fAxleDist>MoverParameters->Dim.L-0.2) //nie mogą być za daleko
|
|
fAxleDist=MoverParameters->Dim.L-0.2; //bo będzie "walenie w mur"
|
|
double fAxleDistHalf=fAxleDist*0.5;
|
|
//WriteLog("Dynamic "+Type_Name+" of length "+MoverParameters->Dim.L+" at "+AnsiString(fDist));
|
|
//if (Cab) //jeśli ma obsadę - zgodność wstecz, jeśli tor startowy ma Event0
|
|
// if (Track->Event0) //jeśli tor ma Event0
|
|
// if (fDist>=0.0) //jeśli jeśli w starych sceneriach początek składu byłby wysunięty na ten tor
|
|
// if (fDist<=0.5*MoverParameters->Dim.L+0.2) //ale nie jest wysunięty
|
|
// fDist+=0.5*MoverParameters->Dim.L+0.2; //wysunąć go na ten tor
|
|
//przesuwanie pojazdu tak, aby jego początek był we wskazanym miejcu
|
|
fDist-=0.5*MoverParameters->Dim.L; //dodajemy pół długości pojazdu, bo ustawiamy jego środek (zliczanie na minus)
|
|
switch (iNumAxles)
|
|
{//Ra: pojazdy wstawiane są na tor początkowy, a potem przesuwane
|
|
case 2: //ustawianie osi na torze
|
|
Axle0.Init(Track,this,iDirection?1:-1);
|
|
Axle0.Move((iDirection?fDist:-fDist)+fAxleDistHalf,false);
|
|
Axle1.Init(Track,this,iDirection?1:-1);
|
|
Axle1.Move((iDirection?fDist:-fDist)-fAxleDistHalf,false); //false, żeby nie generować eventów
|
|
//Axle2.Init(Track,this,iDirection?1:-1);
|
|
//Axle2.Move((iDirection?fDist:-fDist)-fAxleDistHalft+0.01),false);
|
|
//Axle3.Init(Track,this,iDirection?1:-1);
|
|
//Axle3.Move((iDirection?fDist:-fDist)+fAxleDistHalf-0.01),false);
|
|
break;
|
|
case 4:
|
|
Axle0.Init(Track,this,iDirection?1:-1);
|
|
Axle0.Move((iDirection?fDist:-fDist)+(fAxleDistHalf+MoverParameters->ADist*0.5),false);
|
|
Axle1.Init(Track,this,iDirection?1:-1);
|
|
Axle1.Move((iDirection?fDist:-fDist)-(fAxleDistHalf+MoverParameters->ADist*0.5),false);
|
|
//Axle2.Init(Track,this,iDirection?1:-1);
|
|
//Axle2.Move((iDirection?fDist:-fDist)-(fAxleDistHalf-MoverParameters->ADist*0.5),false);
|
|
//Axle3.Init(Track,this,iDirection?1:-1);
|
|
//Axle3.Move((iDirection?fDist:-fDist)+(fAxleDistHalf-MoverParameters->ADist*0.5),false);
|
|
break;
|
|
}
|
|
Move(0.0001); //potrzebne do wyliczenia aktualnej pozycji; nie może być zero, bo nie przeliczy pozycji
|
|
//teraz jeszcze trzeba przypisać pojazdy do nowego toru, bo przesuwanie początkowe osi nie zrobiło tego
|
|
ABuCheckMyTrack(); //zmiana toru na ten, co oś Axle0 (oś z przodu)
|
|
TLocation loc; //Ra: ustawienie pozycji do obliczania sprzęgów
|
|
loc.X=-vPosition.x;
|
|
loc.Y=vPosition.z;
|
|
loc.Z=vPosition.y;
|
|
MoverParameters->Loc=loc; //normalnie przesuwa ComputeMovement() w Update()
|
|
//pOldPos4=Axle1.pPosition; //Ra: nie używane
|
|
//pOldPos1=Axle0.pPosition;
|
|
//ActualTrack= GetTrack(); //McZapkie-030303
|
|
//ABuWozki 060504
|
|
if (mdModel) //jeśli ma w czym szukać
|
|
{
|
|
smBogie[0]=mdModel->GetFromName("bogie1"); //Ra: bo nazwy są małymi
|
|
smBogie[1]=mdModel->GetFromName("bogie2");
|
|
if (!smBogie[0])
|
|
smBogie[0]=mdModel->GetFromName("boogie01"); //Ra: alternatywna nazwa
|
|
if (!smBogie[1])
|
|
smBogie[1]=mdModel->GetFromName("boogie02"); //Ra: alternatywna nazwa
|
|
if (smBogie[0])
|
|
smBogie[0]->WillBeAnimated();
|
|
if (smBogie[1])
|
|
smBogie[1]->WillBeAnimated();
|
|
}
|
|
//ABu: zainicjowanie zmiennej, zeby nic sie nie ruszylo
|
|
//w pierwszej klatce, potem juz liczona prawidlowa wartosc masy
|
|
MoverParameters->ComputeConstans();
|
|
/*Ra: to nie działa - Event0 musi być wykonywany ciągle
|
|
if (fVel==0.0) //jeśli stoi
|
|
if (MoverParameters->CabNo!=0) //i ma kogoś w kabinie
|
|
if (Track->Event0) //a jest w tym torze event od stania
|
|
RaAxleEvent(Track->Event0); //dodanie eventu stania do kolejki
|
|
*/
|
|
vFloor=vector3(0,0,MoverParameters->Floor); //wektor podłogi dla wagonów, przesuwa ładunek
|
|
return MoverParameters->Dim.L; //długość większa od zera oznacza OK; 2mm docisku?
|
|
}
|
|
|
|
void __fastcall TDynamicObject::FastMove(double fDistance)
|
|
{
|
|
MoverParameters->dMoveLen=MoverParameters->dMoveLen+fDistance;
|
|
}
|
|
|
|
void __fastcall TDynamicObject::Move(double fDistance)
|
|
{//przesuwanie pojazdu po trajektorii polega na przesuwaniu poszczególnych osi
|
|
//Ra: wartość prędkości 2km/h ma ograniczyć aktywację eventów w przypadku drgań
|
|
if (Axle0.GetTrack()==Axle1.GetTrack()) //przed przesunięciem
|
|
{//powiązanie pojazdu z osią można zmienić tylko wtedy, gdy skrajne osie są na tym samym torze
|
|
if (MoverParameters->Vel>2) //|[km/h]| nie ma sensu zmiana osi, jesli pojazd drga na postoju
|
|
iAxleFirst=(MoverParameters->V>=0.0)?1:0; //[m/s] ?1:0 - aktywna druga oś w kierunku jazdy
|
|
//aktualnie eventy aktywuje druga oś, żeby AI nie wyłączało sobie semafora za szybko
|
|
}
|
|
if (fDistance>0.0)
|
|
{//gdy ruch w stronę sprzęgu 0, doliczyć korektę do osi 1
|
|
bEnabled&=Axle0.Move(fDistance,!iAxleFirst); //oś z przodu pojazdu
|
|
bEnabled&=Axle1.Move(fDistance/*-fAdjustment*/,iAxleFirst); //oś z tyłu pojazdu
|
|
}
|
|
else if (fDistance<0.0)
|
|
{//gdy ruch w stronę sprzęgu 1, doliczyć korektę do osi 0
|
|
bEnabled&=Axle1.Move(fDistance,iAxleFirst); //oś z tyłu pojazdu prusza się pierwsza
|
|
bEnabled&=Axle0.Move(fDistance/*-fAdjustment*/,!iAxleFirst); //oś z przodu pojazdu
|
|
}
|
|
//Axle2.Move(fDistance,false); //te nigdy pierwsze nie są
|
|
//Axle3.Move(fDistance,false);
|
|
if (fDistance!=0.0) //nie liczyć ponownie, jeśli stoi
|
|
{//liczenie pozycji pojazdu tutaj, bo jest używane w wielu miejscach
|
|
vPosition=0.5*(Axle1.pPosition+Axle0.pPosition); //środek między skrajnymi osiami
|
|
vFront=Axle0.pPosition-Axle1.pPosition; //wektor pomiędzy skrajnymi osiami
|
|
//Ra 2F1J: to nie jest stabilne (powoduje rzucanie taborem) i wymaga dopracowania
|
|
fAdjustment=vFront.Length()-fAxleDist; //na łuku będzie ujemny
|
|
//if (fabs(fAdjustment)>0.02) //jeśli jest zbyt dużo, to rozłożyć na kilka przeliczeń (wygasza drgania?)
|
|
//{//parę centymetrów trzeba by już skorygować; te błędy mogą się też generować na ostrych łukach
|
|
// fAdjustment*=0.5; //w jednym kroku korygowany jest ułamek błędu
|
|
//}
|
|
//else
|
|
// fAdjustment=0.0;
|
|
vFront=Normalize(vFront); //kierunek ustawienia pojazdu (wektor jednostkowy)
|
|
vLeft=Normalize(CrossProduct(vWorldUp,vFront)); //wektor poziomy w lewo, normalizacja potrzebna z powodu pochylenia (vFront)
|
|
vUp=CrossProduct(vFront,vLeft); //wektor w górę, będzie jednostkowy
|
|
modelRot.z=atan2(-vFront.x,vFront.z); //kąt obrotu pojazdu [rad]; z ABuBogies()
|
|
double a=((Axle1.GetRoll()+Axle0.GetRoll())); //suma przechyłek
|
|
if (a!=0.0)
|
|
{//wyznaczanie przechylenia tylko jeśli jest przechyłka
|
|
//można by pobrać wektory normalne z toru...
|
|
mMatrix.Identity(); //ta macierz jest potrzebna głównie do wyświetlania
|
|
mMatrix.Rotation(a*0.5,vFront); //obrót wzdłuż osi o przechyłkę
|
|
vUp=mMatrix*vUp; //wektor w górę pojazdu (przekręcenie na przechyłce)
|
|
//vLeft=mMatrix*DynamicObject->vLeft;
|
|
//vUp=CrossProduct(vFront,vLeft); //wektor w górę
|
|
//vLeft=Normalize(CrossProduct(vWorldUp,vFront)); //wektor w lewo
|
|
vLeft=Normalize(CrossProduct(vUp,vFront)); //wektor w lewo
|
|
//vUp=CrossProduct(vFront,vLeft); //wektor w górę
|
|
}
|
|
mMatrix.Identity(); //to też można by od razu policzyć, ale potrzebne jest do wyświetlania
|
|
mMatrix.BasisChange(vLeft,vUp,vFront); //przesuwanie jest jednak rzadziej niż renderowanie
|
|
mMatrix=Inverse(mMatrix); //wyliczenie macierzy dla pojazdu (potrzebna tylko do wyświetlania?)
|
|
//if (MoverParameters->CategoryFlag&2)
|
|
{//przesunięcia są używane po wyrzuceniu pociągu z toru
|
|
vPosition.x+=MoverParameters->OffsetTrackH*vLeft.x; //dodanie przesunięcia w bok
|
|
vPosition.z+=MoverParameters->OffsetTrackH*vLeft.z; //vLeft jest wektorem poprzecznym
|
|
//if () na przechyłce będzie dodatkowo zmiana wysokości samochodu
|
|
vPosition.y+=MoverParameters->OffsetTrackV; //te offsety są liczone przez moverparam
|
|
}
|
|
//Ra: skopiowanie pozycji do fizyki, tam potrzebna do zrywania sprzęgów
|
|
//MoverParameters->Loc.X=-vPosition.x; //robi to {Fast}ComputeMovement()
|
|
//MoverParameters->Loc.Y= vPosition.z;
|
|
//MoverParameters->Loc.Z= vPosition.y;
|
|
//obliczanie pozycji sprzęgów do liczenia zderzeń
|
|
vector3 dir=(0.5*MoverParameters->Dim.L)*vFront; //wektor sprzęgu
|
|
vCoulpler[0]=vPosition+dir; //współrzędne sprzęgu na początku
|
|
vCoulpler[1]=vPosition-dir; //współrzędne sprzęgu na końcu
|
|
MoverParameters->vCoulpler[0]=vCoulpler[0]; //tymczasowo kopiowane na inny poziom
|
|
MoverParameters->vCoulpler[1]=vCoulpler[1];
|
|
//bCameraNear=
|
|
//if (bCameraNear) //jeśli istotne są szczegóły (blisko kamery)
|
|
{//przeliczenie cienia
|
|
TTrack *t0=Axle0.GetTrack(); //już po przesunięciu
|
|
TTrack *t1=Axle1.GetTrack();
|
|
if ((t0->eEnvironment==e_flat)&&(t1->eEnvironment==e_flat)) //może być e_bridge...
|
|
fShade=0.0; //standardowe oświetlenie
|
|
else
|
|
{//jeżeli te tory mają niestandardowy stopień zacienienia (e_canyon, e_tunnel)
|
|
if (t0->eEnvironment==t1->eEnvironment)
|
|
{switch (t0->eEnvironment)
|
|
{//typ zmiany oświetlenia
|
|
case e_canyon: fShade=0.65; break; //zacienienie w kanionie
|
|
case e_tunnel: fShade=0.20; break; //zacienienie w tunelu
|
|
}
|
|
}
|
|
else //dwa różne
|
|
{//liczymy proporcję
|
|
double d=Axle0.GetTranslation(); //aktualne położenie na torze
|
|
if (Axle0.GetDirection()<0)
|
|
d=t0->fTrackLength-d; //od drugiej strony liczona długość
|
|
d/=fAxleDist; //rozsataw osi procentowe znajdowanie się na torze
|
|
switch (t0->eEnvironment)
|
|
{//typ zmiany oświetlenia - zakładam, że drugi tor ma e_flat
|
|
case e_canyon: fShade=(d*0.65)+(1.0-d); break; //zacienienie w kanionie
|
|
case e_tunnel: fShade=(d*0.20)+(1.0-d); break; //zacienienie w tunelu
|
|
}
|
|
switch (t1->eEnvironment)
|
|
{//typ zmiany oświetlenia - zakładam, że pierwszy tor ma e_flat
|
|
case e_canyon: fShade=d+(1.0-d)*0.65; break; //zacienienie w kanionie
|
|
case e_tunnel: fShade=d+(1.0-d)*0.20; break; //zacienienie w tunelu
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
void __fastcall TDynamicObject::AttachPrev(TDynamicObject *Object, int iType)
|
|
{//Ra: doczepia Object na końcu składu (nazwa funkcji może być myląca)
|
|
//Ra: używane tylko przy wczytywaniu scenerii
|
|
/*
|
|
//Ra: po wstawieniu pojazdu do scenerii nie miał on ustawionej pozycji, teraz już ma
|
|
TLocation loc;
|
|
loc.X=-vPosition.x;
|
|
loc.Y=vPosition.z;
|
|
loc.Z=vPosition.y;
|
|
MoverParameters->Loc=loc; //Ra: do obliczania sprzęgów, na starcie nie są przesunięte
|
|
loc.X=-Object->vPosition.x;
|
|
loc.Y=Object->vPosition.z;
|
|
loc.Z=Object->vPosition.y;
|
|
Object->MoverParameters->Loc=loc; //ustawienie dodawanego pojazdu
|
|
*/
|
|
MoverParameters->Attach(iDirection,Object->iDirection^1,Object->MoverParameters,iType,true);
|
|
MoverParameters->Couplers[iDirection].Render=false;
|
|
Object->MoverParameters->Attach(Object->iDirection^1,iDirection,MoverParameters,iType,true);
|
|
Object->MoverParameters->Couplers[Object->iDirection^1].Render=true; //rysowanie sprzęgu w dołączanym
|
|
if (iDirection)
|
|
{//łączenie standardowe
|
|
NextConnected=Object; //normalnie doczepiamy go sobie do sprzęgu 1
|
|
NextConnectedNo=Object->iDirection^1;
|
|
}
|
|
else
|
|
{//łączenie odwrotne
|
|
PrevConnected=Object; //doczepiamy go sobie do sprzęgu 0, gdy stoimy odwrotnie
|
|
PrevConnectedNo=Object->iDirection^1;
|
|
}
|
|
if (Object->iDirection)
|
|
{//dołączany jest normalnie ustawiany
|
|
Object->PrevConnected=this; //on ma nas z przodu
|
|
Object->PrevConnectedNo=iDirection;
|
|
}
|
|
else
|
|
{//dołączany jest odwrotnie ustawiany
|
|
Object->NextConnected=this; //on ma nas z tyłu
|
|
Object->NextConnectedNo=iDirection;
|
|
}
|
|
if (MoverParameters->TrainType&dt_EZT) //w przypadku łączenia członów, światła w rozrządczym zależą od stanu w silnikowym
|
|
if (MoverParameters->Couplers[iDirection].AllowedFlag&ctrain_depot) //gdy sprzęgi łączone warsztatowo (powiedzmy)
|
|
if ((MoverParameters->Power<1.0)&&(Object->MoverParameters->Power>1.0)) //my nie mamy mocy, ale ten drugi ma
|
|
iLights=Object->MoverParameters->iLights; //to w tym z mocą będą światła załączane, a w tym bez tylko widoczne
|
|
else if ((MoverParameters->Power>1.0)&&(Object->MoverParameters->Power<1.0)) //my mamy moc, ale ten drugi nie ma
|
|
Object->iLights=MoverParameters->iLights; //to w tym z mocą będą światła załączane, a w tym bez tylko widoczne
|
|
return;
|
|
//SetPneumatic(1,1); //Ra: to i tak się nie wykonywało po return
|
|
//SetPneumatic(1,0);
|
|
//SetPneumatic(0,1);
|
|
//SetPneumatic(0,0);
|
|
}
|
|
|
|
bool __fastcall TDynamicObject::UpdateForce(double dt, double dt1, bool FullVer)
|
|
{
|
|
if (!bEnabled)
|
|
return false;
|
|
if (dt>0)
|
|
MoverParameters->ComputeTotalForce(dt,dt1,FullVer); //wywalenie WS zależy od ustawienia kierunku
|
|
return true;
|
|
}
|
|
|
|
void __fastcall TDynamicObject::LoadUpdate()
|
|
{//przeładowanie modelu ładunku
|
|
// Ra: nie próbujemy wczytywać modeli miliony razy podczas renderowania!!!
|
|
if ((mdLoad==NULL)&&(MoverParameters->Load>0))
|
|
{
|
|
AnsiString asLoadName=asBaseDir+MoverParameters->LoadType+".t3d"; //zapamiętany katalog pojazdu
|
|
//asLoadName=MoverParameters->LoadType;
|
|
//if (MoverParameters->LoadType!=AnsiString("passengers"))
|
|
Global::asCurrentTexturePath=asBaseDir; //bieżąca ścieżka do tekstur to dynamic/...
|
|
mdLoad=TModelsManager::GetModel(asLoadName.c_str()); //nowy ładunek
|
|
Global::asCurrentTexturePath=AnsiString(szTexturePath); //z powrotem defaultowa sciezka do tekstur
|
|
//Ra: w MMD można by zapisać położenie modelu ładunku (np. węgiel) w zależności od załadowania
|
|
}
|
|
else if (MoverParameters->Load==0)
|
|
mdLoad=NULL; //nie ma ładunku
|
|
//if ((mdLoad==NULL)&&(MoverParameters->Load>0))
|
|
// {
|
|
// mdLoad=NULL; //Ra: to jest tu bez sensu - co autor miał na myśli?
|
|
// }
|
|
MoverParameters->LoadStatus&=3; //po zakończeniu będzie równe zero
|
|
};
|
|
|
|
/*
|
|
double __fastcall ComputeRadius(double p1x, double p1z, double p2x, double p2z,
|
|
double p3x, double p3z, double p4x, double p4z)
|
|
{
|
|
|
|
double v1z= p1x-p2x;
|
|
double v1x= p1z-p2z;
|
|
double v4z= p3x-p4x;
|
|
double v4x= p3z-p4z;
|
|
double A1= p2z-p1z;
|
|
double B1= p1x-p2x;
|
|
double C1= -p1z*B1-p1x*A1;
|
|
double A2= p4z-p3z;
|
|
double B2= p3x-p4x;
|
|
double C2= -p3z*B1-p3x*A1;
|
|
double y= (A1*C2/A2-C1)/(B1-A1*B2/A2);
|
|
double x= (-B2*y-C2)/A2;
|
|
}
|
|
*/
|
|
double __fastcall TDynamicObject::ComputeRadius(vector3 p1, vector3 p2, vector3 p3, vector3 p4)
|
|
{
|
|
// vector3 v1
|
|
|
|
// TLine l1= TLine(p1,p1-p2);
|
|
// TLine l4= TLine(p4,p4-p3);
|
|
// TPlane p1= l1.GetPlane();
|
|
// vector3 pt;
|
|
// CrossPoint(pt,l4,p1);
|
|
double R= 0.0;
|
|
vector3 p12= p1-p2;
|
|
vector3 p34= p3-p4;
|
|
p12= CrossProduct(p12,vector3(0.0,0.1,0.0));
|
|
p12=Normalize(p12);
|
|
p34= CrossProduct(p34,vector3(0.0,0.1,0.0));
|
|
p34=Normalize(p34);
|
|
if (fabs(p1.x-p2.x)>0.01)
|
|
{
|
|
if (fabs(p12.x-p34.x)>0.001)
|
|
R=(p1.x-p4.x)/(p34.x-p12.x);
|
|
}
|
|
else
|
|
{
|
|
if (fabs(p12.z-p34.z)>0.001)
|
|
R=(p1.z-p4.z)/(p34.z-p12.z);
|
|
}
|
|
return(R);
|
|
}
|
|
|
|
/*
|
|
double __fastcall TDynamicObject::ComputeRadius()
|
|
{
|
|
double L=0;
|
|
double d=0;
|
|
d=sqrt(SquareMagnitude(Axle0.pPosition-Axle1.pPosition));
|
|
L=Axle1.GetLength(Axle1.pPosition,Axle1.pPosition-Axle2.pPosition,Axle0.pPosition-Axle3.pPosition,Axle0.pPosition);
|
|
|
|
double eps=0.01;
|
|
double R= 0;
|
|
double L_d;
|
|
if ((L>0) || (d>0))
|
|
{
|
|
L_d= L-d;
|
|
if (L_d>eps)
|
|
{
|
|
R=L*sqrt(L/(24*(L_d)));
|
|
}
|
|
}
|
|
return R;
|
|
}
|
|
*/
|
|
|
|
/* Ra: na razie nie potrzebne
|
|
void __fastcall TDynamicObject::UpdatePos()
|
|
{
|
|
MoverParameters->Loc.X= -vPosition.x;
|
|
MoverParameters->Loc.Y= vPosition.z;
|
|
MoverParameters->Loc.Z= vPosition.y;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
Ra:
|
|
Powinny być dwie funkcje wykonujące aktualizację fizyki. Jedna wykonująca
|
|
krok obliczeń, powtarzana odpowiednią liczbę razy, a druga wykonująca zbiorczą
|
|
aktualzację mniej istotnych elementów.
|
|
Ponadto należało by ustalić odległość składów od kamery i jeśli przekracza
|
|
ona np. 10km, to traktować składy jako uproszczone, np. bez wnikania w siły
|
|
na sprzęgach, opóźnienie działania hamulca itp. Oczywiście musi mieć to pewną
|
|
histerezę czasową, aby te tryby pracy nie przełączały się zbyt szybko.
|
|
*/
|
|
|
|
|
|
bool __fastcall TDynamicObject::Update(double dt, double dt1)
|
|
{
|
|
if (dt==0) return true; //Ra: pauza
|
|
if (!MoverParameters->PhysicActivation&&!MechInside) //to drugie, bo będąc w maszynowym blokuje się fizyka
|
|
return true; //McZapkie: wylaczanie fizyki gdy nie potrzeba
|
|
if (!MyTrack)
|
|
return false; //pojazdy postawione na torach portalowych mają MyTrack==NULL
|
|
if (!bEnabled)
|
|
return false; //a normalnie powinny mieć bEnabled==false
|
|
|
|
//Ra: przeniosłem - no już lepiej tu, niż w wyświetlaniu!
|
|
//if ((MoverParameters->ConverterFlag==false) && (MoverParameters->TrainType!=dt_ET22))
|
|
//Ra: to nie może tu być, bo wyłącza sprężarkę w rozrządczym EZT!
|
|
//if ((MoverParameters->ConverterFlag==false)&&(MoverParameters->CompressorPower!=0))
|
|
// MoverParameters->CompressorFlag=false;
|
|
//if (MoverParameters->CompressorPower==2)
|
|
// MoverParameters->CompressorAllow=MoverParameters->ConverterFlag;
|
|
|
|
//McZapkie-260202
|
|
if ((MoverParameters->EnginePowerSource.SourceType==CurrentCollector)&&(MoverParameters->Power>1.0)) //aby rozrządczy nie opuszczał silnikowemu
|
|
if ((MechInside)||(MoverParameters->TrainType==dt_EZT))
|
|
{
|
|
//if ((!MoverParameters->PantCompFlag)&&(MoverParameters->CompressedVolume>=2.8))
|
|
// MoverParameters->PantVolume=MoverParameters->CompressedVolume;
|
|
if (MoverParameters->PantPress<(MoverParameters->TrainType==dt_EZT?2.4:3.5))
|
|
{// 3.5 wg http://www.transportszynowy.pl/eu06-07pneumat.php
|
|
//"Wyłączniki ciśnieniowe odbieraków prądu wyłączają sterowanie wyłącznika szybkiego oraz uniemożliwiają podniesienie odbieraków prądu, gdy w instalacji rozrządu ciśnienie spadnie poniżej wartości 3,5 bara."
|
|
//Ra 2013-12: Niebugocław mówi, że w EZT podnoszą się przy 2.5
|
|
//if (!MoverParameters->PantCompFlag)
|
|
// MoverParameters->PantVolume=MoverParameters->CompressedVolume;
|
|
MoverParameters->PantFront(false); //opuszczenie pantografów przy niskim ciśnieniu
|
|
MoverParameters->PantRear(false); //to idzie w ukrotnieniu, a nie powinno...
|
|
}
|
|
//Winger - automatyczne wylaczanie malej sprezarki
|
|
else if (MoverParameters->PantPress>=4.8)
|
|
MoverParameters->PantCompFlag=false;
|
|
} //Ra: do Mover to trzeba przenieść, żeby AI też mogło sobie podpompować
|
|
|
|
double dDOMoveLen;
|
|
|
|
TLocation l;
|
|
l.X=-vPosition.x; //przekazanie pozycji do fizyki
|
|
l.Y=vPosition.z;
|
|
l.Z=vPosition.y;
|
|
TRotation r;
|
|
r.Rx=r.Ry=r.Rz=0;
|
|
//McZapkie: parametry powinny byc pobierane z toru
|
|
|
|
//TTrackShape ts;
|
|
//ts.R=MyTrack->fRadius;
|
|
//if (ABuGetDirection()<0) ts.R=-ts.R;
|
|
// ts.R=MyTrack->fRadius; //ujemne promienie są już zamienione przy wczytywaniu
|
|
if (Axle0.vAngles.z!=Axle1.vAngles.z)
|
|
{//wyliczenie promienia z obrotów osi - modyfikację zgłosił youBy
|
|
ts.R=Axle0.vAngles.z-Axle1.vAngles.z; //różnica może dawać stałą ±M_2PI
|
|
if (ts.R>M_PI) ts.R-=M_2PI else if (ts.R<-M_PI) ts.R+=M_2PI; //normalizacja
|
|
// ts.R=fabs(0.5*MoverParameters->BDist/sin(ts.R*0.5));
|
|
ts.R=-0.5*MoverParameters->BDist/sin(ts.R*0.5);
|
|
if ((ts.R>15000.0)||(ts.R<-15000.0)) ts.R=0.0; //szkoda czasu na zbyt duże promienie, 4km to promień nie wymagający przechyłki
|
|
}
|
|
else ts.R=0.0;
|
|
//ts.R=ComputeRadius(Axle1.pPosition,Axle2.pPosition,Axle3.pPosition,Axle0.pPosition);
|
|
//Ra: składową pochylenia wzdłużnego mamy policzoną w jednostkowym wektorze vFront
|
|
ts.Len=1.0; //Max0R(MoverParameters->BDist,MoverParameters->ADist);
|
|
ts.dHtrack=-vFront.y; //Axle1.pPosition.y-Axle0.pPosition.y; //wektor między skrajnymi osiami (!!!odwrotny)
|
|
ts.dHrail=(Axle1.GetRoll()+Axle0.GetRoll())*0.5; //średnia przechyłka pudła
|
|
//TTrackParam tp;
|
|
tp.Width=MyTrack->fTrackWidth;
|
|
//McZapkie-250202
|
|
tp.friction=MyTrack->fFriction*Global::fFriction;
|
|
tp.CategoryFlag=MyTrack->iCategoryFlag&15;
|
|
tp.DamageFlag=MyTrack->iDamageFlag;
|
|
tp.QualityFlag=MyTrack->iQualityFlag;
|
|
if ((MoverParameters->Couplers[0].CouplingFlag>0)
|
|
&&(MoverParameters->Couplers[1].CouplingFlag>0))
|
|
{
|
|
MoverParameters->InsideConsist=true;
|
|
}
|
|
else
|
|
{
|
|
MoverParameters->InsideConsist=false;
|
|
}
|
|
//napiecie sieci trakcyjnej
|
|
//Ra 15-01: przeliczenie poboru prądu powinno być robione wcześniej, żeby na tym etapie były znane napięcia
|
|
//TTractionParam tmpTraction;
|
|
//tmpTraction.TractionVoltage=0;
|
|
if (MoverParameters->EnginePowerSource.SourceType==CurrentCollector)
|
|
{//dla EZT tylko silnikowy
|
|
//if (Global::bLiveTraction)
|
|
{//Ra 2013-12: to niżej jest chyba trochę bez sensu
|
|
double v=MoverParameters->PantRearVolt;
|
|
if (v==0.0)
|
|
{v=MoverParameters->PantFrontVolt;
|
|
if (v==0.0)
|
|
if (MoverParameters->TrainType&(dt_EZT|dt_ET40|dt_ET41|dt_ET42)) //dwuczłony mogą mieć sprzęg WN
|
|
v=MoverParameters->GetTrainsetVoltage(); //ostatnia szansa
|
|
}
|
|
if (v!=0.0)
|
|
{//jeśli jest zasilanie
|
|
NoVoltTime=0;
|
|
tmpTraction.TractionVoltage=v;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
if (MoverParameters->Vel>0.1f) //jeśli jedzie
|
|
if (NoVoltTime==0.0) //tylko przy pierwszym zaniku napięcia
|
|
if (MoverParameters->PantFrontUp||MoverParameters->PantRearUp)
|
|
//if ((pants[0].fParamPants->PantTraction>1.0)||(pants[1].fParamPants->PantTraction>1.0))
|
|
{//wspomagacz usuwania problemów z siecią
|
|
if (!Global::iPause)
|
|
{//Ra: tymczasowa teleportacja do miejsca, gdzie brakuje prądu
|
|
Global::SetCameraPosition(vPosition+vector3(0,0,5)); //nowa pozycja dla generowania obiektów
|
|
Global::pCamera->Init(vPosition+vector3(0,0,5),Global::pFreeCameraInitAngle[0]); //przestawienie
|
|
}
|
|
Global:l::pGround->Silence(Global::pCamera->Pos); //wyciszenie wszystkiego z poprzedniej pozycji
|
|
Globa:iPause|=1; //tymczasowe zapauzowanie, gdy problem z siecią
|
|
}
|
|
*/
|
|
NoVoltTime=NoVoltTime+dt;
|
|
if (NoVoltTime>0.2) //jeśli brak zasilania dłużej niż 0.2 sekundy (25km/h pod izolatorem daje 0.15s)
|
|
{//Ra 2F1H: prowizorka, trzeba przechować napięcie, żeby nie wywalało WS pod izolatorem
|
|
if (MoverParameters->Vel>0.5) //jeśli jedzie
|
|
if (MoverParameters->PantFrontUp||MoverParameters->PantRearUp) //Ra 2014-07: doraźna blokada logowania zimnych lokomotyw - zrobić to trzeba inaczej
|
|
//if (NoVoltTime>0.02) //tu można ograniczyć czas rozłączenia
|
|
//if (DebugModeFlag) //logowanie nie zawsze
|
|
if (MoverParameters->Mains)
|
|
{//Ra 15-01: logować tylko, jeśli WS załączony
|
|
//if (MoverParameters->PantFrontUp&&pants)
|
|
//Ra 15-01: bezwzględne współrzędne pantografu nie są dostępne, więc lepiej się tego nie zaloguje
|
|
ErrorLog("Voltage loss: by "+MoverParameters->Name+" at "+FloatToStrF(vPosition.x,ffFixed,7,2)+" "+FloatToStrF(vPosition.y,ffFixed,7,2)+" "+FloatToStrF(vPosition.z,ffFixed,7,2)+", time "+FloatToStrF(NoVoltTime,ffFixed,7,2));
|
|
//if (MoverParameters->PantRearUp)
|
|
// if (iAnimType[ANIM_PANTS]>1)
|
|
// if (pants[1])
|
|
// ErrorLog("Voltage loss: by "+MoverParameters->Name+" at "+FloatToStrF(vPosition.x,ffFixed,7,2)+" "+FloatToStrF(vPosition.y,ffFixed,7,2)+" "+FloatToStrF(vPosition.z,ffFixed,7,2)+", time "+FloatToStrF(NoVoltTime,ffFixed,7,2));
|
|
}
|
|
//Ra 2F1H: nie było sensu wpisywać tu zera po upływie czasu, bo zmienna była tymczasowa, a napięcie zerowane od razu
|
|
tmpTraction.TractionVoltage=0; //Ra 2013-12: po co tak?
|
|
//pControlled->MainSwitch(false); //może tak?
|
|
}
|
|
}
|
|
}
|
|
//else //Ra: nie no, trzeba podnieść pantografy, jak nie będzie drutu, to będą miały prąd po osiągnięciu 1.4m
|
|
// tmpTraction.TractionVoltage=0.95*MoverParameters->EnginePowerSource.MaxVoltage;
|
|
}
|
|
else
|
|
tmpTraction.TractionVoltage=0.95*MoverParameters->EnginePowerSource.MaxVoltage;
|
|
tmpTraction.TractionFreq=0;
|
|
tmpTraction.TractionMaxCurrent=7500; //Ra: chyba za dużo? powinno wywalać przy 1500
|
|
tmpTraction.TractionResistivity=0.3;
|
|
|
|
//McZapkie: predkosc w torze przekazac do TrackParam
|
|
//McZapkie: Vel ma wymiar [km/h] (absolutny), V ma wymiar [m/s], taka przyjalem notacje
|
|
tp.Velmax=MyTrack->VelocityGet();
|
|
|
|
if (Mechanik)
|
|
{//Ra 2F3F: do Driver.cpp to przenieść?
|
|
MoverParameters->EqvtPipePress=GetEPP(); //srednie cisnienie w PG
|
|
if ((Mechanik->Primary())&&(MoverParameters->EngineType==ElectricInductionMotor)) //jesli glowny i z asynchronami, to niech steruje
|
|
{ //hamulcem lacznie dla calego pociagu/ezt
|
|
//1. ustal wymagana sile hamowania calego pociagu
|
|
// - opoznienie moze byc ustalane na podstawie charakterystyki
|
|
// - opoznienie moze byc ustalane na podstawie mas i cisnien granicznych
|
|
//
|
|
|
|
//2. ustal mozliwa do realizacji sile hamowania ED
|
|
// - w szczegolnosci powinien brac pod uwage rozne sily hamowania
|
|
float FED=0;
|
|
// for(TDynamicObject *p=GetFirstDynamic(4);p;p->NextC(4))
|
|
// FED+=p->MoverParameters->eimv[eimv_Fmax];
|
|
//3. ustaw pojazdom sile hamowania ED
|
|
// - proporcjonalnie do mozliwosci
|
|
|
|
//4. ustal potrzebne dohamowanie pneumatyczne
|
|
// - od sily zadanej trzeba odjac realizowana przez ED
|
|
//5. w razie potrzeby wlacz hamulec utrzymujacy
|
|
// - gdy zahamowany ma ponizej 2 km/h
|
|
//6. ustaw pojazdom sile hamowania ep
|
|
// - proporcjonalnie do masy, do liczby osi, rowne cisnienia - jak bedzie, tak bedzie dobrze
|
|
}
|
|
|
|
//yB: cos (AI) tu jest nie kompatybilne z czyms (hamulce)
|
|
// if (Controller!=Humandriver)
|
|
// if (Mechanik->LastReactionTime>0.5)
|
|
// {
|
|
// MoverParameters->BrakeCtrlPos=0;
|
|
// Mechanik->LastReactionTime=0;
|
|
// }
|
|
|
|
Mechanik->UpdateSituation(dt1); //przebłyski świadomości AI
|
|
}
|
|
|
|
//fragment "z EXE Kursa"
|
|
if (MoverParameters->Mains) //nie wchodzić w funkcję bez potrzeby
|
|
if ((!MoverParameters->Battery)&&(Controller==Humandriver)&&(MoverParameters->EngineType!=DieselEngine)&&(MoverParameters->EngineType!=WheelsDriven))
|
|
{//jeśli bateria wyłączona, a nie diesel ani drezyna reczna
|
|
if (MoverParameters->MainSwitch(false)) //wyłączyć zasilanie
|
|
MoverParameters->EventFlag=true;
|
|
}
|
|
if (MoverParameters->TrainType==dt_ET42)
|
|
{//powinny być wszystkie dwuczłony oraz EZT
|
|
/*
|
|
//Ra: to jest bez sensu, bo wyłącza WS przy przechodzeniu przez "wewnętrzne" kabiny (z powodu ActiveCab)
|
|
//trzeba to zrobić inaczej, np. dla członu A sprawdzać, czy jest B
|
|
//albo sprawdzać w momencie załączania WS i zmiany w sprzęgach
|
|
if (((TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_controll))&&(MoverParameters->ActiveCab>0)&&(NextConnected->MoverParameters->TrainType!=dt_ET42))||((TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_controll))&&(MoverParameters->ActiveCab<0)&&(PrevConnected->MoverParameters->TrainType!=dt_ET42)))
|
|
{//sprawdzenie, czy z tyłu kabiny mamy drugi człon
|
|
if (MoverParameters->MainSwitch(false))
|
|
MoverParameters->EventFlag=true;
|
|
}
|
|
if ((!(TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_controll))&&(MoverParameters->ActiveCab>0))||(!(TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_controll))&&(MoverParameters->ActiveCab<0)))
|
|
{
|
|
if (MoverParameters->MainSwitch(false))
|
|
MoverParameters->EventFlag=true;
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
//McZapkie-260202 - dMoveLen przyda sie przy stukocie kol
|
|
dDOMoveLen=GetdMoveLen()+MoverParameters->ComputeMovement(dt,dt1,ts,tp,tmpTraction,l,r);
|
|
//yB: zeby zawsze wrzucalo w jedna strone zakretu
|
|
MoverParameters->AccN*=-ABuGetDirection();
|
|
//if (dDOMoveLen!=0.0) //Ra: nie może być, bo blokuje Event0
|
|
Move(dDOMoveLen);
|
|
if (!bEnabled) //usuwane pojazdy nie mają toru
|
|
{//pojazd do usunięcia
|
|
Global::pGround->bDynamicRemove=true; //sprawdzić
|
|
return false;
|
|
}
|
|
Global::ABuDebug=dDOMoveLen/dt1;
|
|
ResetdMoveLen();
|
|
//McZapkie-260202
|
|
//tupot mew, tfu, stukot kol:
|
|
DWORD stat;
|
|
//taka prowizorka zeby sciszyc stukot dalekiej lokomotywy
|
|
double ObjectDist;
|
|
double vol=0;
|
|
//double freq; //Ra: nie używane
|
|
ObjectDist=SquareMagnitude(Global::pCameraPosition-vPosition);
|
|
//McZapkie-270202
|
|
if (MyTrack->fSoundDistance!=-1)
|
|
{
|
|
if (ObjectDist<rsStukot[0].dSoundAtt*rsStukot[0].dSoundAtt*15.0)
|
|
{
|
|
vol= (20.0+MyTrack->iDamageFlag)/21;
|
|
if (MyTrack->eEnvironment==e_tunnel)
|
|
{
|
|
vol*=1.1;
|
|
//freq=1.02;
|
|
}
|
|
else
|
|
if (MyTrack->eEnvironment==e_bridge)
|
|
{
|
|
vol*=1.2;
|
|
//freq=0.99; //MC: stukot w zaleznosci od tego gdzie jest tor
|
|
}
|
|
if (MyTrack->fSoundDistance!=dRailLength)
|
|
{
|
|
dRailLength=MyTrack->fSoundDistance;
|
|
for (int i=0; i<iAxles; i++)
|
|
{
|
|
dRailPosition[i]=dWheelsPosition[i]+MoverParameters->Dim.L;
|
|
}
|
|
}
|
|
if (dRailLength!=-1)
|
|
{
|
|
if (abs(MoverParameters->V)>0)
|
|
{
|
|
for (int i=0; i<iAxles; i++)
|
|
{
|
|
dRailPosition[i]-=dDOMoveLen*Sign(dDOMoveLen);
|
|
if (dRailPosition[i]<0)
|
|
{
|
|
//McZapkie-040302
|
|
if (i==iAxles-1)
|
|
{
|
|
rsStukot[0].Stop();
|
|
MoverParameters->AccV+= 0.5*GetVelocity()/(1+MoverParameters->Vmax);
|
|
}
|
|
else
|
|
{rsStukot[i+1].Stop();}
|
|
rsStukot[i].Play(vol,0,MechInside,vPosition); //poprawic pozycje o uklad osi
|
|
if (i==1)
|
|
MoverParameters->AccV-= 0.5*GetVelocity()/(1+MoverParameters->Vmax);
|
|
dRailPosition[i]+=dRailLength;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//McZapkie-260202 end
|
|
|
|
//yB: przyspieszacz (moze zadziala, ale dzwiek juz jest)
|
|
int flag=MoverParameters->Hamulec->GetSoundFlag();
|
|
if ((bBrakeAcc)&&(TestFlag(flag,sf_Acc))&&(ObjectDist<2500))
|
|
{
|
|
sBrakeAcc->SetVolume(-ObjectDist*3-(FreeFlyModeFlag?0:2000));
|
|
sBrakeAcc->Play(0,0,0);
|
|
sBrakeAcc->SetPan(10000*sin(ModCamRot));
|
|
}
|
|
if ((rsUnbrake.AM!=0)&&(ObjectDist<5000))
|
|
{
|
|
if ((TestFlag(flag,sf_CylU)) && ((MoverParameters->BrakePress*MoverParameters->MaxBrakePress[3])>0.05))
|
|
{
|
|
vol=Min0R(0.2+1.6*sqrt((MoverParameters->BrakePress>0?MoverParameters->BrakePress:0)/MoverParameters->MaxBrakePress[3]),1);
|
|
vol=vol+(FreeFlyModeFlag?0:-0.5)-ObjectDist/5000;
|
|
rsUnbrake.SetPan(10000*sin(ModCamRot));
|
|
rsUnbrake.Play(vol,DSBPLAY_LOOPING,MechInside,GetPosition());
|
|
}
|
|
else
|
|
rsUnbrake.Stop();
|
|
}
|
|
|
|
|
|
//fragment z EXE Kursa
|
|
/* if (MoverParameters->TrainType==dt_ET42)
|
|
{
|
|
if ((MoverParameters->DynamicBrakeType=dbrake_switch) && ((MoverParameters->BrakePress > 0.2) || ( MoverParameters->PipePress < 0.36 )))
|
|
{
|
|
MoverParameters->StLinFlag=true;
|
|
}
|
|
else
|
|
if ((MoverParameters->DynamicBrakeType=dbrake_switch) && (MoverParameters->BrakePress < 0.1))
|
|
{
|
|
MoverParameters->StLinFlag=false;
|
|
|
|
}
|
|
} */
|
|
if ((MoverParameters->TrainType==dt_ET40) || (MoverParameters->TrainType==dt_EP05))
|
|
{//dla ET40 i EU05 automatyczne cofanie nastawnika - i tak nie będzie to działać dobrze...
|
|
/* if ((MoverParameters->MainCtrlPos>MoverParameters->MainCtrlActualPos)&&(abs(MoverParameters->Im)>MoverParameters->IminHi))
|
|
{
|
|
MoverParameters->DecMainCtrl(1);
|
|
} */
|
|
if (( !Console::Pressed(Global::Keys[k_IncMainCtrl]))&&(MoverParameters->MainCtrlPos>MoverParameters->MainCtrlActualPos))
|
|
{
|
|
MoverParameters->DecMainCtrl(1);
|
|
}
|
|
if (( !Console::Pressed(Global::Keys[k_DecMainCtrl]))&&(MoverParameters->MainCtrlPos<MoverParameters->MainCtrlActualPos))
|
|
{
|
|
MoverParameters->IncMainCtrl(1); //Ra 15-01: a to nie miało być tylko cofanie?
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (MoverParameters->Vel!=0)
|
|
{//McZapkie-050402: krecenie kolami:
|
|
dWheelAngle[0]+=114.59155902616464175359630962821*MoverParameters->V*dt1/MoverParameters->WheelDiameterL; //przednie toczne
|
|
dWheelAngle[1]+=MoverParameters->nrot*dt1*360.0; //napędne
|
|
dWheelAngle[2]+=114.59155902616464175359630962821*MoverParameters->V*dt1/MoverParameters->WheelDiameterT; //tylne toczne
|
|
if (dWheelAngle[0]>360.0) dWheelAngle[0]-=360.0; //a w drugą stronę jak się kręcą?
|
|
if (dWheelAngle[1]>360.0) dWheelAngle[1]-=360.0;
|
|
if (dWheelAngle[2]>360.0) dWheelAngle[2]-=360.0;
|
|
}
|
|
if (pants) //pantograf może być w wagonie kuchennym albo pojeździe rewizyjnym (np. SR61)
|
|
{//przeliczanie kątów dla pantografów
|
|
double k; //tymczasowy kąt
|
|
double PantDiff;
|
|
TAnimPant *p; //wskaźnik do obiektu danych pantografu
|
|
double fCurrent=(MoverParameters->DynamicBrakeFlag&&MoverParameters->ResistorsFlag?0:fabs(MoverParameters->Itot))+MoverParameters->TotalCurrent; //prąd pobierany przez pojazd - bez sensu z tym (TotalCurrent)
|
|
//fCurrent+=fabs(MoverParameters->Voltage)*1e-6; //prąd płynący przez woltomierz, rozładowuje kondensator orgromowy 4µF
|
|
double fPantCurrent=fCurrent; //normalnie cały prąd przez jeden pantograf
|
|
if (pants)
|
|
if (iAnimType[ANIM_PANTS]>1) //a jeśli są dwa pantografy //Ra 1014-11: proteza, trzeba zrobić sensowniej
|
|
if (pants[0].fParamPants->hvPowerWire&&pants[1].fParamPants->hvPowerWire) //i oba podłączone do drutów
|
|
fPantCurrent=fCurrent*0.5; //to dzielimy prąd równo na oba (trochę bez sensu, ale lepiej tak niż podwoić prąd)
|
|
for (int i=0;i<iAnimType[ANIM_PANTS];++i)
|
|
{//pętla po wszystkich pantografach
|
|
p=pants[i].fParamPants;
|
|
if (p->PantWys<0)
|
|
{//patograf został połamany, liczony nie będzie
|
|
if (p->fAngleL>p->fAngleL0)
|
|
p->fAngleL-=0.2*dt1; //nieco szybciej niż jak dla opuszczania
|
|
if (p->fAngleL<p->fAngleL0)
|
|
p->fAngleL=p->fAngleL0; //kąt graniczny
|
|
if (p->fAngleU<M_PI)
|
|
p->fAngleU+=0.5*dt1; //górne się musi ruszać szybciej.
|
|
if (p->fAngleU>M_PI)
|
|
p->fAngleU=M_PI;
|
|
if (i&1) //zgłoszono, że po połamaniu potrafi zostać zasilanie
|
|
MoverParameters->PantRearVolt=0.0;
|
|
else
|
|
MoverParameters->PantFrontVolt=0.0;
|
|
continue; //reszta wtedy nie jest wykonywana
|
|
}
|
|
PantDiff=p->PantTraction-p->PantWys; //docelowy-aktualny
|
|
switch (i) //numer pantografu
|
|
{//trzeba usunąć to rozróżnienie
|
|
case 0:
|
|
if (Global::bLiveTraction?false:!p->hvPowerWire) //jeśli nie ma drutu, może pooszukiwać
|
|
MoverParameters->PantFrontVolt=(p->PantWys>=1.2)?0.95*MoverParameters->EnginePowerSource.MaxVoltage:0.0;
|
|
else
|
|
if (MoverParameters->PantFrontUp?(PantDiff<0.01):false) //tolerancja niedolegania
|
|
{
|
|
if ((MoverParameters->PantFrontVolt==0.0)&&(MoverParameters->PantRearVolt==0.0))
|
|
sPantUp.Play(vol,0,MechInside,vPosition);
|
|
if (p->hvPowerWire) //TODO: wyliczyć trzeba prąd przypadający na pantograf i wstawić do GetVoltage()
|
|
{MoverParameters->PantFrontVolt=p->hvPowerWire->VoltageGet(MoverParameters->Voltage,fPantCurrent);
|
|
fCurrent-=fPantCurrent; //taki prąd płynie przez powyższy pantograf
|
|
}
|
|
else
|
|
MoverParameters->PantFrontVolt=0.0;
|
|
}
|
|
else
|
|
MoverParameters->PantFrontVolt=0.0;
|
|
break;
|
|
case 1:
|
|
if (Global::bLiveTraction?false:!p->hvPowerWire) //jeśli nie ma drutu, może pooszukiwać
|
|
MoverParameters->PantRearVolt=(p->PantWys>=1.2)?0.95*MoverParameters->EnginePowerSource.MaxVoltage:0.0;
|
|
else
|
|
if (MoverParameters->PantRearUp?(PantDiff<0.01):false)
|
|
{
|
|
if ((MoverParameters->PantRearVolt==0.0)&&(MoverParameters->PantFrontVolt==0.0))
|
|
sPantUp.Play(vol,0,MechInside,vPosition);
|
|
if (p->hvPowerWire) //TODO: wyliczyć trzeba prąd przypadający na pantograf i wstawić do GetVoltage()
|
|
{MoverParameters->PantRearVolt=p->hvPowerWire->VoltageGet(MoverParameters->Voltage,fPantCurrent);
|
|
fCurrent-=fPantCurrent; //taki prąd płynie przez powyższy pantograf
|
|
}
|
|
else
|
|
MoverParameters->PantRearVolt=0.0;
|
|
}
|
|
else
|
|
MoverParameters->PantRearVolt=0.0;
|
|
break;
|
|
} //pozostałe na razie nie obsługiwane
|
|
if (MoverParameters->PantPress>(MoverParameters->TrainType==dt_EZT?2.5:3.3)) //Ra 2013-12: Niebugocław mówi, że w EZT podnoszą się przy 2.5
|
|
pantspeedfactor=0.015*(MoverParameters->PantPress)*dt1; //z EXE Kursa //Ra: wysokość zależy od ciśnienia !!!
|
|
else
|
|
pantspeedfactor=0.0;
|
|
if (pantspeedfactor<0) pantspeedfactor=0;
|
|
k=p->fAngleL;
|
|
if (i?MoverParameters->PantRearUp:MoverParameters->PantFrontUp) //jeśli ma być podniesiony
|
|
{if (PantDiff>0.001) //jeśli nie dolega do drutu
|
|
{//jeśli poprzednia wysokość jest mniejsza niż pożądana, zwiększyć kąt dolnego ramienia zgodnie z ciśnieniem
|
|
if (pantspeedfactor>0.55*PantDiff) //0.55 to około pochodna kąta po wysokości
|
|
k+=0.55*PantDiff; //ograniczenie "skoku" w danej klatce
|
|
else
|
|
k+=pantspeedfactor; //dolne ramię
|
|
//jeśli przekroczono kąt graniczny, zablokować pantograf (wymaga interwencji pociągu sieciowego)
|
|
}
|
|
else if (PantDiff<-0.001)
|
|
{//drut się obniżył albo pantograf podniesiony za wysoko
|
|
//jeśli wysokość jest zbyt duża, wyznaczyć zmniejszenie kąta
|
|
//jeśli zmniejszenie kąta jest zbyt duże, przejść do trybu łamania pantografu
|
|
//if (PantFrontDiff<-0.05) //skok w dół o 5cm daje złąmanie pantografu
|
|
k+=0.4*PantDiff; //mniej niż pochodna kąta po wysokości
|
|
} //jeśli wysokość jest dobra, nic więcej nie liczyć
|
|
}
|
|
else
|
|
{//jeśli ma być na dole
|
|
if (k>p->fAngleL0) //jeśli wyżej niż położenie wyjściowe
|
|
k-=0.15*dt1; //ruch w dół
|
|
if (k<p->fAngleL0)
|
|
k=p->fAngleL0; //położenie minimalne
|
|
}
|
|
if (k!=p->fAngleL)
|
|
{//żeby nie liczyć w kilku miejscach ani gdy nie potrzeba
|
|
if (k+p->fAngleU<M_PI)
|
|
{//o ile nie został osiągnięty kąt maksymalny
|
|
p->fAngleL=k; //zmieniony kąt
|
|
//wyliczyć kąt górnego ramienia z wzoru (a)cosinusowego
|
|
//=acos((b*cos()+c)/a)
|
|
//p->dPantAngleT=acos((1.22*cos(k)+0.535)/1.755); //górne ramię
|
|
p->fAngleU=acos((p->fLenL1*cos(k)+p->fHoriz)/p->fLenU1); //górne ramię
|
|
//wyliczyć aktualną wysokość z wzoru sinusowego
|
|
//h=a*sin()+b*sin()
|
|
p->PantWys=p->fLenL1*sin(k)+p->fLenU1*sin(p->fAngleU)+p->fHeight; //wysokość całości
|
|
}
|
|
}
|
|
} //koniec pętli po pantografach
|
|
if ((MoverParameters->PantFrontSP==false)&&(MoverParameters->PantFrontUp==false))
|
|
{
|
|
sPantDown.Play(vol,0,MechInside,vPosition);
|
|
MoverParameters->PantFrontSP=true;
|
|
}
|
|
if ((MoverParameters->PantRearSP==false)&&(MoverParameters->PantRearUp==false))
|
|
{
|
|
sPantDown.Play(vol,0,MechInside,vPosition);
|
|
MoverParameters->PantRearSP=true;
|
|
}
|
|
if (MoverParameters->EnginePowerSource.SourceType==CurrentCollector)
|
|
{//Winger 240404 - wylaczanie sprezarki i przetwornicy przy braku napiecia
|
|
if (tmpTraction.TractionVoltage==0)
|
|
{//to coś wyłączało dźwięk silnika w ST43!
|
|
MoverParameters->ConverterFlag=false;
|
|
MoverParameters->CompressorFlag=false; //Ra: to jest wątpliwe - wyłączenie sprężarki powinno być w jednym miejscu!
|
|
}
|
|
}
|
|
}
|
|
else if (MoverParameters->EnginePowerSource.SourceType==InternalSource)
|
|
if (MoverParameters->EnginePowerSource.PowerType==SteamPower)
|
|
//if (smPatykird1[0])
|
|
{//Ra: animacja rozrządu parowozu, na razie nieoptymalizowane
|
|
/* //Ra: tymczasowo wyłączone ze względu na porządkowanie animacji pantografów
|
|
double fi,dx,c2,ka,kc;
|
|
double sin_fi,cos_fi;
|
|
double L1=1.6688888888888889;
|
|
double L2=5.6666666666666667; //2550/450
|
|
double Lc=0.4;
|
|
double L=5.686422222; //2558.89/450
|
|
double G1,G2,G3,ksi,sin_ksi,gam;
|
|
double G1_2,G2_2,G3_2; //kwadraty
|
|
//ruch tłoków oraz korbowodów
|
|
for (int i=0;i<=1;++i)
|
|
{//obie strony w ten sam sposób
|
|
fi=DegToRad(dWheelAngle[1]+(i?pant2x:pant1x)); //kąt obrotu koła dla tłoka 1
|
|
sin_fi=sin(fi);
|
|
cos_fi=cos(fi);
|
|
dx=panty*cos_fi+sqrt(panth*panth-panty*panty*sin_fi*sin_fi)-panth; //nieoptymalne
|
|
if (smPatykird1[i]) //na razie zabezpieczenie
|
|
smPatykird1[i]->SetTranslate(float3(dx,0,0));
|
|
ka=-asin(panty/panth)*sin_fi;
|
|
if (smPatykirg1[i]) //na razie zabezpieczenie
|
|
smPatykirg1[i]->SetRotateXYZ(vector3(RadToDeg(ka),0,0));
|
|
//smPatykirg1[0]->SetRotate(float3(0,1,0),RadToDeg(fi)); //obracamy
|
|
//ruch drążka mimośrodkowego oraz jarzma
|
|
//korzystałem z pliku PDF "mm.pdf" (opis czworoboku korbowo-wahaczowego):
|
|
//"MECHANIKA MASZYN. Szkic wykładu i laboratorium komputerowego."
|
|
//Prof. dr hab. inż. Jerzy Zajączkowski, 2007, Politechnika Łódzka
|
|
//L1 - wysokość (w pionie) osi jarzma ponad osią koła
|
|
//L2 - odległość w poziomie osi jarzma od osi koła
|
|
//Lc - długość korby mimośrodu na kole
|
|
//Lr - promień jarzma =1.0 (pozostałe przeliczone proporcjonalnie)
|
|
//L - długość drążka mimośrodowego
|
|
//fi - kąt obrotu koła
|
|
//ksi - kąt obrotu jarzma (od pionu)
|
|
//gam - odchylenie drążka mimośrodowego od poziomu
|
|
//G1=(Lr*Lr+L1*L1+L2*L2+Kc*Lc-L*L-2.0*Lc*L2*cos(fi)+2.0*Lc*L1*sin(fi))/(Lr*Lr);
|
|
//G2=2.0*(L2-Lc*cos(fi))/Lr;
|
|
//G3=2.0*(L1-Lc*sin(fi))/Lr;
|
|
fi=DegToRad(dWheelAngle[1]+(i?pant2x:pant1x)-96.77416667); //kąt obrotu koła dla tłoka 1
|
|
//1) dla dWheelAngle[1]=0° korba jest w dół, a mimośród w stronę jarzma, czyli fi=-7°
|
|
//2) dla dWheelAngle[1]=90° korba jest do tyłu, a mimośród w dół, czyli fi=83°
|
|
sin_fi=sin(fi);
|
|
cos_fi=cos(fi);
|
|
G1=(1.0+L1*L1+L2*L2+Lc*Lc-L*L-2.0*Lc*L2*cos_fi+2.0*Lc*L1*sin_fi);
|
|
G1_2=G1*G1;
|
|
G2=2.0*(L2-Lc*cos_fi);
|
|
G2_2=G2*G2;
|
|
G3=2.0*(L1-Lc*sin_fi);
|
|
G3_2=G3*G3;
|
|
sin_ksi=(G1*G2-G3*_fm_sqrt(G2_2+G3_2-G1_2))/(G2_2+G3_2); //x1 (minus delta)
|
|
ksi=asin(sin_ksi); //kąt jarzma
|
|
if (smPatykirg2[i])
|
|
smPatykirg2[i]->SetRotateXYZ(vector3(RadToDeg(ksi),0,0)); //obrócenie jarzma
|
|
//1) ksi=-23°, gam=
|
|
//2) ksi=10°, gam=
|
|
//gam=acos((L2-sin_ksi-Lc*cos_fi)/L); //kąt od poziomu, liczony względem poziomu
|
|
//gam=asin((L1-cos_ksi-Lc*sin_fi)/L); //kąt od poziomu, liczony względem pionu
|
|
gam=atan2((L1-cos(ksi)+Lc*sin_fi),(L2-sin_ksi+Lc*cos_fi)); //kąt od poziomu
|
|
if (smPatykird2[i]) //na razie zabezpieczenie
|
|
smPatykird2[i]->SetRotateXYZ(vector3(RadToDeg(-gam-ksi),0,0)); //obrócenie drążka mimośrodowego
|
|
}
|
|
*/
|
|
}
|
|
|
|
//NBMX Obsluga drzwi, MC: zuniwersalnione
|
|
if ((dDoorMoveL<MoverParameters->DoorMaxShiftL) && (MoverParameters->DoorLeftOpened))
|
|
dDoorMoveL+=dt1*0.5*MoverParameters->DoorOpenSpeed;
|
|
if ((dDoorMoveL>0) && (!MoverParameters->DoorLeftOpened))
|
|
{
|
|
dDoorMoveL-=dt1*MoverParameters->DoorCloseSpeed;
|
|
if (dDoorMoveL<0)
|
|
dDoorMoveL=0;
|
|
}
|
|
if ((dDoorMoveR<MoverParameters->DoorMaxShiftR) && (MoverParameters->DoorRightOpened))
|
|
dDoorMoveR+=dt1*0.5*MoverParameters->DoorOpenSpeed;
|
|
if ((dDoorMoveR>0) && (!MoverParameters->DoorRightOpened))
|
|
{
|
|
dDoorMoveR-=dt1*MoverParameters->DoorCloseSpeed;
|
|
if (dDoorMoveR<0)
|
|
dDoorMoveR=0;
|
|
}
|
|
|
|
|
|
//ABu-160303 sledzenie toru przed obiektem: *******************************
|
|
//Z obserwacji: v>0 -> Coupler 0; v<0 ->coupler1 (Ra: prędkość jest związana z pojazdem)
|
|
//Rozroznienie jest tutaj, zeby niepotrzebnie nie skakac do funkcji. Nie jest uzaleznione
|
|
//od obecnosci AI, zeby uwzglednic np. jadace bez lokomotywy wagony.
|
|
//Ra: można by przenieść na poziom obiektu reprezentującego skład, aby nie sprawdzać środkowych
|
|
if (CouplCounter>25) //licznik, aby nie robić za każdym razem
|
|
{//poszukiwanie czegoś do zderzenia się
|
|
fTrackBlock=10000.0; //na razie nie ma przeszkód (na wypadek nie uruchomienia skanowania)
|
|
//jeśli nie ma zwrotnicy po drodze, to tylko przeliczyć odległość?
|
|
if (MoverParameters->V>0.03) //[m/s] jeśli jedzie do przodu (w kierunku Coupler 0)
|
|
{if (MoverParameters->Couplers[0].CouplingFlag==ctrain_virtual) //brak pojazdu podpiętego?
|
|
{ABuScanObjects(1,fScanDist); //szukanie czegoś do podłączenia
|
|
//WriteLog(asName+" - block 0: "+AnsiString(fTrackBlock));
|
|
}
|
|
}
|
|
else if (MoverParameters->V<-0.03) //[m/s] jeśli jedzie do tyłu (w kierunku Coupler 1)
|
|
if (MoverParameters->Couplers[1].CouplingFlag==ctrain_virtual) //brak pojazdu podpiętego?
|
|
{ABuScanObjects(-1,fScanDist);
|
|
//WriteLog(asName+" - block 1: "+AnsiString(fTrackBlock));
|
|
}
|
|
CouplCounter=random(20); //ponowne sprawdzenie po losowym czasie
|
|
}
|
|
if (MoverParameters->Vel>0.1) //[km/h]
|
|
++CouplCounter; //jazda sprzyja poszukiwaniu połączenia
|
|
else
|
|
{CouplCounter=25; //a bezruch nie, ale trzeba zaktualizować odległość, bo zawalidroga może sobie pojechać
|
|
}
|
|
if (MoverParameters->DerailReason>0)
|
|
{switch (MoverParameters->DerailReason)
|
|
{case 1: ErrorLog("Bad driving: "+asName+" derailed due to end of track"); break;
|
|
case 2: ErrorLog("Bad driving: "+asName+" derailed due to too high speed"); break;
|
|
case 3: ErrorLog("Bad dynamic: "+asName+" derailed due to track width"); break; //błąd w scenerii
|
|
case 4: ErrorLog("Bad dynamic: "+asName+" derailed due to wrong track type"); break; //błąd w scenerii
|
|
}
|
|
MoverParameters->DerailReason=0; //żeby tylko raz
|
|
}
|
|
if (MoverParameters->LoadStatus)
|
|
LoadUpdate(); //zmiana modelu ładunku
|
|
return true; //Ra: chyba tak?
|
|
}
|
|
|
|
bool __fastcall TDynamicObject::FastUpdate(double dt)
|
|
{
|
|
if (dt==0.0) return true; //Ra: pauza
|
|
double dDOMoveLen;
|
|
if (!MoverParameters->PhysicActivation)
|
|
return true; //McZapkie: wylaczanie fizyki gdy nie potrzeba
|
|
|
|
if (!bEnabled)
|
|
return false;
|
|
|
|
TLocation l;
|
|
l.X=-vPosition.x;
|
|
l.Y=vPosition.z;
|
|
l.Z=vPosition.y;
|
|
TRotation r;
|
|
r.Rx=r.Ry=r.Rz= 0;
|
|
|
|
//McZapkie: parametry powinny byc pobierane z toru
|
|
//ts.R=MyTrack->fRadius;
|
|
//ts.Len= Max0R(MoverParameters->BDist,MoverParameters->ADist);
|
|
//ts.dHtrack=Axle1.pPosition.y-Axle0.pPosition.y;
|
|
//ts.dHrail=((Axle1.GetRoll())+(Axle0.GetRoll()))*0.5f;
|
|
//tp.Width=MyTrack->fTrackWidth;
|
|
//McZapkie-250202
|
|
//tp.friction= MyTrack->fFriction;
|
|
//tp.CategoryFlag= MyTrack->iCategoryFlag&15;
|
|
//tp.DamageFlag=MyTrack->iDamageFlag;
|
|
//tp.QualityFlag=MyTrack->iQualityFlag;
|
|
dDOMoveLen=MoverParameters->FastComputeMovement(dt,ts,tp,l,r); // ,ts,tp,tmpTraction);
|
|
//Move(dDOMoveLen);
|
|
//ResetdMoveLen();
|
|
FastMove(dDOMoveLen);
|
|
|
|
if (MoverParameters->LoadStatus)
|
|
LoadUpdate(); //zmiana modelu ładunku
|
|
return true; //Ra: chyba tak?
|
|
}
|
|
|
|
//McZapkie-040402: liczenie pozycji uwzgledniajac wysokosc szyn itp.
|
|
//vector3 __fastcall TDynamicObject::GetPosition()
|
|
//{//Ra: pozycja pojazdu jest liczona zaraz po przesunięciu
|
|
// return vPosition;
|
|
//};
|
|
|
|
void __fastcall TDynamicObject::TurnOff()
|
|
{//wyłączenie rysowania submodeli zmiennych dla egemplarza pojazdu
|
|
btnOn=false;
|
|
btCoupler1.TurnOff();
|
|
btCoupler2.TurnOff();
|
|
btCPneumatic1.TurnOff();
|
|
btCPneumatic1r.TurnOff();
|
|
btCPneumatic2.TurnOff();
|
|
btCPneumatic2r.TurnOff();
|
|
btPneumatic1.TurnOff();
|
|
btPneumatic1r.TurnOff();
|
|
btPneumatic2.TurnOff();
|
|
btPneumatic2r.TurnOff();
|
|
btCCtrl1.TurnOff();
|
|
btCCtrl2.TurnOff();
|
|
btCPass1.TurnOff();
|
|
btCPass2.TurnOff();
|
|
btEndSignals11.TurnOff();
|
|
btEndSignals13.TurnOff();
|
|
btEndSignals21.TurnOff();
|
|
btEndSignals23.TurnOff();
|
|
btEndSignals1.TurnOff();
|
|
btEndSignals2.TurnOff();
|
|
btEndSignalsTab1.TurnOff();
|
|
btEndSignalsTab2.TurnOff();
|
|
btHeadSignals11.TurnOff();
|
|
btHeadSignals12.TurnOff();
|
|
btHeadSignals13.TurnOff();
|
|
btHeadSignals21.TurnOff();
|
|
btHeadSignals22.TurnOff();
|
|
btHeadSignals23.TurnOff();
|
|
};
|
|
|
|
void __fastcall TDynamicObject::Render()
|
|
{//rysowanie elementów nieprzezroczystych
|
|
//youBy - sprawdzamy, czy jest sens renderowac
|
|
double modelrotate;
|
|
vector3 tempangle;
|
|
// zmienne
|
|
renderme=false;
|
|
//przeklejka
|
|
double ObjSqrDist=SquareMagnitude(Global::pCameraPosition-vPosition);
|
|
//koniec przeklejki
|
|
if (ObjSqrDist<500) //jak jest blisko - do 70m
|
|
modelrotate=0.01; //mały kąt, żeby nie znikało
|
|
else
|
|
{//Global::pCameraRotation to kąt bewzględny w świecie (zero - na północ)
|
|
tempangle=(vPosition-Global::pCameraPosition); //wektor od kamery
|
|
modelrotate=ABuAcos(tempangle); //określenie kąta
|
|
//if (modelrotate>M_PI) modelrotate-=(2*M_PI);
|
|
modelrotate+=Global::pCameraRotation;
|
|
}
|
|
if (modelrotate>M_PI) modelrotate-=(2*M_PI);
|
|
if (modelrotate<-M_PI) modelrotate+=(2*M_PI);
|
|
ModCamRot=modelrotate;
|
|
|
|
modelrotate=abs(modelrotate);
|
|
|
|
if (modelrotate<maxrot) renderme=true;
|
|
|
|
if (renderme)
|
|
{
|
|
TSubModel::iInstance=(int)this; //żeby nie robić cudzych animacji
|
|
//AnsiString asLoadName="";
|
|
double ObjSqrDist=SquareMagnitude(Global::pCameraPosition-vPosition);
|
|
ABuLittleUpdate(ObjSqrDist); //ustawianie zmiennych submodeli dla wspólnego modelu
|
|
|
|
//Cone(vCoulpler[0],modelRot.z,0);
|
|
//Cone(vCoulpler[1],modelRot.z,1);
|
|
|
|
//ActualTrack= GetTrack(); //McZapkie-240702
|
|
|
|
#if RENDER_CONE
|
|
{//Ra: testowe renderowanie pozycji wózków w postaci ostrosłupów, wymaga GLUT32.DLL
|
|
double dir=RadToDeg(atan2(vLeft.z,vLeft.x));
|
|
Axle0.Render(0);
|
|
Axle1.Render(1); //bogieRot[0]
|
|
//if (PrevConnected) //renderowanie połączenia
|
|
}
|
|
#endif
|
|
|
|
glPushMatrix();
|
|
//vector3 pos= vPosition;
|
|
//double ObjDist= SquareMagnitude(Global::pCameraPosition-pos);
|
|
if (this==Global::pUserDynamic)
|
|
{//specjalne ustawienie, aby nie trzęsło
|
|
if (Global::bSmudge)
|
|
{//jak jest widoczna smuga, to pojazd renderować po wyrenderowaniu smugi
|
|
glPopMatrix(); //a to trzeba zebrać przed wyjściem
|
|
return;
|
|
}
|
|
//if (Global::pWorld->) //tu trzeba by ustawić animacje na modelu zewnętrznym
|
|
glLoadIdentity(); //zacząć od macierzy jedynkowej
|
|
Global::pCamera->SetCabMatrix(vPosition); //specjalne ustawienie kamery
|
|
}
|
|
else
|
|
glTranslated(vPosition.x,vPosition.y,vPosition.z); //standardowe przesunięcie względem początku scenerii
|
|
glMultMatrixd(mMatrix.getArray());
|
|
if (fShade>0.0)
|
|
{//Ra: zmiana oswietlenia w tunelu, wykopie
|
|
GLfloat ambientLight[4]= {0.5f,0.5f,0.5f,1.0f};
|
|
GLfloat diffuseLight[4]= {0.5f,0.5f,0.5f,1.0f};
|
|
GLfloat specularLight[4]={0.5f,0.5f,0.5f,1.0f};
|
|
//trochę problem z ambientem w wykopie...
|
|
for (int li=0;li<3;li++)
|
|
{
|
|
ambientLight[li]= Global::ambientDayLight[li]*fShade;
|
|
diffuseLight[li]= Global::diffuseDayLight[li]*fShade;
|
|
specularLight[li]=Global::specularDayLight[li]*fShade;
|
|
}
|
|
glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);
|
|
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
|
|
glLightfv(GL_LIGHT0,GL_SPECULAR,specularLight);
|
|
}
|
|
if (Global::bUseVBO)
|
|
{//wersja VBO
|
|
if (mdLowPolyInt)
|
|
if (FreeFlyModeFlag?true:!mdKabina||!bDisplayCab)
|
|
mdLowPolyInt->RaRender(ObjSqrDist,ReplacableSkinID,iAlpha);
|
|
mdModel->RaRender(ObjSqrDist,ReplacableSkinID,iAlpha);
|
|
if (mdLoad) //renderowanie nieprzezroczystego ładunku
|
|
mdLoad->RaRender(ObjSqrDist,ReplacableSkinID,iAlpha);
|
|
if (mdPrzedsionek)
|
|
mdPrzedsionek->RaRender(ObjSqrDist,ReplacableSkinID,iAlpha);
|
|
}
|
|
else
|
|
{//wersja Display Lists
|
|
if (mdLowPolyInt)
|
|
if (FreeFlyModeFlag?true:!mdKabina||!bDisplayCab)
|
|
mdLowPolyInt->Render(ObjSqrDist,ReplacableSkinID,iAlpha);
|
|
mdModel->Render(ObjSqrDist,ReplacableSkinID,iAlpha);
|
|
if (mdLoad) //renderowanie nieprzezroczystego ładunku
|
|
mdLoad->Render(ObjSqrDist,ReplacableSkinID,iAlpha);
|
|
if (mdPrzedsionek)
|
|
mdPrzedsionek->Render(ObjSqrDist,ReplacableSkinID,iAlpha);
|
|
}
|
|
|
|
//Ra: czy ta kabina tu ma sens?
|
|
//Ra: czy nie renderuje się dwukrotnie?
|
|
//Ra: dlaczego jest zablokowana w przezroczystych?
|
|
if (mdKabina) //jeśli ma model kabiny
|
|
if ((mdKabina!=mdModel) && bDisplayCab && FreeFlyModeFlag)
|
|
{//rendering kabiny gdy jest oddzielnym modelem i ma byc wyswietlana
|
|
//ABu: tylko w trybie FreeFly, zwykly tryb w world.cpp
|
|
//Ra: świetła są ustawione dla zewnętrza danego pojazdu
|
|
//oswietlenie kabiny
|
|
GLfloat ambientCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f };
|
|
GLfloat diffuseCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f };
|
|
GLfloat specularCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f };
|
|
for (int li=0; li<3; li++)
|
|
{
|
|
ambientCabLight[li]= Global::ambientDayLight[li]*0.9;
|
|
diffuseCabLight[li]= Global::diffuseDayLight[li]*0.5;
|
|
specularCabLight[li]=Global::specularDayLight[li]*0.5;
|
|
}
|
|
switch (MyTrack->eEnvironment)
|
|
{
|
|
case e_canyon:
|
|
{
|
|
for (int li=0; li<3; li++)
|
|
{
|
|
diffuseCabLight[li]*= 0.6;
|
|
specularCabLight[li]*= 0.7;
|
|
}
|
|
}
|
|
break;
|
|
case e_tunnel:
|
|
{
|
|
for (int li=0; li<3; li++)
|
|
{
|
|
ambientCabLight[li]*= 0.3;
|
|
diffuseCabLight[li]*= 0.1;
|
|
specularCabLight[li]*= 0.2;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
glLightfv(GL_LIGHT0,GL_AMBIENT,ambientCabLight);
|
|
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseCabLight);
|
|
glLightfv(GL_LIGHT0,GL_SPECULAR,specularCabLight);
|
|
if (Global::bUseVBO)
|
|
mdKabina->RaRender(ObjSqrDist,0);
|
|
else
|
|
mdKabina->Render(ObjSqrDist,0);
|
|
glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight);
|
|
glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight);
|
|
glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight);
|
|
}
|
|
if (fShade!=0.0) //tylko jeśli było zmieniane
|
|
{//przywrócenie standardowego oświetlenia
|
|
glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight);
|
|
glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight);
|
|
glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight);
|
|
}
|
|
glPopMatrix();
|
|
if (btnOn) TurnOff(); //przywrócenie domyślnych pozycji submodeli
|
|
} //yB - koniec mieszania z grafika
|
|
};
|
|
|
|
void __fastcall TDynamicObject::RenderSounds()
|
|
{//przeliczanie dźwięków, bo będzie słychać bez wyświetlania sektora z pojazdem
|
|
//McZapkie-010302: ulepszony dzwiek silnika
|
|
double freq;
|
|
double vol=0;
|
|
double dt=Timer::GetDeltaTime();
|
|
|
|
// double sounddist;
|
|
// sounddist=SquareMagnitude(Global::pCameraPosition-vPosition);
|
|
|
|
if (MoverParameters->Power>0)
|
|
{
|
|
if ((rsSilnik.AM!=0) && ((MoverParameters->Mains) || (MoverParameters->EngineType==DieselEngine))) //McZapkie-280503: zeby dla dumb dzialal silnik na jalowych obrotach
|
|
{
|
|
if ((fabs(MoverParameters->enrot)>0.01) || (MoverParameters->EngineType==Dumb)) //&& (MoverParameters->EnginePower>0.1))
|
|
{
|
|
freq=rsSilnik.FM*fabs(MoverParameters->enrot)+rsSilnik.FA;
|
|
if (MoverParameters->EngineType==Dumb)
|
|
freq=freq-0.2*MoverParameters->EnginePower/(1+MoverParameters->Power*1000);
|
|
rsSilnik.AdjFreq(freq,dt);
|
|
if (MoverParameters->EngineType==DieselEngine)
|
|
{
|
|
if (MoverParameters->enrot>0)
|
|
{
|
|
if (MoverParameters->EnginePower>0)
|
|
vol=rsSilnik.AM*MoverParameters->dizel_fill+rsSilnik.AA;
|
|
else
|
|
vol=rsSilnik.AM*fabs(MoverParameters->enrot/MoverParameters->nmax)+rsSilnik.AA*0.9;
|
|
}
|
|
else
|
|
vol=0;
|
|
}
|
|
else if (MoverParameters->EngineType==DieselElectric)
|
|
vol=rsSilnik.AM*(MoverParameters->EnginePower/1000/MoverParameters->Power)+0.2*(MoverParameters->enrot*60)/(MoverParameters->DElist[MoverParameters->MainCtrlPosNo].RPM)+rsSilnik.AA;
|
|
else if (MoverParameters->EngineType==ElectricInductionMotor)
|
|
vol=rsSilnik.AM*(MoverParameters->EnginePower+fabs(MoverParameters->enrot*2))+rsSilnik.AA;
|
|
else
|
|
vol=rsSilnik.AM*(MoverParameters->EnginePower/1000+fabs(MoverParameters->enrot)*60.0)+rsSilnik.AA;
|
|
// McZapkie-250302 - natezenie zalezne od obrotow i mocy
|
|
if ((vol<1) && (MoverParameters->EngineType==ElectricSeriesMotor) && (MoverParameters->EnginePower<100))
|
|
{
|
|
float volrnd=random(100)*MoverParameters->enrot/(1+MoverParameters->nmax);
|
|
if (volrnd<2)
|
|
vol=vol+volrnd/200.0;
|
|
}
|
|
switch (MyTrack->eEnvironment)
|
|
{
|
|
case e_tunnel:
|
|
{
|
|
vol+=0.1;
|
|
}
|
|
break;
|
|
case e_canyon:
|
|
{
|
|
vol+=0.05;
|
|
}
|
|
break;
|
|
}
|
|
if ((MoverParameters->DynamicBrakeFlag) && (MoverParameters->EnginePower>0.1) && (MoverParameters->EngineType==ElectricSeriesMotor)) //Szociu - 29012012 - jeżeli uruchomiony jest hamulec elektrodynamiczny, odtwarzany jest dźwięk silnika
|
|
vol +=0.8;
|
|
|
|
if (enginevolume>0.0001)
|
|
if (MoverParameters->EngineType!=DieselElectric)
|
|
{ rsSilnik.Play(enginevolume,DSBPLAY_LOOPING,MechInside,GetPosition()); }
|
|
else
|
|
{
|
|
sConverter.UpdateAF(vol,freq,MechInside,GetPosition());
|
|
|
|
float fincvol;
|
|
fincvol=0;
|
|
if ((MoverParameters->ConverterFlag)&&(MoverParameters->enrot*60>MoverParameters->DElist[0].RPM))
|
|
{
|
|
fincvol=(MoverParameters->DElist[MoverParameters->MainCtrlPos].RPM-(MoverParameters->enrot*60));
|
|
fincvol/=(0.05*MoverParameters->DElist[0].RPM);
|
|
};
|
|
if (fincvol>0.02)
|
|
rsDiesielInc.Play(fincvol,DSBPLAY_LOOPING,MechInside,GetPosition());
|
|
else
|
|
rsDiesielInc.Stop();
|
|
}
|
|
}
|
|
else
|
|
rsSilnik.Stop();
|
|
}
|
|
enginevolume=(enginevolume+vol)/2;
|
|
if (enginevolume<0.01)
|
|
rsSilnik.Stop();
|
|
if ((MoverParameters->EngineType==ElectricSeriesMotor)||(MoverParameters->EngineType==ElectricInductionMotor) && rsWentylator.AM!=0)
|
|
{
|
|
if (MoverParameters->RventRot>0.1)
|
|
{
|
|
freq=rsWentylator.FM*MoverParameters->RventRot+rsWentylator.FA;
|
|
rsWentylator.AdjFreq(freq,dt);
|
|
if (MoverParameters->EngineType==ElectricInductionMotor)
|
|
vol=rsWentylator.AM*sqrt(fabs(MoverParameters->dizel_fill))+rsWentylator.AA;
|
|
else
|
|
vol=rsWentylator.AM*MoverParameters->RventRot+rsWentylator.AA;
|
|
rsWentylator.Play(vol,DSBPLAY_LOOPING,MechInside,GetPosition());
|
|
}
|
|
else
|
|
rsWentylator.Stop();
|
|
}
|
|
if (MoverParameters->TrainType==dt_ET40)
|
|
{
|
|
if (MoverParameters->Vel>0.1)
|
|
{
|
|
freq=rsPrzekladnia.FM*(MoverParameters->Vel)+rsPrzekladnia.FA;
|
|
rsPrzekladnia.AdjFreq(freq,dt);
|
|
vol=rsPrzekladnia.AM*(MoverParameters->Vel)+rsPrzekladnia.AA;
|
|
rsPrzekladnia.Play(vol,DSBPLAY_LOOPING,MechInside,GetPosition());
|
|
}
|
|
else
|
|
rsPrzekladnia.Stop();
|
|
}
|
|
}
|
|
|
|
//youBy: dzwiek ostrych lukow i ciasnych zwrotek
|
|
|
|
if ((ts.R*ts.R>1)&&(MoverParameters->Vel>0))
|
|
vol=MoverParameters->AccN*MoverParameters->AccN;
|
|
else
|
|
vol=0;
|
|
// vol+=(50000/ts.R*ts.R);
|
|
|
|
if (vol>0.001)
|
|
{
|
|
rscurve.Play(2*vol,DSBPLAY_LOOPING,MechInside,GetPosition());
|
|
}
|
|
else
|
|
rscurve.Stop();
|
|
|
|
//McZapkie-280302 - pisk mocno zacisnietych hamulcow - trzeba jeszcze zabezpieczyc przed brakiem deklaracji w mmedia.dta
|
|
if (rsPisk.AM!=0)
|
|
{
|
|
if ((MoverParameters->Vel>(rsPisk.GetStatus()!=0?0.01:0.5)) && (!MoverParameters->SlippingWheels) && (MoverParameters->UnitBrakeForce>rsPisk.AM))
|
|
{
|
|
vol=MoverParameters->UnitBrakeForce/(rsPisk.AM+1)+rsPisk.AA;
|
|
rsPisk.Play(vol,DSBPLAY_LOOPING,MechInside,GetPosition());
|
|
}
|
|
else
|
|
rsPisk.Stop();
|
|
}
|
|
|
|
//if ((MoverParameters->ConverterFlag==false) && (MoverParameters->TrainType!=dt_ET22))
|
|
//if ((MoverParameters->ConverterFlag==false)&&(MoverParameters->CompressorPower!=0))
|
|
// MoverParameters->CompressorFlag=false; //Ra: wywalić to stąd, tu tylko dla wyświetlanych!
|
|
//Ra: no to już wiemy, dlaczego pociągi jeżdżą lepiej, gdy się na nie patrzy!
|
|
//if (MoverParameters->CompressorPower==2)
|
|
// MoverParameters->CompressorAllow=MoverParameters->ConverterFlag;
|
|
|
|
// McZapkie! - dzwiek compressor.wav tylko gdy dziala sprezarka
|
|
if (MoverParameters->VeselVolume!=0)
|
|
{
|
|
if (MoverParameters->CompressorFlag)
|
|
sCompressor.TurnOn(MechInside,GetPosition());
|
|
else
|
|
sCompressor.TurnOff(MechInside,GetPosition());
|
|
sCompressor.Update(MechInside,GetPosition());
|
|
}
|
|
if (MoverParameters->PantCompFlag) // Winger 160404 - dzwiek malej sprezarki
|
|
sSmallCompressor.TurnOn(MechInside,GetPosition());
|
|
else
|
|
sSmallCompressor.TurnOff(MechInside,GetPosition());
|
|
sSmallCompressor.Update(MechInside,GetPosition());
|
|
|
|
//youBy - przenioslem, bo diesel tez moze miec turbo
|
|
if ((MoverParameters->MainCtrlPos)>=(MoverParameters->TurboTest)) //hunter-250312: dlaczego zakomentowane? Ra: bo nie działało dobrze
|
|
{
|
|
//udawanie turbo: (6.66*(eng_vol-0.85))
|
|
if (eng_turbo>6.66*(enginevolume-0.8)+0.2*dt)
|
|
eng_turbo=eng_turbo-0.2*dt; //0.125
|
|
else
|
|
if (eng_turbo<6.66*(enginevolume-0.8)-0.4*dt)
|
|
eng_turbo=eng_turbo+0.4*dt; //0.333
|
|
else
|
|
eng_turbo=6.66*(enginevolume-0.8);
|
|
|
|
sTurbo.TurnOn(MechInside,GetPosition());
|
|
//sTurbo.UpdateAF(eng_turbo,0.7+(eng_turbo*0.6),MechInside,GetPosition());
|
|
sTurbo.UpdateAF(3*eng_turbo-1,0.4+eng_turbo*0.4,MechInside,GetPosition());
|
|
// eng_vol_act=enginevolume;
|
|
//eng_frq_act=eng_frq;
|
|
}
|
|
else sTurbo.TurnOff(MechInside,GetPosition());
|
|
|
|
|
|
|
|
if (MoverParameters->TrainType==dt_PseudoDiesel)
|
|
{
|
|
//ABu: udawanie woodwarda dla lok. spalinowych
|
|
//jesli silnik jest podpiety pod dzwiek przetwornicy
|
|
if (MoverParameters->ConverterFlag) //NBMX dzwiek przetwornicy
|
|
{
|
|
sConverter.TurnOn(MechInside,GetPosition());
|
|
}
|
|
else
|
|
sConverter.TurnOff(MechInside,GetPosition());
|
|
|
|
//glosnosc zalezy od stosunku mocy silnika el. do mocy max
|
|
double eng_vol;
|
|
if (MoverParameters->Power>1)
|
|
//0.85+0.000015*(...)
|
|
eng_vol=0.8+0.00002*(MoverParameters->EnginePower/MoverParameters->Power);
|
|
else
|
|
eng_vol=1;
|
|
|
|
eng_dfrq=eng_dfrq+(eng_vol_act-eng_vol);
|
|
if(eng_dfrq>0)
|
|
{
|
|
eng_dfrq=eng_dfrq-0.025*dt;
|
|
if(eng_dfrq<0.025*dt)
|
|
eng_dfrq=0;
|
|
}
|
|
else
|
|
if(eng_dfrq<0)
|
|
{
|
|
eng_dfrq=eng_dfrq+0.025*dt;
|
|
if(eng_dfrq>-0.025*dt)
|
|
eng_dfrq=0;
|
|
}
|
|
double defrot;
|
|
if (MoverParameters->MainCtrlPos!=0)
|
|
{
|
|
double CtrlPos=MoverParameters->MainCtrlPos;
|
|
double CtrlPosNo=MoverParameters->MainCtrlPosNo;
|
|
//defrot=1+0.4*(CtrlPos/CtrlPosNo);
|
|
defrot=1+0.5*(CtrlPos/CtrlPosNo);
|
|
}
|
|
else
|
|
defrot=1;
|
|
|
|
if (eng_frq_act<defrot)
|
|
{
|
|
//if (MoverParameters->MainCtrlPos==1) eng_frq_act=eng_frq_act+0.1*dt;
|
|
eng_frq_act=eng_frq_act+0.4*dt; //0.05
|
|
if (eng_frq_act>defrot-0.4*dt)
|
|
eng_frq_act=defrot;
|
|
}
|
|
else
|
|
if (eng_frq_act>defrot)
|
|
{
|
|
eng_frq_act=eng_frq_act-0.1*dt; //0.05
|
|
if (eng_frq_act<defrot+0.1*dt)
|
|
eng_frq_act=defrot;
|
|
}
|
|
sConverter.UpdateAF(eng_vol_act,eng_frq_act+eng_dfrq,MechInside,GetPosition());
|
|
//udawanie turbo: (6.66*(eng_vol-0.85))
|
|
if (eng_turbo>6.66*(eng_vol-0.8)+0.2*dt)
|
|
eng_turbo=eng_turbo-0.2*dt; //0.125
|
|
else
|
|
if (eng_turbo<6.66*(eng_vol-0.8)-0.4*dt)
|
|
eng_turbo=eng_turbo+0.4*dt; //0.333
|
|
else
|
|
eng_turbo=6.66*(eng_vol-0.8);
|
|
|
|
sTurbo.TurnOn(MechInside,GetPosition());
|
|
//sTurbo.UpdateAF(eng_turbo,0.7+(eng_turbo*0.6),MechInside,GetPosition());
|
|
sTurbo.UpdateAF(3*eng_turbo-1,0.4+eng_turbo*0.4,MechInside,GetPosition());
|
|
eng_vol_act=eng_vol;
|
|
//eng_frq_act=eng_frq;
|
|
}
|
|
else
|
|
{
|
|
if (MoverParameters->ConverterFlag) //NBMX dzwiek przetwornicy
|
|
sConverter.TurnOn(MechInside,GetPosition());
|
|
else
|
|
sConverter.TurnOff(MechInside,GetPosition());
|
|
sConverter.Update(MechInside,GetPosition());
|
|
}
|
|
if (MoverParameters->WarningSignal>0)
|
|
{
|
|
if (TestFlag(MoverParameters->WarningSignal,1))
|
|
sHorn1.TurnOn(MechInside,GetPosition());
|
|
else
|
|
sHorn1.TurnOff(MechInside,GetPosition());
|
|
if (TestFlag(MoverParameters->WarningSignal,2))
|
|
sHorn2.TurnOn(MechInside,GetPosition());
|
|
else
|
|
sHorn2.TurnOff(MechInside,GetPosition());
|
|
}
|
|
else
|
|
{
|
|
sHorn1.TurnOff(MechInside,GetPosition());
|
|
sHorn2.TurnOff(MechInside,GetPosition());
|
|
}
|
|
if (MoverParameters->DoorClosureWarning)
|
|
{
|
|
if (MoverParameters->DepartureSignal) //NBMX sygnal odjazdu, MC: pod warunkiem ze jest zdefiniowane w chk
|
|
sDepartureSignal.TurnOn(MechInside,GetPosition());
|
|
else
|
|
sDepartureSignal.TurnOff(MechInside,GetPosition());
|
|
sDepartureSignal.Update(MechInside,GetPosition());
|
|
}
|
|
sHorn1.Update(MechInside,GetPosition());
|
|
sHorn2.Update(MechInside,GetPosition());
|
|
//McZapkie: w razie wykolejenia
|
|
if (MoverParameters->EventFlag)
|
|
{
|
|
if (TestFlag(MoverParameters->DamageFlag,dtrain_out) && GetVelocity()>0)
|
|
rsDerailment.Play(1,0,true,GetPosition());
|
|
if (GetVelocity()==0)
|
|
rsDerailment.Stop();
|
|
}
|
|
/* //Ra: dwa razy?
|
|
if (MoverParameters->EventFlag)
|
|
{
|
|
if (TestFlag(MoverParameters->DamageFlag,dtrain_out) && GetVelocity()>0)
|
|
rsDerailment.Play(1,0,true,GetPosition());
|
|
if (GetVelocity()==0)
|
|
rsDerailment.Stop();
|
|
}
|
|
*/
|
|
};
|
|
|
|
void __fastcall TDynamicObject::RenderAlpha()
|
|
{//rysowanie elementów półprzezroczystych
|
|
if (renderme)
|
|
{
|
|
TSubModel::iInstance=(int)this; //żeby nie robić cudzych animacji
|
|
double ObjSqrDist=SquareMagnitude(Global::pCameraPosition-vPosition);
|
|
ABuLittleUpdate(ObjSqrDist); //ustawianie zmiennych submodeli dla wspólnego modelu
|
|
glPushMatrix();
|
|
if (this==Global::pUserDynamic)
|
|
{//specjalne ustawienie, aby nie trzęsło
|
|
if (Global::bSmudge)
|
|
{//jak smuga, to rysować po smudze
|
|
glPopMatrix(); //to trzeba zebrać przed wyściem
|
|
return;
|
|
}
|
|
glLoadIdentity(); //zacząć od macierzy jedynkowej
|
|
Global::pCamera->SetCabMatrix(vPosition); //specjalne ustawienie kamery
|
|
}
|
|
else
|
|
glTranslated(vPosition.x,vPosition.y,vPosition.z); //standardowe przesunięcie względem początku scenerii
|
|
glMultMatrixd(mMatrix.getArray());
|
|
if (fShade>0.0)
|
|
{//Ra: zmiana oswietlenia w tunelu, wykopie
|
|
GLfloat ambientLight[4]= {0.5f,0.5f,0.5f,1.0f};
|
|
GLfloat diffuseLight[4]= {0.5f,0.5f,0.5f,1.0f};
|
|
GLfloat specularLight[4]={0.5f,0.5f,0.5f,1.0f};
|
|
//trochę problem z ambientem w wykopie...
|
|
for (int li=0;li<3;li++)
|
|
{
|
|
ambientLight[li]= Global::ambientDayLight[li]*fShade;
|
|
diffuseLight[li]= Global::diffuseDayLight[li]*fShade;
|
|
specularLight[li]=Global::specularDayLight[li]*fShade;
|
|
}
|
|
glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);
|
|
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
|
|
glLightfv(GL_LIGHT0,GL_SPECULAR,specularLight);
|
|
}
|
|
if (Global::bUseVBO)
|
|
{//wersja VBO
|
|
if (mdLowPolyInt)
|
|
if (FreeFlyModeFlag?true:!mdKabina||!bDisplayCab)
|
|
mdLowPolyInt->RaRenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha);
|
|
mdModel->RaRenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha);
|
|
if (mdLoad)
|
|
mdLoad->RaRenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha);
|
|
//if (mdPrzedsionek) //Ra: przedsionków tu wcześniej nie było - włączyć?
|
|
// mdPrzedsionek->RaRenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha);
|
|
}
|
|
else
|
|
{//wersja Display Lists
|
|
if (mdLowPolyInt)
|
|
if (FreeFlyModeFlag?true:!mdKabina||!bDisplayCab)
|
|
mdLowPolyInt->RenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha);
|
|
mdModel->RenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha);
|
|
if (mdLoad)
|
|
mdLoad->RenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha);
|
|
//if (mdPrzedsionek) //Ra: przedsionków tu wcześniej nie było - włączyć?
|
|
// mdPrzedsionek->RenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha);
|
|
}
|
|
/* skoro false to można wyciąc
|
|
//ABu: Tylko w trybie freefly
|
|
if (false)//((mdKabina!=mdModel) && bDisplayCab && FreeFlyModeFlag)
|
|
{
|
|
//oswietlenie kabiny
|
|
GLfloat ambientCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f };
|
|
GLfloat diffuseCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f };
|
|
GLfloat specularCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f };
|
|
for (int li=0; li<3; li++)
|
|
{
|
|
ambientCabLight[li]= Global::ambientDayLight[li]*0.9;
|
|
diffuseCabLight[li]= Global::diffuseDayLight[li]*0.5;
|
|
specularCabLight[li]= Global::specularDayLight[li]*0.5;
|
|
}
|
|
switch (MyTrack->eEnvironment)
|
|
{
|
|
case e_canyon:
|
|
{
|
|
for (int li=0; li<3; li++)
|
|
{
|
|
diffuseCabLight[li]*= 0.6;
|
|
specularCabLight[li]*= 0.8;
|
|
}
|
|
}
|
|
break;
|
|
case e_tunnel:
|
|
{
|
|
for (int li=0; li<3; li++)
|
|
{
|
|
ambientCabLight[li]*= 0.3;
|
|
diffuseCabLight[li]*= 0.1;
|
|
specularCabLight[li]*= 0.2;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
// dorobic swiatlo od drugiej strony szyby
|
|
|
|
glLightfv(GL_LIGHT0,GL_AMBIENT,ambientCabLight);
|
|
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseCabLight);
|
|
glLightfv(GL_LIGHT0,GL_SPECULAR,specularCabLight);
|
|
|
|
mdKabina->RenderAlpha(ObjSqrDist,0);
|
|
//smierdzi
|
|
// mdModel->RenderAlpha(SquareMagnitude(Global::pCameraPosition-pos),0);
|
|
|
|
glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight);
|
|
glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight);
|
|
glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight);
|
|
}
|
|
*/
|
|
if (fShade!=0.0) //tylko jeśli było zmieniane
|
|
{//przywrócenie standardowego oświetlenia
|
|
glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight);
|
|
glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight);
|
|
glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight);
|
|
}
|
|
glPopMatrix();
|
|
if (btnOn) TurnOff(); //przywrócenie domyślnych pozycji submodeli
|
|
}
|
|
return;
|
|
} //koniec renderalpha
|
|
|
|
|
|
//McZapkie-250202
|
|
//wczytywanie pliku z danymi multimedialnymi (dzwieki)
|
|
void __fastcall TDynamicObject::LoadMMediaFile(AnsiString BaseDir,AnsiString TypeName,AnsiString ReplacableSkin)
|
|
{
|
|
double dSDist;
|
|
TFileStream *fs;
|
|
//asBaseDir=BaseDir;
|
|
Global::asCurrentDynamicPath=BaseDir;
|
|
AnsiString asFileName=BaseDir+TypeName+".mmd";
|
|
AnsiString asLoadName=BaseDir+MoverParameters->LoadType+".t3d";
|
|
if (!FileExists(asFileName))
|
|
{
|
|
ErrorLog("Missed file: "+asFileName); //brak MMD
|
|
return;
|
|
}
|
|
fs=new TFileStream(asFileName,fmOpenRead|fmShareCompat);
|
|
if (!fs) return;
|
|
int size=fs->Size;
|
|
if (!size) {return delete fs;};
|
|
AnsiString asAnimName;
|
|
bool Stop_InternalData=false;
|
|
char* buf=new char[size+1]; //ciąg bajtów o długości równej rozmiwarowi pliku
|
|
buf[size]='\0'; //zakończony zerem na wszelki wypadek
|
|
fs->Read(buf,size);
|
|
delete fs;
|
|
TQueryParserComp *Parser;
|
|
Parser=new TQueryParserComp(NULL);
|
|
Parser->TextToParse=AnsiString(buf);
|
|
delete[] buf;
|
|
AnsiString str;
|
|
//Parser->LoadStringToParse(asFile);
|
|
Parser->First();
|
|
//DecimalSeparator= '.';
|
|
pants=NULL; //wskaźnik pierwszego obiektu animującego dla pantografów
|
|
int i;
|
|
while (!Parser->EndOfFile && !Stop_InternalData)
|
|
{
|
|
str=Parser->GetNextSymbol().LowerCase();
|
|
if (str==AnsiString("models:")) //modele i podmodele
|
|
{
|
|
iMultiTex=0; //czy jest wiele tekstur wymiennych?
|
|
asModel=Parser->GetNextSymbol().LowerCase();
|
|
if (asModel.Pos("#")==asModel.Length()) //Ra 2015-01: nie podoba mi się to
|
|
{//model wymaga wielu tekstur wymiennych
|
|
iMultiTex=1;
|
|
asModel=asModel.SubString(1,asModel.Length()-1);
|
|
}
|
|
if ((i=asModel.Pos(","))>0)
|
|
{//Ra 2015-01: może szukać przecinka w nazwie modelu, a po przecinku była by liczba tekstur?
|
|
if (i<asModel.Length())
|
|
iMultiTex=asModel[i+1]-'0';
|
|
if (iMultiTex<0) iMultiTex=0; else if (iMultiTex>1) iMultiTex=1; //na razie ustawiamy na 1
|
|
}
|
|
asModel=BaseDir+asModel; //McZapkie 2002-07-20: dynamics maja swoje modele w dynamics/basedir
|
|
Global::asCurrentTexturePath=BaseDir; //biezaca sciezka do tekstur to dynamic/...
|
|
mdModel=TModelsManager::GetModel(asModel.c_str(),true);
|
|
if (ReplacableSkin!=AnsiString("none"))
|
|
{//tekstura wymienna jest raczej jedynie w "dynamic\"
|
|
ReplacableSkin=Global::asCurrentTexturePath+ReplacableSkin; //skory tez z dynamic/...
|
|
if ((i=ReplacableSkin.Pos("|"))>0) //replacable dzielone
|
|
{iMultiTex=-1;
|
|
ReplacableSkinID[-iMultiTex]=TTexturesManager::GetTextureID(NULL,NULL,ReplacableSkin.SubString(1,i-1).c_str(),Global::iDynamicFiltering);
|
|
ReplacableSkin.Delete(1,i); //usunięcie razem z pionową kreską
|
|
ReplacableSkin=Global::asCurrentTexturePath+ReplacableSkin; //odtworzenie początku ścieżki
|
|
//sprawdzić, ile jest i ustawić iMultiTex na liczbę podanych tekstur
|
|
if (!ReplacableSkin.IsEmpty())
|
|
{//próba wycięcia drugiej nazwy
|
|
iMultiTex=-2; //skoro zostało coś po kresce, to są co najmniej dwie
|
|
if ((i=ReplacableSkin.Pos("|"))==0) //gdy nie ma już kreski
|
|
ReplacableSkinID[-iMultiTex]=TTexturesManager::GetTextureID(NULL,NULL,ReplacableSkin.SubString(1,i-1).c_str(),Global::iDynamicFiltering);
|
|
else
|
|
{//jak jest kreska, to wczytać drugą i próbować trzecią
|
|
ReplacableSkinID[-iMultiTex]=TTexturesManager::GetTextureID(NULL,NULL,ReplacableSkin.SubString(1,i-1).c_str(),Global::iDynamicFiltering);
|
|
ReplacableSkin.Delete(1,i); //usunięcie razem z pionową kreską
|
|
ReplacableSkin=Global::asCurrentTexturePath+ReplacableSkin; //odtworzenie początku ścieżki
|
|
if (!ReplacableSkin.IsEmpty())
|
|
{//próba wycięcia trzeciej nazwy
|
|
iMultiTex=-3; //skoro zostało coś po kresce, to są co najmniej trzy
|
|
if ((i=ReplacableSkin.Pos("|"))==0) //gdy nie ma już kreski
|
|
ReplacableSkinID[-iMultiTex]=TTexturesManager::GetTextureID(NULL,NULL,ReplacableSkin.SubString(1,i-1).c_str(),Global::iDynamicFiltering);
|
|
else
|
|
{//jak jest kreska, to wczytać trzecią i próbować czwartą
|
|
ReplacableSkinID[-iMultiTex]=TTexturesManager::GetTextureID(NULL,NULL,ReplacableSkin.SubString(1,i-1).c_str(),Global::iDynamicFiltering);
|
|
ReplacableSkin.Delete(1,i); //usunięcie razem z pionową kreską
|
|
ReplacableSkin=Global::asCurrentTexturePath+ReplacableSkin; //odtworzenie początku ścieżki
|
|
if (!ReplacableSkin.IsEmpty())
|
|
{//próba wycięcia trzeciej nazwy
|
|
iMultiTex=-4; //skoro zostało coś po kresce, to są co najmniej cztery
|
|
ReplacableSkinID[-iMultiTex]=TTexturesManager::GetTextureID(NULL,NULL,ReplacableSkin.SubString(1,i-1).c_str(),Global::iDynamicFiltering);
|
|
//więcej na razie nie zadziała, a u tak trzeba to do modeli przenieść
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (iMultiTex>0)
|
|
{//jeśli model ma 4 tekstury
|
|
ReplacableSkinID[1]=TTexturesManager::GetTextureID(NULL,NULL,(ReplacableSkin+",1").c_str(),Global::iDynamicFiltering);
|
|
if (ReplacableSkinID[1])
|
|
{//pierwsza z zestawu znaleziona
|
|
ReplacableSkinID[2]=TTexturesManager::GetTextureID(NULL,NULL,(ReplacableSkin+",2").c_str(),Global::iDynamicFiltering);
|
|
if (ReplacableSkinID[2])
|
|
{iMultiTex=2; //już są dwie
|
|
ReplacableSkinID[3]=TTexturesManager::GetTextureID(NULL,NULL,(ReplacableSkin+",3").c_str(),Global::iDynamicFiltering);
|
|
if (ReplacableSkinID[3])
|
|
{iMultiTex=3; //a teraz nawet trzy
|
|
ReplacableSkinID[4]=TTexturesManager::GetTextureID(NULL,NULL,(ReplacableSkin+",4").c_str(),Global::iDynamicFiltering);
|
|
if (ReplacableSkinID[4]) iMultiTex=4; //jak są cztery, to blokujemy podmianę tekstury rozkładem
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{//zestaw nie zadziałał, próbujemy normanie
|
|
iMultiTex=0;
|
|
ReplacableSkinID[1]=TTexturesManager::GetTextureID(NULL,NULL,ReplacableSkin.c_str(),Global::iDynamicFiltering);
|
|
}
|
|
}
|
|
else
|
|
ReplacableSkinID[1]=TTexturesManager::GetTextureID(NULL,NULL,ReplacableSkin.c_str(),Global::iDynamicFiltering);
|
|
if (TTexturesManager::GetAlpha(ReplacableSkinID[1]))
|
|
iAlpha=0x31310031; //tekstura -1 z kanałem alfa - nie renderować w cyklu nieprzezroczystych
|
|
else
|
|
iAlpha=0x30300030; //wszystkie tekstury nieprzezroczyste - nie renderować w cyklu przezroczystych
|
|
if (ReplacableSkinID[2])
|
|
if (TTexturesManager::GetAlpha(ReplacableSkinID[2]))
|
|
iAlpha|=0x02020002; //tekstura -2 z kanałem alfa - nie renderować w cyklu nieprzezroczystych
|
|
if (ReplacableSkinID[3])
|
|
if (TTexturesManager::GetAlpha(ReplacableSkinID[3]))
|
|
iAlpha|=0x04040004; //tekstura -3 z kanałem alfa - nie renderować w cyklu nieprzezroczystych
|
|
if (ReplacableSkinID[4])
|
|
if (TTexturesManager::GetAlpha(ReplacableSkinID[4]))
|
|
iAlpha|=0x08080008; //tekstura -4 z kanałem alfa - nie renderować w cyklu nieprzezroczystych
|
|
}
|
|
//Winger 040304 - ladowanie przedsionkow dla EZT
|
|
if (MoverParameters->TrainType==dt_EZT)
|
|
{
|
|
asModel="przedsionki.t3d";
|
|
asModel=BaseDir+asModel;
|
|
mdPrzedsionek=TModelsManager::GetModel(asModel.c_str(),true);
|
|
}
|
|
if (!MoverParameters->LoadAccepted.IsEmpty())
|
|
//if (MoverParameters->LoadAccepted!=AnsiString("")); // && MoverParameters->LoadType!=AnsiString("passengers"))
|
|
if (MoverParameters->EnginePowerSource.SourceType==CurrentCollector)
|
|
{//wartość niby "pantstate" - nazwa dla formalności, ważna jest ilość
|
|
if (MoverParameters->Load==1)
|
|
MoverParameters->PantFront(true);
|
|
else if (MoverParameters->Load==2)
|
|
MoverParameters->PantRear(true);
|
|
else if (MoverParameters->Load==3)
|
|
{
|
|
MoverParameters->PantFront(true);
|
|
MoverParameters->PantRear(true);
|
|
}
|
|
else if (MoverParameters->Load==4)
|
|
MoverParameters->DoubleTr=-1;
|
|
else if (MoverParameters->Load==5)
|
|
{
|
|
MoverParameters->DoubleTr=-1;
|
|
MoverParameters->PantRear(true);
|
|
}
|
|
else if (MoverParameters->Load==6)
|
|
{
|
|
MoverParameters->DoubleTr=-1;
|
|
MoverParameters->PantFront(true);
|
|
}
|
|
else if (MoverParameters->Load==7)
|
|
{
|
|
MoverParameters->DoubleTr=-1;
|
|
MoverParameters->PantFront(true);
|
|
MoverParameters->PantRear(true);
|
|
}
|
|
}
|
|
else //Ra: tu wczytywanie modelu ładunku jest w porządku
|
|
mdLoad=TModelsManager::GetModel(asLoadName.c_str(),true); //ladunek
|
|
Global::asCurrentTexturePath=AnsiString(szTexturePath); //z powrotem defaultowa sciezka do tekstur
|
|
while (!Parser->EndOfFile && str!=AnsiString("endmodels"))
|
|
{
|
|
str=Parser->GetNextSymbol().LowerCase();
|
|
if (str==AnsiString("animations:"))
|
|
{//Ra: ustawienie ilości poszczególnych animacji - musi być jako pierwsze, inaczej ilości będą domyślne
|
|
if (!pAnimations)
|
|
{//jeśli nie ma jeszcze tabeli animacji, można odczytać nowe ilości
|
|
int co=0,ile;
|
|
iAnimations=0;
|
|
do
|
|
{//kolejne liczby to ilość animacj, -1 to znacznik końca
|
|
ile=Parser->GetNextSymbol().ToIntDef(-1); //ilość danego typu animacji
|
|
//if (co==ANIM_PANTS)
|
|
// if (!Global::bLoadTraction)
|
|
// if (!DebugModeFlag) //w debugmode pantografy mają "niby działać"
|
|
// ile=0; //wyłączenie animacji pantografów
|
|
if (co<ANIM_TYPES)
|
|
if (ile>=0)
|
|
{iAnimType[co]=ile; //zapamiętanie
|
|
iAnimations+=ile; //ogólna ilość animacji
|
|
}
|
|
++co;
|
|
} while (ile>=0); //-1 to znacznik końca
|
|
while (co<ANIM_TYPES) iAnimType[co++]=0; //zerowanie pozostałych
|
|
str=Parser->GetNextSymbol().LowerCase();
|
|
}
|
|
//WriteLog("Total animations: "+AnsiString(iAnimations));
|
|
}
|
|
if (!pAnimations)
|
|
{//Ra: tworzenie tabeli animacji, jeśli jeszcze nie było
|
|
if (!iAnimations) //jeśli nie podano jawnie, ile ma być animacji
|
|
iAnimations=28; //tyle było kiedyś w każdym pojeździe (2 wiązary wypadły)
|
|
/* //pojazd może mieć pantograf do innych celów niż napęd
|
|
if (MoverParameters->EnginePowerSource.SourceType!=CurrentCollector)
|
|
{//nie będzie pantografów, to się trochę uprości
|
|
iAnimations-=iAnimType[ANIM_PANTS]; //domyślnie były 2 pantografy
|
|
iAnimType[ANIM_PANTS]=0;
|
|
}
|
|
*/
|
|
pAnimations=new TAnim[iAnimations];
|
|
int i,j,k=0,sm=0;
|
|
for (j=0;j<ANIM_TYPES;++j)
|
|
for (i=0;i<iAnimType[j];++i)
|
|
{
|
|
if (j==ANIM_PANTS) //zliczamy poprzednie animacje
|
|
if (!pants)
|
|
if (iAnimType[ANIM_PANTS]) //o ile jakieś pantografy są (a domyślnie są)
|
|
pants=pAnimations+k; //zapamiętanie na potrzeby wyszukania submodeli
|
|
pAnimations[k].iShift=sm; //przesunięcie do przydzielenia wskaźnika
|
|
sm+=pAnimations[k++].TypeSet(j); //ustawienie typu animacji i zliczanie tablicowanych submodeli
|
|
}
|
|
if (sm) //o ile są bardziej złożone animacje
|
|
{pAnimated=new TSubModel*[sm]; //tabela na animowane submodele
|
|
for (k=0;k<iAnimations;++k)
|
|
pAnimations[k].smElement=pAnimated+pAnimations[k].iShift; //przydzielenie wskaźnika do tabelki
|
|
}
|
|
}
|
|
if (str==AnsiString("lowpolyinterior:")) //ABu: wnetrze lowpoly
|
|
{
|
|
asModel=Parser->GetNextSymbol().LowerCase();
|
|
asModel=BaseDir+asModel; //McZapkie-200702 - dynamics maja swoje modele w dynamic/basedir
|
|
Global::asCurrentTexturePath=BaseDir; //biezaca sciezka do tekstur to dynamic/...
|
|
mdLowPolyInt=TModelsManager::GetModel(asModel.c_str(),true);
|
|
//Global::asCurrentTexturePath=AnsiString(szTexturePath); //kiedyś uproszczone wnętrze mieszało tekstury nieba
|
|
}
|
|
if (str==AnsiString("brakemode:"))
|
|
{//Ra 15-01: gałka nastawy hamulca
|
|
asAnimName=Parser->GetNextSymbol().LowerCase();
|
|
smBrakeMode=mdModel->GetFromName(asAnimName.c_str());
|
|
//jeszcze wczytać kąty obrotu dla poszczególnych ustawień
|
|
}
|
|
if (str==AnsiString("loadmode:"))
|
|
{//Ra 15-01: gałka nastawy hamulca
|
|
asAnimName=Parser->GetNextSymbol().LowerCase();
|
|
smLoadMode=mdModel->GetFromName(asAnimName.c_str());
|
|
//jeszcze wczytać kąty obrotu dla poszczególnych ustawień
|
|
}
|
|
else if (str==AnsiString("animwheelprefix:"))
|
|
{//prefiks kręcących się kół
|
|
int i,j,k,m;
|
|
str=Parser->GetNextSymbol();
|
|
for (i=0;i<iAnimType[ANIM_WHEELS];++i) //liczba osi
|
|
{//McZapkie-050402: wyszukiwanie kol o nazwie str*
|
|
asAnimName=str+AnsiString(i+1);
|
|
pAnimations[i].smAnimated=mdModel->GetFromName(asAnimName.c_str()); //ustalenie submodelu
|
|
if (pAnimations[i].smAnimated)
|
|
{//++iAnimatedAxles;
|
|
pAnimations[i].smAnimated->WillBeAnimated(); //wyłączenie optymalizacji transformu
|
|
pAnimations[i].yUpdate=UpdateAxle; //animacja osi
|
|
pAnimations[i].fMaxDist=50*MoverParameters->WheelDiameter; //nie kręcić w większej odległości
|
|
pAnimations[i].fMaxDist*=pAnimations[i].fMaxDist*MoverParameters->WheelDiameter; //50m do kwadratu, a średnica do trzeciej
|
|
pAnimations[i].fMaxDist*=Global::fDistanceFactor; //współczynnik przeliczeniowy jakości ekranu
|
|
}
|
|
}
|
|
//Ra: ustawianie indeksów osi
|
|
for (i=0;i<iAnimType[ANIM_WHEELS];++i) //ilość osi (zabezpieczenie przed błędami w CHK)
|
|
pAnimations[i].dWheelAngle=dWheelAngle+1; //domyślnie wskaźnik na napędzające
|
|
i=0; j=1; k=0; m=0; //numer osi; kolejny znak; ile osi danego typu; która średnica
|
|
if ((MoverParameters->WheelDiameterL!=MoverParameters->WheelDiameter)||(MoverParameters->WheelDiameterT!=MoverParameters->WheelDiameter))
|
|
{//obsługa różnych średnic, o ile występują
|
|
while ((i<iAnimType[ANIM_WHEELS])&&(j<=MoverParameters->AxleArangement.Length()))
|
|
{//wersja ze wskaźnikami jest bardziej elastyczna na nietypowe układy
|
|
if ((k>='A')&&(k<='J')) //10 chyba maksimum?
|
|
{pAnimations[i++].dWheelAngle=dWheelAngle+1; //obrót osi napędzających
|
|
--k; //następna będzie albo taka sama, albo bierzemy kolejny znak
|
|
m=2; //następujące toczne będą miały inną średnicę
|
|
}
|
|
else if ((k>='1')&&(k<='9'))
|
|
{pAnimations[i++].dWheelAngle=dWheelAngle+m; //obrót osi tocznych
|
|
--k; //następna będzie albo taka sama, albo bierzemy kolejny znak
|
|
}
|
|
else
|
|
k=MoverParameters->AxleArangement[j++]; //pobranie kolejnego znaku
|
|
}
|
|
}
|
|
}
|
|
//else if (str==AnsiString("animrodprefix:")) //prefiks wiazarow dwoch
|
|
// {
|
|
// str= Parser->GetNextSymbol();
|
|
// for (int i=1; i<=2; i++)
|
|
// {//McZapkie-050402: wyszukiwanie max 2 wiazarow o nazwie str*
|
|
// asAnimName=str+i;
|
|
// smWiazary[i-1]=mdModel->GetFromName(asAnimName.c_str());
|
|
// smWiazary[i-1]->WillBeAnimated();
|
|
// }
|
|
// }
|
|
else if (str==AnsiString("animpantprefix:"))
|
|
{//Ra: pantografy po nowemu mają literki i numerki
|
|
}
|
|
//Pantografy - Winger 160204
|
|
if (str==AnsiString("animpantrd1prefix:"))
|
|
{//prefiks ramion dolnych 1
|
|
str=Parser->GetNextSymbol();
|
|
float4x4 m; //macierz do wyliczenia pozycji i wektora ruchu pantografu
|
|
TSubModel *sm;
|
|
if (pants)
|
|
for (int i=0;i<iAnimType[ANIM_PANTS];i++)
|
|
{//Winger 160204: wyszukiwanie max 2 patykow o nazwie str*
|
|
asAnimName=str+AnsiString(i+1);
|
|
sm=mdModel->GetFromName(asAnimName.c_str());
|
|
pants[i].smElement[0]=sm; //jak NULL, to nie będzie animowany
|
|
if (sm)
|
|
{//w EP09 wywalało się tu z powodu NULL
|
|
sm->WillBeAnimated();
|
|
sm->ParentMatrix(&m); //pobranie macierzy transformacji
|
|
//m(3)[1]=m[3][1]+0.054; //w górę o wysokość ślizgu (na razie tak)
|
|
if ((mdModel->Flags()&0x8000)==0) //jeśli wczytano z T3D
|
|
m.InitialRotate(); //może być potrzebny dodatkowy obrót, jeśli wczytano z T3D, tzn. przed wykonaniem Init()
|
|
pants[i].fParamPants->vPos.z=m[3][0]; //przesunięcie w bok (asymetria)
|
|
pants[i].fParamPants->vPos.y=m[3][1]; //przesunięcie w górę odczytane z modelu
|
|
if ((sm=pants[i].smElement[0]->ChildGet())!=NULL)
|
|
{//jeśli ma potomny, można policzyć długość (odległość potomnego od osi obrotu)
|
|
m=float4x4(*sm->GetMatrix()); //wystarczyłby wskaźnik, nie trzeba kopiować
|
|
//może trzeba: pobrać macierz dolnego ramienia, wyzerować przesunięcie, przemnożyć przez macierz górnego
|
|
pants[i].fParamPants->fHoriz=-fabs(m[3][1]);
|
|
pants[i].fParamPants->fLenL1=hypot(m[3][1],m[3][2]); //po osi OX nie potrzeba
|
|
pants[i].fParamPants->fAngleL0=atan2(fabs(m[3][2]),fabs(m[3][1]));
|
|
//if (pants[i].fParamPants->fAngleL0<M_PI_2) pants[i].fParamPants->fAngleL0+=M_PI; //gdyby w odwrotną stronę wyszło
|
|
//if ((pants[i].fParamPants->fAngleL0<0.03)||(pants[i].fParamPants->fAngleL0>0.09)) //normalnie ok. 0.05
|
|
// pants[i].fParamPants->fAngleL0=pants[i].fParamPants->fAngleL;
|
|
pants[i].fParamPants->fAngleL=pants[i].fParamPants->fAngleL0; //początkowy kąt dolnego ramienia
|
|
if ((sm=sm->ChildGet())!=NULL)
|
|
{//jeśli dalej jest ślizg, można policzyć długość górnego ramienia
|
|
m=float4x4(*sm->GetMatrix()); //wystarczyłby wskaźnik, nie trzeba kopiować
|
|
//trzeba by uwzględnić macierz dolnego ramienia, żeby uzyskać kąt do poziomu...
|
|
pants[i].fParamPants->fHoriz+=fabs(m(3)[1]); //różnica długości rzutów ramion na płaszczyznę podstawy (jedna dodatnia, druga ujemna)
|
|
pants[i].fParamPants->fLenU1=hypot(m[3][1],m[3][2]); //po osi OX nie potrzeba
|
|
//pants[i].fParamPants->pantu=acos((1.22*cos(pants[i].fParamPants->fAngleL)+0.535)/1.755); //górne ramię
|
|
//pants[i].fParamPants->fAngleU0=acos((1.176289*cos(pants[i].fParamPants->fAngleL)+0.54555075)/1.724482197); //górne ramię
|
|
pants[i].fParamPants->fAngleU0=atan2(fabs(m[3][2]),fabs(m[3][1])); //początkowy kąt górnego ramienia, odczytany z modelu
|
|
//if (pants[i].fParamPants->fAngleU0<M_PI_2) pants[i].fParamPants->fAngleU0+=M_PI; //gdyby w odwrotną stronę wyszło
|
|
//if (pants[i].fParamPants->fAngleU0<0)
|
|
// pants[i].fParamPants->fAngleU0=-pants[i].fParamPants->fAngleU0;
|
|
//if ((pants[i].fParamPants->fAngleU0<0.00)||(pants[i].fParamPants->fAngleU0>0.09)) //normalnie ok. 0.07
|
|
// pants[i].fParamPants->fAngleU0=acos((pants[i].fParamPants->fLenL1*cos(pants[i].fParamPants->fAngleL)+pants[i].fParamPants->fHoriz)/pants[i].fParamPants->fLenU1);
|
|
pants[i].fParamPants->fAngleU=pants[i].fParamPants->fAngleU0; //początkowy kąt
|
|
//Ra: ze względu na to, że niektóre modele pantografów są zrąbane, ich mierzenie ma obecnie ograniczony sens
|
|
sm->ParentMatrix(&m); //pobranie macierzy transformacji pivota ślizgu względem wstawienia pojazdu
|
|
if ((mdModel->Flags()&0x8000)==0) //jeśli wczytano z T3D
|
|
m.InitialRotate(); //może być potrzebny dodatkowy obrót, jeśli wczytano z T3D, tzn. przed wykonaniem Init()
|
|
float det=Det(m);
|
|
if (fabs(det-1.0)<0.001) //dopuszczamy 1 promil błędu na skalowaniu ślizgu
|
|
{//skalowanie jest w normie, można pobrać wymiary z modelu
|
|
pants[i].fParamPants->fHeight=sm->MaxY(m); //przeliczenie maksimum wysokości wierzchołków względem macierzy
|
|
pants[i].fParamPants->fHeight-=m[3][1]; //odjęcie wysokości pivota ślizgu
|
|
pants[i].fParamPants->vPos.x=m[3][2]; //przy okazji odczytać z modelu pozycję w długości
|
|
//ErrorLog("Model OK: "+asModel+", height="+pants[i].fParamPants->fHeight);
|
|
//ErrorLog("Model OK: "+asModel+", pos.x="+pants[i].fParamPants->vPos.x);
|
|
}
|
|
else
|
|
{//gdy ktoś przesadził ze skalowaniem
|
|
pants[i].fParamPants->fHeight=0.0; //niech będzie odczyt z pantfactors:
|
|
ErrorLog("Bad model: "+asModel+", scale of "+AnsiString(sm->pName)+" is "+AnsiString(100.0*det)+"%");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
ErrorLog("Bad model: "+asFileName+" - missed submodel "+asAnimName); //brak ramienia
|
|
}
|
|
}
|
|
else if (str==AnsiString("animpantrd2prefix:"))
|
|
{//prefiks ramion dolnych 2
|
|
str=Parser->GetNextSymbol();
|
|
float4x4 m; //macierz do wyliczenia pozycji i wektora ruchu pantografu
|
|
TSubModel *sm;
|
|
if (pants)
|
|
for (int i=0;i<iAnimType[ANIM_PANTS];i++)
|
|
{//Winger 160204: wyszukiwanie max 2 patykow o nazwie str*
|
|
asAnimName=str+AnsiString(i+1);
|
|
sm=mdModel->GetFromName(asAnimName.c_str());
|
|
pants[i].smElement[1]=sm; //jak NULL, to nie będzie animowany
|
|
if (sm)
|
|
{//w EP09 wywalało się tu z powodu NULL
|
|
sm->WillBeAnimated();
|
|
if (pants[i].fParamPants->vPos.y==0.0)
|
|
{//jeśli pierwsze ramię nie ustawiło tej wartości, próbować drugim
|
|
//!!!! docelowo zrobić niezależną animację ramion z każdej strony
|
|
m=float4x4(*sm->GetMatrix()); //skopiowanie, bo będziemy mnożyć
|
|
m(3)[1]=m[3][1]+0.054; //w górę o wysokość ślizgu (na razie tak)
|
|
while (sm->Parent)
|
|
{
|
|
if (sm->Parent->GetMatrix())
|
|
m=*sm->Parent->GetMatrix()*m;
|
|
sm=sm->Parent;
|
|
}
|
|
pants[i].fParamPants->vPos.z=m[3][0]; //przesunięcie w bok (asymetria)
|
|
pants[i].fParamPants->vPos.y=m[3][1]; //przesunięcie w górę odczytane z modelu
|
|
}
|
|
}
|
|
else
|
|
ErrorLog("Bad model: "+asFileName+" - missed submodel "+asAnimName); //brak ramienia
|
|
}
|
|
}
|
|
else if (str==AnsiString("animpantrg1prefix:"))
|
|
{//prefiks ramion górnych 1
|
|
str=Parser->GetNextSymbol();
|
|
if (pants)
|
|
for (int i=0;i<iAnimType[ANIM_PANTS];i++)
|
|
{//Winger 160204: wyszukiwanie max 2 patykow o nazwie str*
|
|
asAnimName=str+AnsiString(i+1);
|
|
pants[i].smElement[2]=mdModel->GetFromName(asAnimName.c_str());
|
|
pants[i].smElement[2]->WillBeAnimated();
|
|
}
|
|
}
|
|
else
|
|
if (str==AnsiString("animpantrg2prefix:"))
|
|
{//prefiks ramion górnych 2
|
|
str=Parser->GetNextSymbol();
|
|
if (pants)
|
|
for (int i=0;i<iAnimType[ANIM_PANTS];i++)
|
|
{//Winger 160204: wyszukiwanie max 2 patykow o nazwie str*
|
|
asAnimName=str+AnsiString(i+1);
|
|
pants[i].smElement[3]=mdModel->GetFromName(asAnimName.c_str());
|
|
pants[i].smElement[3]->WillBeAnimated();
|
|
}
|
|
}
|
|
else if (str==AnsiString("animpantslprefix:"))
|
|
{//prefiks ślizgaczy
|
|
str=Parser->GetNextSymbol();
|
|
if (pants)
|
|
for (int i=0;i<iAnimType[ANIM_PANTS];i++)
|
|
{//Winger 160204: wyszukiwanie max 2 patykow o nazwie str*
|
|
asAnimName=str+AnsiString(i+1);
|
|
pants[i].smElement[4]=mdModel->GetFromName(asAnimName.c_str());
|
|
pants[i].smElement[4]->WillBeAnimated();
|
|
pants[i].yUpdate=UpdatePant;
|
|
pants[i].fMaxDist=300*300; //nie podnosić w większej odległości
|
|
pants[i].iNumber=i;
|
|
}
|
|
}
|
|
else if (str==AnsiString("pantfactors:"))
|
|
{//Winger 010304: parametry pantografow
|
|
double pant1x=Parser->GetNextSymbol().ToDouble();
|
|
double pant2x=Parser->GetNextSymbol().ToDouble();
|
|
double pant1h=Parser->GetNextSymbol().ToDouble(); //wysokość pierwszego ślizgu
|
|
double pant2h=Parser->GetNextSymbol().ToDouble(); //wysokość drugiego ślizgu
|
|
if (pant1h>0.5) pant1h=pant2h; //tu może być zbyt duża wartość
|
|
if ((pant1x<0)&&(pant2x>0)) //pierwsza powinna być dodatnia, a druga ujemna
|
|
{pant1x=-pant1x; pant2x=-pant2x;}
|
|
if (pants)
|
|
for (int i=0;i<iAnimType[ANIM_PANTS];++i)
|
|
{//przepisanie współczynników do pantografów (na razie nie będzie lepiej)
|
|
pants[i].fParamPants->fAngleL=pants[i].fParamPants->fAngleL0; //początkowy kąt dolnego ramienia
|
|
pants[i].fParamPants->fAngleU=pants[i].fParamPants->fAngleU0; //początkowy kąt
|
|
//pants[i].fParamPants->PantWys=1.22*sin(pants[i].fParamPants->fAngleL)+1.755*sin(pants[i].fParamPants->fAngleU); //wysokość początkowa
|
|
//pants[i].fParamPants->PantWys=1.176289*sin(pants[i].fParamPants->fAngleL)+1.724482197*sin(pants[i].fParamPants->fAngleU); //wysokość początkowa
|
|
if (pants[i].fParamPants->fHeight==0.0) //gdy jest nieprawdopodobna wartość (np. nie znaleziony ślizg)
|
|
{//gdy pomiary modelu nie udały się, odczyt podanych parametrów z MMD
|
|
pants[i].fParamPants->vPos.x=(i&1)?pant2x:pant1x;
|
|
pants[i].fParamPants->fHeight=(i&1)?pant2h:pant1h; //wysokość ślizgu jest zapisana w MMD
|
|
}
|
|
pants[i].fParamPants->PantWys=pants[i].fParamPants->fLenL1*sin(pants[i].fParamPants->fAngleL)+pants[i].fParamPants->fLenU1*sin(pants[i].fParamPants->fAngleU)+pants[i].fParamPants->fHeight; //wysokość początkowa
|
|
//pants[i].fParamPants->vPos.y=panty-panth-pants[i].fParamPants->PantWys; //np. 4.429-0.097=4.332=~4.335
|
|
//pants[i].fParamPants->vPos.z=0; //niezerowe dla pantografów asymetrycznych
|
|
pants[i].fParamPants->PantTraction=pants[i].fParamPants->PantWys;
|
|
pants[i].fParamPants->fWidth=0.5*MoverParameters->EnginePowerSource.CollectorParameters.CSW; //połowa szerokości ślizgu; jest w "Power: CSW="
|
|
}
|
|
}
|
|
else if (str==AnsiString("animpistonprefix:"))
|
|
{//prefiks tłoczysk - na razie używamy modeli pantografów
|
|
str=Parser->GetNextSymbol();
|
|
for (int i=1;i<=2;i++)
|
|
{
|
|
//asAnimName=str+i;
|
|
//smPatykird1[i-1]=mdModel->GetFromName(asAnimName.c_str());
|
|
//smPatykird1[i-1]->WillBeAnimated();
|
|
}
|
|
}
|
|
else if (str==AnsiString("animconrodprefix:"))
|
|
{//prefiks korbowodów - na razie używamy modeli pantografów
|
|
str=Parser->GetNextSymbol();
|
|
for (int i=1;i<=2;i++)
|
|
{
|
|
//asAnimName=str+i;
|
|
//smPatykirg1[i-1]=mdModel->GetFromName(asAnimName.c_str());
|
|
//smPatykirg1[i-1]->WillBeAnimated();
|
|
}
|
|
}
|
|
else if (str==AnsiString("pistonfactors:"))
|
|
{//Ra: parametry silnika parowego (tłoka)
|
|
/* //Ra: tymczasowo wyłączone ze względu na porządkowanie animacji pantografów
|
|
pant1x=Parser->GetNextSymbol().ToDouble(); //kąt przesunięcia dla pierwszego tłoka
|
|
pant2x=Parser->GetNextSymbol().ToDouble(); //kąt przesunięcia dla drugiego tłoka
|
|
panty=Parser->GetNextSymbol().ToDouble(); //długość korby (r)
|
|
panth=Parser->GetNextSymbol().ToDouble(); //długoś korbowodu (k)
|
|
*/
|
|
MoverParameters->EnginePowerSource.PowerType=SteamPower; //Ra: po chamsku, ale z CHK nie działa
|
|
}
|
|
else if (str==AnsiString("animreturnprefix:"))
|
|
{//prefiks drążka mimośrodowego - na razie używamy modeli pantografów
|
|
str=Parser->GetNextSymbol();
|
|
for (int i=1;i<=2;i++)
|
|
{
|
|
//asAnimName=str+i;
|
|
//smPatykird2[i-1]=mdModel->GetFromName(asAnimName.c_str());
|
|
//smPatykird2[i-1]->WillBeAnimated();
|
|
}
|
|
}
|
|
else if (str==AnsiString("animexplinkprefix:")) //animreturnprefix:
|
|
{//prefiks jarzma - na razie używamy modeli pantografów
|
|
str=Parser->GetNextSymbol();
|
|
for (int i=1;i<=2;i++)
|
|
{
|
|
//asAnimName=str+i;
|
|
//smPatykirg2[i-1]=mdModel->GetFromName(asAnimName.c_str());
|
|
//smPatykirg2[i-1]->WillBeAnimated();
|
|
}
|
|
}
|
|
else if (str==AnsiString("animpendulumprefix:"))
|
|
{//prefiks wahaczy
|
|
str=Parser->GetNextSymbol();
|
|
asAnimName="";
|
|
for (int i=1; i<=4; i++)
|
|
{//McZapkie-050402: wyszukiwanie max 4 wahaczy o nazwie str*
|
|
asAnimName=str+AnsiString(i);
|
|
smWahacze[i-1]=mdModel->GetFromName(asAnimName.c_str());
|
|
smWahacze[i-1]->WillBeAnimated();
|
|
}
|
|
str=Parser->GetNextSymbol().LowerCase();
|
|
if (str==AnsiString("pendulumamplitude:"))
|
|
fWahaczeAmp=Parser->GetNextSymbol().ToDouble();
|
|
}
|
|
else
|
|
if (str==AnsiString("engineer:"))
|
|
{//nazwa submodelu maszynisty
|
|
str=Parser->GetNextSymbol();
|
|
smMechanik0=mdModel->GetFromName(str.c_str());
|
|
if (!smMechanik0)
|
|
{//jak nie ma bez numerka, to może jest z numerkiem?
|
|
smMechanik0=mdModel->GetFromName(AnsiString(str+"1").c_str());
|
|
smMechanik1=mdModel->GetFromName(AnsiString(str+"2").c_str());
|
|
}
|
|
//aby dało się go obracać, musi mieć włączoną animację w T3D!
|
|
//if (!smMechanik1) //jeśli drugiego nie ma
|
|
// if (smMechanik0) //a jest pierwszy
|
|
// smMechanik0->WillBeAnimated(); //to będziemy go obracać
|
|
}
|
|
else if (str==AnsiString("animdoorprefix:"))
|
|
{//nazwa animowanych drzwi
|
|
int i,j,k,m;
|
|
str=Parser->GetNextSymbol();
|
|
for (i=0,j=0;i<ANIM_DOORS;++i)
|
|
j+=iAnimType[i]; //zliczanie wcześniejszych animacji
|
|
for (i=0;i<iAnimType[ANIM_DOORS];++i) //liczba drzwi
|
|
{//NBMX wrzesien 2003: wyszukiwanie drzwi o nazwie str*
|
|
asAnimName=str+AnsiString(i+1);
|
|
pAnimations[i+j].smAnimated=mdModel->GetFromName(asAnimName.c_str()); //ustalenie submodelu
|
|
if (pAnimations[i+j].smAnimated)
|
|
{//++iAnimatedDoors;
|
|
pAnimations[i+j].smAnimated->WillBeAnimated(); //wyłączenie optymalizacji transformu
|
|
switch (MoverParameters->DoorOpenMethod)
|
|
{//od razu zapinamy potrzebny typ animacji
|
|
case 1: pAnimations[i+j].yUpdate=UpdateDoorTranslate; break;
|
|
case 2: pAnimations[i+j].yUpdate=UpdateDoorRotate; break;
|
|
case 3: pAnimations[i+j].yUpdate=UpdateDoorFold; break; //obrót 3 kolejnych submodeli
|
|
}
|
|
pAnimations[i+j].iNumber=i; //parzyste działają inaczej niż nieparzyste
|
|
pAnimations[i+j].fMaxDist=300*300; //drzwi to z daleka widać
|
|
pAnimations[i+j].fSpeed=random(150); //oryginalny koncept z DoorSpeedFactor
|
|
pAnimations[i+j].fSpeed=(pAnimations[i+j].fSpeed+100)/100;
|
|
//Ra: te współczynniki są bez sensu, bo modyfikują wektor przesunięcia
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (str==AnsiString("sounds:")) //dzwieki
|
|
while (!Parser->EndOfFile && str!=AnsiString("endsounds"))
|
|
{
|
|
str= Parser->GetNextSymbol().LowerCase();
|
|
if (str==AnsiString("wheel_clatter:")) //polozenia osi w/m srodka pojazdu
|
|
{
|
|
dSDist=Parser->GetNextSymbol().ToDouble();
|
|
for (int i=0; i<iAxles; i++)
|
|
{
|
|
str=Parser->GetNextSymbol();
|
|
dWheelsPosition[i]=str.ToDouble();
|
|
str= Parser->GetNextSymbol().LowerCase();
|
|
if (str!=AnsiString("end"))
|
|
rsStukot[i].Init(str.c_str(),dSDist,GetPosition().x,GetPosition().y+dWheelsPosition[i],GetPosition().z,true);
|
|
}
|
|
if (str!=AnsiString("end"))
|
|
str= Parser->GetNextSymbol();
|
|
}
|
|
else
|
|
if ((str==AnsiString("engine:")) && (MoverParameters->Power>0)) //plik z dzwiekiem silnika, mnozniki i ofsety amp. i czest.
|
|
{
|
|
str= Parser->GetNextSymbol();
|
|
rsSilnik.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true,true);
|
|
if (rsSilnik.GetWaveTime()==0)
|
|
ErrorLog("Missed sound: \""+str+"\" for "+asFileName);
|
|
if (MoverParameters->EngineType==DieselEngine)
|
|
rsSilnik.AM=Parser->GetNextSymbol().ToDouble()/(MoverParameters->Power+MoverParameters->nmax*60);
|
|
else if (MoverParameters->EngineType==DieselElectric)
|
|
rsSilnik.AM=Parser->GetNextSymbol().ToDouble()/(MoverParameters->Power*3);
|
|
else
|
|
rsSilnik.AM=Parser->GetNextSymbol().ToDouble()/(MoverParameters->Power+MoverParameters->nmax*60+MoverParameters->Power+MoverParameters->Power);
|
|
rsSilnik.AA=Parser->GetNextSymbol().ToDouble();
|
|
rsSilnik.FM=Parser->GetNextSymbol().ToDouble();//MoverParameters->nmax;
|
|
rsSilnik.FA=Parser->GetNextSymbol().ToDouble();
|
|
}
|
|
else
|
|
if (((str==AnsiString("ventilator:")) && ((MoverParameters->EngineType==ElectricSeriesMotor)||(MoverParameters->EngineType==ElectricInductionMotor)))) //plik z dzwiekiem wentylatora, mnozniki i ofsety amp. i czest.
|
|
{
|
|
str= Parser->GetNextSymbol();
|
|
rsWentylator.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true,true);
|
|
rsWentylator.AM=Parser->GetNextSymbol().ToDouble()/MoverParameters->RVentnmax;
|
|
rsWentylator.AA=Parser->GetNextSymbol().ToDouble();
|
|
rsWentylator.FM=Parser->GetNextSymbol().ToDouble()/MoverParameters->RVentnmax;
|
|
rsWentylator.FA=Parser->GetNextSymbol().ToDouble();
|
|
}
|
|
else
|
|
if ((str==AnsiString("transmission:")) && (MoverParameters->EngineType==ElectricSeriesMotor)) //plik z dzwiekiem, mnozniki i ofsety amp. i czest.
|
|
{
|
|
str= Parser->GetNextSymbol();
|
|
rsPrzekladnia.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true);
|
|
rsPrzekladnia.AM=0.029;
|
|
rsPrzekladnia.AA=0.1;
|
|
rsPrzekladnia.FM=0.005;
|
|
rsPrzekladnia.FA=1.0;
|
|
}
|
|
else
|
|
if (str==AnsiString("brake:")) //plik z piskiem hamulca, mnozniki i ofsety amplitudy.
|
|
{
|
|
str= Parser->GetNextSymbol();
|
|
rsPisk.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true);
|
|
rsPisk.AM=Parser->GetNextSymbol().ToDouble();
|
|
rsPisk.AA=Parser->GetNextSymbol().ToDouble()*(105-random(10))/100;
|
|
rsPisk.FM=1.0;
|
|
rsPisk.FA=0.0;
|
|
}
|
|
else
|
|
if (str==AnsiString("brakeacc:")) //plik z przyspieszaczem (upust po zlapaniu hamowania)
|
|
{
|
|
str= Parser->GetNextSymbol();
|
|
// sBrakeAcc.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true);
|
|
sBrakeAcc=TSoundsManager::GetFromName(str.c_str(),true);
|
|
bBrakeAcc=true;
|
|
// sBrakeAcc.AM=1.0;
|
|
// sBrakeAcc.AA=0.0;
|
|
// sBrakeAcc.FM=1.0;
|
|
// sBrakeAcc.FA=0.0;
|
|
}
|
|
else
|
|
if (str==AnsiString("unbrake:")) //plik z piskiem hamulca, mnozniki i ofsety amplitudy.
|
|
{
|
|
str= Parser->GetNextSymbol();
|
|
rsUnbrake.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true);
|
|
rsUnbrake.AM=1.0;
|
|
rsUnbrake.AA=0.0;
|
|
rsUnbrake.FM=1.0;
|
|
rsUnbrake.FA=0.0;
|
|
}
|
|
else
|
|
if (str==AnsiString("derail:")) //dzwiek przy wykolejeniu
|
|
{
|
|
str= Parser->GetNextSymbol();
|
|
rsDerailment.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true);
|
|
rsDerailment.AM=1.0;
|
|
rsDerailment.AA=0.0;
|
|
rsDerailment.FM=1.0;
|
|
rsDerailment.FA=0.0;
|
|
}
|
|
else
|
|
if (str==AnsiString("dieselinc:")) //dzwiek przy wlazeniu na obroty woodwarda
|
|
{
|
|
str= Parser->GetNextSymbol();
|
|
rsDiesielInc.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true);
|
|
rsDiesielInc.AM=1.0;
|
|
rsDiesielInc.AA=0.0;
|
|
rsDiesielInc.FM=1.0;
|
|
rsDiesielInc.FA=0.0;
|
|
}
|
|
else
|
|
if (str==AnsiString("curve:"))
|
|
{
|
|
str= Parser->GetNextSymbol();
|
|
rscurve.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true);
|
|
rscurve.AM=1.0;
|
|
rscurve.AA=0.0;
|
|
rscurve.FM=1.0;
|
|
rscurve.FA=0.0;
|
|
}
|
|
else
|
|
if (str==AnsiString("horn1:")) //pliki z trabieniem
|
|
{
|
|
sHorn1.Load(Parser,GetPosition());
|
|
}
|
|
if (str==AnsiString("horn2:")) //pliki z trabieniem wysokoton.
|
|
{
|
|
sHorn2.Load(Parser,GetPosition());
|
|
if (iHornWarning) iHornWarning=2; //numer syreny do użycia po otrzymaniu sygnału do jazdy
|
|
}
|
|
if (str==AnsiString("departuresignal:")) //pliki z sygnalem odjazdu
|
|
{
|
|
sDepartureSignal.Load(Parser,GetPosition());
|
|
}
|
|
if (str==AnsiString("pantographup:")) //pliki dzwiekow pantografow
|
|
{
|
|
str=Parser->GetNextSymbol();
|
|
sPantUp.Init(str.c_str(),50,GetPosition().x,GetPosition().y,GetPosition().z,true);
|
|
sPantUp.AM=50000;
|
|
sPantUp.AA=-1*(105-random(10))/100;
|
|
sPantUp.FM=1.0;
|
|
sPantUp.FA=0.0;
|
|
}
|
|
if (str==AnsiString("pantographdown:")) //pliki dzwiekow pantografow
|
|
{
|
|
str= Parser->GetNextSymbol();
|
|
sPantDown.Init(str.c_str(),50,GetPosition().x,GetPosition().y,GetPosition().z,true);
|
|
sPantDown.AM=50000;
|
|
sPantDown.AA=-1*(105-random(10))/100;
|
|
sPantDown.FM=1.0;
|
|
sPantDown.FA=0.0;
|
|
}
|
|
else if (str==AnsiString("compressor:")) //pliki ze sprezarka
|
|
{
|
|
sCompressor.Load(Parser,GetPosition());
|
|
}
|
|
else if (str==AnsiString("converter:")) //pliki z przetwornica
|
|
{
|
|
//if (MoverParameters->EngineType==DieselElectric) //będzie modulowany?
|
|
sConverter.Load(Parser,GetPosition());
|
|
}
|
|
else if (str==AnsiString("turbo:")) //pliki z turbogeneratorem
|
|
{
|
|
sTurbo.Load(Parser,GetPosition());
|
|
}
|
|
else if (str==AnsiString("small-compressor:")) //pliki z przetwornica
|
|
{
|
|
sSmallCompressor.Load(Parser,GetPosition());
|
|
}
|
|
else if (str==AnsiString("dooropen:"))
|
|
{
|
|
str=Parser->GetNextSymbol();
|
|
rsDoorOpen.Init(str.c_str(),50,GetPosition().x,GetPosition().y,GetPosition().z,true);
|
|
rsDoorOpen.AM=50000;
|
|
rsDoorOpen.AA=-1*(105-random(10))/100;
|
|
rsDoorOpen.FM=1.0;
|
|
rsDoorOpen.FA=0.0;
|
|
}
|
|
else if (str==AnsiString("doorclose:"))
|
|
{
|
|
str=Parser->GetNextSymbol();
|
|
rsDoorClose.Init(str.c_str(),50,GetPosition().x,GetPosition().y,GetPosition().z,true);
|
|
rsDoorClose.AM=50000;
|
|
rsDoorClose.AA=-1*(105-random(10))/100;
|
|
rsDoorClose.FM=1.0;
|
|
rsDoorClose.FA=0.0;
|
|
}
|
|
}
|
|
else
|
|
if (str==AnsiString("internaldata:")) //dalej nie czytaj
|
|
{while (!Parser->EndOfFile)
|
|
{//zbieranie informacji o kabinach
|
|
str=Parser->GetNextSymbol().LowerCase();
|
|
if (str=="cab0model:")
|
|
{str=Parser->GetNextSymbol();
|
|
if (str!="none") iCabs=2;
|
|
}
|
|
else if (str=="cab1model:")
|
|
{str=Parser->GetNextSymbol();
|
|
if (str!="none") iCabs=1;
|
|
}
|
|
else if (str=="cab2model:")
|
|
{str=Parser->GetNextSymbol();
|
|
if (str!="none") iCabs=4;
|
|
}
|
|
}
|
|
Stop_InternalData=true;
|
|
}
|
|
}
|
|
//ABu 050205 - tego wczesniej nie bylo i uciekala pamiec:
|
|
delete Parser;
|
|
if (mdModel) mdModel->Init(); //obrócenie modelu oraz optymalizacja, również zapisanie binarnego
|
|
if (mdLoad) mdLoad->Init();
|
|
if (mdPrzedsionek) mdPrzedsionek->Init();
|
|
if (mdLowPolyInt) mdLowPolyInt->Init();
|
|
//sHorn2.CopyIfEmpty(sHorn1); //żeby jednak trąbił też drugim
|
|
Global::asCurrentTexturePath=AnsiString(szTexturePath); //kiedyś uproszczone wnętrze mieszało tekstury nieba
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TDynamicObject::RadioStop()
|
|
{//zatrzymanie pojazdu
|
|
if (Mechanik) //o ile ktoś go prowadzi
|
|
if (MoverParameters->SecuritySystem.RadioStop) //jeśli pojazd ma RadioStop i jest on aktywny
|
|
Mechanik->PutCommand("Emergency_brake",1.0,1.0,&vPosition,stopRadio);
|
|
};
|
|
|
|
void __fastcall TDynamicObject::RaLightsSet(int head,int rear)
|
|
{//zapalenie świateł z przodu i z tyłu, zależne od kierunku pojazdu
|
|
if (!MoverParameters) return; //może tego nie być na początku
|
|
if (rear==2+32+64)
|
|
{//jeśli koniec pociągu, to trzeba ustalić, czy jest tam czynna lokomotywa
|
|
//EN57 może nie mieć końcówek od środka członu
|
|
if (MoverParameters->Power>1.0) //jeśli ma moc napędową
|
|
if (!MoverParameters->ActiveDir) //jeśli nie ma ustawionego kierunku
|
|
{//jeśli ma zarówno światła jak i końcówki, ustalić, czy jest w stanie aktywnym
|
|
//np. lokomotywa na zimno będzie mieć końcówki a nie światła
|
|
rear=64; //tablice blaszane
|
|
//trzeba to uzależnić od "załączenia baterii" w pojeździe
|
|
}
|
|
if (rear==2+32+64) //jeśli nadal obydwie możliwości
|
|
if (iInventory&(iDirection?0x2A:0x15)) //czy ma jakieś światła czerowone od danej strony
|
|
rear=2+32; //dwa światła czerwone
|
|
else
|
|
rear=64; //tablice blaszane
|
|
}
|
|
if (iDirection) //w zależności od kierunku pojazdu w składzie
|
|
{//jesli pojazd stoi sprzęgiem 0 w stronę czoła
|
|
if (head>=0) iLights[0]=head;
|
|
if (rear>=0) iLights[1]=rear;
|
|
}
|
|
else
|
|
{//jak jest odwrócony w składzie (-1), to zapalamy odwrotnie
|
|
if (head>=0) iLights[1]=head;
|
|
if (rear>=0) iLights[0]=rear;
|
|
}
|
|
};
|
|
|
|
int __fastcall TDynamicObject::DirectionSet(int d)
|
|
{//ustawienie kierunku w składzie (wykonuje AI)
|
|
iDirection=d>0?1:0; //d:1=zgodny,-1=przeciwny; iDirection:1=zgodny,0=przeciwny;
|
|
CouplCounter=20; //żeby normalnie skanować kolizje, to musi ruszyć z miejsca
|
|
if (MyTrack)
|
|
{//podczas wczytywania wstawiane jest AI, ale może jeszcze nie być toru
|
|
//AI ustawi kierunek ponownie po uruchomieniu silnika
|
|
if (iDirection) //jeśli w kierunku Coupler 0
|
|
{if (MoverParameters->Couplers[0].CouplingFlag==ctrain_virtual) //brak pojazdu podpiętego?
|
|
ABuScanObjects(1,300); //szukanie czegoś do podłączenia
|
|
}
|
|
else
|
|
if (MoverParameters->Couplers[1].CouplingFlag==ctrain_virtual) //brak pojazdu podpiętego?
|
|
ABuScanObjects(-1,300);
|
|
}
|
|
return 1-(iDirection?NextConnectedNo:PrevConnectedNo); //informacja o położeniu następnego
|
|
};
|
|
|
|
TDynamicObject* __fastcall TDynamicObject::PrevAny()
|
|
{//wskaźnik na poprzedni, nawet wirtualny
|
|
return iDirection?PrevConnected:NextConnected;
|
|
};
|
|
TDynamicObject* __fastcall TDynamicObject::Prev()
|
|
{
|
|
if (MoverParameters->Couplers[iDirection^1].CouplingFlag)
|
|
return iDirection?PrevConnected:NextConnected;
|
|
return NULL; //gdy sprzęg wirtualny, to jakby nic nie było
|
|
};
|
|
TDynamicObject* __fastcall TDynamicObject::Next()
|
|
{
|
|
if (MoverParameters->Couplers[iDirection].CouplingFlag)
|
|
return iDirection?NextConnected:PrevConnected;
|
|
return NULL; //gdy sprzęg wirtualny, to jakby nic nie było
|
|
};
|
|
TDynamicObject* __fastcall TDynamicObject::NextC(int C)
|
|
{
|
|
if (MoverParameters->Couplers[iDirection].CouplingFlag&C)
|
|
return iDirection?NextConnected:PrevConnected;
|
|
return NULL; //gdy sprzęg inny, to jakby nic nie było
|
|
};
|
|
double __fastcall TDynamicObject::NextDistance(double d)
|
|
{//ustalenie odległości do następnego pojazdu, potrzebne do wstecznego skanowania
|
|
if (!MoverParameters->Couplers[iDirection].Connected)
|
|
return d; //jeśli nic nie ma, zwrócenie domyślnej wartości
|
|
if ((d<=0.0)||(MoverParameters->Couplers[iDirection].CoupleDist<d))
|
|
return MoverParameters->Couplers[iDirection].Dist;
|
|
else
|
|
return d;
|
|
};
|
|
|
|
TDynamicObject* __fastcall TDynamicObject::Neightbour(int &dir)
|
|
{//ustalenie następnego (1) albo poprzedniego (0) w składzie bez względu na prawidłowość iDirection
|
|
int d=dir; //zapamiętanie kierunku
|
|
dir=1-(dir?NextConnectedNo:PrevConnectedNo); //nowa wartość
|
|
return (d?(MoverParameters->Couplers[1].CouplingFlag?NextConnected:NULL):(MoverParameters->Couplers[0].CouplingFlag?PrevConnected:NULL));
|
|
};
|
|
|
|
void __fastcall TDynamicObject::CoupleDist()
|
|
{//obliczenie odległości sprzęgów
|
|
if (MyTrack?(MyTrack->iCategoryFlag&1):true) //jeśli nie ma przypisanego toru, to liczyć jak dla kolei
|
|
{//jeśli jedzie po szynach (również unimog), liczenie kul wystarczy
|
|
MoverParameters->SetCoupleDist();
|
|
}
|
|
else
|
|
{//na drodze trzeba uwzględnić wektory ruchu
|
|
double d0=MoverParameters->Couplers[0].CoupleDist;
|
|
//double d1=MoverParameters->Couplers[1].CoupleDist; //sprzęg z tyłu samochodu można olać, dopóki nie jeździ na wstecznym
|
|
vector3 p1,p2;
|
|
double d,w; //dopuszczalny dystans w poprzek
|
|
MoverParameters->SetCoupleDist(); //liczenie standardowe
|
|
if (MoverParameters->Couplers[0].Connected) //jeśli cokolwiek podłączone
|
|
if (MoverParameters->Couplers[0].CouplingFlag==0) //jeśli wirtualny
|
|
if (MoverParameters->Couplers[0].CoupleDist<300.0) //i mniej niż 300m
|
|
{//przez MoverParameters->Couplers[0].Connected nie da się dostać do DynObj, stąd prowizorka
|
|
//WriteLog("Collision of "+AnsiString(MoverParameters->Couplers[0].CoupleDist)+"m detected by "+asName+":0.");
|
|
w=0.5*(MoverParameters->Couplers[0].Connected->Dim.W+MoverParameters->Dim.W); //minimalna odległość minięcia
|
|
d=-DotProduct(vLeft,vCoulpler[0]); //odległość prostej ruchu od początku układu współrzędnych
|
|
d=fabs(DotProduct(vLeft,((TMoverParameters*)(MoverParameters->Couplers[0].Connected))->vCoulpler[MoverParameters->Couplers[0].ConnectedNr])+d);
|
|
//WriteLog("Distance "+AnsiString(d)+"m from "+asName+":0.");
|
|
if (d>w)
|
|
MoverParameters->Couplers[0].CoupleDist=(d0<10?50:d0); //przywrócenie poprzedniej
|
|
}
|
|
if (MoverParameters->Couplers[1].Connected) //jeśli cokolwiek podłączone
|
|
if (MoverParameters->Couplers[1].CouplingFlag==0) //jeśli wirtualny
|
|
if (MoverParameters->Couplers[1].CoupleDist<300.0) //i mniej niż 300m
|
|
{
|
|
//WriteLog("Collision of "+AnsiString(MoverParameters->Couplers[1].CoupleDist)+"m detected by "+asName+":1.");
|
|
w=0.5*(MoverParameters->Couplers[1].Connected->Dim.W+MoverParameters->Dim.W); //minimalna odległość minięcia
|
|
d=-DotProduct(vLeft,vCoulpler[1]); //odległość prostej ruchu od początku układu współrzędnych
|
|
d=fabs(DotProduct(vLeft,((TMoverParameters*)(MoverParameters->Couplers[1].Connected))->vCoulpler[MoverParameters->Couplers[1].ConnectedNr])+d);
|
|
//WriteLog("Distance "+AnsiString(d)+"m from "+asName+":1.");
|
|
if (d>w)
|
|
MoverParameters->Couplers[0].CoupleDist=(d0<10?50:d0); //przywrócenie poprzedniej
|
|
}
|
|
}
|
|
};
|
|
|
|
TDynamicObject* __fastcall TDynamicObject::ControlledFind()
|
|
{//taka proteza: chcę podłączyć kabinę EN57 bezpośrednio z silnikowym, aby nie robić tego przez ukrotnienie
|
|
//drugi silnikowy i tak musi być ukrotniony, podobnie jak kolejna jednostka
|
|
//lepiej by było przesyłać komendy sterowania, co jednak wymaga przebudowy transmisji komend (LD)
|
|
//problem się robi ze światłami, które będą zapalane w silnikowym, ale muszą świecić się w rozrządczych
|
|
//dla EZT światłą czołowe będą "zapalane w silnikowym", ale widziane z rozrządczych
|
|
//również wczytywanie MMD powinno dotyczyć aktualnego członu
|
|
//problematyczna może być kwestia wybranej kabiny (w silnikowym...)
|
|
//jeśli silnikowy będzie zapięty odwrotnie (tzn. -1), to i tak powinno jeździć dobrze
|
|
//również hamowanie wykonuje się zaworem w członie, a nie w silnikowym...
|
|
TDynamicObject *d=this; //zaczynamy od aktualnego
|
|
if (d->MoverParameters->TrainType&dt_EZT) //na razie dotyczy to EZT
|
|
if (d->NextConnected?d->MoverParameters->Couplers[1].AllowedFlag&ctrain_depot:false)
|
|
{//gdy jest człon od sprzęgu 1, a sprzęg łączony warsztatowo (powiedzmy)
|
|
if ((d->MoverParameters->Power<1.0)&&(d->NextConnected->MoverParameters->Power>1.0)) //my nie mamy mocy, ale ten drugi ma
|
|
d=d->NextConnected; //będziemy sterować tym z mocą
|
|
}
|
|
else if (d->PrevConnected?d->MoverParameters->Couplers[0].AllowedFlag&ctrain_depot:false)
|
|
{//gdy jest człon od sprzęgu 0, a sprzęg łączony warsztatowo (powiedzmy)
|
|
if ((d->MoverParameters->Power<1.0)&&(d->PrevConnected->MoverParameters->Power>1.0)) //my nie mamy mocy, ale ten drugi ma
|
|
d=d->PrevConnected; //będziemy sterować tym z mocą
|
|
}
|
|
return d;
|
|
};
|
|
//---------------------------------------------------------------------------
|
|
|
|
void __fastcall TDynamicObject::ParamSet(int what,int into)
|
|
{//ustawienie lokalnego parametru (what) na stan (into)
|
|
switch (what&0xFF00)
|
|
{
|
|
case 0x0100: //to np. są drzwi, bity 0..7 określają numer 1..254 albo maskę dla 8 różnych
|
|
if (what&1) //na razie mamy lewe oraz prawe, czyli używamy maskę 1=lewe, 2=prawe, 3=wszystkie
|
|
if (MoverParameters->DoorLeftOpened)
|
|
{//są otwarte
|
|
if (!into) //jeśli zamykanie
|
|
{
|
|
//dźwięk zamykania
|
|
}
|
|
}
|
|
else
|
|
{//są zamknięte
|
|
if (into) //jeśli otwieranie
|
|
{
|
|
//dźwięk otwierania
|
|
}
|
|
}
|
|
if (what&2) //prawe działają niezależnie od lewych
|
|
if (MoverParameters->DoorRightOpened)
|
|
{//są otwarte
|
|
if (!into) //jeśli zamykanie
|
|
{
|
|
//dźwięk zamykania
|
|
}
|
|
}
|
|
else
|
|
{//są zamknięte
|
|
if (into) //jeśli otwieranie
|
|
{
|
|
//dźwięk otwierania
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
};
|
|
|
|
int __fastcall TDynamicObject::RouteWish(TTrack *tr)
|
|
{//zapytanie do AI, po którym segmencie (-6..6) jechać na skrzyżowaniu (tr)
|
|
return Mechanik?Mechanik->CrossRoute(tr):0; //wg AI albo prosto
|
|
};
|
|
|
|
AnsiString __fastcall TDynamicObject::TextureTest(AnsiString &name)
|
|
{//Ra 2015-01: sprawdzenie dostępności tekstury o podanej nazwie
|
|
AnsiString x=name+".dds"; //na razie prymitywnie
|
|
if (FileExists(x))
|
|
return x;
|
|
else
|
|
{x=name+".tga"; //w zasadzie to należałoby uwzględnić deklarowaną kolejność
|
|
if (FileExists(x))
|
|
return x;
|
|
else
|
|
{x=name+".bmp";
|
|
if (FileExists(x))
|
|
return x;
|
|
}
|
|
}
|
|
return ""; //nie znaleziona
|
|
};
|
|
|
|
void __fastcall TDynamicObject::DestinationSet(AnsiString to)
|
|
{//ustawienie stacji docelowej oraz wymiennej tekstury 4, jeśli istnieje plik
|
|
//w zasadzie, to każdy wagon mógłby mieć inną stację docelową
|
|
//zwłaszcza w towarowych, pod kątem zautomatyzowania maewrów albo pracy górki
|
|
//ale to jeszcze potrwa, zanim będzie możliwe, na razie można wpisać stację z rozkładu
|
|
if (abs(iMultiTex)>=4) return; //jak są 4 tekstury wymienne, to nie zmieniać rozkładem
|
|
asDestination=to;
|
|
to=Global::Bezogonkow(to); //do szukania pliku obcinamy ogonki
|
|
AnsiString x;
|
|
if (to.IsEmpty()) to="nowhere";
|
|
x=TextureTest(asBaseDir+to+"@"+MoverParameters->TypeName); //w pierwszej kolejności z nazwą FIZ/MMD
|
|
if (!x.IsEmpty())
|
|
{
|
|
ReplacableSkinID[4]=TTexturesManager::GetTextureID(NULL,NULL,x.c_str(),9); //rozmywania 0,1,4,5 nie nadają się
|
|
return;
|
|
}
|
|
x=TextureTest(asBaseDir+to); //na razie prymitywnie
|
|
if (!x.IsEmpty())
|
|
ReplacableSkinID[4]=TTexturesManager::GetTextureID(NULL,NULL,x.c_str(),9); //rozmywania 0,1,4,5 nie nadają się
|
|
else
|
|
ReplacableSkinID[4]=0; //0 to brak? -1 odpada, bo inaczej się będzie mapować
|
|
//Ra 2015-01: żeby zalogować błąd, trzeba by mieć pewność, że model używa tekstury nr 4
|
|
};
|
|
|
|
void __fastcall TDynamicObject::OverheadTrack(float o)
|
|
{//ewentualne wymuszanie jazdy bezprądowej z powodu informacji w torze
|
|
if (ctOwner) //jeśli ma obiekt nadzorujący
|
|
{//trzeba zaktualizować mapę flag bitowych jazdy bezprądowej
|
|
if (o<0.0)
|
|
{//normalna jazda po tym torze
|
|
ctOwner->iOverheadZero&=~iOverheadMask; //zerowanie bitu - może pobierać prąd
|
|
ctOwner->iOverheadDown&=~iOverheadMask; //zerowanie bitu - może podnieść pantograf
|
|
}
|
|
else if (o>0.0)
|
|
{//opuszczenie pantografów
|
|
ctOwner->iOverheadZero|=iOverheadMask; //ustawienie bitu - ma jechać bez pobierania prądu
|
|
ctOwner->iOverheadDown|=iOverheadMask; //ustawienie bitu - ma opuścić pantograf
|
|
}
|
|
else
|
|
{//jazda bezprądowa z podniesionym pantografem
|
|
ctOwner->iOverheadZero|=iOverheadMask; //ustawienie bitu - ma jechać bez pobierania prądu
|
|
ctOwner->iOverheadDown&=~iOverheadMask; //zerowanie bitu - może podnieść pantograf
|
|
}
|
|
}
|
|
};
|
|
|