Maelstrom: volume, gamma correction, and controls are all hooked up to the preferences.

https://github.com/libsdl-org/Maelstrom/commit/53154cf85553efdc29406a6bfdb3c4e49477b7cf

From 53154cf85553efdc29406a6bfdb3c4e49477b7cf Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 4 Nov 2011 20:56:19 -0400
Subject: [PATCH] volume, gamma correction, and controls are all hooked up to
 the preferences.

---
 Maelstrom_Globals.h |  4 +-
 controls.cpp        | 94 ++++++++++++++-------------------------------
 controls.h          | 25 +++++++-----
 init.cpp            |  4 ++
 main.cpp            | 49 ++---------------------
 prefs.cpp           |  2 +-
 prefs.h             | 89 ++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 144 insertions(+), 123 deletions(-)

diff --git a/Maelstrom_Globals.h b/Maelstrom_Globals.h
index 79e7a547..0f93e8ad 100644
--- a/Maelstrom_Globals.h
+++ b/Maelstrom_Globals.h
@@ -106,8 +106,8 @@ extern StarPtr	gTheStars[MAX_STARS];
 extern Uint32	gStarColors[];
 // in controls.cpp :
 extern Controls	controls;
-extern Uint8	gSoundLevel;
-extern Uint8	gGammaCorrect;
+extern PrefsVariable<Uint8> gSoundLevel;
+extern PrefsVariable<Uint8> gGammaCorrect;
 // int scores.cpp :
 extern Scores	hScores[];
 
diff --git a/controls.cpp b/controls.cpp
index 87fbcfcd..8704d081 100644
--- a/controls.cpp
+++ b/controls.cpp
@@ -36,83 +36,47 @@
 
 /* Savable and configurable controls/data */
 
-/* Pause        Shield     Thrust  TurnR      TurnL     Fire     Quit  */
-#ifdef FAITHFUL_SPECS
-Controls controls =
-{ SDLK_CAPSLOCK,SDLK_SPACE,SDLK_UP,SDLK_RIGHT,SDLK_LEFT,SDLK_TAB,SDLK_ESCAPE };
-#else
-Controls controls =
-   { SDLK_PAUSE,SDLK_SPACE,SDLK_UP,SDLK_RIGHT,SDLK_LEFT,SDLK_TAB,SDLK_ESCAPE };
-#endif
+Controls::Controls() :
+	gPauseControl("Controls.PauseControl", SDLK_PAUSE),
+	gShieldControl("Controls.ShieldControl", SDLK_SPACE),
+	gThrustControl("Controls.ThrustControl", SDLK_UP),
+	gTurnRControl("Controls.TurnRControl", SDLK_RIGHT),
+	gTurnLControl("Controls.TurnLControl", SDLK_LEFT),
+	gFireControl("Controls.FireControl", SDLK_TAB),
+	gQuitControl("Controls.QuitControl", SDLK_ESCAPE)
+{
+}
 
+void
+Controls::Register(Prefs *prefs)
+{
+	gPauseControl.Register(prefs);
+	gShieldControl.Register(prefs);
+	gThrustControl.Register(prefs);
+	gTurnRControl.Register(prefs);
+	gTurnLControl.Register(prefs);
+	gFireControl.Register(prefs);
+	gQuitControl.Register(prefs);
+}
+
+Controls controls;
 #ifdef MOVIE_SUPPORT
 int	gMovie = 0;
 #endif
-Uint8 gSoundLevel = 4;
-Uint8 gGammaCorrect = 3;
-
-
-static FILE *OpenData(const char *mode, char **fname)
-{
-	static char datafile[BUFSIZ];
-	FILE *data;
+PrefsVariable<Uint8> gSoundLevel("SoundLevel", 4);
+PrefsVariable<Uint8> gGammaCorrect("GammaCorrect", 3);
 
-	if ( fname ) {
-		*fname = datafile;
-	}
-	sprintf(datafile,  "%s/%s", PHYSFS_getWriteDir(), MAELSTROM_DATA);
-	if ( (data=fopen(datafile, mode)) == NULL )
-		return(NULL);
-	return(data);
-}
 
 void LoadControls(void)
 {
-	char  buffer[BUFSIZ], *datafile;
-	FILE *data;
-
-	/* Open our control data file */
-	data = OpenData("r", &datafile);
-	if ( data == NULL ) {
-		return;
-	}
-
-	/* Read the controls */
-	if ( (fread(buffer, 1, 5, data) != 5) || strncmp(buffer, "MAEL3", 5) ) {
-		error(
-		"Warning: Data file '%s' is corrupt! (will fix)\n", datafile);
-		fclose(data);
-		return;
-	}
-	fread(&gSoundLevel, sizeof(gSoundLevel), 1, data);
-	fread(&controls, sizeof(controls), 1, data);
-	fread(&gGammaCorrect, sizeof(gGammaCorrect), 1, data);
-	fclose(data);
+	gSoundLevel.Register(prefs);
+	gGammaCorrect.Register(prefs);
+	controls.Register(prefs);
 }
 
 void SaveControls(void)
 {
-	char  *datafile;
-	const char *newmode;
-	FILE *data;
-
-	/* Don't clobber existing joystick data */
-	if ( (data=OpenData("r", NULL)) != NULL ) {
-		newmode = "r+";
-		fclose(data);
-	} else
-		newmode = "w";
-
-	if ( (data=OpenData(newmode, &datafile)) == NULL ) {
-		error("Warning: Couldn't save controls to %s\n", datafile);
-		return;
-	}
-
-	fwrite("MAEL3", 1, 5, data);
-	fwrite(&gSoundLevel, sizeof(gSoundLevel), 1, data);
-	fwrite(&controls, sizeof(controls), 1, data);
-	fwrite(&gGammaCorrect, sizeof(gGammaCorrect), 1, data);
-	fclose(data);
+	prefs->Save();
 }
 
 bool
