This commit is contained in:
Veyrdite 2021-08-02 15:23:10 +00:00 committed by GitHub
commit e8c8b3ff94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 457 additions and 93 deletions

View File

@ -2347,11 +2347,17 @@ PlayCruising:
SampleManager.StopChannel(CHANNEL_PLAYER_VEHICLE_ENGINE);
if (isMoped || accelerateState >= 150 && wheelsOnGround && brakeState <= 0 && !params.m_pVehicle->bIsHandbrakeOn
&& !lostTraction && currentGear >= params.m_pTransmission->nNumberOfGears - 1) {
if (accelerateState >= 220 && params.m_fVelocityChange + 0.001f >= velocityChangeForAudio) {
if (nCruising < 800)
++nCruising;
} else if (nCruising > 3) {
--nCruising;
#ifdef FIX_BUGS
// Prevent the fake top gear ("cruise gear") rising in pitch too quickly at high FPS.
if (CTimer::GetLogicalFramesPassed())
#endif
{
if (accelerateState >= 220 && params.m_fVelocityChange + 0.001f >= velocityChangeForAudio) {
if (nCruising < 800)
++nCruising;
} else if (nCruising > 3) {
--nCruising;
}
}
freq = 27 * nCruising + freqModifier + 22050;
if (engineSoundType == SFX_BANK_TRUCK)

View File

@ -3895,10 +3895,12 @@ CCam::Process_Debug(const CVector&, float, float, float)
if(Alpha > DEGTORAD(89.5f)) Alpha = DEGTORAD(89.5f);
else if(Alpha < DEGTORAD(-89.5f)) Alpha = DEGTORAD(-89.5f);
const float TimeStep = CTimer::GetTimeStepNonClipped();
if(CPad::GetPad(1)->GetSquare() || KEYDOWN('W'))
Speed += 0.1f;
Speed += 0.1f * TimeStep;
else if(CPad::GetPad(1)->GetCross() || KEYDOWN('S'))
Speed -= 0.1f;
Speed -= 0.1f * TimeStep;
else
Speed = 0.0f;
if(Speed > 70.0f) Speed = 70.0f;
@ -3906,9 +3908,9 @@ CCam::Process_Debug(const CVector&, float, float, float)
if(KEYDOWN(rsRIGHT) || KEYDOWN('D'))
PanSpeedX += 0.1f;
PanSpeedX += 0.1f * TimeStep;
else if(KEYDOWN(rsLEFT) || KEYDOWN('A'))
PanSpeedX -= 0.1f;
PanSpeedX -= 0.1f * TimeStep;
else
PanSpeedX = 0.0f;
if(PanSpeedX > 70.0f) PanSpeedX = 70.0f;
@ -3916,23 +3918,22 @@ CCam::Process_Debug(const CVector&, float, float, float)
if(KEYDOWN(rsUP))
PanSpeedY += 0.1f;
PanSpeedY += 0.1f * TimeStep;
else if(KEYDOWN(rsDOWN))
PanSpeedY -= 0.1f;
PanSpeedY -= 0.1f * TimeStep;
else
PanSpeedY = 0.0f;
if(PanSpeedY > 70.0f) PanSpeedY = 70.0f;
if(PanSpeedY < -70.0f) PanSpeedY = -70.0f;
Front = TargetCoors - Source;
Front.Normalise();
Source = Source + Front*Speed;
Source = Source + Front * Speed * TimeStep;
Up = CVector{ 0.0f, 0.0f, 1.0f };
CVector Right = CrossProduct(Front, Up);
Up = CrossProduct(Right, Front);
Source = Source + Up*PanSpeedY + Right*PanSpeedX;
Source = Source + Up * PanSpeedY * TimeStep + Right * PanSpeedX * TimeStep;
if(Source.z < -450.0f)
Source.z = -450.0f;
@ -3955,11 +3956,7 @@ CCam::Process_Debug(const CVector&, float, float, float)
Source.y += 1.0f;
GetVectorsReadyForRW();
#ifdef FIX_BUGS
CPad::GetPad(0)->SetDisablePlayerControls(PLAYERCONTROL_CAMERA);
#else
CPad::GetPad(0)->DisablePlayerControls = PLAYERCONTROL_CAMERA;
#endif
if(CPad::GetPad(1)->GetLeftShockJustDown() && gbBigWhiteDebugLightSwitchedOn)
CShadows::StoreShadowToBeRendered(SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &Source,

View File

@ -590,7 +590,12 @@ CPhysical::ApplyAirResistance(void)
}else if(GetStatus() != STATUS_GHOST){
float f = Pow(1.0f/Abs(1.0f + m_fAirResistance*0.5f*m_vecMoveSpeed.MagnitudeSqr()), CTimer::GetTimeStep());
m_vecMoveSpeed *= f;
#ifdef FIX_BUGS
// Fix too much friction at high FPS (evil cause of bad vehicle handling, rear tires unable to lose traction, etc!)
m_vecTurnSpeed *= Pow(0.99f, CTimer::GetTimeStepFix());
#else
m_vecTurnSpeed *= 0.99f;
#endif
}
}
@ -1071,6 +1076,10 @@ CPhysical::ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint)
if(fOtherSpeedA > speedSum){
impulseA = (speedSum - fOtherSpeedA) * A->m_fMass;
impulseB = (speedSum - fOtherSpeedB) * B->m_fMass;
#ifdef FIX_BUGS
impulseA *= CTimer::GetTimeStepFix();
impulseB *= CTimer::GetTimeStepFix();
#endif
impulseLimit = adhesiveLimit*CTimer::GetTimeStep();
if(impulseA < -impulseLimit) impulseA = -impulseLimit;
#ifdef FIX_BUGS
@ -1107,6 +1116,10 @@ CPhysical::ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint)
if(fOtherSpeedA > speedSum){
impulseA = (speedSum - fOtherSpeedA) * A->m_fMass;
impulseB = (speedSum - fOtherSpeedB) * massB;
#ifdef FIX_BUGS
impulseA *= CTimer::GetTimeStepFix();
impulseB *= CTimer::GetTimeStepFix();
#endif
impulseLimit = adhesiveLimit*CTimer::GetTimeStep();
if(impulseA < -impulseLimit) impulseA = -impulseLimit;
if(impulseB > impulseLimit) impulseB = impulseLimit;
@ -1140,6 +1153,10 @@ CPhysical::ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint)
if(fOtherSpeedA > speedSum){
impulseA = (speedSum - fOtherSpeedA) * massA;
impulseB = (speedSum - fOtherSpeedB) * B->m_fMass;
#ifdef FIX_BUGS
impulseA *= CTimer::GetTimeStepFix();
impulseB *= CTimer::GetTimeStepFix();
#endif
impulseLimit = adhesiveLimit*CTimer::GetTimeStep();
if(impulseA < -impulseLimit) impulseA = -impulseLimit;
if(impulseB > impulseLimit) impulseB = impulseLimit;
@ -1174,6 +1191,10 @@ CPhysical::ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint)
if(fOtherSpeedA > speedSum){
impulseA = (speedSum - fOtherSpeedA) * massA;
impulseB = (speedSum - fOtherSpeedB) * massB;
#ifdef FIX_BUGS
impulseA *= CTimer::GetTimeStepFix();
impulseB *= CTimer::GetTimeStepFix();
#endif
impulseLimit = adhesiveLimit*CTimer::GetTimeStep();
if(impulseA < -impulseLimit) impulseA = -impulseLimit;
if(impulseB > impulseLimit) impulseB = impulseLimit;
@ -1214,6 +1235,9 @@ CPhysical::ApplyFriction(float adhesiveLimit, CColPoint &colpoint)
// not really impulse but speed
// maybe use ApplyFrictionMoveForce instead?
fImpulse = -fOtherSpeed;
#ifdef FIX_BUGS
fImpulse *= CTimer::GetTimeStepFix();
#endif
impulseLimit = adhesiveLimit*CTimer::GetTimeStep() / m_fMass;
if(fImpulse < -impulseLimit) fImpulse = -impulseLimit;
CVector vImpulse = frictionDir*fImpulse;
@ -1235,6 +1259,9 @@ CPhysical::ApplyFriction(float adhesiveLimit, CColPoint &colpoint)
frictionDir = vOtherSpeed * (1.0f/fOtherSpeed);
#endif
fImpulse = -fOtherSpeed * m_fMass;
#ifdef FIX_BUGS
fImpulse *= CTimer::GetTimeStepFix();
#endif
impulseLimit = adhesiveLimit*CTimer::GetTimeStep() * 1.5;
if(fImpulse < -impulseLimit) fImpulse = -impulseLimit;
ApplyFrictionMoveForce(frictionDir*fImpulse);
@ -1834,9 +1861,16 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists)
A->GetStatus() == STATUS_PLAYER && A->IsVehicle() &&
Abs(A->m_vecMoveSpeed.x) > 0.2f &&
Abs(A->m_vecMoveSpeed.y) > 0.2f){
#ifdef FIX_BUGS
// Fix vehicles having lower turning circles at high FPS
A->m_vecMoveFriction.x += CTimer::GetTimeStepFix() * moveSpeed.x * -0.3f / numCollisions;
A->m_vecMoveFriction.y += CTimer::GetTimeStepFix() * moveSpeed.y * -0.3f / numCollisions;
A->m_vecTurnFriction += CTimer::GetTimeStepFix() * turnSpeed * -0.3f / numCollisions;
#else
A->m_vecMoveFriction.x += moveSpeed.x * -0.3f / numCollisions;
A->m_vecMoveFriction.y += moveSpeed.y * -0.3f / numCollisions;
A->m_vecTurnFriction += turnSpeed * -0.3f / numCollisions;
#endif
}
if(B->IsObject() && Bobj->m_nCollisionDamageEffect && maxImpulseA > 20.0f)

