diff options
Diffstat (limited to 'src/entities/Physical.cpp')
-rw-r--r-- | src/entities/Physical.cpp | 537 |
1 files changed, 416 insertions, 121 deletions
diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp index 04cec96b..acf9c702 100644 --- a/src/entities/Physical.cpp +++ b/src/entities/Physical.cpp @@ -1,7 +1,9 @@ #include "common.h" #include "World.h" +#include "General.h" #include "Timer.h" +#include "Stats.h" #include "ModelIndices.h" #include "Treadable.h" #include "Vehicle.h" @@ -15,8 +17,17 @@ #include "CarCtrl.h" #include "DMAudio.h" #include "Automobile.h" +#include "Bike.h" +#include "Pickups.h" #include "Physical.h" +//--MIAMI: file done + +#ifdef WALLCLIMB_CHEAT +bool gGravityCheat; +#endif + + CPhysical::CPhysical(void) { int i; @@ -41,6 +52,7 @@ CPhysical::CPhysical(void) m_aCollisionRecords[i] = nil; m_bIsVehicleBeingShifted = false; + bJustCheckCollision = false; m_nDamagePieceType = 0; m_fDamageImpulse = 0.0f; @@ -56,21 +68,22 @@ CPhysical::CPhysical(void) bIsHeavy = false; bAffectedByGravity = true; bInfiniteMass = false; + m_phy_flagA08 = false; bIsInWater = false; bHitByTrain = false; bSkipLineCol = false; m_fDistanceTravelled = 0.0f; - m_treadable[PATH_CAR] = nil; - m_treadable[PATH_PED] = nil; - m_phy_flagA10 = false; m_phy_flagA20 = false; #ifdef FIX_BUGS m_nSurfaceTouched = SURFACE_DEFAULT; #endif m_nZoneLevel = LEVEL_GENERIC; + + bIsFrozen = false; + bDontLoadCollision = false; } CPhysical::~CPhysical(void) @@ -225,7 +238,8 @@ CPhysical::GetBoundRect(void) void CPhysical::AddToMovingList(void) { - m_movingListNode = CWorld::GetMovingEntityList().InsertItem(this); + if (!bIsStaticWaitingForCollision) + m_movingListNode = CWorld::GetMovingEntityList().InsertItem(this); } void @@ -274,17 +288,6 @@ void CPhysical::AddCollisionRecord_Treadable(CEntity *ent) { if(ent->IsBuilding() && ((CBuilding*)ent)->GetIsATreadable()){ - CTreadable *t = (CTreadable*)ent; - if(t->m_nodeIndices[PATH_PED][0] >= 0 || - t->m_nodeIndices[PATH_PED][1] >= 0 || - t->m_nodeIndices[PATH_PED][2] >= 0 || - t->m_nodeIndices[PATH_PED][3] >= 0) - m_treadable[PATH_PED] = t; - if(t->m_nodeIndices[PATH_CAR][0] >= 0 || - t->m_nodeIndices[PATH_CAR][1] >= 0 || - t->m_nodeIndices[PATH_CAR][2] >= 0 || - t->m_nodeIndices[PATH_CAR][3] >= 0) - m_treadable[PATH_CAR] = t; } } @@ -417,18 +420,26 @@ CPhysical::GetSpeed(const CVector &r) void CPhysical::ApplyMoveSpeed(void) { - GetMatrix().Translate(m_vecMoveSpeed * CTimer::GetTimeStep()); + if(bIsFrozen) + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + else + GetMatrix().Translate(m_vecMoveSpeed * CTimer::GetTimeStep()); } + void CPhysical::ApplyTurnSpeed(void) { - // Move the coordinate axes by their speed - // Note that this denormalizes the matrix - CVector turnvec = m_vecTurnSpeed*CTimer::GetTimeStep(); - GetRight() += CrossProduct(turnvec, GetRight()); - GetForward() += CrossProduct(turnvec, GetForward()); - GetUp() += CrossProduct(turnvec, GetUp()); + if(bIsFrozen){ + m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); + }else{ + // Move the coordinate axes by their speed + // Note that this denormalizes the matrix + CVector turnvec = m_vecTurnSpeed*CTimer::GetTimeStep(); + GetRight() += CrossProduct(turnvec, GetRight()); + GetForward() += CrossProduct(turnvec, GetForward()); + GetUp() += CrossProduct(turnvec, GetUp()); + } } void @@ -472,6 +483,23 @@ CPhysical::ApplySpringCollision(float springConst, CVector &springDir, CVector & return true; } +bool +CPhysical::ApplySpringCollisionAlt(float springConst, CVector &springDir, CVector &point, float springRatio, float bias, CVector &forceDir) +{ + float compression = 1.0f - springRatio; + if(compression > 0.0f){ + if(DotProduct(springDir, forceDir) > 0.0f) + forceDir *= -1.0f; + float step = Min(CTimer::GetTimeStep(), 3.0f); + float impulse = GRAVITY*m_fMass*step * springConst * compression * bias*2.0f; + if(bIsHeavy) + impulse *= 0.75f; + ApplyMoveForce(forceDir*impulse); + ApplyTurnForce(forceDir*impulse, point); + } + return true; +} + // What exactly is speed? bool CPhysical::ApplySpringDampening(float damping, CVector &springDir, CVector &point, CVector &speed) @@ -480,6 +508,8 @@ CPhysical::ApplySpringDampening(float damping, CVector &springDir, CVector &poin float speedB = DotProduct(GetSpeed(point), springDir); float step = Min(CTimer::GetTimeStep(), 3.0f); float impulse = -damping * (speedA + speedB)/2.0f * m_fMass * step * 0.53f; + if(bIsHeavy) + impulse *= 2.0f; // what is this? float a = m_fTurnMass / ((point.MagnitudeSqr() + 1.0f) * 2.0f * m_fMass); @@ -496,8 +526,29 @@ CPhysical::ApplySpringDampening(float damping, CVector &springDir, CVector &poin void CPhysical::ApplyGravity(void) { - if(bAffectedByGravity) - m_vecMoveSpeed.z -= GRAVITY * CTimer::GetTimeStep(); + if (!bAffectedByGravity) + return; +#ifdef WALLCLIMB_CHEAT + if (gGravityCheat && this == FindPlayerVehicle()) { + static CVector v1(0.0f, 0.0f, 1.0f), v2(0.0f, 0.0f, 1.0f); + CVector prop = GetPosition() - (GetUp() + GetUp()); + CColPoint point; + CEntity* entity; + if (CWorld::ProcessLineOfSight(GetPosition(), prop, point, entity, true, false, false, false, false, false)) + v2 = point.normal; + else + v2 = CVector(0.0f, 0.0f, 1.0f); + float coef = clamp(CTimer::GetTimeStep() * 0.5f, 0.05f, 0.8f); + v1 = v1 * (1.0f - coef) + v2 * coef; + if (v1.MagnitudeSqr() < 0.1f) + v1 = CVector(0.0f, 0.0f, 1.0f); + else + v1.Normalise(); + m_vecMoveSpeed -= GRAVITY * CTimer::GetTimeStep() * v1; + return; + } +#endif + m_vecMoveSpeed.z -= GRAVITY * CTimer::GetTimeStep(); } void @@ -513,9 +564,11 @@ void CPhysical::ApplyAirResistance(void) { if(m_fAirResistance > 0.1f){ - float f = Pow(m_fAirResistance, CTimer::GetTimeStep()); - m_vecMoveSpeed *= f; - m_vecTurnSpeed *= f; + if(GetStatus() != STATUS_GHOST){ + float f = Pow(m_fAirResistance, CTimer::GetTimeStep()); + m_vecMoveSpeed *= f; + m_vecTurnSpeed *= f; + } }else{ float f = Pow(1.0f/(m_fAirResistance*0.5f*m_vecMoveSpeed.MagnitudeSqr() + 1.0f), CTimer::GetTimeStep()); m_vecMoveSpeed *= f; @@ -523,7 +576,6 @@ CPhysical::ApplyAirResistance(void) } } - bool CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, float &impulseB) { @@ -531,6 +583,7 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl CPhysical *A = this; CObject *Bobj = (CObject*)B; + bool foo = false; // TODO: what does this mean? bool ispedcontactA = false; bool ispedcontactB = false; @@ -546,7 +599,7 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl if(A->bPedPhysics){ if(A->IsPed() && ((CPed*)A)->IsPlayer() && B->IsVehicle() && (B->GetStatus() == STATUS_ABANDONED || B->GetStatus() == STATUS_WRECKED || A->bHasHitWall)) - massFactorB = 2200.0f / B->m_fMass; + massFactorB = 1.0f/(Max(B->m_fMass - 2000.0f, 0.0f)/5000.0f + 1.0f); else massFactorB = 10.0f; @@ -555,8 +608,13 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl }else massFactorB = B->bIsHeavy ? 2.0f : 1.0f; + if(B->bInfiniteMass && !B->m_phy_flagA08){ + ispedcontactB = false; + foo = true; + } + float speedA, speedB; - if(B->GetIsStatic()){ + if(B->GetIsStatic() && !foo){ if(A->bPedPhysics){ speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal); if(speedA < 0.0f){ @@ -566,8 +624,11 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl if(impulseA > Bobj->m_fUprootLimit){ if(IsGlass(B->GetModelIndex())) CGlass::WindowRespondsToCollision(B, impulseA, A->m_vecMoveSpeed, colpoint.point, false); - else if(!B->bInfiniteMass) + else if(!B->bInfiniteMass){ B->SetIsStatic(false); + CWorld::Players[CWorld::PlayerInFocus].m_nHavocLevel += 2; + CStats::PropertyDestroyed += CGeneral::GetRandomNumberInRange(30, 60); + } }else{ if(IsGlass(B->GetModelIndex())) CGlass::WindowRespondsToSoftCollision(B, impulseA); @@ -619,6 +680,9 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl if(model == MI_FIRE_HYDRANT && !Bobj->bHasBeenDamaged){ CParticleObject::AddObject(POBJECT_FIRE_HYDRANT, B->GetPosition() - CVector(0.0f, 0.0f, 0.5f), true); Bobj->bHasBeenDamaged = true; + }else if(model == MI_PARKINGMETER || model == MI_PARKINGMETER2){ + CPickups::CreateSomeMoney(GetPosition(), CGeneral::GetRandomNumber()%100); + Bobj->bHasBeenDamaged = true; }else if(B->IsObject() && !IsExplosiveThingModel(model)) Bobj->bHasBeenDamaged = true; }else{ @@ -641,7 +705,7 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl if(B->GetIsStatic()) return false; - if(!B->bInfiniteMass) + if(!B->bInfiniteMass && !B->m_phy_flagA08) B->AddToMovingList(); } @@ -651,19 +715,36 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl // negative if A is moving towards B speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal); // positive if B is moving towards A - // not interested in how much B moves into A apparently? - // only interested in cases where A collided into B - speedB = DotProduct(B->m_vecMoveSpeed, colpoint.normal); - float speedSum = Max(0.0f, DotProduct(B->m_vecMoveSpeed, colpoint.normal)); - // A has moved into B + float speedB = DotProduct(B->m_vecMoveSpeed, colpoint.normal); + + bool affectB = false; + float mA = A->m_fMass;; + float mB = B->m_fMass;; + float speedSum; + if(((CPed*)A)->GetPedState() == PED_FOLLOW_PATH){ + affectB = true; + speedSum = (2.0f*mA*speedA + mB*speedB)/(2.0f*mA + mB); + }else{ + speedSum = Max(speedB, 0.0f); + } + if(speedA < speedSum){ if(A->bHasHitWall) eA = speedSum; else eA = speedSum - (speedA - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f; - impulseA = (eA-speedA) * A->m_fMass * massFactorA; + impulseA = (eA-speedA) * mA; if(!A->bInfiniteMass) - A->ApplyMoveForce(colpoint.normal*(impulseA/massFactorA)); + A->ApplyMoveForce(colpoint.normal*impulseA); + if(affectB && speedB < speedSum){ + if(B->bHasHitWall) + eB = speedSum; + else + eB = speedSum - (speedB - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f; + impulseB = -(eB-speedB) * mB; + if(!B->bInfiniteMass) + B->ApplyMoveForce(colpoint.normal*-impulseB); + } return true; } }else if(A->bPedPhysics){ @@ -673,7 +754,11 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl float mA = A->m_fMass*massFactorA; float mB = B->GetMassTweak(pointposB, colpoint.normal, massFactorB); - float speedSum = (mB*speedB + mA*speedA)/(mA + mB); + float speedSum; + if(foo) + speedSum = speedB; + else + speedSum = (mB*speedB + mA*speedA)/(mA + mB); if(speedA < speedSum){ if(A->bHasHitWall) eA = speedSum; @@ -804,13 +889,52 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl } bool +CPhysical::ApplyCollision(CColPoint &colpoint, float &impulse) +{ + float speed; + if(bPedPhysics){ + speed = DotProduct(m_vecMoveSpeed, colpoint.normal); + if(speed < 0.0f){ + impulse = -speed * m_fMass; + ApplyMoveForce(colpoint.normal*impulse); + return true; + } + }else{ + CVector pointpos = colpoint.point - GetPosition(); + speed = DotProduct(GetSpeed(pointpos), colpoint.normal); + + if(speed < 0.0f){ + float mass = GetMass(pointpos, colpoint.normal); + impulse = -(m_fElasticity + 1.0f) * speed * mass; + CVector f = colpoint.normal*impulse; + if(IsVehicle()){ + f.x *= 1.4f; + f.y *= 1.4f; + if(colpoint.normal.z < 0.7f) + f.z *= 0.3f; + } + if(!bInfiniteMass){ + ApplyMoveForce(f); + if(!IsVehicle() || !CWorld::bNoMoreCollisionTorque) + ApplyTurnForce(f, pointpos); + } + return true; + } + } + + return false; +} + +bool CPhysical::ApplyCollisionAlt(CEntity *B, CColPoint &colpoint, float &impulse, CVector &moveSpeed, CVector &turnSpeed) { float normalSpeed; - float e; CVector speed; CVector vImpulse; + if(GetModelIndex() == MI_BEACHBALL && B != (CEntity*)FindPlayerPed()) + ((CObject*)this)->m_nBeachballBounces = 0; + if(bPedPhysics){ normalSpeed = DotProduct(m_vecMoveSpeed, colpoint.normal); if(normalSpeed < 0.0f){ @@ -823,28 +947,61 @@ CPhysical::ApplyCollisionAlt(CEntity *B, CColPoint &colpoint, float &impulse, CV speed = GetSpeed(pointpos); normalSpeed = DotProduct(speed, colpoint.normal); if(normalSpeed < 0.0f){ - float minspeed = 1.3f*GRAVITY * CTimer::GetTimeStep(); -#if GTA_VERSION >= GTA3_PC_11 - if ((IsObject() || IsVehicle() && (GetUp().z < -0.3f || ((CVehicle*)this)->IsBike() && (GetStatus() == STATUS_ABANDONED || GetStatus() == STATUS_WRECKED))) && -#else - if((IsObject() || IsVehicle() && GetUp().z < -0.3f) && -#endif - !bHasContacted && + int16 elasticityType = 0; + float mass = GetMass(pointpos, colpoint.normal); + float minspeed = GRAVITY * CTimer::GetTimeStep(); + + if(IsObject()) + elasticityType = 1; + else if(IsVehicle() && !bIsInWater){ + if(((CVehicle*)this)->IsBike() && (GetStatus() == STATUS_ABANDONED || GetStatus() == STATUS_WRECKED)){ + minspeed *= 1.3f; + elasticityType = 3; + }else if(((CVehicle*)this)->IsBoat()){ + minspeed *= 1.2f; + elasticityType = 4; + }else if(GetUp().z < -0.3f){ + minspeed *= 1.1f; + elasticityType = 2; + } + } + + if(elasticityType == 1 && !bHasContacted && + Abs(m_vecMoveSpeed.x) < minspeed && + Abs(m_vecMoveSpeed.y) < minspeed && + Abs(m_vecMoveSpeed.z) < minspeed*2.0f) + impulse = -0.98f * normalSpeed * mass; + if(elasticityType == 3 && + Abs(m_vecMoveSpeed.x) < minspeed && + Abs(m_vecMoveSpeed.y) < minspeed && + Abs(m_vecMoveSpeed.z) < minspeed*2.0f) + impulse = -0.8f * normalSpeed * mass; + else if(elasticityType == 2 && Abs(m_vecMoveSpeed.x) < minspeed && Abs(m_vecMoveSpeed.y) < minspeed && Abs(m_vecMoveSpeed.z) < minspeed*2.0f) - e = -1.0f; + impulse = -0.92f * normalSpeed * mass; + else if(elasticityType == 4 && + Abs(m_vecMoveSpeed.x) < minspeed && + Abs(m_vecMoveSpeed.y) < minspeed && + Abs(m_vecMoveSpeed.z) < minspeed*2.0f) + impulse = -0.8f * normalSpeed * mass; + else if(IsVehicle() && ((CVehicle*)this)->IsBoat() && + colpoint.surfaceB == SURFACE_WOOD_SOLID && colpoint.normal.z < 0.5f) + impulse = -(2.0f * m_fElasticity + 1.0f) * normalSpeed * mass; else - e = -(m_fElasticity + 1.0f); - impulse = normalSpeed * e * GetMass(pointpos, colpoint.normal); + impulse = -(m_fElasticity + 1.0f) * normalSpeed * mass; // ApplyMoveForce vImpulse = colpoint.normal*impulse; - if(IsVehicle() && - (!bHasHitWall || - !(m_vecMoveSpeed.MagnitudeSqr() > 0.1 || !(B->IsBuilding() || ((CPhysical*)B)->bInfiniteMass)))) - moveSpeed += vImpulse * 1.2f * (1.0f/m_fMass); - else + if(IsVehicle()){ + if(!bHasHitWall || + !(m_vecMoveSpeed.MagnitudeSqr() > 0.1 || !(B->IsBuilding() || ((CPhysical*)B)->bInfiniteMass))) + moveSpeed += vImpulse * 1.2f * (1.0f/m_fMass); + else + moveSpeed += vImpulse * (1.0f/m_fMass); + vImpulse *= 0.8f; + }else moveSpeed += vImpulse * (1.0f/m_fMass); // ApplyTurnForce @@ -1086,13 +1243,13 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists) if(B->IsBuilding()) skipShift = false; - else if(IsStreetLight(A->GetModelIndex()) && + else if(IsLightWithoutShift(A->GetModelIndex()) && (B->IsVehicle() || B->IsPed()) && A->GetUp().z < 0.66f) skipShift = true; else if((A->IsVehicle() || A->IsPed()) && B->GetUp().z < 0.66f && - IsStreetLight(B->GetModelIndex())) + IsLightWithoutShift(B->GetModelIndex())) skipShift = true; else if(A->IsObject() && B->IsVehicle()){ CObject *Aobj = (CObject*)A; @@ -1212,6 +1369,9 @@ CPhysical::ProcessCollisionSectorList_SimpleCar(CPtrList *lists) A = (CPhysical*)this; + if(!A->bUsesCollision) + return false; + radius = A->GetBoundRadius(); A->GetBoundCentre(center); @@ -1230,6 +1390,7 @@ CPhysical::ProcessCollisionSectorList_SimpleCar(CPtrList *lists) for(listnode = list->first; listnode; listnode = listnode->next){ B = (CPhysical*)listnode->item; if(B != A && + !(B->IsObject() && ((CObject*)B)->bIsStreetLight && B->GetUp().z < 0.66f) && B->m_scanCode != CWorld::GetCurrentScanCode() && B->bUsesCollision && B->GetIsTouching(center, radius)){ @@ -1373,6 +1534,7 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) int numResponses; int i, j; bool skipCollision, altcollision; + bool ret = false; float impulseA = -1.0f; float impulseB = -1.0f; @@ -1393,9 +1555,9 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) Bped = (CPed*)B; bool isTouching = true; - if(B == A || + if(!B->bUsesCollision || B->m_scanCode == CWorld::GetCurrentScanCode() || - !B->bUsesCollision || + B == A || !(isTouching = B->GetIsTouching(center, radius))){ if(!isTouching){ if(A->IsObject() && Aobj->m_pCollidingEntity == B) @@ -1416,27 +1578,27 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) if(B->IsBuilding()) skipCollision = false; - else if(IsStreetLight(A->GetModelIndex()) && + else if(A->IsObject() && Aobj->bIsStreetLight && (B->IsVehicle() || B->IsPed()) && A->GetUp().z < 0.66f){ skipCollision = true; A->bSkipLineCol = true; Aobj->m_pCollidingEntity = B; - }else if((A->IsVehicle() || A->IsPed()) && - B->GetUp().z < 0.66f && - IsStreetLight(B->GetModelIndex())){ + }else if(B->IsObject() && Bobj->bIsStreetLight && + (A->IsVehicle() || A->IsPed()) && + B->GetUp().z < 0.66f){ skipCollision = true; A->bSkipLineCol = true; Bobj->m_pCollidingEntity = A; }else if(A->IsObject() && B->IsVehicle()){ - if(A->GetModelIndex() == MI_CAR_BUMPER || A->GetModelIndex() == MI_FILES) + if(A->GetModelIndex() == MI_CAR_BUMPER) skipCollision = true; else if(Aobj->ObjectCreatedBy == TEMP_OBJECT || Aobj->bHasBeenDamaged || !Aobj->GetIsStatic()){ if(Aobj->m_pCollidingEntity == B) skipCollision = true; - else{ + else if(Aobj->m_nCollisionDamageEffect < DAMAGE_EFFECT_SMASH_COMPLETELY){ CMatrix inv; CVector size = CModelInfo::GetModelInfo(A->GetModelIndex())->GetColModel()->boundingBox.GetSize(); size = A->GetMatrix() * size; @@ -1448,14 +1610,14 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) } } }else if(B->IsObject() && A->IsVehicle()){ - if(B->GetModelIndex() == MI_CAR_BUMPER || B->GetModelIndex() == MI_FILES) + if(B->GetModelIndex() == MI_CAR_BUMPER) skipCollision = true; else if(Bobj->ObjectCreatedBy == TEMP_OBJECT || Bobj->bHasBeenDamaged || !Bobj->GetIsStatic()){ if(Bobj->m_pCollidingEntity == A) skipCollision = true; - else{ + else if(Bobj->m_nCollisionDamageEffect < DAMAGE_EFFECT_SMASH_COMPLETELY){ CMatrix inv; CVector size = CModelInfo::GetModelInfo(B->GetModelIndex())->GetColModel()->boundingBox.GetSize(); size = B->GetMatrix() * size; @@ -1465,14 +1627,16 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) } } } - }else if(IsBodyPart(A->GetModelIndex()) && B->IsPed()){ + }else if(A->GetModelIndex() == MI_GRENADE && B->IsPed() && + A->GetPosition().z < B->GetPosition().z){ skipCollision = true; - }else if(A->IsPed() && IsBodyPart(B->GetModelIndex())){ + }else if(B->GetModelIndex() == MI_GRENADE && A->IsPed() && + B->GetPosition().z < A->GetPosition().z){ skipCollision = true; A->bSkipLineCol = true; }else if(A->IsPed() && Aped->m_pCollidingEntity == B){ skipCollision = true; - if(!Aped->bKnockedUpIntoAir) + if(!Aped->bKnockedUpIntoAir || Aped->bKnockedOffBike) A->bSkipLineCol = true; }else if(B->IsPed() && Bped->m_pCollidingEntity == A){ skipCollision = true; @@ -1487,7 +1651,11 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) if(!A->bUsesCollision || skipCollision){ B->m_scanCode = CWorld::GetCurrentScanCode(); - A->ProcessEntityCollision(B, aColPoints); + numCollisions = A->ProcessEntityCollision(B, aColPoints); + if(A->bJustCheckCollision && numCollisions > 0) + return true; + if(numCollisions == 0 && A == (CEntity*)FindPlayerPed() && Aped->m_pCollidingEntity == B) + Aped->m_pCollidingEntity = nil; }else if(B->IsBuilding() || B->bIsStuck || B->bInfiniteMass || altcollision){ // This is the case where B doesn't move @@ -1499,6 +1667,7 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) CVector moveSpeed = { 0.0f, 0.0f, 0.0f }; CVector turnSpeed = { 0.0f, 0.0f, 0.0f }; + float maxImpulseA = 0.0f; numResponses = 0; if(A->bHasContacted){ for(i = 0; i < numCollisions; i++){ @@ -1506,20 +1675,35 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) continue; numResponses++; + if(impulseA > maxImpulseA) maxImpulseA = impulseA; - if(impulseA > A->m_fDamageImpulse) - A->SetDamagedPieceRecord(aColPoints[i].pieceA, impulseA, B, aColPoints[i].normal); + if(A->IsVehicle()){ + if(!(((CVehicle*)A)->IsBoat() && aColPoints[i].surfaceB == SURFACE_WOOD_SOLID) && + impulseA > A->m_fDamageImpulse) + A->SetDamagedPieceRecord(aColPoints[i].pieceA, impulseA, B, aColPoints[i].normal); - float imp = impulseA; - if(A->IsVehicle() && A->GetUp().z < -0.6f && - Abs(A->m_vecMoveSpeed.x) < 0.05f && - Abs(A->m_vecMoveSpeed.y) < 0.05f) - imp *= 0.1f; + if(CSurfaceTable::GetAdhesionGroup(aColPoints[i].surfaceB) == ADHESIVE_SAND) + aColPoints[i].surfaceB = SURFACE_SAND; - float turnSpeedDiff = A->m_vecTurnSpeed.MagnitudeSqr(); - float moveSpeedDiff = A->m_vecMoveSpeed.MagnitudeSqr(); + float turnSpeedDiff = A->m_vecTurnSpeed.MagnitudeSqr(); + float moveSpeedDiff = A->m_vecMoveSpeed.MagnitudeSqr(); - DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, imp, Max(turnSpeedDiff, moveSpeedDiff)); + if(A->GetUp().z < -0.6f && + Abs(A->m_vecMoveSpeed.x) < 0.05f && + Abs(A->m_vecMoveSpeed.y) < 0.05f) + DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, 0.1f*impulseA, Max(turnSpeedDiff, moveSpeedDiff)); + else + DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, Max(turnSpeedDiff, moveSpeedDiff)); + + }else{ + if(impulseA > A->m_fDamageImpulse) + A->SetDamagedPieceRecord(aColPoints[i].pieceA, impulseA, B, aColPoints[i].normal); + + float turnSpeedDiff = A->m_vecTurnSpeed.MagnitudeSqr(); + float moveSpeedDiff = A->m_vecMoveSpeed.MagnitudeSqr(); + + DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, Max(turnSpeedDiff, moveSpeedDiff)); + } } }else{ for(i = 0; i < numCollisions; i++){ @@ -1527,38 +1711,52 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) continue; numResponses++; + if(impulseA > maxImpulseA) maxImpulseA = impulseA; + float adhesion = CSurfaceTable::GetAdhesiveLimit(aColPoints[i]) / numCollisions; - if(impulseA > A->m_fDamageImpulse) - A->SetDamagedPieceRecord(aColPoints[i].pieceA, impulseA, B, aColPoints[i].normal); - - float imp = impulseA; - if(A->IsVehicle() && A->GetUp().z < -0.6f && - Abs(A->m_vecMoveSpeed.x) < 0.05f && - Abs(A->m_vecMoveSpeed.y) < 0.05f) - imp *= 0.1f; - - float turnSpeedDiff = A->m_vecTurnSpeed.MagnitudeSqr(); - float moveSpeedDiff = A->m_vecMoveSpeed.MagnitudeSqr(); + if(A->IsVehicle()){ + if(((CVehicle*)A)->IsBoat() && aColPoints[i].surfaceB == SURFACE_WOOD_SOLID) + adhesion = 0.0f; + else if(impulseA > A->m_fDamageImpulse) + A->SetDamagedPieceRecord(aColPoints[i].pieceA, impulseA, B, aColPoints[i].normal); - DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, imp, Max(turnSpeedDiff, moveSpeedDiff)); + if(CSurfaceTable::GetAdhesionGroup(aColPoints[i].surfaceB) == ADHESIVE_SAND) + aColPoints[i].surfaceB = SURFACE_SAND; - float adhesion = CSurfaceTable::GetAdhesiveLimit(aColPoints[i]) / numCollisions; + float turnSpeedDiff = A->m_vecTurnSpeed.MagnitudeSqr(); + float moveSpeedDiff = A->m_vecMoveSpeed.MagnitudeSqr(); - if(A->GetModelIndex() == MI_RCBANDIT) - adhesion *= 0.2f; - else if(IsBoatModel(A->GetModelIndex())){ - if(aColPoints[i].normal.z > 0.6f){ - if(CSurfaceTable::GetAdhesionGroup(aColPoints[i].surfaceB) == ADHESIVE_LOOSE) - adhesion *= 3.0f; - }else - adhesion = 0.0f; - }else if(A->IsVehicle()){ - if(A->GetStatus() == STATUS_WRECKED) + if(A->GetUp().z < -0.6f && + Abs(A->m_vecMoveSpeed.x) < 0.05f && + Abs(A->m_vecMoveSpeed.y) < 0.05f) + DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, 0.1f*impulseA, Max(turnSpeedDiff, moveSpeedDiff)); + else + DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, Max(turnSpeedDiff, moveSpeedDiff)); + + + if(A->GetModelIndex() == MI_RCBANDIT) + adhesion *= 0.2f; + else if(((CVehicle*)A)->IsBoat()){ + if(aColPoints[i].normal.z > 0.6f){ + if(CSurfaceTable::GetAdhesionGroup(aColPoints[i].surfaceB) == ADHESIVE_LOOSE || + CSurfaceTable::GetAdhesionGroup(aColPoints[i].surfaceB) == ADHESIVE_SAND) + adhesion *= 3.0f; + }else + adhesion = 0.0f; + }else if(A->GetStatus() == STATUS_WRECKED) adhesion *= 3.0f; else if(A->GetUp().z > 0.3f) adhesion = 0.0f; else adhesion *= Min(5.0f, 0.03f*impulseA + 1.0f); + }else{ + if(impulseA > A->m_fDamageImpulse) + A->SetDamagedPieceRecord(aColPoints[i].pieceA, impulseA, B, aColPoints[i].normal); + + float turnSpeedDiff = A->m_vecTurnSpeed.MagnitudeSqr(); + float moveSpeedDiff = A->m_vecMoveSpeed.MagnitudeSqr(); + + DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, Max(turnSpeedDiff, moveSpeedDiff)); } if(A->ApplyFriction(adhesion, aColPoints[i])) @@ -1577,7 +1775,13 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) A->m_vecMoveFriction.y += moveSpeed.y * -0.3f / numCollisions; A->m_vecTurnFriction += turnSpeed * -0.3f / numCollisions; } - return true; + + if(B->IsObject() && Bobj->m_nCollisionDamageEffect && maxImpulseA > 20.0f) + Bobj->ObjectDamage(maxImpulseA); + + if(!CWorld::bSecondShift) + return true; + ret = true; } }else{ @@ -1717,9 +1921,25 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) // BUG? not impulseA? if(Bobj->m_nCollisionDamageEffect && maxImpulseB > 20.0f) Bobj->ObjectDamage(maxImpulseB); + else if(Bobj->m_nCollisionDamageEffect >= DAMAGE_EFFECT_SMASH_COMPLETELY){ + CMatrix inv; + CVector size = CModelInfo::GetModelInfo(B->GetModelIndex())->GetColModel()->boundingBox.GetSize(); + size = B->GetMatrix() * size; + if(size.z < B->GetPosition().z || + (Invert(A->GetMatrix(), inv) * size).z < 0.0f) + Bobj->ObjectDamage(50.0f); + } }else if(A->IsObject() && A->bUsesCollision && B->IsVehicle()){ if(Aobj->m_nCollisionDamageEffect && maxImpulseB > 20.0f) Aobj->ObjectDamage(maxImpulseB); + else if(Aobj->m_nCollisionDamageEffect >= DAMAGE_EFFECT_SMASH_COMPLETELY){ + CMatrix inv; + CVector size = CModelInfo::GetModelInfo(A->GetModelIndex())->GetColModel()->boundingBox.GetSize(); + size = A->GetMatrix() * size; + if(size.z < A->GetPosition().z || + (Invert(B->GetMatrix(), inv) * size).z < 0.0f) + Aobj->ObjectDamage(50.0f); + } } if(B->GetStatus() == STATUS_SIMPLE){ @@ -1728,13 +1948,15 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) CCarCtrl::SwitchVehicleToRealPhysics((CVehicle*)B); } - return true; + if(!CWorld::bSecondShift) + return true; + ret = true; } } } - return false; + return ret; } bool @@ -1763,6 +1985,8 @@ CPhysical::CheckCollision_SimpleCar(void) return false; } +float PHYSICAL_SHIFT_SPEED_DAMP = 0.707f; + void CPhysical::ProcessShift(void) { @@ -1772,6 +1996,13 @@ CPhysical::ProcessShift(void) bIsInSafePosition = true; RemoveAndAdd(); }else{ + CPhysical *surf; + if(bHasHitWall && IsPed() && (surf = ((CPed*)this)->m_pCurrentPhysSurface, surf == nil || !surf->bInfiniteMass || surf->m_phy_flagA08) || + CWorld::bSecondShift){ + m_vecMoveSpeed *= Pow(PHYSICAL_SHIFT_SPEED_DAMP, CTimer::GetTimeStep()); + m_vecTurnSpeed *= Pow(PHYSICAL_SHIFT_SPEED_DAMP, CTimer::GetTimeStep()); + } + CMatrix matrix(GetMatrix()); ApplyMoveSpeed(); ApplyTurnSpeed(); @@ -1789,11 +2020,19 @@ CPhysical::ProcessShift(void) m_bIsVehicleBeingShifted = false; if(hasshifted){ CWorld::AdvanceCurrentScanCode(); + bool hadCollision = false; for(node = m_entryInfoList.first; node; node = node->next) if(ProcessCollisionSectorList(node->sector->m_lists)){ - GetMatrix() = matrix; - return; + if(!CWorld::bSecondShift){ + GetMatrix() = matrix; + return; + } + hadCollision = true; } + if(hadCollision){ + GetMatrix() = matrix; + return; + } } bIsStuck = false; bIsInSafePosition = true; @@ -1805,6 +2044,9 @@ CPhysical::ProcessShift(void) // x is the number of units (m) we would like to step #define NUMSTEPS(x) ceil(Sqrt(distSq) * (1.0f/(x))) +float HIGHSPEED_ELASTICITY_MULT_PED = 2.0f; +float HIGHSPEED_ELASTICITY_MULT_COPCAR = 2.0f; + void CPhysical::ProcessCollision(void) { @@ -1836,31 +2078,78 @@ CPhysical::ProcessCollision(void) // Save current state CMatrix savedMatrix(GetMatrix()); + float savedElasticity = m_fElasticity; + CVector savedMoveSpeed = m_vecMoveSpeed; float savedTimeStep = CTimer::GetTimeStep(); int8 n = 1; // The number of steps we divide the time step into float step = 0.0f; // divided time step float distSq = m_vecMoveSpeed.MagnitudeSqr() * sq(CTimer::GetTimeStep()); - if(IsPed() && (distSq >= sq(0.2f) || ped->IsPlayer())){ - if(ped->IsPlayer()) - n = Max(NUMSTEPS(0.2f), 2.0f); - else - n = NUMSTEPS(0.3f); + if(IsPed() && (distSq >= sq(0.3f) || ped->IsPlayer())){ + if(ped->IsPlayer()){ + if(ped->m_pCurrentPhysSurface) + n = Max(NUMSTEPS(0.15f), 4.0f); + else + n = Max(NUMSTEPS(0.3f), 2.0f); + }else + n = NUMSTEPS(0.45f); step = savedTimeStep / n; + if(!ped->IsPlayer()) + ped->m_fElasticity *= HIGHSPEED_ELASTICITY_MULT_PED; }else if(IsVehicle() && distSq >= sq(0.4f)){ if(GetStatus() == STATUS_PLAYER) n = NUMSTEPS(0.2f); else n = distSq > 0.32f ? NUMSTEPS(0.3f) : NUMSTEPS(0.4f); step = savedTimeStep / n; - }else if(IsObject()){ + + CVector bbox = GetColModel()->boundingBox.GetSize(); + float relDistX = Abs(DotProduct(m_vecMoveSpeed, GetRight())) * CTimer::GetTimeStep() / bbox.x; + float relDistY = Abs(DotProduct(m_vecMoveSpeed, GetForward())) * CTimer::GetTimeStep() / bbox.y; + float relDistZ = Abs(DotProduct(m_vecMoveSpeed, GetUp())) * CTimer::GetTimeStep() / bbox.z; + if(Max(relDistX, Max(relDistY, relDistZ)) < 1.0f){ + // check if we can get away with simplified processing + + ApplyMoveSpeed(); + ApplyTurnSpeed(); + GetMatrix().Reorthogonalise(); + bSkipLineCol = false; + m_bIsVehicleBeingShifted = false; + + bJustCheckCollision = true; + bUsesCollision = false; + if(!CheckCollision()){ + bJustCheckCollision = false; + bUsesCollision = true; + if(IsVehicle()) + ((CVehicle*)this)->bVehicleColProcessed = true; + + bHitByTrain = false; + m_fDistanceTravelled = (GetPosition() - savedMatrix.GetPosition()).Magnitude(); + bSkipLineCol = false; + + bIsStuck = false; + bIsInSafePosition = true; + m_fElasticity = savedElasticity; + RemoveAndAdd(); + return; + } + bJustCheckCollision = false; + bUsesCollision = true; + GetMatrix() = savedMatrix; + m_vecMoveSpeed = savedMoveSpeed; + if(IsVehicle() && ((CVehicle*)this)->bIsLawEnforcer) + m_fElasticity *= HIGHSPEED_ELASTICITY_MULT_COPCAR; + } + }else if(IsObject() && ((CObject*)this)->ObjectCreatedBy != TEMP_OBJECT){ int responsecase = ((CObject*)this)->m_nSpecialCollisionResponseCases; if(responsecase == COLLRESPONSE_LAMPOST){ CVector speedUp = { 0.0f, 0.0f, 0.0f }; CVector speedDown = { 0.0f, 0.0f, 0.0f }; - speedUp.z = GetBoundRadius(); - speedDown.z = -speedUp.z; + CColModel *colModel = GetColModel(); + speedUp.z = colModel->boundingBox.max.z; + speedDown.z = colModel->boundingBox.min.z; speedUp = Multiply3x3(GetMatrix(), speedUp); speedDown = Multiply3x3(GetMatrix(), speedDown); speedUp = GetSpeed(speedUp); @@ -1900,6 +2189,7 @@ CPhysical::ProcessCollision(void) savedMatrix.GetPosition().z = GetPosition().z; GetMatrix() = savedMatrix; CTimer::SetTimeStep(savedTimeStep); + m_fElasticity = savedElasticity; return; } if(IsPed() && m_vecMoveSpeed.z == 0.0f && @@ -1917,7 +2207,11 @@ CPhysical::ProcessCollision(void) car->m_aSuspensionSpringRatio[2] = 1.0f; car->m_aSuspensionSpringRatio[3] = 1.0f; }else if(veh->m_vehType == VEHICLE_TYPE_BIKE){ - assert(0 && "TODO - but unused"); + CBike *bike = (CBike*)this; + bike->m_aSuspensionSpringRatio[0] = 1.0f; + bike->m_aSuspensionSpringRatio[1] = 1.0f; + bike->m_aSuspensionSpringRatio[2] = 1.0f; + bike->m_aSuspensionSpringRatio[3] = 1.0f; } } } @@ -1929,15 +2223,15 @@ CPhysical::ProcessCollision(void) bSkipLineCol = false; if(!m_vecMoveSpeed.IsZero() || !m_vecTurnSpeed.IsZero() || -#ifdef GTA_TRAIN bHitByTrain || -#endif GetStatus() == STATUS_PLAYER || + IsVehicle() && ((CVehicle*)this)->bRestingOnPhysical || IsPed() && ped->IsPlayer()){ if(IsVehicle()) ((CVehicle*)this)->bVehicleColProcessed = true; if(CheckCollision()){ GetMatrix() = savedMatrix; + m_fElasticity = savedElasticity; return; } } @@ -1947,5 +2241,6 @@ CPhysical::ProcessCollision(void) bIsStuck = false; bIsInSafePosition = true; + m_fElasticity = savedElasticity; RemoveAndAdd(); } |