implemented CTrain
This commit is contained in:
commit
5f6b235301
@ -142,7 +142,7 @@ CCollision::LoadCollisionWhenINeedIt(bool forceChange)
|
||||
|
||||
veh = FindPlayerVehicle();
|
||||
if(veh && veh->IsTrain()){
|
||||
if(((CTrain*)veh)->m_doorState != TRAIN_DOOR_STATE2)
|
||||
if(((CTrain*)veh)->m_nDoorState != TRAIN_DOOR_OPEN)
|
||||
return;
|
||||
}else if(playerCoors.z < 4.0f && !CCullZones::DoINeedToLoadCollision())
|
||||
return;
|
||||
|
@ -186,7 +186,7 @@ CCullZones::MarkSubwayAsInvisible(bool visible)
|
||||
n = CPools::GetVehiclePool()->GetSize();
|
||||
for(i = 0; i < n; i++){
|
||||
v = CPools::GetVehiclePool()->GetSlot(i);
|
||||
if(v && v->IsTrain() && ((CTrain*)v)->m_trackId != 0)
|
||||
if(v && v->IsTrain() && ((CTrain*)v)->m_nTrackId != TRACK_ELTRAIN)
|
||||
v->bIsVisible = visible;
|
||||
}
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ char version_name[64];
|
||||
float FramesPerSecond = 30.0f;
|
||||
|
||||
bool gbPrintShite = false;
|
||||
bool gbModelViewer;
|
||||
|
||||
bool DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha);
|
||||
void DoRWStuffEndOfFrame(void);
|
||||
|
@ -18,6 +18,7 @@ extern wchar *gUString;
|
||||
extern wchar *gUString2;
|
||||
extern bool &b_FoundRecentSavedGameWantToLoad;
|
||||
extern bool gbPrintShite;
|
||||
extern bool gbModelViewer;
|
||||
|
||||
class CSprite2d;
|
||||
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
uint8 bIsInWater : 1;
|
||||
uint8 m_phy_flagA10 : 1;
|
||||
uint8 m_phy_flagA20 : 1;
|
||||
uint8 bHitByTrain : 1; // from nick
|
||||
uint8 bHitByTrain : 1;
|
||||
uint8 m_phy_flagA80 : 1;
|
||||
|
||||
uint8 m_nSurfaceTouched;
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "FileMgr.h"
|
||||
#include "World.h"
|
||||
#include "Vehicle.h"
|
||||
#include "Automobile.h"
|
||||
#include "Train.h"
|
||||
#include "ModelIndices.h"
|
||||
#include "ModelInfo.h"
|
||||
|
||||
@ -84,13 +86,13 @@ RwObjectNameIdAssocation boatIds[] = {
|
||||
};
|
||||
|
||||
RwObjectNameIdAssocation trainIds[] = {
|
||||
{ "door_lhs_dummy", 1, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_COLLAPSE },
|
||||
{ "door_rhs_dummy", 2, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_COLLAPSE },
|
||||
{ "light_front", 0, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||
{ "light_rear", 1, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||
{ "ped_left_entry", 2, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||
{ "ped_mid_entry", 3, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||
{ "ped_right_entry", 4, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||
{ "door_lhs_dummy", TRAIN_DOOR_LHS, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_COLLAPSE },
|
||||
{ "door_rhs_dummy", TRAIN_DOOR_RHS, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_COLLAPSE },
|
||||
{ "light_front", TRAIN_POS_LIGHT_FRONT, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||
{ "light_rear", TRAIN_POS_LIGHT_REAR, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||
{ "ped_left_entry", TRAIN_POS_LEFT_ENTRY, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||
{ "ped_mid_entry", TRAIN_POS_MID_ENTRY, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||
{ "ped_right_entry", TRAIN_POS_RIGHT_ENTRY, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||
{ nil, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -79,7 +79,7 @@ CPed::~CPed(void)
|
||||
CWorld::Remove(this);
|
||||
CRadar::ClearBlipForEntity(BLIP_CHAR, CPools::GetPedPool()->GetIndex(this));
|
||||
if (bInVehicle && m_pMyVehicle){
|
||||
uint8 door_flag = GetVehDoorFlag(m_vehEnterType);
|
||||
uint8 door_flag = GetCarDoorFlag(m_vehEnterType);
|
||||
if (m_pMyVehicle->pDriver == this)
|
||||
m_pMyVehicle->pDriver = nil;
|
||||
else {
|
||||
@ -1415,7 +1415,7 @@ CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg)
|
||||
ped->m_pSeekTarget = nil;
|
||||
vehicle = ped->m_pMyVehicle;
|
||||
|
||||
vehicle->m_nGettingOutFlags &= ~GetVehDoorFlag(ped->m_vehEnterType);
|
||||
vehicle->m_nGettingOutFlags &= ~GetCarDoorFlag(ped->m_vehEnterType);
|
||||
|
||||
if (vehicle->pDriver == ped) {
|
||||
vehicle->RemoveDriver();
|
||||
@ -2725,7 +2725,7 @@ CPed::QuitEnteringCar(void)
|
||||
if (veh->m_nNumGettingIn != 0)
|
||||
veh->m_nNumGettingIn--;
|
||||
|
||||
veh->m_nGettingInFlags &= ~GetVehDoorFlag(m_vehEnterType);
|
||||
veh->m_nGettingInFlags &= ~GetCarDoorFlag(m_vehEnterType);
|
||||
}
|
||||
|
||||
bUsesCollision = true;
|
||||
|
@ -394,7 +394,7 @@ public:
|
||||
float m_fRotationCur;
|
||||
float m_fRotationDest;
|
||||
float m_headingRate;
|
||||
uint16 m_vehEnterType;
|
||||
uint16 m_vehEnterType; // TODO: this is more like a door, not a type
|
||||
uint16 m_walkAroundType;
|
||||
CEntity *m_pCurrentPhysSurface;
|
||||
CVector m_vecOffsetFromPhysSurface;
|
||||
|
@ -545,11 +545,7 @@ CShadows::StoreCarLightShadow(CAutomobile *pCar, int32 nID, RwTexture *pTexture,
|
||||
{
|
||||
float fDistToCam = Sqrt(fDistToCamSqr);
|
||||
|
||||
#ifndef FIX_BUGS
|
||||
if ( fDistToCam >= (fDrawDistance*(1.0f-(1.0f/4.0f))) && !bSpecialCam ) // BUG: must be 3.0
|
||||
#else
|
||||
if ( fDistToCam >= (fDrawDistance*(1.0f-(1.0f/3.0f))) && !bSpecialCam )
|
||||
#endif
|
||||
if ( fDistToCam >= (fDrawDistance*(1.0f-(1.0f/4.0f))) && !bSpecialCam ) // BUG? must be 3.0?
|
||||
{
|
||||
//fDistToCam == 0 -> 3
|
||||
//fDistToCam == fDrawDistance -> 0
|
||||
@ -607,22 +603,12 @@ CShadows::StoreShadowForPedObject(CEntity *pPedObject, float fDisplacementX, flo
|
||||
{
|
||||
float fDistToCam = Sqrt(fDistToCamSqr);
|
||||
|
||||
#ifndef FIX_BUGS
|
||||
//fDistToCam == 0 -> 2
|
||||
//fDistToCam == fDrawDistance -> -2
|
||||
float fMult = 1.0f - (4.0f / fDrawDistance) * (fDistToCam - (fDrawDistance*(1.0f/4.0f))); // BUG: negative
|
||||
#else
|
||||
//fDistToCam == 0 -> 4
|
||||
//fDistToCam == fDrawDistance -> 0
|
||||
float fMult = 1.0f - (4.0f / fDrawDistance) * (fDistToCam - (fDrawDistance*(1.0f-(1.0f/4.0f))) );
|
||||
#endif
|
||||
float fMult = 1.0f - (4.0f / fDrawDistance) * (fDistToCam - (fDrawDistance*(1.0f/4.0f))); // BUG ? negative
|
||||
int32 nColorStrength;
|
||||
|
||||
#ifndef FIX_BUGS
|
||||
if ( fDistToCam >= (fDrawDistance*(1.0f/4.0f)) ) // BUG: negative
|
||||
#else
|
||||
if ( fDistToCam >= (fDrawDistance*(1.0f-(1.0f/4.0f))) )
|
||||
#endif
|
||||
if ( fDistToCam >= (fDrawDistance*(1.0f/4.0f)) ) // BUG ? negative
|
||||
nColorStrength = (int32)(CTimeCycle::GetShadowStrength() * fMult);
|
||||
else
|
||||
nColorStrength = CTimeCycle::GetShadowStrength();
|
||||
|
@ -6,6 +6,39 @@
|
||||
|
||||
class CObject;
|
||||
|
||||
enum eCarNodes
|
||||
{
|
||||
CAR_WHEEL_RF = 1,
|
||||
CAR_WHEEL_RM,
|
||||
CAR_WHEEL_RB,
|
||||
CAR_WHEEL_LF,
|
||||
CAR_WHEEL_LM,
|
||||
CAR_WHEEL_LB,
|
||||
CAR_BUMP_FRONT,
|
||||
CAR_BUMP_REAR,
|
||||
CAR_WING_RF,
|
||||
CAR_WING_RR,
|
||||
CAR_DOOR_RF,
|
||||
CAR_DOOR_RR,
|
||||
CAR_WING_LF,
|
||||
CAR_WING_LR,
|
||||
CAR_DOOR_LF,
|
||||
CAR_DOOR_LR,
|
||||
CAR_BONNET,
|
||||
CAR_BOOT,
|
||||
CAR_WINDSCREEN,
|
||||
NUM_CAR_NODES,
|
||||
};
|
||||
|
||||
enum eCarPositions
|
||||
{
|
||||
CAR_POS_HEADLIGHTS,
|
||||
CAR_POS_TAILLIGHTS,
|
||||
CAR_POS_FRONTSEAT,
|
||||
CAR_POS_BACKSEAT,
|
||||
CAR_POS_EXHAUST = 9,
|
||||
};
|
||||
|
||||
// These are used for all the wheel arrays
|
||||
// DON'T confuse with VEHWHEEL, which are vehicle components
|
||||
enum {
|
||||
@ -81,7 +114,7 @@ public:
|
||||
|
||||
static bool &m_sAllTaxiLights;
|
||||
|
||||
CAutomobile(int32, uint8);
|
||||
CAutomobile(int32 id, uint8 CreatedBy);
|
||||
|
||||
// from CEntity
|
||||
void SetModelIndex(uint32 id);
|
||||
@ -152,3 +185,18 @@ public:
|
||||
static void SetAllTaxiLights(bool set);
|
||||
};
|
||||
static_assert(sizeof(CAutomobile) == 0x5A8, "CAutomobile: error");
|
||||
|
||||
inline uint8 GetCarDoorFlag(int32 carnode) {
|
||||
switch (carnode) {
|
||||
case CAR_DOOR_LF:
|
||||
return 1;
|
||||
case CAR_DOOR_LR:
|
||||
return 2;
|
||||
case CAR_DOOR_RF:
|
||||
return 4;
|
||||
case CAR_DOOR_RR:
|
||||
return 8;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -115,6 +115,60 @@ CDoor::IsClosed(void)
|
||||
return m_fAngle == RetAngleWhenClosed();
|
||||
}
|
||||
|
||||
|
||||
CTrainDoor::CTrainDoor(void)
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
void
|
||||
CTrainDoor::Open(float ratio)
|
||||
{
|
||||
float open;
|
||||
|
||||
m_fPrevPosn = m_fPosn;
|
||||
open = RetTranslationWhenOpen();
|
||||
if(ratio < 1.0f){
|
||||
m_fPosn = open*ratio;
|
||||
}else{
|
||||
m_nDoorState = DOORST_OPEN;
|
||||
m_fPosn = open;
|
||||
}
|
||||
}
|
||||
|
||||
float
|
||||
CTrainDoor::RetTranslationWhenClosed(void)
|
||||
{
|
||||
if(Abs(m_fClosedPosn) < Abs(m_fOpenPosn))
|
||||
return m_fClosedPosn;
|
||||
else
|
||||
return m_fOpenPosn;
|
||||
}
|
||||
|
||||
float
|
||||
CTrainDoor::RetTranslationWhenOpen(void)
|
||||
{
|
||||
if(Abs(m_fClosedPosn) < Abs(m_fOpenPosn))
|
||||
return m_fOpenPosn;
|
||||
else
|
||||
return m_fClosedPosn;
|
||||
}
|
||||
|
||||
bool
|
||||
CTrainDoor::IsFullyOpen(void)
|
||||
{
|
||||
// 0.5f again...
|
||||
if(Abs(m_fPosn) < Abs(RetTranslationWhenOpen()) - 0.5f)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CTrainDoor::IsClosed(void)
|
||||
{
|
||||
return m_fPosn == RetTranslationWhenClosed();
|
||||
}
|
||||
|
||||
STARTPATCHES
|
||||
InjectHook(0x545EF0, &CDoor::Open, PATCH_JUMP);
|
||||
InjectHook(0x545BD0, &CDoor::Process, PATCH_JUMP);
|
||||
@ -123,4 +177,10 @@ STARTPATCHES
|
||||
InjectHook(0x545F80, &CDoor::GetAngleOpenRatio, PATCH_JUMP);
|
||||
InjectHook(0x546090, &CDoor::IsFullyOpen, PATCH_JUMP);
|
||||
InjectHook(0x546060, &CDoor::IsClosed, PATCH_JUMP);
|
||||
|
||||
InjectHook(0x546200, &CTrainDoor::Open, PATCH_JUMP);
|
||||
InjectHook(0x546180, &CTrainDoor::RetTranslationWhenClosed, PATCH_JUMP);
|
||||
InjectHook(0x5461C0, &CTrainDoor::RetTranslationWhenOpen, PATCH_JUMP);
|
||||
InjectHook(0x546120, &CTrainDoor::IsFullyOpen, PATCH_JUMP);
|
||||
InjectHook(0x5460F0, &CTrainDoor::IsClosed, PATCH_JUMP);
|
||||
ENDPATCHES
|
||||
|
@ -11,8 +11,9 @@ enum eDoorState
|
||||
DOORST_CLOSED
|
||||
};
|
||||
|
||||
struct CDoor
|
||||
class CDoor
|
||||
{
|
||||
public:
|
||||
float m_fMaxAngle;
|
||||
float m_fMinAngle;
|
||||
// direction of rotation for air resistance
|
||||
@ -34,9 +35,35 @@ struct CDoor
|
||||
}
|
||||
void Open(float ratio);
|
||||
void Process(CVehicle *veh);
|
||||
float RetAngleWhenClosed(void);
|
||||
float RetAngleWhenClosed(void); // dead
|
||||
float RetAngleWhenOpen(void);
|
||||
float GetAngleOpenRatio(void);
|
||||
bool IsFullyOpen(void);
|
||||
bool IsClosed(void);
|
||||
bool IsClosed(void); // dead
|
||||
};
|
||||
|
||||
class CTrainDoor
|
||||
{
|
||||
public:
|
||||
float m_fClosedPosn;
|
||||
float m_fOpenPosn;
|
||||
int8 m_nDirn;
|
||||
int8 m_nDoorState; // same enum as above?
|
||||
int8 m_nAxis;
|
||||
float m_fPosn;
|
||||
float m_fPrevPosn;
|
||||
int field_14; // unused?
|
||||
|
||||
CTrainDoor(void);
|
||||
void Init(float open, float closed, int8 dir, int8 axis) {
|
||||
m_fOpenPosn = open;
|
||||
m_fClosedPosn = closed;
|
||||
m_nDirn = dir;
|
||||
m_nAxis = axis;
|
||||
}
|
||||
bool IsClosed(void);
|
||||
bool IsFullyOpen(void);
|
||||
float RetTranslationWhenClosed(void);
|
||||
float RetTranslationWhenOpen(void);
|
||||
void Open(float ratio);
|
||||
};
|
||||
|
@ -1,20 +1,719 @@
|
||||
#include "common.h"
|
||||
#include "main.h"
|
||||
#include "patcher.h"
|
||||
#include "Timer.h"
|
||||
#include "ModelIndices.h"
|
||||
#include "FileMgr.h"
|
||||
#include "Streaming.h"
|
||||
#include "Pad.h"
|
||||
#include "Camera.h"
|
||||
#include "Coronas.h"
|
||||
#include "World.h"
|
||||
#include "Ped.h"
|
||||
#include "HandlingMgr.h"
|
||||
#include "Train.h"
|
||||
|
||||
CTrain::CTrain(int mi, uint8 owner)
|
||||
static CTrainNode *&pTrackNodes = *(CTrainNode**)0x8F4338;
|
||||
static int16 &NumTrackNodes = *(int16*)0x95CC5C;
|
||||
static float StationDist[3] = { 873.0f, 1522.0f, 2481.0f };
|
||||
static float &TotalLengthOfTrack = *(float*)0x64D000;
|
||||
static float &TotalDurationOfTrack = *(float*)0x64D004;
|
||||
static CTrainInterpolationLine *aLineBits = (CTrainInterpolationLine*)0x70D838; // [17]
|
||||
static float *EngineTrackPosition = (float*)0x64D008; //[2]
|
||||
static float *EngineTrackSpeed = (float*)0x880848; //[2]
|
||||
|
||||
static CTrainNode *&pTrackNodes_S = *(CTrainNode**)0x8F2560;
|
||||
static int16 &NumTrackNodes_S = *(int16*)0x95CC6A;
|
||||
static float StationDist_S[4] = { 55.0f, 1388.0f, 2337.0f, 3989.0f };
|
||||
static float &TotalLengthOfTrack_S = *(float*)0x64D010;
|
||||
static float &TotalDurationOfTrack_S = *(float*)0x64D014;
|
||||
static CTrainInterpolationLine *aLineBits_S = (CTrainInterpolationLine*)0x726600; // [18]
|
||||
static float *EngineTrackPosition_S = (float*)0x64D018; //[4]
|
||||
static float *EngineTrackSpeed_S = (float*)0x87C7C8; //[4]
|
||||
|
||||
CVector CTrain::aStationCoors[3];
|
||||
CVector CTrain::aStationCoors_S[4];
|
||||
|
||||
CTrain::CTrain(int32 id, uint8 CreatedBy)
|
||||
: CVehicle(CreatedBy)
|
||||
{
|
||||
ctor(mi, owner);
|
||||
CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id);
|
||||
m_vehType = VEHICLE_TYPE_TRAIN;
|
||||
pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId);
|
||||
SetModelIndex(id);
|
||||
|
||||
Doors[0].Init(0.8f, 0.0f, 1, 0);
|
||||
Doors[1].Init(-0.8f, 0.0f, 0, 0);
|
||||
|
||||
m_fMass = 100000000.0f;
|
||||
m_fTurnMass = 100000000.0f;
|
||||
m_fAirResistance = 0.9994f;
|
||||
m_fElasticity = 0.05f;
|
||||
|
||||
m_bProcessDoor = true;
|
||||
m_bTrainStopping = false;
|
||||
|
||||
m_nNumMaxPassengers = 5;
|
||||
m_nDoorTimer = CTimer::GetTimeInMilliseconds();
|
||||
m_nDoorState = TRAIN_DOOR_CLOSED;
|
||||
|
||||
bUsesCollision = true;
|
||||
m_status = STATUS_TRAIN_MOVING;
|
||||
}
|
||||
|
||||
WRAPPER CTrain* CTrain::ctor(int, uint8) { EAXJMP(0x54E2A0); }
|
||||
void
|
||||
CTrain::SetModelIndex(uint32 id)
|
||||
{
|
||||
int i;
|
||||
|
||||
CVehicle::SetModelIndex(id);
|
||||
for(i = 0; i < 3; i++)
|
||||
m_aTrainNodes[i] = nil;
|
||||
CClumpModelInfo::FillFrameArray(GetClump(), m_aTrainNodes);
|
||||
}
|
||||
|
||||
void
|
||||
CTrain::ProcessControl(void)
|
||||
{
|
||||
if(gbModelViewer || m_isFarAway && (CTimer::GetFrameCounter() + m_nWagonId) & 0xF)
|
||||
return;
|
||||
|
||||
CTrainNode *trackNodes;
|
||||
int16 numTrackNodes;
|
||||
float totalLengthOfTrack;
|
||||
float *engineTrackPosition;
|
||||
float *engineTrackSpeed;
|
||||
|
||||
if(m_nTrackId == TRACK_SUBWAY){
|
||||
trackNodes = pTrackNodes_S;
|
||||
numTrackNodes = NumTrackNodes_S;
|
||||
totalLengthOfTrack = TotalLengthOfTrack_S;
|
||||
engineTrackPosition = EngineTrackPosition_S;
|
||||
engineTrackSpeed = EngineTrackSpeed_S;
|
||||
}else{
|
||||
trackNodes = pTrackNodes;
|
||||
numTrackNodes = NumTrackNodes;
|
||||
totalLengthOfTrack = TotalLengthOfTrack;
|
||||
engineTrackPosition = EngineTrackPosition;
|
||||
engineTrackSpeed = EngineTrackSpeed;
|
||||
}
|
||||
|
||||
float trackPositionRear = engineTrackPosition[m_nWagonGroup] - m_fWagonPosition;
|
||||
if(trackPositionRear < 0.0f)
|
||||
trackPositionRear += totalLengthOfTrack;
|
||||
|
||||
// Advance current node to appropriate position
|
||||
float pos1, pos2;
|
||||
int nextTrackNode = m_nCurTrackNode + 1;
|
||||
pos1 = trackNodes[m_nCurTrackNode].t;
|
||||
if(nextTrackNode < numTrackNodes)
|
||||
pos2 = trackNodes[nextTrackNode].t;
|
||||
else{
|
||||
nextTrackNode = 0;
|
||||
pos2 = totalLengthOfTrack;
|
||||
}
|
||||
while(trackPositionRear < pos1 || trackPositionRear > pos2){
|
||||
m_nCurTrackNode = (m_nCurTrackNode+1) % numTrackNodes;
|
||||
nextTrackNode = m_nCurTrackNode + 1;
|
||||
pos1 = trackNodes[m_nCurTrackNode].t;
|
||||
if(nextTrackNode < numTrackNodes)
|
||||
pos2 = trackNodes[nextTrackNode].t;
|
||||
else{
|
||||
nextTrackNode = 0;
|
||||
pos2 = totalLengthOfTrack;
|
||||
}
|
||||
}
|
||||
float dist = trackNodes[nextTrackNode].t - trackNodes[m_nCurTrackNode].t;
|
||||
if(dist < 0.0f)
|
||||
dist += totalLengthOfTrack;
|
||||
float f = (trackPositionRear - trackNodes[m_nCurTrackNode].t)/dist;
|
||||
CVector posRear = (1.0f - f)*trackNodes[m_nCurTrackNode].p + f*trackNodes[nextTrackNode].p;
|
||||
|
||||
// Now same again for the front
|
||||
float trackPositionFront = trackPositionRear + 20.0f;
|
||||
if(trackPositionFront > totalLengthOfTrack)
|
||||
trackPositionFront -= totalLengthOfTrack;
|
||||
int curTrackNodeFront = m_nCurTrackNode;
|
||||
int nextTrackNodeFront = curTrackNodeFront + 1;
|
||||
pos1 = trackNodes[curTrackNodeFront].t;
|
||||
if(nextTrackNodeFront < numTrackNodes)
|
||||
pos2 = trackNodes[nextTrackNodeFront].t;
|
||||
else{
|
||||
nextTrackNodeFront = 0;
|
||||
pos2 = totalLengthOfTrack;
|
||||
}
|
||||
while(trackPositionFront < pos1 || trackPositionFront > pos2){
|
||||
curTrackNodeFront = (curTrackNodeFront+1) % numTrackNodes;
|
||||
nextTrackNodeFront = curTrackNodeFront + 1;
|
||||
pos1 = trackNodes[curTrackNodeFront].t;
|
||||
if(nextTrackNodeFront < numTrackNodes)
|
||||
pos2 = trackNodes[nextTrackNodeFront].t;
|
||||
else{
|
||||
nextTrackNodeFront = 0;
|
||||
pos2 = totalLengthOfTrack;
|
||||
}
|
||||
}
|
||||
dist = trackNodes[nextTrackNodeFront].t - trackNodes[curTrackNodeFront].t;
|
||||
if(dist < 0.0f)
|
||||
dist += totalLengthOfTrack;
|
||||
f = (trackPositionFront - trackNodes[curTrackNodeFront].t)/dist;
|
||||
CVector posFront = (1.0f - f)*trackNodes[curTrackNodeFront].p + f*trackNodes[nextTrackNodeFront].p;
|
||||
|
||||
// Now set matrix
|
||||
GetPosition() = (posRear + posFront)/2.0f;
|
||||
CVector fwd = posFront - posRear;
|
||||
fwd.Normalise();
|
||||
CVector right = CrossProduct(fwd, CVector(0.0f, 0.0f, 1.0f));
|
||||
right.Normalise();
|
||||
CVector up = CrossProduct(right, fwd);
|
||||
GetRight() = right;
|
||||
GetUp() = up;
|
||||
GetForward() = fwd;
|
||||
|
||||
// Set speed
|
||||
m_vecMoveSpeed = fwd*engineTrackSpeed[m_nWagonGroup]/60.0f;
|
||||
m_fSpeed = engineTrackSpeed[m_nWagonGroup]/60.0f;
|
||||
m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
|
||||
|
||||
if(engineTrackSpeed[m_nWagonGroup] > 0.001f){
|
||||
m_status = STATUS_TRAIN_MOVING;
|
||||
m_bTrainStopping = false;
|
||||
m_bProcessDoor = true;
|
||||
}else{
|
||||
m_status = STATUS_TRAIN_NOT_MOVING;
|
||||
m_bTrainStopping = true;
|
||||
}
|
||||
|
||||
m_isFarAway = !((posFront - TheCamera.GetPosition()).Magnitude2D() < sq(250.0f));
|
||||
|
||||
if(m_fWagonPosition == 20.0f && m_fSpeed > 0.0001f)
|
||||
if(Abs(TheCamera.GetPosition().z - GetPosition().z) < 15.0f)
|
||||
CPad::GetPad(0)->StartShake_Train(GetPosition().x, GetPosition().y);
|
||||
|
||||
if(m_bProcessDoor)
|
||||
switch(m_nDoorState){
|
||||
case TRAIN_DOOR_CLOSED:
|
||||
if(m_bTrainStopping){
|
||||
m_nDoorTimer = CTimer::GetTimeInMilliseconds() + 1000;
|
||||
m_nDoorState = TRAIN_DOOR_OPENING;
|
||||
DMAudio.PlayOneShot(m_audioEntityId, SOUND_18, 0.0f);
|
||||
}
|
||||
break;
|
||||
|
||||
case TRAIN_DOOR_OPENING:
|
||||
if(CTimer::GetTimeInMilliseconds() < m_nDoorTimer){
|
||||
OpenTrainDoor(1.0f - (m_nDoorTimer - CTimer::GetTimeInMilliseconds())/1000.0f);
|
||||
}else{
|
||||
OpenTrainDoor(1.0f);
|
||||
m_nDoorState = TRAIN_DOOR_OPEN;
|
||||
}
|
||||
break;
|
||||
|
||||
case TRAIN_DOOR_OPEN:
|
||||
if(!m_bTrainStopping){
|
||||
m_nDoorTimer = CTimer::GetTimeInMilliseconds() + 1000;
|
||||
m_nDoorState = TRAIN_DOOR_CLOSING;
|
||||
DMAudio.PlayOneShot(m_audioEntityId, SOUND_19, 0.0f);
|
||||
}
|
||||
break;
|
||||
|
||||
case TRAIN_DOOR_CLOSING:
|
||||
if(CTimer::GetTimeInMilliseconds() < m_nDoorTimer){
|
||||
OpenTrainDoor((m_nDoorTimer - CTimer::GetTimeInMilliseconds())/1000.0f);
|
||||
}else{
|
||||
OpenTrainDoor(0.0f);
|
||||
m_nDoorState = TRAIN_DOOR_CLOSED;
|
||||
m_bProcessDoor = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
GetMatrix().UpdateRW();
|
||||
UpdateRwFrame();
|
||||
RemoveAndAdd();
|
||||
|
||||
bIsStuck = false;
|
||||
bIsInSafePosition = true;
|
||||
bWasPostponed = false;
|
||||
|
||||
// request/remove model
|
||||
if(m_isFarAway){
|
||||
if(m_rwObject)
|
||||
DeleteRwObject();
|
||||
}else if(CStreaming::HasModelLoaded(MI_TRAIN)){
|
||||
if(m_rwObject == nil){
|
||||
m_modelIndex = -1;
|
||||
SetModelIndex(MI_TRAIN);
|
||||
}
|
||||
}else{
|
||||
if(FindPlayerCoors().z * GetPosition().z >= 0.0f)
|
||||
CStreaming::RequestModel(MI_TRAIN, STREAMFLAGS_DEPENDENCY);
|
||||
}
|
||||
|
||||
// Hit stuff
|
||||
if(m_bIsFirstWagon && m_status == STATUS_TRAIN_MOVING){
|
||||
CVector front = GetPosition() + GetForward()*GetColModel()->boundingBox.max.y + m_vecMoveSpeed*CTimer::GetTimeStep();
|
||||
|
||||
int x, xmin, xmax;
|
||||
int y, ymin, ymax;
|
||||
|
||||
xmin = CWorld::GetSectorIndexX(front.x - 3.0f);
|
||||
if(xmin < 0) xmin = 0;
|
||||
xmax = CWorld::GetSectorIndexX(front.x + 3.0f);
|
||||
if(xmax > NUMSECTORS_X-1) xmax = NUMSECTORS_X-1;
|
||||
ymin = CWorld::GetSectorIndexX(front.y - 3.0f);
|
||||
if(ymin < 0) ymin = 0;
|
||||
ymax = CWorld::GetSectorIndexX(front.y + 3.0f);
|
||||
if(ymax > NUMSECTORS_Y-1) ymax = NUMSECTORS_X-1;
|
||||
|
||||
CWorld::AdvanceCurrentScanCode();
|
||||
|
||||
for(y = ymin; y <= ymax; y++)
|
||||
for(x = xmin; x <= xmax; x++){
|
||||
CSector *s = CWorld::GetSector(x, y);
|
||||
TrainHitStuff(s->m_lists[ENTITYLIST_VEHICLES]);
|
||||
TrainHitStuff(s->m_lists[ENTITYLIST_VEHICLES_OVERLAP]);
|
||||
TrainHitStuff(s->m_lists[ENTITYLIST_PEDS]);
|
||||
TrainHitStuff(s->m_lists[ENTITYLIST_PEDS_OVERLAP]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CTrain::PreRender(void)
|
||||
{
|
||||
CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
|
||||
|
||||
if(m_bIsFirstWagon){
|
||||
CVector lookVector = GetPosition() - TheCamera.GetPosition();
|
||||
float camDist = lookVector.Magnitude();
|
||||
if(camDist != 0.0f)
|
||||
lookVector *= 1.0f/camDist;
|
||||
else
|
||||
lookVector = CVector(1.0f, 0.0f, 0.0f);
|
||||
float behindness = DotProduct(lookVector, GetForward());
|
||||
|
||||
if(behindness < 0.0f){
|
||||
// In front of train
|
||||
CVector lightPos = mi->m_positions[TRAIN_POS_LIGHT_FRONT];
|
||||
CVector lightR = GetMatrix() * lightPos;
|
||||
CVector lightL = lightR;
|
||||
lightL -= GetRight()*2.0f*lightPos.x;
|
||||
|
||||
float intensity = -0.4f*behindness + 0.2f;
|
||||
float size = 1.0f - behindness;
|
||||
|
||||
if(behindness < -0.9f && camDist < 35.0f){
|
||||
// directly in front
|
||||
CCoronas::RegisterCorona((uintptr)this + 10, 255*intensity, 255*intensity, 255*intensity, 255,
|
||||
lightL, size, 80.0f,
|
||||
CCoronas::TYPE_NORMAL, CCoronas::FLARE_HEADLIGHTS, CCoronas::REFLECTION_ON,
|
||||
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
|
||||
CCoronas::RegisterCorona((uintptr)this + 11, 255*intensity, 255*intensity, 255*intensity, 255,
|
||||
lightR, size, 80.0f,
|
||||
CCoronas::TYPE_NORMAL, CCoronas::FLARE_HEADLIGHTS, CCoronas::REFLECTION_ON,
|
||||
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
|
||||
}else{
|
||||
CCoronas::RegisterCorona((uintptr)this + 10, 255*intensity, 255*intensity, 255*intensity, 255,
|
||||
lightL, size, 80.0f,
|
||||
CCoronas::TYPE_NORMAL, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
|
||||
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
|
||||
CCoronas::RegisterCorona((uintptr)this + 11, 255*intensity, 255*intensity, 255*intensity, 255,
|
||||
lightR, size, 80.0f,
|
||||
CCoronas::TYPE_NORMAL, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
|
||||
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(m_bIsLastWagon){
|
||||
CVector lightPos = mi->m_positions[TRAIN_POS_LIGHT_REAR];
|
||||
CVector lightR = GetMatrix() * lightPos;
|
||||
CVector lightL = lightR;
|
||||
lightL -= GetRight()*2.0f*lightPos.x;
|
||||
|
||||
CCoronas::RegisterCorona((uintptr)this + 12, 255, 0, 0, 255,
|
||||
lightL, 1.0f, 80.0f,
|
||||
CCoronas::TYPE_NORMAL, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
|
||||
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
|
||||
CCoronas::RegisterCorona((uintptr)this + 13, 255, 0, 0, 255,
|
||||
lightR, 1.0f, 80.0f,
|
||||
CCoronas::TYPE_NORMAL, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
|
||||
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CTrain::Render(void)
|
||||
{
|
||||
CEntity::Render();
|
||||
}
|
||||
|
||||
void
|
||||
CTrain::TrainHitStuff(CPtrList &list)
|
||||
{
|
||||
CPtrNode *node;
|
||||
CPhysical *phys;
|
||||
|
||||
for(node = list.first; node; node = node->next){
|
||||
phys = (CPhysical*)node->item;
|
||||
if(phys != this && Abs(this->GetPosition().z - phys->GetPosition().z) < 1.5f)
|
||||
phys->bHitByTrain = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CTrain::AddPassenger(CPed *ped)
|
||||
{
|
||||
int i = ped->m_vehEnterType;
|
||||
if((i == TRAIN_POS_LEFT_ENTRY || i == TRAIN_POS_MID_ENTRY || i == TRAIN_POS_RIGHT_ENTRY) && pPassengers[i] == nil){
|
||||
pPassengers[i] = ped;
|
||||
m_nNumPassengers++;
|
||||
}else{
|
||||
for(i = 0; i < 6; i++)
|
||||
if(pPassengers[i] == nil){
|
||||
pPassengers[i] = ped;
|
||||
m_nNumPassengers++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CTrain::OpenTrainDoor(float ratio)
|
||||
{
|
||||
if(m_rwObject == nil)
|
||||
return;
|
||||
|
||||
CMatrix doorL(RwFrameGetMatrix(m_aTrainNodes[TRAIN_DOOR_LHS]));
|
||||
CMatrix doorR(RwFrameGetMatrix(m_aTrainNodes[TRAIN_DOOR_RHS]));
|
||||
CVector posL = doorL.GetPosition();
|
||||
CVector posR = doorR.GetPosition();
|
||||
|
||||
bool isClosed = Doors[0].IsClosed(); // useless
|
||||
|
||||
Doors[0].Open(ratio);
|
||||
Doors[1].Open(ratio);
|
||||
|
||||
if(isClosed)
|
||||
Doors[0].RetTranslationWhenClosed(); // useless
|
||||
|
||||
posL.y = Doors[0].m_fPosn;
|
||||
posR.y = Doors[1].m_fPosn;
|
||||
|
||||
doorL.SetTranslate(posL);
|
||||
doorR.SetTranslate(posR);
|
||||
|
||||
doorL.UpdateRW();
|
||||
doorR.UpdateRW();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CTrain::InitTrains(void)
|
||||
{
|
||||
int i, j;
|
||||
CTrain *train;
|
||||
|
||||
// El train
|
||||
if(pTrackNodes == nil)
|
||||
ReadAndInterpretTrackFile("data\\paths\\tracks.dat", &pTrackNodes, &NumTrackNodes, 3, StationDist,
|
||||
&TotalLengthOfTrack, &TotalDurationOfTrack, aLineBits, false);
|
||||
// Subway
|
||||
if(pTrackNodes_S == nil)
|
||||
ReadAndInterpretTrackFile("data\\paths\\tracks2.dat", &pTrackNodes_S, &NumTrackNodes_S, 4, StationDist_S,
|
||||
&TotalLengthOfTrack_S, &TotalDurationOfTrack_S, aLineBits_S, true);
|
||||
|
||||
int trainId;
|
||||
CStreaming::LoadAllRequestedModels(false);
|
||||
if(CModelInfo::GetModelInfo("train", &trainId))
|
||||
CStreaming::RequestModel(trainId, 0);
|
||||
CStreaming::LoadAllRequestedModels(false);
|
||||
|
||||
// El-Train wagons
|
||||
float wagonPositions[] = { 0.0f, 20.0f, 40.0f, 0.0f, 20.0f };
|
||||
int8 firstWagon[] = { 1, 0, 0, 1, 0 };
|
||||
int8 lastWagon[] = { 0, 0, 1, 0, 1 };
|
||||
int16 wagonGroup[] = { 0, 0, 0, 1, 1 };
|
||||
for(i = 0; i < 5; i++){
|
||||
train = new CTrain(MI_TRAIN, PERMANENT_VEHICLE);
|
||||
train->GetMatrix().SetTranslate(0.0f, 0.0f, 0.0f);
|
||||
train->m_status = STATUS_ABANDONED;
|
||||
train->bIsLocked = true;
|
||||
train->m_fWagonPosition = wagonPositions[i];
|
||||
train->m_bIsFirstWagon = firstWagon[i];
|
||||
train->m_bIsLastWagon = lastWagon[i];
|
||||
train->m_nWagonGroup = wagonGroup[i];
|
||||
train->m_nWagonId = i;
|
||||
train->m_nCurTrackNode = 0;
|
||||
CWorld::Add(train);
|
||||
}
|
||||
|
||||
// Subway wagons
|
||||
float wagonPositions_S[] = { 0.0f, 20.0f, 0.0f, 20.0f, 0.0f, 20.0f, 0.0f, 20.0f };
|
||||
int8 firstWagon_S[] = { 1, 0, 1, 0, 1, 0, 1, 0 };
|
||||
int8 lastWagon_S[] = { 0, 1, 0, 1, 0, 1, 0, 1 };
|
||||
int16 wagonGroup_S[] = { 0, 0, 1, 1, 2, 2, 3, 3 };
|
||||
for(i = 0; i < 8; i++){
|
||||
train = new CTrain(MI_TRAIN, PERMANENT_VEHICLE);
|
||||
train->GetMatrix().SetTranslate(0.0f, 0.0f, 0.0f);
|
||||
train->m_status = STATUS_ABANDONED;
|
||||
train->bIsLocked = true;
|
||||
train->m_fWagonPosition = wagonPositions_S[i];
|
||||
train->m_bIsFirstWagon = firstWagon_S[i];
|
||||
train->m_bIsLastWagon = lastWagon_S[i];
|
||||
train->m_nWagonGroup = wagonGroup_S[i];
|
||||
train->m_nWagonId = i;
|
||||
train->m_nCurTrackNode = 0;
|
||||
train->m_nTrackId = TRACK_SUBWAY;
|
||||
CWorld::Add(train);
|
||||
}
|
||||
|
||||
// This code is actually useless, it seems it was used for announcements once
|
||||
for(i = 0; i < 3; i++){
|
||||
for(j = 0; pTrackNodes[j].t < StationDist[i]; j++);
|
||||
aStationCoors[i] = pTrackNodes[j].p;
|
||||
}
|
||||
for(i = 0; i < 4; i++){
|
||||
for(j = 0; pTrackNodes_S[j].t < StationDist_S[i]; j++);
|
||||
aStationCoors_S[i] = pTrackNodes_S[j].p;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CTrain::Shutdown(void)
|
||||
{
|
||||
if(pTrackNodes) delete[] pTrackNodes;
|
||||
if(pTrackNodes_S) delete[] pTrackNodes_S;
|
||||
pTrackNodes = nil;
|
||||
pTrackNodes_S = nil;
|
||||
}
|
||||
|
||||
void
|
||||
CTrain::ReadAndInterpretTrackFile(char *filename, CTrainNode **nodes, int16 *numNodes, int32 numStations, float *stationDists,
|
||||
float *totalLength, float *totalDuration, CTrainInterpolationLine *interpLines, bool rightRail)
|
||||
{
|
||||
bool readingFile = false;
|
||||
int bp, lp;
|
||||
int i, tmp;
|
||||
|
||||
if(*nodes == nil){
|
||||
readingFile = true;
|
||||
|
||||
CFileMgr::LoadFile(filename, work_buff, sizeof(work_buff), "r");
|
||||
*gString = '\0';
|
||||
for(bp = 0, lp = 0; work_buff[bp] != '\n'; bp++, lp++)
|
||||
gString[lp] = work_buff[bp];
|
||||
bp++;
|
||||
// BUG: game doesn't terminate string and uses numNodes in sscanf directly
|
||||
gString[lp] = '\0';
|
||||
sscanf(gString, "%d", &tmp);
|
||||
*numNodes = tmp;
|
||||
*nodes = new CTrainNode[*numNodes];
|
||||
|
||||
for(i = 0; i < *numNodes; i++){
|
||||
*gString = '\0';
|
||||
for(lp = 0; work_buff[bp] != '\n'; bp++, lp++)
|
||||
gString[lp] = work_buff[bp];
|
||||
bp++;
|
||||
// BUG: game doesn't terminate string
|
||||
gString[lp] = '\0';
|
||||
sscanf(gString, "%f %f %f", &(*nodes)[i].p.x, &(*nodes)[i].p.y, &(*nodes)[i].p.z);
|
||||
}
|
||||
|
||||
// Coordinates are of one of the rails, but we want the center
|
||||
float toCenter = rightRail ? 0.9f : -0.9f;
|
||||
CVector fwd;
|
||||
for(i = 0; i < *numNodes; i++){
|
||||
if(i == *numNodes-1)
|
||||
fwd = (*nodes)[0].p - (*nodes)[i].p;
|
||||
else
|
||||
fwd = (*nodes)[i+1].p - (*nodes)[i].p;
|
||||
CVector right = CrossProduct(fwd, CVector(0.0f, 0.0f, 1.0f));
|
||||
right.Normalise();
|
||||
(*nodes)[i].p -= right*toCenter;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate length of segments and track
|
||||
float t = 0.0f;
|
||||
for(i = 0; i < *numNodes; i++){
|
||||
(*nodes)[i].t = t;
|
||||
t += ((*nodes)[(i+1) % (*numNodes)].p - (*nodes)[i].p).Magnitude2D();
|
||||
}
|
||||
*totalLength = t;
|
||||
|
||||
// Find correct z values
|
||||
if(readingFile){
|
||||
CColPoint colpoint;
|
||||
CEntity *entity;
|
||||
for(i = 0; i < *numNodes; i++){
|
||||
CVector p = (*nodes)[i].p;
|
||||
p.z += 1.0f;
|
||||
if(CWorld::ProcessVerticalLine(p, p.z-0.5f, colpoint, entity, true, false, false, false, true, false, nil))
|
||||
(*nodes)[i].p.z = colpoint.point.z;
|
||||
(*nodes)[i].p.z += 0.2f;
|
||||
}
|
||||
}
|
||||
|
||||
// Create animation for stopping at stations
|
||||
// TODO: figure out magic numbers?
|
||||
float position = 0.0f;
|
||||
float time = 0.0f;
|
||||
int j = 0;
|
||||
for(i = 0; i < numStations; i++){
|
||||
// Start at full speed
|
||||
interpLines[j].type = 1;
|
||||
interpLines[j].time = time;
|
||||
interpLines[j].position = position;
|
||||
interpLines[j].speed = 15.0f;
|
||||
interpLines[j].acceleration = 0.0f;
|
||||
j++;
|
||||
// distance to next keyframe
|
||||
float dist = (stationDists[i]-40.0f) - position;
|
||||
time += dist/15.0f;
|
||||
position += dist;
|
||||
|
||||
// Now slow down 40 units before stop
|
||||
interpLines[j].type = 2;
|
||||
interpLines[j].time = time;
|
||||
interpLines[j].position = position;
|
||||
interpLines[j].speed = 15.0f;
|
||||
interpLines[j].acceleration = -45.0f/32.0f;
|
||||
j++;
|
||||
time += 16.0f/3.0f;
|
||||
position += 40.0f; // at station
|
||||
|
||||
// stopping
|
||||
interpLines[j].type = 0;
|
||||
interpLines[j].time = time;
|
||||
interpLines[j].position = position;
|
||||
interpLines[j].speed = 0.0f;
|
||||
interpLines[j].acceleration = 0.0f;
|
||||
j++;
|
||||
time += 25.0f;
|
||||
|
||||
// accelerate again
|
||||
interpLines[j].type = 2;
|
||||
interpLines[j].time = time;
|
||||
interpLines[j].position = position;
|
||||
interpLines[j].speed = 0.0f;
|
||||
interpLines[j].acceleration = 45.0f/32.0f;
|
||||
j++;
|
||||
time += 16.0f/3.0f;
|
||||
position += 40.0f; // after station
|
||||
}
|
||||
// last keyframe
|
||||
interpLines[j].type = 1;
|
||||
interpLines[j].time = time;
|
||||
interpLines[j].position = position;
|
||||
interpLines[j].speed = 15.0f;
|
||||
interpLines[j].acceleration = 0.0f;
|
||||
j++;
|
||||
*totalDuration = time + (*totalLength - position)/15.0f;
|
||||
|
||||
// end
|
||||
interpLines[j].time = *totalDuration;
|
||||
}
|
||||
|
||||
void
|
||||
ProcessTrainAnnouncements(void)
|
||||
{
|
||||
// TODO but unused
|
||||
}
|
||||
|
||||
void
|
||||
CTrain::UpdateTrains(void)
|
||||
{
|
||||
int i, j;
|
||||
uint32 time;
|
||||
float t, deltaT;
|
||||
|
||||
if(TheCamera.GetPosition().x > 200.0f && TheCamera.GetPosition().x < 1600.0f &&
|
||||
TheCamera.GetPosition().y > -1000.0f && TheCamera.GetPosition().y < 500.0f){
|
||||
// Update El-Train
|
||||
|
||||
time = CTimer::GetTimeInMilliseconds();
|
||||
for(i = 0; i < 2; i++){
|
||||
t = TotalDurationOfTrack * (float)(time & 0x1FFFF)/0x20000;
|
||||
// find current frame
|
||||
for(j = 0; t > aLineBits[j+1].time; j++);
|
||||
|
||||
deltaT = t - aLineBits[j].time;
|
||||
switch(aLineBits[j].type){
|
||||
case 0: // standing still
|
||||
EngineTrackPosition[i] = aLineBits[j].position;
|
||||
EngineTrackSpeed[i] = 0.0f;
|
||||
break;
|
||||
case 1: // moving with constant speed
|
||||
EngineTrackPosition[i] = aLineBits[j].position + aLineBits[j].speed*deltaT;
|
||||
EngineTrackSpeed[i] = (TotalDurationOfTrack*1000.0f/0x20000) * aLineBits[j].speed;
|
||||
break;
|
||||
case 2: // accelerating/braking
|
||||
EngineTrackPosition[i] = aLineBits[j].position + (aLineBits[j].speed + aLineBits[j].acceleration*deltaT)*deltaT;
|
||||
EngineTrackSpeed[i] = (TotalDurationOfTrack*1000.0f/0x20000)*aLineBits[j].speed + 2.0f*aLineBits[j].acceleration*deltaT;
|
||||
break;
|
||||
}
|
||||
|
||||
// time offset for each train
|
||||
time += 0x10000;
|
||||
}
|
||||
|
||||
ProcessTrainAnnouncements();
|
||||
}
|
||||
|
||||
// Update Subway
|
||||
time = CTimer::GetTimeInMilliseconds();
|
||||
for(i = 0; i < 4; i++){
|
||||
t = TotalDurationOfTrack_S * (float)(time & 0x3FFFF)/0x40000;
|
||||
// find current frame
|
||||
for(j = 0; t > aLineBits_S[j+1].time; j++);
|
||||
|
||||
deltaT = t - aLineBits_S[j].time;
|
||||
switch(aLineBits_S[j].type){
|
||||
case 0: // standing still
|
||||
EngineTrackPosition_S[i] = aLineBits_S[j].position;
|
||||
EngineTrackSpeed_S[i] = 0.0f;
|
||||
break;
|
||||
case 1: // moving with constant speed
|
||||
EngineTrackPosition_S[i] = aLineBits_S[j].position + aLineBits_S[j].speed*deltaT;
|
||||
EngineTrackSpeed_S[i] = (TotalDurationOfTrack*1000.0f/0x40000) * aLineBits_S[j].speed;
|
||||
break;
|
||||
case 2: // accelerating/braking
|
||||
EngineTrackPosition_S[i] = aLineBits_S[j].position + (aLineBits_S[j].speed + aLineBits_S[j].acceleration*deltaT)*deltaT;
|
||||
EngineTrackSpeed_S[i] = (TotalDurationOfTrack*1000.0f/0x40000)*aLineBits_S[j].speed + 2.0f*aLineBits_S[j].acceleration*deltaT;
|
||||
break;
|
||||
}
|
||||
|
||||
// time offset for each train
|
||||
time += 0x10000;
|
||||
}
|
||||
}
|
||||
|
||||
class CTrain_ : public CTrain
|
||||
{
|
||||
public:
|
||||
void ctor(int32 id, uint8 CreatedBy) { ::new (this) CTrain(id, CreatedBy); }
|
||||
void SetModelIndex_(uint32 id) { CTrain::SetModelIndex(id); }
|
||||
void ProcessControl_(void) { CTrain::ProcessControl(); }
|
||||
void PreRender_(void) { CTrain::PreRender(); }
|
||||
void Render_(void) { CTrain::Render(); }
|
||||
void dtor(void) { CTrain::~CTrain(); }
|
||||
};
|
||||
|
||||
STARTPATCHES
|
||||
InjectHook(0x54E470, &CTrain_::SetModelIndex_, PATCH_JUMP);
|
||||
InjectHook(0x54E4C0, &CTrain_::PreRender_, PATCH_JUMP);
|
||||
InjectHook(0x54EAA0, &CTrain_::Render_, PATCH_JUMP);
|
||||
InjectHook(0x54E450, &CTrain_::dtor, PATCH_JUMP);
|
||||
InjectHook(0x54E2A0, &CTrain_::ctor, PATCH_JUMP);
|
||||
InjectHook(0x550300, &CTrain::TrainHitStuff, PATCH_JUMP);
|
||||
InjectHook(0x5504A0, &CTrain::AddPassenger, PATCH_JUMP);
|
||||
InjectHook(0x550360, &CTrain::OpenTrainDoor, PATCH_JUMP);
|
||||
|
||||
InjectHook(0x54F000, CTrain::InitTrains, PATCH_JUMP);
|
||||
InjectHook(0x54F360, CTrain::Shutdown, PATCH_JUMP);
|
||||
InjectHook(0x54EAB0, CTrain::ReadAndInterpretTrackFile, PATCH_JUMP);
|
||||
InjectHook(0x54F3A0, CTrain::UpdateTrains, PATCH_JUMP);
|
||||
ENDPATCHES
|
||||
|
@ -1,25 +1,93 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "patcher.h"
|
||||
#include "Vehicle.h"
|
||||
#include "Door.h"
|
||||
|
||||
enum
|
||||
{
|
||||
TRAIN_DOOR_STATE2 = 2
|
||||
TRACK_ELTRAIN,
|
||||
TRACK_SUBWAY
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TRAIN_DOOR_CLOSED,
|
||||
TRAIN_DOOR_OPENING,
|
||||
TRAIN_DOOR_OPEN,
|
||||
TRAIN_DOOR_CLOSING
|
||||
};
|
||||
|
||||
enum eTrainNodes
|
||||
{
|
||||
TRAIN_DOOR_LHS = 1,
|
||||
TRAIN_DOOR_RHS
|
||||
};
|
||||
|
||||
enum eTrainPositions
|
||||
{
|
||||
TRAIN_POS_LIGHT_FRONT,
|
||||
TRAIN_POS_LIGHT_REAR,
|
||||
TRAIN_POS_LEFT_ENTRY,
|
||||
TRAIN_POS_MID_ENTRY,
|
||||
TRAIN_POS_RIGHT_ENTRY
|
||||
};
|
||||
|
||||
struct CTrainNode
|
||||
{
|
||||
CVector p; // position
|
||||
float t; // xy-distance from start on track
|
||||
};
|
||||
|
||||
struct CTrainInterpolationLine
|
||||
{
|
||||
uint8 type;
|
||||
float time; // when does this keyframe start
|
||||
// initial values at start of frame
|
||||
float position;
|
||||
float speed;
|
||||
float acceleration;
|
||||
};
|
||||
|
||||
class CTrain : public CVehicle
|
||||
{
|
||||
public:
|
||||
// 0x288
|
||||
uint8 stuff1[20];
|
||||
uint8 m_trackId;
|
||||
uint8 stuff2[7];
|
||||
int16 m_doorState;
|
||||
uint8 stuff3[62];
|
||||
float m_fWagonPosition;
|
||||
int16 m_nWagonId;
|
||||
int16 m_isFarAway; // don't update so often?
|
||||
int16 m_nCurTrackNode;
|
||||
int16 m_nWagonGroup;
|
||||
float m_fSpeed;
|
||||
bool m_bProcessDoor;
|
||||
bool m_bTrainStopping;
|
||||
bool m_bIsFirstWagon;
|
||||
bool m_bIsLastWagon;
|
||||
uint8 m_nTrackId; // or m_bUsesSubwayTracks?
|
||||
uint32 m_nDoorTimer;
|
||||
int16 m_nDoorState;
|
||||
CTrainDoor Doors[2];
|
||||
RwFrame *m_aTrainNodes[3];
|
||||
|
||||
CTrain(int, uint8);
|
||||
CTrain* ctor(int, uint8);
|
||||
// unused
|
||||
static CVector aStationCoors[3];
|
||||
static CVector aStationCoors_S[4];
|
||||
|
||||
CTrain(int32 id, uint8 CreatedBy);
|
||||
|
||||
// from CEntity
|
||||
void SetModelIndex(uint32 id);
|
||||
void ProcessControl(void);
|
||||
void PreRender(void);
|
||||
void Render(void);
|
||||
|
||||
void AddPassenger(CPed *ped);
|
||||
void OpenTrainDoor(float ratio);
|
||||
void TrainHitStuff(CPtrList &list);
|
||||
|
||||
static void InitTrains(void);
|
||||
static void Shutdown(void);
|
||||
static void ReadAndInterpretTrackFile(char *filename, CTrainNode **nodes, int16 *numNodes, int32 numStations, float *stationDists,
|
||||
float *totalLength, float *totalDuration, CTrainInterpolationLine *interpLines, bool rightRail);
|
||||
static void UpdateTrains(void);
|
||||
};
|
||||
static_assert(sizeof(CTrain) == 0x2E4, "CTrain: error");
|
||||
|
@ -26,39 +26,6 @@ enum eCarLock {
|
||||
};
|
||||
|
||||
|
||||
enum eCarNodes
|
||||
{
|
||||
CAR_WHEEL_RF = 1,
|
||||
CAR_WHEEL_RM,
|
||||
CAR_WHEEL_RB,
|
||||
CAR_WHEEL_LF,
|
||||
CAR_WHEEL_LM,
|
||||
CAR_WHEEL_LB,
|
||||
CAR_BUMP_FRONT,
|
||||
CAR_BUMP_REAR,
|
||||
CAR_WING_RF,
|
||||
CAR_WING_RR,
|
||||
CAR_DOOR_RF,
|
||||
CAR_DOOR_RR,
|
||||
CAR_WING_LF,
|
||||
CAR_WING_LR,
|
||||
CAR_DOOR_LF,
|
||||
CAR_DOOR_LR,
|
||||
CAR_BONNET,
|
||||
CAR_BOOT,
|
||||
CAR_WINDSCREEN,
|
||||
NUM_CAR_NODES,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CAR_POS_HEADLIGHTS,
|
||||
CAR_POS_TAILLIGHTS,
|
||||
CAR_POS_FRONTSEAT,
|
||||
CAR_POS_BACKSEAT,
|
||||
CAR_POS_EXHAUST = 9,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
BOAT_POS_FRONTSEAT
|
||||
@ -311,21 +278,6 @@ static_assert(offsetof(CVehicle, m_pCurGroundEntity) == 0x1E0, "CVehicle: error"
|
||||
static_assert(offsetof(CVehicle, m_nAlarmState) == 0x1A0, "CVehicle: error");
|
||||
static_assert(offsetof(CVehicle, m_nLastWeaponDamage) == 0x228, "CVehicle: error");
|
||||
|
||||
inline uint8 GetVehDoorFlag(int32 carnode) {
|
||||
switch (carnode) {
|
||||
case CAR_DOOR_LF:
|
||||
return 1;
|
||||
case CAR_DOOR_LR:
|
||||
return 2;
|
||||
case CAR_DOOR_RF:
|
||||
return 4;
|
||||
case CAR_DOOR_RR:
|
||||
return 8;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class cTransmission;
|
||||
|
||||
class cVehicleParams
|
||||
|
Loading…
Reference in New Issue
Block a user