Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions MM2Hook.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,7 @@
<ClCompile Include="src\modules\effects.cpp" />
<ClCompile Include="src\modules\effects\birth.cpp" />
<ClCompile Include="src\modules\effects\damage.cpp" />
<ClCompile Include="src\modules\effects\damage3d.cpp" />
<ClCompile Include="src\modules\effects\ptx.cpp" />
<ClCompile Include="src\modules\effects\waterspout.cpp" />
<ClCompile Include="src\modules\gfx.cpp" />
Expand Down
2 changes: 2 additions & 0 deletions MM2Hook.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -2797,6 +2797,8 @@
<ClCompile Include="src\modules\node\dof.cpp">
<Filter>Source Files\modules\node</Filter>
</ClCompile>
<ClCompile Include="src\modules\effects\damage3d.cpp">
<Filter>Source Files\modules\effects</Filter>
<ClCompile Include="src\modules\vehicle\breakable.cpp">
<Filter>Source Files\modules\vehicle</Filter>
</ClCompile>
Expand Down
6 changes: 4 additions & 2 deletions mm2hook.ini
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ UseModsFolder=1 ; Enable use of the mods folder for overriding the
MaximumCopsLimit=3 ; Limits the number of cops pursuing the player. 3 = Default, 0 = Unlimited.
Ragdolls=1 ; Enable collision with pedestrians, with ragdoll physics like Midnight Club: Street Racing.
3DDamage=1 ; Enable 3D damage on supported mods like Midnight Club: Street Racing.
3DDynamicDamage=0 ; Enable switching 3D damage type from specific to dynamic on all vehicles when 3D damage is enabled.
3DShadows=0 ; Enable 3D shadows on player vehicles, opponent vehicles, traffic, and props
DynamicParkedCarDensity=1 ; Allows the traffic density slider to also control how many parked cars you see in Cruise mode. No traffic = no parked cars.
OpponentsUseAllColors=0 ; Allow opponents to use more than their default four colors
Expand All @@ -36,6 +37,9 @@ HornSirenThreshold=0.15 ; Threshold in seconds for how long the horn butto
ExplosionSound=1 ; Enables explosion sound effect for player's emergency vehicles if they're damaged out with activated siren, it also turns off the engine for all cars if they're destroyed.
ReflectionsOnBreakables=1 ; Enables reflections on breakable parts, such as mirrors.
ReflectionsOnCarParts=0 ; Enables reflections on car parts such as wheels and fenders. Note that addon cars will have shiny tires with this enabled if they are not set up correctly.
ReflectionsOnDamagedParts=0 ; Enables reflections on damaged parts of the vehicle when MM1 damage is enabled.
MM1StyleDamage=1 ; Modifies the way damage textures are applied to vehicles, in a way that resembles how Midtown Madness 1 did it.
MM1StyleFlipOver=0 ; Modifies the way the car flips over itself in a way that resembles how Midtown Madness 1 did it.
MM1StyleTransmission=0 ; Improves transmission physics with more realistic behavior.
MM1StyleAutoReverse=0 ; Improves auto reverse system with behavior resembling Midtown Madness 1.
EnableHudArrowStyles=1 ; Enables the unused alternative style hud arrows for Blitz and Crash Course game modes.
Expand All @@ -44,8 +48,6 @@ EscapeDeepWater=1 ; Enables a new check which allows you to continue
ResetToNearestLocation=0 ; Resets you to the nearest valid location if you fall into deep water.
PhysicalEngineDamage=0 ; Damage affects engine torque when the engine spews smoke and that means the vehicle will have less acceleration and less top speed.
EnableMouseBar=0 ; Enables showing up the mouse bar for all input devices, this style is similar to the steering bar in Gran Turismo games.
MM1StyleFlipOver=0 ; Modifies the way the car flips over itself in a way that resembles how Midtown Madness 1 did it.
MM1StyleDamage=1 ; Modifies the way damage textures are applied to vehicles, in a way that resembles how Midtown Madness 1 did it.
UseRichPresence=1 ; Broadcast your current game mode, city, and vehicle on your Discord profile.
EnableLua=1 ; Enable the Lua script system. Always disabled in multiplayer.

