more work on CPhysical

This commit is contained in:
aap
2019-05-18 12:39:39 +02:00
parent 58ebd6c6d4
commit 9e496100b7
106 changed files with 57865 additions and 103 deletions

View File

@ -1,7 +1,11 @@
#include "common.h"
#include "patcher.h"
#include "Weather.h"
#include "Collision.h"
#include "SurfaceTable.h"
float (*CSurfaceTable::ms_aAdhesiveLimitTable)[NUMADHESIVEGROUPS] = (float (*)[NUMADHESIVEGROUPS])0x8E29D4;
int
CSurfaceTable::GetAdhesionGroup(uint8 surfaceType)
{
@ -42,3 +46,52 @@ CSurfaceTable::GetAdhesionGroup(uint8 surfaceType)
default: return ADHESIVE_ROAD;
}
}
float
CSurfaceTable::GetWetMultiplier(uint8 surfaceType)
{
switch(surfaceType){
case SURFACE_0:
case SURFACE_1:
case SURFACE_4:
case SURFACE_5:
case SURFACE_8:
case SURFACE_20:
case SURFACE_21:
case SURFACE_22:
case SURFACE_25:
case SURFACE_30:
case SURFACE_31:
return 1.0f - CWeather::WetRoads*0.25f;
case SURFACE_2:
case SURFACE_6:
case SURFACE_7:
case SURFACE_9:
case SURFACE_10:
case SURFACE_11:
case SURFACE_12:
case SURFACE_13:
case SURFACE_14:
case SURFACE_15:
case SURFACE_16:
case SURFACE_17:
case SURFACE_23:
case SURFACE_24:
case SURFACE_26:
case SURFACE_27:
case SURFACE_28:
case SURFACE_29:
case SURFACE_32:
return 1.0f - CWeather::WetRoads*0.4f;
default:
return 1.0f;
}
}
float
CSurfaceTable::GetAdhesiveLimit(CColPoint &colpoint)
{
return ms_aAdhesiveLimitTable[GetAdhesionGroup(colpoint.surfaceB)][GetAdhesionGroup(colpoint.surfaceA)];
}

View File

@ -92,8 +92,14 @@ enum
NUMADHESIVEGROUPS
};
struct CColPoint;
class CSurfaceTable
{
// static float ms_aAdhesiveLimitTable[NUMADHESIVEGROUPS][NUMADHESIVEGROUPS];
static float (*ms_aAdhesiveLimitTable)[NUMADHESIVEGROUPS];
public:
static int GetAdhesionGroup(uint8 surfaceType);
static float GetWetMultiplier(uint8 surfaceType);
static float GetAdhesiveLimit(CColPoint &colpoint);
};

5
src/audio/DMAudio.cpp Normal file
View File

@ -0,0 +1,5 @@
#include "common.h"
#include "patcher.h"
#include "DMAudio.h"
WRAPPER void cDMAudio::ReportCollision(CEntity *A, CEntity *B, uint8 surfA, uint8 surfB, float impulse, float speed) { EAXJMP(0x161684); }

9
src/audio/DMAudio.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
class CEntity;
class cDMAudio
{
public:
static void ReportCollision(CEntity *A, CEntity *B, uint8 surfA, uint8 surfB, float impulse, float speed);
};

5
src/control/CarCtrl.cpp Normal file
View File

@ -0,0 +1,5 @@
#include "common.h"
#include "patcher.h"
#include "CarCtrl.h"
WRAPPER void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle*) { EAXJMP(0x41F7F0); }

9
src/control/CarCtrl.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
class CVehicle;
class CCarCtrl
{
public:
static void SwitchVehicleToRealPhysics(CVehicle*);
};

View File

