summaryrefslogtreecommitdiffstats
path: root/src/entities
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/entities/Building.cpp22
-rw-r--r--src/entities/Building.h2
-rw-r--r--src/entities/Dummy.cpp15
-rw-r--r--src/entities/Dummy.h2
-rw-r--r--src/entities/Entity.cpp555
-rw-r--r--src/entities/Entity.h14
-rw-r--r--src/entities/Physical.cpp567
-rw-r--r--src/entities/Physical.h18
8 files changed, 825 insertions, 370 deletions
diff --git a/src/entities/Building.cpp b/src/entities/Building.cpp
index 3c096636..3217e684 100644
--- a/src/entities/Building.cpp
+++ b/src/entities/Building.cpp
@@ -20,3 +20,25 @@ CBuilding::ReplaceWithNewModel(int32 id)
if(m_level == LEVEL_NONE || m_level == CGame::currLevel)
CStreaming::RequestModel(id, STREAMFLAGS_DONT_REMOVE);
}
+
+bool
+IsBuildingPointerValid(CBuilding* pBuilding)
+{
+ if (!pBuilding)
+ return false;
+ if (pBuilding->GetIsATreadable()) {
+ int index = CPools::GetTreadablePool()->GetJustIndex((CTreadable*)pBuilding);
+#ifdef FIX_BUGS
+ return index >= 0 && index < CPools::GetTreadablePool()->GetSize();
+#else
+ return index >= 0 && index <= CPools::GetTreadablePool()->GetSize();
+#endif
+ } else {
+ int index = CPools::GetBuildingPool()->GetJustIndex(pBuilding);
+#ifdef FIX_BUGS
+ return index >= 0 && index < CPools::GetBuildingPool()->GetSize();
+#else
+ return index >= 0 && index <= CPools::GetBuildingPool()->GetSize();
+#endif
+ }
+}
diff --git a/src/entities/Building.h b/src/entities/Building.h
index 29608c10..2c2dfb1f 100644
--- a/src/entities/Building.h
+++ b/src/entities/Building.h
@@ -16,3 +16,5 @@ public:
virtual bool GetIsATreadable(void) { return false; }
};
+
+bool IsBuildingPointerValid(CBuilding*);
diff --git a/src/entities/Dummy.cpp b/src/entities/Dummy.cpp
index 8a4bfd5f..92b69761 100644
--- a/src/entities/Dummy.cpp
+++ b/src/entities/Dummy.cpp
@@ -50,3 +50,18 @@ CDummy::Remove(void)
m_entryInfoList.DeleteNode(node);
}
}
+
+bool
+IsDummyPointerValid(CDummy* pDummy)
+{
+ if (!pDummy)
+ return false;
+ int index = CPools::GetDummyPool()->GetJustIndex(pDummy);
+#ifdef FIX_BUGS
+ if (index < 0 || index >= CPools::GetDummyPool()->GetSize())
+#else
+ if (index < 0 || index > CPools::GetDummyPool()->GetSize())
+#endif
+ return false;
+ return pDummy->m_entryInfoList.first;
+}
diff --git a/src/entities/Dummy.h b/src/entities/Dummy.h
index 7998a748..84b1ce1a 100644
--- a/src/entities/Dummy.h
+++ b/src/entities/Dummy.h
@@ -15,3 +15,5 @@ public:
static void *operator new(size_t);
static void operator delete(void*, size_t);
};
+
+bool IsDummyPointerValid(CDummy* pDummy);
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index 6f8ebcb4..68486a3c 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -28,6 +28,11 @@
#include "Bones.h"
#include "Debug.h"
#include "Renderer.h"
+#include "Ped.h"
+#include "Dummy.h"
+#include "WindModifiers.h"
+
+//--MIAMI: file almost done (see TODO)
int gBuildings;
@@ -78,7 +83,7 @@ CEntity::CEntity(void)
bIsStaticWaitingForCollision = false;
m_flagE10 = false;
bUnderwater = false;
- m_flagE40 = false;
+ bHasPreRenderEffects = false;
m_scanCode = 0;
m_modelIndex = -1;
@@ -275,6 +280,21 @@ CEntity::Remove(void)
}
void
+CEntity::SetModelIndex(uint32 id)
+{
+ m_modelIndex = id;
+ bHasPreRenderEffects = HasPreRenderEffects();
+ CreateRwObject();
+}
+
+void
+CEntity::SetModelIndexNoCreate(uint32 id)
+{
+ m_modelIndex = id;
+ bHasPreRenderEffects = HasPreRenderEffects();
+}
+
+void
CEntity::CreateRwObject(void)
{
CBaseModelInfo *mi;
@@ -304,10 +324,8 @@ CEntity::DeleteRwObject(void)
RpAtomicDestroy((RpAtomic*)m_rwObject);
RwFrameDestroy(f);
}else if(RwObjectGetType(m_rwObject) == rpCLUMP){
-#ifdef PED_SKIN
if(IsClumpSkinned((RpClump*)m_rwObject))
RpClumpForAllAtomics((RpClump*)m_rwObject, AtomicRemoveAnimFromSkinCB, nil);
-#endif
RpClumpDestroy((RpClump*)m_rwObject);
}
m_rwObject = nil;
@@ -328,7 +346,6 @@ CEntity::UpdateRwFrame(void)
}
}
-//--MIAMI: done
void
CEntity::SetupBigBuilding(void)
{
@@ -368,19 +385,39 @@ CEntity::GetBoundRect(void)
return rect;
}
+bool
+CEntity::HasPreRenderEffects(void)
+{
+ return IsTreeModel(GetModelIndex()) ||
+ GetModelIndex() == MI_COLLECTABLE1 ||
+ GetModelIndex() == MI_MONEY ||
+ GetModelIndex() == MI_CARMINE ||
+ GetModelIndex() == MI_NAUTICALMINE ||
+ GetModelIndex() == MI_BRIEFCASE ||
+ GetModelIndex() == MI_GRENADE ||
+ GetModelIndex() == MI_MOLOTOV ||
+ GetModelIndex() == MI_MISSILE ||
+ GetModelIndex() == MI_BEACHBALL ||
+ IsGlass(GetModelIndex()) ||
+ IsObject() && ((CObject*)this)->bIsPickup ||
+ IsLightWithPreRenderEffects(GetModelIndex());
+}
+
void
CEntity::PreRender(void)
{
+ if (CModelInfo::GetModelInfo(GetModelIndex())->GetNum2dEffects() != 0)
+ ProcessLightsForEntity();
+
+ if(!bHasPreRenderEffects)
+ return;
+
switch(m_type){
case ENTITY_TYPE_BUILDING:
- if(GetModelIndex() == MI_RAILTRACKS){
- CShadows::StoreShadowForPole(this, 0.0f, -10.949f, 5.0f, 8.0f, 1.0f, 0);
- CShadows::StoreShadowForPole(this, 0.0f, 10.949f, 5.0f, 8.0f, 1.0f, 1);
- }else if(IsTreeModel(GetModelIndex())){
- CShadows::StoreShadowForTree(this);
+ if(IsTreeModel(GetModelIndex())){
+ float dist = (TheCamera.GetPosition() - GetPosition()).Magnitude2D();
+ CObject::fDistToNearestTree = Min(CObject::fDistToNearestTree, dist);
ModifyMatrixForTreeInWind();
- }else if(IsBannerModel(GetModelIndex())){
- ModifyMatrixForBannerInWind();
}
break;
case ENTITY_TYPE_OBJECT:
@@ -400,22 +437,6 @@ CEntity::PreRender(void)
GetMatrix().UpdateRW();
UpdateRwFrame();
}
- }else if(IsPickupModel(GetModelIndex())){
- if(((CObject*)this)->bIsPickup){
- CPickups::DoPickUpEffects(this);
- GetMatrix().UpdateRW();
- UpdateRwFrame();
- }else if(GetModelIndex() == MI_GRENADE){
- CMotionBlurStreaks::RegisterStreak((uintptr)this,
- 100, 100, 100,
- GetPosition() - 0.07f*TheCamera.GetRight(),
- GetPosition() + 0.07f*TheCamera.GetRight());
- }else if(GetModelIndex() == MI_MOLOTOV){
- CMotionBlurStreaks::RegisterStreak((uintptr)this,
- 0, 100, 0,
- GetPosition() - 0.07f*TheCamera.GetRight(),
- GetPosition() + 0.07f*TheCamera.GetRight());
- }
}else if(GetModelIndex() == MI_MISSILE){
CVector pos = GetPosition();
float flicker = (CGeneral::GetRandomNumber() & 0xF)/(float)0x10;
@@ -438,12 +459,44 @@ CEntity::PreRender(void)
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
}else if(IsGlass(GetModelIndex())){
PreRenderForGlassWindow();
+ }else if (((CObject*)this)->bIsPickup) {
+ CPickups::DoPickUpEffects(this);
+ GetMatrix().UpdateRW();
+ UpdateRwFrame();
+ } else if (GetModelIndex() == MI_GRENADE) {
+ CMotionBlurStreaks::RegisterStreak((uintptr)this,
+ 100, 100, 100,
+ GetPosition() - 0.07f * TheCamera.GetRight(),
+ GetPosition() + 0.07f * TheCamera.GetRight());
+ } else if (GetModelIndex() == MI_MOLOTOV) {
+ CMotionBlurStreaks::RegisterStreak((uintptr)this,
+ 0, 100, 0,
+ GetPosition() - 0.07f * TheCamera.GetRight(),
+ GetPosition() + 0.07f * TheCamera.GetRight());
+ }else if(GetModelIndex() == MI_BEACHBALL){
+ CVector pos = GetPosition();
+ CShadows::StoreShadowToBeRendered(SHADOWTYPE_DARK,
+ gpShadowPedTex, &pos,
+ 0.4f, 0.0f, 0.0f, -0.4f,
+ CTimeCycle::GetShadowStrength(),
+ CTimeCycle::GetShadowStrength(),
+ CTimeCycle::GetShadowStrength(),
+ CTimeCycle::GetShadowStrength(),
+ 20.0f, false, 1.0f);
}
// fall through
case ENTITY_TYPE_DUMMY:
if(GetModelIndex() == MI_TRAFFICLIGHTS){
CTrafficLights::DisplayActualLight(this);
CShadows::StoreShadowForPole(this, 2.957f, 0.147f, 0.0f, 16.0f, 0.4f, 0);
+ }else if(GetModelIndex() == MI_TRAFFICLIGHTS_VERTICAL){
+ CTrafficLights::DisplayActualLight(this);
+ }else if(GetModelIndex() == MI_TRAFFICLIGHTS_MIAMI){
+ CTrafficLights::DisplayActualLight(this);
+ CShadows::StoreShadowForPole(this, 4.819f, 1.315f, 0.0f, 16.0f, 0.4f, 0);
+ }else if(GetModelIndex() == MI_TRAFFICLIGHTS_TWOVERTICAL){
+ CTrafficLights::DisplayActualLight(this);
+ CShadows::StoreShadowForPole(this, 7.503f, 0.0f, 0.0f, 16.0f, 0.4f, 0);
}else if(GetModelIndex() == MI_SINGLESTREETLIGHTS1)
CShadows::StoreShadowForPole(this, 0.744f, 0.0f, 0.0f, 16.0f, 0.4f, 0);
else if(GetModelIndex() == MI_SINGLESTREETLIGHTS2)
@@ -452,19 +505,15 @@ CEntity::PreRender(void)
CShadows::StoreShadowForPole(this, 1.143f, 0.145f, 0.0f, 16.0f, 0.4f, 0);
else if(GetModelIndex() == MI_DOUBLESTREETLIGHTS)
CShadows::StoreShadowForPole(this, 0.0f, -0.048f, 0.0f, 16.0f, 0.4f, 0);
- else if(GetModelIndex() == MI_STREETLAMP1 ||
- GetModelIndex() == MI_STREETLAMP2)
- CShadows::StoreShadowForPole(this, 0.0f, 0.0f, 0.0f, 16.0f, 0.4f, 0);
break;
}
-
- if (CModelInfo::GetModelInfo(GetModelIndex())->GetNum2dEffects() != 0)
- ProcessLightsForEntity();
}
void
CEntity::PreRenderForGlassWindow(void)
{
+ if(((CSimpleModelInfo*)CModelInfo::GetModelInfo(m_modelIndex))->m_isArtistGlass)
+ return;
CGlass::AskForObjectToBeRenderedInGlass(this);
bIsVisible = false;
}
@@ -485,8 +534,6 @@ CEntity::Render(void)
bool
CEntity::SetupLighting(void)
{
- DeActivateDirectional();
- SetAmbientColours();
return false;
}
@@ -572,13 +619,12 @@ CEntity::PruneReferences(void)
}
}
-#ifdef PED_SKIN
void
CEntity::UpdateRpHAnim(void)
{
- RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump());
- RpHAnimHierarchyUpdateMatrices(hier);
-
+ if(IsClumpSkinned(GetClump())){
+ RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump());
+ RpHAnimHierarchyUpdateMatrices(hier);
#if 0
int i;
char buf[256];
@@ -607,8 +653,8 @@ CEntity::UpdateRpHAnim(void)
void RenderSkeleton(RpHAnimHierarchy *hier);
RenderSkeleton(hier);
#endif
+ }
}
-#endif
void
CEntity::AddSteamsFromGround(CVector *unused)
@@ -640,6 +686,15 @@ CEntity::AddSteamsFromGround(CVector *unused)
case 4:
CParticleObject::AddObject(POBJECT_DARK_SMOKE, pos, effect->particle.dir, effect->particle.scale, false);
break;
+// TODO(MIAMI): enable this once we have the particle objects
+/*
+ case 5:
+ CParticleObject::AddObject(POBJECT_WATER_FOUNTAIN_VERT, pos, effect->particle.dir, effect->particle.scale, false);
+ break;
+ case 6:
+ CParticleObject::AddObject(POBJECT_WATER_FOUNTAIN_HORIZ, pos, effect->particle.dir, effect->particle.scale, false);
+ break;
+*/
}
}
}
@@ -664,80 +719,66 @@ CEntity::ProcessLightsForEntity(void)
for(i = 0; i < n; i++, flashTimer1 += 0x80, flashTimer2 += 0x100, flashTimer3 += 0x200){
effect = CModelInfo::GetModelInfo(GetModelIndex())->Get2dEffect(i);
- if(effect->type != EFFECT_LIGHT)
- continue;
-
- pos = GetMatrix() * effect->pos;
+ switch(effect->type){
+ case EFFECT_LIGHT:
+ pos = GetMatrix() * effect->pos;
- lightOn = false;
- lightFlickering = false;
- switch(effect->light.lightType){
- case LIGHT_ON:
- lightOn = true;
- break;
- case LIGHT_ON_NIGHT:
- if(CClock::GetHours() > 18 || CClock::GetHours() < 7)
- lightOn = true;
- break;
- case LIGHT_FLICKER:
- if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed) & 0x60)
+ lightOn = false;
+ lightFlickering = false;
+ switch(effect->light.lightType){
+ case LIGHT_ON:
lightOn = true;
- else
- lightFlickering = true;
- if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed) & 3)
- lightOn = true;
- break;
- case LIGHT_FLICKER_NIGHT:
- if(CClock::GetHours() > 18 || CClock::GetHours() < 7){
+ break;
+ case LIGHT_ON_NIGHT:
+ if(CClock::GetHours() > 18 || CClock::GetHours() < 7)
+ lightOn = true;
+ break;
+ case LIGHT_FLICKER:
if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed) & 0x60)
lightOn = true;
else
lightFlickering = true;
if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed) & 3)
lightOn = true;
- }
- break;
- case LIGHT_FLASH1:
- if((CTimer::GetTimeInMilliseconds() + flashTimer1) & 0x200)
- lightOn = true;
- break;
- case LIGHT_FLASH1_NIGHT:
- if(CClock::GetHours() > 18 || CClock::GetHours() < 7)
+ break;
+ case LIGHT_FLICKER_NIGHT:
+ if(CClock::GetHours() > 18 || CClock::GetHours() < 7 || CWeather::WetRoads > 0.5f){
+ if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed) & 0x60)
+ lightOn = true;
+ else
+ lightFlickering = true;
+ if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed) & 3)
+ lightOn = true;
+ }
+ break;
+ case LIGHT_FLASH1:
if((CTimer::GetTimeInMilliseconds() + flashTimer1) & 0x200)
lightOn = true;
- break;
- case LIGHT_FLASH2:
- if((CTimer::GetTimeInMilliseconds() + flashTimer2) & 0x400)
- lightOn = true;
- break;
- case LIGHT_FLASH2_NIGHT:
- if(CClock::GetHours() > 18 || CClock::GetHours() < 7)
+ break;
+ case LIGHT_FLASH1_NIGHT:
+ if(CClock::GetHours() > 18 || CClock::GetHours() < 7)
+ if((CTimer::GetTimeInMilliseconds() + flashTimer1) & 0x200)
+ lightOn = true;
+ break;
+ case LIGHT_FLASH2:
if((CTimer::GetTimeInMilliseconds() + flashTimer2) & 0x400)
lightOn = true;
- break;
- case LIGHT_FLASH3:
- if((CTimer::GetTimeInMilliseconds() + flashTimer3) & 0x800)
- lightOn = true;
- break;
- case LIGHT_FLASH3_NIGHT:
- if(CClock::GetHours() > 18 || CClock::GetHours() < 7)
+ break;
+ case LIGHT_FLASH2_NIGHT:
+ if(CClock::GetHours() > 18 || CClock::GetHours() < 7)
+ if((CTimer::GetTimeInMilliseconds() + flashTimer2) & 0x400)
+ lightOn = true;
+ break;
+ case LIGHT_FLASH3:
if((CTimer::GetTimeInMilliseconds() + flashTimer3) & 0x800)
lightOn = true;
- break;
- case LIGHT_RANDOM_FLICKER:
- if(m_randomSeed > 16)
- lightOn = true;
- else{
- if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed*8) & 0x60)
- lightOn = true;
- else
- lightFlickering = true;
- if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed*8) & 3)
- lightOn = true;
- }
- break;
- case LIGHT_RANDOM_FLICKER_NIGHT:
- if(CClock::GetHours() > 18 || CClock::GetHours() < 7){
+ break;
+ case LIGHT_FLASH3_NIGHT:
+ if(CClock::GetHours() > 18 || CClock::GetHours() < 7)
+ if((CTimer::GetTimeInMilliseconds() + flashTimer3) & 0x800)
+ lightOn = true;
+ break;
+ case LIGHT_RANDOM_FLICKER:
if(m_randomSeed > 16)
lightOn = true;
else{
@@ -748,85 +789,143 @@ CEntity::ProcessLightsForEntity(void)
if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed*8) & 3)
lightOn = true;
}
+ break;
+ case LIGHT_RANDOM_FLICKER_NIGHT:
+ if(CClock::GetHours() > 18 || CClock::GetHours() < 7){
+ if(m_randomSeed > 16)
+ lightOn = true;
+ else{
+ if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed*8) & 0x60)
+ lightOn = true;
+ else
+ lightFlickering = true;
+ if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed*8) & 3)
+ lightOn = true;
+ }
+ }
+ break;
+ case LIGHT_BRIDGE_FLASH1:
+ if(CBridge::ShouldLightsBeFlashing() && CTimer::GetTimeInMilliseconds() & 0x200)
+ lightOn = true;
+ break;
+ case LIGHT_BRIDGE_FLASH2:
+ if(CBridge::ShouldLightsBeFlashing() && (CTimer::GetTimeInMilliseconds() & 0x1FF) < 60)
+ lightOn = true;
+ break;
+ }
+
+ if(effect->light.flags & LIGHTFLAG_HIDE_OBJECT){
+ if(lightOn)
+ bDoNotRender = false;
+ else
+ bDoNotRender = true;
+ return;
+ }
+
+ // Corona
+ if(lightOn)
+ CCoronas::RegisterCorona((uintptr)this + i,
+ effect->col.r, effect->col.g, effect->col.b, 255,
+ pos, effect->light.size, effect->light.dist,
+ effect->light.corona, effect->light.flareType, effect->light.roadReflection,
+ effect->light.flags&LIGHTFLAG_LOSCHECK, CCoronas::STREAK_OFF, 0.0f,
+ !!(effect->light.flags&LIGHTFLAG_LONG_DIST));
+ else if(lightFlickering)
+ CCoronas::RegisterCorona((uintptr)this + i,
+ 0, 0, 0, 255,
+ pos, effect->light.size, effect->light.dist,
+ effect->light.corona, effect->light.flareType, effect->light.roadReflection,
+ effect->light.flags&LIGHTFLAG_LOSCHECK, CCoronas::STREAK_OFF, 0.0f,
+ !!(effect->light.flags&LIGHTFLAG_LONG_DIST));
+
+ // Pointlight
+ bool alreadyProcessedFog;
+ alreadyProcessedFog = false;
+ if(effect->light.range != 0.0f && lightOn){
+ if(effect->col.r == 0 && effect->col.g == 0 && effect->col.b == 0){
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ pos, CVector(0.0f, 0.0f, 0.0f),
+ effect->light.range,
+ 0.0f, 0.0f, 0.0f,
+ CPointLights::FOG_NONE, true);
+ }else{
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ pos, CVector(0.0f, 0.0f, 0.0f),
+ effect->light.range,
+ effect->col.r*CTimeCycle::GetSpriteBrightness()/255.0f,
+ effect->col.g*CTimeCycle::GetSpriteBrightness()/255.0f,
+ effect->col.b*CTimeCycle::GetSpriteBrightness()/255.0f,
+ (effect->light.flags & LIGHTFLAG_FOG) >> 1,
+ true);
+ alreadyProcessedFog = true;
+ }
}
- break;
- case LIGHT_BRIDGE_FLASH1:
- if(CBridge::ShouldLightsBeFlashing() && CTimer::GetTimeInMilliseconds() & 0x200)
- lightOn = true;
- break;
- case LIGHT_BRIDGE_FLASH2:
- if(CBridge::ShouldLightsBeFlashing() && (CTimer::GetTimeInMilliseconds() & 0x1FF) < 60)
- lightOn = true;
- break;
- }
- // Corona
- if(lightOn)
- CCoronas::RegisterCorona((uintptr)this + i,
- effect->col.r, effect->col.g, effect->col.b, 255,
- pos, effect->light.size, effect->light.dist,
- effect->light.corona, effect->light.flareType, effect->light.roadReflection,
- effect->light.flags&LIGHTFLAG_LOSCHECK, CCoronas::STREAK_OFF, 0.0f);
- else if(lightFlickering)
- CCoronas::RegisterCorona((uintptr)this + i,
- 0, 0, 0, 255,
- pos, effect->light.size, effect->light.dist,
- effect->light.corona, effect->light.flareType, effect->light.roadReflection,
- effect->light.flags&LIGHTFLAG_LOSCHECK, CCoronas::STREAK_OFF, 0.0f);
-
- // Pointlight
- if(effect->light.flags & LIGHTFLAG_FOG_ALWAYS){
- CPointLights::AddLight(CPointLights::LIGHT_FOGONLY_ALWAYS,
- pos, CVector(0.0f, 0.0f, 0.0f),
- effect->light.range,
- effect->col.r/255.0f, effect->col.g/255.0f, effect->col.b/255.0f,
- CPointLights::FOG_ALWAYS, true);
- }else if(effect->light.flags & LIGHTFLAG_FOG_NORMAL && lightOn && effect->light.range == 0.0f){
- CPointLights::AddLight(CPointLights::LIGHT_FOGONLY,
- pos, CVector(0.0f, 0.0f, 0.0f),
- effect->light.range,
- effect->col.r/255.0f, effect->col.g/255.0f, effect->col.b/255.0f,
- CPointLights::FOG_NORMAL, true);
- }else if(lightOn && effect->light.range != 0.0f){
- if(effect->col.r == 0 && effect->col.g == 0 && effect->col.b == 0){
- CPointLights::AddLight(CPointLights::LIGHT_POINT,
- pos, CVector(0.0f, 0.0f, 0.0f),
- effect->light.range,
- 0.0f, 0.0f, 0.0f,
- CPointLights::FOG_NONE, true);
- }else{
- CPointLights::AddLight(CPointLights::LIGHT_POINT,
- pos, CVector(0.0f, 0.0f, 0.0f),
- effect->light.range,
- effect->col.r*CTimeCycle::GetSpriteBrightness()/255.0f,
- effect->col.g*CTimeCycle::GetSpriteBrightness()/255.0f,
- effect->col.b*CTimeCycle::GetSpriteBrightness()/255.0f,
- // half-useless because LIGHTFLAG_FOG_ALWAYS can't be on
- (effect->light.flags & LIGHTFLAG_FOG) >> 1,
- true);
+ if(!alreadyProcessedFog){
+ if(effect->light.flags & LIGHTFLAG_FOG_ALWAYS){
+ CPointLights::AddLight(CPointLights::LIGHT_FOGONLY_ALWAYS,
+ pos, CVector(0.0f, 0.0f, 0.0f),
+ 0.0f,
+ effect->col.r/255.0f, effect->col.g/255.0f, effect->col.b/255.0f,
+ CPointLights::FOG_ALWAYS, true);
+ }else if(effect->light.flags & LIGHTFLAG_FOG_NORMAL && lightOn && effect->light.range == 0.0f){
+ CPointLights::AddLight(CPointLights::LIGHT_FOGONLY,
+ pos, CVector(0.0f, 0.0f, 0.0f),
+ 0.0f,
+ effect->col.r/255.0f, effect->col.g/255.0f, effect->col.b/255.0f,
+ CPointLights::FOG_NORMAL, true);
+ }
}
- }
- // Light shadow
- if(effect->light.shadowRange != 0.0f){
- if(lightOn){
- CShadows::StoreStaticShadow((uintptr)this + i, SHADOWTYPE_ADDITIVE,
- effect->light.shadow, &pos,
- effect->light.shadowRange, 0.0f,
- 0.0f, -effect->light.shadowRange,
- 128,
- effect->col.r*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f,
- effect->col.g*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f,
- effect->col.b*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f,
- 15.0f, 1.0f, 40.0f, false, 0.0f);
- }else if(lightFlickering){
- CShadows::StoreStaticShadow((uintptr)this + i, SHADOWTYPE_ADDITIVE,
- effect->light.shadow, &pos,
- effect->light.shadowRange, 0.0f,
- 0.0f, -effect->light.shadowRange,
- 0, 0.0f, 0.0f, 0.0f,
- 15.0f, 1.0f, 40.0f, false, 0.0f);
+ // Light shadow
+ if(effect->light.shadowRange != 0.0f){
+ if(lightOn){
+ CShadows::StoreStaticShadow((uintptr)this + i, SHADOWTYPE_ADDITIVE,
+ effect->light.shadow, &pos,
+ effect->light.shadowRange, 0.0f,
+ 0.0f, -effect->light.shadowRange,
+ 128,
+ effect->col.r*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f,
+ effect->col.g*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f,
+ effect->col.b*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f,
+ 15.0f, 1.0f, 40.0f, false, 0.0f);
+ }else if(lightFlickering){
+ CShadows::StoreStaticShadow((uintptr)this + i, SHADOWTYPE_ADDITIVE,
+ effect->light.shadow, &pos,
+ effect->light.shadowRange, 0.0f,
+ 0.0f, -effect->light.shadowRange,
+ 0, 0.0f, 0.0f, 0.0f,
+ 15.0f, 1.0f, 40.0f, false, 0.0f);
+ }
+ }
+ break;
+
+ case EFFECT_SUNGLARE:
+ if(CWeather::SunGlare >= 0.0f){
+ CVector pos = GetMatrix() * effect->pos;
+ CVector glareDir = pos - GetPosition();
+ glareDir.Normalise();
+ CVector camDir = TheCamera.GetPosition() - pos;
+ float dist = camDir.Magnitude();
+ camDir *= 2.0f/dist;
+ glareDir += camDir;
+ glareDir.Normalise();
+ float camAngle = -DotProduct(glareDir, CTimeCycle::GetSunDirection());
+ if(camAngle > 0.0f){
+ float intens = Sqrt(camAngle) * CWeather::SunGlare;
+ pos += camDir;
+ CCoronas::RegisterCorona((uintptr)this + 33 + i,
+ intens * (CTimeCycle::GetSunCoreRed() + 2*255)/3.0f,
+ intens * (CTimeCycle::GetSunCoreGreen() + 2*255)/3.0f,
+ intens * (CTimeCycle::GetSunCoreBlue() + 2*255)/3.0f,
+ 255,
+ pos, 0.5f*CWeather::SunGlare*Sqrt(dist), 120.0f,
+ CCoronas::TYPE_STAR, CCoronas::FLARE_NONE,
+ CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF,
+ CCoronas::STREAK_OFF, 0.0f);
+ }
}
+ break;
}
}
}
@@ -849,27 +948,31 @@ CEntity::ModifyMatrixForTreeInWind(void)
CMatrix mat(GetMatrix().m_attachment);
if(CWeather::Wind >= 0.5){
- t = m_randomSeed + 16*CTimer::GetTimeInMilliseconds();
+ t = m_randomSeed + 8*CTimer::GetTimeInMilliseconds();
f = (t & 0xFFF)/(float)0x1000;
flutter = f * WindTabel[(t>>12)+1 & 0xF] +
(1.0f - f) * WindTabel[(t>>12) & 0xF] +
1.0f;
- strength = CWeather::Wind < 0.8f ? 0.008f : 0.014f;
+ strength = -0.015f*CWeather::Wind;
}else if(CWeather::Wind >= 0.2){
t = (uintptr)this + CTimer::GetTimeInMilliseconds();
f = (t & 0xFFF)/(float)0x1000;
flutter = Sin(f * 6.28f);
- strength = 0.008f;
+ strength = -0.008f;
}else{
t = (uintptr)this + CTimer::GetTimeInMilliseconds();
f = (t & 0xFFF)/(float)0x1000;
flutter = Sin(f * 6.28f);
- strength = 0.005f;
+ strength = -0.005f;
}
mat.GetUp().x = strength * flutter;
+ if(IsPalmTreeModel(GetModelIndex()))
+ mat.GetUp().x += -0.07f*CWeather::Wind;
mat.GetUp().y = mat.GetUp().x;
+ CWindModifiers::FindWindModifier(GetPosition(), &mat.GetUp().x, &mat.GetUp().y);
+
mat.UpdateRW();
UpdateRwFrame();
}
@@ -881,6 +984,7 @@ float BannerWindTabel[] = {
0.28f, 0.28f, 0.22f, 0.1f, 0.0f, -0.1f, -0.17f, -0.12f
};
+//--MIAMI: unused
void
CEntity::ModifyMatrixForBannerInWind(void)
{
@@ -928,7 +1032,6 @@ CEntity::AddSteamsFromGround(CPtrList& list)
}
#ifdef COMPATIBLE_SAVES
-// TODO(MIAMI)
void
CEntity::SaveEntityFlags(uint8*& buf)
{
@@ -952,35 +1055,41 @@ CEntity::SaveEntityFlags(uint8*& buf)
if (bRenderScorched) tmp |= BIT(20);
if (bHasBlip) tmp |= BIT(21);
if (bIsBIGBuilding) tmp |= BIT(22);
- if (bRenderDamaged) tmp |= BIT(23);
+ if (bStreamBIGBuilding) tmp |= BIT(23);
- if (bBulletProof) tmp |= BIT(24);
- if (bFireProof) tmp |= BIT(25);
- if (bCollisionProof) tmp |= BIT(26);
- if (bMeleeProof) tmp |= BIT(27);
- if (bOnlyDamagedByPlayer) tmp |= BIT(28);
- if (bStreamingDontDelete) tmp |= BIT(29);
- if (bRemoveFromWorld) tmp |= BIT(0);
- if (bHasHitWall) tmp |= BIT(1);
+ if (bRenderDamaged) tmp |= BIT(24);
+ if (bBulletProof) tmp |= BIT(25);
+ if (bFireProof) tmp |= BIT(26);
+ if (bCollisionProof) tmp |= BIT(27);
+ if (bMeleeProof) tmp |= BIT(28);
+ if (bOnlyDamagedByPlayer) tmp |= BIT(29);
+ if (bStreamingDontDelete) tmp |= BIT(30);
+ if (bRemoveFromWorld) tmp |= BIT(31);
WriteSaveBuf<uint32>(buf, tmp);
tmp = 0;
- if (bImBeingRendered) tmp |= BIT(2);
- if (bTouchingWater) tmp |= BIT(3);
- if (bIsSubway) tmp |= BIT(4);
- if (bDrawLast) tmp |= BIT(5);
- if (bNoBrightHeadLights) tmp |= BIT(6);
- if (bDoNotRender) tmp |= BIT(7);
- if (bDistanceFade) tmp |= BIT(8);
+ if (bHasHitWall) tmp |= BIT(0);
+ if (bImBeingRendered) tmp |= BIT(1);
+ if (bTouchingWater) tmp |= BIT(2);
+ if (bIsSubway) tmp |= BIT(3);
+ if (bDrawLast) tmp |= BIT(4);
+ if (bNoBrightHeadLights) tmp |= BIT(5);
+ if (bDoNotRender) tmp |= BIT(6);
+ if (bDistanceFade) tmp |= BIT(7);
+ if (m_flagE1) tmp |= BIT(8);
if (m_flagE2) tmp |= BIT(9);
+ if (bOffscreen) tmp |= BIT(10);
+ if (bIsStaticWaitingForCollision) tmp |= BIT(11);
+ if (m_flagE10) tmp |= BIT(12);
+ if (bUnderwater) tmp |= BIT(13);
+ if (bHasPreRenderEffects) tmp |= BIT(14);
WriteSaveBuf<uint32>(buf, tmp);
}
-// TODO(MIAMI)
void
CEntity::LoadEntityFlags(uint8*& buf)
{
@@ -1004,28 +1113,50 @@ CEntity::LoadEntityFlags(uint8*& buf)
bRenderScorched = !!(tmp & BIT(20));
bHasBlip = !!(tmp & BIT(21));
bIsBIGBuilding = !!(tmp & BIT(22));
- bRenderDamaged = !!(tmp & BIT(23));
+ bStreamBIGBuilding = !!(tmp & BIT(23));
- bBulletProof = !!(tmp & BIT(24));
- bFireProof = !!(tmp & BIT(25));
- bCollisionProof = !!(tmp & BIT(26));
- bMeleeProof = !!(tmp & BIT(27));
- bOnlyDamagedByPlayer = !!(tmp & BIT(28));
- bStreamingDontDelete = !!(tmp & BIT(29));
- bRemoveFromWorld = !!(tmp & BIT(0));
- bHasHitWall = !!(tmp & BIT(1));
+ bRenderDamaged = !!(tmp & BIT(24));
+ bBulletProof = !!(tmp & BIT(25));
+ bFireProof = !!(tmp & BIT(26));
+ bCollisionProof = !!(tmp & BIT(27));
+ bMeleeProof = !!(tmp & BIT(28));
+ bOnlyDamagedByPlayer = !!(tmp & BIT(29));
+ bStreamingDontDelete = !!(tmp & BIT(30));
+ bRemoveFromWorld = !!(tmp & BIT(31));
tmp = ReadSaveBuf<uint32>(buf);
- bImBeingRendered = !!(tmp & BIT(2));
- bTouchingWater = !!(tmp & BIT(3));
- bIsSubway = !!(tmp & BIT(4));
- bDrawLast = !!(tmp & BIT(5));
- bNoBrightHeadLights = !!(tmp & BIT(6));
- bDoNotRender = !!(tmp & BIT(7));
- bDistanceFade = !!(tmp & BIT(8));
+ bHasHitWall = !!(tmp & BIT(0));
+ bImBeingRendered = !!(tmp & BIT(1));
+ bTouchingWater = !!(tmp & BIT(2));
+ bIsSubway = !!(tmp & BIT(3));
+ bDrawLast = !!(tmp & BIT(4));
+ bNoBrightHeadLights = !!(tmp & BIT(5));
+ bDoNotRender = !!(tmp & BIT(6));
+ bDistanceFade = !!(tmp & BIT(7));
+ m_flagE1 = !!(tmp & BIT(8));
m_flagE2 = !!(tmp & BIT(9));
+ bOffscreen = !!(tmp & BIT(10));
+ bIsStaticWaitingForCollision = !!(tmp & BIT(11));
+ m_flagE10 = !!(tmp & BIT(12));
+ bUnderwater = !!(tmp & BIT(13));
+ bHasPreRenderEffects = !!(tmp & BIT(14));
}
#endif
+
+bool IsEntityPointerValid(CEntity* pEntity)
+{
+ if (!pEntity)
+ return false;
+ switch (pEntity->GetType()) {
+ case ENTITY_TYPE_NOTHING: return false;
+ case ENTITY_TYPE_BUILDING: return IsBuildingPointerValid((CBuilding*)pEntity);
+ case ENTITY_TYPE_VEHICLE: return IsVehiclePointerValid((CVehicle*)pEntity);
+ case ENTITY_TYPE_PED: return IsPedPointerValid((CPed*)pEntity);
+ case ENTITY_TYPE_OBJECT: return IsObjectPointerValid((CObject*)pEntity);
+ case ENTITY_TYPE_DUMMY: return IsDummyPointerValid((CDummy*)pEntity);
+ }
+ return false;
+}
diff --git a/src/entities/Entity.h b/src/entities/Entity.h
index fa57519e..e7d402d0 100644
--- a/src/entities/Entity.h
+++ b/src/entities/Entity.h
@@ -30,6 +30,7 @@ enum eEntityStatus : uint8
STATUS_PLANE,
STATUS_PLAYER_REMOTE,
STATUS_PLAYER_DISABLED,
+ STATUS_12, // TODO: what is this? used in CPhysical::ApplyAirResistance
};
class CEntity : public CPlaceable
@@ -78,7 +79,7 @@ public:
uint32 bIsSubway : 1; // set when subway, but maybe different meaning?
uint32 bDrawLast : 1; // draw object last
uint32 bNoBrightHeadLights : 1;
- uint32 bDoNotRender : 1;
+ uint32 bDoNotRender : 1; //-- only applies to CObjects apparently
uint32 bDistanceFade : 1; // Fade entity because it is far away
// flagsE
@@ -88,7 +89,7 @@ public:
uint32 bIsStaticWaitingForCollision : 1; // this is used by script created entities - they are static until the collision is loaded below them
uint32 m_flagE10 : 1; // probably bDontStream
uint32 bUnderwater : 1; // this object is underwater change drawing order
- uint32 m_flagE40 : 1;
+ uint32 bHasPreRenderEffects : 1; // Object has a prerender effects attached to it
uint16 m_scanCode;
uint16 m_randomSeed;
@@ -112,12 +113,12 @@ public:
#endif
CEntity(void);
- ~CEntity(void);
+ virtual ~CEntity(void);
virtual void Add(void);
virtual void Remove(void);
- virtual void SetModelIndex(uint32 id) { m_modelIndex = id; CreateRwObject(); }
- virtual void SetModelIndexNoCreate(uint32 id) { m_modelIndex = id; }
+ virtual void SetModelIndex(uint32 id);
+ virtual void SetModelIndexNoCreate(uint32 id);
virtual void CreateRwObject(void);
virtual void DeleteRwObject(void);
virtual CRect GetBoundRect(void);
@@ -160,6 +161,7 @@ public:
int16 GetModelIndex(void) const { return m_modelIndex; }
void UpdateRwFrame(void);
void SetupBigBuilding(void);
+ bool HasPreRenderEffects(void);
void AttachToRwObject(RwObject *obj);
void DetachFromRwObject(void);
@@ -180,3 +182,5 @@ public:
static void AddSteamsFromGround(CPtrList& list);
};
+
+bool IsEntityPointerValid(CEntity*);
diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp
index 22b391e8..02feb5cb 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,11 @@
#include "CarCtrl.h"
#include "DMAudio.h"
#include "Automobile.h"
+#include "Pickups.h"
#include "Physical.h"
+//--MIAMI: file done except one bike thing
+
CPhysical::CPhysical(void)
{
int i;
@@ -37,6 +42,7 @@ CPhysical::CPhysical(void)
m_aCollisionRecords[i] = nil;
m_bIsVehicleBeingShifted = false;
+ bJustCheckCollision = false;
m_nDamagePieceType = 0;
m_fDamageImpulse = 0.0f;
@@ -45,25 +51,26 @@ CPhysical::CPhysical(void)
bUsesCollision = true;
m_audioEntityId = -5;
- unk1 = 100.0f;
+ m_phys_unused1 = 100.0f;
m_vecCentreOfMass = CVector(0.0f, 0.0f, 0.0f);
- field_EC = 0;
+ m_phys_unused2 = 0;
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;
m_nZoneLevel = LEVEL_NONE;
+
+ bIsFrozen = false;
+ bDontLoadCollision = false;
}
CPhysical::~CPhysical(void)
@@ -264,7 +271,6 @@ CPhysical::AddCollisionRecord(CEntity *ent)
}
}
-//--MIAMI: done
void
CPhysical::AddCollisionRecord_Treadable(CEntity *ent)
{
@@ -401,18 +407,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
@@ -456,6 +470,21 @@ 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;
+ ApplyMoveForce(forceDir*impulse);
+ ApplyTurnForce(forceDir*impulse, point);
+ }
+ return true;
+}
+
// What exactly is speed?
bool
CPhysical::ApplySpringDampening(float damping, CVector &springDir, CVector &point, CVector &speed)
@@ -464,6 +493,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);
@@ -497,9 +528,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_12){
+ 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;
@@ -507,7 +540,6 @@ CPhysical::ApplyAirResistance(void)
}
}
-
bool
CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, float &impulseB)
{
@@ -515,32 +547,38 @@ 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;
- float timestepA;
+ float massFactorA;
if(B->bPedPhysics){
- timestepA = 10.0f;
+ massFactorA = 10.0f;
if(B->IsPed() && ((CPed*)B)->m_pCurrentPhysSurface == A)
ispedcontactA = true;
}else
- timestepA = A->bIsHeavy ? 2.0f : 1.0f;
+ massFactorA = A->bIsHeavy ? 2.0f : 1.0f;
- float timestepB;
+ float massFactorB;
if(A->bPedPhysics){
if(A->IsPed() && ((CPed*)A)->IsPlayer() && B->IsVehicle() &&
(B->GetStatus() == STATUS_ABANDONED || B->GetStatus() == STATUS_WRECKED || A->bHasHitWall))
- timestepB = 2200.0f / B->m_fMass;
+ massFactorB = 1.0f/(Max(B->m_fMass - 2000.0f, 0.0f)/5000.0f + 1.0f);
else
- timestepB = 10.0f;
+ massFactorB = 10.0f;
if(A->IsPed() && ((CPed*)A)->m_pCurrentPhysSurface == B)
ispedcontactB = true;
}else
- timestepB = B->bIsHeavy ? 2.0f : 1.0f;
+ massFactorB = B->bIsHeavy ? 2.0f : 1.0f;
+
+ if(B->bInfiniteMass && !B->m_phy_flagA08){
+ ispedcontactB = false;
+ foo = true;
+ }
float speedA, speedB;
- if(B->IsStatic()){
+ if(B->IsStatic() && !foo){
if(A->bPedPhysics){
speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal);
if(speedA < 0.0f){
@@ -550,8 +588,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->bIsStatic = false;
+ CWorld::Players[CWorld::PlayerInFocus].m_nHavocLevel += 2;
+ CStats::PropertyDestroyed += CGeneral::GetRandomNumberInRange(30, 60);
+ }
}else{
if(IsGlass(B->GetModelIndex()))
CGlass::WindowRespondsToSoftCollision(B, impulseA);
@@ -603,6 +644,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{
@@ -625,7 +669,7 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl
if(B->IsStatic())
return false;
- if(!B->bInfiniteMass)
+ if(!B->bInfiniteMass && !B->m_phy_flagA08)
B->AddToMovingList();
}
@@ -635,16 +679,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 = Max(0.0f, DotProduct(B->m_vecMoveSpeed, colpoint.normal));
- // A has moved into B
- if(speedA < speedB){
- if(!A->bHasHitWall)
- speedB -= (speedA - speedB) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
- impulseA = (speedB-speedA) * A->m_fMass * timestepA;
+ 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) * mA;
if(!A->bInfiniteMass)
- A->ApplyMoveForce(colpoint.normal*(impulseA/timestepA));
+ 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){
@@ -652,9 +716,13 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl
speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal);
speedB = DotProduct(B->GetSpeed(pointposB), colpoint.normal);
- float a = A->m_fMass*timestepA;
- float b = B->GetMassTime(pointposB, colpoint.normal, timestepB);
- float speedSum = (b*speedB + a*speedA)/(a + b);
+ float mA = A->m_fMass*massFactorA;
+ float mB = B->GetMassTweak(pointposB, colpoint.normal, massFactorB);
+ float speedSum;
+ if(foo)
+ speedSum = speedB;
+ else
+ speedSum = (mB*speedB + mA*speedA)/(mA + mB);
if(speedA < speedSum){
if(A->bHasHitWall)
eA = speedSum;
@@ -664,10 +732,10 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl
eB = speedSum;
else
eB = speedSum - (speedB - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
- impulseA = (eA - speedA) * a;
- impulseB = -(eB - speedB) * b;
- CVector fA = colpoint.normal*(impulseA/timestepA);
- CVector fB = colpoint.normal*(-impulseB/timestepB);
+ impulseA = (eA - speedA) * mA;
+ impulseB = -(eB - speedB) * mB;
+ CVector fA = colpoint.normal*(impulseA/massFactorA);
+ CVector fB = colpoint.normal*(-impulseB/massFactorB);
if(!A->bInfiniteMass){
if(fA.z < 0.0f) fA.z = 0.0f;
if(ispedcontactB){
@@ -687,9 +755,9 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl
speedA = DotProduct(A->GetSpeed(pointposA), colpoint.normal);
speedB = DotProduct(B->m_vecMoveSpeed, colpoint.normal);
- float a = A->GetMassTime(pointposA, colpoint.normal, timestepA);
- float b = B->m_fMass*timestepB;
- float speedSum = (b*speedB + a*speedA)/(a + b);
+ float mA = A->GetMassTweak(pointposA, colpoint.normal, massFactorA);
+ float mB = B->m_fMass*massFactorB;
+ float speedSum = (mB*speedB + mA*speedA)/(mA + mB);
if(speedA < speedSum){
if(A->bHasHitWall)
eA = speedSum;
@@ -699,10 +767,10 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl
eB = speedSum;
else
eB = speedSum - (speedB - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
- impulseA = (eA - speedA) * a;
- impulseB = -(eB - speedB) * b;
- CVector fA = colpoint.normal*(impulseA/timestepA);
- CVector fB = colpoint.normal*(-impulseB/timestepB);
+ impulseA = (eA - speedA) * mA;
+ impulseB = -(eB - speedB) * mB;
+ CVector fA = colpoint.normal*(impulseA/massFactorA);
+ CVector fB = colpoint.normal*(-impulseB/massFactorB);
if(!A->bInfiniteMass && !ispedcontactA){
if(fA.z < 0.0f) fA.z = 0.0f;
A->ApplyMoveForce(fA);
@@ -727,9 +795,9 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl
CVector pointposB = colpoint.point - B->GetPosition();
speedA = DotProduct(A->GetSpeed(pointposA), colpoint.normal);
speedB = DotProduct(B->GetSpeed(pointposB), colpoint.normal);
- float a = A->GetMassTime(pointposA, colpoint.normal, timestepA);
- float b = B->GetMassTime(pointposB, colpoint.normal, timestepB);
- float speedSum = (b*speedB + a*speedA)/(a + b);
+ float mA = A->GetMassTweak(pointposA, colpoint.normal, massFactorA);
+ float mB = B->GetMassTweak(pointposB, colpoint.normal, massFactorB);
+ float speedSum = (mB*speedB + mA*speedA)/(mA + mB);
if(speedA < speedSum){
if(A->bHasHitWall)
eA = speedSum;
@@ -739,10 +807,10 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl
eB = speedSum;
else
eB = speedSum - (speedB - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
- impulseA = (eA - speedA) * a;
- impulseB = -(eB - speedB) * b;
- CVector fA = colpoint.normal*(impulseA/timestepA);
- CVector fB = colpoint.normal*(-impulseB/timestepB);
+ impulseA = (eA - speedA) * mA;
+ impulseB = -(eB - speedB) * mB;
+ CVector fA = colpoint.normal*(impulseA/massFactorA);
+ CVector fB = colpoint.normal*(-impulseB/massFactorB);
if(A->IsVehicle() && !A->bHasHitWall){
fA.x *= 1.4f;
fA.y *= 1.4f;
@@ -758,7 +826,7 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl
if(B->IsVehicle() && !B->bHasHitWall){
fB.x *= 1.4f;
fB.y *= 1.4f;
- if(colpoint.normal.z < 0.7f)
+ if(-colpoint.normal.z < 0.7f)
fB.z *= 0.3f;
if(B->GetStatus() == STATUS_PLAYER)
pointposB *= 0.8f;
@@ -785,13 +853,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){
@@ -804,28 +911,61 @@ CPhysical::ApplyCollisionAlt(CEntity *B, CColPoint &colpoint, float &impulse, CV
speed = GetSpeed(pointpos);
normalSpeed = DotProduct(speed, colpoint.normal);
if(normalSpeed < 0.0f){
- float minspeed = 0.0104f * CTimer::GetTimeStep();
-#ifdef GTA3_1_1_PATCH
- 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)
+ 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)
- e = -1.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
@@ -1006,7 +1146,7 @@ CPhysical::ApplyFriction(float adhesiveLimit, CColPoint &colpoint)
ApplyFrictionTurnForce(frictionDir*fImpulse, pointpos);
if(fOtherSpeed > 0.1f &&
- colpoint.surfaceB != SURFACE_2 && colpoint.surfaceB != SURFACE_4 &&
+ colpoint.surfaceB != SURFACE_GRASS && colpoint.surfaceB != SURFACE_MUD_DRY &&
CSurfaceTable::GetAdhesionGroup(colpoint.surfaceA) == ADHESIVE_HARD){
CVector v = frictionDir * fOtherSpeed * 0.25f;
for(int i = 0; i < 4; i++)
@@ -1055,7 +1195,7 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists)
canshift = true;
else
canshift = A->IsPed() &&
- B->IsObject() && B->bInfiniteMass && !Bobj->bHasBeenDamaged;
+ B->IsObject() && B->IsStatic() && !Bobj->bHasBeenDamaged;
if(B == A ||
B->m_scanCode == CWorld::GetCurrentScanCode() ||
!B->bUsesCollision ||
@@ -1067,15 +1207,14 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists)
if(B->IsBuilding())
skipShift = false;
- else if(IsTrafficLight(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 &&
- IsTrafficLight(B->GetModelIndex()))
+ IsLightWithoutShift(B->GetModelIndex()))
skipShift = true;
-// TODO: maybe flip some ifs here
else if(A->IsObject() && B->IsVehicle()){
CObject *Aobj = (CObject*)A;
if(Aobj->ObjectCreatedBy != TEMP_OBJECT &&
@@ -1194,6 +1333,9 @@ CPhysical::ProcessCollisionSectorList_SimpleCar(CPtrList *lists)
A = (CPhysical*)this;
+ if(!A->bUsesCollision)
+ return false;
+
radius = A->GetBoundRadius();
A->GetBoundCentre(center);
@@ -1212,6 +1354,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)){
@@ -1355,6 +1498,7 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists)
int numResponses;
int i, j;
bool skipCollision, altcollision;
+ bool ret = false;
float impulseA = -1.0f;
float impulseB = -1.0f;
@@ -1375,9 +1519,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)
@@ -1398,27 +1542,27 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists)
if(B->IsBuilding())
skipCollision = false;
- else if(IsTrafficLight(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 &&
- IsTrafficLight(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->IsStatic()){
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;
@@ -1430,14 +1574,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->IsStatic()){
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;
@@ -1447,14 +1591,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->b158_4)
A->bSkipLineCol = true;
}else if(B->IsPed() && Bped->m_pCollidingEntity == A){
skipCollision = true;
@@ -1469,7 +1615,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
@@ -1481,6 +1631,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++){
@@ -1488,20 +1639,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);
+
+ 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();
+
+ 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));
- 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;
+ }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();
+ 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));
+ DMAudio.ReportCollision(A, B, aColPoints[i].surfaceA, aColPoints[i].surfaceB, impulseA, Max(turnSpeedDiff, moveSpeedDiff));
+ }
}
}else{
for(i = 0; i < numCollisions; i++){
@@ -1509,39 +1675,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;
-// TODO(MIAMI): check this
- else if(A->IsVehicle() && ((CVehicle*)A)->IsBoat()){
- 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]))
@@ -1560,7 +1739,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{
@@ -1691,18 +1876,34 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists)
}
if(B->IsPed() && A->IsVehicle() &&
- (!Bped->IsPlayer() || B->bHasHitWall && A->m_vecMoveSpeed.MagnitudeSqr() > 0.0025f))
+ (!Bped->IsPlayer() || B->bHasHitWall && A->m_vecMoveSpeed.MagnitudeSqr() > SQR(0.05f)))
Bped->KillPedWithCar((CVehicle*)A, maxImpulseB);
else if(B->GetModelIndex() == MI_TRAIN && A->IsPed() &&
(!Aped->IsPlayer() || A->bHasHitWall))
Aped->KillPedWithCar((CVehicle*)B, maxImpulseA*2.0f);
else if(B->IsObject() && B->bUsesCollision && A->IsVehicle()){
+ // 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()){
- // BUG? not impulseA?
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){
@@ -1711,13 +1912,15 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists)
CCarCtrl::SwitchVehicleToRealPhysics((CVehicle*)B);
}
- return true;
+ if(!CWorld::bSecondShift)
+ return true;
+ ret = true;
}
}
}
- return false;
+ return ret;
}
bool
@@ -1746,6 +1949,8 @@ CPhysical::CheckCollision_SimpleCar(void)
return false;
}
+float PHYSICAL_SHIFT_SPEED_DAMP = 0.707f;
+
void
CPhysical::ProcessShift(void)
{
@@ -1755,6 +1960,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();
@@ -1766,17 +1978,25 @@ CPhysical::ProcessShift(void)
m_bIsVehicleBeingShifted = true;
CEntryInfoNode *node;
- bool hasshifted = false; // whatever that means...
+ bool hasshifted = false;
for(node = m_entryInfoList.first; node; node = node->next)
hasshifted |= ProcessShiftSectorList(node->sector->m_lists);
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;
@@ -1788,6 +2008,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)
{
@@ -1819,31 +2042,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 = GetDistanceSq();
+ 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);
@@ -1883,6 +2153,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 &&
@@ -1900,7 +2171,7 @@ 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");
+ assert(0 && "TODO(MIAMI)");
}
}
}
@@ -1913,11 +2184,14 @@ CPhysical::ProcessCollision(void)
if(!m_vecMoveSpeed.IsZero() ||
!m_vecTurnSpeed.IsZero() ||
bHitByTrain ||
- GetStatus() == STATUS_PLAYER || IsPed() && ped->IsPlayer()){
+ GetStatus() == STATUS_PLAYER ||
+ IsVehicle() && ((CVehicle*)this)->bRestingOnPhysical ||
+ IsPed() && ped->IsPlayer()){
if(IsVehicle())
((CVehicle*)this)->bVehicleColProcessed = true;
if(CheckCollision()){
GetMatrix() = savedMatrix;
+ m_fElasticity = savedElasticity;
return;
}
}
@@ -1927,5 +2201,6 @@ CPhysical::ProcessCollision(void)
bIsStuck = false;
bIsInSafePosition = true;
+ m_fElasticity = savedElasticity;
RemoveAndAdd();
}
diff --git a/src/entities/Physical.h b/src/entities/Physical.h
index ce02e463..926b9762 100644
--- a/src/entities/Physical.h
+++ b/src/entities/Physical.h
@@ -18,8 +18,7 @@ public:
// The not properly indented fields haven't been checked properly yet
int32 m_audioEntityId;
- float unk1;
- CTreadable *m_treadable[2]; // car and ped
+ float m_phys_unused1;
uint32 m_nLastTimeCollided;
CVector m_vecMoveSpeed; // velocity
CVector m_vecTurnSpeed; // angular velocity
@@ -37,10 +36,9 @@ public:
CEntryInfoList m_entryInfoList;
CPtrNode *m_movingListNode;
- char field_EC;
+ int8 m_phys_unused2;
uint8 m_nStaticFrames;
uint8 m_nCollisionRecords;
- bool m_bIsVehicleBeingShifted;
CEntity *m_aCollisionRecords[PHYSICAL_MAX_COLLISIONRECORDS];
float m_fDistanceTravelled;
@@ -54,12 +52,17 @@ public:
uint8 bIsHeavy : 1;
uint8 bAffectedByGravity : 1;
uint8 bInfiniteMass : 1;
+ uint8 m_phy_flagA08 : 1;
uint8 bIsInWater : 1;
- uint8 m_phy_flagA10 : 1; // unused
uint8 m_phy_flagA20 : 1; // unused
uint8 bHitByTrain : 1;
uint8 bSkipLineCol : 1;
+ uint8 bIsFrozen : 1;
+ uint8 bDontLoadCollision : 1;
+ uint8 m_bIsVehicleBeingShifted : 1; // wrong name - also used on but never set for peds
+ uint8 bJustCheckCollision : 1; // just see if there is a collision
+
uint8 m_nSurfaceTouched;
int8 m_nZoneLevel;
@@ -86,7 +89,6 @@ public:
void RemoveRefsToEntity(CEntity *ent);
static void PlacePhysicalRelativeToOtherPhysical(CPhysical *other, CPhysical *phys, CVector localPos);
- float GetDistanceSq(void) { return m_vecMoveSpeed.MagnitudeSqr() * sq(CTimer::GetTimeStep()); }
// get speed of point p relative to entity center
CVector GetSpeed(const CVector &r);
CVector GetSpeed(void) { return GetSpeed(CVector(0.0f, 0.0f, 0.0f)); }
@@ -94,7 +96,7 @@ public:
return 1.0f / (CrossProduct(pos, dir).MagnitudeSqr()/m_fTurnMass +
1.0f/m_fMass);
}
- float GetMassTime(const CVector &pos, const CVector &dir, float t) {
+ float GetMassTweak(const CVector &pos, const CVector &dir, float t) {
return 1.0f / (CrossProduct(pos, dir).MagnitudeSqr()/(m_fTurnMass*t) +
1.0f/(m_fMass*t));
}
@@ -156,11 +158,13 @@ public:
void ApplyFrictionTurnForce(const CVector &j, const CVector &p) { ApplyFrictionTurnForce(j.x, j.y, j.z, p.x, p.y, p.z); }
// springRatio: 1.0 fully extended, 0.0 fully compressed
bool ApplySpringCollision(float springConst, CVector &springDir, CVector &point, float springRatio, float bias);
+ bool ApplySpringCollisionAlt(float springConst, CVector &springDir, CVector &point, float springRatio, float bias, CVector &forceDir);
bool ApplySpringDampening(float damping, CVector &springDir, CVector &point, CVector &speed);
void ApplyGravity(void);
void ApplyFriction(void);
void ApplyAirResistance(void);
bool ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, float &impulseB);
+ bool ApplyCollision(CColPoint &colpoint, float &impulse);
bool ApplyCollisionAlt(CEntity *B, CColPoint &colpoint, float &impulse, CVector &moveSpeed, CVector &turnSpeed);
bool ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint);
bool ApplyFriction(float adhesiveLimit, CColPoint &colpoint);