Added settings.ini
This commit is contained in:
@ -39,6 +39,7 @@ add_executable(tetris
|
|||||||
src/core/input/InputManager.cpp
|
src/core/input/InputManager.cpp
|
||||||
src/core/assets/AssetManager.cpp
|
src/core/assets/AssetManager.cpp
|
||||||
src/core/GlobalState.cpp
|
src/core/GlobalState.cpp
|
||||||
|
src/core/Settings.cpp
|
||||||
src/graphics/renderers/RenderManager.cpp
|
src/graphics/renderers/RenderManager.cpp
|
||||||
src/persistence/Scores.cpp
|
src/persistence/Scores.cpp
|
||||||
src/graphics/effects/Starfield.cpp
|
src/graphics/effects/Starfield.cpp
|
||||||
|
|||||||
15
settings.ini
Normal file
15
settings.ini
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
; Tetris Game Settings
|
||||||
|
; This file is auto-generated
|
||||||
|
|
||||||
|
[Display]
|
||||||
|
Fullscreen=1
|
||||||
|
|
||||||
|
[Audio]
|
||||||
|
Music=1
|
||||||
|
Sound=0
|
||||||
|
|
||||||
|
[Player]
|
||||||
|
Name=Player
|
||||||
|
|
||||||
|
[Debug]
|
||||||
|
Enabled=0
|
||||||
@ -85,6 +85,7 @@ void Audio::start(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Audio::toggleMute(){ muted=!muted; }
|
void Audio::toggleMute(){ muted=!muted; }
|
||||||
|
void Audio::setMuted(bool m){ muted=m; }
|
||||||
|
|
||||||
void Audio::nextTrack(){
|
void Audio::nextTrack(){
|
||||||
if(tracks.empty()) { current = -1; return; }
|
if(tracks.empty()) { current = -1; return; }
|
||||||
|
|||||||
@ -43,6 +43,8 @@ public:
|
|||||||
void shuffle(); // randomize order
|
void shuffle(); // randomize order
|
||||||
void start(); // begin playback
|
void start(); // begin playback
|
||||||
void toggleMute();
|
void toggleMute();
|
||||||
|
void setMuted(bool m);
|
||||||
|
bool isMuted() const { return muted; }
|
||||||
|
|
||||||
// Menu music support
|
// Menu music support
|
||||||
void setMenuTrack(const std::string& path);
|
void setMenuTrack(const std::string& path);
|
||||||
|
|||||||
112
src/core/Settings.cpp
Normal file
112
src/core/Settings.cpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#include "Settings.h"
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
// Singleton instance
|
||||||
|
Settings& Settings::instance() {
|
||||||
|
static Settings s_instance;
|
||||||
|
return s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings::Settings() {
|
||||||
|
// Constructor - defaults already set in header
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Settings::getSettingsPath() {
|
||||||
|
// Save settings.ini in the game's directory
|
||||||
|
return "settings.ini";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Settings::load() {
|
||||||
|
std::ifstream file(getSettingsPath());
|
||||||
|
if (!file.is_open()) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Settings file not found, using defaults");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
std::string currentSection;
|
||||||
|
|
||||||
|
while (std::getline(file, line)) {
|
||||||
|
// Trim whitespace
|
||||||
|
size_t start = line.find_first_not_of(" \t\r\n");
|
||||||
|
size_t end = line.find_last_not_of(" \t\r\n");
|
||||||
|
if (start == std::string::npos) continue; // Empty line
|
||||||
|
line = line.substr(start, end - start + 1);
|
||||||
|
|
||||||
|
// Skip comments
|
||||||
|
if (line[0] == ';' || line[0] == '#') continue;
|
||||||
|
|
||||||
|
// Check for section header
|
||||||
|
if (line[0] == '[' && line[line.length() - 1] == ']') {
|
||||||
|
currentSection = line.substr(1, line.length() - 2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse key=value
|
||||||
|
size_t equalsPos = line.find('=');
|
||||||
|
if (equalsPos == std::string::npos) continue;
|
||||||
|
|
||||||
|
std::string key = line.substr(0, equalsPos);
|
||||||
|
std::string value = line.substr(equalsPos + 1);
|
||||||
|
|
||||||
|
// Trim key and value
|
||||||
|
key.erase(key.find_last_not_of(" \t") + 1);
|
||||||
|
value.erase(0, value.find_first_not_of(" \t"));
|
||||||
|
|
||||||
|
// Parse settings
|
||||||
|
if (currentSection == "Display") {
|
||||||
|
if (key == "Fullscreen") {
|
||||||
|
m_fullscreen = (value == "1" || value == "true" || value == "True");
|
||||||
|
}
|
||||||
|
} else if (currentSection == "Audio") {
|
||||||
|
if (key == "Music") {
|
||||||
|
m_musicEnabled = (value == "1" || value == "true" || value == "True");
|
||||||
|
} else if (key == "Sound") {
|
||||||
|
m_soundEnabled = (value == "1" || value == "true" || value == "True");
|
||||||
|
}
|
||||||
|
} else if (currentSection == "Player") {
|
||||||
|
if (key == "Name") {
|
||||||
|
m_playerName = value;
|
||||||
|
}
|
||||||
|
} else if (currentSection == "Debug") {
|
||||||
|
if (key == "Enabled") {
|
||||||
|
m_debugEnabled = (value == "1" || value == "true" || value == "True");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Settings loaded from %s", getSettingsPath().c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Settings::save() {
|
||||||
|
std::ofstream file(getSettingsPath());
|
||||||
|
if (!file.is_open()) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to save settings to %s", getSettingsPath().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write settings in INI format
|
||||||
|
file << "; Tetris Game Settings\n";
|
||||||
|
file << "; This file is auto-generated\n\n";
|
||||||
|
|
||||||
|
file << "[Display]\n";
|
||||||
|
file << "Fullscreen=" << (m_fullscreen ? "1" : "0") << "\n\n";
|
||||||
|
|
||||||
|
file << "[Audio]\n";
|
||||||
|
file << "Music=" << (m_musicEnabled ? "1" : "0") << "\n";
|
||||||
|
file << "Sound=" << (m_soundEnabled ? "1" : "0") << "\n\n";
|
||||||
|
|
||||||
|
file << "[Player]\n";
|
||||||
|
file << "Name=" << m_playerName << "\n\n";
|
||||||
|
|
||||||
|
file << "[Debug]\n";
|
||||||
|
file << "Enabled=" << (m_debugEnabled ? "1" : "0") << "\n";
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Settings saved to %s", getSettingsPath().c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
49
src/core/Settings.h
Normal file
49
src/core/Settings.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings - Persistent game settings manager
|
||||||
|
* Handles loading/saving settings to settings.ini
|
||||||
|
*/
|
||||||
|
class Settings {
|
||||||
|
public:
|
||||||
|
// Singleton access
|
||||||
|
static Settings& instance();
|
||||||
|
|
||||||
|
// Load settings from file (returns true if file existed)
|
||||||
|
bool load();
|
||||||
|
|
||||||
|
// Save settings to file
|
||||||
|
bool save();
|
||||||
|
|
||||||
|
// Settings accessors
|
||||||
|
bool isFullscreen() const { return m_fullscreen; }
|
||||||
|
void setFullscreen(bool value) { m_fullscreen = value; }
|
||||||
|
|
||||||
|
bool isMusicEnabled() const { return m_musicEnabled; }
|
||||||
|
void setMusicEnabled(bool value) { m_musicEnabled = value; }
|
||||||
|
|
||||||
|
bool isSoundEnabled() const { return m_soundEnabled; }
|
||||||
|
void setSoundEnabled(bool value) { m_soundEnabled = value; }
|
||||||
|
|
||||||
|
bool isDebugEnabled() const { return m_debugEnabled; }
|
||||||
|
void setDebugEnabled(bool value) { m_debugEnabled = value; }
|
||||||
|
|
||||||
|
const std::string& getPlayerName() const { return m_playerName; }
|
||||||
|
void setPlayerName(const std::string& name) { m_playerName = name; }
|
||||||
|
|
||||||
|
// Get the settings file path
|
||||||
|
static std::string getSettingsPath();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Settings(); // Private constructor for singleton
|
||||||
|
Settings(const Settings&) = delete;
|
||||||
|
Settings& operator=(const Settings&) = delete;
|
||||||
|
|
||||||
|
// Settings values
|
||||||
|
bool m_fullscreen = false;
|
||||||
|
bool m_musicEnabled = true;
|
||||||
|
bool m_soundEnabled = true;
|
||||||
|
bool m_debugEnabled = false;
|
||||||
|
std::string m_playerName = "Player";
|
||||||
|
};
|
||||||
@ -6,6 +6,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include "../../core/Settings.h"
|
||||||
|
|
||||||
// Color constants (copied from main.cpp)
|
// Color constants (copied from main.cpp)
|
||||||
static const SDL_Color COLORS[] = {
|
static const SDL_Color COLORS[] = {
|
||||||
@ -413,30 +414,32 @@ void GameRenderer::renderPlayingState(
|
|||||||
pixelFont->draw(renderer, scoreX, baseY + 290, timeStr, 0.9f, {255, 255, 255, 255});
|
pixelFont->draw(renderer, scoreX, baseY + 290, timeStr, 0.9f, {255, 255, 255, 255});
|
||||||
|
|
||||||
// Debug: Gravity timing info
|
// Debug: Gravity timing info
|
||||||
pixelFont->draw(renderer, scoreX, baseY + 330, "GRAVITY", 0.8f, {150, 150, 150, 255});
|
if (Settings::instance().isDebugEnabled()) {
|
||||||
double gravityMs = game->getGravityMs();
|
pixelFont->draw(renderer, scoreX, baseY + 330, "GRAVITY", 0.8f, {150, 150, 150, 255});
|
||||||
double fallAcc = game->getFallAccumulator();
|
double gravityMs = game->getGravityMs();
|
||||||
|
double fallAcc = game->getFallAccumulator();
|
||||||
// Calculate effective gravity (accounting for soft drop)
|
|
||||||
bool isSoftDrop = game->isSoftDropping();
|
// Calculate effective gravity (accounting for soft drop)
|
||||||
double effectiveGravityMs = isSoftDrop ? (gravityMs / 2.0) : gravityMs;
|
bool isSoftDrop = game->isSoftDropping();
|
||||||
double timeUntilDrop = std::max(0.0, effectiveGravityMs - fallAcc);
|
double effectiveGravityMs = isSoftDrop ? (gravityMs / 2.0) : gravityMs;
|
||||||
|
double timeUntilDrop = std::max(0.0, effectiveGravityMs - fallAcc);
|
||||||
char gravityStr[32];
|
|
||||||
snprintf(gravityStr, sizeof(gravityStr), "%.0f ms%s", gravityMs, isSoftDrop ? " (SD)" : "");
|
char gravityStr[32];
|
||||||
pixelFont->draw(renderer, scoreX, baseY + 350, gravityStr, 0.7f, {180, 180, 180, 255});
|
snprintf(gravityStr, sizeof(gravityStr), "%.0f ms%s", gravityMs, isSoftDrop ? " (SD)" : "");
|
||||||
|
pixelFont->draw(renderer, scoreX, baseY + 350, gravityStr, 0.7f, {180, 180, 180, 255});
|
||||||
char dropStr[32];
|
|
||||||
snprintf(dropStr, sizeof(dropStr), "Drop: %.0f", timeUntilDrop);
|
char dropStr[32];
|
||||||
SDL_Color dropColor = isSoftDrop ? SDL_Color{255, 200, 100, 255} : SDL_Color{100, 255, 100, 255};
|
snprintf(dropStr, sizeof(dropStr), "Drop: %.0f", timeUntilDrop);
|
||||||
pixelFont->draw(renderer, scoreX, baseY + 370, dropStr, 0.7f, dropColor);
|
SDL_Color dropColor = isSoftDrop ? SDL_Color{255, 200, 100, 255} : SDL_Color{100, 255, 100, 255};
|
||||||
|
pixelFont->draw(renderer, scoreX, baseY + 370, dropStr, 0.7f, dropColor);
|
||||||
// Gravity HUD
|
|
||||||
char gms[64];
|
// Gravity HUD (Top)
|
||||||
double gms_val = game->getGravityMs();
|
char gms[64];
|
||||||
double gfps = gms_val > 0.0 ? (1000.0 / gms_val) : 0.0;
|
double gms_val = game->getGravityMs();
|
||||||
snprintf(gms, sizeof(gms), "GRAV: %.0f ms (%.2f fps)", gms_val, gfps);
|
double gfps = gms_val > 0.0 ? (1000.0 / gms_val) : 0.0;
|
||||||
pixelFont->draw(renderer, logicalW - 260, 10, gms, 0.9f, {200, 200, 220, 255});
|
snprintf(gms, sizeof(gms), "GRAV: %.0f ms (%.2f fps)", gms_val, gfps);
|
||||||
|
pixelFont->draw(renderer, logicalW - 260, 10, gms, 0.9f, {200, 200, 220, 255});
|
||||||
|
}
|
||||||
|
|
||||||
// Hold piece (if implemented)
|
// Hold piece (if implemented)
|
||||||
if (game->held().type < PIECE_COUNT) {
|
if (game->held().type < PIECE_COUNT) {
|
||||||
|
|||||||
34
src/main.cpp
34
src/main.cpp
@ -34,6 +34,7 @@
|
|||||||
#include "utils/ImagePathResolver.h"
|
#include "utils/ImagePathResolver.h"
|
||||||
#include "graphics/renderers/GameRenderer.h"
|
#include "graphics/renderers/GameRenderer.h"
|
||||||
#include "core/Config.h"
|
#include "core/Config.h"
|
||||||
|
#include "core/Settings.h"
|
||||||
|
|
||||||
// Debug logging removed: no-op in this build (previously LOG_DEBUG)
|
// Debug logging removed: no-op in this build (previously LOG_DEBUG)
|
||||||
|
|
||||||
@ -534,6 +535,17 @@ int main(int, char **)
|
|||||||
// Initialize random seed for fireworks
|
// Initialize random seed for fireworks
|
||||||
srand(static_cast<unsigned int>(SDL_GetTicks()));
|
srand(static_cast<unsigned int>(SDL_GetTicks()));
|
||||||
|
|
||||||
|
// Load settings
|
||||||
|
Settings::instance().load();
|
||||||
|
|
||||||
|
// Sync static variables with settings
|
||||||
|
musicEnabled = Settings::instance().isMusicEnabled();
|
||||||
|
playerName = Settings::instance().getPlayerName();
|
||||||
|
if (playerName.empty()) playerName = "Player";
|
||||||
|
|
||||||
|
// Apply sound settings to manager
|
||||||
|
SoundEffectManager::instance().setEnabled(Settings::instance().isSoundEnabled());
|
||||||
|
|
||||||
int sdlInitRes = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
|
int sdlInitRes = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
|
||||||
if (sdlInitRes < 0)
|
if (sdlInitRes < 0)
|
||||||
{
|
{
|
||||||
@ -547,7 +559,13 @@ int main(int, char **)
|
|||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
SDL_Window *window = SDL_CreateWindow("Tetris (SDL3)", LOGICAL_W, LOGICAL_H, SDL_WINDOW_RESIZABLE);
|
|
||||||
|
SDL_WindowFlags windowFlags = SDL_WINDOW_RESIZABLE;
|
||||||
|
if (Settings::instance().isFullscreen()) {
|
||||||
|
windowFlags |= SDL_WINDOW_FULLSCREEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Window *window = SDL_CreateWindow("Tetris (SDL3)", LOGICAL_W, LOGICAL_H, windowFlags);
|
||||||
if (!window)
|
if (!window)
|
||||||
{
|
{
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateWindow failed: %s", SDL_GetError());
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateWindow failed: %s", SDL_GetError());
|
||||||
@ -711,7 +729,8 @@ int main(int, char **)
|
|||||||
AppState state = AppState::Loading;
|
AppState state = AppState::Loading;
|
||||||
double loadingProgress = 0.0;
|
double loadingProgress = 0.0;
|
||||||
Uint64 loadStart = SDL_GetTicks();
|
Uint64 loadStart = SDL_GetTicks();
|
||||||
bool running = true, isFullscreen = false;
|
bool running = true;
|
||||||
|
bool isFullscreen = Settings::instance().isFullscreen();
|
||||||
bool leftHeld = false, rightHeld = false;
|
bool leftHeld = false, rightHeld = false;
|
||||||
double moveTimerMs = 0;
|
double moveTimerMs = 0;
|
||||||
const double DAS = 170.0, ARR = 40.0;
|
const double DAS = 170.0, ARR = 40.0;
|
||||||
@ -869,11 +888,13 @@ int main(int, char **)
|
|||||||
{
|
{
|
||||||
Audio::instance().toggleMute();
|
Audio::instance().toggleMute();
|
||||||
musicEnabled = !musicEnabled;
|
musicEnabled = !musicEnabled;
|
||||||
|
Settings::instance().setMusicEnabled(musicEnabled);
|
||||||
}
|
}
|
||||||
if (e.key.scancode == SDL_SCANCODE_S)
|
if (e.key.scancode == SDL_SCANCODE_S)
|
||||||
{
|
{
|
||||||
// Toggle sound effects
|
// Toggle sound effects
|
||||||
SoundEffectManager::instance().setEnabled(!SoundEffectManager::instance().isEnabled());
|
SoundEffectManager::instance().setEnabled(!SoundEffectManager::instance().isEnabled());
|
||||||
|
Settings::instance().setSoundEnabled(SoundEffectManager::instance().isEnabled());
|
||||||
}
|
}
|
||||||
if (e.key.scancode == SDL_SCANCODE_N)
|
if (e.key.scancode == SDL_SCANCODE_N)
|
||||||
{
|
{
|
||||||
@ -884,6 +905,7 @@ int main(int, char **)
|
|||||||
{
|
{
|
||||||
isFullscreen = !isFullscreen;
|
isFullscreen = !isFullscreen;
|
||||||
SDL_SetWindowFullscreen(window, isFullscreen ? SDL_WINDOW_FULLSCREEN : 0);
|
SDL_SetWindowFullscreen(window, isFullscreen ? SDL_WINDOW_FULLSCREEN : 0);
|
||||||
|
Settings::instance().setFullscreen(isFullscreen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -901,6 +923,7 @@ int main(int, char **)
|
|||||||
} else if (e.key.scancode == SDL_SCANCODE_RETURN || e.key.scancode == SDL_SCANCODE_KP_ENTER) {
|
} else if (e.key.scancode == SDL_SCANCODE_RETURN || e.key.scancode == SDL_SCANCODE_KP_ENTER) {
|
||||||
if (playerName.empty()) playerName = "PLAYER";
|
if (playerName.empty()) playerName = "PLAYER";
|
||||||
scores.submit(game.score(), game.lines(), game.level(), game.elapsed(), playerName);
|
scores.submit(game.score(), game.lines(), game.level(), game.elapsed(), playerName);
|
||||||
|
Settings::instance().setPlayerName(playerName);
|
||||||
isNewHighScore = false;
|
isNewHighScore = false;
|
||||||
SDL_StopTextInput(window);
|
SDL_StopTextInput(window);
|
||||||
}
|
}
|
||||||
@ -1169,6 +1192,9 @@ int main(int, char **)
|
|||||||
// Initialize audio system and start background loading on first frame
|
// Initialize audio system and start background loading on first frame
|
||||||
if (!musicLoaded && currentTrackLoading == 0) {
|
if (!musicLoaded && currentTrackLoading == 0) {
|
||||||
Audio::instance().init();
|
Audio::instance().init();
|
||||||
|
// Apply audio settings
|
||||||
|
Audio::instance().setMuted(!Settings::instance().isMusicEnabled());
|
||||||
|
// Note: SoundEffectManager doesn't have a global mute yet, but we can add it or handle it in playSound
|
||||||
|
|
||||||
// Count actual music files first
|
// Count actual music files first
|
||||||
totalTracks = 0;
|
totalTracks = 0;
|
||||||
@ -1686,6 +1712,10 @@ int main(int, char **)
|
|||||||
SDL_DestroyTexture(blocksTex);
|
SDL_DestroyTexture(blocksTex);
|
||||||
if (logoSmallTex)
|
if (logoSmallTex)
|
||||||
SDL_DestroyTexture(logoSmallTex);
|
SDL_DestroyTexture(logoSmallTex);
|
||||||
|
|
||||||
|
// Save settings on exit
|
||||||
|
Settings::instance().save();
|
||||||
|
|
||||||
lineEffect.shutdown();
|
lineEffect.shutdown();
|
||||||
Audio::instance().shutdown();
|
Audio::instance().shutdown();
|
||||||
SoundEffectManager::instance().shutdown();
|
SoundEffectManager::instance().shutdown();
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
#include "../core/Settings.h"
|
||||||
|
|
||||||
OptionsState::OptionsState(StateContext& ctx) : State(ctx) {}
|
OptionsState::OptionsState(StateContext& ctx) : State(ctx) {}
|
||||||
|
|
||||||
@ -233,18 +234,36 @@ void OptionsState::toggleFullscreen() {
|
|||||||
if (ctx.fullscreenFlag) {
|
if (ctx.fullscreenFlag) {
|
||||||
*ctx.fullscreenFlag = nextState;
|
*ctx.fullscreenFlag = nextState;
|
||||||
}
|
}
|
||||||
|
// Save setting
|
||||||
|
Settings::instance().setFullscreen(nextState);
|
||||||
|
Settings::instance().save();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OptionsState::toggleMusic() {
|
void OptionsState::toggleMusic() {
|
||||||
Audio::instance().toggleMute();
|
Audio::instance().toggleMute();
|
||||||
|
// If muted, music is disabled. If not muted, music is enabled.
|
||||||
|
// Note: Audio::instance().isMuted() returns true if muted.
|
||||||
|
// But Audio class doesn't expose isMuted directly in header usually?
|
||||||
|
// Let's assume toggleMute toggles internal state.
|
||||||
|
// We can track it via ctx.musicEnabled if it's synced.
|
||||||
|
|
||||||
|
bool enabled = true;
|
||||||
if (ctx.musicEnabled) {
|
if (ctx.musicEnabled) {
|
||||||
*ctx.musicEnabled = !*ctx.musicEnabled;
|
*ctx.musicEnabled = !*ctx.musicEnabled;
|
||||||
|
enabled = *ctx.musicEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save setting
|
||||||
|
Settings::instance().setMusicEnabled(enabled);
|
||||||
|
Settings::instance().save();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OptionsState::toggleSoundFx() {
|
void OptionsState::toggleSoundFx() {
|
||||||
bool next = !SoundEffectManager::instance().isEnabled();
|
bool next = !SoundEffectManager::instance().isEnabled();
|
||||||
SoundEffectManager::instance().setEnabled(next);
|
SoundEffectManager::instance().setEnabled(next);
|
||||||
|
// Save setting
|
||||||
|
Settings::instance().setSoundEnabled(next);
|
||||||
|
Settings::instance().save();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OptionsState::exitToMenu() {
|
void OptionsState::exitToMenu() {
|
||||||
|
|||||||
Reference in New Issue
Block a user