@ -10,6 +10,8 @@
#include "ParticleObject.h"
#include "Particle.h"
#include "SurfaceTable.h"
#include "CarCtrl.h"
#include "DMAudio.h"
#include "Physical.h"
void
@ -171,6 +173,145 @@ CPhysical::RemoveFromMovingList(void)
}
}
void
CPhysical::SetDamagedPieceRecord(uint16 piece, float impulse, CEntity *entity, CVector dir)
{
m_nCollisionPieceType = piece;
m_fCollisionImpulse = impulse;
m_pCollidingEntity = entity;
entity->RegisterReference(&m_pCollidingEntity);
m_vecCollisionDirection = dir;
}
void
CPhysical::AddCollisionRecord(CEntity *ent)
{
AddCollisionRecord_Treadable(ent);
this->bHasCollided = true;
ent->bHasCollided = true;
if(IsVehicle() && ent->IsVehicle()){
if(((CVehicle*)this)->m_nAlarmState == -1)
((CVehicle*)this)->m_nAlarmState = 15000;
if(((CVehicle*)ent)->m_nAlarmState == -1)
((CVehicle*)ent)->m_nAlarmState = 15000;
}
if(bUseCollisionRecords){
int i;
for(i = 0; i < m_nCollisionRecords; i++)
if(m_aCollisionRecords[i] == ent)
return;
if(m_nCollisionRecords < PHYSICAL_MAX_COLLISIONRECORDS)
m_aCollisionRecords[m_nCollisionRecords++] = ent;
m_nLastTimeCollided = CTimer::GetTimeInMilliseconds();
}
}
void
CPhysical::AddCollisionRecord_Treadable(CEntity *ent)
{
if(ent->IsBuilding() && ((CBuilding*)ent)->GetIsATreadable()){
CTreadable *t = (CTreadable*)ent;
if(t->m_nodeIndicesPeds[0] >= 0 ||
t->m_nodeIndicesPeds[1] >= 0 ||
t->m_nodeIndicesPeds[2] >= 0 ||
t->m_nodeIndicesPeds[3] >= 0)
m_pedTreadable = t;
if(t->m_nodeIndicesCars[0] >= 0 ||
t->m_nodeIndicesCars[1] >= 0 ||
t->m_nodeIndicesCars[2] >= 0 ||
t->m_nodeIndicesCars[3] >= 0)
m_carTreadable = t;
}
}
bool
CPhysical::GetHasCollidedWith(CEntity *ent)
{
int i;
if(bUseCollisionRecords)
for(i = 0; i < m_nCollisionRecords; i++)
if(m_aCollisionRecords[i] == ent)
return true;
return false;
}
void
CPhysical::RemoveRefsToEntity(CEntity *ent)
{
int i, j;
for(i = 0; i < m_nCollisionRecords; i++){
if(m_aCollisionRecords[i] == ent){
for(j = i; j < m_nCollisionRecords-1; j++)
m_aCollisionRecords[j] = m_aCollisionRecords[j+1];
m_nCollisionRecords--;
}
}
}
int32
CPhysical::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints)
{
int32 numSpheres = CCollision::ProcessColModels(
GetMatrix(), *CModelInfo::GetModelInfo(GetModelIndex())->GetColModel(),
ent->GetMatrix(), *CModelInfo::GetModelInfo(ent->GetModelIndex())->GetColModel(),
colpoints,
nil, nil); // No Lines allowed!
if(numSpheres > 0){
AddCollisionRecord(ent);
if(!ent->IsBuilding()) // Can't this catch dummies too?
((CPhysical*)ent)->AddCollisionRecord(this);
if(ent->IsBuilding() || ent->bIsStatic)
this->bHasHitWall = true;
}
return numSpheres;
}
void
CPhysical::ProcessControl(void)
{
if(!IsPed())
m_phy_flagA8 = false;
bHasContacted = false;
bIsInSafePosition = false;
bWasPostponed = false;
bHasHitWall = false;
if(m_status == STATUS_SIMPLE)
return;
m_nCollisionRecords = 0;
bHasCollided = false;
m_nCollisionPieceType = 0;
m_fCollisionImpulse = 0.0f;
m_pCollidingEntity = nil;
if(!bIsStuck){
if(IsObject() ||
IsPed() && !bPedPhysics){
m_vecMoveSpeedAvg = (m_vecMoveSpeedAvg + m_vecMoveSpeed)/2.0f;
m_vecTurnSpeedAvg = (m_vecTurnSpeedAvg + m_vecTurnSpeed)/2.0f;
float step = CTimer::GetTimeStep() * 0.003;
if(m_vecMoveSpeedAvg.MagnitudeSqr() < step*step &&
m_vecTurnSpeedAvg.MagnitudeSqr() < step*step){
m_nStaticFrames++;
if(m_nStaticFrames > 10){
m_nStaticFrames = 10;
bIsStatic = true;
m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
m_vecMoveFriction = m_vecMoveSpeed;
m_vecTurnFriction = m_vecTurnSpeed;
return;
}
}else
m_nStaticFrames = 0;
}
}
ApplyGravity();
ApplyFriction();
ApplyAirResistance();
}
/*
* Some quantities (german in parens):
@ -245,8 +386,8 @@ CPhysical::ApplySpringCollision(float f1, CVector &v, CVector &p, float f2, floa
return;
float step = min(CTimer::GetTimeStep(), 3.0f);
float strength = -0.008f*m_fMass*2.0f*step * f1 * (1.0f-f2) * f3;
ApplyMoveForce(v.x*strength, v.y*strength, v.z*strength);
ApplyTurnForce(v.x*strength, v.y*strength, v.z*strength, p.x, p.y, p.z);
ApplyMoveForce(v*strength);
ApplyTurnForce(v*strength, p);
}
void
@ -798,58 +939,6 @@ CPhysical::ApplyFriction(float adhesiveLimit, CColPoint &colpoint)
// ProcessCollisionSectorList
// ProcessShiftSectorList
void
CPhysical::AddCollisionRecord(CEntity *ent)
{
AddCollisionRecord_Treadable(ent);
this->bHasCollided = true;
ent->bHasCollided = true;
if(IsVehicle() && ent->IsVehicle()){
if(((CVehicle*)this)->m_nAlarmState == -1)
((CVehicle*)this)->m_nAlarmState = 15000;
if(((CVehicle*)ent)->m_nAlarmState == -1)
((CVehicle*)ent)->m_nAlarmState = 15000;
}
if(bUseCollisionRecords){
int i;
for(i = 0; i < m_nCollisionRecords; i++)
if(m_aCollisionRecords[i] == ent)
return;
if(m_nCollisionRecords < PHYSICAL_MAX_COLLISIONRECORDS)
m_aCollisionRecords[m_nCollisionRecords++] = ent;
m_nLastTimeCollided = CTimer::GetTimeInMilliseconds();
}
}
void
CPhysical::AddCollisionRecord_Treadable(CEntity *ent)
{
if(ent->IsBuilding() && ((CBuilding*)ent)->GetIsATreadable()){
CTreadable *t = (CTreadable*)ent;
if(t->m_nodeIndicesPeds[0] >= 0 ||
t->m_nodeIndicesPeds[1] >= 0 ||
t->m_nodeIndicesPeds[2] >= 0 ||
t->m_nodeIndicesPeds[3] >= 0)
m_pedTreadable = t;
if(t->m_nodeIndicesCars[0] >= 0 ||
t->m_nodeIndicesCars[1] >= 0 ||
t->m_nodeIndicesCars[2] >= 0 ||
t->m_nodeIndicesCars[3] >= 0)
m_carTreadable = t;
}
}
bool
CPhysical::GetHasCollidedWith(CEntity *ent)
{
int i;
if(bUseCollisionRecords)
for(i = 0; i < m_nCollisionRecords; i++)
if(m_aCollisionRecords[i] == ent)
return true;
return false;
}
bool
CPhysical::ProcessShiftSectorList(CPtrList *lists)
{
@ -1012,65 +1101,181 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists)
return true;
}
void
CPhysical::ProcessControl(void)
bool
CPhysical::ProcessCollisionSectorList_SimpleCar(CPtrList *lists)
{
if(!IsPed())
m_phy_flagA8 = false;
bHasContacted = false;
bIsInSafePosition = false;
bWasPostponed = false;
bHasHitWall = false;
static CColPoint aColPoints[32];
float radius;
CVector center;
int listtype;
CPhysical *A, *B;
int numCollisions;
int i;
float impulseA = -1.0f;
float impulseB = -1.0f;
if(m_status == STATUS_SIMPLE)
return;
A = (CPhysical*)this;
m_nCollisionRecords = 0;
bHasCollided = false;
m_nCollisionPieceType = 0;
m_fCollisionImpulse = 0.0f;
m_pCollidingEntity = nil;
radius = A->GetBoundRadius();
A->GetBoundCentre(center);
if(!bIsStuck){
if(IsObject() ||
IsPed() && !bPedPhysics){
m_vecMoveSpeedAvg = (m_vecMoveSpeedAvg + m_vecMoveSpeed)/2.0f;
m_vecTurnSpeedAvg = (m_vecTurnSpeedAvg + m_vecTurnSpeed)/2.0f;
float step = CTimer::GetTimeStep() * 0.003;
if(m_vecMoveSpeedAvg.MagnitudeSqr() < step*step &&
m_vecTurnSpeedAvg.MagnitudeSqr() < step*step){
m_nStaticFrames++;
if(m_nStaticFrames > 10){
m_nStaticFrames = 10;
bIsStatic = true;
m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
m_vecMoveFriction = m_vecMoveSpeed;
m_vecTurnFriction = m_vecTurnSpeed;
return;
}
}else
m_nStaticFrames = 0;
for(listtype = 3; listtype >= 0; listtype--){
// Go through vehicles and objects
CPtrList *list;
switch(listtype){
case 0: list = &lists[ENTITYLIST_VEHICLES]; break;
case 1: list = &lists[ENTITYLIST_VEHICLES_OVERLAP]; break;
case 2: list = &lists[ENTITYLIST_OBJECTS]; break;
case 3: list = &lists[ENTITYLIST_OBJECTS_OVERLAP]; break;
}
// Find first collision in list
CPtrNode *listnode;
for(listnode = list->first; listnode; listnode = listnode->next){
B = (CPhysical*)listnode->item;
if(B != A &&
B->m_scanCode != CWorld::GetCurrentScanCode() &&
B->bUsesCollision &&
B->GetIsTouching(center, radius)){
B->m_scanCode = CWorld::GetCurrentScanCode();
numCollisions = A->ProcessEntityCollision(B, aColPoints);
if(numCollisions > 0)
goto collision;
}
}
}
ApplyGravity();
ApplyFriction();
ApplyAirResistance();
// no collision
return false;
collision:
if(A->bHasContacted && B->bHasContacted){
for(i = 0; i < numCollisions; i++){
if(!A->ApplyCollision(B, aColPoints[i], impulseA, impulseB))
continue;
if(impulseA > A->m_fCollisionImpulse)
A->SetDamagedPieceRecord(aColPoints[i].pieceA, impulseA, B, aColPoints[i].normal);
if(impulseB > B->m_fCollisionImpulse)
A->SetDamagedPieceRecord(aColPoints[i].pieceB, impulseB, A, aColPoints[i].normal);
float turnSpeedDiff = (B->m_vecTurnSpeed - A->m_vecTurnSpeed).MagnitudeSqr();
float moveSpeedDiff = (B->m_vecMoveSpeed - A->m_vecMoveSpeed).MagnitudeSqr();
cDMAudio::ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, max(turnSpeedDiff, moveSpeedDiff));
}
}else if(A->bHasContacted){
CVector savedMoveFriction = A->m_vecMoveFriction;
CVector savedTurnFriction = A->m_vecTurnFriction;
A->m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f);
A->m_vecTurnFriction = CVector(0.0f, 0.0f, 0.0f);
A->bHasContacted = false;
for(i = 0; i < numCollisions; i++){
if(!A->ApplyCollision(B, aColPoints[i], impulseA, impulseB))
continue;
if(impulseA > A->m_fCollisionImpulse)
A->SetDamagedPieceRecord(aColPoints[i].pieceA, impulseA, B, aColPoints[i].normal);
if(impulseB > B->m_fCollisionImpulse)
A->SetDamagedPieceRecord(aColPoints[i].pieceB, impulseB, A, aColPoints[i].normal);
float turnSpeedDiff = (B->m_vecTurnSpeed - A->m_vecTurnSpeed).MagnitudeSqr();
float moveSpeedDiff = (B->m_vecMoveSpeed - A->m_vecMoveSpeed).MagnitudeSqr();
cDMAudio::ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, max(turnSpeedDiff, moveSpeedDiff));
if(A->ApplyFriction(B, CSurfaceTable::GetAdhesiveLimit(aColPoints[i])/numCollisions, aColPoints[i])){
A->bHasContacted = true;
B->bHasContacted = true;
}
}
if(!A->bHasContacted){
A->bHasContacted = true;
A->m_vecMoveFriction = savedMoveFriction;
A->m_vecTurnFriction = savedTurnFriction;
}
}else if(B->bHasContacted){
CVector savedMoveFriction = B->m_vecMoveFriction;
CVector savedTurnFriction = B->m_vecTurnFriction;
B->m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f);
B->m_vecTurnFriction = CVector(0.0f, 0.0f, 0.0f);
B->bHasContacted = false;
for(i = 0; i < numCollisions; i++){
if(!A->ApplyCollision(B, aColPoints[i], impulseA, impulseB))
continue;
if(impulseA > A->m_fCollisionImpulse)
A->SetDamagedPieceRecord(aColPoints[i].pieceA, impulseA, B, aColPoints[i].normal);
if(impulseB > B->m_fCollisionImpulse)
A->SetDamagedPieceRecord(aColPoints[i].pieceB, impulseB, A, aColPoints[i].normal);
float turnSpeedDiff = (B->m_vecTurnSpeed - A->m_vecTurnSpeed).MagnitudeSqr();
float moveSpeedDiff = (B->m_vecMoveSpeed - A->m_vecMoveSpeed).MagnitudeSqr();
cDMAudio::ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, max(turnSpeedDiff, moveSpeedDiff));
if(A->ApplyFriction(B, CSurfaceTable::GetAdhesiveLimit(aColPoints[i])/numCollisions, aColPoints[i])){
A->bHasContacted = true;
B->bHasContacted = true;
}
}
if(!B->bHasContacted){
B->bHasContacted = true;
B->m_vecMoveFriction = savedMoveFriction;
B->m_vecTurnFriction = savedTurnFriction;
}
}else{
for(i = 0; i < numCollisions; i++){
if(!A->ApplyCollision(B, aColPoints[i], impulseA, impulseB))
continue;
if(impulseA > A->m_fCollisionImpulse)
A->SetDamagedPieceRecord(aColPoints[i].pieceA, impulseA, B, aColPoints[i].normal);
if(impulseB > B->m_fCollisionImpulse)
A->SetDamagedPieceRecord(aColPoints[i].pieceB, impulseB, A, aColPoints[i].normal);
float turnSpeedDiff = (B->m_vecTurnSpeed - A->m_vecTurnSpeed).MagnitudeSqr();
float moveSpeedDiff = (B->m_vecMoveSpeed - A->m_vecMoveSpeed).MagnitudeSqr();
cDMAudio::ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, max(turnSpeedDiff, moveSpeedDiff));
if(A->ApplyFriction(B, CSurfaceTable::GetAdhesiveLimit(aColPoints[i])/numCollisions, aColPoints[i])){
A->bHasContacted = true;
B->bHasContacted = true;
}
}
}
if(B->m_status == STATUS_SIMPLE){
B->m_status = STATUS_PHYSICS;
if(B->IsVehicle())
CCarCtrl::SwitchVehicleToRealPhysics((CVehicle*)B);
}
return true;
}
STARTPATCHES
InjectHook(0x4951F0, &CPhysical::Add_, PATCH_JUMP);
InjectHook(0x4954B0, &CPhysical::Remove_, PATCH_JUMP);
InjectHook(0x495540, &CPhysical::RemoveAndAdd, PATCH_JUMP);
InjectHook(0x495F10, &CPhysical::ProcessControl_, PATCH_JUMP);
InjectHook(0x49F790, &CPhysical::ProcessEntityCollision_, PATCH_JUMP);
InjectHook(0x4958F0, &CPhysical::AddToMovingList, PATCH_JUMP);
InjectHook(0x495940, &CPhysical::RemoveFromMovingList, PATCH_JUMP);
InjectHook(0x497180, &CPhysical::AddCollisionRecord, PATCH_JUMP);
InjectHook(0x4970C0, &CPhysical::AddCollisionRecord_Treadable, PATCH_JUMP);
InjectHook(0x497240, &CPhysical::GetHasCollidedWith, PATCH_JUMP);
InjectHook(0x49DA10, &CPhysical::ProcessShiftSectorList, PATCH_JUMP);
InjectHook(0x49F820, &CPhysical::RemoveRefsToEntity, PATCH_JUMP);
#define F3 float, float, float
InjectHook(0x495B10, &CPhysical::ApplyMoveSpeed, PATCH_JUMP);
@ -1088,4 +1293,7 @@ STARTPATCHES
InjectHook(0x4992A0, &CPhysical::ApplyCollisionAlt, PATCH_JUMP);
InjectHook(0x499BE0, (bool (CPhysical::*)(float, CColPoint&))&CPhysical::ApplyFriction, PATCH_JUMP);
InjectHook(0x49A180, (bool (CPhysical::*)(CPhysical*, float, CColPoint&))&CPhysical::ApplyFriction, PATCH_JUMP);
InjectHook(0x49DA10, &CPhysical::ProcessShiftSectorList, PATCH_JUMP);
InjectHook(0x49E790, &CPhysical::ProcessCollisionSectorList_SimpleCar, PATCH_JUMP);
ENDPATCHES

View File

@ -82,6 +82,11 @@ public:
void RemoveAndAdd(void);
void AddToMovingList(void);
void RemoveFromMovingList(void);
void SetDamagedPieceRecord(uint16 piece, float impulse, CEntity *entity, CVector dir);
void AddCollisionRecord(CEntity *ent);
void AddCollisionRecord_Treadable(CEntity *ent);
bool GetHasCollidedWith(CEntity *ent);
void RemoveRefsToEntity(CEntity *ent);
// get speed of point p relative to entity center
CVector GetSpeed(const CVector &r);
@ -126,16 +131,14 @@ public:
bool ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint);
bool ApplyFriction(float adhesiveLimit, CColPoint &colpoint);
void AddCollisionRecord(CEntity *ent);
void AddCollisionRecord_Treadable(CEntity *ent);
bool GetHasCollidedWith(CEntity *ent);
bool ProcessShiftSectorList(CPtrList *ptrlists);
bool ProcessCollisionSectorList_SimpleCar(CPtrList *lists);
// to make patching virtual functions possible
void Add_(void) { CPhysical::Add(); }
void Remove_(void) { CPhysical::Remove(); }
CRect GetBoundRect_(void) { return CPhysical::GetBoundRect(); }
void ProcessControl_(void) { CPhysical::ProcessControl(); }
int32 ProcessEntityCollision_(CEntity *ent, CColPoint *point) { return CPhysical::ProcessEntityCollision(ent, point); }
};
static_assert(sizeof(CPhysical) == 0x128, "CPhysical: error");