diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index a78a9f71..c3035de6 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -173,6 +173,7 @@ IsleApp::IsleApp() m_transitionType = MxTransitionManager::e_mosaic; m_cursorSensitivity = 4; m_touchScheme = LegoInputManager::e_gamepad; + m_haptic = TRUE; } // FUNCTION: ISLE 0x4011a0 @@ -791,6 +792,11 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) SDL_Log("Game started"); } } + else if (event->user.type == g_legoSdlEvents.m_hitActor && g_isle->GetHaptic()) { + if (InputManager()) { + InputManager()->HandleRumbleEvent(); + } + } return SDL_APP_CONTINUE; } @@ -1042,6 +1048,7 @@ bool IsleApp::LoadConfig() iniparser_set(dict, "isle:Max Allowed Extras", SDL_itoa(m_maxAllowedExtras, buf, 10)); iniparser_set(dict, "isle:Transition Type", SDL_itoa(m_transitionType, buf, 10)); iniparser_set(dict, "isle:Touch Scheme", SDL_itoa(m_touchScheme, buf, 10)); + iniparser_set(dict, "isle:Haptic", m_haptic ? "true" : "false"); #ifdef EXTENSIONS iniparser_set(dict, "extensions", NULL); @@ -1113,6 +1120,7 @@ bool IsleApp::LoadConfig() m_transitionType = (MxTransitionManager::TransitionType) iniparser_getint(dict, "isle:Transition Type", m_transitionType); m_touchScheme = (LegoInputManager::TouchScheme) iniparser_getint(dict, "isle:Touch Scheme", m_touchScheme); + m_haptic = iniparser_getboolean(dict, "isle:Haptic", m_haptic); const char* deviceId = iniparser_getstring(dict, "isle:3D Device ID", NULL); if (deviceId != NULL) { diff --git a/ISLE/isleapp.h b/ISLE/isleapp.h index 3322427e..180c2252 100644 --- a/ISLE/isleapp.h +++ b/ISLE/isleapp.h @@ -55,6 +55,7 @@ class IsleApp { MxS32 GetGameStarted() { return m_gameStarted; } MxFloat GetCursorSensitivity() { return m_cursorSensitivity; } LegoInputManager::TouchScheme GetTouchScheme() { return m_touchScheme; } + MxBool GetHaptic() { return m_haptic; } void SetWindowActive(MxS32 p_windowActive) { m_windowActive = p_windowActive; } void SetGameStarted(MxS32 p_gameStarted) { m_gameStarted = p_gameStarted; } @@ -105,6 +106,7 @@ class IsleApp { MxU32 m_maxAllowedExtras; MxTransitionManager::TransitionType m_transitionType; LegoInputManager::TouchScheme m_touchScheme; + MxBool m_haptic; }; extern IsleApp* g_isle; diff --git a/LEGO1/lego/legoomni/include/legoinputmanager.h b/LEGO1/lego/legoomni/include/legoinputmanager.h index 30170822..ee87b50a 100644 --- a/LEGO1/lego/legoomni/include/legoinputmanager.h +++ b/LEGO1/lego/legoomni/include/legoinputmanager.h @@ -153,6 +153,7 @@ class LegoInputManager : public MxPresenter { MxResult GetNavigationKeyStates(MxU32& p_keyFlags); MxResult GetNavigationTouchStates(MxU32& p_keyFlags); LEGO1_EXPORT MxBool HandleTouchEvent(SDL_Event* p_event, TouchScheme p_touchScheme); + LEGO1_EXPORT MxBool HandleRumbleEvent(); // SYNTHETIC: LEGO1 0x1005b8d0 // LegoInputManager::`scalar deleting destructor' @@ -183,7 +184,7 @@ class LegoInputManager : public MxPresenter { std::map m_touchOrigins; std::map m_touchFlags; - std::map m_touchLastMotion; + std::map> m_touchLastMotion; }; // TEMPLATE: LEGO1 0x10028850 diff --git a/LEGO1/lego/legoomni/include/legoutils.h b/LEGO1/lego/legoomni/include/legoutils.h index 2df6ad4a..b29a336c 100644 --- a/LEGO1/lego/legoomni/include/legoutils.h +++ b/LEGO1/lego/legoomni/include/legoutils.h @@ -71,6 +71,7 @@ LegoNamedTexture* ReadNamedTexture(LegoStorage* p_storage); void WriteDefaultTexture(LegoStorage* p_storage, const char* p_name); void WriteNamedTexture(LegoStorage* p_storage, LegoNamedTexture* p_namedTexture); void LoadFromNamedTexture(LegoNamedTexture* p_namedTexture); +void HitActorEvent(); // FUNCTION: BETA10 0x100260a0 inline void StartIsleAction(IsleScript::Script p_objectId) diff --git a/LEGO1/lego/legoomni/src/common/legoutils.cpp b/LEGO1/lego/legoomni/src/common/legoutils.cpp index ff45676b..0a07a7c0 100644 --- a/LEGO1/lego/legoomni/src/common/legoutils.cpp +++ b/LEGO1/lego/legoomni/src/common/legoutils.cpp @@ -782,3 +782,10 @@ void LoadFromNamedTexture(LegoNamedTexture* p_namedTexture) textureInfo->LoadBits(p_namedTexture->GetTexture()->GetImage()->GetBits()); } } + +void HitActorEvent() +{ + SDL_Event event; + event.user.type = g_legoSdlEvents.m_hitActor; + SDL_PushEvent(&event); +} diff --git a/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp b/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp index ddcadaae..7c80e78e 100644 --- a/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp +++ b/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp @@ -532,9 +532,14 @@ MxResult LegoInputManager::GetNavigationTouchStates(MxU32& p_keyStates) p_keyStates |= touchFlags; // We need to clear these as they are not meant to be persistent in e_gamepad mode. - if (m_touchOrigins.count(fingerID) && SDL_GetTicks() - m_touchLastMotion[fingerID] > 5) { - touchFlags &= ~c_left; - touchFlags &= ~c_right; + if (m_touchOrigins.count(fingerID) && m_touchLastMotion.count(fingerID)) { + const MxU32 inactivityThreshold = 3; + + if (m_touchLastMotion[fingerID].first++ > inactivityThreshold) { + touchFlags &= ~c_left; + touchFlags &= ~c_right; + m_touchOrigins[fingerID].x = m_touchLastMotion[fingerID].second.x; + } } } @@ -586,12 +591,11 @@ MxBool LegoInputManager::HandleTouchEvent(SDL_Event* p_event, TouchScheme p_touc break; case SDL_EVENT_FINGER_MOTION: if (m_touchOrigins.count(event.fingerID)) { - m_touchFlags[event.fingerID] = 0; - m_touchLastMotion[event.fingerID] = SDL_GetTicks(); + const float activationThreshold = 0.03f; + m_touchFlags[event.fingerID] &= ~c_down; + m_touchFlags[event.fingerID] &= ~c_up; const float deltaY = event.y - m_touchOrigins[event.fingerID].y; - const float activationThreshold = 0.05f; - if (SDL_fabsf(deltaY) > activationThreshold) { if (deltaY > 0) { m_touchFlags[event.fingerID] |= c_down; @@ -601,12 +605,18 @@ MxBool LegoInputManager::HandleTouchEvent(SDL_Event* p_event, TouchScheme p_touc } } - const float deltaX = event.dx; - if (deltaX > 0) { - m_touchFlags[event.fingerID] |= c_right; - } - else if (deltaX < 0) { - m_touchFlags[event.fingerID] |= c_left; + const float deltaX = event.x - m_touchOrigins[event.fingerID].x; + if (SDL_fabsf(deltaX) > activationThreshold && event.dx) { + if (event.dx > 0) { + m_touchFlags[event.fingerID] |= c_right; + m_touchFlags[event.fingerID] &= ~c_left; + } + else if (event.dx < 0) { + m_touchFlags[event.fingerID] |= c_left; + m_touchFlags[event.fingerID] &= ~c_right; + } + + m_touchLastMotion[event.fingerID] = {0, {event.x, event.y}}; } } break; @@ -616,3 +626,18 @@ MxBool LegoInputManager::HandleTouchEvent(SDL_Event* p_event, TouchScheme p_touc return TRUE; } + +MxBool LegoInputManager::HandleRumbleEvent() +{ + if (m_joystick != NULL && SDL_GamepadConnected(m_joystick) == TRUE) { + const Uint16 frequency = 65535 / 2; + const Uint32 durationMs = 700; + SDL_RumbleGamepad(m_joystick, frequency, frequency, durationMs); + } + else { + return FALSE; + } + + // Add support for SDL Haptic API + return TRUE; +} diff --git a/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp b/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp index 0a888b46..7f640326 100644 --- a/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp @@ -235,6 +235,7 @@ MxResult LegoExtraActor::HitActor(LegoPathActor* p_actor, MxBool p_bool) assert(m_roi); assert(SoundManager()->GetCacheSoundManager()); SoundManager()->GetCacheSoundManager()->Play("crash5", m_roi->GetName(), FALSE); + HitActorEvent(); m_scheduledTime = Timer()->GetTime() + m_disAnim->GetDuration(); m_prevWorldSpeed = GetWorldSpeed(); VTable0xc4(); @@ -248,6 +249,7 @@ MxResult LegoExtraActor::HitActor(LegoPathActor* p_actor, MxBool p_bool) LegoROI* roi = GetROI(); assert(roi); SoundManager()->GetCacheSoundManager()->Play("crash5", m_roi->GetName(), FALSE); + HitActorEvent(); VTable0xc4(); SetActorState(c_two | c_noCollide); Mx3DPointFloat dir = p_actor->GetWorldDirection(); diff --git a/LEGO1/omni/include/mxutilities.h b/LEGO1/omni/include/mxutilities.h index c5237bb0..33754f3c 100644 --- a/LEGO1/omni/include/mxutilities.h +++ b/LEGO1/omni/include/mxutilities.h @@ -10,6 +10,7 @@ struct LegoSdlEvents { Uint32 m_windowsMessage; Uint32 m_presenterProgress; + Uint32 m_hitActor; }; LEGO1_EXPORT extern LegoSdlEvents g_legoSdlEvents; diff --git a/LEGO1/omni/src/main/mxomni.cpp b/LEGO1/omni/src/main/mxomni.cpp index d7b76847..b6081b16 100644 --- a/LEGO1/omni/src/main/mxomni.cpp +++ b/LEGO1/omni/src/main/mxomni.cpp @@ -163,9 +163,10 @@ MxResult MxOmni::Create(MxOmniCreateParam& p_param) } { - Uint32 event = SDL_RegisterEvents(2); + Uint32 event = SDL_RegisterEvents(3); g_legoSdlEvents.m_windowsMessage = event + 0; g_legoSdlEvents.m_presenterProgress = event + 1; + g_legoSdlEvents.m_hitActor = event + 2; } result = SUCCESS; diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index 2902c4fe..2039a7e2 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -1288,6 +1288,10 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::CreateCursorSurface(const CursorBitmap* p_ break; } default: { + DDCOLORKEY colorkey; + colorkey.dwColorSpaceHighValue = RGB8888_CREATE(0, 0, 0, 0); + colorkey.dwColorSpaceLowValue = RGB8888_CREATE(0, 0, 0, 0); + newSurface->SetColorKey(DDCKEY_SRCBLT, &colorkey); break; } }