Expand Down
6 changes: 5 additions & 1 deletion src/handlers/feature_handlers/vehCarModelFeatureHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ using namespace MM2;
static ConfigValue<bool> cfgMm1StyleTransmission("MM1StyleTransmission", false);
static ConfigValue<bool> cfgMm1StyleDamage("MM1StyleDamage", true);
static ConfigValue<bool> cfgEnable3DDamage("3DDamage", true);
static ConfigValue<bool> cfgEnable3DDynamicDamage("3DDynamicDamage", false);
static ConfigValue<bool> cfgCarShadows("3DShadows", false);

/*
Expand Down Expand Up @@ -48,7 +49,7 @@ void vehCarModelFeatureHandler::ApplyImpact(vehDamageImpactInfo* a1)
auto damage3d = damage->GetCar()->GetModel()->GetDamage3D();
if (damage3d)
{
damage3d->Impact(a1->LocalPosition);
damage3d->Impact(a1->LocalPosition, vehCarModel::Enable3DDynamicDamage);
}

auto mm1Damage = damage->GetCar()->GetModel()->GetMM1Damage();
Expand Down Expand Up @@ -144,6 +145,7 @@ void vehCarModelFeatureHandler::Install() {

ConfigValue<bool> cfgEnableSpinningWheels("EnableSpinningWheels", true);
ConfigValue<bool> cfgPartReflections("ReflectionsOnCarParts", false);
ConfigValue<bool> cfgDamageReflections("ReflectionsOnDamagedParts", false);
ConfigValue<bool> cfgHeadlightFlashing("EnableHeadlightFlashing", true);
ConfigValue<bool> cfgNfsMwStyleTotaledCar("NFSMWStyleTotaledCar", false);
ConfigValue<bool> cfgBreakableRenderTweak("BreakableRenderTweak", false);
Expand All @@ -162,12 +164,14 @@ void vehCarModelFeatureHandler::Install() {

vehCarModel::PartReflections = cfgPartReflections.Get();
vehCarModel::WheelReflections = vehCarModel::PartReflections;
vehCarModel::DamageReflections = cfgDamageReflections.Get();

vehCarModel::mm1StyleTransmission = cfgMm1StyleTransmission.Get();
vehCarModel::mm1StyleDamage = cfgMm1StyleDamage.Get();
vehCarModel::breakableRenderTweak = cfgBreakableRenderTweak.Get();

vehCarModel::Enable3DDamage = cfgEnable3DDamage.Get();
vehCarModel::Enable3DDynamicDamage = cfgEnable3DDynamicDamage.Get();
vehCarModel::Enable3DShadows = cfgCarShadows.Get();
}

2 changes: 2 additions & 0 deletions src/mm2_vehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ bool vehCarModel::EnableHeadlightFlashing = true;
bool vehCarModel::MWStyleTotaledCar = false;
bool vehCarModel::PartReflections = false;
bool vehCarModel::WheelReflections = false;
bool vehCarModel::DamageReflections = false;
int vehCarModel::SirenType = 0;
int vehCarModel::HeadlightType = 0;
float vehCarModel::SirenCycle = 0.25f;
Expand All @@ -29,6 +30,7 @@ bool vehCarModel::mm1StyleDamage = true;
bool vehCarModel::breakableRenderTweak = false;

bool vehCarModel::Enable3DDamage = true;
bool vehCarModel::Enable3DDynamicDamage = false;
bool vehCarModel::Enable3DShadows = true;

/*
Expand Down
274 changes: 274 additions & 0 deletions src/modules/effects/damage3d.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
#include "damage3d.h"

namespace MM2
{
fxDamage3D::fxDamage3D()
{
m_DamageRadius = 0.25f;
}

fxDamage3D::~fxDamage3D()
{
delete[] m_VertDeformAmount;
delete[] m_PacketMatchesVertCount;

if (m_EnableMM1Damage)
delete[] m_VertDeformPosition;
}

void fxDamage3D::Init(modStatic* bodyModel, modStatic* damageModel, bool mm1Damage)
{
m_BodyModel = bodyModel;
m_DamageModel = damageModel;
m_DeformModel = bodyModel->Clone();
m_DeformDamageModel = bodyModel->Clone();

int bodyPacketCount = 0;
int bodyVertCount = 0;
for (int i = 0; i < bodyModel->GetPacketCount(); i++)
{
auto packet = bodyModel->GetPacket(i);
while (packet)
{
bodyVertCount += packet->GetAdjunctCount();
bodyPacketCount++;
packet = packet->GetNext();
}
}

m_VertDeformAmount = new float[bodyVertCount];
m_PacketMatchesVertCount = new bool[bodyPacketCount];

int currentPacket = 0;
for (int i = 0; i < bodyModel->GetPacketCount(); i++)
{
if (i >= damageModel->GetPacketCount()) break;

auto bodyPacket = bodyModel->GetPacket(i);
auto damagePacket = damageModel->GetPacket(i);

while (bodyPacket && damagePacket)
{
m_PacketMatchesVertCount[currentPacket] = (bodyPacket->GetAdjunctCount() == damagePacket->GetAdjunctCount());
bodyPacket = bodyPacket->GetNext();
damagePacket = damagePacket->GetNext();
currentPacket++;
}
}

m_EnableMM1Damage = mm1Damage;

if (mm1Damage)
{
m_VertDeformPosition = new Vector3[bodyVertCount];

int currentVertex = 0;
for (int i = 0; i < bodyModel->GetPacketCount(); i++)
{
auto bodyPacket = bodyModel->GetPacket(i);
while (bodyPacket)
{
bodyPacket->DoLock();

for (unsigned int j = 0; j < bodyPacket->GetAdjunctCount(); j++)
{
bodyPacket->GetPosition(m_VertDeformPosition[currentVertex], j);
currentVertex++;
}

bodyPacket->DoUnlock();
bodyPacket = bodyPacket->GetNext();
}
}
}

SetNoDamage();
}

void fxDamage3D::SetNoDamage()
{
int currentVertex = 0;

for (int i = 0; i < m_DeformModel->GetPacketCount(); i++)
{
if (i >= m_BodyModel->GetPacketCount()) break;

auto deformDamagePacket = m_DeformDamageModel->GetPacket(i);
auto deformPacket = m_DeformModel->GetPacket(i);
auto bodyPacket = m_BodyModel->GetPacket(i);

while (bodyPacket && deformPacket && deformDamagePacket)
{
bodyPacket->DoLock(); deformPacket->DoLock(); deformDamagePacket->DoLock();

for (unsigned int j = 0; j < bodyPacket->GetAdjunctCount() && j < deformPacket->GetAdjunctCount(); j++)
{
Vector3 position = Vector3::ORIGIN;
bodyPacket->GetPosition(position, j);
deformPacket->SetPosition(position, j);
deformDamagePacket->SetPosition(position, j);
m_VertDeformAmount[currentVertex] = 0.0f;
currentVertex++;
}

if (m_EnableMM1Damage)
{
for (unsigned int j = 0; j < deformPacket->GetTriangleCount() / 3; j++)
{
int tri[3];
bodyPacket->GetTri(tri, j);
deformPacket->SetTri(tri[0], tri[1], tri[2], j);
deformDamagePacket->SetTri(0, 0, 0, j);
}
}

bodyPacket->DoUnlock(); deformPacket->DoUnlock(); deformDamagePacket->DoUnlock();

bodyPacket = bodyPacket->GetNext();
deformPacket = deformPacket->GetNext();
deformDamagePacket = deformDamagePacket->GetNext();
}
}
}

void fxDamage3D::SetFullDamage()
{
int currentVertex = 0;

for (int i = 0; i < m_DeformModel->GetPacketCount(); i++)
{
if (i >= m_DamageModel->GetPacketCount()) break;

auto deformDamagePacket = m_DeformDamageModel->GetPacket(i);
auto deformPacket = m_DeformModel->GetPacket(i);
auto damagePacket = m_DamageModel->GetPacket(i);

while (damagePacket && deformPacket && deformDamagePacket)
{
damagePacket->DoLock(); deformPacket->DoLock(); deformDamagePacket->DoLock();

for (unsigned int j = 0; j < damagePacket->GetAdjunctCount() && j < deformPacket->GetAdjunctCount(); j++)
{
Vector3 position = Vector3::ORIGIN;
damagePacket->GetPosition(position, j);
deformPacket->SetPosition(position, j);
deformDamagePacket->SetPosition(position, j);
m_VertDeformAmount[currentVertex] = 1.0f;
currentVertex++;
}

if (m_EnableMM1Damage)
{
for (unsigned int j = 0; j < deformDamagePacket->GetTriangleCount() / 3; j++)
{
int tri[3];
damagePacket->GetTri(tri, j);
deformDamagePacket->SetTri(tri[0], tri[1], tri[2], j);
deformPacket->SetTri(0, 0, 0, j);
}
}

damagePacket->DoUnlock(); deformPacket->DoUnlock(); deformDamagePacket->DoUnlock();

damagePacket = damagePacket->GetNext();
deformPacket = deformPacket->GetNext();
deformDamagePacket = deformDamagePacket->GetNext();
}
}
}

void fxDamage3D::Impact(Vector3& localImpactPosition, bool dynamicDamage)
{
int currentVertex = 0;
int currentVertex2 = 0;
int currentPacket = 0;

for (int i = 0; i < m_DeformModel->GetPacketCount(); i++)
{
if (i >= m_DamageModel->GetPacketCount()) break;

auto deformDamagePacket = m_DeformDamageModel->GetPacket(i);
auto deformPacket = m_DeformModel->GetPacket(i);
auto damagePacket = m_DamageModel->GetPacket(i);
auto bodyPacket = m_DamageModel->GetPacket(i);

while (damagePacket && deformPacket && bodyPacket && deformDamagePacket)
{
if (m_PacketMatchesVertCount[currentPacket]) {
damagePacket->DoLock(); deformPacket->DoLock(); bodyPacket->DoLock(); deformDamagePacket->DoLock();

for (unsigned int j = 0; j < damagePacket->GetAdjunctCount() && j < deformPacket->GetAdjunctCount(); j++)
{
Vector3 position = Vector3::ORIGIN;
bodyPacket->GetPosition(position, j);

float squareDistance = (localImpactPosition - position).Mag2();
if (squareDistance < m_DamageRadius)
{
Vector3 fullDamagePosition = Vector3::ORIGIN;
Vector3 bodyModelPosition = Vector3::ORIGIN;

damagePacket->GetPosition(fullDamagePosition, j);
bodyPacket->GetPosition(bodyModelPosition, j);

float deformAmount = 1.0f - (squareDistance / m_DamageRadius);
if (deformAmount < m_VertDeformAmount[currentVertex])
{
deformAmount = m_VertDeformAmount[currentVertex];
}
if (!dynamicDamage)
m_VertDeformAmount[currentVertex] = deformAmount;

Vector3 deformedPosition = Vector3::ORIGIN;
dynamicDamage ?
deformedPosition.Lerp(deformAmount, bodyModelPosition, fullDamagePosition - localImpactPosition * 0.1f) :
deformedPosition.Lerp(deformAmount, bodyModelPosition, fullDamagePosition);
deformPacket->SetPosition(deformedPosition, j);
deformDamagePacket->SetPosition(deformedPosition, j);

currentVertex++;
}
}

if (m_EnableMM1Damage)
{
for (unsigned int j = 0; j < deformDamagePacket->GetTriangleCount() / 3; j++)
{
int tri[3];
bodyPacket->GetTri(tri, j);

float dist0 = (m_VertDeformPosition[currentVertex2 + tri[0]] - localImpactPosition).Mag2();
float dist1 = (m_VertDeformPosition[currentVertex2 + tri[1]] - localImpactPosition).Mag2();
float dist2 = (m_VertDeformPosition[currentVertex2 + tri[2]] - localImpactPosition).Mag2();

if (dist0 < m_DamageRadius || dist1 < m_DamageRadius || dist2 < m_DamageRadius)
{
deformDamagePacket->SetTri(tri[0], tri[1], tri[2], j);
deformPacket->SetTri(0, 0, 0, j);
}
}
}

damagePacket->DoUnlock(); deformPacket->DoUnlock(); bodyPacket->DoUnlock(); deformDamagePacket->DoUnlock();
}
currentVertex2 += deformDamagePacket->GetAdjunctCount();

damagePacket = damagePacket->GetNext();
deformPacket = deformPacket->GetNext();
bodyPacket = bodyPacket->GetNext();
deformDamagePacket = deformDamagePacket->GetNext();
currentPacket++;
}
}
}

modStatic* fxDamage3D::GetDeformModel()
{
return m_DeformModel;
}

modStatic* fxDamage3D::GetDeformDamageModel()
{
return m_DeformDamageModel;
}
}
Loading
Loading