mirror of
https://github.com/cxong/cdogs-sdl.git
synced 2025-07-23 07:23:01 +02:00
Refactor pause menu #284
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -26,7 +26,6 @@ install_manifest_Runtime.txt
|
||||
__pycache__/
|
||||
.cmake/
|
||||
compile_commands.json
|
||||
CMakeSettings.json
|
||||
|
||||
# Generated files
|
||||
src/cdogs/sys_config.h
|
||||
@@ -62,6 +61,7 @@ Win32/
|
||||
*.tmp
|
||||
*.VC.*
|
||||
.vs/
|
||||
CMakeSettings.json
|
||||
VSInheritEnvironments.txt
|
||||
|
||||
# XCode
|
||||
|
@@ -34,6 +34,7 @@ set(CDOGS_SDL_SOURCES
|
||||
menu_utils.c
|
||||
namegen.c
|
||||
password.c
|
||||
pause_menu.c
|
||||
player_select_menus.c
|
||||
prep.c
|
||||
prep_equip.c
|
||||
@@ -57,6 +58,7 @@ set(CDOGS_SDL_HEADERS
|
||||
menu_utils.h
|
||||
namegen.h
|
||||
password.h
|
||||
pause_menu.h
|
||||
player_select_menus.h
|
||||
prep.h
|
||||
prep_equip.h
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
C-Dogs SDL
|
||||
A port of the legendary (and fun) action/arcade cdogs.
|
||||
Copyright (c) 2013-2017, 2019-2020 Cong Xu
|
||||
Copyright (c) 2013-2017, 2019-2020, 2024 Cong Xu
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -120,16 +120,12 @@ static void DrawSharedRadar(GraphicsDevice *device, bool showExit)
|
||||
|
||||
static void DrawPlayerAreas(HUD *hud, const int numViews);
|
||||
static void DrawDeathmatchScores(HUD *hud);
|
||||
static void DrawStateMessage(
|
||||
HUD *hud, const input_device_e pausingDevice,
|
||||
const bool controllerUnplugged);
|
||||
static void DrawMissionState(HUD *hud);
|
||||
static void DrawHUDMessage(HUD *hud);
|
||||
static void DrawKeycards(HUD *hud);
|
||||
static void DrawMissionTime(HUD *hud);
|
||||
static void DrawObjectiveCounts(HUD *hud);
|
||||
void HUDDraw(
|
||||
HUD *hud, const input_device_e pausingDevice,
|
||||
const bool controllerUnplugged, const int numViews)
|
||||
void HUDDraw(HUD *hud, const int numViews, const bool paused)
|
||||
{
|
||||
if (ConfigGetBool(&gConfig, "Graphics.ShowHUD"))
|
||||
{
|
||||
@@ -153,7 +149,10 @@ void HUDDraw(
|
||||
}
|
||||
}
|
||||
|
||||
DrawStateMessage(hud, pausingDevice, controllerUnplugged);
|
||||
if (!paused)
|
||||
{
|
||||
DrawMissionState(hud);
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawPlayerAreas(HUD *hud, const int numViews)
|
||||
@@ -282,79 +281,6 @@ static void DrawDeathmatchScores(HUD *hud)
|
||||
CA_FOREACH_END()
|
||||
}
|
||||
|
||||
static void DrawMissionState(HUD *hud);
|
||||
static void DrawStateMessage(
|
||||
HUD *hud, const input_device_e pausingDevice,
|
||||
const bool controllerUnplugged)
|
||||
{
|
||||
if (controllerUnplugged || pausingDevice != INPUT_DEVICE_UNSET)
|
||||
{
|
||||
// Draw a background overlay
|
||||
color_t overlay = colorBlack;
|
||||
overlay.a = 128;
|
||||
DrawRectangle(
|
||||
hud->device, svec2i_zero(), hud->device->cachedConfig.Res, overlay,
|
||||
true);
|
||||
}
|
||||
if (controllerUnplugged)
|
||||
{
|
||||
struct vec2i pos = svec2i_scale_divide(
|
||||
svec2i_subtract(
|
||||
gGraphicsDevice.cachedConfig.Res,
|
||||
FontStrSize(ARROW_LEFT
|
||||
"Paused" ARROW_RIGHT
|
||||
"\nFoobar\nPlease reconnect controller")),
|
||||
2);
|
||||
const int x = pos.x;
|
||||
FontStr(ARROW_LEFT "Paused" ARROW_RIGHT, pos);
|
||||
|
||||
pos.y += FontH();
|
||||
pos = FontStr("Press ", pos);
|
||||
char buf[256];
|
||||
color_t c = colorWhite;
|
||||
InputGetButtonNameColor(pausingDevice, 0, CMD_ESC, buf, &c);
|
||||
pos = FontStrMask(buf, pos, c);
|
||||
FontStr(" to quit", pos);
|
||||
|
||||
pos.x = x;
|
||||
pos.y += FontH();
|
||||
FontStr("Please reconnect controller", pos);
|
||||
}
|
||||
else if (pausingDevice != INPUT_DEVICE_UNSET)
|
||||
{
|
||||
struct vec2i pos = svec2i_scale_divide(
|
||||
svec2i_subtract(
|
||||
gGraphicsDevice.cachedConfig.Res,
|
||||
FontStrSize("Foo\nPress foo or bar to unpause\nBaz")),
|
||||
2);
|
||||
const int x = pos.x;
|
||||
FontStr(ARROW_LEFT "Paused" ARROW_RIGHT, pos);
|
||||
|
||||
pos.y += FontH();
|
||||
pos = FontStr("Press ", pos);
|
||||
char buf[256];
|
||||
color_t c = colorWhite;
|
||||
InputGetButtonNameColor(pausingDevice, 0, CMD_ESC, buf, &c);
|
||||
pos = FontStrMask(buf, pos, c);
|
||||
FontStr(" again to quit", pos);
|
||||
|
||||
pos.x = x;
|
||||
pos.y += FontH();
|
||||
pos = FontStr("Press ", pos);
|
||||
c = colorWhite;
|
||||
InputGetButtonNameColor(pausingDevice, 0, CMD_BUTTON1, buf, &c);
|
||||
pos = FontStrMask(buf, pos, c);
|
||||
pos = FontStr(" or ", pos);
|
||||
c = colorWhite;
|
||||
InputGetButtonNameColor(pausingDevice, 0, CMD_BUTTON2, buf, &c);
|
||||
pos = FontStrMask(buf, pos, c);
|
||||
FontStr(" to unpause", pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawMissionState(hud);
|
||||
}
|
||||
}
|
||||
static void DrawMissionState(HUD *hud)
|
||||
{
|
||||
char s[50];
|
||||
|
@@ -77,6 +77,4 @@ HUDDrawData HUDGetDrawData(void);
|
||||
|
||||
void HUDUpdate(HUD *hud, const int ms);
|
||||
|
||||
void HUDDraw(
|
||||
HUD *hud, const input_device_e pausingDevice,
|
||||
const bool controllerUnplugged, const int numViews);
|
||||
void HUDDraw(HUD *hud, const int numViews, const bool paused);
|
||||
|
100
src/game.c
100
src/game.c
@@ -86,8 +86,8 @@ static void PlayerSpecialCommands(TActor *actor, const int cmd)
|
||||
}
|
||||
}
|
||||
else if (
|
||||
!Button2(actor->lastCmd) && Button2(cmd) &&
|
||||
!actor->specialCmdDir && !actor->CanPickupSpecial &&
|
||||
!Button2(actor->lastCmd) && Button2(cmd) && !actor->specialCmdDir &&
|
||||
!actor->CanPickupSpecial &&
|
||||
!(ConfigGetEnum(&gConfig, "Game.SwitchMoveStyle") ==
|
||||
SWITCHMOVE_SLIDE &&
|
||||
CMD_HAS_DIRECTION(cmd)))
|
||||
@@ -216,6 +216,8 @@ static void RunGameOnEnter(GameLoopData *data)
|
||||
}
|
||||
}
|
||||
|
||||
PauseMenuInit(&rData->pm, &gEventHandlers, &gGraphicsDevice);
|
||||
|
||||
rData->m->state = MISSION_STATE_WAITING;
|
||||
rData->m->isDone = false;
|
||||
rData->m->DoneCounter = 0;
|
||||
@@ -264,6 +266,7 @@ static void RunGameOnExit(GameLoopData *data)
|
||||
CA_FOREACH_END()
|
||||
CArrayTerminate(&rData->ammoSpawners);
|
||||
CameraTerminate(&rData->Camera);
|
||||
PauseMenuTerminate(&rData->pm);
|
||||
|
||||
// Draw background
|
||||
GrafxRedrawBackground(&gGraphicsDevice, rData->Camera.lastPosition);
|
||||
@@ -311,17 +314,14 @@ static void RunGameInput(GameLoopData *data)
|
||||
}
|
||||
memset(rData->cmds, 0, sizeof rData->cmds);
|
||||
int cmdAll = 0;
|
||||
int idx = 0;
|
||||
input_device_e pausingDevice = INPUT_DEVICE_UNSET;
|
||||
input_device_e firstPausingDevice = INPUT_DEVICE_UNSET;
|
||||
if (GetNumPlayers(PLAYER_ANY, false, true) == 0)
|
||||
{
|
||||
// If no players, allow default keyboard to control camera
|
||||
rData->cmds[0] = GetKeyboardCmd(&gEventHandlers.keyboard, 0, false);
|
||||
firstPausingDevice = INPUT_DEVICE_KEYBOARD;
|
||||
}
|
||||
else
|
||||
{
|
||||
int idx = 0;
|
||||
for (int i = 0; i < (int)gPlayerDatas.size; i++, idx++)
|
||||
{
|
||||
const PlayerData *p = CArrayGet(&gPlayerDatas, i);
|
||||
@@ -330,87 +330,29 @@ static void RunGameInput(GameLoopData *data)
|
||||
idx--;
|
||||
continue;
|
||||
}
|
||||
if (firstPausingDevice == INPUT_DEVICE_UNSET)
|
||||
{
|
||||
firstPausingDevice = p->inputDevice;
|
||||
}
|
||||
rData->cmds[idx] = GetGameCmd(&gEventHandlers, p);
|
||||
cmdAll |= rData->cmds[idx];
|
||||
|
||||
// Only allow the first player to escape
|
||||
// Use keypress otherwise the player will quit immediately
|
||||
if (idx == 0 && (rData->cmds[idx] & CMD_ESC) &&
|
||||
!(rData->lastCmds[idx] & CMD_ESC))
|
||||
{
|
||||
pausingDevice = p->inputDevice;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (KeyIsPressed(&gEventHandlers.keyboard, SDL_SCANCODE_ESCAPE))
|
||||
{
|
||||
pausingDevice = INPUT_DEVICE_KEYBOARD;
|
||||
}
|
||||
|
||||
// Check if any controllers are unplugged
|
||||
rData->controllerUnplugged = false;
|
||||
CA_FOREACH(const PlayerData, p, gPlayerDatas)
|
||||
if (p->inputDevice == INPUT_DEVICE_UNSET && p->IsLocal)
|
||||
{
|
||||
rData->controllerUnplugged = true;
|
||||
break;
|
||||
}
|
||||
CA_FOREACH_END()
|
||||
|
||||
// If in Superhot(tm) Mode, don't update unless there was an input in this
|
||||
// or the last frame
|
||||
data->SkipNextFrame = data->SuperhotMode && !lastCmdAll;
|
||||
|
||||
// Check if:
|
||||
// - escape was pressed, or
|
||||
// - window lost focus
|
||||
// - controller unplugged
|
||||
// If the game is paused, unpause if a button is released
|
||||
// If the game was not paused, enter pause mode
|
||||
// If the game was paused and escape was pressed, exit the game
|
||||
if (rData->pausingDevice != INPUT_DEVICE_UNSET && AnyButton(lastCmdAll) &&
|
||||
!AnyButton(cmdAll))
|
||||
// Update and check if we want to quit
|
||||
if (PauseMenuUpdate(&rData->pm, rData->cmds, rData->lastCmds))
|
||||
{
|
||||
rData->pausingDevice = INPUT_DEVICE_UNSET;
|
||||
}
|
||||
else if (rData->controllerUnplugged || gEventHandlers.HasLostFocus)
|
||||
{
|
||||
// Pause the game
|
||||
rData->pausingDevice = firstPausingDevice;
|
||||
rData->isMap = false;
|
||||
SoundPlay(&gSoundDevice, StrSound("menu_error"));
|
||||
}
|
||||
else if (pausingDevice != INPUT_DEVICE_UNSET)
|
||||
{
|
||||
if (rData->pausingDevice != INPUT_DEVICE_UNSET)
|
||||
{
|
||||
// Already paused; exit
|
||||
GameEvent e = GameEventNew(GAME_EVENT_MISSION_END);
|
||||
e.u.MissionEnd.IsQuit = true;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
// Need to unpause to process the quit
|
||||
rData->pausingDevice = INPUT_DEVICE_UNSET;
|
||||
rData->controllerUnplugged = false;
|
||||
// Don't skip exiting the game
|
||||
data->SkipNextFrame = false;
|
||||
SoundPlay(&gSoundDevice, StrSound("menu_back"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pause the game
|
||||
rData->pausingDevice = pausingDevice;
|
||||
rData->isMap = false;
|
||||
SoundPlay(&gSoundDevice, StrSound("menu_back"));
|
||||
}
|
||||
// Need to unpause to process the quit
|
||||
data->SkipNextFrame = true;
|
||||
}
|
||||
|
||||
const bool paused = rData->pausingDevice != INPUT_DEVICE_UNSET ||
|
||||
rData->controllerUnplugged;
|
||||
if (!paused)
|
||||
// Don't show map if pause menu is shown
|
||||
if (PauseMenuIsShown(&rData->pm))
|
||||
{
|
||||
rData->isMap = false;
|
||||
}
|
||||
|
||||
if (!PauseMenuIsShown(&rData->pm))
|
||||
{
|
||||
// Check if automap key is pressed by any player
|
||||
// Toggle
|
||||
@@ -464,8 +406,7 @@ static GameLoopResult RunGameUpdate(GameLoopData *data, LoopRunner *l)
|
||||
// If we're not hosting a net game,
|
||||
// don't update if the game has paused or has automap shown
|
||||
// Important: don't consider paused if we are trying to quit
|
||||
const bool paused = rData->pausingDevice != INPUT_DEVICE_UNSET ||
|
||||
rData->controllerUnplugged || rData->isMap;
|
||||
const bool paused = PauseMenuIsShown(&rData->pm) || rData->isMap;
|
||||
if (!gCampaign.IsClient && !ConfigGetBool(&gConfig, "StartServer") &&
|
||||
paused && !gEventHandlers.HasQuit)
|
||||
{
|
||||
@@ -700,9 +641,8 @@ static void RunGameDraw(GameLoopData *data)
|
||||
// Draw HUD layer
|
||||
BlitClearBuf(&gGraphicsDevice);
|
||||
CameraDrawMode(&rData->Camera);
|
||||
HUDDraw(
|
||||
&rData->Camera.HUD, rData->pausingDevice, rData->controllerUnplugged,
|
||||
rData->Camera.NumViews);
|
||||
HUDDraw(&rData->Camera.HUD, rData->Camera.NumViews, PauseMenuIsShown(&rData->pm));
|
||||
PauseMenuDraw(&rData->pm);
|
||||
// Draw automap if enabled
|
||||
if (rData->isMap)
|
||||
{
|
||||
|
@@ -22,7 +22,7 @@
|
||||
This file incorporates work covered by the following copyright and
|
||||
permission notice:
|
||||
|
||||
Copyright (c) 2015, 2017, 2020-2021 Cong Xu
|
||||
Copyright (c) 2015, 2017, 2020-2021, 2024 Cong Xu
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -58,6 +58,7 @@
|
||||
#include <cdogs/powerup.h>
|
||||
|
||||
#include "game_loop.h"
|
||||
#include "pause_menu.h"
|
||||
|
||||
GameLoopData *RunGame(Campaign *co, struct MissionOptions *m, Map *map);
|
||||
|
||||
@@ -67,9 +68,7 @@ typedef struct
|
||||
struct MissionOptions *m;
|
||||
Map *map;
|
||||
Camera Camera;
|
||||
// TODO: turn the following into a screen system?
|
||||
input_device_e pausingDevice; // INPUT_DEVICE_UNSET if not paused
|
||||
bool controllerUnplugged;
|
||||
PauseMenu pm;
|
||||
bool isMap;
|
||||
int cmds[MAX_LOCAL_PLAYERS];
|
||||
int lastCmds[MAX_LOCAL_PLAYERS];
|
||||
|
226
src/pause_menu.c
Normal file
226
src/pause_menu.c
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
C-Dogs SDL
|
||||
A port of the legendary (and fun) action/arcade cdogs.
|
||||
Copyright (c) 2024 Cong Xu
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "pause_menu.h"
|
||||
|
||||
#include <cdogs/draw/drawtools.h>
|
||||
#include <cdogs/font.h>
|
||||
|
||||
void PauseMenuInit(PauseMenu *pm, EventHandlers *handlers, GraphicsDevice *g)
|
||||
{
|
||||
memset(pm, 0, sizeof *pm);
|
||||
MenuSystemInit(&pm->ms, handlers, g, svec2i_zero(), g->cachedConfig.Res);
|
||||
// TODO: create pause menu
|
||||
pm->handlers = handlers;
|
||||
pm->g = g;
|
||||
pm->pausingDevice = INPUT_DEVICE_UNSET;
|
||||
}
|
||||
void PauseMenuTerminate(PauseMenu *pm)
|
||||
{
|
||||
MenuSystemTerminate(&pm->ms);
|
||||
}
|
||||
|
||||
bool PauseMenuUpdate(
|
||||
PauseMenu *pm, const int cmds[MAX_LOCAL_PLAYERS],
|
||||
const int lastCmds[MAX_LOCAL_PLAYERS])
|
||||
{
|
||||
int cmdAll = 0;
|
||||
int lastCmdAll = 0;
|
||||
for (int i = 0; i < MAX_LOCAL_PLAYERS; i++)
|
||||
{
|
||||
lastCmdAll |= lastCmds[i];
|
||||
}
|
||||
|
||||
input_device_e pausingDevice = INPUT_DEVICE_UNSET;
|
||||
input_device_e firstPausingDevice = INPUT_DEVICE_UNSET;
|
||||
if (GetNumPlayers(PLAYER_ANY, false, true) == 0)
|
||||
{
|
||||
// If no players, allow default keyboard
|
||||
firstPausingDevice = INPUT_DEVICE_KEYBOARD;
|
||||
cmdAll |= cmds[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
int idx = 0;
|
||||
for (int i = 0; i < (int)gPlayerDatas.size; i++, idx++)
|
||||
{
|
||||
const PlayerData *p = CArrayGet(&gPlayerDatas, i);
|
||||
if (!p->IsLocal)
|
||||
{
|
||||
idx--;
|
||||
continue;
|
||||
}
|
||||
cmdAll |= cmds[idx];
|
||||
if (firstPausingDevice == INPUT_DEVICE_UNSET)
|
||||
{
|
||||
firstPausingDevice = p->inputDevice;
|
||||
}
|
||||
|
||||
// Only allow the first player to escape
|
||||
// Use keypress otherwise the player will quit immediately
|
||||
if (idx == 0 && (cmds[idx] & CMD_ESC) &&
|
||||
!(lastCmds[idx] & CMD_ESC))
|
||||
{
|
||||
pausingDevice = p->inputDevice;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (KeyIsPressed(&gEventHandlers.keyboard, SDL_SCANCODE_ESCAPE))
|
||||
{
|
||||
pausingDevice = INPUT_DEVICE_KEYBOARD;
|
||||
}
|
||||
|
||||
// Check if any controllers are unplugged
|
||||
pm->controllerUnplugged = false;
|
||||
CA_FOREACH(const PlayerData, p, gPlayerDatas)
|
||||
if (p->inputDevice == INPUT_DEVICE_UNSET && p->IsLocal)
|
||||
{
|
||||
pm->controllerUnplugged = true;
|
||||
break;
|
||||
}
|
||||
CA_FOREACH_END()
|
||||
|
||||
// Check if:
|
||||
// - escape was pressed, or
|
||||
// - window lost focus
|
||||
// - controller unplugged
|
||||
// If the game is paused, update the pause menu
|
||||
// If the game was not paused, enter pause mode
|
||||
// If the game was paused and escape was pressed, exit the game
|
||||
if (pm->pausingDevice != INPUT_DEVICE_UNSET && AnyButton(lastCmdAll) &&
|
||||
!AnyButton(cmdAll))
|
||||
{
|
||||
// Unpause on any button press
|
||||
// TODO: don't do this, update menu system instead
|
||||
pm->pausingDevice = INPUT_DEVICE_UNSET;
|
||||
}
|
||||
else if (pm->controllerUnplugged || gEventHandlers.HasLostFocus)
|
||||
{
|
||||
// Pause the game
|
||||
pm->pausingDevice = firstPausingDevice;
|
||||
SoundPlay(&gSoundDevice, StrSound("menu_error"));
|
||||
}
|
||||
else if (pausingDevice != INPUT_DEVICE_UNSET)
|
||||
{
|
||||
if (pm->pausingDevice != INPUT_DEVICE_UNSET)
|
||||
{
|
||||
// Already paused; exit
|
||||
// TODO: don't exit, use pause menu
|
||||
GameEvent e = GameEventNew(GAME_EVENT_MISSION_END);
|
||||
e.u.MissionEnd.IsQuit = true;
|
||||
GameEventsEnqueue(&gGameEvents, e);
|
||||
// Need to unpause to process the quit
|
||||
pm->pausingDevice = INPUT_DEVICE_UNSET;
|
||||
pm->controllerUnplugged = false;
|
||||
SoundPlay(&gSoundDevice, StrSound("menu_back"));
|
||||
// Return true to say we want to quit
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pause the game
|
||||
pm->pausingDevice = pausingDevice;
|
||||
SoundPlay(&gSoundDevice, StrSound("menu_back"));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void PauseMenuDraw(const PauseMenu *pm)
|
||||
{
|
||||
if (!PauseMenuIsShown(pm))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw a background overlay
|
||||
color_t overlay = colorBlack;
|
||||
overlay.a = 128;
|
||||
DrawRectangle(
|
||||
pm->g, svec2i_zero(), pm->g->cachedConfig.Res, overlay, true);
|
||||
|
||||
if (pm->controllerUnplugged)
|
||||
{
|
||||
struct vec2i pos = svec2i_scale_divide(
|
||||
svec2i_subtract(
|
||||
pm->g->cachedConfig.Res,
|
||||
FontStrSize(ARROW_LEFT
|
||||
"Paused" ARROW_RIGHT
|
||||
"\nFoobar\nPlease reconnect controller")),
|
||||
2);
|
||||
const int x = pos.x;
|
||||
FontStr(ARROW_LEFT "Paused" ARROW_RIGHT, pos);
|
||||
|
||||
pos.y += FontH();
|
||||
pos = FontStr("Press ", pos);
|
||||
char buf[256];
|
||||
color_t c = colorWhite;
|
||||
InputGetButtonNameColor(pm->pausingDevice, 0, CMD_ESC, buf, &c);
|
||||
pos = FontStrMask(buf, pos, c);
|
||||
FontStr(" to quit", pos);
|
||||
|
||||
pos.x = x;
|
||||
pos.y += FontH();
|
||||
FontStr("Please reconnect controller", pos);
|
||||
}
|
||||
else if (pm->pausingDevice != INPUT_DEVICE_UNSET)
|
||||
{
|
||||
struct vec2i pos = svec2i_scale_divide(
|
||||
svec2i_subtract(
|
||||
gGraphicsDevice.cachedConfig.Res,
|
||||
FontStrSize("Foo\nPress foo or bar to unpause\nBaz")),
|
||||
2);
|
||||
const int x = pos.x;
|
||||
FontStr(ARROW_LEFT "Paused" ARROW_RIGHT, pos);
|
||||
|
||||
pos.y += FontH();
|
||||
pos = FontStr("Press ", pos);
|
||||
char buf[256];
|
||||
color_t c = colorWhite;
|
||||
InputGetButtonNameColor(pm->pausingDevice, 0, CMD_ESC, buf, &c);
|
||||
pos = FontStrMask(buf, pos, c);
|
||||
FontStr(" again to quit", pos);
|
||||
|
||||
pos.x = x;
|
||||
pos.y += FontH();
|
||||
pos = FontStr("Press ", pos);
|
||||
c = colorWhite;
|
||||
InputGetButtonNameColor(pm->pausingDevice, 0, CMD_BUTTON1, buf, &c);
|
||||
pos = FontStrMask(buf, pos, c);
|
||||
pos = FontStr(" or ", pos);
|
||||
c = colorWhite;
|
||||
InputGetButtonNameColor(pm->pausingDevice, 0, CMD_BUTTON2, buf, &c);
|
||||
pos = FontStrMask(buf, pos, c);
|
||||
FontStr(" to unpause", pos);
|
||||
}
|
||||
}
|
||||
|
||||
bool PauseMenuIsShown(const PauseMenu *pm)
|
||||
{
|
||||
return pm->pausingDevice != INPUT_DEVICE_UNSET || pm->controllerUnplugged;
|
||||
}
|
50
src/pause_menu.h
Normal file
50
src/pause_menu.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
C-Dogs SDL
|
||||
A port of the legendary (and fun) action/arcade cdogs.
|
||||
Copyright (c) 2024 Cong Xu
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "menu.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MenuSystem ms;
|
||||
EventHandlers *handlers;
|
||||
GraphicsDevice *g;
|
||||
input_device_e pausingDevice; // INPUT_DEVICE_UNSET if not paused
|
||||
bool controllerUnplugged;
|
||||
} PauseMenu;
|
||||
|
||||
void PauseMenuInit(PauseMenu *pm, EventHandlers *handlers, GraphicsDevice *g);
|
||||
void PauseMenuTerminate(PauseMenu *pm);
|
||||
|
||||
// Returns whether to quit
|
||||
bool PauseMenuUpdate(
|
||||
PauseMenu *pm, const int cmds[MAX_LOCAL_PLAYERS],
|
||||
const int lastCmds[MAX_LOCAL_PLAYERS]);
|
||||
void PauseMenuDraw(const PauseMenu *pm);
|
||||
|
||||
bool PauseMenuIsShown(const PauseMenu *pm);
|
Reference in New Issue
Block a user