diff --git a/controls.h b/controls.h
index e4432ec1..8f834d28 100644
--- a/controls.h
+++ b/controls.h
@@ -44,15 +44,22 @@ extern void	ShowDawn(void);
 #define ABORT_KEY	0x07
 
 /* The controls structure */
-typedef struct {
-	SDL_Keycode gPauseControl;
-	SDL_Keycode gShieldControl;
-	SDL_Keycode gThrustControl;
-	SDL_Keycode gTurnRControl;
-	SDL_Keycode gTurnLControl;
-	SDL_Keycode gFireControl;
-	SDL_Keycode gQuitControl;
-} Controls;
+class Controls
+{
+public:
+	Controls();
+
+	void Register(Prefs *prefs);
+
+public:
+	PrefsVariable<SDL_Keycode> gPauseControl;
+	PrefsVariable<SDL_Keycode> gShieldControl;
+	PrefsVariable<SDL_Keycode> gThrustControl;
+	PrefsVariable<SDL_Keycode> gTurnRControl;
+	PrefsVariable<SDL_Keycode> gTurnLControl;
+	PrefsVariable<SDL_Keycode> gFireControl;
+	PrefsVariable<SDL_Keycode> gQuitControl;
+};
 
 
 class UIElement;
diff --git a/init.cpp b/init.cpp
index 436b29fc..99193e42 100644
--- a/init.cpp
+++ b/init.cpp
@@ -640,6 +640,7 @@ static void BuildVelocityTable(void)
 void CleanUp(void)
 {
 	HaltLogic();
+	SaveControls();
 	if ( spriteres ) {
 		delete spriteres;
 		spriteres = NULL;
@@ -687,6 +688,9 @@ int DoInitializations(Uint32 window_flags, Uint32 render_flags)
 	prefs = new Prefs(GAME_PREFS_FILE);
 	prefs->Load();
 
+	// -- Load our controls
+	LoadControls();
+
 	Uint32 init_flags = (SDL_INIT_VIDEO|SDL_INIT_AUDIO);
 #ifdef SDL_INIT_JOYSTICK
 	init_flags |= SDL_INIT_JOYSTICK;
diff --git a/main.cpp b/main.cpp
index d1468fb9..71e3028d 100644
--- a/main.cpp
+++ b/main.cpp
@@ -180,8 +180,6 @@ void PrintUsage(void)
 	error("Where <options> can be any of:\n\n"
 "	-fullscreen		# Run Maelstrom in full-screen mode\n"
 "	-windowed		# Run Maelstrom in windowed mode\n"
-"	-gamma [0-8]		# Set the gamma correction\n"
-"	-volume [0-8]		# Set the sound volume\n"
 	);
 	LogicUsage();
 	error("\n");
@@ -254,8 +252,6 @@ int main(int argc, char *argv[])
 
 	/* Seed the random number generator */
 	SeedRandom(0L);
-	/* Initialize the controls */
-	LoadControls();
 
 	/* Initialize game logic data structures */
 	if ( InitLogicData() < 0 ) {
@@ -272,47 +268,6 @@ int main(int argc, char *argv[])
 		} else
 		if ( strcmp(argv[1], "-windowed") == 0 ) {
 			window_flags &= ~SDL_WINDOW_FULLSCREEN;
-		} else
-		if ( strcmp(argv[1], "-gamma") == 0 ) {
-			int gammacorrect;
-
-			if ( ! argv[2] ) {  /* Print the current gamma */
-				mesg("Current Gamma correction level: %d\n",
-								gGammaCorrect);
-				exit(0);
-			}
-			if ( (gammacorrect=atoi(argv[2])) < 0 || 
-							gammacorrect > 8 ) {
-				error(
-	"Gamma correction value must be between 0 and 8. -- Exiting.\n");
-				exit(1);
-			}
-			/* We need to update the gamma */
-			gGammaCorrect = gammacorrect;
-			SaveControls();
-
-			++argv;
-			--argc;
-		}
-		else if ( strcmp(argv[1], "-volume") == 0 ) {
-			int volume;
-
-			if ( ! argv[2] ) {  /* Print the current volume */
-				mesg("Current volume level: %d\n",
-								gSoundLevel);
-				exit(0);
-			}
-			if ( (volume=atoi(argv[2])) < 0 || volume > 8 ) {
-				error(
-	"Volume must be a number between 0 and 8. -- Exiting.\n");
-				exit(1);
-			}
-			/* We need to update the volume */
-			gSoundLevel = volume;
-			SaveControls();
-
-			++argv;
-			--argc;
 		} else if ( LogicParseArgs(&argv, &argc) == 0 ) {
 			/* LogicParseArgs() took care of everything */;
 		} else if ( strcmp(argv[1], "-version") == 0 ) {
@@ -330,6 +285,7 @@ int main(int argc, char *argv[])
 	/* Initialize everything. :) */
 	if ( DoInitializations(window_flags, render_flags) < 0 ) {
 		/* An error message was already printed */
+		CleanUp();
 		exit(1);
 	}
 
@@ -360,6 +316,7 @@ int main(int argc, char *argv[])
 	}
 
 	ui->HidePanel(PANEL_MAIN);
+	CleanUp();
 	exit(0);
 }	/* -- main */
 
@@ -528,7 +485,7 @@ MainPanelDelegate::OnTick()
 
 	label = m_panel->GetElement<UIElement>("volume");
 	if (label) {
-		sprintf(text, "%d", gSoundLevel);
+		sprintf(text, "%d", gSoundLevel.Value());
 		label->SetText(text);
 	}
 }
