finished CBoat
This commit is contained in:
parent
a622c9e877
commit
3aae52d220
@ -33,7 +33,6 @@ to reverse at the time, calling the original functions is acceptable.
|
|||||||
### Unreversed / incomplete classes (at least the ones we know)
|
### Unreversed / incomplete classes (at least the ones we know)
|
||||||
```
|
```
|
||||||
cAudioManager - WIP
|
cAudioManager - WIP
|
||||||
CBoat
|
|
||||||
CBulletInfo
|
CBulletInfo
|
||||||
CPacManPickups
|
CPacManPickups
|
||||||
CPedPath
|
CPedPath
|
||||||
|
@ -342,6 +342,7 @@ DebugMenuPopulate(void)
|
|||||||
DebugMenuAddCmd("Spawn", "Spawn Dodo", [](){ SpawnCar(MI_DODO); });
|
DebugMenuAddCmd("Spawn", "Spawn Dodo", [](){ SpawnCar(MI_DODO); });
|
||||||
DebugMenuAddCmd("Spawn", "Spawn Rhino", [](){ SpawnCar(MI_RHINO); });
|
DebugMenuAddCmd("Spawn", "Spawn Rhino", [](){ SpawnCar(MI_RHINO); });
|
||||||
DebugMenuAddCmd("Spawn", "Spawn Firetruck", [](){ SpawnCar(MI_FIRETRUCK); });
|
DebugMenuAddCmd("Spawn", "Spawn Firetruck", [](){ SpawnCar(MI_FIRETRUCK); });
|
||||||
|
DebugMenuAddCmd("Spawn", "Spawn Predator", [](){ SpawnCar(MI_PREDATOR); });
|
||||||
|
|
||||||
DebugMenuAddVarBool8("Debug", "Draw hud", (int8*)&CHud::m_Wants_To_Draw_Hud, nil);
|
DebugMenuAddVarBool8("Debug", "Draw hud", (int8*)&CHud::m_Wants_To_Draw_Hud, nil);
|
||||||
DebugMenuAddVar("Debug", "Engine Status", &engineStatus, nil, 1, 0, 226, nil);
|
DebugMenuAddVar("Debug", "Engine Status", &engineStatus, nil, 1, 0, 226, nil);
|
||||||
|
@ -21,7 +21,7 @@ CPhysical::CPhysical(void)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
fForceMultiplier = 1.0f;
|
m_fForceMultiplier = 1.0f;
|
||||||
m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
|
m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
|
||||||
m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
|
m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
|
||||||
m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f);
|
m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f);
|
||||||
|
@ -29,7 +29,7 @@ public:
|
|||||||
CVector m_vecTurnSpeedAvg;
|
CVector m_vecTurnSpeedAvg;
|
||||||
float m_fMass;
|
float m_fMass;
|
||||||
float m_fTurnMass; // moment of inertia
|
float m_fTurnMass; // moment of inertia
|
||||||
float fForceMultiplier;
|
float m_fForceMultiplier;
|
||||||
float m_fAirResistance;
|
float m_fAirResistance;
|
||||||
float m_fElasticity;
|
float m_fElasticity;
|
||||||
float m_fBuoyancy;
|
float m_fBuoyancy;
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "World.h"
|
#include "World.h"
|
||||||
#include "Vehicle.h"
|
#include "Vehicle.h"
|
||||||
#include "Automobile.h"
|
#include "Automobile.h"
|
||||||
|
#include "Boat.h"
|
||||||
#include "Train.h"
|
#include "Train.h"
|
||||||
#include "Plane.h"
|
#include "Plane.h"
|
||||||
#include "Heli.h"
|
#include "Heli.h"
|
||||||
@ -80,9 +81,9 @@ RwObjectNameIdAssocation carIds[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
RwObjectNameIdAssocation boatIds[] = {
|
RwObjectNameIdAssocation boatIds[] = {
|
||||||
{ "boat_moving_hi", 1, VEHICLE_FLAG_COLLAPSE },
|
{ "boat_moving_hi", BOAT_MOVING, VEHICLE_FLAG_COLLAPSE },
|
||||||
{ "boat_rudder_hi", 3, VEHICLE_FLAG_COLLAPSE },
|
{ "boat_rudder_hi", BOAT_RUDDER, VEHICLE_FLAG_COLLAPSE },
|
||||||
{ "windscreen", 2, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_COLLAPSE },
|
{ "windscreen", BOAT_WINDSCREEN, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_COLLAPSE },
|
||||||
{ "ped_frontseat", BOAT_POS_FRONTSEAT, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
{ "ped_frontseat", BOAT_POS_FRONTSEAT, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
|
||||||
{ nil, 0, 0 }
|
{ nil, 0, 0 }
|
||||||
};
|
};
|
||||||
|
@ -667,7 +667,7 @@ CAutomobile::ProcessControl(void)
|
|||||||
if(!strongGrip1 && !CVehicle::bCheat3)
|
if(!strongGrip1 && !CVehicle::bCheat3)
|
||||||
gripCheat = false;
|
gripCheat = false;
|
||||||
float acceleration = pHandling->Transmission.CalculateDriveAcceleration(m_fGasPedal, m_nCurrentGear, m_fChangeGearTime, fwdSpeed, gripCheat);
|
float acceleration = pHandling->Transmission.CalculateDriveAcceleration(m_fGasPedal, m_nCurrentGear, m_fChangeGearTime, fwdSpeed, gripCheat);
|
||||||
acceleration /= fForceMultiplier;
|
acceleration /= m_fForceMultiplier;
|
||||||
|
|
||||||
// unused
|
// unused
|
||||||
if(GetModelIndex() == MI_MIAMI_RCBARON ||
|
if(GetModelIndex() == MI_MIAMI_RCBARON ||
|
||||||
@ -718,7 +718,7 @@ CAutomobile::ProcessControl(void)
|
|||||||
else
|
else
|
||||||
traction = 0.004f;
|
traction = 0.004f;
|
||||||
traction *= pHandling->fTractionMultiplier / 4.0f;
|
traction *= pHandling->fTractionMultiplier / 4.0f;
|
||||||
traction /= fForceMultiplier;
|
traction /= m_fForceMultiplier;
|
||||||
if(CVehicle::bCheat3)
|
if(CVehicle::bCheat3)
|
||||||
traction *= 4.0f;
|
traction *= 4.0f;
|
||||||
|
|
||||||
@ -3791,7 +3791,7 @@ CAutomobile::BlowUpCar(CEntity *culprit)
|
|||||||
}
|
}
|
||||||
ChangeLawEnforcerState(false);
|
ChangeLawEnforcerState(false);
|
||||||
|
|
||||||
gFireManager.StartFire(this, culprit, 0.8f, 1); // TODO
|
gFireManager.StartFire(this, culprit, 0.8f, true);
|
||||||
CDarkel::RegisterCarBlownUpByPlayer(this);
|
CDarkel::RegisterCarBlownUpByPlayer(this);
|
||||||
if(GetModelIndex() == MI_RCBANDIT)
|
if(GetModelIndex() == MI_RCBANDIT)
|
||||||
CExplosion::AddExplosion(this, culprit, EXPLOSION_CAR_QUICK, GetPosition(), 0);
|
CExplosion::AddExplosion(this, culprit, EXPLOSION_CAR_QUICK, GetPosition(), 0);
|
||||||
@ -4054,7 +4054,7 @@ CAutomobile::HasCarStoppedBecauseOfLight(void)
|
|||||||
if(ThePaths.m_connections[curnode->firstLink + i] == AutoPilot.m_nNextRouteNode)
|
if(ThePaths.m_connections[curnode->firstLink + i] == AutoPilot.m_nNextRouteNode)
|
||||||
break;
|
break;
|
||||||
if(i < curnode->numLinks &&
|
if(i < curnode->numLinks &&
|
||||||
ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3) // TODO
|
ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4064,7 +4064,7 @@ CAutomobile::HasCarStoppedBecauseOfLight(void)
|
|||||||
if(ThePaths.m_connections[curnode->firstLink + i] == AutoPilot.m_nPrevRouteNode)
|
if(ThePaths.m_connections[curnode->firstLink + i] == AutoPilot.m_nPrevRouteNode)
|
||||||
break;
|
break;
|
||||||
if(i < curnode->numLinks &&
|
if(i < curnode->numLinks &&
|
||||||
ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3) // TODO
|
ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,25 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "patcher.h"
|
#include "patcher.h"
|
||||||
#include "Boat.h"
|
#include "General.h"
|
||||||
|
#include "Timecycle.h"
|
||||||
#include "HandlingMgr.h"
|
#include "HandlingMgr.h"
|
||||||
|
#include "CarCtrl.h"
|
||||||
#include "RwHelper.h"
|
#include "RwHelper.h"
|
||||||
#include "ModelIndices.h"
|
#include "ModelIndices.h"
|
||||||
|
#include "VisibilityPlugins.h"
|
||||||
|
#include "DMAudio.h"
|
||||||
|
#include "Camera.h"
|
||||||
|
#include "Darkel.h"
|
||||||
|
#include "Explosion.h"
|
||||||
|
#include "Particle.h"
|
||||||
#include "WaterLevel.h"
|
#include "WaterLevel.h"
|
||||||
#include "Pools.h"
|
#include "Floater.h"
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
|
#include "Pools.h"
|
||||||
|
#include "Pad.h"
|
||||||
|
#include "Boat.h"
|
||||||
|
|
||||||
|
#define INVALID_ORIENTATION (-9999.99f)
|
||||||
|
|
||||||
float &fShapeLength = *(float*)0x600E78;
|
float &fShapeLength = *(float*)0x600E78;
|
||||||
float &fShapeTime = *(float*)0x600E7C;
|
float &fShapeTime = *(float*)0x600E7C;
|
||||||
@ -19,10 +32,6 @@ float WAKE_LIFETIME = 400.0f;
|
|||||||
|
|
||||||
CBoat * (&CBoat::apFrameWakeGeneratingBoats)[4] = *(CBoat * (*)[4])*(uintptr*)0x8620E0;
|
CBoat * (&CBoat::apFrameWakeGeneratingBoats)[4] = *(CBoat * (*)[4])*(uintptr*)0x8620E0;
|
||||||
|
|
||||||
WRAPPER void CBoat::ProcessControl() { EAXJMP(0x53EF10); }
|
|
||||||
WRAPPER void CBoat::ProcessControlInputs(uint8) { EAXJMP(0x53EC70); }
|
|
||||||
WRAPPER void CBoat::BlowUpCar(CEntity* ent) { EAXJMP(0x541CB0); }
|
|
||||||
|
|
||||||
CBoat::CBoat(int mi, uint8 owner) : CVehicle(owner)
|
CBoat::CBoat(int mi, uint8 owner) : CVehicle(owner)
|
||||||
{
|
{
|
||||||
CVehicleModelInfo *minfo = (CVehicleModelInfo*)CModelInfo::GetModelInfo(mi);
|
CVehicleModelInfo *minfo = (CVehicleModelInfo*)CModelInfo::GetModelInfo(mi);
|
||||||
@ -47,35 +56,31 @@ CBoat::CBoat(int mi, uint8 owner) : CVehicle(owner)
|
|||||||
m_fGasPedal = 0.0f;
|
m_fGasPedal = 0.0f;
|
||||||
m_fBrakePedal = 0.0f;
|
m_fBrakePedal = 0.0f;
|
||||||
|
|
||||||
field_288 = 0.25f;
|
m_fPropellerZ = 0.25f;
|
||||||
field_28C = 0.35f;
|
m_fPropellerY = 0.35f;
|
||||||
field_290 = 0.7f;
|
m_waterMoveDrag = CVector(0.7f, 0.998f, 0.999f);
|
||||||
field_294 = 0.998f;
|
m_waterTurnDrag = CVector(0.85f, 0.96f, 0.96f);
|
||||||
field_298 = 0.999f;
|
|
||||||
field_29C = 0.85f;
|
|
||||||
field_2A0 = 0.96f;
|
|
||||||
field_2A4 = 0.96f;
|
|
||||||
_unk2 = false;
|
_unk2 = false;
|
||||||
|
|
||||||
m_fTurnForceZ = 7.0f;
|
m_fVolumeUnderWater = 7.0f;
|
||||||
field_2FC = 7.0f;
|
m_fPrevVolumeUnderWater = 7.0f;
|
||||||
m_vecMoveForce = CVector(0.0f, 0.0f, 0.0f);
|
m_vecBuoyancePoint = CVector(0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
field_300 = 0;
|
m_nDeltaVolumeUnderWater = 0;
|
||||||
m_bBoatFlag1 = true;
|
bBoatInWater = true;
|
||||||
m_bBoatFlag2 = true;
|
bPropellerInWater = true;
|
||||||
|
|
||||||
bIsInWater = true;
|
bIsInWater = true;
|
||||||
|
|
||||||
unk1 = 0.0f;
|
unk1 = 0.0f;
|
||||||
m_bIsAnchored = true;
|
m_bIsAnchored = true;
|
||||||
field_2C4 = -9999.99f;
|
m_fOrientation = INVALID_ORIENTATION;
|
||||||
bTouchingWater = true;
|
bTouchingWater = true;
|
||||||
field_2CC = 0.0f;
|
m_fDamage = 0.0f;
|
||||||
field_2D0 = 0;
|
m_pSetOnFireEntity = nil;
|
||||||
m_nNumWakePoints = 0;
|
m_nNumWakePoints = 0;
|
||||||
|
|
||||||
for (int16 i = 0; i < 32; i++)
|
for (int16 i = 0; i < ARRAY_SIZE(m_afWakePointLifeTime); i++)
|
||||||
m_afWakePointLifeTime[i] = 0.0f;
|
m_afWakePointLifeTime[i] = 0.0f;
|
||||||
|
|
||||||
m_nAmmoInClip = 20;
|
m_nAmmoInClip = 20;
|
||||||
@ -94,6 +99,541 @@ CBoat::GetComponentWorldPosition(int32 component, CVector &pos)
|
|||||||
pos = *RwMatrixGetPos(RwFrameGetLTM(m_aBoatNodes[component]));
|
pos = *RwMatrixGetPos(RwFrameGetLTM(m_aBoatNodes[component]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CBoat::ProcessControl(void)
|
||||||
|
{
|
||||||
|
if(m_nZoneLevel > LEVEL_NONE && m_nZoneLevel != CCollision::ms_collisionInMemory)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool onLand = m_fDamageImpulse > 0.0f && m_vecDamageNormal.z > 0.1f;
|
||||||
|
|
||||||
|
PruneWakeTrail();
|
||||||
|
|
||||||
|
int r, g, b;
|
||||||
|
RwRGBA splashColor, jetColor;
|
||||||
|
r = 114.75f*(CTimeCycle::GetAmbientRed() + 0.5f*CTimeCycle::GetDirectionalRed());
|
||||||
|
g = 114.75f*(CTimeCycle::GetAmbientGreen() + 0.5f*CTimeCycle::GetDirectionalGreen());
|
||||||
|
b = 114.75f*(CTimeCycle::GetAmbientBlue() + 0.5f*CTimeCycle::GetDirectionalBlue());
|
||||||
|
r = clamp(r, 0, 255);
|
||||||
|
g = clamp(g, 0, 255);
|
||||||
|
b = clamp(b, 0, 255);
|
||||||
|
splashColor.red = r;
|
||||||
|
splashColor.green = g;
|
||||||
|
splashColor.blue = b;
|
||||||
|
splashColor.alpha = CGeneral::GetRandomNumberInRange(128, 150);
|
||||||
|
|
||||||
|
r = 242.25f*(CTimeCycle::GetAmbientRed() + 0.5f*CTimeCycle::GetDirectionalRed());
|
||||||
|
g = 242.25f*(CTimeCycle::GetAmbientGreen() + 0.5f*CTimeCycle::GetDirectionalGreen());
|
||||||
|
b = 242.25f*(CTimeCycle::GetAmbientBlue() + 0.5f*CTimeCycle::GetDirectionalBlue());
|
||||||
|
r = clamp(r, 0, 255);
|
||||||
|
g = clamp(g, 0, 255);
|
||||||
|
b = clamp(b, 0, 255);
|
||||||
|
jetColor.red = r;
|
||||||
|
jetColor.green = g;
|
||||||
|
jetColor.blue = b;
|
||||||
|
jetColor.alpha = CGeneral::GetRandomNumberInRange(96, 128);
|
||||||
|
|
||||||
|
CGeneral::GetRandomNumber(); // unused
|
||||||
|
|
||||||
|
ProcessCarAlarm();
|
||||||
|
|
||||||
|
switch(m_status){
|
||||||
|
case STATUS_PLAYER:
|
||||||
|
m_bIsAnchored = false;
|
||||||
|
m_fOrientation = INVALID_ORIENTATION;
|
||||||
|
ProcessControlInputs(0);
|
||||||
|
if(GetModelIndex() == MI_PREDATOR)
|
||||||
|
DoFixedMachineGuns();
|
||||||
|
break;
|
||||||
|
case STATUS_SIMPLE:
|
||||||
|
m_bIsAnchored = false;
|
||||||
|
m_fOrientation = INVALID_ORIENTATION;
|
||||||
|
CPhysical::ProcessControl();
|
||||||
|
bBoatInWater = true;
|
||||||
|
bPropellerInWater = true;
|
||||||
|
bIsInWater = true;
|
||||||
|
return;
|
||||||
|
case STATUS_PHYSICS:
|
||||||
|
m_bIsAnchored = false;
|
||||||
|
m_fOrientation = INVALID_ORIENTATION;
|
||||||
|
CCarCtrl::SteerAIBoatWithPhysics(this);
|
||||||
|
break;
|
||||||
|
case STATUS_ABANDONED:
|
||||||
|
case STATUS_WRECKED:
|
||||||
|
bBoatInWater = true;
|
||||||
|
bPropellerInWater = true;
|
||||||
|
bIsInWater = true;
|
||||||
|
m_fSteerAngle = 0.0;
|
||||||
|
bIsHandbrakeOn = false;
|
||||||
|
m_fBrakePedal = 0.5f;
|
||||||
|
m_fGasPedal = 0.0f;
|
||||||
|
if((GetPosition() - CWorld::Players[CWorld::PlayerInFocus].GetPos()).Magnitude() > 150.0f){
|
||||||
|
m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
|
||||||
|
m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
float collisionDamage = pHandling->fCollisionDamageMultiplier * m_fDamageImpulse;
|
||||||
|
if(collisionDamage > 25.0f && m_status != STATUS_WRECKED && m_fHealth >= 150.0f){
|
||||||
|
float prevHealth = m_fHealth;
|
||||||
|
if(this == FindPlayerVehicle()){
|
||||||
|
if(bTakeLessDamage)
|
||||||
|
m_fHealth -= (collisionDamage-25.0f)/6.0f;
|
||||||
|
else
|
||||||
|
m_fHealth -= (collisionDamage-25.0f)/2.0f;
|
||||||
|
}else{
|
||||||
|
if(collisionDamage > 60.0f && pDriver)
|
||||||
|
pDriver->Say(SOUND_PED_CAR_COLLISION);
|
||||||
|
if(bTakeLessDamage)
|
||||||
|
m_fHealth -= (collisionDamage-25.0f)/12.0f;
|
||||||
|
else
|
||||||
|
m_fHealth -= (collisionDamage-25.0f)/4.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_fHealth <= 0.0f && prevHealth > 0.0f){
|
||||||
|
m_fHealth = 1.0f;
|
||||||
|
m_pSetOnFireEntity = m_pDamageEntity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Damage particles
|
||||||
|
if(m_fHealth <= 600.0f && m_status != STATUS_WRECKED &&
|
||||||
|
Abs(GetPosition().x - TheCamera.GetPosition().x) < 200.0f &&
|
||||||
|
Abs(GetPosition().y - TheCamera.GetPosition().y) < 200.0f){
|
||||||
|
float speedSq = m_vecMoveSpeed.MagnitudeSqr();
|
||||||
|
CVector smokeDir = 0.8f*m_vecMoveSpeed;
|
||||||
|
CVector smokePos;
|
||||||
|
switch(GetModelIndex()){
|
||||||
|
case MI_SPEEDER:
|
||||||
|
smokePos = CVector(0.4f, -2.4f, 0.8f);
|
||||||
|
smokeDir += 0.05f*GetRight();
|
||||||
|
smokeDir.z += 0.2f*m_vecMoveSpeed.z;
|
||||||
|
break;
|
||||||
|
case MI_REEFER:
|
||||||
|
smokePos = CVector(2.0f, -1.0f, 0.5f);
|
||||||
|
smokeDir += 0.07f*GetRight();
|
||||||
|
break;
|
||||||
|
case MI_PREDATOR:
|
||||||
|
default:
|
||||||
|
smokePos = CVector(-1.5f, -0.5f, 1.2f);
|
||||||
|
smokeDir += -0.08f*GetRight();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
smokePos = GetMatrix() * smokePos;
|
||||||
|
|
||||||
|
// On fire
|
||||||
|
if(m_fHealth < 150.0f){
|
||||||
|
CParticle::AddParticle(PARTICLE_CARFLAME, smokePos,
|
||||||
|
CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(2.25f/200.0f, 0.09f)),
|
||||||
|
nil, 0.9f);
|
||||||
|
CVector smokePos2 = smokePos;
|
||||||
|
smokePos2.x += CGeneral::GetRandomNumberInRange(-2.25f/4.0f, 2.25f/4.0f);
|
||||||
|
smokePos2.y += CGeneral::GetRandomNumberInRange(-2.25f/4.0f, 2.25f/4.0f);
|
||||||
|
smokePos2.z += CGeneral::GetRandomNumberInRange(2.25f/4.0f, 2.25f);
|
||||||
|
CParticle::AddParticle(PARTICLE_ENGINE_SMOKE2, smokePos2, CVector(0.0f, 0.0f, 0.0f));
|
||||||
|
|
||||||
|
m_fDamage += CTimer::GetTimeStepInMilliseconds();
|
||||||
|
if(m_fDamage > 5000.0f)
|
||||||
|
BlowUpCar(m_pSetOnFireEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(speedSq < 0.25f && (CTimer::GetFrameCounter() + m_randomSeed) & 1)
|
||||||
|
CParticle::AddParticle(PARTICLE_ENGINE_STEAM, smokePos, smokeDir);
|
||||||
|
if(speedSq < 0.25f && m_fHealth <= 350.0f)
|
||||||
|
CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, smokePos, 1.25f*smokeDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
CPhysical::ProcessControl();
|
||||||
|
|
||||||
|
CVector buoyanceImpulse(0.0f, 0.0f, 0.0f);
|
||||||
|
CVector buoyancePoint(0.0f, 0.0f, 0.0f);
|
||||||
|
if(mod_Buoyancy.ProcessBuoyancy(this, pHandling->fBuoyancy, &buoyancePoint, &buoyanceImpulse)){
|
||||||
|
// Process boat in water
|
||||||
|
if(0.1f * m_fMass * GRAVITY*CTimer::GetTimeStep() < buoyanceImpulse.z){
|
||||||
|
bBoatInWater = true;
|
||||||
|
bIsInWater = true;
|
||||||
|
}else{
|
||||||
|
bBoatInWater = false;
|
||||||
|
bIsInWater = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fVolumeUnderWater = mod_Buoyancy.m_volumeUnderWater;
|
||||||
|
m_vecBuoyancePoint = buoyancePoint;
|
||||||
|
ApplyMoveForce(buoyanceImpulse);
|
||||||
|
if(!onLand)
|
||||||
|
ApplyTurnForce(buoyanceImpulse, buoyancePoint);
|
||||||
|
|
||||||
|
if(!onLand && bBoatInWater && GetUp().z > 0.0f){
|
||||||
|
float impulse;
|
||||||
|
if(m_fGasPedal > 0.05f)
|
||||||
|
impulse = m_vecMoveSpeed.MagnitudeSqr()*pHandling->fSuspensionForceLevel*buoyanceImpulse.z*CTimer::GetTimeStep()*0.5f*m_fGasPedal;
|
||||||
|
else
|
||||||
|
impulse = 0.0f;
|
||||||
|
impulse = min(impulse, GRAVITY*pHandling->fSuspensionDampingLevel*m_fMass*CTimer::GetTimeStep());
|
||||||
|
ApplyMoveForce(impulse*GetUp());
|
||||||
|
ApplyTurnForce(impulse*GetUp(), buoyancePoint - pHandling->fSuspensionBias*GetForward());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle boat moving forward
|
||||||
|
if(Abs(m_fGasPedal) > 0.05f || m_vecMoveSpeed.Magnitude() > 0.01f){
|
||||||
|
if(bBoatInWater)
|
||||||
|
AddWakePoint(GetPosition());
|
||||||
|
|
||||||
|
float steerFactor = 1.0f - DotProduct(m_vecMoveSpeed, GetForward());
|
||||||
|
if(m_modelIndex == MI_GHOST)
|
||||||
|
steerFactor = 1.0f - DotProduct(m_vecMoveSpeed, GetForward())*0.3f;
|
||||||
|
if(steerFactor < 0.0f) steerFactor = 0.0f;
|
||||||
|
|
||||||
|
CVector propeller(0.0f, -pHandling->Dimension.y*m_fPropellerY, -pHandling->Dimension.z*m_fPropellerZ);
|
||||||
|
propeller = Multiply3x3(GetMatrix(), propeller);
|
||||||
|
CVector propellerWorld = GetPosition() + propeller;
|
||||||
|
|
||||||
|
float steerSin = Sin(-m_fSteerAngle * steerFactor);
|
||||||
|
float steerCos = Cos(-m_fSteerAngle * steerFactor);
|
||||||
|
float waterLevel;
|
||||||
|
CWaterLevel::GetWaterLevel(propellerWorld, &waterLevel, true);
|
||||||
|
if(propellerWorld.z-0.5f < waterLevel){
|
||||||
|
float propellerDepth = waterLevel - (propellerWorld.z - 0.5f);
|
||||||
|
if(propellerDepth > 1.0f)
|
||||||
|
propellerDepth = 1.0f;
|
||||||
|
else
|
||||||
|
propellerDepth = SQR(propellerDepth);
|
||||||
|
bPropellerInWater = true;
|
||||||
|
|
||||||
|
if(Abs(m_fGasPedal) > 0.05f){
|
||||||
|
CVector forceDir = Multiply3x3(GetMatrix(), CVector(-steerSin, steerCos, -Abs(m_fSteerAngle)));
|
||||||
|
CVector force = propellerDepth * m_fGasPedal * 40.0f * pHandling->Transmission.fEngineAcceleration * pHandling->fMass * forceDir;
|
||||||
|
if(force.z > 0.2f)
|
||||||
|
force.z = SQR(1.2f - force.z) + 0.2f;
|
||||||
|
if(onLand){
|
||||||
|
if(m_fGasPedal < 0.0f){
|
||||||
|
force.x *= 5.0f;
|
||||||
|
force.y *= 5.0f;
|
||||||
|
}
|
||||||
|
if(force.z < 0.0f)
|
||||||
|
force.z = 0.0f;
|
||||||
|
ApplyMoveForce(force * CTimer::GetTimeStep());
|
||||||
|
}else{
|
||||||
|
ApplyMoveForce(force * CTimer::GetTimeStep());
|
||||||
|
ApplyTurnForce(force * CTimer::GetTimeStep(), propeller - pHandling->fTractionBias*GetUp());
|
||||||
|
float rightForce = DotProduct(GetRight(), force);
|
||||||
|
ApplyTurnForce(-rightForce*GetRight() * CTimer::GetTimeStep(), GetUp());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spray some particles
|
||||||
|
CVector jetDir = -0.04f * force;
|
||||||
|
if(m_fGasPedal > 0.0f){
|
||||||
|
if(m_status == STATUS_PLAYER){
|
||||||
|
bool cameraHack = TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN ||
|
||||||
|
TheCamera.WhoIsInControlOfTheCamera == CAMCONTROL_OBBE;
|
||||||
|
CVector sternPos = GetColModel()->boundingBox.min;
|
||||||
|
sternPos.x = 0.0f;
|
||||||
|
sternPos.z = 0.0f;
|
||||||
|
sternPos = Multiply3x3(GetMatrix(), sternPos);
|
||||||
|
|
||||||
|
CVector jetPos = GetPosition() + sternPos;
|
||||||
|
if(cameraHack)
|
||||||
|
jetPos.z = 1.0f;
|
||||||
|
else
|
||||||
|
jetPos.z = 0.0f;
|
||||||
|
|
||||||
|
CVector wakePos = GetPosition() + sternPos;
|
||||||
|
wakePos.z -= 0.65f;
|
||||||
|
|
||||||
|
CVector wakeDir = 0.75f * jetDir;
|
||||||
|
|
||||||
|
CParticle::AddParticle(PARTICLE_BOAT_THRUSTJET, jetPos, jetDir, nil, 0.0f, jetColor);
|
||||||
|
CParticle::AddParticle(PARTICLE_CAR_SPLASH, jetPos, 0.25f * jetDir, nil, 1.0f, splashColor,
|
||||||
|
CGeneral::GetRandomNumberInRange(0, 30),
|
||||||
|
CGeneral::GetRandomNumberInRange(0, 90), 3);
|
||||||
|
if(!cameraHack)
|
||||||
|
CParticle::AddParticle(PARTICLE_BOAT_WAKE, wakePos, wakeDir, nil, 0.0f, jetColor);
|
||||||
|
}else if((CTimer::GetFrameCounter() + m_randomSeed) & 1){
|
||||||
|
jetDir.z = 0.018f;
|
||||||
|
jetDir.x *= 0.01f;
|
||||||
|
jetDir.y *= 0.01f;
|
||||||
|
propellerWorld.z += 1.5f;
|
||||||
|
|
||||||
|
CParticle::AddParticle(PARTICLE_BOAT_SPLASH, propellerWorld, jetDir, nil, 1.5f, jetColor);
|
||||||
|
CParticle::AddParticle(PARTICLE_CAR_SPLASH, propellerWorld, 0.1f * jetDir, nil, 0.5f, splashColor,
|
||||||
|
CGeneral::GetRandomNumberInRange(0, 30),
|
||||||
|
CGeneral::GetRandomNumberInRange(0, 90), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else if(!onLand){
|
||||||
|
float force = 50.0f*DotProduct(m_vecMoveSpeed, GetForward());
|
||||||
|
if(force > 10.0f) force = 10.0f;
|
||||||
|
CVector propellerForce = propellerDepth * Multiply3x3(GetMatrix(), force*CVector(-steerSin, 0.0f, 0.0f));
|
||||||
|
ApplyMoveForce(propellerForce * CTimer::GetTimeStep()*0.5f);
|
||||||
|
ApplyTurnForce(propellerForce * CTimer::GetTimeStep()*0.5f, propeller);
|
||||||
|
}
|
||||||
|
}else
|
||||||
|
bPropellerInWater = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slow down or push down boat as it approaches the world limits
|
||||||
|
m_vecMoveSpeed.x = min(m_vecMoveSpeed.x, -(GetPosition().x - 1900.0f)*0.01f); // east
|
||||||
|
m_vecMoveSpeed.x = max(m_vecMoveSpeed.x, -(GetPosition().x - -1515.0f)*0.01f); // west
|
||||||
|
m_vecMoveSpeed.y = min(m_vecMoveSpeed.y, -(GetPosition().y - 600.0f)*0.01f); // north
|
||||||
|
m_vecMoveSpeed.y = max(m_vecMoveSpeed.y, -(GetPosition().y - -1900.0f)*0.01f); // south
|
||||||
|
|
||||||
|
if(!onLand && bBoatInWater)
|
||||||
|
ApplyWaterResistance();
|
||||||
|
|
||||||
|
// No idea what exactly is going on here besides drag in YZ
|
||||||
|
float fx = Pow(m_waterTurnDrag.x, CTimer::GetTimeStep());
|
||||||
|
float fy = Pow(m_waterTurnDrag.y, CTimer::GetTimeStep());
|
||||||
|
float fz = Pow(m_waterTurnDrag.z, CTimer::GetTimeStep());
|
||||||
|
m_vecTurnSpeed = Multiply3x3(m_vecTurnSpeed, GetMatrix()); // invert - to local space
|
||||||
|
// TODO: figure this out
|
||||||
|
float magic = 1.0f/(1000.0f * SQR(m_vecTurnSpeed.x) + 1.0f) * fx;
|
||||||
|
m_vecTurnSpeed.y *= fy;
|
||||||
|
m_vecTurnSpeed.z *= fz;
|
||||||
|
float forceUp = (magic - 1.0f) * m_vecTurnSpeed.x * m_fTurnMass;
|
||||||
|
m_vecTurnSpeed = Multiply3x3(GetMatrix(), m_vecTurnSpeed); // back to world
|
||||||
|
CVector com = Multiply3x3(GetMatrix(), m_vecCentreOfMass);
|
||||||
|
ApplyTurnForce(CVector(0.0f, 0.0f, forceUp), com + GetForward());
|
||||||
|
|
||||||
|
m_nDeltaVolumeUnderWater = (m_fVolumeUnderWater-m_fPrevVolumeUnderWater)*10000;
|
||||||
|
|
||||||
|
// Falling into water
|
||||||
|
if(!onLand && bBoatInWater && GetUp().z > 0.0f && m_nDeltaVolumeUnderWater > 200){
|
||||||
|
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_SPLASH, m_nDeltaVolumeUnderWater);
|
||||||
|
|
||||||
|
float speedUp = m_vecMoveSpeed.MagnitudeSqr() * m_nDeltaVolumeUnderWater * 0.0004f;
|
||||||
|
if(speedUp + m_vecMoveSpeed.z > pHandling->fBrakeDeceleration)
|
||||||
|
speedUp = pHandling->fBrakeDeceleration - m_vecMoveSpeed.z;
|
||||||
|
if(speedUp < 0.0f) speedUp = 0.0f;
|
||||||
|
float speedFwd = DotProduct(m_vecMoveSpeed, GetForward());
|
||||||
|
speedFwd *= -m_nDeltaVolumeUnderWater * 0.01f * pHandling->fTractionLoss;
|
||||||
|
CVector speed = speedFwd*GetForward() + CVector(0.0f, 0.0f, speedUp);
|
||||||
|
CVector splashImpulse = speed * m_fMass;
|
||||||
|
ApplyMoveForce(splashImpulse);
|
||||||
|
ApplyTurnForce(splashImpulse, buoyancePoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spray particles on sides of boat
|
||||||
|
if(m_nDeltaVolumeUnderWater > 75){
|
||||||
|
float speed = m_vecMoveSpeed.Magnitude();
|
||||||
|
float splash1Size = speed;
|
||||||
|
float splash2Size = m_nDeltaVolumeUnderWater * 0.005f * 0.2f;
|
||||||
|
float front = 0.9f * GetColModel()->boundingBox.max.y;
|
||||||
|
if(splash1Size > 0.75f) splash1Size = 0.75f;
|
||||||
|
|
||||||
|
CVector dir, pos;
|
||||||
|
|
||||||
|
// right
|
||||||
|
dir = -0.5f*m_vecMoveSpeed;
|
||||||
|
dir.z += 0.1f*speed;
|
||||||
|
dir += 0.5f*GetRight()*speed;
|
||||||
|
pos = front*GetForward() + 0.5f*GetRight() + GetPosition() + m_vecBuoyancePoint;
|
||||||
|
CWaterLevel::GetWaterLevel(pos, &pos.z, true);
|
||||||
|
CParticle::AddParticle(PARTICLE_CAR_SPLASH, pos, 0.75f * dir, nil, splash1Size, splashColor,
|
||||||
|
CGeneral::GetRandomNumberInRange(0, 30),
|
||||||
|
CGeneral::GetRandomNumberInRange(0, 90), 1);
|
||||||
|
CParticle::AddParticle(PARTICLE_BOAT_SPLASH, pos, dir, nil, splash2Size, jetColor);
|
||||||
|
|
||||||
|
// left
|
||||||
|
dir = -0.5f*m_vecMoveSpeed;
|
||||||
|
dir.z += 0.1f*speed;
|
||||||
|
dir -= 0.5f*GetRight()*speed;
|
||||||
|
pos = front*GetForward() - 0.5f*GetRight() + GetPosition() + m_vecBuoyancePoint;
|
||||||
|
CWaterLevel::GetWaterLevel(pos, &pos.z, true);
|
||||||
|
CParticle::AddParticle(PARTICLE_CAR_SPLASH, pos, 0.75f * dir, nil, splash1Size, splashColor,
|
||||||
|
CGeneral::GetRandomNumberInRange(0, 30),
|
||||||
|
CGeneral::GetRandomNumberInRange(0, 90), 1);
|
||||||
|
CParticle::AddParticle(PARTICLE_BOAT_SPLASH, pos, dir, nil, splash2Size, jetColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fPrevVolumeUnderWater = m_fVolumeUnderWater;
|
||||||
|
}else{
|
||||||
|
bBoatInWater = false;
|
||||||
|
bIsInWater = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_bIsAnchored){
|
||||||
|
m_vecMoveSpeed.x = 0.0f;
|
||||||
|
m_vecMoveSpeed.y = 0.0f;
|
||||||
|
|
||||||
|
if(m_fOrientation == INVALID_ORIENTATION){
|
||||||
|
m_fOrientation = GetForward().Heading();
|
||||||
|
}else{
|
||||||
|
// is this some inlined CPlaceable method?
|
||||||
|
CVector pos = GetPosition();
|
||||||
|
GetMatrix().RotateZ(m_fOrientation - GetForward().Heading());
|
||||||
|
GetPosition() = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessDelayedExplosion();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CBoat::ProcessControlInputs(uint8 pad)
|
||||||
|
{
|
||||||
|
m_nPadID = pad;
|
||||||
|
if(m_nPadID > 3)
|
||||||
|
m_nPadID = 3;
|
||||||
|
|
||||||
|
m_fBrake += (CPad::GetPad(pad)->GetBrake()/255.0f - m_fBrake)*0.1f;
|
||||||
|
m_fBrake = clamp(m_fBrake, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
if(m_fBrake < 0.05f){
|
||||||
|
m_fBrake = 0.0f;
|
||||||
|
m_fAccelerate += (CPad::GetPad(pad)->GetAccelerate()/255.0f - m_fAccelerate)*0.1f;
|
||||||
|
m_fAccelerate = clamp(m_fAccelerate, 0.0f, 1.0f);
|
||||||
|
}else
|
||||||
|
m_fAccelerate = -m_fBrake*0.2f;
|
||||||
|
|
||||||
|
m_fSteeringLeftRight += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteeringLeftRight)*0.2f;
|
||||||
|
m_fSteeringLeftRight = clamp(m_fSteeringLeftRight, -1.0f, 1.0f);
|
||||||
|
|
||||||
|
float steeringSq = m_fSteeringLeftRight < 0.0f ? -SQR(m_fSteeringLeftRight) : SQR(m_fSteeringLeftRight);
|
||||||
|
m_fSteerAngle = pHandling->fSteeringLock * DEGTORAD(steeringSq);
|
||||||
|
m_fGasPedal = m_fAccelerate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CBoat::ApplyWaterResistance(void)
|
||||||
|
{
|
||||||
|
float fwdSpeed = DotProduct(GetMoveSpeed(), GetForward());
|
||||||
|
// TODO: figure out how this works
|
||||||
|
float magic = (SQR(fwdSpeed) + 0.05f) * (0.001f * SQR(m_fVolumeUnderWater) * m_fMass) + 1.0f;
|
||||||
|
magic = Abs(magic);
|
||||||
|
// FRAMETIME
|
||||||
|
float fx = Pow(m_waterMoveDrag.x/magic, 0.5f*CTimer::GetTimeStep());
|
||||||
|
float fy = Pow(m_waterMoveDrag.y/magic, 0.5f*CTimer::GetTimeStep());
|
||||||
|
float fz = Pow(m_waterMoveDrag.z/magic, 0.5f*CTimer::GetTimeStep());
|
||||||
|
|
||||||
|
m_vecMoveSpeed = Multiply3x3(m_vecMoveSpeed, GetMatrix()); // invert - to local space
|
||||||
|
m_vecMoveSpeed.x *= fx;
|
||||||
|
m_vecMoveSpeed.y *= fy;
|
||||||
|
m_vecMoveSpeed.z *= fz;
|
||||||
|
float force = (fy - 1.0f) * m_vecMoveSpeed.y * m_fMass;
|
||||||
|
m_vecMoveSpeed = Multiply3x3(GetMatrix(), m_vecMoveSpeed); // back to world
|
||||||
|
|
||||||
|
ApplyTurnForce(force*GetForward(), -GetUp());
|
||||||
|
|
||||||
|
if(m_vecMoveSpeed.z > 0.0f)
|
||||||
|
m_vecMoveSpeed.z *= fz;
|
||||||
|
else
|
||||||
|
m_vecMoveSpeed.z *= (1.0f - fz)*0.5f + fz;
|
||||||
|
}
|
||||||
|
|
||||||
|
RwObject*
|
||||||
|
GetBoatAtomicObjectCB(RwObject *object, void *data)
|
||||||
|
{
|
||||||
|
RpAtomic *atomic = (RpAtomic*)object;
|
||||||
|
assert(RwObjectGetType(object) == rpATOMIC);
|
||||||
|
if(RpAtomicGetFlags(atomic) & rpATOMICRENDER)
|
||||||
|
*(RpAtomic**)data = atomic;
|
||||||
|
return object;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CBoat::BlowUpCar(CEntity *culprit)
|
||||||
|
{
|
||||||
|
RpAtomic *atomic;
|
||||||
|
RwFrame *frame;
|
||||||
|
RwMatrix *matrix;
|
||||||
|
CObject *obj;
|
||||||
|
|
||||||
|
if(!bCanBeDamaged)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// explosion pushes vehicle up
|
||||||
|
m_vecMoveSpeed.z += 0.13f;
|
||||||
|
m_status = STATUS_WRECKED;
|
||||||
|
bRenderScorched = true;
|
||||||
|
|
||||||
|
m_fHealth = 0.0;
|
||||||
|
m_nBombTimer = 0;
|
||||||
|
TheCamera.CamShake(0.7f, GetPosition().x, GetPosition().y, GetPosition().z);
|
||||||
|
|
||||||
|
if(this == FindPlayerVehicle())
|
||||||
|
FindPlayerPed()->m_fHealth = 0.0f; // kill player
|
||||||
|
if(pDriver){
|
||||||
|
CDarkel::RegisterKillByPlayer(pDriver, WEAPONTYPE_EXPLOSION);
|
||||||
|
pDriver->SetDead();
|
||||||
|
pDriver->FlagToDestroyWhenNextProcessed();
|
||||||
|
}
|
||||||
|
|
||||||
|
bEngineOn = false;
|
||||||
|
bLightsOn = false;
|
||||||
|
ChangeLawEnforcerState(false);
|
||||||
|
|
||||||
|
CExplosion::AddExplosion(this, culprit, EXPLOSION_CAR, GetPosition(), 0);
|
||||||
|
if(m_aBoatNodes[BOAT_MOVING] == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// much like CAutomobile::SpawnFlyingComponent from here on
|
||||||
|
|
||||||
|
atomic = nil;
|
||||||
|
RwFrameForAllObjects(m_aBoatNodes[BOAT_MOVING], GetBoatAtomicObjectCB, &atomic);
|
||||||
|
if(atomic == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
obj = new CObject();
|
||||||
|
if(obj == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
obj->SetModelIndexNoCreate(MI_CAR_WHEEL);
|
||||||
|
|
||||||
|
// object needs base model
|
||||||
|
obj->RefModelInfo(GetModelIndex());
|
||||||
|
|
||||||
|
// create new atomic
|
||||||
|
matrix = RwFrameGetLTM(m_aBoatNodes[BOAT_MOVING]);
|
||||||
|
frame = RwFrameCreate();
|
||||||
|
atomic = RpAtomicClone(atomic);
|
||||||
|
*RwFrameGetMatrix(frame) = *matrix;
|
||||||
|
RpAtomicSetFrame(atomic, frame);
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
|
||||||
|
obj->AttachToRwObject((RwObject*)atomic);
|
||||||
|
|
||||||
|
// init object
|
||||||
|
obj->m_fMass = 10.0f;
|
||||||
|
obj->m_fTurnMass = 25.0f;
|
||||||
|
obj->m_fAirResistance = 0.99f;
|
||||||
|
obj->m_fElasticity = 0.1f;
|
||||||
|
obj->m_fBuoyancy = obj->m_fMass*GRAVITY/0.75f;
|
||||||
|
obj->ObjectCreatedBy = TEMP_OBJECT;
|
||||||
|
obj->bIsStatic = false;
|
||||||
|
obj->bIsPickup = false;
|
||||||
|
|
||||||
|
// life time
|
||||||
|
CObject::nNoTempObjects++;
|
||||||
|
obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 20000;
|
||||||
|
|
||||||
|
obj->m_vecMoveSpeed = m_vecMoveSpeed;
|
||||||
|
if(GetUp().z > 0.0f)
|
||||||
|
obj->m_vecMoveSpeed.z = 0.3f;
|
||||||
|
else
|
||||||
|
obj->m_vecMoveSpeed.z = 0.0f;
|
||||||
|
|
||||||
|
obj->m_vecTurnSpeed = m_vecTurnSpeed*2.0f;
|
||||||
|
obj->m_vecTurnSpeed.x = 0.5f;
|
||||||
|
|
||||||
|
// push component away from boat
|
||||||
|
CVector dist = obj->GetPosition() - GetPosition();
|
||||||
|
dist.Normalise();
|
||||||
|
if(GetUp().z > 0.0f)
|
||||||
|
dist += GetUp();
|
||||||
|
obj->GetPosition() += GetUp();
|
||||||
|
|
||||||
|
CWorld::Add(obj);
|
||||||
|
|
||||||
|
atomic = nil;
|
||||||
|
RwFrameForAllObjects(m_aBoatNodes[BOAT_MOVING], GetBoatAtomicObjectCB, &atomic);
|
||||||
|
if(atomic)
|
||||||
|
RpAtomicSetFlags(atomic, 0);
|
||||||
|
}
|
||||||
|
|
||||||
RwIm3DVertex KeepWaterOutVertices[4];
|
RwIm3DVertex KeepWaterOutVertices[4];
|
||||||
RwImVertexIndex KeepWaterOutIndices[6];
|
RwImVertexIndex KeepWaterOutIndices[6];
|
||||||
|
|
||||||
@ -102,8 +642,8 @@ CBoat::Render()
|
|||||||
{
|
{
|
||||||
CMatrix matrix;
|
CMatrix matrix;
|
||||||
|
|
||||||
if (m_aBoatNodes[1] != nil) {
|
if (m_aBoatNodes[BOAT_MOVING] != nil) {
|
||||||
matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[1]));
|
matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_MOVING]));
|
||||||
|
|
||||||
CVector pos = matrix.GetPosition();
|
CVector pos = matrix.GetPosition();
|
||||||
matrix.SetRotateZ(m_fMovingHiRotation);
|
matrix.SetRotateZ(m_fMovingHiRotation);
|
||||||
@ -111,7 +651,7 @@ CBoat::Render()
|
|||||||
|
|
||||||
matrix.UpdateRW();
|
matrix.UpdateRW();
|
||||||
if (CVehicle::bWheelsOnlyCheat) {
|
if (CVehicle::bWheelsOnlyCheat) {
|
||||||
RpAtomicRender((RpAtomic*)GetFirstObject(m_aBoatNodes[1]));
|
RpAtomicRender((RpAtomic*)GetFirstObject(m_aBoatNodes[BOAT_MOVING]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_fMovingHiRotation += 0.05f;
|
m_fMovingHiRotation += 0.05f;
|
||||||
@ -234,10 +774,9 @@ CBoat::IsVertexAffectedByWake(CVector vecVertex, CBoat *pBoat)
|
|||||||
void
|
void
|
||||||
CBoat::SetupModelNodes()
|
CBoat::SetupModelNodes()
|
||||||
{
|
{
|
||||||
m_aBoatNodes[0] = nil;
|
int i;
|
||||||
m_aBoatNodes[1] = nil;
|
for(i = 0; i < ARRAY_SIZE(m_aBoatNodes); i++)
|
||||||
m_aBoatNodes[2] = nil;
|
m_aBoatNodes[i] = nil;
|
||||||
m_aBoatNodes[3] = nil;
|
|
||||||
CClumpModelInfo::FillFrameArray(GetClump(), m_aBoatNodes);
|
CClumpModelInfo::FillFrameArray(GetClump(), m_aBoatNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,6 +814,43 @@ CBoat::FillBoatList()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CBoat::PruneWakeTrail(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < ARRAY_SIZE(m_afWakePointLifeTime); i++){
|
||||||
|
if(m_afWakePointLifeTime[i] <= 0.0f)
|
||||||
|
break;
|
||||||
|
if(m_afWakePointLifeTime[i] <= CTimer::GetTimeStep()){
|
||||||
|
m_afWakePointLifeTime[i] = 0.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_afWakePointLifeTime[i] -= CTimer::GetTimeStep();
|
||||||
|
}
|
||||||
|
m_nNumWakePoints = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CBoat::AddWakePoint(CVector point)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if(m_afWakePointLifeTime[0] > 0.0f){
|
||||||
|
if((CVector2D(GetPosition()) - m_avec2dWakePoints[0]).MagnitudeSqr() < SQR(1.0f)){
|
||||||
|
for(i = min(m_nNumWakePoints, ARRAY_SIZE(m_afWakePointLifeTime)-1); i != 0; i--){
|
||||||
|
m_avec2dWakePoints[i] = m_avec2dWakePoints[i-1];
|
||||||
|
m_afWakePointLifeTime[i] = m_afWakePointLifeTime[i-1];
|
||||||
|
}
|
||||||
|
m_avec2dWakePoints[0] = point;
|
||||||
|
m_afWakePointLifeTime[0] = 400.0f;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
m_avec2dWakePoints[0] = point;
|
||||||
|
m_afWakePointLifeTime[0] = 400.0f;
|
||||||
|
m_nNumWakePoints = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
class CBoat_ : public CBoat
|
class CBoat_ : public CBoat
|
||||||
@ -291,4 +867,7 @@ STARTPATCHES
|
|||||||
InjectHook(0x542370, CBoat::IsSectorAffectedByWake, PATCH_JUMP);
|
InjectHook(0x542370, CBoat::IsSectorAffectedByWake, PATCH_JUMP);
|
||||||
InjectHook(0x5424A0, CBoat::IsVertexAffectedByWake, PATCH_JUMP);
|
InjectHook(0x5424A0, CBoat::IsVertexAffectedByWake, PATCH_JUMP);
|
||||||
InjectHook(0x542250, CBoat::FillBoatList, PATCH_JUMP);
|
InjectHook(0x542250, CBoat::FillBoatList, PATCH_JUMP);
|
||||||
|
InjectHook(0x542140, &CBoat::AddWakePoint, PATCH_JUMP);
|
||||||
|
InjectHook(0x5420D0, &CBoat::PruneWakeTrail, PATCH_JUMP);
|
||||||
|
InjectHook(0x541A30, &CBoat::ApplyWaterResistance, PATCH_JUMP);
|
||||||
ENDPATCHES
|
ENDPATCHES
|
||||||
|
@ -2,47 +2,41 @@
|
|||||||
|
|
||||||
#include "Vehicle.h"
|
#include "Vehicle.h"
|
||||||
|
|
||||||
|
enum eBoatNodes
|
||||||
|
{
|
||||||
|
BOAT_MOVING = 1,
|
||||||
|
BOAT_RUDDER,
|
||||||
|
BOAT_WINDSCREEN
|
||||||
|
};
|
||||||
|
|
||||||
class CBoat : public CVehicle
|
class CBoat : public CVehicle
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// 0x288
|
// 0x288
|
||||||
float field_288;
|
float m_fPropellerZ;
|
||||||
float field_28C;
|
float m_fPropellerY;
|
||||||
float field_290;
|
CVector m_waterMoveDrag;
|
||||||
float field_294;
|
CVector m_waterTurnDrag;
|
||||||
float field_298;
|
|
||||||
float field_29C;
|
|
||||||
float field_2A0;
|
|
||||||
float field_2A4;
|
|
||||||
float m_fMovingHiRotation;
|
float m_fMovingHiRotation;
|
||||||
int32 _unk0;
|
int32 _unk0;
|
||||||
RwFrame *m_aBoatNodes[4];
|
RwFrame *m_aBoatNodes[4];
|
||||||
uint8 m_bBoatFlag1 : 1;
|
uint8 bBoatInWater : 1;
|
||||||
uint8 m_bBoatFlag2 : 1;
|
uint8 bPropellerInWater : 1;
|
||||||
uint8 m_bBoatFlag3 : 1;
|
|
||||||
uint8 m_bBoatFlag4 : 1;
|
|
||||||
uint8 m_bBoatFlag5 : 1;
|
|
||||||
uint8 m_bBoatFlag6 : 1;
|
|
||||||
uint8 m_bBoatFlag7 : 1;
|
|
||||||
uint8 m_bBoatFlag8 : 1;
|
|
||||||
bool m_bIsAnchored;
|
bool m_bIsAnchored;
|
||||||
char _pad0[2];
|
float m_fOrientation;
|
||||||
float field_2C4;
|
|
||||||
int32 _unk1;
|
int32 _unk1;
|
||||||
float field_2CC;
|
float m_fDamage;
|
||||||
CEntity *field_2D0;
|
CEntity *m_pSetOnFireEntity;
|
||||||
bool _unk2;
|
bool _unk2;
|
||||||
char _pad1[3];
|
|
||||||
float m_fAccelerate;
|
float m_fAccelerate;
|
||||||
float m_fBrake;
|
float m_fBrake;
|
||||||
float m_fSteeringLeftRight;
|
float m_fSteeringLeftRight;
|
||||||
uint8 m_nPadID;
|
uint8 m_nPadID;
|
||||||
char _pad2[3];
|
|
||||||
int32 _unk3;
|
int32 _unk3;
|
||||||
float m_fTurnForceZ;
|
float m_fVolumeUnderWater;
|
||||||
CVector m_vecMoveForce;
|
CVector m_vecBuoyancePoint;
|
||||||
float field_2FC;
|
float m_fPrevVolumeUnderWater;
|
||||||
uint16 field_300;
|
int16 m_nDeltaVolumeUnderWater;
|
||||||
uint16 m_nNumWakePoints;
|
uint16 m_nNumWakePoints;
|
||||||
CVector2D m_avec2dWakePoints[32];
|
CVector2D m_avec2dWakePoints[32];
|
||||||
float m_afWakePointLifeTime[32];
|
float m_afWakePointLifeTime[32];
|
||||||
@ -59,7 +53,10 @@ public:
|
|||||||
virtual bool IsComponentPresent(int32 component) { return true; }
|
virtual bool IsComponentPresent(int32 component) { return true; }
|
||||||
virtual void BlowUpCar(CEntity *ent);
|
virtual void BlowUpCar(CEntity *ent);
|
||||||
|
|
||||||
|
void ApplyWaterResistance(void);
|
||||||
void SetupModelNodes();
|
void SetupModelNodes();
|
||||||
|
void PruneWakeTrail(void);
|
||||||
|
void AddWakePoint(CVector point);
|
||||||
|
|
||||||
static CBoat *(&apFrameWakeGeneratingBoats)[4];
|
static CBoat *(&apFrameWakeGeneratingBoats)[4];
|
||||||
|
|
||||||
|
@ -481,6 +481,55 @@ CVehicle::InflictDamage(CEntity* damagedBy, eWeaponType weaponType, float damage
|
|||||||
FindPlayerPed()->SetWantedLevelNoDrop(1);
|
FindPlayerPed()->SetWantedLevelNoDrop(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CVehicle::DoFixedMachineGuns(void)
|
||||||
|
{
|
||||||
|
if(CPad::GetPad(0)->GetCarGunFired() && !bGunSwitchedOff){
|
||||||
|
if(CTimer::GetTimeInMilliseconds() > m_nGunFiringTime + 150){
|
||||||
|
CVector source, target;
|
||||||
|
float dx, dy, len;
|
||||||
|
|
||||||
|
dx = GetForward().x;
|
||||||
|
dy = GetForward().y;
|
||||||
|
len = Sqrt(SQR(dx) + SQR(dy));
|
||||||
|
if(len < 0.1f) len = 0.1f;
|
||||||
|
dx /= len;
|
||||||
|
dy /= len;
|
||||||
|
|
||||||
|
m_nGunFiringTime = CTimer::GetTimeInMilliseconds();
|
||||||
|
|
||||||
|
source = GetMatrix() * CVector(2.0f, 2.5f, 1.0f);
|
||||||
|
target = source + CVector(dx, dy, 0.0f)*60.0f;
|
||||||
|
target += CVector(
|
||||||
|
((CGeneral::GetRandomNumber()&0xFF)-128) * 0.015f,
|
||||||
|
((CGeneral::GetRandomNumber()&0xFF)-128) * 0.015f,
|
||||||
|
((CGeneral::GetRandomNumber()&0xFF)-128) * 0.02f);
|
||||||
|
CWeapon::DoTankDoomAiming(this, pDriver, &source, &target);
|
||||||
|
FireOneInstantHitRound(&source, &target, 15);
|
||||||
|
|
||||||
|
source = GetMatrix() * CVector(-2.0f, 2.5f, 1.0f);
|
||||||
|
target = source + CVector(dx, dy, 0.0f)*60.0f;
|
||||||
|
target += CVector(
|
||||||
|
((CGeneral::GetRandomNumber()&0xFF)-128) * 0.015f,
|
||||||
|
((CGeneral::GetRandomNumber()&0xFF)-128) * 0.015f,
|
||||||
|
((CGeneral::GetRandomNumber()&0xFF)-128) * 0.02f);
|
||||||
|
CWeapon::DoTankDoomAiming(this, pDriver, &source, &target);
|
||||||
|
FireOneInstantHitRound(&source, &target, 15);
|
||||||
|
|
||||||
|
DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_SHOT_FIRED, 0.0f);
|
||||||
|
|
||||||
|
m_nAmmoInClip--;
|
||||||
|
if(m_nAmmoInClip == 0){
|
||||||
|
m_nAmmoInClip = 20;
|
||||||
|
m_nGunFiringTime = CTimer::GetTimeInMilliseconds() + 1400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(CTimer::GetTimeInMilliseconds() > m_nGunFiringTime + 1400)
|
||||||
|
m_nAmmoInClip = 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CVehicle::ExtinguishCarFire(void)
|
CVehicle::ExtinguishCarFire(void)
|
||||||
{
|
{
|
||||||
|
@ -269,6 +269,7 @@ public:
|
|||||||
bool IsSphereTouchingVehicle(float sx, float sy, float sz, float radius);
|
bool IsSphereTouchingVehicle(float sx, float sy, float sz, float radius);
|
||||||
bool ShufflePassengersToMakeSpace(void);
|
bool ShufflePassengersToMakeSpace(void);
|
||||||
void InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage);
|
void InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage);
|
||||||
|
void DoFixedMachineGuns(void);
|
||||||
|
|
||||||
bool IsAlarmOn(void) { return m_nAlarmState != 0 && m_nAlarmState != -1; }
|
bool IsAlarmOn(void) { return m_nAlarmState != 0 && m_nAlarmState != -1; }
|
||||||
CVehicleModelInfo* GetModelInfo() { return (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); }
|
CVehicleModelInfo* GetModelInfo() { return (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); }
|
||||||
|
Loading…
Reference in New Issue
Block a user