mirror of
https://github.com/cxong/cdogs-sdl.git
synced 2025-07-23 07:23:01 +02:00
Options in pause menu #284
This commit is contained in:
@@ -33,6 +33,7 @@ set(CDOGS_SDL_SOURCES
|
||||
menu.c
|
||||
menu_utils.c
|
||||
namegen.c
|
||||
options_menu.c
|
||||
password.c
|
||||
pause_menu.c
|
||||
player_select_menus.c
|
||||
@@ -57,6 +58,7 @@ set(CDOGS_SDL_HEADERS
|
||||
menu.h
|
||||
menu_utils.h
|
||||
namegen.h
|
||||
options_menu.h
|
||||
password.h
|
||||
pause_menu.h
|
||||
player_select_menus.h
|
||||
|
19
src/game.c
19
src/game.c
@@ -134,6 +134,17 @@ static void RunGameReset(RunGameData *rData)
|
||||
BlitUpdateFromBuf(&gGraphicsDevice, gGraphicsDevice.bkg);
|
||||
CameraReset(&rData->Camera);
|
||||
}
|
||||
static void OnGfxChangeCallback(void *data, const bool resetBg)
|
||||
{
|
||||
RunGameData *rData = data;
|
||||
if (resetBg)
|
||||
{
|
||||
RunGameReset(rData);
|
||||
}
|
||||
rData->pm.ms.size = svec2i(
|
||||
rData->pm.ms.graphics->cachedConfig.Res.x,
|
||||
rData->pm.ms.graphics->cachedConfig.Res.y);
|
||||
}
|
||||
static void RunGameTerminate(GameLoopData *data)
|
||||
{
|
||||
RunGameData *rData = data->Data;
|
||||
@@ -216,7 +227,9 @@ static void RunGameOnEnter(GameLoopData *data)
|
||||
}
|
||||
}
|
||||
|
||||
PauseMenuInit(&rData->pm, &gEventHandlers, &gGraphicsDevice);
|
||||
PauseMenuInit(
|
||||
&rData->pm, &gEventHandlers, &gGraphicsDevice, OnGfxChangeCallback,
|
||||
rData);
|
||||
|
||||
rData->m->state = MISSION_STATE_WAITING;
|
||||
rData->m->isDone = false;
|
||||
@@ -645,7 +658,9 @@ static void RunGameDraw(GameLoopData *data)
|
||||
// Draw HUD layer
|
||||
BlitClearBuf(&gGraphicsDevice);
|
||||
CameraDrawMode(&rData->Camera);
|
||||
HUDDraw(&rData->Camera.HUD, rData->Camera.NumViews, PauseMenuIsShown(&rData->pm));
|
||||
HUDDraw(
|
||||
&rData->Camera.HUD, rData->Camera.NumViews,
|
||||
PauseMenuIsShown(&rData->pm));
|
||||
PauseMenuDraw(&rData->pm);
|
||||
// Draw automap if enabled
|
||||
if (rData->isMap)
|
||||
|
263
src/mainmenu.c
263
src/mainmenu.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2013-2022 Cong Xu
|
||||
Copyright (c) 2013-2022, 2024 Cong Xu
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -49,11 +49,13 @@
|
||||
#include "game.h"
|
||||
#include "loading_screens.h"
|
||||
#include "menu.h"
|
||||
#include "options_menu.h"
|
||||
#include "prep.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MenuSystem ms;
|
||||
OptionsMenuData oData;
|
||||
GraphicsDevice *graphics;
|
||||
credits_displayer_t creditsDisplayer;
|
||||
CustomCampaigns campaigns;
|
||||
@@ -103,7 +105,9 @@ static void GenerateLiveBackground(MainMenuData *data)
|
||||
GameEventsInit(&gGameEvents);
|
||||
gCampaign.MissionIndex = 0;
|
||||
|
||||
MapBuild(&gMap, gMission.missionData, true, gMission.index, GAME_MODE_NORMAL, &gCampaign.Setting.characters);
|
||||
MapBuild(
|
||||
&gMap, gMission.missionData, true, gMission.index, GAME_MODE_NORMAL,
|
||||
&gCampaign.Setting.characters);
|
||||
|
||||
// Add AI player
|
||||
GameEvent e = GameEventNew(GAME_EVENT_PLAYER_DATA);
|
||||
@@ -125,12 +129,21 @@ static void GenerateLiveBackground(MainMenuData *data)
|
||||
|
||||
GameInit(&data->rData, &gCampaign, &gMission, &gMap);
|
||||
}
|
||||
static void OnGfxChange(void *data, const bool resetBg)
|
||||
{
|
||||
MainMenuData *mData = data;
|
||||
if (resetBg)
|
||||
{
|
||||
GenerateLiveBackground(mData);
|
||||
}
|
||||
MenuResetSize(&mData->ms);
|
||||
}
|
||||
static void MainMenuReset(MainMenuData *data)
|
||||
{
|
||||
GenerateLiveBackground(data);
|
||||
|
||||
MenuResetSize(&data->ms);
|
||||
|
||||
|
||||
data->entry = NULL;
|
||||
}
|
||||
static void MainMenuTerminate(GameLoopData *data)
|
||||
@@ -217,7 +230,10 @@ static GameLoopResult MainMenuUpdate(GameLoopData *data, LoopRunner *l)
|
||||
if (gCampaign.IsLoaded)
|
||||
{
|
||||
// Loaded game already; skip menus and go straight to game
|
||||
LoopRunnerPush(l, ScreenCampaignIntro(&gCampaign.Setting, gCampaign.Entry.Mode, &gCampaign.Entry));
|
||||
LoopRunnerPush(
|
||||
l,
|
||||
ScreenCampaignIntro(
|
||||
&gCampaign.Setting, gCampaign.Entry.Mode, &gCampaign.Entry));
|
||||
return UPDATE_RESULT_OK;
|
||||
}
|
||||
|
||||
@@ -229,7 +245,12 @@ static GameLoopResult MainMenuUpdate(GameLoopData *data, LoopRunner *l)
|
||||
{
|
||||
if (mData->entry)
|
||||
{
|
||||
LoopRunnerPush(l, ScreenLoading("Loading game...", true, ScreenCampaignIntro(&gCampaign.Setting, mData->gameMode, mData->entry), false));
|
||||
LoopRunnerPush(
|
||||
l, ScreenLoading(
|
||||
"Loading game...", true,
|
||||
ScreenCampaignIntro(
|
||||
&gCampaign.Setting, mData->gameMode, mData->entry),
|
||||
false));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -261,8 +282,6 @@ static void MainMenuDraw(GameLoopData *data)
|
||||
|
||||
static menu_t *MenuCreateStart(
|
||||
const char *name, MainMenuData *mainMenu, LoopRunner *l);
|
||||
static menu_t *MenuCreateOptions(const char *name, MainMenuData *data);
|
||||
menu_t *MenuCreateQuit(const char *name);
|
||||
|
||||
static void MenuCreateAll(
|
||||
MainMenuData *data, LoopRunner *l, EventHandlers *handlers)
|
||||
@@ -273,12 +292,14 @@ static void MenuCreateAll(
|
||||
data->ms.root = data->ms.current = MenuCreateNormal(
|
||||
"", "", MENU_TYPE_NORMAL,
|
||||
MENU_DISPLAY_ITEMS_CREDITS | MENU_DISPLAY_ITEMS_AUTHORS);
|
||||
MenuAddSubmenu(
|
||||
data->ms.root,
|
||||
MenuCreateStart("Start", data, l));
|
||||
MenuAddSubmenu(data->ms.root, MenuCreateOptions("Options...", data));
|
||||
MenuAddSubmenu(data->ms.root, MenuCreateStart("Start", data, l));
|
||||
data->oData.config = &gConfig;
|
||||
data->oData.gfxChangeCallback = OnGfxChange;
|
||||
data->oData.gfxChangeData = data;
|
||||
data->oData.ms = &data->ms;
|
||||
MenuAddSubmenu(data->ms.root, MenuCreateOptions("Options...", &data->oData));
|
||||
#ifndef __EMSCRIPTEN__
|
||||
MenuAddSubmenu(data->ms.root, MenuCreateQuit("Quit"));
|
||||
MenuAddSubmenu(data->ms.root, MenuCreate("Quit", MENU_TYPE_QUIT));
|
||||
MenuAddExitType(&data->ms, MENU_TYPE_QUIT);
|
||||
#endif
|
||||
MenuAddExitType(&data->ms, MENU_TYPE_RETURN);
|
||||
@@ -290,10 +311,11 @@ typedef struct
|
||||
// so we can enable it if LAN servers are found
|
||||
int MenuJoinIndex;
|
||||
} CheckLANServerData;
|
||||
static menu_t *MenuCreateContinue(const char *name, MainMenuData *mainMenu, const CampaignEntry *entry);
|
||||
static menu_t *MenuCreateContinue(
|
||||
const char *name, MainMenuData *mainMenu, const CampaignEntry *entry);
|
||||
static menu_t *MenuCreateCampaigns(
|
||||
const char *name, const char *title, MainMenuData *mainMenu, CampaignList *list,
|
||||
const GameMode mode);
|
||||
const char *name, const char *title, MainMenuData *mainMenu,
|
||||
CampaignList *list, const GameMode mode);
|
||||
static menu_t *CreateJoinLANGame(
|
||||
const char *name, const char *title, MenuSystem *ms, LoopRunner *l);
|
||||
static void CheckLANServers(menu_t *menu, void *data);
|
||||
@@ -307,18 +329,19 @@ static menu_t *MenuCreateStart(
|
||||
const int menuContinueIndex = (int)menu->u.normal.subMenus.size - 1;
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateCampaigns(
|
||||
"Campaign", "Select a campaign:", mainMenu, &mainMenu->campaigns.campaignList,
|
||||
GAME_MODE_NORMAL));
|
||||
"Campaign", "Select a campaign:", mainMenu,
|
||||
&mainMenu->campaigns.campaignList, GAME_MODE_NORMAL));
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateCampaigns(
|
||||
"Dogfight", "Select a dogfight scenario:",
|
||||
mainMenu, &mainMenu->campaigns.dogfightList, GAME_MODE_DOGFIGHT));
|
||||
"Dogfight", "Select a dogfight scenario:", mainMenu,
|
||||
&mainMenu->campaigns.dogfightList, GAME_MODE_DOGFIGHT));
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateCampaigns(
|
||||
"Deathmatch", "Select a deathmatch scenario:",
|
||||
mainMenu, &mainMenu->campaigns.dogfightList, GAME_MODE_DEATHMATCH));
|
||||
"Deathmatch", "Select a deathmatch scenario:", mainMenu,
|
||||
&mainMenu->campaigns.dogfightList, GAME_MODE_DEATHMATCH));
|
||||
MenuAddSubmenu(
|
||||
menu, CreateJoinLANGame("Join LAN game", "Choose LAN server", &mainMenu->ms, l));
|
||||
menu, CreateJoinLANGame(
|
||||
"Join LAN game", "Choose LAN server", &mainMenu->ms, l));
|
||||
CheckLANServerData *cdata;
|
||||
CMALLOC(cdata, sizeof *cdata);
|
||||
cdata->MenuJoinIndex = (int)menu->u.normal.subMenus.size - 1;
|
||||
@@ -345,7 +368,8 @@ typedef struct
|
||||
} StartGameModeData;
|
||||
static void StartGameMode(menu_t *menu, void *data);
|
||||
static menu_t *CreateStartGameMode(
|
||||
const char *name, MainMenuData *mainMenu, GameMode mode, const CampaignEntry *entry)
|
||||
const char *name, MainMenuData *mainMenu, GameMode mode,
|
||||
const CampaignEntry *entry)
|
||||
{
|
||||
menu_t *menu = MenuCreate(name, MENU_TYPE_RETURN);
|
||||
menu->enterSound = MENU_SOUND_START;
|
||||
@@ -364,12 +388,14 @@ static void StartGameMode(menu_t *menu, void *data)
|
||||
mData->MainMenu->gameMode = mData->GameMode;
|
||||
mData->MainMenu->entry = mData->Entry;
|
||||
}
|
||||
static menu_t *MenuCreateContinue(const char *name, MainMenuData *mainMenu, const CampaignEntry *entry)
|
||||
static menu_t *MenuCreateContinue(
|
||||
const char *name, MainMenuData *mainMenu, const CampaignEntry *entry)
|
||||
{
|
||||
return CreateStartGameMode(name, mainMenu, GAME_MODE_NORMAL, entry);
|
||||
}
|
||||
|
||||
static menu_t *MenuCreateCampaignItem(MainMenuData *mainMenu, CampaignEntry *entry, const GameMode mode);
|
||||
static menu_t *MenuCreateCampaignItem(
|
||||
MainMenuData *mainMenu, CampaignEntry *entry, const GameMode mode);
|
||||
|
||||
static void CampaignsDisplayFilename(
|
||||
const menu_t *menu, GraphicsDevice *g, const struct vec2i pos,
|
||||
@@ -400,8 +426,8 @@ static void CampaignsDisplayFilename(
|
||||
FontStrOpt(s, pos, opts);
|
||||
}
|
||||
static menu_t *MenuCreateCampaigns(
|
||||
const char *name, const char *title, MainMenuData *mainMenu, CampaignList *list,
|
||||
const GameMode mode)
|
||||
const char *name, const char *title, MainMenuData *mainMenu,
|
||||
CampaignList *list, const GameMode mode)
|
||||
{
|
||||
menu_t *menu = MenuCreateNormal(name, title, MENU_TYPE_NORMAL, 0);
|
||||
menu->u.normal.maxItems = 20;
|
||||
@@ -419,7 +445,8 @@ static menu_t *MenuCreateCampaigns(
|
||||
return menu;
|
||||
}
|
||||
|
||||
static menu_t *MenuCreateCampaignItem(MainMenuData *mainMenu, CampaignEntry *entry, const GameMode mode)
|
||||
static menu_t *MenuCreateCampaignItem(
|
||||
MainMenuData *mainMenu, CampaignEntry *entry, const GameMode mode)
|
||||
{
|
||||
menu_t *menu = CreateStartGameMode(entry->Info, mainMenu, mode, entry);
|
||||
// Special colors:
|
||||
@@ -550,186 +577,6 @@ static void CheckLANServers(menu_t *menu, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
static void PostInputConfigApply(menu_t *menu, int cmd, void *data)
|
||||
{
|
||||
UNUSED(menu);
|
||||
UNUSED(cmd);
|
||||
MainMenuData *mData = data;
|
||||
bool resetBg = false;
|
||||
if (!ConfigApply(&gConfig, &resetBg))
|
||||
{
|
||||
LOG(LM_MAIN, LL_ERROR, "Failed to apply config; reset to last used");
|
||||
ConfigResetChanged(&gConfig);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Save config immediately
|
||||
ConfigSave(&gConfig, GetConfigFilePath(CONFIG_FILE));
|
||||
if (resetBg)
|
||||
{
|
||||
GenerateLiveBackground(mData);
|
||||
}
|
||||
}
|
||||
|
||||
MenuResetSize(&mData->ms);
|
||||
}
|
||||
|
||||
static menu_t *MenuCreateConfigOptions(
|
||||
const char *name, const char *title, const Config *c, MainMenuData *data,
|
||||
const bool backOrReturn)
|
||||
{
|
||||
menu_t *menu = MenuCreateNormal(name, title, MENU_TYPE_OPTIONS, 0);
|
||||
CASSERT(
|
||||
c->Type == CONFIG_TYPE_GROUP,
|
||||
"Cannot make menu from non-group config");
|
||||
CA_FOREACH(Config, child, c->u.Group)
|
||||
MenuAddConfigOptionsItem(menu, child);
|
||||
CA_FOREACH_END()
|
||||
MenuAddSubmenu(menu, MenuCreateSeparator(""));
|
||||
if (backOrReturn)
|
||||
{
|
||||
MenuAddSubmenu(menu, MenuCreateBack("Done"));
|
||||
}
|
||||
else
|
||||
{
|
||||
MenuAddSubmenu(menu, MenuCreateReturn("Done", 0));
|
||||
}
|
||||
MenuSetPostInputFunc(menu, PostInputConfigApply, data);
|
||||
return menu;
|
||||
}
|
||||
|
||||
static menu_t *MenuCreateOptionsGraphics(const char *name, MainMenuData *data);
|
||||
#if !defined(__ANDROID__) && !defined(__GCWZERO__)
|
||||
static menu_t *MenuCreateOptionsControls(const char *name, MainMenuData *data);
|
||||
#endif
|
||||
|
||||
static menu_t *MenuCreateOptions(const char *name, MainMenuData *data)
|
||||
{
|
||||
menu_t *menu = MenuCreateNormal(name, "Options:", MENU_TYPE_NORMAL, 0);
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateConfigOptions(
|
||||
"Game...", "Game Options:", ConfigGet(&gConfig, "Game"),
|
||||
data, true));
|
||||
MenuAddSubmenu(menu, MenuCreateOptionsGraphics("Graphics...", data));
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateConfigOptions(
|
||||
"Interface...", "Interface Options:",
|
||||
ConfigGet(&gConfig, "Interface"), data, true));
|
||||
#if !defined(__ANDROID__) && !defined(__GCWZERO__)
|
||||
MenuAddSubmenu(menu, MenuCreateOptionsControls("Controls...", data));
|
||||
#endif
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateConfigOptions(
|
||||
"Sound...", "Configure Sound:", ConfigGet(&gConfig, "Sound"),
|
||||
data, true));
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateConfigOptions(
|
||||
"Quick Play...", "Quick Play Options:",
|
||||
ConfigGet(&gConfig, "QuickPlay"), data, true));
|
||||
MenuAddSubmenu(menu, MenuCreateSeparator(""));
|
||||
MenuAddSubmenu(menu, MenuCreateBack("Back"));
|
||||
return menu;
|
||||
}
|
||||
|
||||
static menu_t *MenuCreateOptionsGraphics(const char *name, MainMenuData *data)
|
||||
{
|
||||
menu_t *menu =
|
||||
MenuCreateNormal(name, "Graphics Options:", MENU_TYPE_OPTIONS, 0);
|
||||
MenuAddConfigOptionsItem(menu, ConfigGet(&gConfig, "Graphics.Brightness"));
|
||||
#ifndef __GCWZERO__
|
||||
#ifndef __ANDROID__
|
||||
MenuAddConfigOptionsItem(menu, ConfigGet(&gConfig, "Graphics.Fullscreen"));
|
||||
// TODO: fix second window rendering
|
||||
// MenuAddConfigOptionsItem(
|
||||
// menu, ConfigGet(&gConfig, "Graphics.SecondWindow"));
|
||||
#endif // ANDROID
|
||||
|
||||
MenuAddConfigOptionsItem(
|
||||
menu, ConfigGet(&gConfig, "Graphics.ScaleFactor"));
|
||||
MenuAddConfigOptionsItem(menu, ConfigGet(&gConfig, "Graphics.ScaleMode"));
|
||||
#endif // GCWZERO
|
||||
MenuAddConfigOptionsItem(menu, ConfigGet(&gConfig, "Graphics.Shadows"));
|
||||
MenuAddConfigOptionsItem(menu, ConfigGet(&gConfig, "Graphics.Gore"));
|
||||
MenuAddConfigOptionsItem(menu, ConfigGet(&gConfig, "Graphics.Brass"));
|
||||
MenuAddSubmenu(menu, MenuCreateSeparator(""));
|
||||
MenuAddSubmenu(menu, MenuCreateBack("Done"));
|
||||
MenuSetPostInputFunc(menu, PostInputConfigApply, data);
|
||||
return menu;
|
||||
}
|
||||
|
||||
static menu_t *MenuCreateKeys(const char *name, MainMenuData *data);
|
||||
|
||||
#if !defined(__ANDROID__) && !defined(__GCWZERO__)
|
||||
static menu_t *MenuCreateOptionsControls(const char *name, MainMenuData *data)
|
||||
{
|
||||
menu_t *menu =
|
||||
MenuCreateNormal(name, "Configure Controls:", MENU_TYPE_OPTIONS, 0);
|
||||
MenuAddSubmenu(menu, MenuCreateKeys("Redefine keys...", data));
|
||||
MenuAddSubmenu(menu, MenuCreateSeparator(""));
|
||||
MenuAddSubmenu(menu, MenuCreateBack("Done"));
|
||||
MenuSetPostInputFunc(menu, PostInputConfigApply, data);
|
||||
return menu;
|
||||
}
|
||||
#endif
|
||||
|
||||
menu_t *MenuCreateQuit(const char *name)
|
||||
{
|
||||
return MenuCreate(name, MENU_TYPE_QUIT);
|
||||
}
|
||||
|
||||
static void MenuCreateKeysSingleSection(
|
||||
menu_t *menu, const char *sectionName, const int playerIndex);
|
||||
static menu_t *MenuCreateOptionChangeKey(
|
||||
const char *name, const key_code_e code, const int playerIndex, const bool isOptional);
|
||||
|
||||
static menu_t *MenuCreateKeys(const char *name, MainMenuData *data)
|
||||
{
|
||||
menu_t *menu = MenuCreateNormal(name, "", MENU_TYPE_OPTIONS, 0);
|
||||
MenuCreateKeysSingleSection(menu, "Keyboard 1", 0);
|
||||
MenuCreateKeysSingleSection(menu, "Keyboard 2", 1);
|
||||
MenuAddSubmenu(menu, MenuCreateOptionChangeKey("map", KEY_CODE_MAP, 0, true));
|
||||
MenuAddSubmenu(menu, MenuCreateSeparator(""));
|
||||
MenuAddSubmenu(menu, MenuCreateBack("Done"));
|
||||
MenuSetPostInputFunc(menu, PostInputConfigApply, data);
|
||||
return menu;
|
||||
}
|
||||
|
||||
static void MenuCreateKeysSingleSection(
|
||||
menu_t *menu, const char *sectionName, const int playerIndex)
|
||||
{
|
||||
MenuAddSubmenu(menu, MenuCreateSeparator(sectionName));
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateOptionChangeKey("left", KEY_CODE_LEFT, playerIndex, false));
|
||||
MenuAddSubmenu(
|
||||
menu,
|
||||
MenuCreateOptionChangeKey("right", KEY_CODE_RIGHT, playerIndex, false));
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateOptionChangeKey("up", KEY_CODE_UP, playerIndex, false));
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateOptionChangeKey("down", KEY_CODE_DOWN, playerIndex, false));
|
||||
MenuAddSubmenu(
|
||||
menu,
|
||||
MenuCreateOptionChangeKey("fire", KEY_CODE_BUTTON1, playerIndex, false));
|
||||
MenuAddSubmenu(
|
||||
menu,
|
||||
MenuCreateOptionChangeKey("switch/strafe", KEY_CODE_BUTTON2, playerIndex, false));
|
||||
MenuAddSubmenu(
|
||||
menu,
|
||||
MenuCreateOptionChangeKey("grenade", KEY_CODE_GRENADE, playerIndex, true));
|
||||
MenuAddSubmenu(menu, MenuCreateSeparator(""));
|
||||
}
|
||||
|
||||
static menu_t *MenuCreateOptionChangeKey(
|
||||
const char *name, const key_code_e code, const int playerIndex, const bool isOptional)
|
||||
{
|
||||
menu_t *menu =
|
||||
MenuCreate(name, MENU_TYPE_SET_OPTION_CHANGE_KEY);
|
||||
menu->u.changeKey.code = code;
|
||||
menu->u.changeKey.playerIndex = playerIndex;
|
||||
menu->u.changeKey.isOptional = isOptional;
|
||||
return menu;
|
||||
}
|
||||
|
||||
static void MenuResetSize(MenuSystem *ms)
|
||||
{
|
||||
// Update menu system so that resolution changes don't
|
||||
|
220
src/options_menu.c
Normal file
220
src/options_menu.c
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "options_menu.h"
|
||||
|
||||
#include <cdogs/config_io.h>
|
||||
#include <cdogs/log.h>
|
||||
|
||||
#include "files.h"
|
||||
|
||||
static menu_t *MenuCreateConfigOptions(
|
||||
const char *name, const char *title, const Config *c,
|
||||
OptionsMenuData *data, const bool backOrReturn);
|
||||
static menu_t *MenuCreateOptionsGraphics(
|
||||
const char *name, OptionsMenuData *data);
|
||||
|
||||
#if !defined(__ANDROID__) && !defined(__GCWZERO__)
|
||||
static menu_t *MenuCreateOptionsControls(
|
||||
const char *name, OptionsMenuData *data);
|
||||
#endif
|
||||
|
||||
menu_t *MenuCreateOptions(const char *name, OptionsMenuData *data)
|
||||
{
|
||||
menu_t *menu = MenuCreateNormal(name, "Options:", MENU_TYPE_NORMAL, 0);
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateConfigOptions(
|
||||
"Game...", "Game Options:", ConfigGet(data->config, "Game"),
|
||||
data, true));
|
||||
MenuAddSubmenu(menu, MenuCreateOptionsGraphics("Graphics...", data));
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateConfigOptions(
|
||||
"Interface...", "Interface Options:",
|
||||
ConfigGet(data->config, "Interface"), data, true));
|
||||
#if !defined(__ANDROID__) && !defined(__GCWZERO__)
|
||||
MenuAddSubmenu(menu, MenuCreateOptionsControls("Controls...", data));
|
||||
#endif
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateConfigOptions(
|
||||
"Sound...", "Configure Sound:",
|
||||
ConfigGet(data->config, "Sound"), data, true));
|
||||
MenuAddSubmenu(menu, MenuCreateSeparator(""));
|
||||
MenuAddSubmenu(menu, MenuCreateBack("Back"));
|
||||
return menu;
|
||||
}
|
||||
|
||||
static void PostInputConfigApply(menu_t *menu, int cmd, void *data);
|
||||
|
||||
static menu_t *MenuCreateConfigOptions(
|
||||
const char *name, const char *title, const Config *c,
|
||||
OptionsMenuData *data, const bool backOrReturn)
|
||||
{
|
||||
menu_t *menu = MenuCreateNormal(name, title, MENU_TYPE_OPTIONS, 0);
|
||||
CASSERT(
|
||||
c->Type == CONFIG_TYPE_GROUP,
|
||||
"Cannot make menu from non-group config");
|
||||
CA_FOREACH(Config, child, c->u.Group)
|
||||
MenuAddConfigOptionsItem(menu, child);
|
||||
CA_FOREACH_END()
|
||||
MenuAddSubmenu(menu, MenuCreateSeparator(""));
|
||||
if (backOrReturn)
|
||||
{
|
||||
MenuAddSubmenu(menu, MenuCreateBack("Done"));
|
||||
}
|
||||
else
|
||||
{
|
||||
MenuAddSubmenu(menu, MenuCreateReturn("Done", 0));
|
||||
}
|
||||
MenuSetPostInputFunc(menu, PostInputConfigApply, data);
|
||||
return menu;
|
||||
}
|
||||
|
||||
static void PostInputConfigApply(menu_t *menu, int cmd, void *data)
|
||||
{
|
||||
UNUSED(menu);
|
||||
UNUSED(cmd);
|
||||
OptionsMenuData *mData = data;
|
||||
bool resetBg = false;
|
||||
if (!ConfigApply(mData->config, &resetBg))
|
||||
{
|
||||
LOG(LM_MAIN, LL_ERROR, "Failed to apply config; reset to last used");
|
||||
ConfigResetChanged(mData->config);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Save config immediately
|
||||
ConfigSave(mData->config, GetConfigFilePath(CONFIG_FILE));
|
||||
}
|
||||
|
||||
if (mData->gfxChangeCallback)
|
||||
{
|
||||
mData->gfxChangeCallback(mData->gfxChangeData, resetBg);
|
||||
}
|
||||
}
|
||||
|
||||
static menu_t *MenuCreateOptionsGraphics(
|
||||
const char *name, OptionsMenuData *data)
|
||||
{
|
||||
menu_t *menu =
|
||||
MenuCreateNormal(name, "Graphics Options:", MENU_TYPE_OPTIONS, 0);
|
||||
MenuAddConfigOptionsItem(
|
||||
menu, ConfigGet(data->config, "Graphics.Brightness"));
|
||||
#ifndef __GCWZERO__
|
||||
#ifndef __ANDROID__
|
||||
MenuAddConfigOptionsItem(
|
||||
menu, ConfigGet(data->config, "Graphics.Fullscreen"));
|
||||
// TODO: fix second window rendering
|
||||
// MenuAddConfigOptionsItem(
|
||||
// menu, ConfigGet(data->config, "Graphics.SecondWindow"));
|
||||
#endif // ANDROID
|
||||
|
||||
MenuAddConfigOptionsItem(
|
||||
menu, ConfigGet(data->config, "Graphics.ScaleFactor"));
|
||||
MenuAddConfigOptionsItem(
|
||||
menu, ConfigGet(data->config, "Graphics.ScaleMode"));
|
||||
#endif // GCWZERO
|
||||
MenuAddConfigOptionsItem(
|
||||
menu, ConfigGet(data->config, "Graphics.Shadows"));
|
||||
MenuAddConfigOptionsItem(menu, ConfigGet(data->config, "Graphics.Gore"));
|
||||
MenuAddConfigOptionsItem(menu, ConfigGet(data->config, "Graphics.Brass"));
|
||||
MenuAddSubmenu(menu, MenuCreateSeparator(""));
|
||||
MenuAddSubmenu(menu, MenuCreateBack("Done"));
|
||||
MenuSetPostInputFunc(menu, PostInputConfigApply, data);
|
||||
return menu;
|
||||
}
|
||||
|
||||
static menu_t *MenuCreateKeys(const char *name, OptionsMenuData *data);
|
||||
|
||||
#if !defined(__ANDROID__) && !defined(__GCWZERO__)
|
||||
static menu_t *MenuCreateOptionsControls(
|
||||
const char *name, OptionsMenuData *data)
|
||||
{
|
||||
menu_t *menu =
|
||||
MenuCreateNormal(name, "Configure Controls:", MENU_TYPE_OPTIONS, 0);
|
||||
MenuAddSubmenu(menu, MenuCreateKeys("Redefine keys...", data));
|
||||
MenuAddSubmenu(menu, MenuCreateSeparator(""));
|
||||
MenuAddSubmenu(menu, MenuCreateBack("Done"));
|
||||
MenuSetPostInputFunc(menu, PostInputConfigApply, data);
|
||||
return menu;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void MenuCreateKeysSingleSection(
|
||||
menu_t *menu, const char *sectionName, const int playerIndex);
|
||||
static menu_t *MenuCreateOptionChangeKey(
|
||||
const char *name, const key_code_e code, const int playerIndex,
|
||||
const bool isOptional);
|
||||
|
||||
static menu_t *MenuCreateKeys(const char *name, OptionsMenuData *data)
|
||||
{
|
||||
menu_t *menu = MenuCreateNormal(name, "", MENU_TYPE_OPTIONS, 0);
|
||||
MenuCreateKeysSingleSection(menu, "Keyboard 1", 0);
|
||||
MenuCreateKeysSingleSection(menu, "Keyboard 2", 1);
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateOptionChangeKey("map", KEY_CODE_MAP, 0, true));
|
||||
MenuAddSubmenu(menu, MenuCreateSeparator(""));
|
||||
MenuAddSubmenu(menu, MenuCreateBack("Done"));
|
||||
MenuSetPostInputFunc(menu, PostInputConfigApply, data);
|
||||
return menu;
|
||||
}
|
||||
|
||||
static void MenuCreateKeysSingleSection(
|
||||
menu_t *menu, const char *sectionName, const int playerIndex)
|
||||
{
|
||||
MenuAddSubmenu(menu, MenuCreateSeparator(sectionName));
|
||||
MenuAddSubmenu(
|
||||
menu,
|
||||
MenuCreateOptionChangeKey("left", KEY_CODE_LEFT, playerIndex, false));
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateOptionChangeKey(
|
||||
"right", KEY_CODE_RIGHT, playerIndex, false));
|
||||
MenuAddSubmenu(
|
||||
menu,
|
||||
MenuCreateOptionChangeKey("up", KEY_CODE_UP, playerIndex, false));
|
||||
MenuAddSubmenu(
|
||||
menu,
|
||||
MenuCreateOptionChangeKey("down", KEY_CODE_DOWN, playerIndex, false));
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateOptionChangeKey(
|
||||
"fire", KEY_CODE_BUTTON1, playerIndex, false));
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateOptionChangeKey(
|
||||
"switch/strafe", KEY_CODE_BUTTON2, playerIndex, false));
|
||||
MenuAddSubmenu(
|
||||
menu, MenuCreateOptionChangeKey(
|
||||
"grenade", KEY_CODE_GRENADE, playerIndex, true));
|
||||
MenuAddSubmenu(menu, MenuCreateSeparator(""));
|
||||
}
|
||||
|
||||
static menu_t *MenuCreateOptionChangeKey(
|
||||
const char *name, const key_code_e code, const int playerIndex,
|
||||
const bool isOptional)
|
||||
{
|
||||
menu_t *menu = MenuCreate(name, MENU_TYPE_SET_OPTION_CHANGE_KEY);
|
||||
menu->u.changeKey.code = code;
|
||||
menu->u.changeKey.playerIndex = playerIndex;
|
||||
menu->u.changeKey.isOptional = isOptional;
|
||||
return menu;
|
||||
}
|
39
src/options_menu.h
Normal file
39
src/options_menu.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
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
|
||||
{
|
||||
Config *config;
|
||||
MenuSystem *ms;
|
||||
// Callback when gfx options changed - param = change background
|
||||
void (*gfxChangeCallback)(void *, const bool);
|
||||
void *gfxChangeData;
|
||||
} OptionsMenuData;
|
||||
|
||||
menu_t *MenuCreateOptions(const char *name, OptionsMenuData *data);
|
@@ -30,14 +30,23 @@
|
||||
#include <cdogs/draw/drawtools.h>
|
||||
#include <cdogs/font.h>
|
||||
|
||||
void PauseMenuInit(PauseMenu *pm, EventHandlers *handlers, GraphicsDevice *g)
|
||||
void PauseMenuInit(
|
||||
PauseMenu *pm, EventHandlers *handlers, GraphicsDevice *g,
|
||||
void (*gfxChangeCallback)(void *, const bool), void *gfxChangeData)
|
||||
{
|
||||
memset(pm, 0, sizeof *pm);
|
||||
MenuSystemInit(&pm->ms, handlers, g, svec2i_zero(), g->cachedConfig.Res);
|
||||
pm->ms.current = pm->ms.root =
|
||||
MenuCreateNormal("", "", MENU_TYPE_NORMAL, 0);
|
||||
MenuAddSubmenu(pm->ms.root, MenuCreateReturn("Resume", 0));
|
||||
MenuAddSubmenu(pm->ms.root, MenuCreateReturn("Quit", 1));
|
||||
MenuAddSubmenu(pm->ms.root, MenuCreate("Resume", MENU_TYPE_QUIT));
|
||||
MenuAddSubmenu(pm->ms.root, MenuCreateSeparator(""));
|
||||
pm->oData.config = &gConfig;
|
||||
pm->oData.gfxChangeCallback = gfxChangeCallback;
|
||||
pm->oData.gfxChangeData = gfxChangeData;
|
||||
pm->oData.ms = &pm->ms;
|
||||
MenuAddSubmenu(pm->ms.root, MenuCreateOptions("Options...", &pm->oData));
|
||||
MenuAddSubmenu(pm->ms.root, MenuCreateSeparator(""));
|
||||
MenuAddSubmenu(pm->ms.root, MenuCreateReturn("Quit", 0));
|
||||
MenuAddExitType(&pm->ms, MENU_TYPE_RETURN);
|
||||
pm->ms.allowAborts = true;
|
||||
pm->handlers = handlers;
|
||||
@@ -110,11 +119,11 @@ bool PauseMenuUpdate(
|
||||
if (pm->pausingDevice != INPUT_DEVICE_UNSET)
|
||||
{
|
||||
const GameLoopResult result = MenuUpdate(&pm->ms);
|
||||
if (result == UPDATE_RESULT_OK)
|
||||
if (result == UPDATE_RESULT_OK || pm->ms.current->type == MENU_TYPE_QUIT)
|
||||
{
|
||||
// Unpause
|
||||
pm->pausingDevice = INPUT_DEVICE_UNSET;
|
||||
if (pm->ms.current->u.returnCode == 1)
|
||||
if (pm->ms.current->type == MENU_TYPE_RETURN)
|
||||
{
|
||||
// Quit
|
||||
GameEvent e = GameEventNew(GAME_EVENT_MISSION_END);
|
||||
|
@@ -28,17 +28,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "menu.h"
|
||||
#include "options_menu.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MenuSystem ms;
|
||||
OptionsMenuData oData;
|
||||
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 PauseMenuInit(
|
||||
PauseMenu *pm, EventHandlers *handlers, GraphicsDevice *g,
|
||||
void (*gfxChangeCallback)(void *, const bool), void *gfxChangeData);
|
||||
void PauseMenuTerminate(PauseMenu *pm);
|
||||
|
||||
// Returns whether to quit
|
||||
|
Reference in New Issue
Block a user