Skip to content

Commit 865915e

Browse files
committed
Fix bug where you could pause then open the map overview which would lock the game up
Fix the "GAME PAUSED" message Dim the background slightly while paused fix the mouse enter/leaving logic for SDL3 fix demo recording
1 parent 3af1550 commit 865915e

11 files changed

Lines changed: 197 additions & 125 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,3 +357,4 @@ nbproject/
357357
Projects/emscripten/build-ems/
358358
Projects/emscripten/.emsdk_cache/
359359
/Projects/VS
360+
/Projects/VS32

Source/Camera.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -532,10 +532,9 @@ void cFodder::Camera_Pan_ComputeSpeed()
532532

533533
void cFodder::Camera_Update_Mouse_Position_For_Pan()
534534
{
535-
535+
// Keep the in-game cursor over the same world position while the camera pans.
536536
if (!mMouse_Locked)
537537
{
538-
539538
// Mouse in playfield?
540539
if (mMouseX > 0x0F)
541540
{

Source/Event.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ enum eEventType {
3232
eEvent_MouseWheel = 8,
3333
eEvent_Quit = 10,
3434
eEvent_Focus = 11,
35+
eEvent_MouseEnter = 12,
36+
eEvent_MouseLeave = 13,
3537
};
3638

3739
class cEvent {

Source/Fodder.cpp

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ cFodder::cFodder(std::shared_ptr<cWindow> pWindow)
205205
mSprite_SheetPtr = 0;
206206

207207
mWindow_Focus = false;
208+
mWindow_MouseInside = false;
208209

209210
Sprite_Clear_All();
210211

@@ -239,7 +240,7 @@ int16 cFodder::Phase_Cycle()
239240
mStartParams->mDemoPlayback = false;
240241
mStartParams->mDemoRecord = true;
241242
mStartParams->mDemoRecordResumeCycle = 0;
242-
mParams->mSleepDelta = 0;
243+
mParams->mSleepDelta = mStartParams->mSleepDelta;
243244
mParams->mDemoRecord = mStartParams->mDemoRecord;
244245
mParams->mDemoPlayback = mStartParams->mDemoPlayback;
245246
mStartParams->mDisableVideo = false;
@@ -388,20 +389,22 @@ void cFodder::Phase_Paused()
388389
{
389390
Draw_Phase_Paused();
390391

391-
// Fade the background out, and the 'mission paused' message in
392-
mSurface->palette_FadeTowardNew();
393-
mSurface->palette_FadeTowardNew();
394-
mSurface->palette_FadeTowardNew();
395-
396392
while (mPhase_Paused)
397393
{
394+
if (mSurface->isPaletteAdjusting())
395+
mSurface->palette_FadeTowardNew();
398396

397+
// Draw background with faded palette, then overlay text using its own palette.
399398
mSurface->draw();
399+
mSurface2->draw();
400+
mSurface->mergeSurfaceBuffer(mSurface2);
400401

401-
// Copy the rendered surface of the 'mission paused' message over the top of the main surface
402-
mSurface->mergeFrom(mSurface2);
402+
mWindow->RenderAt(mSurface);
403+
mWindow->FrameEnd();
403404

404-
Video_Sleep();
405+
mWindow->Cycle();
406+
eventsProcess();
407+
SDL_Delay(1);
405408
}
406409

407410
mGraphics->PaletteSet();
@@ -2019,6 +2022,14 @@ void cFodder::eventProcess(const cEvent &pEvent)
20192022
mWindow_Focus = pEvent.mHasFocus;
20202023
break;
20212024

2025+
case eEvent_MouseEnter:
2026+
mWindow_MouseInside = true;
2027+
break;
2028+
2029+
case eEvent_MouseLeave:
2030+
mWindow_MouseInside = false;
2031+
break;
2032+
20222033
case eEvent_KeyDown:
20232034
keyProcess(pEvent.mButton, true);
20242035
break;
@@ -2137,12 +2148,14 @@ void cFodder::keyProcess(uint8 pKeyCode, bool pPressed)
21372148

21382149
if ((pKeyCode == SDL_SCANCODE_EQUALS && pPressed) || (pKeyCode == SDL_SCANCODE_KP_PLUS && pPressed))
21392150
{
2140-
mWindow->WindowIncrease();
2151+
if(!mStartParams->mDemoPlayback)
2152+
mWindow->WindowIncrease();
21412153
}
21422154

21432155
if ((pKeyCode == SDL_SCANCODE_MINUS && pPressed) || (pKeyCode == SDL_SCANCODE_KP_MINUS && pPressed))
21442156
{
2145-
mWindow->WindowDecrease();
2157+
if (!mStartParams->mDemoPlayback)
2158+
mWindow->WindowDecrease();
21462159
}
21472160

21482161
if (pKeyCode == SDL_SCANCODE_F11 && pPressed)
@@ -2179,14 +2192,15 @@ void cFodder::keyProcess(uint8 pKeyCode, bool pPressed)
21792192
}
21802193

21812194
if (pKeyCode == SDL_SCANCODE_P && pPressed)
2182-
mPhase_Paused = !mPhase_Paused;
2195+
if(!mPhase_ShowMapOverview)
2196+
mPhase_Paused = !mPhase_Paused;
21832197

21842198
if (pKeyCode == SDL_SCANCODE_SPACE && pPressed)
21852199
++mSquad_SwitchWeapon;
21862200

21872201
if (pKeyCode == SDL_SCANCODE_M && pPressed)
21882202
{
2189-
if (mPhase_Finished == false)
2203+
if (mPhase_Finished == false && !mPhase_Paused)
21902204
mPhase_ShowMapOverview = -1;
21912205
}
21922206

@@ -2592,7 +2606,7 @@ void cFodder::Draw_Phase_Paused()
25922606
mSurface2->surfaceSetToPaletteNew();
25932607

25942608
// Dim the current surface
2595-
mSurface->paletteNew_SetToBlack();
2609+
mSurface->paletteNew_SetDimmed(64);
25962610

25972611
// Draw to the secondary surface
25982612
{

Source/Fodder.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,9 @@ class cFodder {
177177
uint32 mMouse_EventLastButtonsPressed;
178178
cPosition mMouse_EventLastWheel;
179179
bool mMouse_Locked;
180-
int16 mMouse_LeftWindow;
180+
uint64 mMouse_LeftWindow;
181181
bool mWindow_Focus;
182+
bool mWindow_MouseInside;
182183

183184
bool mSquad_Member_Fire_CoolDown_Override;
184185

@@ -1329,7 +1330,7 @@ class cFodder {
13291330
virtual void Mouse_ReadInputs();
13301331
void Mouse_Inputs_Check();
13311332
void Mouse_Setup();
1332-
cPosition Mouse_GetOnBorderPosition();
1333+
bool Mouse_IsOnBorder() const;
13331334

13341335
void eventProcess(const cEvent& pEvent);
13351336
void eventsProcess();

Source/Mouse.cpp

Lines changed: 115 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -39,119 +39,148 @@ void cFodder::Mouse_Setup() {
3939
}
4040

4141
void cFodder::Mouse_Cursor_Handle() {
42-
static bool WasClicked = false;
43-
44-
const cPosition WindowPos = mWindow->GetWindowPosition();
45-
const cDimension ScreenSize = mWindow->GetScreenSize();
46-
const cDimension WindowSize = mWindow->GetWindowSize();
42+
static int32 CaptureBlockFrames = 0;
43+
static bool MouseCapturedGlobal = false;
4744
const cDimension scale = mWindow->GetScale();
48-
static bool CursorGrabbed = true;
45+
static bool CursorCaptured = true;
46+
const int edgePadding = 2;
47+
const uint64 recaptureDelayMs = 150;
4948

5049
mMouseButtonStatus = mMouse_EventLastButtonsPressed;
5150

52-
if (!mWindow_Focus && CursorGrabbed) {
53-
CursorGrabbed = false;
54-
}
51+
auto UpdateInputFromWindowPos = [&]() {
52+
float x = 0.0f;
53+
float y = 0.0f;
54+
SDL_GetMouseState(&x, &y);
55+
mInputMouseX = (static_cast<int>(x) / scale.getWidth()) + MOUSE_POSITION_X_ADJUST;
56+
mInputMouseY = (static_cast<int>(y) / scale.getHeight()) + MOUSE_POSITION_Y_ADJUST;
57+
};
58+
59+
auto ReleaseCursor = [&](bool pWarpToEdge) {
60+
CursorCaptured = false;
61+
mMouse_LeftWindow = static_cast<uint64>(SDL_GetTicks());
62+
mWindow->SetRelativeMouseMode(false);
63+
SDL_GetRelativeMouseState(nullptr, nullptr);
64+
mMouse_EventLastPositionRelative = { 0, 0 };
65+
SDL_ShowCursor();
66+
mWindow_MouseInside = false;
67+
68+
if (MouseCapturedGlobal) {
69+
SDL_CaptureMouse(false);
70+
MouseCapturedGlobal = false;
71+
}
72+
73+
if (!pWarpToEdge)
74+
return;
75+
76+
const cDimension windowSize = mWindow->GetWindowSize();
77+
int x = (mMouseX - MOUSE_POSITION_X_ADJUST) * scale.getWidth();
78+
int y = (mMouseY - MOUSE_POSITION_Y_ADJUST) * scale.getHeight();
79+
if (x < 0)
80+
x = 0;
81+
else if (x >= windowSize.getWidth())
82+
x = windowSize.getWidth() - 1;
83+
if (y < 0)
84+
y = 0;
85+
else if (y >= windowSize.getHeight())
86+
y = windowSize.getHeight() - 1;
87+
mWindow->SetMousePositionInWindow(static_cast<float>(x), static_cast<float>(y));
88+
};
5589

5690
if (mStartParams->mMouseAlternative) {
5791
mInputMouseX = (mMouse_EventLastPosition.mX / scale.getWidth()) + MOUSE_POSITION_X_ADJUST;
5892
mInputMouseY = (mMouse_EventLastPosition.mY / scale.getHeight()) + MOUSE_POSITION_Y_ADJUST;
5993
return;
6094
}
6195

62-
// Check if the system mouse is grabbed
63-
if (!CursorGrabbed) {
64-
65-
if (!mWindow_Focus && mWindow->isMouseInside()) {
96+
if (!mWindow_Focus) {
97+
if (CursorCaptured) {
98+
CursorCaptured = false;
99+
mWindow->SetRelativeMouseMode(false);
100+
SDL_GetRelativeMouseState(nullptr, nullptr);
101+
mMouse_EventLastPositionRelative = { 0, 0 };
102+
SDL_ShowCursor();
103+
}
104+
mWindow_MouseInside = false;
105+
if (MouseCapturedGlobal) {
106+
SDL_CaptureMouse(false);
107+
MouseCapturedGlobal = false;
108+
}
109+
if (mWindow->isMouseInside()) {
66110
// Register mouse position even when not focused but cursor on window
67-
mInputMouseX = (mMouse_EventLastPosition.mX / scale.getWidth()) + MOUSE_POSITION_X_ADJUST;
68-
mInputMouseY = (mMouse_EventLastPosition.mY / scale.getHeight()) + MOUSE_POSITION_Y_ADJUST;
111+
UpdateInputFromWindowPos();
69112
}
70-
71-
if (SDL_GetTicks() - mMouse_LeftWindow < 100)
72-
return;
113+
return;
114+
}
73115

74-
// Check if the system cursor x/y is inside our window
75-
// and ensure the mouse button has been released before we focus
76-
if (mWindow_Focus && mWindow->isMouseInside() && !mMouseButtonStatus) {
77-
WasClicked = true;
78-
CursorGrabbed = true;
79-
80-
if (!mWindow->isFullscreen()) {
81-
// Ensure X not too close to a border
82-
if (mInputMouseX <= MOUSE_POSITION_X_ADJUST)
83-
mInputMouseX = MOUSE_POSITION_X_ADJUST + 1;
84-
else if (mInputMouseX >= ScreenSize.getWidth() + MOUSE_POSITION_X_ADJUST - 1)
85-
mInputMouseX = ScreenSize.getWidth() + MOUSE_POSITION_X_ADJUST - 2;
86-
87-
// Ensure Y not too close to a border
88-
if (mInputMouseY <= MOUSE_POSITION_Y_ADJUST)
89-
mInputMouseY = MOUSE_POSITION_Y_ADJUST + 1;
90-
else if (mInputMouseY >= ScreenSize.getHeight() + MOUSE_POSITION_Y_ADJUST - 1)
91-
mInputMouseY = ScreenSize.getHeight() + MOUSE_POSITION_Y_ADJUST - 2;
92-
}
116+
// Free cursor mode: wait for window mouse enter event to recapture.
117+
if (!CursorCaptured) {
118+
const uint64 now = static_cast<uint64>(SDL_GetTicks());
119+
const bool canRecapture = (now - mMouse_LeftWindow) > recaptureDelayMs;
120+
const bool inside = mWindow_MouseInside || mWindow->isMouseInside();
121+
122+
if (canRecapture && inside) {
123+
float wx = 0.0f, wy = 0.0f;
124+
SDL_GetMouseState(&wx, &wy);
125+
const cDimension windowSize = mWindow->GetWindowSize();
126+
const bool awayFromEdge =
127+
(wx > edgePadding) &&
128+
(wy > edgePadding) &&
129+
(wx < static_cast<float>(windowSize.getWidth() - edgePadding)) &&
130+
(wy < static_cast<float>(windowSize.getHeight() - edgePadding));
131+
if (!awayFromEdge)
132+
return;
133+
134+
UpdateInputFromWindowPos();
135+
mMouseX = mInputMouseX;
136+
mMouseY = mInputMouseY;
137+
138+
CaptureBlockFrames = 1;
139+
CursorCaptured = true;
93140
mWindow->SetRelativeMouseMode(true);
141+
SDL_HideCursor();
142+
SDL_GetRelativeMouseState(nullptr, nullptr);
143+
mMouse_EventLastPositionRelative = { 0, 0 };
94144
}
95-
} else {
96-
if (!mWindow->isFullscreen()) {
97-
if (!mParams->mMouseLocked) {
98-
cPosition BorderMouse = Mouse_GetOnBorderPosition();
99-
100-
// Cursor leaving window
101-
if (BorderMouse.mX || BorderMouse.mY) {
102-
CursorGrabbed = false;
103-
mMouse_LeftWindow = SDL_GetTicks();
145+
return;
146+
}
104147

105-
mWindow->SetRelativeMouseMode(false);
106-
mWindow->SetMousePosition(BorderMouse);
107-
return;
108-
}
109-
}
148+
if (!mParams->mMouseLocked && !mWindow->isFullscreen()) {
149+
if (Mouse_IsOnBorder() && !mMouseButtonStatus) {
150+
ReleaseCursor(true);
151+
return;
110152
}
153+
}
111154

112-
// hack to avoid moving cursor on window resizing
113-
if (mWindow->isResized()) {
114-
mWindow->ClearResized();
155+
// hack to avoid moving cursor on window resizing
156+
if (mWindow->isResized()) {
157+
mWindow->ClearResized();
115158

159+
} else {
160+
if (CaptureBlockFrames > 0) {
161+
--CaptureBlockFrames;
116162
} else {
117-
if (WasClicked) {
118-
if (!mWindow->isMouseButtonPressed_Global())
119-
WasClicked = false;
120-
} else {
121-
// Calc the distance from the cursor to the centre of the window
122-
mInputMouseX = mMouseX + static_cast<int16>(mMouse_EventLastPositionRelative.mX);
123-
mInputMouseY = mMouseY + static_cast<int16>(mMouse_EventLastPositionRelative.mY);
124-
mMouse_EventLastPositionRelative = { 0,0 };
125-
}
163+
// Calc the distance from the cursor to the centre of the window
164+
mInputMouseX = mMouseX + static_cast<int16>(mMouse_EventLastPositionRelative.mX);
165+
mInputMouseY = mMouseY + static_cast<int16>(mMouse_EventLastPositionRelative.mY);
166+
mMouse_EventLastPositionRelative = { 0,0 };
126167
}
127168
}
128169
}
129170

130-
cPosition cFodder::Mouse_GetOnBorderPosition() {
131-
cPosition BorderMouse;
132-
const cPosition WindowPos = mWindow->GetWindowPosition();
171+
bool cFodder::Mouse_IsOnBorder() const {
133172
const cDimension ScreenSize = mWindow->GetScreenSize();
134-
const cDimension WindowSize = mWindow->GetWindowSize();
135-
const cDimension scale = mWindow->GetScale();
136-
137-
if ((mMouseX <= MOUSE_POSITION_X_ADJUST && mMouseY <= MOUSE_POSITION_Y_ADJUST) ||
138-
(mMouseX >= ScreenSize.getWidth() + MOUSE_POSITION_X_ADJUST - 1 && mMouseY <= MOUSE_POSITION_Y_ADJUST) ||
139-
(mMouseX <= MOUSE_POSITION_X_ADJUST && mMouseY >= ScreenSize.getHeight() + MOUSE_POSITION_Y_ADJUST - 1) ||
140-
(mMouseX >= ScreenSize.getWidth() + MOUSE_POSITION_X_ADJUST - 1 && mMouseY >= ScreenSize.getHeight() + MOUSE_POSITION_Y_ADJUST - 1)) {
141-
BorderMouse.mX = mMouseX <= MOUSE_POSITION_X_ADJUST ? WindowPos.mX - 1 : WindowPos.mX + WindowSize.getWidth() + 1;
142-
BorderMouse.mY = mMouseY <= MOUSE_POSITION_Y_ADJUST ? WindowPos.mY - 1 : WindowPos.mY + WindowSize.getHeight() + 1;
143-
}
144-
// Need to check if the game cursor is near a border on X axis
145-
else if (mMouseX <= MOUSE_POSITION_X_ADJUST || mMouseX >= ScreenSize.getWidth() + MOUSE_POSITION_X_ADJUST - 1) {
146-
BorderMouse.mX = mMouseX <= MOUSE_POSITION_X_ADJUST ? WindowPos.mX - 1 : WindowPos.mX + WindowSize.getWidth() + 1;
147-
BorderMouse.mY = WindowPos.mY + (mMouseY - MOUSE_POSITION_Y_ADJUST) * scale.getHeight();
148-
} // Need to check if the game cursor is near a border Y axis
149-
else if (mMouseY <= MOUSE_POSITION_Y_ADJUST || mMouseY >= ScreenSize.getHeight() + MOUSE_POSITION_Y_ADJUST - 1) {
150-
BorderMouse.mX = WindowPos.mX + (mMouseX - MOUSE_POSITION_X_ADJUST) * scale.getWidth();
151-
BorderMouse.mY = mMouseY <= MOUSE_POSITION_Y_ADJUST ? WindowPos.mY - 1 : WindowPos.mY + WindowSize.getHeight() + 1;
152-
}
153173

154-
return BorderMouse;
174+
if (mMouseX <= MOUSE_POSITION_X_ADJUST)
175+
return true;
176+
if (mMouseX >= ScreenSize.getWidth() + MOUSE_POSITION_X_ADJUST - 1)
177+
return true;
178+
if (mMouseY <= MOUSE_POSITION_Y_ADJUST)
179+
return true;
180+
if (mMouseY >= ScreenSize.getHeight() + MOUSE_POSITION_Y_ADJUST - 1)
181+
return true;
182+
183+
return false;
155184
}
156185

157186
void cFodder::Mouse_ReadInputs() {

0 commit comments

Comments
 (0)