2019-10-26 22:57:33 +02:00
|
|
|
/*This file is part of FFB Arcade Plugin.
|
|
|
|
FFB Arcade Plugin is free software : you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
FFB Arcade Plugin is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with FFB Arcade Plugin.If not, see < https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include "HOTD4.h"
|
|
|
|
#include "SDL.h"
|
|
|
|
#include <Windows.h>
|
2019-10-30 07:45:24 +01:00
|
|
|
static wchar_t* settingsFilename = TEXT(".\\FFBPlugin.ini");
|
2019-10-26 22:57:33 +02:00
|
|
|
extern int joystick_index1;
|
|
|
|
extern int joystick_index2;
|
|
|
|
extern SDL_Joystick* GameController2;
|
|
|
|
extern SDL_Haptic* ControllerHaptic2;
|
|
|
|
extern SDL_Haptic* haptic2;
|
|
|
|
static EffectTriggers *myTriggers;
|
|
|
|
static EffectConstants *myConstants;
|
|
|
|
static Helpers *myHelpers;
|
2019-10-27 03:03:02 +01:00
|
|
|
extern HINSTANCE gl_cgGLDll;
|
2019-10-27 08:21:57 +01:00
|
|
|
static bool HealthA = false;
|
|
|
|
static bool HealthB = false;
|
2019-11-08 19:17:51 +01:00
|
|
|
static bool init = false;
|
2019-10-27 00:43:00 +02:00
|
|
|
SDL_Event e;
|
2019-10-26 22:57:33 +02:00
|
|
|
|
2019-12-18 01:41:02 +01:00
|
|
|
static int ThreadLoop()
|
2019-10-26 22:57:33 +02:00
|
|
|
{
|
2019-12-18 01:41:02 +01:00
|
|
|
INT_PTR Base1p = myHelpers->ReadIntPtr((INT_PTR)gl_cgGLDll + 0x9164, false);
|
|
|
|
INT_PTR Base11p = myHelpers->ReadIntPtr(Base1p + 0x11C, false);
|
|
|
|
INT_PTR Base21p = myHelpers->ReadIntPtr(Base11p + 0x50, false);
|
|
|
|
INT_PTR Base31p = myHelpers->ReadIntPtr(Base21p + 0x20, false);
|
|
|
|
UINT8 Health1p = myHelpers->ReadByte(Base31p + 0x3C, false);
|
|
|
|
UINT8 Bullet1p = myHelpers->ReadByte(Base31p + 0x274, false);
|
|
|
|
UINT8 GrenadeExplode1p = myHelpers->ReadByte(Base31p + 0x2B3, false);
|
|
|
|
INT_PTR Base2p = myHelpers->ReadIntPtr((INT_PTR)gl_cgGLDll + 0x9164, false);
|
|
|
|
INT_PTR Base12p = myHelpers->ReadIntPtr(Base2p + 0x11C, false);
|
|
|
|
INT_PTR Base22p = myHelpers->ReadIntPtr(Base12p + 0x50, false);
|
|
|
|
INT_PTR Base32p = myHelpers->ReadIntPtr(Base22p + 0x38, false);
|
|
|
|
UINT8 Health2p = myHelpers->ReadByte(Base32p + 0x3C, false);
|
|
|
|
UINT8 Bullet2p = myHelpers->ReadByte(Base32p + 0x274, false);
|
|
|
|
UINT8 GrenadeExplode2p = myHelpers->ReadByte(Base32p + 0x2B3, false);
|
|
|
|
UINT8 IngameValue1p = myHelpers->ReadByte(Base31p + 0x38, false);
|
|
|
|
UINT8 IngameValue2p = myHelpers->ReadByte(Base32p + 0x38, false);
|
|
|
|
INT_PTR StartBase = myHelpers->ReadIntPtr((INT_PTR)gl_cgGLDll + 0x3C40, false);
|
|
|
|
INT_PTR StartBase1 = myHelpers->ReadIntPtr(StartBase + 0x130, false);
|
|
|
|
INT_PTR StartBase2 = myHelpers->ReadIntPtr(StartBase1 + 0x234, false);
|
|
|
|
UINT8 StartButton1p = myHelpers->ReadByte(StartBase2 + 0x530, false);
|
|
|
|
UINT8 StartButton2p = myHelpers->ReadByte(StartBase2 + 0x538, false);
|
2019-10-26 22:57:33 +02:00
|
|
|
|
2019-12-18 01:41:02 +01:00
|
|
|
UINT8 static oldHealth1p = 0;
|
|
|
|
UINT8 static oldBullet1p = 0;
|
|
|
|
UINT8 static oldHealth2p = 0;
|
|
|
|
UINT8 static oldBullet2p = 0;
|
|
|
|
UINT8 newHealth1p = Health1p;
|
|
|
|
UINT8 newBullet1p = Bullet1p;
|
|
|
|
UINT8 newHealth2p = Health2p;
|
|
|
|
UINT8 newBullet2p = Bullet2p;
|
2019-10-26 22:57:33 +02:00
|
|
|
|
2019-12-18 01:41:02 +01:00
|
|
|
wchar_t* settingsFilename = TEXT(".\\FFBPlugin.ini");
|
|
|
|
int configFeedbackLength = GetPrivateProfileInt(TEXT("Settings"), TEXT("FeedbackLength"), 120, settingsFilename);
|
|
|
|
int HowtoRumbleBulletEffect = GetPrivateProfileInt(TEXT("Settings"), TEXT("HowtoRumbleBulletEffect"), 0, settingsFilename);
|
|
|
|
int HowtoRumbleGrenadeEffect = GetPrivateProfileInt(TEXT("Settings"), TEXT("HowtoRumbleGrenadeEffect"), 0, settingsFilename);
|
|
|
|
int HowtoRumbleHealthEffect = GetPrivateProfileInt(TEXT("Settings"), TEXT("HowtoRumbleHealthEffect"), 0, settingsFilename);
|
|
|
|
int Bullet1pStrength = GetPrivateProfileInt(TEXT("Settings"), TEXT("Bullet1pStrength"), 0, settingsFilename);
|
|
|
|
int Grenade1pStrength = GetPrivateProfileInt(TEXT("Settings"), TEXT("Grenade1pStrength"), 0, settingsFilename);
|
|
|
|
int Health1pStrength = GetPrivateProfileInt(TEXT("Settings"), TEXT("Health1pStrength"), 0, settingsFilename);
|
|
|
|
int Bullet2pStrength = GetPrivateProfileInt(TEXT("Settings"), TEXT("Bullet2pStrength"), 0, settingsFilename);
|
|
|
|
int Grenade2pStrength = GetPrivateProfileInt(TEXT("Settings"), TEXT("Grenade2pStrength"), 0, settingsFilename);
|
|
|
|
int Health2pStrength = GetPrivateProfileInt(TEXT("Settings"), TEXT("Health2pStrength"), 0, settingsFilename);
|
2019-10-26 22:57:33 +02:00
|
|
|
|
2019-12-18 01:41:02 +01:00
|
|
|
if ((Health1p == 0) && (IngameValue1p == 11))
|
|
|
|
{
|
|
|
|
if (!HealthA)
|
2019-10-26 22:57:33 +02:00
|
|
|
{
|
2019-12-18 01:41:02 +01:00
|
|
|
if (HowtoRumbleHealthEffect == 0)
|
|
|
|
{
|
|
|
|
double percentForce = ((Health1pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->Rumble(percentForce, percentForce, percentLength);
|
|
|
|
}
|
|
|
|
else if (HowtoRumbleHealthEffect == 1)
|
2019-10-26 22:57:33 +02:00
|
|
|
{
|
2019-12-18 01:41:02 +01:00
|
|
|
double percentForce = ((Health1pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->Rumble(0, percentForce, percentLength);
|
2019-10-26 22:57:33 +02:00
|
|
|
}
|
2019-12-18 01:41:02 +01:00
|
|
|
else if (HowtoRumbleHealthEffect == 2)
|
|
|
|
{
|
|
|
|
double percentForce = ((Health1pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->Rumble(percentForce, 0, percentLength);
|
|
|
|
}
|
|
|
|
HealthA = true;
|
2019-10-27 08:21:57 +01:00
|
|
|
}
|
2019-12-18 01:41:02 +01:00
|
|
|
}
|
2019-10-27 08:21:57 +01:00
|
|
|
|
2019-12-18 01:41:02 +01:00
|
|
|
if ((Health2p == 0) && (IngameValue2p == 11))
|
|
|
|
{
|
|
|
|
if (!HealthB)
|
2019-10-27 08:21:57 +01:00
|
|
|
{
|
2019-12-18 01:41:02 +01:00
|
|
|
if (HowtoRumbleHealthEffect == 0)
|
|
|
|
{
|
|
|
|
double percentForce = ((Health2pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->RumbleDevice2(percentForce, percentForce, percentLength);
|
|
|
|
}
|
|
|
|
else if (HowtoRumbleHealthEffect == 1)
|
2019-10-26 22:57:33 +02:00
|
|
|
{
|
2019-12-18 01:41:02 +01:00
|
|
|
double percentForce = ((Health2pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->RumbleDevice2(0, percentForce, percentLength);
|
2019-10-26 22:57:33 +02:00
|
|
|
}
|
2019-12-18 01:41:02 +01:00
|
|
|
else if (HowtoRumbleHealthEffect == 2)
|
|
|
|
{
|
|
|
|
double percentForce = ((Health2pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->RumbleDevice2(percentForce, 0, percentLength);
|
|
|
|
}
|
|
|
|
HealthB = true;
|
2019-10-26 22:57:33 +02:00
|
|
|
}
|
2019-12-18 01:41:02 +01:00
|
|
|
}
|
2019-10-27 08:21:57 +01:00
|
|
|
|
2019-12-18 01:41:02 +01:00
|
|
|
if ((IngameValue1p == 3) && (StartButton1p != 0x80))
|
|
|
|
{
|
|
|
|
if (oldHealth1p != newHealth1p)
|
|
|
|
{
|
|
|
|
if (HowtoRumbleHealthEffect == 0)
|
|
|
|
{
|
|
|
|
double percentForce = ((Health1pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->Rumble(percentForce, percentForce, percentLength);
|
|
|
|
}
|
|
|
|
else if (HowtoRumbleHealthEffect == 1)
|
|
|
|
{
|
|
|
|
double percentForce = ((Health1pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->Rumble(0, percentForce, percentLength);
|
|
|
|
}
|
|
|
|
else if (HowtoRumbleHealthEffect == 2)
|
|
|
|
{
|
|
|
|
double percentForce = ((Health1pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->Rumble(percentForce, 0, percentLength);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (oldBullet1p != newBullet1p)
|
|
|
|
{
|
|
|
|
if (HowtoRumbleBulletEffect == 0)
|
|
|
|
{
|
|
|
|
double percentForce = ((Bullet1pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->Rumble(percentForce, percentForce, percentLength);
|
|
|
|
}
|
|
|
|
else if (HowtoRumbleBulletEffect == 1)
|
|
|
|
{
|
|
|
|
double percentForce = ((Bullet1pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->Rumble(0, percentForce, percentLength);
|
|
|
|
}
|
|
|
|
else if (HowtoRumbleBulletEffect == 2)
|
|
|
|
{
|
|
|
|
double percentForce = ((Bullet1pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->Rumble(percentForce, 0, percentLength);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (GrenadeExplode1p == 0x42)
|
2019-10-26 22:57:33 +02:00
|
|
|
{
|
2019-12-18 01:41:02 +01:00
|
|
|
if (HowtoRumbleGrenadeEffect == 0)
|
2019-10-26 22:57:33 +02:00
|
|
|
{
|
2019-12-18 01:41:02 +01:00
|
|
|
double percentForce = ((Grenade1pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->Rumble(percentForce, percentForce, percentLength);
|
2019-10-26 22:57:33 +02:00
|
|
|
}
|
2019-12-18 01:41:02 +01:00
|
|
|
else if (HowtoRumbleGrenadeEffect == 1)
|
2019-10-26 22:57:33 +02:00
|
|
|
{
|
2019-12-18 01:41:02 +01:00
|
|
|
double percentForce = ((Grenade1pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->Rumble(0, percentForce, percentLength);
|
2019-10-26 22:57:33 +02:00
|
|
|
}
|
2019-12-18 01:41:02 +01:00
|
|
|
else if (HowtoRumbleGrenadeEffect == 2)
|
2019-10-26 22:57:33 +02:00
|
|
|
{
|
2019-12-18 01:41:02 +01:00
|
|
|
double percentForce = ((Grenade1pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->Rumble(percentForce, 0, percentLength);
|
2019-10-26 22:57:33 +02:00
|
|
|
}
|
|
|
|
}
|
2019-12-18 01:41:02 +01:00
|
|
|
HealthA = false;
|
|
|
|
}
|
2019-10-27 08:21:57 +01:00
|
|
|
|
2019-12-18 01:41:02 +01:00
|
|
|
if ((IngameValue2p == 3) && (StartButton2p != 0x80))
|
|
|
|
{
|
|
|
|
if (oldHealth2p != newHealth2p)
|
|
|
|
{
|
|
|
|
if (HowtoRumbleHealthEffect == 0)
|
|
|
|
{
|
|
|
|
double percentForce = ((Health2pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->RumbleDevice2(percentForce, percentForce, percentLength);
|
|
|
|
}
|
|
|
|
else if (HowtoRumbleHealthEffect == 1)
|
|
|
|
{
|
|
|
|
double percentForce = ((Health2pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->RumbleDevice2(0, percentForce, percentLength);
|
|
|
|
}
|
|
|
|
else if (HowtoRumbleHealthEffect == 2)
|
|
|
|
{
|
|
|
|
double percentForce = ((Health2pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->RumbleDevice2(percentForce, 0, percentLength);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (oldBullet2p != newBullet2p)
|
2019-10-26 22:57:33 +02:00
|
|
|
{
|
2019-12-18 01:41:02 +01:00
|
|
|
if (HowtoRumbleBulletEffect == 0)
|
2019-10-26 22:57:33 +02:00
|
|
|
{
|
2019-12-18 01:41:02 +01:00
|
|
|
double percentForce = ((Bullet2pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->RumbleDevice2(percentForce, percentForce, percentLength);
|
2019-10-26 22:57:33 +02:00
|
|
|
}
|
2019-12-18 01:41:02 +01:00
|
|
|
else if (HowtoRumbleBulletEffect == 1)
|
2019-10-26 22:57:33 +02:00
|
|
|
{
|
2019-12-18 01:41:02 +01:00
|
|
|
double percentForce = ((Bullet2pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->RumbleDevice2(0, percentForce, percentLength);
|
2019-10-26 22:57:33 +02:00
|
|
|
}
|
2019-12-18 01:41:02 +01:00
|
|
|
else if (HowtoRumbleBulletEffect == 2)
|
2019-10-26 22:57:33 +02:00
|
|
|
{
|
2019-12-18 01:41:02 +01:00
|
|
|
double percentForce = ((Bullet2pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->RumbleDevice2(percentForce, 0, percentLength);
|
2019-10-26 22:57:33 +02:00
|
|
|
}
|
|
|
|
}
|
2019-12-18 01:41:02 +01:00
|
|
|
if (GrenadeExplode2p == 0x42)
|
|
|
|
{
|
|
|
|
if (HowtoRumbleGrenadeEffect == 0)
|
|
|
|
{
|
|
|
|
double percentForce = ((Grenade2pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->RumbleDevice2(percentForce, percentForce, percentLength);
|
|
|
|
}
|
|
|
|
else if (HowtoRumbleGrenadeEffect == 1)
|
|
|
|
{
|
|
|
|
double percentForce = ((Grenade2pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->RumbleDevice2(0, percentForce, percentLength);
|
|
|
|
}
|
|
|
|
else if (HowtoRumbleGrenadeEffect == 2)
|
|
|
|
{
|
|
|
|
double percentForce = ((Grenade2pStrength) / 100.0);
|
|
|
|
double percentLength = configFeedbackLength;
|
|
|
|
myTriggers->RumbleDevice2(percentForce, 0, percentLength);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
HealthB = false;
|
2019-10-26 22:57:33 +02:00
|
|
|
}
|
2019-12-18 01:41:02 +01:00
|
|
|
oldHealth1p = newHealth1p;
|
|
|
|
oldBullet1p = newBullet1p;
|
|
|
|
oldHealth2p = newHealth2p;
|
|
|
|
oldBullet2p = newBullet2p;
|
|
|
|
|
2019-10-26 22:57:33 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-12-18 01:41:02 +01:00
|
|
|
static DWORD WINAPI RunningLoop(LPVOID lpParam)
|
|
|
|
{
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
ThreadLoop();
|
|
|
|
Sleep(16);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-26 22:57:33 +02:00
|
|
|
void HOTD4::FFBLoop(EffectConstants *constants, Helpers *helpers, EffectTriggers* triggers) {
|
|
|
|
|
2019-11-08 19:17:51 +01:00
|
|
|
if (!init)
|
2019-10-26 22:57:33 +02:00
|
|
|
{
|
2019-11-08 19:17:51 +01:00
|
|
|
myTriggers = triggers;
|
|
|
|
myConstants = constants;
|
|
|
|
myHelpers = helpers;
|
2019-12-18 01:41:02 +01:00
|
|
|
CreateThread(NULL, 0, RunningLoop, NULL, 0, NULL);
|
2019-11-08 19:17:51 +01:00
|
|
|
|
2019-10-26 22:57:33 +02:00
|
|
|
for (int i = 0; i < SDL_NumJoysticks(); i++)
|
|
|
|
{
|
2019-11-08 19:17:51 +01:00
|
|
|
wchar_t* deviceGUIDString2 = new wchar_t[256];
|
|
|
|
int Device2GUID = GetPrivateProfileString(TEXT("Settings"), TEXT("Device2GUID"), NULL, deviceGUIDString2, 256, settingsFilename);
|
|
|
|
char joystick_guid[256];
|
|
|
|
sprintf(joystick_guid, "%S", deviceGUIDString2);
|
|
|
|
SDL_JoystickGUID guid, dev_guid;
|
|
|
|
int numJoysticks = SDL_NumJoysticks();
|
|
|
|
std::string njs = std::to_string(numJoysticks);
|
|
|
|
((char)njs.c_str());
|
|
|
|
for (int i = 0; i < SDL_NumJoysticks(); i++)
|
2019-10-26 22:57:33 +02:00
|
|
|
{
|
2019-11-08 19:17:51 +01:00
|
|
|
extern int joystick1Index;
|
|
|
|
if (i == joystick1Index)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
SDL_Joystick* js2 = SDL_JoystickOpen(i);
|
|
|
|
joystick_index2 = SDL_JoystickInstanceID(js2);
|
|
|
|
SDL_JoystickGUID guid = SDL_JoystickGetGUID(js2);
|
|
|
|
char guid_str[1024];
|
|
|
|
SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
|
|
|
|
const char* name = SDL_JoystickName(js2);
|
|
|
|
char text[256];
|
|
|
|
sprintf(text, "Joystick: %d / Name: %s / GUID: %s\n", i, name, guid_str);
|
|
|
|
guid = SDL_JoystickGetGUIDFromString(joystick_guid);
|
|
|
|
dev_guid = SDL_JoystickGetGUID(js2);
|
|
|
|
if (!memcmp(&guid, &dev_guid, sizeof(SDL_JoystickGUID)))
|
|
|
|
{
|
|
|
|
GameController2 = SDL_JoystickOpen(i);
|
|
|
|
ControllerHaptic2 = SDL_HapticOpenFromJoystick(GameController2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
SDL_JoystickClose(js2);
|
2019-10-26 22:57:33 +02:00
|
|
|
}
|
2019-11-08 19:17:51 +01:00
|
|
|
haptic2 = ControllerHaptic2;
|
|
|
|
if ((SDL_HapticRumbleSupported(haptic2) == SDL_TRUE))
|
2019-10-26 22:57:33 +02:00
|
|
|
{
|
2019-11-08 19:17:51 +01:00
|
|
|
SDL_HapticRumbleInit;
|
|
|
|
SDL_HapticRumbleInit(ControllerHaptic2);
|
2019-10-26 22:57:33 +02:00
|
|
|
}
|
|
|
|
}
|
2019-11-08 19:17:51 +01:00
|
|
|
init = true;
|
2019-10-26 22:57:33 +02:00
|
|
|
}
|
2019-11-08 19:17:51 +01:00
|
|
|
|
2019-11-01 21:34:57 +01:00
|
|
|
myTriggers = triggers;
|
|
|
|
myConstants = constants;
|
|
|
|
myHelpers = helpers;
|
2019-10-26 22:57:33 +02:00
|
|
|
}
|