diff --git a/Common Files/Game.h b/Common Files/Game.h index b47550e..a39ea4f 100644 --- a/Common Files/Game.h +++ b/Common Files/Game.h @@ -7,8 +7,10 @@ struct EffectTriggers { void(*Friction)(double strength); void(*Sine)(UINT16 period, UINT16 fadePeriod, double strength); void(*SineDevice2)(UINT16 period, UINT16 fadePeriod, double strength); + void(*SineDevice3)(UINT16 period, UINT16 fadePeriod, double strength); void(*Rumble)(double lowfrequency, double highfrequency, double length); void(*RumbleDevice2)(double lowfrequency, double highfrequency, double length); + void(*RumbleDevice3)(double lowfrequency, double highfrequency, double length); void(*LeftRight)(double smallstrength, double largestrength, double length); void(*LeftRightDevice2)(double smallstrength, double largestrength, double length); void(*Springi)(double strength); @@ -30,6 +32,7 @@ public: int effect_leftright_id; int effect_sine_id; int effect_sine_id_device2; + int effect_sine_id_device3; int effect_spring_id; int effect_vibration_id; int effect_inertia_id; diff --git a/DllMain.cpp b/DllMain.cpp index ef6012e..c9c8651 100644 --- a/DllMain.cpp +++ b/DllMain.cpp @@ -827,6 +827,7 @@ LPCDIDATAFORMAT WINAPI DirectInputGetdfDIJoystick() // global variables SDL_Haptic* haptic; SDL_Haptic* haptic2 = NULL; +SDL_Haptic* haptic3 = NULL; EffectCollection effects; EffectConstants effectConst; Helpers hlp; @@ -838,6 +839,8 @@ SDL_Joystick* GameController = NULL; SDL_Haptic* ControllerHaptic = NULL; SDL_Joystick* GameController2 = NULL; SDL_Haptic* ControllerHaptic2 = NULL; +SDL_Joystick* GameController3 = NULL; +SDL_Haptic* ControllerHaptic3 = NULL; HINSTANCE gl_hOriginalDll = NULL; HINSTANCE gl_hjgtDll = NULL; HINSTANCE gl_cgGLDll = NULL; @@ -846,6 +849,7 @@ extern HINSTANCE ProcDLL; int joystick_index1; int joystick1Index = -1; int joystick_index2 = -1; +int joystick_index3 = -1; // settings wchar_t* settingsFilename = TEXT(".\\FFBPlugin.ini"); @@ -872,11 +876,20 @@ int configMinForceDevice2 = GetPrivateProfileInt(TEXT("Settings"), TEXT("MinForc int configMaxForceDevice2 = GetPrivateProfileInt(TEXT("Settings"), TEXT("MaxForceDevice2"), 100, settingsFilename); int EnableRumbleDevice2 = GetPrivateProfileInt(TEXT("Settings"), TEXT("EnableRumbleDevice2"), 0, settingsFilename); int ReverseRumbleDevice2 = GetPrivateProfileInt(TEXT("Settings"), TEXT("ReverseRumbleDevice2"), 0, settingsFilename); -int AlternativeFFBDevice2 = GetPrivateProfileInt(TEXT("Settings"), TEXT("AlternativeFFB"), 0, settingsFilename); +int AlternativeFFBDevice2 = GetPrivateProfileInt(TEXT("Settings"), TEXT("AlternativeFFBDevice2"), 0, settingsFilename); int configAlternativeMinForceLeftDevice2 = GetPrivateProfileInt(TEXT("Settings"), TEXT("AlternativeMinForceLeftDevice2"), 0, settingsFilename); int configAlternativeMaxForceLeftDevice2 = GetPrivateProfileInt(TEXT("Settings"), TEXT("AlternativeMaxForceLeftDevice2"), 100, settingsFilename); int configAlternativeMinForceRightDevice2 = GetPrivateProfileInt(TEXT("Settings"), TEXT("AlternativeMinForceRightDevice2"), 0, settingsFilename); int configAlternativeMaxForceRightDevice2 = GetPrivateProfileInt(TEXT("Settings"), TEXT("AlternativeMaxForceRightDevice2"), 100, settingsFilename); +int configMinForceDevice3 = GetPrivateProfileInt(TEXT("Settings"), TEXT("MinForceDevice3"), 0, settingsFilename); +int configMaxForceDevice3 = GetPrivateProfileInt(TEXT("Settings"), TEXT("MaxForceDevice3"), 100, settingsFilename); +int EnableRumbleDevice3 = GetPrivateProfileInt(TEXT("Settings"), TEXT("EnableRumbleDevice3"), 0, settingsFilename); +int ReverseRumbleDevice3 = GetPrivateProfileInt(TEXT("Settings"), TEXT("ReverseRumbleDevice3"), 0, settingsFilename); +int AlternativeFFBDevice3 = GetPrivateProfileInt(TEXT("Settings"), TEXT("AlternativeFFBDevice3"), 0, settingsFilename); +int configAlternativeMinForceLeftDevice3 = GetPrivateProfileInt(TEXT("Settings"), TEXT("AlternativeMinForceLeftDevice3"), 0, settingsFilename); +int configAlternativeMaxForceLeftDevice3 = GetPrivateProfileInt(TEXT("Settings"), TEXT("AlternativeMaxForceLeftDevice3"), 100, settingsFilename); +int configAlternativeMinForceRightDevice3 = GetPrivateProfileInt(TEXT("Settings"), TEXT("AlternativeMinForceRightDevice3"), 0, settingsFilename); +int configAlternativeMaxForceRightDevice3 = GetPrivateProfileInt(TEXT("Settings"), TEXT("AlternativeMaxForceRightDevice3"), 100, settingsFilename); char chainedDLL[256]; @@ -1091,6 +1104,16 @@ void Initialize(int device_index) tempEffect2.constant.direction.type = SDL_HAPTIC_CARTESIAN; effects.effect_sine_id_device2 = SDL_HapticNewEffect(haptic2, &tempEffect2); } + + if (haptic3 != NULL) + { + SDL_HapticEffect tempEffect3; + SDL_memset(&tempEffect3, 0, sizeof(SDL_HapticEffect)); + tempEffect3 = SDL_HapticEffect(); + tempEffect3.type = SDL_HAPTIC_SINE; + tempEffect3.constant.direction.type = SDL_HAPTIC_CARTESIAN; + effects.effect_sine_id_device3 = SDL_HapticNewEffect(haptic3, &tempEffect3); + } // TODO: why don't we just define this as hackFix = true in the other file? @@ -1103,10 +1126,14 @@ void Initialize(int device_index) using namespace std::chrono; std::chrono::milliseconds timeOfLastSineEffect = duration_cast(system_clock::now().time_since_epoch()); std::chrono::milliseconds timeOfLastSineEffectDevice2 = duration_cast(system_clock::now().time_since_epoch()); +std::chrono::milliseconds timeOfLastSineEffectDevice3 = duration_cast(system_clock::now().time_since_epoch()); double lastSineEffectStrength = 0; double lastSineEffectStrengthDevice2 = 0; +double lastSineEffectStrengthDevice3 = 0; double lastSineEffectPeriod = 0; double lastSineEffectPeriodDevice2 = 0; +double lastSineEffectPeriodDevice3 = 0; + void TriggerConstantEffect(int direction, double strength) { SDL_HapticEffect tempEffect; @@ -1532,6 +1559,80 @@ void TriggerSineEffectDevice2(UINT16 period, UINT16 fadePeriod, double strength) lastSineEffectPeriodDevice2 = period; } +void TriggerSineEffectDevice3(UINT16 period, UINT16 fadePeriod, double strength) +{ + std::chrono::milliseconds now = duration_cast(system_clock::now().time_since_epoch()); + long long elapsedTime = (std::chrono::duration_cast(now - timeOfLastSineEffectDevice3)).count(); + + int direction = 1; + if (strength < -0.001) { + strength *= -1; + direction = -1; + } + + // if no strength, we do nothing + if (strength <= 0.001) { + return; + } + + // we ignore the new effect until the last one is completed, unless the new one is significantly stronger + if (elapsedTime < lastSineEffectPeriodDevice3 && strength < (lastSineEffectStrengthDevice3 * 1.5)) { + return; + } + + SDL_HapticEffect tempEffect; + SDL_memset(&tempEffect, 0, sizeof(SDL_HapticEffect)); + hlp.log("Doing Device3 sine..."); + tempEffect.type = SDL_HAPTIC_SINE; + tempEffect.periodic.direction.type = SDL_HAPTIC_CARTESIAN; + tempEffect.periodic.direction.dir[0] = direction; + tempEffect.constant.direction.dir[1] = 0; //Y Position + tempEffect.periodic.period = period; + + int confMinForce = configMinForceDevice3; + int confMaxForce = configMaxForceDevice3; + if (AlternativeFFBDevice3 == 1) + { + if (direction == -1) + { + confMinForce = configAlternativeMinForceLeftDevice3; + confMaxForce = configAlternativeMaxForceLeftDevice3; + } + else + { + confMinForce = configAlternativeMinForceRightDevice3; + confMaxForce = configAlternativeMaxForceRightDevice3; + } + } + SHORT minForce = (SHORT)(strength > 0.001 ? (confMinForce / 100.0 * 32767.0) : 0); // strength is a double so we do an epsilon check of 0.001 instead of > 0. + SHORT maxForce = (SHORT)(confMaxForce / 100.0 * 32767.0); + SHORT range = maxForce - minForce; + SHORT magnitude = (SHORT)(strength * range + minForce); + if (range > 0 && magnitude < 0) + { + magnitude = 32767; + } + else if (range < 0 && magnitude > 0) + { + magnitude = -32767; + } + + tempEffect.periodic.magnitude = (SHORT)(magnitude); + tempEffect.periodic.length = period; + tempEffect.periodic.attack_length = fadePeriod; + tempEffect.periodic.fade_length = fadePeriod; + + SDL_HapticUpdateEffect(haptic3, effects.effect_sine_id_device3, &tempEffect); + SDL_HapticRunEffect(haptic3, effects.effect_sine_id_device3, 1); + + /*int supported = SDL_HapticEffectSupported(haptic, &tempEffect); + hlp.log((char *)std::to_string(supported).c_str());*/ + + timeOfLastSineEffectDevice3 = now; + lastSineEffectStrengthDevice3 = strength; + lastSineEffectPeriodDevice3 = period; +} + void TriggerSpringEffectWithDefaultOption(double strength, bool isDefault) { SDL_HapticEffect tempEffect; @@ -1735,6 +1836,37 @@ void TriggerRumbleEffectDevice2(double highfrequency, double lowfrequency, doubl } } +void TriggerRumbleEffectDevice3(double highfrequency, double lowfrequency, double length) +{ + if (EnableRumbleDevice3 == 1) + { + DWORD minForceLow = (DWORD)(lowfrequency > 0.001 ? (configMinForce / 100.0 * 65535.0) : 0); + DWORD minForceHigh = (DWORD)(highfrequency > 0.001 ? (configMinForce / 100.0 * 65535.0) : 0); + DWORD maxForce = (DWORD)(configMaxForce / 100.0 * 65535.0); + DWORD rangeLow = maxForce - minForceLow; + DWORD rangeHigh = maxForce - minForceHigh; + DWORD LowMotor = (DWORD)(lowfrequency * rangeLow + minForceLow); + DWORD HighMotor = (DWORD)(highfrequency * rangeHigh + minForceHigh); + + if (ReverseRumbleDevice3 == 1) + { + int ReverseRumble3 = SDL_JoystickRumble(GameController3, HighMotor, LowMotor, length); + if (ReverseRumble3 == -1) + { + EnableRumbleDevice3 = 0; + } + } + else + { + int Rumble3 = SDL_JoystickRumble(GameController3, LowMotor, HighMotor, length); + if (Rumble3 == -1) + { + EnableRumbleDevice3 = 0; + } + } + } +} + void TriggerSpringEffect(double strength) { TriggerSpringEffectWithDefaultOption(strength, false); @@ -1791,8 +1923,10 @@ DWORD WINAPI FFBLoop(LPVOID lpParam) t.Friction = &TriggerFrictionEffect; t.Sine = &TriggerSineEffect; t.SineDevice2 = &TriggerSineEffectDevice2; + t.SineDevice3 = &TriggerSineEffectDevice3; t.Rumble = &TriggerRumbleEffect; t.RumbleDevice2 = &TriggerRumbleEffectDevice2; + t.RumbleDevice3 = &TriggerRumbleEffectDevice3; t.LeftRight = &TriggerLeftRightEffect; t.LeftRightDevice2 = &TriggerLeftRightDevice2Effect; t.Springi = &TriggerSpringEffectInfinite; diff --git a/Game Files/OutputReading.cpp b/Game Files/OutputReading.cpp index 0c04041..ca5b6f7 100644 --- a/Game Files/OutputReading.cpp +++ b/Game Files/OutputReading.cpp @@ -21,9 +21,13 @@ along with FFB Arcade Plugin.If not, see < https://www.gnu.org/licenses/>. #include "SDL.h" extern int joystick_index1; extern int joystick_index2; +extern int joystick_index3; extern SDL_Joystick* GameController2; extern SDL_Haptic* ControllerHaptic2; extern SDL_Haptic* haptic2; +extern SDL_Joystick* GameController3; +extern SDL_Haptic* ControllerHaptic3; +extern SDL_Haptic* haptic3; HINSTANCE ProcDLL = NULL; static wchar_t* settingsFilename = TEXT(".\\FFBPlugin.ini"); @@ -42,6 +46,7 @@ static bool EmuName = false; static bool RomGameName = false; static bool Effect1 = false; static bool Effect2 = false; +static bool Effect3 = false; static bool DirtDevilSine = false; static bool ForceSpringEffect = false; static bool DontSineUntilRaceStart = false; @@ -65,6 +70,7 @@ int HardDrivinFFB; int newstateFFB; int stateFFB; int stateFFBDevice2; +int stateFFBDevice3; std::string wheelA("wheel"); @@ -1760,6 +1766,7 @@ std::string srally2pa("srally2pa"); //MAME Games std::string aburner2("aburner2"); +std::string aburner2g("aburner2g"); std::string vformula("vformula"); std::string vr("vr"); std::string sfrush("sfrush"); @@ -1836,6 +1843,18 @@ std::string racedrivc2("racedrivc2"); std::string racedrivc4("racedrivc4"); std::string racedrivc("racedrivc"); std::string racedrivpan("racedrivpan"); +std::string othunder("othunder"); +std::string othundero("othundero"); +std::string othunderuo("othunderuo"); +std::string othunderu("othunderu"); +std::string othunderj("othunderj"); +std::string opwolf("opwolf"); +std::string opwolfp("opwolfp"); +std::string opwolfj("opwolfj"); +std::string opwolfu("opwolfu"); +std::string opwolfa("opwolfa"); +std::string revx("revx"); +std::string revxp5("revxp5"); //Our string to load game from std::string Daytona2Active("Daytona2Active"); @@ -1853,6 +1872,8 @@ std::string OutrunnersActive("OutrunnersActive"); std::string SanFran2049Active("SanFran2049Active"); std::string HardDrivinActive("HardDrivinActive"); std::string AfterburnerActive("AfterburnerActive"); +std::string RecoilPistolActive("RecoilPistolActive"); +std::string RecoilGunActive("RecoilGunActive"); //Names of FFB Outputs std::string RawDrive("RawDrive"); @@ -1863,6 +1884,11 @@ std::string Vibration_motor("Vibration_motor"); std::string upright_wheel_motor("upright_wheel_motor"); std::string MA_Steering_Wheel_motor("MA_Steering_Wheel_motor"); std::string MB_Steering_Wheel_motor("MB_Steering_Wheel_motor"); +std::string Player1_Recoil_Piston("Player1_Recoil_Piston"); +std::string Player2_Recoil_Piston("Player2_Recoil_Piston"); +std::string Player1_Gun_Recoil("Player1_Gun_Recoil"); +std::string Player2_Gun_Recoil("Player2_Gun_Recoil"); +std::string Player3_Gun_Recoil("Player3_Gun_Recoil"); //Emulator Name std::string MAME("MAME"); @@ -1926,6 +1952,50 @@ void OutputReading::FFBLoop(EffectConstants* constants, Helpers* helpers, Effect SDL_HapticSetGain(haptic2, 100); } + for (int i = 0; i < SDL_NumJoysticks(); i++) + { + wchar_t* deviceGUIDString3 = new wchar_t[256]; + int Device3GUID = GetPrivateProfileString(TEXT("Settings"), TEXT("Device3GUID"), NULL, deviceGUIDString3, 256, settingsFilename); + char joystick_guid[256]; + sprintf(joystick_guid, "%S", deviceGUIDString3); + 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++) + { + extern int joystick1Index; + if (i == joystick1Index) + { + continue; + } + SDL_Joystick* js3 = SDL_JoystickOpen(i); + joystick_index3 = SDL_JoystickInstanceID(js3); + SDL_JoystickGUID guid = SDL_JoystickGetGUID(js3); + char guid_str[1024]; + SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); + const char* name = SDL_JoystickName(js3); + 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(js3); + if (!memcmp(&guid, &dev_guid, sizeof(SDL_JoystickGUID))) + { + GameController3 = SDL_JoystickOpen(i); + ControllerHaptic3 = SDL_HapticOpenFromJoystick(GameController3); + break; + } + SDL_JoystickClose(js3); + } + haptic3 = ControllerHaptic3; + if ((SDL_HapticRumbleSupported(haptic3) == SDL_TRUE)) + { + SDL_HapticRumbleInit; + SDL_HapticRumbleInit(ControllerHaptic3); + } + SDL_HapticSetGain(haptic3, 100); + } + if (EnableForceSpringEffect == 1) { if (ForceSpringEffect) @@ -2019,11 +2089,22 @@ void OutputReading::FFBLoop(EffectConstants* constants, Helpers* helpers, Effect RunningFFB = "HardDrivinActive"; } - if (romname == aburner2) + if (romname == aburner2 || romname == aburner2g) { RunningFFB = "AfterburnerActive"; } + if (romname == othunder || romname == othundero || romname == othunderuo || romname == othunderu || romname == othunderj || romname == opwolf || romname == opwolfp || romname == opwolfj || + romname == opwolfu || romname == opwolfa) + { + RunningFFB = "RecoilPistolActive"; + } + + if (romname == revx || romname == revxp5) + { + RunningFFB = "RecoilGunActive"; + } + if ((RunningFFB != NULL) && (RunningFFB[0] != '\0')) { RomGameName = true; @@ -2689,5 +2770,155 @@ void OutputReading::FFBLoop(EffectConstants* constants, Helpers* helpers, Effect } } } + + if (RunningFFB == RecoilPistolActive) + { + if (Emulator == MAME) + { + if (name == Player1_Recoil_Piston) + { + helpers->log("got value: "); + std::string ffs = std::to_string(newstateFFB); + helpers->log((char*)ffs.c_str()); + + stateFFB = newstateFFB; + } + + if (name == Player2_Recoil_Piston) + { + stateFFBDevice2 = newstateFFB; + } + + if (stateFFB == 1) + { + Effect1 = true; + } + else + { + Effect1 = false; + } + + if (stateFFBDevice2 == 1) + { + Effect2 = true; + } + else + { + Effect2 = false; + } + + if (Effect1) + { + triggers->Sine(SinePeriod, SineFadePeriod, SineStrength / 100.0); + triggers->Rumble(RumbleStrengthLeftMotor / 100.0, RumbleStrengthRightMotor / 100.0, 100); + } + + if (!Effect1) + { + triggers->Sine(0, 0, 0); + triggers->Rumble(0, 0, 0); + } + + if (Effect2) + { + triggers->SineDevice2(SinePeriod, SineFadePeriod, SineStrength / 100.0); + triggers->RumbleDevice2(RumbleStrengthLeftMotor / 100.0, RumbleStrengthRightMotor / 100.0, 100); + } + + if (!Effect2) + { + triggers->SineDevice2(0, 0, 0); + triggers->RumbleDevice2(0, 0, 0); + } + } + } + + if (RunningFFB == RecoilGunActive) + { + if (Emulator == MAME) + { + if (name == Player1_Gun_Recoil) + { + helpers->log("got value: "); + std::string ffs = std::to_string(newstateFFB); + helpers->log((char*)ffs.c_str()); + + stateFFB = newstateFFB; + } + + if (name == Player2_Gun_Recoil) + { + stateFFBDevice2 = newstateFFB; + } + + if (name == Player3_Gun_Recoil) + { + stateFFBDevice3 = newstateFFB; + } + + if (stateFFB == 1) + { + Effect1 = true; + } + else + { + Effect1 = false; + } + + if (stateFFBDevice2 == 1) + { + Effect2 = true; + } + else + { + Effect2 = false; + } + + if (stateFFBDevice3 == 1) + { + Effect3 = true; + } + else + { + Effect3 = false; + } + + if (Effect1) + { + triggers->Sine(SinePeriod, SineFadePeriod, SineStrength / 100.0); + triggers->Rumble(RumbleStrengthLeftMotor / 100.0, RumbleStrengthRightMotor / 100.0, 100); + } + + if (!Effect1) + { + triggers->Sine(0, 0, 0); + triggers->Rumble(0, 0, 0); + } + + if (Effect2) + { + triggers->SineDevice2(SinePeriod, SineFadePeriod, SineStrength / 100.0); + triggers->RumbleDevice2(RumbleStrengthLeftMotor / 100.0, RumbleStrengthRightMotor / 100.0, 100); + } + + if (!Effect2) + { + triggers->SineDevice2(0, 0, 0); + triggers->RumbleDevice2(0, 0, 0); + } + + if (Effect3) + { + triggers->SineDevice3(SinePeriod, SineFadePeriod, SineStrength / 100.0); + triggers->RumbleDevice3(RumbleStrengthLeftMotor / 100.0, RumbleStrengthRightMotor / 100.0, 100); + } + + if (!Effect3) + { + triggers->SineDevice3(0, 0, 0); + triggers->RumbleDevice3(0, 0, 0); + } + } + } } } \ No newline at end of file