CAutomobile::FireTruckControl and HydraulicControl

This commit is contained in:
aap 2019-07-26 14:27:13 +02:00
parent 7d6a04b5c6
commit 9a50a59a3c
12 changed files with 373 additions and 20 deletions

View File

@ -20,9 +20,9 @@ enum eSound : int16
SOUND_F = 15,
SOUND_CAR_ENGINE_START = 16,
SOUND_CAR_LIGHT_BREAK = 17,
SOUND_CAR_HYDRALIC_1 = 18,
SOUND_CAR_HYDRALIC_2 = 19,
SOUND_CAR_HYDRALIC_3 = 20,
SOUND_CAR_HYDRAULIC_1 = 18,
SOUND_CAR_HYDRAULIC_2 = 19,
SOUND_CAR_HYDRAULIC_3 = 20,
SOUND_CAR_JERK = 21,
SOUND_CAR_SPLASH = 22,
SOUND_17 = 23,

View File

@ -2023,11 +2023,11 @@ CColModel::operator=(const CColModel &other)
numVerts = 0;
for(i = 0; i < other.numTriangles; i++){
if(other.triangles[i].a > numVerts)
other.triangles[i].a = numVerts;
numVerts = other.triangles[i].a;
if(other.triangles[i].b > numVerts)
other.triangles[i].b = numVerts;
numVerts = other.triangles[i].b;
if(other.triangles[i].c > numVerts)
other.triangles[i].c = numVerts;
numVerts = other.triangles[i].c;
}
numVerts++;
if(vertices)

View File

@ -7,3 +7,4 @@ CFireManager &gFireManager = *(CFireManager*)0x8F31D0;
WRAPPER void CFire::Extinguish(void) { EAXJMP(0x479D40); }
WRAPPER void CFireManager::StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32) { EAXJMP(0x479590); }
WRAPPER CFire *CFireManager::FindFurthestFire_NeverMindFireMen(CVector coors, float, float) { EAXJMP(0x479430); }

View File

@ -4,6 +4,7 @@ class CEntity;
class CFire
{
public:
bool m_bIsOngoing;
bool m_bExists;
bool m_bPropogationFlag;
@ -18,7 +19,6 @@ class CFire
int field_28;
float field_2C;
public:
void Extinguish(void);
};
@ -26,5 +26,6 @@ class CFireManager
{
public:
void StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32);
CFire *FindFurthestFire_NeverMindFireMen(CVector coors, float, float);
};
extern CFireManager &gFireManager;

View File

@ -20,7 +20,7 @@ public:
CPlayerPed *m_pPed;
CVehicle *m_pRemoteVehicle;
CColModel m_ColModel;
CVehicle *m_pVehicleEx;
CVehicle *m_pVehicleEx; // vehicle using the col model above
char m_aPlayerName[70];
int32 m_nMoney;
int32 m_nVisibleMoney;

View File

@ -295,6 +295,7 @@ DebugMenuPopulate(void)
DebugMenuAddCmd("Spawn", "Spawn Enforcer", [](){ SpawnCar(MI_ENFORCER); });
DebugMenuAddCmd("Spawn", "Spawn Banshee", [](){ SpawnCar(MI_BANSHEE); });
DebugMenuAddCmd("Spawn", "Spawn Yakuza", [](){ SpawnCar(MI_YAKUZA); });
DebugMenuAddCmd("Spawn", "Spawn Yardie", [](){ SpawnCar(MI_YARDIE); });
DebugMenuAddCmd("Spawn", "Spawn Dodo", [](){ SpawnCar(MI_DODO); });
DebugMenuAddCmd("Spawn", "Spawn Rhino", [](){ SpawnCar(MI_RHINO); });
DebugMenuAddCmd("Spawn", "Spawn Firetruck", [](){ SpawnCar(MI_FIRETRUCK); });

View File

@ -2,4 +2,5 @@
#include "patcher.h"
#include "WaterCannon.h"
WRAPPER void CWaterCannons::UpdateOne(uint32 id, CVector *pos, CVector *dir) { EAXJMP(0x522470); }
WRAPPER void CWaterCannons::Render(void) { EAXJMP(0x522550); }

View File

@ -3,5 +3,6 @@
class CWaterCannons
{
public:
static void UpdateOne(uint32 id, CVector *pos, CVector *dir);
static void Render(void);
};

View File