View File

@ -6,6 +6,7 @@
#include "Timer.h"
#include "rtcharse.h"
#include "re3_inttypes.h"
#include "Frontend.h"
#include "debugmenu.h"
#include <new>
@ -1017,6 +1018,10 @@ DebugMenuProcess(void)
CPad *pad = CPad::GetPad(0);
if(CTRLJUSTDOWN('M'))
menuOn = !menuOn;
if (KEYJUSTDOWN(rsF4))
FrontEndMenuManager.m_PrefsFrameLimiter = !FrontEndMenuManager.m_PrefsFrameLimiter;
if(KEYJUSTDOWN(rsESC))
menuOn = false;
if(!menuOn)
return;
@ -1309,4 +1314,4 @@ DebugMenuEntrySetAddress(MenuEntry *e, void *addr)
((MenuEntry_Float32*)e)->variable = (float*)addr;
}
}
#endif
#endif

View File

@ -429,6 +429,12 @@ CParticleObject::RemoveObject(void)
void
CParticleObject::UpdateAll(void)
{
#ifdef FIX_BUGS
// Fix particle generation spam at high FPS
if (CTimer::GetLogicalFramesPassed() == 0)
return;
#endif
{
CParticleObject *pobj = pCloseListHead;
CParticleObject *nextpobj;

View File

@ -1259,8 +1259,11 @@ void CParticle::Update()
}
vecPos += vecMoveStep;
#ifdef FIX_BUGS
if ( psystem->m_Type == PARTICLE_FIREBALL && CTimer::GetLogicalFramesPassed()) // Fix particle spam at high FPS
#else
if ( psystem->m_Type == PARTICLE_FIREBALL )
#endif
{
AddParticle(PARTICLE_HEATHAZE, particle->m_vecPosition, CVector(0.0f, 0.0f, 0.0f),
nil, particle->m_fSize * 5.0f);
@ -1326,11 +1329,18 @@ void CParticle::Update()
fDistToCam = (TheCamera.GetPosition() - vecPos).Magnitude();
}
#ifdef FIX_BUGS
if ( numWaterDropOnScreen < nMaxDrops && numWaterDropOnScreen < 63
&& fDistToCam < 10.0f
&& clearWaterDrop == false
&& !CGame::IsInInterior()
&& CTimer::GetLogicalFramesPassed()) // Fix waterdrop spam at high FPS
#else
if ( numWaterDropOnScreen < nMaxDrops && numWaterDropOnScreen < 63
&& fDistToCam < 10.0f
&& clearWaterDrop == false
&& !CGame::IsInInterior() )
#endif
{
CVector vecWaterdropTarget
(
@ -1411,7 +1421,11 @@ void CParticle::Update()
}
}
#ifdef FIX_BUGS
if ( !(psystem->Flags & SCREEN_TRAIL) && CTimer::GetLogicalFramesPassed()) // Fix particle over-expansion at high FPS
#else
if ( !(psystem->Flags & SCREEN_TRAIL) )
#endif
{
float size;
@ -1701,6 +1715,12 @@ void CParticle::Update()
}
}
#ifdef FIX_BUGS
// Keep particles animating, rotating, fading etc at the right speed
// at high or low FPS.
for (uint32 i=0; i<CTimer::GetLogicalFramesPassed(); i++)
#endif
{ // -- start FPS fix ---
if ( particle->m_nFadeToBlackTimer != 0 )
{
particle->m_nColorIntensity = Clamp(particle->m_nColorIntensity - particle->m_nFadeToBlackTimer,
@ -1764,6 +1784,7 @@ void CParticle::Update()
#else
particle->m_nRotation += particle->m_nRotationStep;
#endif
} // -- end FPS fix --
if ( particle->m_fCurrentZRadius != 0.0f )
{
@ -1773,6 +1794,16 @@ void CParticle::Update()
float fY = (Sin(nSinCosIndex) + Cos(nSinCosIndex)) * particle->m_fCurrentZRadius;
#ifdef FIX_BUGS
// Prevent super-fast movement at high FPS
// We can use GetTimeSetpFix() here instead of GetLogicalFramesPassed()
// so the visual result looks "smooth" on player's screens. We can't
// do this with most of the above Timers because the effects are stored
// as uint16's instead of floats, which means tiny changes each frame
// are often rounded down to zero change each frame.
fX *= CTimer::GetTimeStepFix();
fY *= CTimer::GetTimeStepFix();
#endif
vecPos -= particle->m_vecParticleMovementOffset;
vecPos += CVector(fX, fY, 0.0f);

View File

@ -81,7 +81,7 @@ enum tParticleType
PARTICLE_TEST,
PARTICLE_BIRD_FRONT,
PARTICLE_SHIP_SIDE,
PARTICLE_BEASTIE,
PARTICLE_BEASTIE, // "Beasties" look like tree leaves circling up at canopy height, but are also used in other places (eg docks)
PARTICLE_RAINDROP_2D,
PARTICLE_HEATHAZE,
PARTICLE_HEATHAZE_IN_DIST,

View File

@ -921,16 +921,30 @@ CWaterLevel::RenderWater()
if ( !CTimer::GetIsPaused() )
{
TEXTURE_ADDU += windAddUV;
TEXTURE_ADDV += windAddUV;
_TEXTURE_MASK_ADDU += Sin(fAngle) * 0.0005f + 1.1f * windAddUV;
_TEXTURE_MASK_ADDV -= Cos(fAngle * 1.3f) * 0.0005f + 1.2f * windAddUV;
_TEXTURE_WAKE_ADDU -= Sin(fAngle) * 0.0003f + windAddUV;
_TEXTURE_WAKE_ADDV += Cos(fAngle * 0.7f) * 0.0003f + windAddUV;
#ifdef FIX_BUGS
// Stop the movement of the ocean speeding up at high FPS.
// Should be purely aesthetic, affecting only the texture UVs.
TEXTURE_ADDU += windAddUV * CTimer::GetTimeStepFix();
TEXTURE_ADDV += windAddUV * CTimer::GetTimeStepFix();
_TEXTURE_MASK_ADDU += (Sin(fAngle) * 0.0005f + 1.1f * windAddUV) * CTimer::GetTimeStepFix();
_TEXTURE_MASK_ADDV -= (Cos(fAngle * 1.3f) * 0.0005f + 1.2f * windAddUV) * CTimer::GetTimeStepFix();
_TEXTURE_WAKE_ADDU -= (Sin(fAngle) * 0.0003f + windAddUV) * CTimer::GetTimeStepFix();
_TEXTURE_WAKE_ADDV += (Cos(fAngle * 0.7f) * 0.0003f + windAddUV) * CTimer::GetTimeStepFix();
#else
TEXTURE_ADDU += windAddUV;
TEXTURE_ADDV += windAddUV;
_TEXTURE_MASK_ADDU += Sin(fAngle) * 0.0005f + 1.1f * windAddUV;
_TEXTURE_MASK_ADDV -= Cos(fAngle * 1.3f) * 0.0005f + 1.2f * windAddUV;
_TEXTURE_WAKE_ADDU -= Sin(fAngle) * 0.0003f + windAddUV;
_TEXTURE_WAKE_ADDV += Cos(fAngle * 0.7f) * 0.0003f + windAddUV;
#endif
}
// What does this code do? Are the above equations sometimes unstable and make big numbers?
if ( _TEXTURE_MASK_ADDU >= 1.0f )
_TEXTURE_MASK_ADDU = 0.0f;
if ( _TEXTURE_MASK_ADDV >= 1.0f )
@ -1954,7 +1968,7 @@ CWaterLevel::RenderWavyMask(float fX, float fY, float fZ,
#ifndef PC_WATER
if (maskMorphVerts[base].z >= fMinSparkZ)
#else
if ( maskMorphVerts[base].z > fMinSparkZ )
if (maskMorphVerts[base].z > fMinSparkZ)
#endif
{
switch ( (i + j + randval) & 3 )

View File

@ -169,7 +169,11 @@ void CWeather::Update(void)
LightningFlash = false;
LightningBurst = false;
}
#ifdef FIX_BUGS
else if (CTimer::GetLogicalFramesPassed()) {
#else
else{
#endif
if (LightningBurst) {
if ((CGeneral::GetRandomNumber() & 255) >= 32) {
// 0.875 probability
@ -303,7 +307,11 @@ void CWeather::Update(void)
TrafficLightBrightness = Max(Foggyness, TrafficLightBrightness);
TrafficLightBrightness = Max(Rain, TrafficLightBrightness);
#ifdef FIX_BUGS
if (CTimer::GetLogicalFramesPassed()) AddRain();
#else
AddRain();
#endif
if ((NewWeatherType == WEATHER_SUNNY || NewWeatherType == WEATHER_EXTRA_SUNNY) &&
!CGame::IsInInterior() && !CCutsceneMgr::IsRunning() && (CTimer::GetFrameCounter() & 7) == 0) {
@ -323,6 +331,11 @@ void CWeather::Update(void)
void CWeather::AddHeatHaze()
{
#ifdef FIX_BUGS
// Fix particle spam at high FPS
if (!CTimer::GetLogicalFramesPassed())
return;
#endif
if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN ||
TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED)
return;
@ -338,6 +351,11 @@ void CWeather::AddHeatHaze()
void CWeather::AddBeastie()
{
#ifdef FIX_BUGS
// Fix particle spam at high FPS. Beasties look like tree leaves.
if (!CTimer::GetLogicalFramesPassed())
return;
#endif
if(FindPlayerVehicle() || CTimer::GetFrameCounter()%10 || (CGeneral::GetRandomNumber()&5) == 0)
return;
CVector pos = TheCamera.GetPosition();

View File

@ -235,6 +235,12 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
bExplosionProof = true;
bBulletProof = true;
}
#ifdef FIX_BUGS
// Probably not neccesary to zero these
m_nCarHornTimer = 0;
m_fCarHornTimeButtonLastHit = 0.0f;
#endif
}
void
@ -857,8 +863,12 @@ CAutomobile::ProcessControl(void)
(m_aSuspensionSpringRatio[1] < 1.0f || m_aSuspensionSpringRatio[3] < 1.0f))
ApplyTurnForce(-GRAVITY*Min(m_fTurnMass, 2500.0f)*GetUp(), -1.0f*GetForward());
}
#ifdef FIX_BUGS
// Keep brake non-timestepped (so the later ProcessWheel() takes only non-timestepped inputs)
brake = m_fBrakePedal * pHandling->fBrakeDeceleration * CTimer::GetDefaultTimeStep();
#else
brake = m_fBrakePedal * pHandling->fBrakeDeceleration * CTimer::GetTimeStep();
#endif
bool neutralHandling = GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE && (pHandling->Flags & HANDLING_NEUTRALHANDLING);
float brakeBiasFront = neutralHandling ? 1.0f : 2.0f*pHandling->fBrakeBias;
float brakeBiasRear = neutralHandling ? 1.0f : 2.0f-pHandling->fBrakeBias; // looks like a bug, but it was correct in III...
@ -1058,12 +1068,7 @@ CAutomobile::ProcessControl(void)
float rearBrake = brake;
float rearTraction = traction;
if(bIsHandbrakeOn){
#ifdef FIX_BUGS
// Not sure if this is needed, but brake usually has timestep as a factor
rearBrake = 20000.0f * CTimer::GetTimeStepFix();
#else
rearBrake = 20000.0f;
#endif
if(fwdSpeed > 0.1f && pHandling->Flags & HANDLING_HANDBRAKE_TYRE){
m_fTireTemperature += 0.005*CTimer::GetTimeStep();
if(m_fTireTemperature > 2.0f)
@ -1072,8 +1077,11 @@ CAutomobile::ProcessControl(void)
}else if(m_doingBurnout && mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier)){
rearBrake = 0.0f;
rearTraction = 0.0f;
// BUG: missing timestep
#ifdef FIX_BUGS
ApplyTurnForce(contactPoints[CARWHEEL_REAR_LEFT], -0.001f*m_fTurnMass*m_fSteerAngle*GetRight()*CTimer::GetTimeStepFix());
#else
ApplyTurnForce(contactPoints[CARWHEEL_REAR_LEFT], -0.001f*m_fTurnMass*m_fSteerAngle*GetRight());
#endif
}else if(m_fTireTemperature > 1.0f){
rearTraction *= m_fTireTemperature;
}
@ -1364,18 +1372,49 @@ CAutomobile::ProcessControl(void)
ReduceHornCounter();
}else{
if(UsesSiren()){
#ifdef FIX_BUGS
// Allow sirens to be toggled at high FPS
const float minPressTime = 100.0f; // milli-seconds
bool currentButtonState = Pads[0].bHornHistory[(CPad::HORNHISTORY_SIZE + Pads[0].iCurrHornHistory - 0) % CPad::HORNHISTORY_SIZE];
bool lastButtonState = Pads[0].bHornHistory[(CPad::HORNHISTORY_SIZE + Pads[0].iCurrHornHistory - 1) % CPad::HORNHISTORY_SIZE]; // Extra addition of CPad::HORNHISTORY_SIZE avoids modulo of negative numbers
if (currentButtonState && !lastButtonState)
{
// Horn button has just been hit
m_fCarHornTimeButtonLastHit = CTimer::GetTimeInMilliseconds();
}
else if (currentButtonState && lastButtonState)
{
// Horn button is being held down
if (CTimer::GetTimeInMilliseconds() - m_fCarHornTimeButtonLastHit >= minPressTime)
m_nCarHornTimer = 1; // enable horn
}
else if (!currentButtonState && lastButtonState)
{
// Horn button has just been released
m_nCarHornTimer = 0;
if (CTimer::GetTimeInMilliseconds() - m_fCarHornTimeButtonLastHit < minPressTime)
m_bSirenOrAlarm = !m_bSirenOrAlarm; // Toggle siren-like-feature
}
else
{
// Nothing pressed
m_nCarHornTimer = 0; // Should not be neccesary, but may as well keep in
}
#else
if(Pads[0].bHornHistory[Pads[0].iCurrHornHistory]){
if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5] &&
Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+3) % 5])
if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % CPad::HORNHISTORY_SIZE] &&
Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+3) % CPad::HORNHISTORY_SIZE])
m_nCarHornTimer = 1;
else
m_nCarHornTimer = 0;
}else if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5] &&
!Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+1) % 5]){
}else if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % CPad::HORNHISTORY_SIZE] &&
!Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+1) % CPad::HORNHISTORY_SIZE]){
m_nCarHornTimer = 0;
m_bSirenOrAlarm = !m_bSirenOrAlarm;
}else
m_nCarHornTimer = 0;
#endif
}else if(GetModelIndex() != MI_VOODOO && !CVehicle::bCheat3 && !carHasNitro){
if(!IsAlarmOn()){
if(Pads[0].GetHorn())
@ -5738,8 +5777,14 @@ CAutomobile::ShowAllComps(void)
void
CAutomobile::ReduceHornCounter(void)
{
#ifdef FIX_BUGS
// Make horns last longer (only used by AI drivers?)
if(m_nCarHornTimer != 0 && CTimer::GetLogicalFramesPassed())
m_nCarHornTimer--;
#else
if(m_nCarHornTimer != 0)
m_nCarHornTimer--;
#endif
}
void

View File

@ -722,7 +722,12 @@ CBike::ProcessControl(void)
acceleration = pHandling->Transmission.CalculateDriveAcceleration(m_fGasPedal, m_nCurrentGear, m_fChangeGearTime, fwdSpeed, gripCheat);
acceleration /= m_fForceMultiplier;
#ifdef FIX_BUGS
// Keep timestep out of this, it gets added properly inside ProcessWheel() later. Fixes weak brakes at high FPS.
brake = m_fBrakePedal * pHandling->fBrakeDeceleration * CTimer::GetDefaultTimeStep();
#else
brake = m_fBrakePedal * pHandling->fBrakeDeceleration * CTimer::GetTimeStep();
#endif
bool neutralHandling = GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE && (pHandling->Flags & HANDLING_NEUTRALHANDLING);
float brakeBiasFront = neutralHandling ? 1.0f : 2.0f*pHandling->fBrakeBias;
float brakeBiasRear = neutralHandling ? 1.0f : 2.0f*(1.0f-pHandling->fBrakeBias);
@ -882,12 +887,7 @@ CBike::ProcessControl(void)
wheelRight.Normalise();
if(bIsHandbrakeOn){
#ifdef FIX_BUGS
// Not sure if this is needed, but brake usually has timestep as a factor
rearBrake = 20000.0f * CTimer::GetTimeStepFix();
#else
rearBrake = 20000.0f;
#endif
m_fTireTemperature = 1.0f;
}else if(m_doingBurnout){
rearBrake = 0.0f;
@ -2941,8 +2941,14 @@ CBike::SetupModelNodes(void)
void
CBike::ReduceHornCounter(void)
{
if(m_nCarHornTimer != 0)
#ifdef FIX_BUGS
// Make horns last longer (only used by AI drivers?)
if(m_nCarHornTimer != 0 && CTimer::GetLogicalFramesPassed())
m_nCarHornTimer--;
#else
if(m_nCarHornTimer != 0)
m_nCarHornTimer--;
#endif
}
#ifdef COMPATIBLE_SAVES

View File

@ -263,9 +263,17 @@ CBoat::ProcessControl(void)
}
// Damage particles
#ifdef FIX_BUGS
if(m_fHealth <= 460.0f && GetStatus() != STATUS_WRECKED &&
Abs(GetPosition().x - TheCamera.GetPosition().x) < 200.0f &&
Abs(GetPosition().y - TheCamera.GetPosition().y) < 200.0f &&
CTimer::GetLogicalFramesPassed() ) // Fix high-FPS particle spam
{
#else
if(m_fHealth <= 460.0f && GetStatus() != STATUS_WRECKED &&
Abs(GetPosition().x - TheCamera.GetPosition().x) < 200.0f &&
Abs(GetPosition().y - TheCamera.GetPosition().y) < 200.0f){
#endif
float speedSq = m_vecMoveSpeed.MagnitudeSqr();
CVector smokeDir = 0.8f*m_vecMoveSpeed;
CVector smokePos;
@ -335,6 +343,7 @@ CBoat::ProcessControl(void)
bIsDrowning = false;
}
// Apply buoyancy impulse the first time (why twice?)
m_fVolumeUnderWater = mod_Buoyancy.m_volumeUnderWater;
m_vecBuoyancePoint = buoyancePoint;
if(GetModelIndex() == MI_SKIMMER && GetUp().z < -0.5f && Abs(m_vecMoveSpeed.x) < 0.2f && Abs(m_vecMoveSpeed.y) < 0.2f)
@ -344,13 +353,17 @@ CBoat::ProcessControl(void)
if(bSeparateTurnForce)
ApplyTurnForce(0.4f*buoyanceImpulse, buoyancePoint);
// TODO: what is this?
if(GetModelIndex() == MI_SKIMMER)
if(m_skimmerThingTimer != 0.0f ||
GetForward().z < -0.5f && GetUp().z > -0.5f && m_vecMoveSpeed.z < -0.15f &&
buoyanceImpulse.z > 0.01f*m_fMass * GRAVITY*CTimer::GetTimeStep() &&
buoyanceImpulse.z < 0.4f*m_fMass * GRAVITY*CTimer::GetTimeStep()){
#ifdef FIX_BUGS
// buoyanceImpulse already has a factor of timestep in it
float turnImpulse = -0.00017f*GetForward().z*buoyanceImpulse.z * m_fMass*CTimer::GetDefaultTimeStep();
#else
float turnImpulse = -0.00017f*GetForward().z*buoyanceImpulse.z * m_fMass*CTimer::GetTimeStep();
#endif
ApplyTurnForce(turnImpulse*GetForward(), GetUp());
bBoatInWater = false;
//BUG? aren't we forgetting the timestep here?
@ -362,15 +375,21 @@ CBoat::ProcessControl(void)
m_skimmerThingTimer = 0.0f;
}
// Apply buoyancy impulse the second time (why twice?)
if(!onLand && bBoatInWater && GetUp().z > 0.0f){
#ifdef FIX_BUGS
// buoyanceImpulse already has a factor of timestep in it
float impulse = m_vecMoveSpeed.MagnitudeSqr()*pBoatHandling->fAqPlaneForce*buoyanceImpulse.z*CTimer::GetDefaultTimeStep()*0.5f;
#else
float impulse = m_vecMoveSpeed.MagnitudeSqr()*pBoatHandling->fAqPlaneForce*buoyanceImpulse.z*CTimer::GetTimeStep()*0.5f;
#endif
if(GetModelIndex() == MI_SKIMMER)
impulse *= 1.0f + m_fGasPedal;
else if(m_fGasPedal > 0.05f)
impulse *= m_fGasPedal;
else
impulse = 0.0f;
impulse = Min(impulse, GRAVITY*pBoatHandling->fAqPlaneLimit*m_fMass*CTimer::GetTimeStep());
impulse = Min(impulse, GRAVITY*pBoatHandling->fAqPlaneLimit*m_fMass*CTimer::GetTimeStep()); // Both sides have a factor of TimeStep, therefore this Min() is not a problem at high FPS
ApplyMoveForce(impulse*GetUp());
ApplyTurnForce(impulse*GetUp(), buoyancePoint - pBoatHandling->fAqPlaneOffset*GetForward());
}
@ -378,7 +397,11 @@ CBoat::ProcessControl(void)
// Handle boat moving forward
float fwdSpeed = 1.0f;
if(Abs(m_fGasPedal) > 0.05f || (fwdSpeed = m_vecMoveSpeed.Magnitude2D()) > 0.01f){
#ifdef FIX_BUGS
if(bBoatInWater && fwdSpeed > 0.05f && CTimer::GetLogicalFramesPassed()) // Fix super-short wake trail at high FPS
#else
if(bBoatInWater && fwdSpeed > 0.05f)
#endif
AddWakePoint(GetPosition());
float steerFactor = 1.0f;
@ -433,7 +456,11 @@ CBoat::ProcessControl(void)
// Spray some particles
CVector jetDir = -0.04f * force;
#ifdef FIX_BUGS
if(m_fGasPedal > 0.0f && CTimer::GetLogicalFramesPassed()){ // Fix high-FPS particle spam
#else
if(m_fGasPedal > 0.0f){
#endif
if(GetStatus() == STATUS_PLAYER){
CVector sternPos = GetColModel()->boundingBox.min;
sternPos.x = 0.0f;
@ -475,7 +502,11 @@ CBoat::ProcessControl(void)
CVector propellerForce = propellerDepth * Multiply3x3(GetMatrix(), force*CVector(-steerSin, 0.0f, 0.0f));
ApplyMoveForce(propellerForce * CTimer::GetTimeStep());
ApplyTurnForce(propellerForce * CTimer::GetTimeStep(), propeller);
#ifdef FIX_BUGS
float rightForce = -steerSin * force * 0.75f/steerFactor * CTimer::GetTimeStep();
#else
float rightForce = -steerSin * force * 0.75f/steerFactor * Max(CTimer::GetTimeStep(), 0.01f);
#endif
ApplyTurnForce(GetRight() * rightForce, GetUp());
}
}else
@ -485,7 +516,12 @@ CBoat::ProcessControl(void)
CVector right = CrossProduct(GetForward(), CVector(0.0f, 0.0f, 1.0f));
float rightSpeed = DotProduct(m_vecMoveSpeed, right);
float impulse = 0.1f*pHandling->fSuspensionBias * m_fMass * m_fVolumeUnderWater * rightSpeed * CTimer::GetTimeStep();
ApplyMoveForce(right - impulse * 0.3f * CVector(-right.y, right.x, 0.0f));
#ifdef FIX_BUGS
// Fix boat perf at high FPS: ensure both terms have a (correct) factor of timestep before doing subtraction
ApplyMoveForce(right * CTimer::GetTimeStepFix() - impulse * 0.3f * CVector(-right.y, right.x, 0.0f));
#else
ApplyMoveForce(right - impulse * 0.3f * CVector(-right.y, right.x, 0.0f));
#endif
}
if(GetStatus() == STATUS_PLAYER && CPad::GetPad(0)->GetHandBrake()){
@ -503,25 +539,45 @@ CBoat::ProcessControl(void)
m_vecMoveSpeed.y = Min(m_vecMoveSpeed.y, -(GetPosition().y - (WORLD_MAX_Y-100.0f))*0.01f); // north
m_vecMoveSpeed.y = Max(m_vecMoveSpeed.y, -(GetPosition().y - (WORLD_MIN_Y+100.0f))*0.01f); // south
// Apply water resistance to linear movement
if(!onLand && bBoatInWater && !bSeparateTurnForce)
ApplyWaterResistance();
// Apply water resistance to rotation
if((GetModelIndex() != MI_SKIMMER || m_skimmerThingTimer == 0.0f) && !bSeparateTurnForce){
// No idea what exactly is going on here besides drag in YZ
#ifdef FIX_BUGS
// Rockstar's attempts to make this framerate independent are totally wrong.
// Rules of thumb:
// - use Pow(x,time) if you multiply the result into the velocity
// - use x*time if you add the result into the velocity
// We have to disable one of these Pow() methods and then add our own correction at the end.
float fxfake = Pow(pBoatHandling->vecTurnRes.x, CTimer::GetDefaultTimeStep());
float fy = Pow(pBoatHandling->vecTurnRes.y, CTimer::GetTimeStep());
float fz = Pow(pBoatHandling->vecTurnRes.z, CTimer::GetTimeStep());
m_vecTurnSpeed = Multiply3x3(m_vecTurnSpeed, GetMatrix()); // invert - to local space
float drag = 1.0f/(1000.0f * SQR(m_vecTurnSpeed.x) + 1.0f) * fxfake;
m_vecTurnSpeed.y *= fy;
m_vecTurnSpeed.z *= fz;
float forceUp = -(1.0f - drag) * m_vecTurnSpeed.x * m_fTurnMass;
m_vecTurnSpeed = Multiply3x3(GetMatrix(), m_vecTurnSpeed); // back to world
CVector com = Multiply3x3(GetMatrix(), m_vecCentreOfMass);
ApplyTurnForce(forceUp*GetUp() * CTimer::GetTimeStepFix(), com + GetForward());
#else
float fx = Pow(pBoatHandling->vecTurnRes.x, CTimer::GetTimeStep());
float fy = Pow(pBoatHandling->vecTurnRes.y, CTimer::GetTimeStep());
float fz = Pow(pBoatHandling->vecTurnRes.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;
float drag = 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;
float forceUp = (drag - 1.0f) * m_vecTurnSpeed.x * m_fTurnMass;
m_vecTurnSpeed = Multiply3x3(GetMatrix(), m_vecTurnSpeed); // back to world
CVector com = Multiply3x3(GetMatrix(), m_vecCentreOfMass);
ApplyTurnForce(forceUp*GetUp(), com + GetForward());
#endif
}
m_nDeltaVolumeUnderWater = (m_fVolumeUnderWater-m_fPrevVolumeUnderWater)*10000;
// Falling into water
@ -539,6 +595,9 @@ CBoat::ProcessControl(void)
speedFwd *= -m_nDeltaVolumeUnderWater * 0.01f * pHandling->fBrakeBias;
CVector speed = speedFwd*GetForward() + CVector(0.0f, 0.0f, speedUp);
CVector splashImpulse = speed * m_fMass;
#ifdef FIX_BUGS
splashImpulse *= CTimer::GetTimeStepFix();
#endif
ApplyMoveForce(splashImpulse);
ApplyTurnForce(splashImpulse, buoyancePoint);
}
@ -546,8 +605,15 @@ CBoat::ProcessControl(void)
// Splashes
float speed = m_vecMoveSpeed.Magnitude();
#ifdef FIX_BUGS
if(speed > 0.05f && GetUp().x > 0.0f && !TheCamera.GetLookingForwardFirstPerson() && IsVisible() &&
(AutoPilot.m_nCarMission != MISSION_CRUISE || (CTimer::GetFrameCounter()&2) == 0)){
(AutoPilot.m_nCarMission != MISSION_CRUISE || (CTimer::GetFrameCounter()&2) == 0) &&
CTimer::GetLogicalFramesPassed() ) // Fix particle spam at high FPS
#else
if(speed > 0.05f && GetUp().x > 0.0f && !TheCamera.GetLookingForwardFirstPerson() && IsVisible() &&
(AutoPilot.m_nCarMission != MISSION_CRUISE || (CTimer::GetFrameCounter()&2) == 0))
#endif
{
CVector splashPos, splashDir;
float splashSize, front, waterLevel;
@ -682,8 +748,14 @@ CBoat::ProcessControl(void)
}
// Spray waterdrops on screen
#ifdef FIX_BUGS
if(TheCamera.GetLookingForwardFirstPerson() && FindPlayerVehicle() && FindPlayerVehicle()->IsBoat() &&
m_nDeltaVolumeUnderWater > 0 && numWaterDropOnScreen < 20){
m_nDeltaVolumeUnderWater > 0 && numWaterDropOnScreen < 20 && CTimer::GetLogicalFramesPassed()) // Fix particle spam at high FPS
#else
if(TheCamera.GetLookingForwardFirstPerson() && FindPlayerVehicle() && FindPlayerVehicle()->IsBoat() &&
m_nDeltaVolumeUnderWater > 0 && numWaterDropOnScreen < 20)
#endif
{
CVector dropPos;
CVector dropDir(CGeneral::GetRandomNumberInRange(-0.25f, 0.25f), CGeneral::GetRandomNumberInRange(1.0f, 0.75f), 0.0f);
@ -714,7 +786,13 @@ CBoat::ProcessControl(void)
numWaterDropOnScreen++;
}
if(m_fPrevVolumeUnderWater == 0.0f && m_fVolumeUnderWater > 0.0f && GetModelIndex() == MI_SKIMMER){
#ifdef FIX_BUGS
if(m_fPrevVolumeUnderWater == 0.0f && m_fVolumeUnderWater > 0.0f && GetModelIndex() == MI_SKIMMER &&
CTimer::GetLogicalFramesPassed()) // Fix particle spam at high FPS
#else
if(m_fPrevVolumeUnderWater == 0.0f && m_fVolumeUnderWater > 0.0f && GetModelIndex() == MI_SKIMMER)
#endif
{
CVector splashDir(0.0f, 0.0f, 0.25f*speed);
CVector splashPos = GetPosition();
float level;
@ -773,6 +851,18 @@ CBoat::ProcessControlInputs(uint8 pad)
m_fBrake += (CPad::GetPad(pad)->GetBrake()/255.0f - m_fBrake)*0.1f;
m_fBrake = Clamp(m_fBrake, 0.0f, 1.0f);
#ifdef FIX_BUGS
// Fix accelerator control and steering control ramp rates at high FPS
if(m_fBrake < 0.05f){
m_fBrake = 0.0f;
m_fAccelerate += (CPad::GetPad(pad)->GetAccelerate()/255.0f - m_fAccelerate)*0.1f*CTimer::GetTimeStepFix();
m_fAccelerate = Clamp(m_fAccelerate, 0.0f, 1.0f);
}else
m_fAccelerate = -m_fBrake*0.3f;
m_fSteeringLeftRight += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteeringLeftRight)*0.2f*CTimer::GetTimeStepFix();
m_fSteeringLeftRight = Clamp(m_fSteeringLeftRight, -1.0f, 1.0f);
#else
if(m_fBrake < 0.05f){
m_fBrake = 0.0f;
m_fAccelerate += (CPad::GetPad(pad)->GetAccelerate()/255.0f - m_fAccelerate)*0.1f;
@ -782,6 +872,7 @@ CBoat::ProcessControlInputs(uint8 pad)
m_fSteeringLeftRight += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteeringLeftRight)*0.2f;
m_fSteeringLeftRight = Clamp(m_fSteeringLeftRight, -1.0f, 1.0f);
#endif
float steeringSq = m_fSteeringLeftRight < 0.0f ? -SQR(m_fSteeringLeftRight) : SQR(m_fSteeringLeftRight);
m_fSteerAngle = pHandling->fSteeringLock * DEGTORAD(steeringSq);
@ -793,6 +884,82 @@ float fSeaPlaneWaterResistance = 30.0f;
void
CBoat::ApplyWaterResistance(void)
{
#ifdef FIX_BUGS
// TODO: confirm if the explanation below makes sense
float depthResistance = 0.001f * pHandling->fSuspensionForceLevel * SQR(m_fVolumeUnderWater) * m_fMass;
if(GetModelIndex() == MI_SKIMMER)
depthResistance *= fSeaPlaneWaterResistance;
float fwdSpeed = DotProduct(GetMoveSpeed(), GetForward());
// Water resistances goes up with the square of boat speed (in real life it goes up by the
// cube? close enough!). An extra 0.05f fudge factor was probably put in to make sure the
// boat still has resistance at low speeds (ie auto-brakes to standstill).
float waterResistance = (SQR(fwdSpeed) + 0.05f) * Abs(depthResistance); // Abs() used defensively, negative numbers stuff things up later
// waterResistance will now be a small number like 0.002 or 0.015
// An odd use of Abs() was in the original binary. It's possible that the developers did not
// put this in intentionally, instead the compiler may have silently added it to avoid
// Pow() having to deal with negative numbers to a fractional power (undefined) later.
// Regardless it was done badly, making assumptions like vecMoveRes never accidentally
// being negative, so the use of Abs() has changed a little bit in this FIX_BUGS. In
// real gameplay these corner cases should rarely (never?) be encountered anyway.
// Our boat has different water resistances when travelling forwards (y axis) versus
// sideways (x axis). Boats tend to find it hard to move sideways.
float rx = Abs(pBoatHandling->vecMoveRes.x/(waterResistance + 1.0f)); // Abs() used defensively, negative numbers stuff things up later
float ry = Abs(pBoatHandling->vecMoveRes.y/(waterResistance + 1.0f));
float rz = Abs(pBoatHandling->vecMoveRes.z/(waterResistance + 1.0f));
// These rx, ry, rz resistance numbers will each be something like 0.8 or 0.9 or so
// Fun fact: the above equations are _approximately_ the same as:
//
// pBoatHandling->vecMoveRes.x * (1.0f - waterResistance)
//
// If you change the equations to this then boating feels about the same in-game.
// Which version makes more sense compared to physics in real life? Probably neither :P
// This second version of the equation is a little more efficient however (no division).
// Now how do we apply these rx ry rz resistance numbers to the boat speed?
// It's not simple:
//
// - We can't multiply them into the speed once per frame, because then players with
// higher framerates will get a lot more friction when boating (lower top speed).
//
// - We can't linearly modify each r number based off frametime, as higher FPS players
// will still end up with more friction. This is for the same reason why linearly
// reducing your bank account's yearly interest into monthly amounts but then
// compounding it monthly will yield you more money than just compounding it yearly.
//
// - We could try compounding each r number based off how many fixed units of time have
// passed (eg multiply itself by itself for every 1ms elapsed this frame). This will
// work fairly regardless of framerate.
//
// We don't actually have to limit ourselves to a fixed time unit (like 1ms chunks),
// instead we can raise the resistance to some power of time using Pow().
float rrx = Pow(rx, 0.5f*CTimer::GetTimeStep()); // Why 0.5f? Taste?
float rry = Pow(ry, 0.5f*CTimer::GetTimeStep());
float rrz = Pow(rz, 0.5f*CTimer::GetTimeStep());
float rryfake = Pow(ry, 0.5f*CTimer::GetDefaultTimeStep()); // Fudge factor needed for other equations to make sense at high FPS
m_vecMoveSpeed = Multiply3x3(m_vecMoveSpeed, GetMatrix()); // convert velocities to boat-local space (y = boat forwards, x = sideways, z = up/down)
m_vecMoveSpeed.x *= rrx;
m_vecMoveSpeed.y *= rry;
m_vecMoveSpeed.z *= rrz;
float force = (rryfake - 1.0f) * m_vecMoveSpeed.y * m_fMass;
m_vecMoveSpeed = Multiply3x3(GetMatrix(), m_vecMoveSpeed); // back to world space
// WTH is this for?
ApplyTurnForce(force*GetForward()*CTimer::GetTimeStepFix(), -GetUp());
// What the hell? Why arbitrarily compound in one more factor of rrz?
// This is framerate dependent! Bah! I suspect it has very little effect.
/*
if(m_vecMoveSpeed.z > 0.0f)
m_vecMoveSpeed.z *= rrz;
else
m_vecMoveSpeed.z *= (1.0f - rrz)*0.5f + rrz;
*/
#else
// TODO: figure out how this works
float resistance = 0.001f * pHandling->fSuspensionForceLevel * SQR(m_fVolumeUnderWater) * m_fMass;
if(GetModelIndex() == MI_SKIMMER)
@ -817,6 +984,7 @@ CBoat::ApplyWaterResistance(void)
m_vecMoveSpeed.z *= fz;
else
m_vecMoveSpeed.z *= (1.0f - fz)*0.5f + fz;
#endif
}
RwObject*

View File

@ -109,6 +109,17 @@ cBuoyancy::ProcessBuoyancyBoat(CVehicle *veh, float buoyancy, CVector *point, CV
float volume = SimpleSumBuoyancyData(waterLevel, waterPosition);
float upImpulse = volume * volDiv * buoyancy * CTimer::GetTimeStep();
CVector speed = veh->GetSpeed(Multiply3x3(veh->GetMatrix(), CVector(x, y, 0.0f)));
#ifdef FIX_BUGS
// "GetSpeed" seems to depend on framerate (bad).
// This ruins boat performance at high FPS. Approximate sequence of events:
// - "speed" goes tiny at high FPS
// - "damp" goes high as a result
// - high dampening reduces the buoyancy forces that keep the boat above the water
// - boats sit _slightly_ lower in water (you have to disable ALL waves to see this, it's a very small change)
// - all of boat handling performance changes because a different amount of the boat is underwater
// Finding this was a PITA!
speed /= CTimer::GetTimeStepFix();
#endif
float damp = 1.0f - DotProduct(speed, waterNormal)*veh->pHandling->fSuspensionDampingLevel;
float finalImpulse = upImpulse*Max(damp, 0.0f);
impulse->z += finalImpulse;

View File

@ -55,6 +55,8 @@ cTransmission::CalculateGearForSimpleCar(float speed, uint8 &gear)
}
}
/* This function causes 'pulsing' of throttle when reversing at max speed. You
* can most easily observe this when the framelimiter is enabled.*/
float
cTransmission::CalculateDriveAcceleration(const float &gasPedal, uint8 &gear, float &time, const float &velocity, bool cheat)
{
@ -123,7 +125,12 @@ cTransmission::CalculateDriveAcceleration(const float &gasPedal, uint8 &gear, fl
float targetVelocity = Gears[gear].fMaxVelocity*speedMul*fCheat;
float accel = (targetVelocity - fVelocity) * (fEngineAcceleration*accelMul) / Abs(targetVelocity);
if(Abs(fVelocity) < Abs(Gears[gear].fMaxVelocity*fCheat))
#ifdef FIX_BUGS
// The acceleration provided by a transmission+engine should not depend on framelength.
fAcceleration = gasPedal * accel;
#else
fAcceleration = gasPedal * accel * CTimer::GetTimeStep();
#endif
else
fAcceleration = 0.0f;
return fAcceleration;

View File

@ -126,6 +126,9 @@ CVehicle::CVehicle(uint8 CreatedBy)
m_nCarHornTimer = 0;
m_nCarHornPattern = 0;
m_nCarHornDelay = 0;
#ifdef FIX_BUGS
m_fCarHornTimeButtonLastHit = 0.0f;
#endif
bPartOfConvoy = false;
bHeliMinimumTilt = false;
bAudioChangingGear = false;
@ -788,7 +791,14 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
bAlreadySkidding = false;
#endif
// how much force we want to apply in these axes
// Velocity impulses fwd and right. Units are like meters per second.
// This function was written assuming a fixed FPS, so a correction is made
// right at the end before actually applying these impulses.
//
// Note that many functions in this engine deal with "force impulses" rather
// than "velocity impulses". They are directly related: F=ma. It is
// possible that the original devs actually used force impulses here but
// an optimising compiler re-arranged their maths.
float fwd = 0.0f;
float right = 0.0f;
@ -804,7 +814,12 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
bAlreadySkidding = true;
*wheelState = WHEEL_STATE_NORMAL;
#ifdef FIX_BUGS
// Everything else here is timestep independent, let's stay with this theme to keep the rest of the FPS bugfixes simpler.
adhesion *= CTimer::GetDefaultTimeStep();
#else
adhesion *= CTimer::GetTimeStep();
#endif
if(bAlreadySkidding)
adhesion *= pHandling->fTractionLoss;
@ -812,12 +827,6 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
if(contactSpeedRight != 0.0f){
// exert opposing force
right = -contactSpeedRight/wheelsOnGround;
// BUG?
// contactSpeedRight is independent of framerate but right has timestep as a factor
// so we probably have to fix this
// fixing this causes jittery cars at 15fps, and causes the car to move backwards slowly at 18fps
// at 19fps, the effects are gone ...
//right *= CTimer::GetTimeStepFix();
if(wheelStatus == WHEEL_STATUS_BURST){
float fwdspeed = Min(contactSpeedFwd, fBurstSpeedMax);
@ -828,7 +837,7 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
if(bDriving){
fwd = thrust;
// limit sideways force (why?)
// Limit sideways forces applied by the tires to the max the tires can possibly do.
if(right > 0.0f){
if(right > adhesion)
right = adhesion;
@ -838,11 +847,6 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
}
}else if(contactSpeedFwd != 0.0f){
fwd = -contactSpeedFwd/wheelsOnGround;
#ifdef FIX_BUGS
// contactSpeedFwd is independent of framerate but fwd has timestep as a factor
// so we probably have to fix this
fwd *= CTimer::GetTimeStepFix();
#endif
if(!bBraking){
if(m_fGasPedal < 0.01f){
@ -854,9 +858,6 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
brake = 0.2f * mod_HandlingManager.fWheelFriction / pHandling->fMass;
else
brake = mod_HandlingManager.fWheelFriction / pHandling->fMass;
#ifdef FIX_BUGS
brake *= CTimer::GetTimeStepFix();
#endif
}
}
@ -883,10 +884,10 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
*wheelState = WHEEL_STATE_SKIDDING;
}
float l = Sqrt(speedSq);
float speed = Sqrt(speedSq);
float tractionLoss = bAlreadySkidding ? 1.0f : pHandling->fTractionLoss;
right *= adhesion * tractionLoss / l;
fwd *= adhesion * tractionLoss / l;
right *= adhesion * tractionLoss / speed;
fwd *= adhesion * tractionLoss / speed;
}
if(fwd != 0.0f || right != 0.0f){
@ -918,9 +919,19 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
else
turnDirection = direction;
// Curious: there is a perfectly good ApplyMoveSpeed() function that
// takes "velocity impulses", but instead we use the ApplyMoveForce()
// function which takes a "force impulse" instead and then fix up the
// difference by multiplying in the vehicle mass (F=ma). Possibly
// evidence that an optimising compiler re-arranged the arithmetic?
float impulse = speed*m_fMass;
float turnImpulse = turnSpeed*GetMass(wheelContactPoint, turnDirection);
#ifdef FIX_BUGS
impulse = impulse * CTimer::GetTimeStepFix();
turnImpulse = turnImpulse * CTimer::GetTimeStepFix();
#endif
ApplyMoveForce(impulse * direction);
ApplyTurnForce(turnImpulse * turnDirection, wheelContactPoint);
}
@ -944,7 +955,14 @@ CVehicle::ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &whee
bAlreadySkidding = false;
#endif
// how much force we want to apply in these axes
// Velocity impulses fwd and right. Units are like meters per second.
// This function was written assuming a fixed FPS, so a correction is made
// right at the end before actually applying these impulses.
//
// Note that many functions in this engine deal with "force impulses" rather
// than "velocity impulses". They are directly related: F=ma. It is
// possible that the original devs actually used force impulses here but
// an optimising compiler re-arranged their maths.
float fwd = 0.0f;
float right = 0.0f;
@ -961,7 +979,12 @@ CVehicle::ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &whee
bAlreadySkidding = true;
*wheelState = WHEEL_STATE_NORMAL;
#ifdef FIX_BUGS
// Everything else here is timestep independent, let's stay with this theme to keep the rest of the FPS bugfixes simpler.
adhesion *= CTimer::GetDefaultTimeStep();
#else
adhesion *= CTimer::GetTimeStep();
#endif
if(bAlreadySkidding)
adhesion *= pHandling->fTractionLoss;
@ -974,14 +997,9 @@ CVehicle::ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &whee
if(contactSpeedRight != 0.0f){
// exert opposing force
right = -contactSpeedRight/wheelsOnGround;
#ifdef FIX_BUGS
// contactSpeedRight is independent of framerate but right has timestep as a factor
// so we probably have to fix this
right *= CTimer::GetTimeStepFix();
#endif
if(wheelStatus == WHEEL_STATUS_BURST){
float fwdspeed = Min(contactSpeedFwd, fBurstBikeSpeedMax);
float fwdspeed = Min(contactSpeedFwd, fBurstBikeSpeedMax);
right += fwdspeed * CGeneral::GetRandomNumberInRange(-fBurstBikeTyreMod, fBurstBikeTyreMod);
}
}
@ -999,12 +1017,6 @@ CVehicle::ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &whee
}
}else if(contactSpeedFwd != 0.0f){
fwd = -contactSpeedFwd/wheelsOnGround;
#ifdef FIX_BUGS
// contactSpeedFwd is independent of framerate but fwd has timestep as a factor
// so we probably have to fix this
fwd *= CTimer::GetTimeStepFix();
#endif
if(!bBraking){
if(m_fGasPedal < 0.01f){
if(IsBike())
@ -1015,9 +1027,6 @@ CVehicle::ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &whee
brake = 0.2f * mod_HandlingManager.fWheelFriction / m_fMass;
else
brake = mod_HandlingManager.fWheelFriction / m_fMass;
#ifdef FIX_BUGS
brake *= CTimer::GetTimeStepFix();
#endif
}
}
@ -1068,6 +1077,10 @@ CVehicle::ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &whee
float impulse = speed*m_fMass;
float turnImpulse = speed*GetMass(wheelContactPoint, direction);
#ifdef FIX_BUGS
impulse = impulse * CTimer::GetTimeStepFix();
turnImpulse = turnImpulse * CTimer::GetTimeStepFix();
#endif
CVector vTurnImpulse = turnImpulse * direction;
ApplyMoveForce(impulse * direction);

View File

@ -273,6 +273,9 @@ public:
uint8 m_nCarHornPattern;
bool m_bSirenOrAlarm;
uint8 m_nCarHornDelay;
#ifdef FIX_BUGS
float m_fCarHornTimeButtonLastHit;
#endif
int8 m_comedyControlState;
CStoredCollPoly m_aCollPolys[2]; // poly which is under front/rear part of car
float m_fSteerInput;