diff --git a/prefs.cpp b/prefs.cpp
index aeb32a94..5438879b 100644
--- a/prefs.cpp
+++ b/prefs.cpp
@@ -90,7 +90,7 @@ Prefs::Load()
 		SetString(key, value);
 
 		key = next;
-		while (*key && *key == '\r' && *key == '\n') {
+		while (*key && (*key == '\r' || *key == '\n')) {
 			++key;
 		}
 	}
diff --git a/prefs.h b/prefs.h
index 0fb7ffb7..81567f11 100644
--- a/prefs.h
+++ b/prefs.h
@@ -38,13 +38,102 @@ class Prefs
 
 	void SetString(const char *key, const char *value);
 	void SetNumber(const char *key, Uint32 value);
+	void Set(const char *key, const char *value) {
+		SetString(key, value);
+	}
+	void Set(const char *key, int value) {
+		SetNumber(key, value);
+	}
+	void Set(const char *key, Uint32 value) {
+		SetNumber(key, value);
+	}
+	void Set(const char *key, Uint8 value) {
+		SetNumber(key, value);
+	}
 
 	const char *GetString(const char *key, const char *defaultValue = NULL);
 	Uint32 GetNumber(const char *key, Uint32 defaultValue = 0);
+	void Get(const char *key, const char *&value, const char *defaultValue) {
+		value = GetString(key, defaultValue);
+	}
+	void Get(const char *key, int &value, int defaultValue) {
+		value = GetNumber(key, defaultValue);
+	}
+	void Get(const char *key, Uint32 &value, Uint32 defaultValue) {
+		value = GetNumber(key, defaultValue);
+	}
+	void Get(const char *key, Uint8 &value, Uint8 defaultValue) {
+		value = GetNumber(key, defaultValue);
+	}
 
 protected:
 	char *m_file;
 	HashTable *m_values;
 };
 
+template <typename T>
+class PrefsVariable
+{
+public:
+	PrefsVariable(const char *name, const T &rhs) {
+		m_prefs = NULL;
+		m_name = name;
+		m_defaultValue = m_value = rhs;
+	}
+
+	PrefsVariable& operator =(const T &rhs) {
+		m_value = rhs;
+		if (m_prefs) {
+			m_prefs->Set(m_name, m_value);
+		}
+		return *this;
+	}
+
+	PrefsVariable& operator =(const PrefsVariable<T> &rhs) {
+		return *this = rhs.m_value;
+	}
+
+	operator T() {
+		return m_value;
+	}
+
+	T& operator++() {
+		*this = m_value + 1;
+		return m_value;
+	}
+	T operator++(int) {
+		T value = m_value;
+		*this = m_value + 1;
+		return value;
+	}
+	T& operator--() {
+		*this = m_value - 1;
+		return m_value;
+	}
+	T operator--(int) {
+		T value = m_value;
+		*this = m_value - 1;
+		return value;
+	}
+
+	void Register(Prefs *prefs) {
+		m_prefs = prefs;
+		m_prefs->Get(m_name, m_value, m_defaultValue);
+	}
+
+	T Value() {
+		return m_value;
+	}
+
+	void Reset() {
+		*this = m_defaultValue;
+	}
+
+protected:
+	Prefs *m_prefs;
+	const char *m_name;
+	T m_value;
+	T m_defaultValue;
+};
+
 #endif /* _prefs_h */