summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/control/Garages.cpp12
-rw-r--r--src/control/Pickups.cpp29
-rw-r--r--src/vehicles/Vehicle.cpp188
-rw-r--r--src/vehicles/Vehicle.h3
-rw-r--r--src/weapons/Weapon.cpp1
-rw-r--r--src/weapons/Weapon.h2
6 files changed, 207 insertions, 28 deletions
diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp
index 93857b14..68d58b10 100644
--- a/src/control/Garages.cpp
+++ b/src/control/Garages.cpp
@@ -2078,14 +2078,12 @@ void CGarage::CenterCarInGarage(CVehicle* pVehicle)
return;
if (IsAnyOtherPedTouchingGarage(FindPlayerPed()))
return;
- float posX = pVehicle->GetPosition().x;
- float posY = pVehicle->GetPosition().y;
- float posZ = pVehicle->GetPosition().z;
+ CVector pos = pVehicle->GetPosition();
float garageX = GetGarageCenterX();
float garageY = GetGarageCenterY();
- float offsetX = garageX - posX;
- float offsetY = garageY - posY;
- float offsetZ = posZ - posZ;
+ float offsetX = garageX - pos.x;
+ float offsetY = garageY - pos.y;
+ float offsetZ = pos.z - pos.z;
float distance = CVector(offsetX, offsetY, offsetZ).Magnitude();
if (distance < RESPRAY_CENTERING_COEFFICIENT) {
pVehicle->GetPosition().x = GetGarageCenterX();
@@ -2096,7 +2094,7 @@ void CGarage::CenterCarInGarage(CVehicle* pVehicle)
pVehicle->GetPosition().y += offsetY * RESPRAY_CENTERING_COEFFICIENT / distance;
}
if (!IsEntityEntirelyInside3D(pVehicle, 0.1f))
- pVehicle->GetPosition() = CVector(posX, posY, posZ);
+ pVehicle->GetPosition() = pos;
}
void CGarages::CloseHideOutGaragesBeforeSave()
diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp
index b1832f0e..3e3c2a48 100644
--- a/src/control/Pickups.cpp
+++ b/src/control/Pickups.cpp
@@ -20,6 +20,9 @@
#include "Fire.h"
#include "PointLights.h"
#include "Pools.h"
+#ifdef FIX_BUGS
+#include "Replay.h"
+#endif
#include "Script.h"
#include "Shadows.h"
#include "SpecialFX.h"
@@ -642,32 +645,26 @@ CPickups::AddToCollectedPickupsArray(int32 index)
void
CPickups::Update()
{
-#ifndef FIX_BUGS
- // BUG: this code can only reach 318 out of 320 pickups
+#ifdef FIX_BUGS // RIP speedrunning (solution from SA)
+ if (CReplay::IsPlayingBack())
+ return;
+#endif
#define PICKUPS_FRAME_SPAN (6)
-#define PICKUPS_PER_FRAME (NUMGENERALPICKUPS/PICKUPS_FRAME_SPAN)
-
- for (uint32 i = PICKUPS_PER_FRAME * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN); i < PICKUPS_PER_FRAME * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1); i++) {
- if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) {
- AddToCollectedPickupsArray(i);
- }
- }
-
- for (uint32 i = NUMGENERALPICKUPS; i < NUMPICKUPS; i++) {
+#ifdef FIX_BUGS
+ for (uint32 i = NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN) / PICKUPS_FRAME_SPAN; i < NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1) / PICKUPS_FRAME_SPAN; i++) {
+#else // BUG: this code can only reach 318 out of 320 pickups
+ for (uint32 i = NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN); i < NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1); i++) {
+#endif
if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) {
AddToCollectedPickupsArray(i);
}
}
-
#undef PICKUPS_FRAME_SPAN
-#undef PICKUPS_PER_FRAME
-#else
- for (uint32 i = 0; i < NUMPICKUPS; i++) {
+ for (uint32 i = NUMGENERALPICKUPS; i < NUMPICKUPS; i++) {
if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) {
AddToCollectedPickupsArray(i);
}
}
-#endif
}
void
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index 1fe02953..adeba19e 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -31,10 +31,17 @@ void *CVehicle::operator new(size_t sz, int handle) { return CPools::GetVehicleP
void CVehicle::operator delete(void *p, size_t sz) { CPools::GetVehiclePool()->Delete((CVehicle*)p); }
void CVehicle::operator delete(void *p, int handle) { CPools::GetVehiclePool()->Delete((CVehicle*)p); }
-WRAPPER bool CVehicle::ShufflePassengersToMakeSpace(void) { EAXJMP(0x5528A0); }
-// or Weapon.cpp?
-WRAPPER void FireOneInstantHitRound(CVector *shotSource, CVector *shotTarget, int32 damage) { EAXJMP(0x563B00); }
-WRAPPER void CVehicle::InflictDamage(CEntity *damagedBy, uint32 weaponType, float damage) { EAXJMP(0x551950); }
+#ifdef FIX_BUGS
+// I think they meant that
+#define DAMAGE_FLEE_IN_CAR_PROBABILITY_VALUE (MYRAND_MAX * 35 / 100)
+#define DAMAGE_FLEE_ON_FOOT_PROBABILITY_VALUE (MYRAND_MAX * 70 / 100)
+#else
+#define DAMAGE_FLEE_IN_CAR_PROBABILITY_VALUE (35000)
+#define DAMAGE_FLEE_ON_FOOT_PROBABILITY_VALUE (70000)
+#endif
+#define DAMAGE_HEALTH_TO_FLEE_ALWAYS (200.0f)
+#define DAMAGE_HEALTH_TO_CATCH_FIRE (250.0f)
+
CVehicle::CVehicle(uint8 CreatedBy)
{
@@ -362,6 +369,119 @@ CVehicle::ProcessWheelRotation(tWheelState state, const CVector &fwd, const CVec
}
void
+CVehicle::InflictDamage(CEntity* damagedBy, eWeaponType weaponType, float damage)
+{
+ if (!bCanBeDamaged)
+ return;
+ if (bOnlyDamagedByPlayer && (damagedBy != FindPlayerPed() && damagedBy != FindPlayerVehicle()))
+ return;
+ bool bFrightensDriver = false;
+ switch (weaponType) {
+ case WEAPONTYPE_UNARMED:
+ case WEAPONTYPE_BASEBALLBAT:
+ if (bMeleeProof)
+ return;
+ break;
+ case WEAPONTYPE_COLT45:
+ case WEAPONTYPE_UZI:
+ case WEAPONTYPE_SHOTGUN:
+ case WEAPONTYPE_AK47:
+ case WEAPONTYPE_M16:
+ case WEAPONTYPE_SNIPERRIFLE:
+ case WEAPONTYPE_TOTAL_INVENTORY_WEAPONS:
+ case WEAPONTYPE_UZI_DRIVEBY:
+ if (bBulletProof)
+ return;
+ bFrightensDriver = true;
+ break;
+ case WEAPONTYPE_ROCKETLAUNCHER:
+ case WEAPONTYPE_MOLOTOV:
+ case WEAPONTYPE_GRENADE:
+ case WEAPONTYPE_EXPLOSION:
+ if (bExplosionProof)
+ return;
+ bFrightensDriver = true;
+ break;
+ case WEAPONTYPE_FLAMETHROWER:
+ if (bFireProof)
+ return;
+ break;
+ case WEAPONTYPE_RAMMEDBYCAR:
+ if (bCollisionProof)
+ return;
+ break;
+ default:
+ break;
+ }
+ if (m_fHealth > 0.0f) {
+ if (VehicleCreatedBy == RANDOM_VEHICLE && pDriver &&
+ (m_status == STATUS_SIMPLE || m_status == STATUS_PHYSICS) &&
+ AutoPilot.m_nCarMission == MISSION_CRUISE) {
+ if (m_randomSeed < DAMAGE_FLEE_IN_CAR_PROBABILITY_VALUE) {
+ CCarCtrl::SwitchVehicleToRealPhysics(this);
+ AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS;
+ AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * pHandling->Transmission.fUnkMaxVelocity;
+ m_status = STATUS_PHYSICS;
+ }
+ }
+ m_nLastWeaponDamage = weaponType;
+ float oldHealth = m_fHealth;
+ if (m_fHealth > damage) {
+ m_fHealth -= damage;
+ if (VehicleCreatedBy == RANDOM_VEHICLE &&
+ (m_fHealth < DAMAGE_HEALTH_TO_FLEE_ALWAYS ||
+ bFrightensDriver && m_randomSeed > DAMAGE_FLEE_ON_FOOT_PROBABILITY_VALUE)) {
+ switch (m_status) {
+ case STATUS_SIMPLE:
+ case STATUS_PHYSICS:
+ if (pDriver) {
+ m_status = STATUS_ABANDONED;
+ pDriver->bFleeAfterExitingCar = true;
+ pDriver->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
+ }
+ for (int i = 0; i < m_nNumMaxPassengers; i++) {
+ if (pPassengers[i]) {
+ pPassengers[i]->bFleeAfterExitingCar = true;
+ pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (oldHealth > DAMAGE_HEALTH_TO_CATCH_FIRE && m_fHealth < DAMAGE_HEALTH_TO_CATCH_FIRE) {
+ if (IsCar()) {
+ CAutomobile* pThisCar = (CAutomobile*)this;
+ pThisCar->Damage.SetEngineStatus(ENGINE_STATUS_ON_FIRE);
+ pThisCar->m_pSetOnFireEntity = damagedBy;
+ if (damagedBy)
+ damagedBy->RegisterReference((CEntity**)&pThisCar->m_pSetOnFireEntity);
+ }
+ }
+ }
+ else {
+ m_fHealth = 0.0f;
+ if (weaponType == WEAPONTYPE_EXPLOSION) {
+ // between 1000 and 3047. Also not very nice: can't be saved by respray or cheat
+ m_nBombTimer = 1000 + CGeneral::GetRandomNumber() & 0x7FF;
+ m_pBlowUpEntity = damagedBy;
+ if (damagedBy)
+ damagedBy->RegisterReference((CEntity**)&m_pBlowUpEntity);
+ }
+ else
+ BlowUpCar(damagedBy);
+ }
+ }
+#ifdef FIX_BUGS // removing dumb case when shooting police car in player's own garage gives wanted level
+ if (GetModelIndex() == MI_POLICE && damagedBy == FindPlayerPed() && !bHasBeenOwnedByPlayer)
+#else
+ if (GetModelIndex() == MI_POLICE && damagedBy == FindPlayerPed())
+#endif
+ FindPlayerPed()->SetWantedLevelNoDrop(1);
+}
+
+void
CVehicle::ExtinguishCarFire(void)
{
m_fHealth = max(m_fHealth, 300.0f);
@@ -375,6 +495,65 @@ CVehicle::ExtinguishCarFire(void)
}
}
+bool
+CVehicle::ShufflePassengersToMakeSpace(void)
+{
+ if (m_nNumPassengers >= m_nNumMaxPassengers)
+ return false;
+ if (pPassengers[1] &&
+ !(m_nGettingInFlags & CAR_DOOR_FLAG_LR) &&
+ IsRoomForPedToLeaveCar(COMPONENT_DOOR_REAR_LEFT, nil)) {
+ if (!pPassengers[2] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RR)) {
+ pPassengers[2] = pPassengers[1];
+ pPassengers[1] = nil;
+ pPassengers[2]->m_vehEnterType = CAR_DOOR_RR;
+ return true;
+ }
+ if (!pPassengers[0] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RF)) {
+ pPassengers[0] = pPassengers[1];
+ pPassengers[1] = nil;
+ pPassengers[0]->m_vehEnterType = CAR_DOOR_RF;
+ return true;
+ }
+ return false;
+ }
+ if (pPassengers[2] &&
+ !(m_nGettingInFlags & CAR_DOOR_FLAG_RR) &&
+ IsRoomForPedToLeaveCar(COMPONENT_DOOR_REAR_RIGHT, nil)) {
+ if (!pPassengers[1] && !(m_nGettingInFlags & CAR_DOOR_FLAG_LR)) {
+ pPassengers[1] = pPassengers[2];
+ pPassengers[2] = nil;
+ pPassengers[1]->m_vehEnterType = CAR_DOOR_LR;
+ return true;
+ }
+ if (!pPassengers[0] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RF)) {
+ pPassengers[0] = pPassengers[2];
+ pPassengers[2] = nil;
+ pPassengers[0]->m_vehEnterType = CAR_DOOR_RF;
+ return true;
+ }
+ return false;
+ }
+ if (pPassengers[0] &&
+ !(m_nGettingInFlags & CAR_DOOR_FLAG_RF) &&
+ IsRoomForPedToLeaveCar(COMPONENT_DOOR_FRONT_RIGHT, nil)) {
+ if (!pPassengers[1] && !(m_nGettingInFlags & CAR_DOOR_FLAG_LR)) {
+ pPassengers[1] = pPassengers[0];
+ pPassengers[0] = nil;
+ pPassengers[1]->m_vehEnterType = CAR_DOOR_LR;
+ return true;
+ }
+ if (!pPassengers[2] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RR)) {
+ pPassengers[2] = pPassengers[0];
+ pPassengers[0] = nil;
+ pPassengers[2]->m_vehEnterType = CAR_DOOR_RR;
+ return true;
+ }
+ return false;
+ }
+ return false;
+}
+
void
CVehicle::ProcessDelayedExplosion(void)
{
@@ -831,4 +1010,5 @@ STARTPATCHES
InjectHook(0x551EB0, &CVehicle::RemovePassenger, PATCH_JUMP);
InjectHook(0x5525A0, &CVehicle::ProcessCarAlarm, PATCH_JUMP);
InjectHook(0x552620, &CVehicle::IsSphereTouchingVehicle, PATCH_JUMP);
+ InjectHook(0x551950, &CVehicle::InflictDamage, PATCH_JUMP);
ENDPATCHES
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index 2ca97841..4639f3e1 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -4,6 +4,7 @@
#include "AutoPilot.h"
#include "ModelIndices.h"
#include "AnimManager.h"
+#include "Weapon.h"
class CPed;
class CFire;
@@ -266,7 +267,7 @@ public:
void ProcessCarAlarm(void);
bool IsSphereTouchingVehicle(float sx, float sy, float sz, float radius);
bool ShufflePassengersToMakeSpace(void);
- void InflictDamage(CEntity *damagedBy, uint32 weaponType, float damage);
+ void InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage);
bool IsAlarmOn(void) { return m_nAlarmState != 0 && m_nAlarmState != -1; }
CVehicleModelInfo* GetModelInfo() { return (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); }
diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp
index 09844c23..0f41264f 100644
--- a/src/weapons/Weapon.cpp
+++ b/src/weapons/Weapon.cpp
@@ -14,6 +14,7 @@ WRAPPER void CWeapon::AddGunshell(CEntity*, CVector const&, CVector2D const&, fl
WRAPPER void CWeapon::Update(int32 audioEntity) { EAXJMP(0x563A10); }
WRAPPER void CWeapon::DoTankDoomAiming(CEntity *playerVehicle, CEntity *playerPed, CVector *start, CVector *end) { EAXJMP(0x563200); }
WRAPPER void CWeapon::InitialiseWeapons(void) { EAXJMP(0x55C2D0); }
+WRAPPER void FireOneInstantHitRound(CVector* shotSource, CVector* shotTarget, int32 damage) { EAXJMP(0x563B00); }
void
CWeapon::Initialise(eWeaponType type, int ammo)
diff --git a/src/weapons/Weapon.h b/src/weapons/Weapon.h
index 74145564..84760550 100644
--- a/src/weapons/Weapon.h
+++ b/src/weapons/Weapon.h
@@ -81,3 +81,5 @@ public:
static void UpdateWeapons(void);
};
static_assert(sizeof(CWeapon) == 0x18, "CWeapon: error");
+
+void FireOneInstantHitRound(CVector* shotSource, CVector* shotTarget, int32 damage); \ No newline at end of file