From 9a7ce75c0371b4c35523a6c8872bba782a1eeb0b Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 18 Jul 2019 21:41:20 +0200 Subject: [PATCH] CAutomobile damage --- src/vehicles/Automobile.cpp | 295 ++++++++++++++++++++++++++++++++- src/vehicles/Automobile.h | 5 +- src/vehicles/DamageManager.cpp | 18 +- src/vehicles/DamageManager.h | 5 + src/vehicles/Vehicle.cpp | 6 +- src/vehicles/Vehicle.h | 17 +- 6 files changed, 323 insertions(+), 23 deletions(-) diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index ecf3bde3..6890eeb9 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -1,4 +1,5 @@ #include "common.h" +#include "main.h" #include "patcher.h" #include "General.h" #include "Pad.h" @@ -317,7 +318,7 @@ CAutomobile::ProcessControl(void) return; } - VehicleDamage(1.0f, 0); + VehicleDamage(0.0f, 0); // special control switch(GetModelIndex()){ @@ -925,7 +926,7 @@ CAutomobile::ProcessControl(void) m_fFireBlowUpTimer = 0.0f; // Decrease car health if engine is damaged badly - if(engineStatus > 225 && m_fHealth > 250.0f) + if(engineStatus > ENGINE_STATUS_ON_FIRE && m_fHealth > 250.0f) m_fHealth -= 2.0f; ProcessDelayedExplosion(); @@ -1283,12 +1284,6 @@ CAutomobile::HydraulicControl(void) { EAXJMP(0x52D4E0); } -WRAPPER void -CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece) -{ EAXJMP(0x52F390); -} - - WRAPPER void CAutomobile::ProcessBuoyancy(void) { EAXJMP(0x5308D0); @@ -1304,6 +1299,289 @@ CAutomobile::RcbanditCheckHitWheels(void) { EAXJMP(0x53C990); } +//WRAPPER void +//CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece) +//{ EAXJMP(0x52F390); +void +CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece) +{ + int i; + float damageMultiplier = 0.2f; + bool doubleMoney = false; + + if(impulse == 0.0f){ + impulse = m_fDamageImpulse; + damagedPiece = m_nDamagePieceType; + damageMultiplier = 1.0f; + } + + CVector pos(0.0f, 0.0f, 0.0f); + + if(!bCanBeDamaged) + return; + + // damage flipped over car + if(GetUp().z < 0.0f && this != FindPlayerVehicle()){ + if(bNotDamagedUpsideDown || m_status == STATUS_PLAYER_REMOTE || bIsInWater) + return; + m_fHealth -= 4.0f*CTimer::GetTimeStep(); + } + + if(impulse > 25.0f && m_status != STATUS_WRECKED){ + if(bIsLawEnforcer && + FindPlayerVehicle() && FindPlayerVehicle() == m_pDamageEntity && + m_status != STATUS_ABANDONED && + FindPlayerVehicle()->m_vecMoveSpeed.Magnitude() >= m_vecMoveSpeed.Magnitude() && + FindPlayerVehicle()->m_vecMoveSpeed.Magnitude() > 0.2f) + FindPlayerPed()->SetWantedLevelNoDrop(1); + + if(m_status == STATUS_PLAYER && impulse > 50.0f){ + uint8 freq = min(0.4f*impulse*2000.0f/m_fMass + 100.0f, 250.0f); + CPad::GetPad(0)->StartShake(40000/freq, freq); + } + + if(bOnlyDamagedByPlayer){ + if(m_pDamageEntity != FindPlayerPed() && + m_pDamageEntity != FindPlayerVehicle()) + return; + } + + if(bCollisionProof) + return; + + if(m_pDamageEntity){ + if(m_pDamageEntity->m_status == STATUS_PLAYER_PLAYBACKFROMBUFFER && + DotProduct(m_vecDamageNormal, GetUp()) > 0.6f) + return; + } + + int oldLightStatus[4]; + for(i = 0; i < 4; i++) + oldLightStatus[i] = Damage.GetLightStatus((eLights)i); + + if(GetUp().z > 0.0f || m_vecMoveSpeed.MagnitudeSqr() > 0.1f){ + float impulseMult = bMoreResistantToDamage ? 0.5f : 4.0f; + + switch(damagedPiece){ + case CAR_PIECE_BUMP_FRONT: + GetComponentWorldPosition(CAR_BUMP_FRONT, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if(Damage.ApplyDamage(COMPONENT_BUMPER_FRONT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetBumperDamage(CAR_BUMP_FRONT, VEHBUMPER_FRONT); + doubleMoney = true; + } + if(m_aCarNodes[CAR_BONNET] && Damage.GetPanelStatus(VEHBUMPER_FRONT) == PANEL_STATUS_MISSING){ + case CAR_PIECE_BONNET: + GetComponentWorldPosition(CAR_BONNET, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if(Damage.ApplyDamage(COMPONENT_DOOR_BONNET, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetDoorDamage(CAR_BONNET, DOOR_BONNET); + doubleMoney = true; + } + } + break; + + case CAR_PIECE_BUMP_REAR: + GetComponentWorldPosition(CAR_BUMP_REAR, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if(Damage.ApplyDamage(COMPONENT_BUMPER_FRONT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetBumperDamage(CAR_BUMP_REAR, VEHBUMPER_REAR); + doubleMoney = true; + } + if(m_aCarNodes[CAR_BOOT] && Damage.GetPanelStatus(VEHBUMPER_REAR) == PANEL_STATUS_MISSING){ + case CAR_PIECE_BOOT: + GetComponentWorldPosition(CAR_BOOT, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if(Damage.ApplyDamage(COMPONENT_DOOR_BOOT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetDoorDamage(CAR_BOOT, DOOR_BOOT); + doubleMoney = true; + } + } + break; + + case CAR_PIECE_DOOR_LF: + GetComponentWorldPosition(CAR_DOOR_LF, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) && + Damage.ApplyDamage(COMPONENT_DOOR_FRONT_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetDoorDamage(CAR_DOOR_LF, DOOR_FRONT_LEFT); + doubleMoney = true; + } + break; + case CAR_PIECE_DOOR_RF: + GetComponentWorldPosition(CAR_DOOR_RF, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) && + Damage.ApplyDamage(COMPONENT_DOOR_FRONT_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetDoorDamage(CAR_DOOR_RF, DOOR_FRONT_RIGHT); + doubleMoney = true; + } + break; + case CAR_PIECE_DOOR_LR: + GetComponentWorldPosition(CAR_DOOR_LR, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) && + Damage.ApplyDamage(COMPONENT_DOOR_REAR_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetDoorDamage(CAR_DOOR_LR, DOOR_REAR_LEFT); + doubleMoney = true; + } + break; + case CAR_PIECE_DOOR_RR: + GetComponentWorldPosition(CAR_DOOR_RR, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) && + Damage.ApplyDamage(COMPONENT_DOOR_REAR_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetDoorDamage(CAR_DOOR_RR, DOOR_REAR_RIGHT); + doubleMoney = true; + } + break; + + case CAR_PIECE_WING_LF: + GetComponentWorldPosition(CAR_WING_LF, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetPanelDamage(CAR_WING_LF, VEHPANEL_FRONT_LEFT); + doubleMoney = true; + } + break; + case CAR_PIECE_WING_RF: + GetComponentWorldPosition(CAR_WING_RF, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetPanelDamage(CAR_WING_RF, VEHPANEL_FRONT_RIGHT); + doubleMoney = true; + } + break; + case CAR_PIECE_WING_LR: + GetComponentWorldPosition(CAR_WING_LR, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetPanelDamage(CAR_WING_LR, VEHPANEL_REAR_LEFT); + doubleMoney = true; + } + break; + case CAR_PIECE_WING_RR: + GetComponentWorldPosition(CAR_WING_RR, pos); + dmgDrawCarCollidingParticles(pos, impulse); + if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + SetPanelDamage(CAR_WING_RR, VEHPANEL_REAR_RIGHT); + doubleMoney = true; + } + break; + + case CAR_PIECE_WHEEL_LF: + case CAR_PIECE_WHEEL_LR: + case CAR_PIECE_WHEEL_RF: + case CAR_PIECE_WHEEL_RR: + break; + + case CAR_PIECE_WINDSCREEN: + if(Damage.ApplyDamage(COMPONENT_PANEL_WINDSCREEN, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){ + uint8 oldStatus = Damage.GetPanelStatus(VEHPANEL_WINDSCREEN); + SetPanelDamage(CAR_WINDSCREEN, VEHPANEL_WINDSCREEN); + if(oldStatus != Damage.GetPanelStatus(VEHPANEL_WINDSCREEN)){ + DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_WINDSHIELD_CRACK, 0.0f); + doubleMoney = true; + } + } + break; + } + + if(m_pDamageEntity && m_pDamageEntity == FindPlayerVehicle() && impulse > 10.0f){ + int money = (doubleMoney ? 2 : 1) * impulse*pHandling->nMonetaryValue/1000000.0f; + money = min(money, 40); + if(money > 2){ + sprintf(gString, "$%d", money); + CWorld::Players[CWorld::PlayerInFocus].m_nMoney += money; + } + } + } + + float damage = (impulse-25.0f)*pHandling->fCollisionDamageMultiplier*0.6f*damageMultiplier; + + if(GetModelIndex() == MI_SECURICA && m_pDamageEntity && m_pDamageEntity->m_status == STATUS_PLAYER) + damage *= 7.0f; + + if(damage > 0.0f){ + int oldHealth = m_fHealth; + if(this == FindPlayerVehicle()){ + m_fHealth -= bTakeLessDamage ? damage/6.0f : damage/2.0f; + }else{ + if(damage > 35.0f && pDriver) + pDriver->Say(SOUND_PED_CAR_COLLISION); + m_fHealth -= bTakeLessDamage ? damage/12.0f : damage/4.0f; + } + if(m_fHealth <= 0.0f && oldHealth > 0) + m_fHealth = 1.0f; + } + + // play sound if a light broke + for(i = 0; i < 4; i++) + if(oldLightStatus[i] != 1 && Damage.GetLightStatus((eLights)i) == 1){ + DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_LIGHT_BREAK, i); // BUG? i? + break; + } + } + + if(m_fHealth < 250.0f){ + // Car is on fire + if(Damage.GetEngineStatus() < ENGINE_STATUS_ON_FIRE){ + // Set engine on fire and remember who did this + Damage.SetEngineStatus(ENGINE_STATUS_ON_FIRE); + m_fFireBlowUpTimer = 0.0f; + m_pSetOnFireEntity = m_pDamageEntity; + if(m_pSetOnFireEntity) + m_pSetOnFireEntity->RegisterReference(&m_pSetOnFireEntity); + } + }else{ + if(GetModelIndex() == MI_BFINJECT){ + if(m_fHealth < 400.0f) + Damage.SetEngineStatus(200); + else if(m_fHealth < 600.0f) + Damage.SetEngineStatus(100); + } + } +} + +void +CAutomobile::dmgDrawCarCollidingParticles(const CVector &pos, float amount) +{ + int i, n; + + if(!GetIsOnScreen()) + return; + + // FindPlayerSpeed() unused + + n = (int)amount/20; + + for(i = 0; i < ((n+4)&0x1F); i++) + CParticle::AddParticle(PARTICLE_SPARK_SMALL, pos, + CVector(CGeneral::GetRandomNumberInRange(-0.1f, 0.1f), + CGeneral::GetRandomNumberInRange(-0.1f, 0.1f), + 0.006f)); + + for(i = 0; i < n+2; i++) + CParticle::AddParticle(PARTICLE_CARCOLLISION_DUST, + CVector(CGeneral::GetRandomNumberInRange(-1.2f, 1.2f) + pos.x, + CGeneral::GetRandomNumberInRange(-1.2f, 1.2f) + pos.y, + pos.z), + CVector(0.0f, 0.0f, 0.0f), nil, 0.5f); + + n = (int)amount/50 + 1; + for(i = 0; i < n; i++) + CParticle::AddParticle(PARTICLE_CAR_DEBRIS, pos, + CVector(CGeneral::GetRandomNumberInRange(-0.25f, 0.25f), + CGeneral::GetRandomNumberInRange(-0.25f, 0.25f), + CGeneral::GetRandomNumberInRange(0.1f, 0.25f)), + nil, + CGeneral::GetRandomNumberInRange(0.02f, 0.08f), + CVehicleModelInfo::ms_vehicleColourTable[m_currentColour1], + CGeneral::GetRandomNumberInRange(-40.0f, 40.0f), + 0, + CGeneral::GetRandomNumberInRange(0.0f, 4.0f)); +} + void CAutomobile::GetComponentWorldPosition(int32 component, CVector &pos) { @@ -2292,6 +2570,7 @@ STARTPATCHES InjectHook(0x53C0E0, &CAutomobile_::BurstTyre_, PATCH_JUMP); InjectHook(0x437690, &CAutomobile_::GetHeightAboveRoad_, PATCH_JUMP); InjectHook(0x53C450, &CAutomobile_::PlayCarHorn_, PATCH_JUMP); + InjectHook(0x52F030, &CAutomobile::dmgDrawCarCollidingParticles, PATCH_JUMP); InjectHook(0x5353A0, &CAutomobile::ResetSuspension, PATCH_JUMP); InjectHook(0x52D210, &CAutomobile::SetupSuspensionLines, PATCH_JUMP); InjectHook(0x53E000, &CAutomobile::BlowUpCarsInPath, PATCH_JUMP); diff --git a/src/vehicles/Automobile.h b/src/vehicles/Automobile.h index 5ff39fed..6caf5dde 100644 --- a/src/vehicles/Automobile.h +++ b/src/vehicles/Automobile.h @@ -49,7 +49,9 @@ public: uint8 m_auto_flagA20 : 1; uint8 m_auto_flagA40 : 1; uint8 m_auto_flagA80 : 1; - uint8 field_4DA[2]; + uint8 bNotDamagedUpsideDown : 1; + uint8 bMoreResistantToDamage : 1; + uint8 field_4DB; CEntity *field_4DC; // blow up entity uint8 field_4E0[4]; uint32 m_nBusDoorTimerEnd; @@ -115,6 +117,7 @@ public: void ProcessBuoyancy(void); void DoDriveByShootings(void); int32 RcbanditCheckHitWheels(void); + void dmgDrawCarCollidingParticles(const CVector &pos, float amount); void PlayHornIfNecessary(void); void ResetSuspension(void); void SetupSuspensionLines(void); diff --git a/src/vehicles/DamageManager.cpp b/src/vehicles/DamageManager.cpp index 380537f2..c4d16207 100644 --- a/src/vehicles/DamageManager.cpp +++ b/src/vehicles/DamageManager.cpp @@ -18,15 +18,15 @@ CDamageManager::FuckCarCompletely(void) { int i; - m_wheelStatus[0] = 2; + m_wheelStatus[0] = WHEEL_STATUS_MISSING; // wheels 1-3 not reset? - m_doorStatus[0] = 3; - m_doorStatus[1] = 3; - m_doorStatus[2] = 3; - m_doorStatus[3] = 3; - m_doorStatus[4] = 3; - m_doorStatus[5] = 3; + m_doorStatus[0] = DOOR_STATUS_MISSING; + m_doorStatus[1] = DOOR_STATUS_MISSING; + m_doorStatus[2] = DOOR_STATUS_MISSING; + m_doorStatus[3] = DOOR_STATUS_MISSING; + m_doorStatus[4] = DOOR_STATUS_MISSING; + m_doorStatus[5] = DOOR_STATUS_MISSING; for(i = 0; i < 3; i++){ #ifdef FIX_BUGS @@ -216,8 +216,8 @@ CDamageManager::ProgressEngineDamage(void) { int status = GetEngineStatus(); int newstatus = status + 32 + (CGeneral::GetRandomNumber() & 0x1F); - if(status < 225 && newstatus > 224) - newstatus = 224; + if(status < ENGINE_STATUS_ON_FIRE && newstatus > ENGINE_STATUS_ON_FIRE-1) + newstatus = ENGINE_STATUS_ON_FIRE-1; SetEngineStatus(newstatus); return true; } diff --git a/src/vehicles/DamageManager.h b/src/vehicles/DamageManager.h index ee1297d9..37fd90f5 100644 --- a/src/vehicles/DamageManager.h +++ b/src/vehicles/DamageManager.h @@ -4,6 +4,11 @@ // TODO: move some of this into Vehicle.h +enum eEngineStatus +{ + ENGINE_STATUS_ON_FIRE = 225 +}; + enum eDoorStatus { DOOR_STATUS_OK, diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index b91e4268..4ac3af53 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -61,7 +61,7 @@ CVehicle::CVehicle(uint8 CreatedBy) bComedyControls = false; m_veh_flagB40 = false; m_veh_flagB80 = false; - m_veh_flagC1 = false; + bTakeLessDamage = false; bIsDamaged = false; bFadeOut = false; m_veh_flagC10 = false; @@ -362,8 +362,8 @@ CVehicle::ExtinguishCarFire(void) m_pCarFire->Extinguish(); if(IsCar()){ CAutomobile *car = (CAutomobile*)this; - if(car->Damage.GetEngineStatus() >= 225) - car->Damage.SetEngineStatus(215); + if(car->Damage.GetEngineStatus() >= ENGINE_STATUS_ON_FIRE) + car->Damage.SetEngineStatus(ENGINE_STATUS_ON_FIRE-10); car->m_fFireBlowUpTimer = 0.0f; } } diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h index 7513c0da..3074bfb6 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -98,10 +98,23 @@ enum eWheels enum { - CAR_PIECE_WHEEL_LF = 13, + CAR_PIECE_BONNET = 1, + CAR_PIECE_BOOT, + CAR_PIECE_BUMP_FRONT, + CAR_PIECE_BUMP_REAR, + CAR_PIECE_DOOR_LF, + CAR_PIECE_DOOR_RF, + CAR_PIECE_DOOR_LR, + CAR_PIECE_DOOR_RR, + CAR_PIECE_WING_LF, + CAR_PIECE_WING_RF, + CAR_PIECE_WING_LR, + CAR_PIECE_WING_RR, + CAR_PIECE_WHEEL_LF, CAR_PIECE_WHEEL_LR, CAR_PIECE_WHEEL_RF, CAR_PIECE_WHEEL_RR, + CAR_PIECE_WINDSCREEN, }; enum tWheelState @@ -166,7 +179,7 @@ public: uint8 m_veh_flagB40 : 1; uint8 m_veh_flagB80 : 1; - uint8 m_veh_flagC1 : 1; + uint8 bTakeLessDamage : 1; // This vehicle is stronger (takes about 1/4 of damage) uint8 bIsDamaged : 1; // This vehicle has been damaged and is displaying all its components uint8 bHasBeenOwnedByPlayer : 1;// To work out whether stealing it is a crime uint8 bFadeOut : 1; // Fade vehicle out