@ -15,6 +15,7 @@
#include "Explosion.h"
#include "Particle.h"
#include "ParticleObject.h"
#include "WaterCannon.h"
#include "WaterLevel.h"
#include "Floater.h"
#include "World.h"
@ -122,7 +123,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
bNotDamagedUpsideDown = false;
bMoreResistantToDamage = false;
m_fVelocityChangeForAudio = 0.f;
field_4E2 = 0;
m_hydraulicState = 0;
for(i = 0; i < 4; i++){
m_aGroundPhysical[i] = nil;
@ -205,7 +206,7 @@ CAutomobile::ProcessControl(void)
int i;
CColModel *colModel;
if(m_veh_flagC80)
if(bUseSpecialColModel)
colModel = &CWorld::Players[CWorld::PlayerInFocus].m_ColModel;
else
colModel = GetColModel();
@ -488,7 +489,7 @@ CAutomobile::ProcessControl(void)
m_aSuspensionSpringRatio[0] < 1.0f &&
CPad::GetPad(0)->HornJustDown()){
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRALIC_1, 0.0f);
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_1, 0.0f);
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_JUMP, 1.0f);
CParticle::AddParticle(PARTICLE_ENGINE_STEAM,
@ -1213,7 +1214,7 @@ CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints)
if(m_status != STATUS_SIMPLE)
bVehicleColProcessed = true;
if(m_veh_flagC80)
if(bUseSpecialColModel)
colModel = &CWorld::Players[CWorld::PlayerInFocus].m_ColModel;
else
colModel = GetColModel();
@ -1416,9 +1417,62 @@ CAutomobile::ProcessControlInputs(uint8 pad)
}
}
WRAPPER void
void
CAutomobile::FireTruckControl(void)
{ EAXJMP(0x522590);
{
if(this == FindPlayerVehicle()){
if(!CPad::GetPad(0)->GetWeapon())
return;
m_fCarGunLR += CPad::GetPad(0)->GetCarGunLeftRight()*0.00025f*CTimer::GetTimeStep();
m_fCarGunUD += CPad::GetPad(0)->GetCarGunUpDown()*0.0001f*CTimer::GetTimeStep();
m_fCarGunUD = clamp(m_fCarGunUD, 0.05f, 0.3f);
CVector cannonPos(0.0f, 1.5f, 1.9f);
cannonPos = GetMatrix() * cannonPos;
CVector cannonDir(
Sin(m_fCarGunLR) * Cos(m_fCarGunUD),
Cos(m_fCarGunLR) * Cos(m_fCarGunUD),
Sin(m_fCarGunUD));
cannonDir = Multiply3x3(GetMatrix(), cannonDir);
cannonDir.z += (CGeneral::GetRandomNumber()&0xF)/1000.0f;
CWaterCannons::UpdateOne((uintptr)this, &cannonPos, &cannonDir);
}else if(m_status == STATUS_PHYSICS){
CFire *fire = gFireManager.FindFurthestFire_NeverMindFireMen(GetPosition(), 10.0f, 35.0f);
if(fire == nil)
return;
// Target cannon onto fire
float targetAngle = CGeneral::GetATanOfXY(fire->m_vecPos.x-GetPosition().x, fire->m_vecPos.y-GetPosition().y);
float fwdAngle = CGeneral::GetATanOfXY(GetForward().x, GetForward().y);
float targetCannonAngle = fwdAngle - targetAngle;
float angleDelta = CTimer::GetTimeStep()*0.01f;
float cannonDelta = targetCannonAngle - m_fCarGunLR;
while(cannonDelta < PI) cannonDelta += TWOPI;
while(cannonDelta > PI) cannonDelta -= TWOPI;
if(Abs(cannonDelta) < angleDelta)
m_fCarGunLR = targetCannonAngle;
else if(cannonDelta > 0.0f)
m_fCarGunLR += angleDelta;
else
m_fCarGunLR -= angleDelta;
// Go up and down a bit
float upDown = Sin((float)(CTimer::GetTimeInMilliseconds() & 0xFFF)/0x1000 * TWOPI);
m_fCarGunUD = 0.2f + 0.2f*upDown;
// Spray water every once in a while
if((CTimer::GetTimeInMilliseconds()>>10) & 3){
CVector cannonPos(0.0f, 0.0f, 2.2f); // different position than player's firetruck!
cannonPos = GetMatrix() * cannonPos;
CVector cannonDir(
Sin(m_fCarGunLR) * Cos(m_fCarGunUD),
Cos(m_fCarGunLR) * Cos(m_fCarGunUD),
Sin(m_fCarGunUD));
cannonDir = Multiply3x3(GetMatrix(), cannonDir);
cannonDir.z += (CGeneral::GetRandomNumber()&0xF)/1000.0f;
CWaterCannons::UpdateOne((uintptr)this, &cannonPos, &cannonDir);
}
}
}
void
@ -1528,13 +1582,307 @@ CAutomobile::TankControl(void)
}
}
WRAPPER void
void
CAutomobile::HydraulicControl(void)
{ EAXJMP(0x52D4E0);
{
int i;
float wheelPositions[4];
CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
CColModel *normalColModel = mi->GetColModel();
float wheelRadius = 0.5f*mi->m_wheelScale;
CPlayerInfo *playerInfo = &CWorld::Players[CWorld::PlayerInFocus];
CColModel *specialColModel = &playerInfo->m_ColModel;
if(m_status != STATUS_PLAYER){
// reset hydraulics for non-player cars
if(!bUseSpecialColModel)
return;
if(specialColModel != nil) // this is always true
for(i = 0; i < 4; i++)
wheelPositions[i] = specialColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
for(i = 0; i < 4; i++){
m_aSuspensionSpringLength[i] = pHandling->fSuspensionUpperLimit - pHandling->fSuspensionLowerLimit;
m_aSuspensionLineLength[i] = normalColModel->lines[i].p0.z - normalColModel->lines[i].p1.z;
m_aSuspensionSpringRatio[i] = (normalColModel->lines[i].p0.z - wheelPositions[i]) / m_aSuspensionLineLength[i];
if(m_aSuspensionSpringRatio[i] > 1.0f)
m_aSuspensionSpringRatio[i] = 1.0f;
}
if(m_hydraulicState == 0)
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_1, 0.0f);
else if(m_hydraulicState >= 100)
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
if(playerInfo->m_pVehicleEx == this)
playerInfo->m_pVehicleEx = nil;
bUseSpecialColModel = false;
m_hydraulicState = 0;
return;
}
// Player car
float normalUpperLimit = pHandling->fSuspensionUpperLimit;
float normalLowerLimit = pHandling->fSuspensionLowerLimit;
float normalSpringLength = normalUpperLimit - normalLowerLimit;
float extendedUpperLimit = normalUpperLimit - 0.2f;
float extendedLowerLimit = normalLowerLimit - 0.2f;
float extendedSpringLength = extendedUpperLimit - extendedLowerLimit;
if(!bUseSpecialColModel){
// Init special col model
if(playerInfo->m_pVehicleEx && playerInfo->m_pVehicleEx == this)
playerInfo->m_pVehicleEx->bUseSpecialColModel = false;
playerInfo->m_pVehicleEx = this;
playerInfo->m_ColModel = *normalColModel;
bUseSpecialColModel = true;
specialColModel = &playerInfo->m_ColModel;
if(m_fVelocityChangeForAudio > 0.1f)
m_hydraulicState = 20;
else{
m_hydraulicState = 0;
normalUpperLimit += -0.12f;
normalSpringLength = normalUpperLimit - (normalLowerLimit+0.14f);
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
}
// Setup suspension
float normalLineLength = normalSpringLength + wheelRadius;
CVector pos;
for(i = 0; i < 4; i++){
wheelPositions[i] = normalColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
mi->GetWheelPosn(i, pos);
pos.z += normalUpperLimit;
specialColModel->lines[i].p0 = pos;
pos.z -= normalLineLength;
specialColModel->lines[i].p1 = pos;
m_aSuspensionSpringLength[i] = normalSpringLength;
m_aSuspensionLineLength[i] = normalLineLength;
if(m_aSuspensionSpringRatio[i] < 1.0f){
m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i];
if(m_aSuspensionSpringRatio[i] > 1.0f)
m_aSuspensionSpringRatio[i] = 1.0f;
}
}
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
// Adjust col model
mi->GetWheelPosn(0, pos);
float minz = pos.z + extendedLowerLimit - wheelRadius;
if(minz < specialColModel->boundingBox.min.z)
specialColModel->boundingBox.min.z = minz;
float radius = max(specialColModel->boundingBox.min.Magnitude(), specialColModel->boundingBox.max.Magnitude());
if(specialColModel->boundingSphere.radius < radius)
specialColModel->boundingSphere.radius = radius;
}
if(playerInfo->m_WBState != WBSTATE_PLAYING)
return;
bool setPrevRatio = false;
if(m_hydraulicState < 20 && m_fVelocityChangeForAudio > 0.2f){
if(m_hydraulicState == 0){
m_hydraulicState = 20;
for(i = 0; i < 4; i++)
m_aWheelPosition[i] -= 0.06f;
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_1, 0.0f);
setPrevRatio = true;
}else{
m_hydraulicState++;
}
}else if(m_hydraulicState != 0){ // must always be true
if(m_hydraulicState < 21 && m_fVelocityChangeForAudio < 0.1f){
m_hydraulicState--;
if(m_hydraulicState == 0)
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
}
}
if(CPad::GetPad(0)->HornJustDown()){
// Switch between normal and extended
if(m_hydraulicState < 100)
m_hydraulicState = 100;
else{
if(m_fVelocityChangeForAudio > 0.1f)
m_hydraulicState = 20;
else
m_hydraulicState = 0;
}
if(m_hydraulicState < 100){
if(m_hydraulicState == 0){
normalUpperLimit += -0.12f;
normalLowerLimit += 0.14f;
normalSpringLength = normalUpperLimit - normalLowerLimit;
}
// Reset suspension to normal
float normalLineLength = normalSpringLength + wheelRadius;
CVector pos;
for(i = 0; i < 4; i++){
wheelPositions[i] = specialColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
mi->GetWheelPosn(i, pos);
pos.z += normalUpperLimit;
specialColModel->lines[i].p0 = pos;
pos.z -= normalLineLength;
specialColModel->lines[i].p1 = pos;
m_aSuspensionSpringLength[i] = normalSpringLength;
m_aSuspensionLineLength[i] = normalLineLength;
if(m_aSuspensionSpringRatio[i] < 1.0f){
m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i];
if(m_aSuspensionSpringRatio[i] > 1.0f)
m_aSuspensionSpringRatio[i] = 1.0f;
}
}
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
}else{
// Reset suspension to extended
float extendedLineLength = extendedSpringLength + wheelRadius;
CVector pos;
for(i = 0; i < 4; i++){
wheelPositions[i] = specialColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
mi->GetWheelPosn(i, pos);
pos.z += extendedUpperLimit;
specialColModel->lines[i].p0 = pos;
pos.z -= extendedLineLength;
specialColModel->lines[i].p1 = pos;
m_aSuspensionSpringLength[i] = extendedSpringLength;
m_aSuspensionLineLength[i] = extendedLineLength;
if(m_aSuspensionSpringRatio[i] < 1.0f){
m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i];
if(m_aSuspensionSpringRatio[i] > 1.0f)
m_aSuspensionSpringRatio[i] = 1.0f;
}
setPrevRatio = true;
m_aWheelPosition[i] -= 0.05f;
}
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
}
}else{
float suspChange[4];
float maxDelta = 0.0f;
float rear = CPad::GetPad(0)->GetCarGunUpDown()/128.0f;
float front = -rear;
float right = CPad::GetPad(0)->GetCarGunLeftRight()/128.0f;
float left = -right;
suspChange[CARWHEEL_FRONT_LEFT] = max(front+left, 0.0f);
suspChange[CARWHEEL_REAR_LEFT] = max(rear+left, 0.0f);
suspChange[CARWHEEL_FRONT_RIGHT] = max(front+right, 0.0f);
suspChange[CARWHEEL_REAR_RIGHT] = max(rear+right, 0.0f);
if(m_hydraulicState < 100){
// Lowered, move wheels up
if(m_hydraulicState == 0){
normalUpperLimit += -0.12f;
normalLowerLimit += 0.14f;
normalSpringLength = normalUpperLimit - normalLowerLimit;
}
// Set suspension
CVector pos;
for(i = 0; i < 4; i++){
if(suspChange[i] > 1.0f)
suspChange[i] = 1.0f;
float oldZ = specialColModel->lines[i].p1.z;
float upperLimit = suspChange[i]*(extendedUpperLimit-normalUpperLimit) + normalUpperLimit;
float springLength = suspChange[i]*(extendedSpringLength-normalSpringLength) + normalSpringLength;
float lineLength = springLength + wheelRadius;
wheelPositions[i] = specialColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
mi->GetWheelPosn(i, pos);
pos.z += upperLimit;
specialColModel->lines[i].p0 = pos;
pos.z -= lineLength;
if(Abs(pos.z - specialColModel->lines[i].p1.z) > Abs(maxDelta))
maxDelta = pos.z - specialColModel->lines[i].p1.z;
specialColModel->lines[i].p1 = pos;
m_aSuspensionSpringLength[i] = springLength;
m_aSuspensionLineLength[i] = lineLength;
if(m_aSuspensionSpringRatio[i] < 1.0f){
m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i];
if(m_aSuspensionSpringRatio[i] > 1.0f)
m_aSuspensionSpringRatio[i] = 1.0f;
m_aWheelPosition[i] -= (oldZ - specialColModel->lines[i].p1.z)*0.3f;
}
}
}else{
if(m_hydraulicState < 104){
m_hydraulicState++;
for(i = 0; i < 4; i++)
m_aWheelPosition[i] -= 0.1f;
}
if(m_fVelocityChangeForAudio < 0.1f){
normalUpperLimit += -0.12f;
normalLowerLimit += 0.14f;
normalSpringLength = normalUpperLimit - normalLowerLimit;
}
// Set suspension
CVector pos;
for(i = 0; i < 4; i++){
if(suspChange[i] > 1.0f)
suspChange[i] = 1.0f;
float upperLimit = suspChange[i]*(normalUpperLimit-extendedUpperLimit) + extendedUpperLimit;
float springLength = suspChange[i]*(normalSpringLength-extendedSpringLength) + extendedSpringLength;
float lineLength = springLength + wheelRadius;
wheelPositions[i] = specialColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
mi->GetWheelPosn(i, pos);
pos.z += upperLimit;
specialColModel->lines[i].p0 = pos;
pos.z -= lineLength;
if(Abs(pos.z - specialColModel->lines[i].p1.z) > Abs(maxDelta))
maxDelta = pos.z - specialColModel->lines[i].p1.z;
specialColModel->lines[i].p1 = pos;
m_aSuspensionSpringLength[i] = springLength;
m_aSuspensionLineLength[i] = lineLength;
if(m_aSuspensionSpringRatio[i] < 1.0f){
m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i];
if(m_aSuspensionSpringRatio[i] > 1.0f)
m_aSuspensionSpringRatio[i] = 1.0f;
}
}
}
float limitDiff = extendedLowerLimit - normalLowerLimit;
if(limitDiff != 0.0f && Abs(maxDelta/limitDiff) > 0.01f){
float f = (maxDelta + limitDiff)/2.0f/limitDiff;
f = clamp(f, 0.0f, 1.0f);
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_3, f);
if(f < 0.4f || f > 0.6f)
setPrevRatio = true;
if(f < 0.25f)
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
else if(f > 0.75f)
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_1, 0.0f);
}
}
if(setPrevRatio)
for(i = 0; i < 4; i++){
// wheel radius in relation to suspension line
float wheelRadius = 1.0f - m_aSuspensionSpringLength[i]/m_aSuspensionLineLength[i];
m_aSuspensionSpringRatioPrev[i] = (m_aSuspensionSpringRatio[i]-wheelRadius)/(1.0f-wheelRadius);
}
}
void
CAutomobile::ProcessBuoyancy(void)
CAutomobile::ProcessBuoyancy(void)
{
int i;
CVector impulse, point;

View File

@ -54,7 +54,7 @@ public:
uint8 field_4DB;
CEntity *m_pBombRigger;
int16 field_4E0;
int16 field_4E2;
uint16 m_hydraulicState;
uint32 m_nBusDoorTimerEnd;
uint32 m_nBusDoorTimerStart;
float m_aSuspensionSpringLength[4];

View File

@ -70,7 +70,7 @@ CVehicle::CVehicle(uint8 CreatedBy)
bHasBeenOwnedByPlayer = false;
m_veh_flagC20 = false;
bCanBeDamaged = true;
m_veh_flagC80 = false;
bUseSpecialColModel = false;
m_veh_flagD1 = false;
m_veh_flagD2 = false;
m_nGunFiringTime = 0;

View File

@ -186,7 +186,7 @@ public:
uint8 m_veh_flagC10 : 1;
uint8 m_veh_flagC20 : 1;
uint8 bCanBeDamaged : 1; // Set to FALSE during cut scenes to avoid explosions
uint8 m_veh_flagC80 : 1;
uint8 bUseSpecialColModel : 1;
uint8 m_veh_flagD1 : 1;
uint8 m_veh_flagD2 : 1;