diff --git a/codxe.vcxproj b/codxe.vcxproj
index 01a54a1..08e2351 100644
--- a/codxe.vcxproj
+++ b/codxe.vcxproj
@@ -80,9 +80,13 @@
+
+
+
+
@@ -148,7 +152,7 @@
-
+
@@ -184,11 +188,15 @@
+
+
+
+
diff --git a/src/game/iw2/mp/components/project_velocity.cpp b/src/game/iw2/mp/components/project_velocity.cpp
new file mode 100644
index 0000000..766046d
--- /dev/null
+++ b/src/game/iw2/mp/components/project_velocity.cpp
@@ -0,0 +1,97 @@
+#include "pch.h"
+#include "project_velocity.h"
+#include
+
+namespace iw2 {
+namespace mp {
+
+// Global detour object
+Detour PM_ProjectVelocity_Detour;
+
+const uint32_t NOP_INST = 0x60000000;
+
+// The Hook function that the Detour will point to
+void PM_ProjectVelocity_Hook(vec3_t in, vec3_t normal, vec3_t out)
+{
+ const float EPSILON = 0.001f;
+ float normalZ = normal[2];
+ float speedXY = (in[0] * in[0]) + (in[1] * in[1]);
+
+ if (normalZ < EPSILON || speedXY <= 0.0f) {
+ out[0] = in[0]; out[1] = in[1]; out[2] = in[2];
+ return;
+ }
+
+ float dotNormalXY = (in[0] * normal[0]) + (in[1] * normal[1]);
+ float projRatio = -dotNormalXY / normalZ;
+ float projSq = (in[2] * in[2]) + speedXY;
+ float divisor = speedXY + (projRatio * projRatio);
+
+ if (divisor > 0.0f) {
+ float scale = sqrtf(projSq / divisor);
+ // FIXED: Added logical OR operators
+ if (scale < 1.0f || projRatio < 0.0f || in[2] > 0.0f) {
+ out[0] = in[0] * scale;
+ out[1] = in[1] * scale;
+ out[2] = projRatio * scale;
+ return;
+ }
+ }
+
+ out[0] = in[0]; out[1] = in[1]; out[2] = in[2];
+}
+
+// Simple helper to build the branch-link (bl) instruction
+static uint32_t make_bl(uint32_t current, uint32_t target) {
+ uint32_t li = (target - current) & 0x03FFFFFC;
+ return (18u << 26) | li | 1u;
+}
+
+// Simple helper to build the unconditional branch (b) instruction
+static uint32_t make_b(uint32_t current, uint32_t target) {
+ uint32_t li = (target - current) & 0x03FFFFFC;
+ return (18u << 26) | li;
+}
+
+void project_velocity::install_patch() {
+ // 1. NOP out the original call to the dummy function
+ *(volatile uint32_t*)PV_Config::CallToDummyAddr = NOP_INST;
+
+ // 2. Initialize the Detour on the DummyAddr
+ // This redirects any call to DummyAddr to our PM_ProjectVelocity_Hook
+ PM_ProjectVelocity_Detour = Detour(reinterpret_cast(PV_Config::DummyAddr), reinterpret_cast(PM_ProjectVelocity_Hook));
+ PM_ProjectVelocity_Detour.Install();
+
+ // 3. Write the inline argument setup and call at PatchAddr
+ volatile uint32_t* patch = (volatile uint32_t*)PV_Config::PatchAddr;
+
+ // Setup Arguments
+ patch[0] = 0x7FE3FB78; // mr r3, r31
+ patch[1] = 0x388100A4; // addi r4, r1, 0xA4
+ patch[2] = 0x7FE5FB78; // mr r5, r31
+
+ // Call the hooked DummyAddr (where our Detour is waiting)
+ uint32_t blAddr = PV_Config::PatchAddr + (3 * 4);
+ patch[3] = make_bl(blAddr, PV_Config::DummyAddr);
+
+ // Jump past the rest of the original logic (18 instructions total)
+ uint32_t bAddr = PV_Config::PatchAddr + (4 * 4);
+ uint32_t targetAddr = PV_Config::PatchAddr + (18 * 4);
+ patch[4] = make_b(bAddr, targetAddr);
+
+ // Clear the remaining original instructions
+ for (int i = 5; i < 18; i++) {
+ patch[i] = NOP_INST;
+ }
+}
+
+project_velocity::project_velocity() {
+ install_patch();
+}
+
+project_velocity::~project_velocity() {
+ PM_ProjectVelocity_Detour.Remove();
+}
+
+} // namespace mp
+} // namespace iw2
\ No newline at end of file
diff --git a/src/game/iw2/mp/components/project_velocity.h b/src/game/iw2/mp/components/project_velocity.h
new file mode 100644
index 0000000..15c7274
--- /dev/null
+++ b/src/game/iw2/mp/components/project_velocity.h
@@ -0,0 +1,31 @@
+#pragma once
+#include "pch.h"
+
+namespace iw2 {
+namespace mp {
+
+ typedef float vec_t;
+ typedef vec_t vec3_t[3];
+
+ namespace PV_Config {
+ static const uint32_t PatchAddr = 0x8248B178; // Location where we should call our dummy function
+ static const uint32_t DummyAddr = 0x824550B8; // In COD2 there is no call to clip_velocity so we will use a dummy function address (and hook to it)
+ static const uint32_t CallToDummyAddr = 0x82455F74; // Location of calls to unused function
+ }
+ typedef float vec3_t[3];
+ // Forward declaration using float* to avoid array-size decay errors
+ void PM_ProjectVelocity_Hook(vec3_t in, vec3_t normal, vec3_t out);
+
+ class project_velocity : public Module {
+ public:
+ project_velocity();
+ virtual ~project_velocity();
+
+ private:
+ void install_patch();
+ project_velocity(const project_velocity&);
+ project_velocity& operator=(const project_velocity&);
+ };
+
+} // namespace mp
+} // namespace iw2
\ No newline at end of file
diff --git a/src/game/iw2/mp/main.cpp b/src/game/iw2/mp/main.cpp
index 827f597..89a8b2f 100644
--- a/src/game/iw2/mp/main.cpp
+++ b/src/game/iw2/mp/main.cpp
@@ -1,6 +1,7 @@
#include "pch.h"
#include "components/g_scr_main.h"
#include "components/scr_parser.h"
+#include "components/project_velocity.h"
#include "main.h"
namespace iw2
@@ -14,6 +15,7 @@ IW2_MP_Plugin::IW2_MP_Plugin()
RegisterModule(new Config());
RegisterModule(new g_scr_main());
RegisterModule(new scr_parser());
+ RegisterModule(new project_velocity());
}
IW2_MP_Plugin::~IW2_MP_Plugin()
diff --git a/src/game/ngl/mp/components/project_velocity.cpp b/src/game/ngl/mp/components/project_velocity.cpp
new file mode 100644
index 0000000..5439219
--- /dev/null
+++ b/src/game/ngl/mp/components/project_velocity.cpp
@@ -0,0 +1,80 @@
+#include "pch.h"
+#include "project_velocity.h"
+#include
+
+namespace ngl {
+namespace mp {
+
+// Global detour object
+Detour PM_ProjectVelocity_Detour;
+
+const uint32_t NOP_INST = 0x60000000;
+
+// The Hook function that the Detour will point to
+void PM_ProjectVelocity_Hook(vec3_t in, vec3_t normal, vec3_t out)
+{
+ const float EPSILON = 0.001f;
+ float normalZ = normal[2];
+ float speedXY = (in[0] * in[0]) + (in[1] * in[1]);
+
+ if (normalZ < EPSILON || speedXY <= 0.0f) {
+ out[0] = in[0]; out[1] = in[1]; out[2] = in[2];
+ return;
+ }
+
+ float dotNormalXY = (in[0] * normal[0]) + (in[1] * normal[1]);
+ float projRatio = -dotNormalXY / normalZ;
+ float projSq = (in[2] * in[2]) + speedXY;
+ float divisor = speedXY + (projRatio * projRatio);
+
+ if (divisor > 0.0f) {
+ float scale = sqrtf(projSq / divisor);
+ // FIXED: Added logical OR operators
+ if (scale < 1.0f || projRatio < 0.0f || in[2] > 0.0f) {
+ out[0] = in[0] * scale;
+ out[1] = in[1] * scale;
+ out[2] = projRatio * scale;
+ return;
+ }
+ }
+
+ out[0] = in[0]; out[1] = in[1]; out[2] = in[2];
+}
+
+// Simple helper to build the branch-link (bl) instruction
+static uint32_t make_bl(uint32_t current, uint32_t target) {
+ uint32_t li = (target - current) & 0x03FFFFFC;
+ return (18u << 26) | li | 1u;
+}
+
+// Simple helper to build the unconditional branch (b) instruction
+//static uint32_t make_b(uint32_t current, uint32_t target) {
+// uint32_t li = (target - current) & 0x03FFFFFC;
+// return (18u << 26) | li;
+//}
+
+void project_velocity::install_patch() {
+ // 1. NOP out the original call to the dummy function
+ *(volatile uint32_t*)PV_Config::CallToDummyAddr = NOP_INST;
+
+ // 2. Initialize the Detour on the DummyAddr
+ // This redirects any call to DummyAddr to our PM_ProjectVelocity_Hook
+ PM_ProjectVelocity_Detour = Detour(reinterpret_cast(PV_Config::DummyAddr), reinterpret_cast(PM_ProjectVelocity_Hook));
+ PM_ProjectVelocity_Detour.Install();
+
+ // 3. Write the inline argument setup and call at PatchAddr
+ volatile uint32_t* patch = (volatile uint32_t*)PV_Config::PatchAddr;
+
+ patch[0] = make_bl(PV_Config::PatchAddr, PV_Config::DummyAddr);
+}
+
+project_velocity::project_velocity() {
+ install_patch();
+}
+
+project_velocity::~project_velocity() {
+ PM_ProjectVelocity_Detour.Remove();
+}
+
+} // namespace mp
+} // namespace ngl
\ No newline at end of file
diff --git a/src/game/ngl/mp/components/project_velocity.h b/src/game/ngl/mp/components/project_velocity.h
new file mode 100644
index 0000000..94e8fdf
--- /dev/null
+++ b/src/game/ngl/mp/components/project_velocity.h
@@ -0,0 +1,31 @@
+#pragma once
+#include "pch.h"
+
+namespace ngl {
+namespace mp {
+
+ typedef float vec_t;
+ typedef vec_t vec3_t[3];
+
+ namespace PV_Config {
+ static const uint32_t PatchAddr = 0x8246E1E0; // Location where we should call our dummy function
+ static const uint32_t DummyAddr = 0x8244C1C8; // In COD2 there is no call to clip_velocity so we will use a dummy function address (and hook to it)
+ static const uint32_t CallToDummyAddr = 0x82466704; // Location of calls to unused function
+ }
+ typedef float vec3_t[3];
+ // Forward declaration using float* to avoid array-size decay errors
+ void PM_ProjectVelocity_Hook(vec3_t in, vec3_t normal, vec3_t out);
+
+ class project_velocity : public Module {
+ public:
+ project_velocity();
+ virtual ~project_velocity();
+
+ private:
+ void install_patch();
+ project_velocity(const project_velocity&);
+ project_velocity& operator=(const project_velocity&);
+ };
+
+} // namespace mp
+} // namespace ngl
\ No newline at end of file
diff --git a/src/game/ngl/mp/main.cpp b/src/game/ngl/mp/main.cpp
new file mode 100644
index 0000000..25fbf3b
--- /dev/null
+++ b/src/game/ngl/mp/main.cpp
@@ -0,0 +1,24 @@
+#include "pch.h"
+#include "main.h"
+#include "components/project_velocity.h"
+
+namespace ngl
+{
+namespace mp
+{
+
+NGL_MP_Plugin::NGL_MP_Plugin()
+{
+ DbgPrint("NGL MP Plugin initialized\n");
+
+ //install_patch();
+ RegisterModule(new project_velocity());
+}
+
+NGL_MP_Plugin::~NGL_MP_Plugin()
+{
+ DbgPrint("NGL MP Plugin shutting down\n");
+}
+
+} // namespace mp
+} // namespace ngl
\ No newline at end of file
diff --git a/src/game/ngl/mp/main.h b/src/game/ngl/mp/main.h
new file mode 100644
index 0000000..dbab00c
--- /dev/null
+++ b/src/game/ngl/mp/main.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "plugin.h"
+
+namespace ngl
+{
+namespace mp
+{
+class NGL_MP_Plugin : public Plugin
+{
+
+ public:
+ NGL_MP_Plugin();
+ ~NGL_MP_Plugin();
+};
+} // namespace mp
+} // namespace ngl
diff --git a/src/pch.h b/src/pch.h
index c420dc1..f07dab0 100644
--- a/src/pch.h
+++ b/src/pch.h
@@ -44,6 +44,8 @@
#include "common/branding.h"
#include "common/config.h"
+#include "game/ngl/mp/main.h"
+
// IW2-specific includes
#include "game/iw2/sp/main.h"
#include "game/iw2/sp/structs.h"
diff --git a/src/plugin_manager.cpp b/src/plugin_manager.cpp
index 49123da..caa49db 100644
--- a/src/plugin_manager.cpp
+++ b/src/plugin_manager.cpp
@@ -146,6 +146,14 @@ const GameInfo GAME_INFO[] = {
"Call of Duty: Modern Warfare 3 MP Title Update #24",
&CreatePlugin,
},
+ {
+ 0x415607E1,
+ 0x45B56A5C,// Mon Jan 22 20 : 52 : 28 2007
+ "codmp_xenonf.xex",
+ "NGL MP TU3",
+ "Call of Duty: 3 Title Update #3",
+ &CreatePlugin,
+ },
};
const GameInfo *FindGameInfo(DWORD title_id, DWORD timestamp)
diff --git a/src/version.h b/src/version.h
index 2078852..2e59f06 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1,4 +1,4 @@
// Auto-generated version header
#pragma once
-#define BUILD_NUMBER 0
+#define BUILD_NUMBER 249