diff --git a/doc/ChangeLog.html b/doc/ChangeLog.html
index 2b1c9a9f8..9bcca5c74 100644
--- a/doc/ChangeLog.html
+++ b/doc/ChangeLog.html
@@ -1008,6 +1008,7 @@
     <LI>Fixed bug #628947: WC2 Graphic Display Errors (from Jimmy Salmon).
     <LI>Added smooth scrolling for messages (from Jimmy Salmon).
     <LI>Fixed bug #657167: Crash on human campaign level 2 (from Jimmy Salmon).
+    <LI>Added load/save of config options (from Jimmy Salmon).
     <LI>+++
     </UL>
 </UL>
diff --git a/src/include/script.h b/src/include/script.h
index 59306c312..d851289fa 100644
--- a/src/include/script.h
+++ b/src/include/script.h
@@ -117,6 +117,7 @@ extern void CclGcProtect(SCM obj);	/// Protect scm object for GC
 extern void InitCcl(void);		/// Initialise ccl
 extern void LoadCcl(void);		/// Load ccl config file
 extern void SaveCcl(FILE* file);	/// Save CCL module
+extern void SavePreferences(void);	/// Save user preferences
 extern void CclCommand(const char*);	/// Execute a ccl command
 extern void CclFree(void*);		/// Save free
 
diff --git a/src/include/sound.h b/src/include/sound.h
index a0b01673d..cc6d97287 100644
--- a/src/include/sound.h
+++ b/src/include/sound.h
@@ -76,6 +76,7 @@ typedef struct _game_sound_ {
     **	really turning it off on the server side.
     */
 extern int SoundOff;
+extern int MusicOff;			/// Music turned off
 
 extern GameSound GameSounds;		/// Game sound configuration
 
diff --git a/src/sound/music.cpp b/src/sound/music.cpp
index 6de3ebc5c..8238661fa 100644
--- a/src/sound/music.cpp
+++ b/src/sound/music.cpp
@@ -450,6 +450,10 @@ global void PlayMusic(const char* name)
     }
 #endif
 
+    if (MusicOff) {
+	return;
+    }
+
     name = LibraryFileName(name, buffer);
 
 #ifdef USE_OGG
diff --git a/src/sound/script_sound.cpp b/src/sound/script_sound.cpp
index beb0bf252..7c2e5ca0c 100644
--- a/src/sound/script_sound.cpp
+++ b/src/sound/script_sound.cpp
@@ -409,6 +409,28 @@ local SCM CclSoundOn(void)
     return SCM_BOOL_F;
 }
 
+/**
+**	Turn Off Music (client side)
+*/
+local SCM CclMusicOff(void)
+{
+    StopMusic();
+    MusicOff=1;
+    return SCM_UNSPECIFIED;
+}
+
+/**
+**	Turn On Music (client side)
+**
+**	@return true if and only if the sound is REALLY turned on
+**		(uses SoundFildes)
+*/
+local SCM CclMusicOn(void)
+{
+    MusicOff=0;
+    return SCM_UNSPECIFIED;
+}
+
 /**
 **	Set the cut off distance.
 **
@@ -516,6 +538,8 @@ global void SoundCclRegister(void)
 
     init_subr_0("sound-off",CclSoundOff);
     init_subr_0("sound-on",CclSoundOn);
+    init_subr_0("music-off",CclMusicOff);
+    init_subr_0("music-on",CclMusicOn);
     init_subr_0("sound-thread",CclSoundThread);
     init_subr_1("set-global-sound-range!",CclSetGlobalSoundRange);
     init_lsubr("define-game-sounds",CclDefineGameSounds);
@@ -585,6 +609,25 @@ local SCM CclSoundOn(void)
     return SCM_BOOL_T;
 }
 
+/**
+**	Turn Off Music (client side)
+*/
+local SCM CclMusicOff(void)
+{
+    return SCM_UNSPECIFIED;
+}
+
+/**
+**	Turn On Music (client side)
+**
+**	@return true if and only if the sound is REALLY turned on
+**		(uses SoundFildes)
+*/
+local SCM CclMusicOn(void)
+{
+    return SCM_UNSPECIFIED;
+}
+
 /**
 **	Set the cut off distance.
 **
@@ -685,6 +728,8 @@ global void SoundCclRegister(void)
     gh_new_procedure1_0("set-cd-mode!",CclSetCdMode);
     gh_new_procedure0_0("sound-off",CclSoundOff);
     gh_new_procedure0_0("sound-on",CclSoundOn);
+    gh_new_procedure0_0("music-off",CclMusicOff);
+    gh_new_procedure0_0("music-on",CclMusicOn);
     gh_new_procedure0_0("sound-thread",CclSoundThread);
     gh_new_procedure1_0("set-global-sound-range!",CclSetGlobalSoundRange);
     gh_new_procedureN("define-game-sounds",CclDefineGameSounds);
diff --git a/src/sound/sound.cpp b/src/sound/sound.cpp
index 400a1ef78..cf0ebc527 100644
--- a/src/sound/sound.cpp
+++ b/src/sound/sound.cpp
@@ -59,6 +59,7 @@
 ----------------------------------------------------------------------------*/
 
 global int SoundOff;			/// True quiet, sound turned off
+global int MusicOff;			/// Music turned off
 
 /**
 **	Various sounds used in game.
diff --git a/src/sound/sound_server.cpp b/src/sound/sound_server.cpp
index 6d1323371..2adca92c7 100644
--- a/src/sound/sound_server.cpp
+++ b/src/sound/sound_server.cpp
@@ -1210,8 +1210,11 @@ global int InitSound(void)
 */
 global int InitSoundServer(void)
 {
-    int MapWidth = (TheUI.MapArea.EndX-TheUI.MapArea.X +TileSizeX) / TileSizeX;
-    int MapHeight = (TheUI.MapArea.EndY-TheUI.MapArea.Y +TileSizeY) / TileSizeY;
+    int MapWidth;
+    int MapHeight;
+
+    MapWidth = (TheUI.MapArea.EndX-TheUI.MapArea.X +TileSizeX) / TileSizeX;
+    MapHeight = (TheUI.MapArea.EndY-TheUI.MapArea.Y +TileSizeY) / TileSizeY;
     //FIXME: Valid only in shared memory context!
     DistanceSilent=3*max(MapWidth,MapHeight);
     DebugLevel2("Distance Silent: %d\n" _C_ DistanceSilent);
diff --git a/src/stratagus/script.cpp b/src/stratagus/script.cpp
index 0b02e052c..27fb04d09 100644
--- a/src/stratagus/script.cpp
+++ b/src/stratagus/script.cpp
@@ -55,6 +55,9 @@
 #include "trigger.h"
 #include "settings.h"
 #include "editor.h"
+#include "sound.h"
+#include "sound_server.h"
+#include "netconnect.h"
 
 /*----------------------------------------------------------------------------
 --	Variables
@@ -117,6 +120,28 @@ local SCM CclSetGameCycle(SCM cycle)
     return SCM_UNSPECIFIED;
 }
 
+/**
+**	Set the video sync speed
+*/
+local SCM CclSetVideoSyncSpeed(SCM speed)
+{
+    VideoSyncSpeed=gh_scm2int(speed);
+    return SCM_UNSPECIFIED;
+}
+
+/**
+**	Set the local player name
+*/
+local SCM CclSetLocalPlayerName(SCM name)
+{
+    char *str;
+
+    str = gh_scm2newstr(name,NIL);
+    strncpy(LocalPlayerName,str,sizeof(LocalPlayerName)-1);
+    LocalPlayerName[sizeof(LocalPlayerName)-1]='\0';
+    return SCM_UNSPECIFIED;
+}
+
 /**
 **	Enable/disable Showing the tips at the start of a level.
 **
@@ -133,6 +158,25 @@ local SCM CclSetShowTips(SCM flag)
     return gh_bool2scm(old);
 }
 
+/**
+**	Set the current tip number.
+**
+**	@param tip	Tip number.
+**	@return		The old tip number.
+*/
+local SCM CclSetCurrentTip(SCM tip)
+{
+    int old;
+
+    old=CurrentTip;
+    CurrentTip=gh_scm2int(tip);
+    if (CurrentTip >= MAX_TIPS || Tips[CurrentTip] == NULL) {
+	CurrentTip = 0;
+    }
+
+    return gh_int2scm(old);
+}
+
 /**
 **	Add a new tip to the list of tips.
 **
@@ -577,8 +621,11 @@ global void InitCcl(void)
     gh_new_procedure0_0("library-path",CclFreeCraftLibraryPath);
     gh_new_procedure0_0("game-cycle",CclGameCycle);
     gh_new_procedure1_0("set-game-cycle!",CclSetGameCycle);
+    gh_new_procedure1_0("set-video-sync-speed!",CclSetVideoSyncSpeed);
+    gh_new_procedure1_0("set-local-player-name!",CclSetLocalPlayerName);
 
     gh_new_procedure1_0("set-show-tips!",CclSetShowTips);
+    gh_new_procedure1_0("set-current-tip!",CclSetCurrentTip);
     gh_new_procedure1_0("add-tip",CclAddTip);
 
     gh_new_procedure1_0("set-speed-mine!",CclSetSpeedMine);
@@ -721,6 +768,146 @@ global void InitCcl(void)
     print_welcome();
 }
 
+/**
+**	Load user preferences
+*/
+local void LoadPreferences1(void)
+{
+    FILE* fd;
+    char buf[1024];
+
+#ifdef USE_WIN32
+    strcpy(buf,"preferences1.ccl");
+#else
+    sprintf(buf,"%s/%s/preferences1.ccl",getenv("HOME"),FREECRAFT_HOME_PATH);
+#endif
+
+    fd=fopen(buf,"r");
+    if( fd ) {
+	fclose(fd);
+	vload(buf,0,1);
+    }
+}
+
+/**
+**	Load user preferences
+*/
+local void LoadPreferences2(void)
+{
+    FILE* fd;
+    char buf[1024];
+
+#ifdef USE_WIN32
+    strcpy(buf,"preferences2.ccl");
+#else
+    sprintf(buf,"%s/%s/preferences2.ccl",getenv("HOME"),FREECRAFT_HOME_PATH);
+#endif
+
+    fd=fopen(buf,"r");
+    if( fd ) {
+	fclose(fd);
+	vload(buf,0,1);
+    }
+}
+
+/**
+**	Save user preferences
+*/
+global void SavePreferences(void)
+{
+    FILE* fd;
+    char buf[1024];
+
+    //
+    //	    preferences1.ccl
+    //	    This file is loaded before freecraft.ccl
+    //
+
+#ifdef USE_WIN32
+    strcpy(buf,"preferences1.ccl");
+#else
+    sprintf(buf,"%s/%s/preferences1.ccl",getenv("HOME"),FREECRAFT_HOME_PATH);
+#endif
+
+    fd=fopen(buf,"w");
+    if( !fd ) {
+	return;
+    }
+
+    fprintf(fd,";;; -----------------------------------------\n");
+    fprintf(fd,";;; $Id$\n");
+
+    fprintf(fd,"(set-video-resolution! %d %d)\n", VideoWidth, VideoHeight);
+    
+    fclose(fd);
+
+
+    //
+    //	    preferences2.ccl
+    //	    This file is loaded after freecraft.ccl
+    //
+
+#ifdef USE_WIN32
+    strcpy(buf,"preferences2.ccl");
+#else
+    sprintf(buf,"%s/%s/preferences2.ccl",getenv("HOME"),FREECRAFT_HOME_PATH);
+#endif
+
+    fd=fopen(buf,"w");
+    if( !fd ) {
+	return;
+    }
+
+    fprintf(fd,";;; -----------------------------------------\n");
+    fprintf(fd,";;; $Id$\n");
+
+    // Global options
+    if( OriginalFogOfWar ) {
+	fprintf(fd,"(original-fog-of-war)\n");
+    } else {
+	fprintf(fd,"(gray-fog-of-war)\n");
+    }
+    fprintf(fd,"(set-video-fullscreen! #%c)\n", VideoFullScreen ? 't' : 'f');
+#if 0
+    // FIXME: Uncomment when this is configurable in the menus
+    fprintf(fd,"(set-contrast! %d)\n", TheUI.Contrast);
+    fprintf(fd,"(set-brightness! %d)\n", TheUI.Brightness);
+    fprintf(fd,"(set-saturation! %d)\n", TheUI.Saturation);
+#endif
+    fprintf(fd,"(set-local-player-name! \"%s\")\n", LocalPlayerName);
+
+    // Game options
+    fprintf(fd,"(set-show-tips! #%c)\n", ShowTips ? 't' : 'f');
+    fprintf(fd,"(set-current-tip! %d)\n", CurrentTip);
+
+    fprintf(fd,"(set-fog-of-war! #%c)\n", !TheMap.NoFogOfWar ? 't' : 'f');
+    fprintf(fd,"(set-show-command-key! #%c)\n", ShowCommandKey ? 't' : 'f');
+
+    // Speeds
+    fprintf(fd,"(set-video-sync-speed! %d)\n", VideoSyncSpeed);
+    fprintf(fd,"(set-mouse-scroll-speed! %d)\n", SpeedMouseScroll);
+    fprintf(fd,"(set-key-scroll-speed! %d)\n", SpeedKeyScroll);
+
+    // Sound options
+    if( !SoundOff ) {
+	fprintf(fd,"(sound-on)\n");
+    } else {
+	fprintf(fd,"(sound-off)\n");
+    }
+    fprintf(fd,"(set-sound-volume! %d)\n", GlobalVolume);
+    if( !MusicOff ) {
+	fprintf(fd,"(music-on)\n");
+    } else {
+	fprintf(fd,"(music-off)\n");
+    }
+    fprintf(fd,"(set-music-volume! %d)\n", MusicVolume);
+#if defined(USE_SDLCD) || defined(USE_LIBCDA) || defined(USE_CDDA)
+    fprintf(fd,"(set-cd-mode! \"%s\")\n", CDMode);
+#endif
+
+    fclose(fd);
+}
+
 /**
 **	Load freecraft config file.
 */
@@ -735,6 +922,7 @@ global void LoadCcl(void)
     //	Load and evaluate configuration file
     //
     CclInConfigFile=1;
+    LoadPreferences1();
     file=LibraryFileName(CclStartFile,buf);
     ShowLoadProgress("Script %s\n",file);
     if( (s=strrchr(file,'.')) && s[1]=='C' ) {
@@ -742,6 +930,7 @@ global void LoadCcl(void)
     } else {
 	vload(file,0,1);
     }
+    LoadPreferences2();
     CclInConfigFile=0;
     user_gc(SCM_BOOL_F);		// Cleanup memory after load
 }
diff --git a/src/stratagus/stratagus.cpp b/src/stratagus/stratagus.cpp
index 8e23402c9..5b04f842f 100644
--- a/src/stratagus/stratagus.cpp
+++ b/src/stratagus/stratagus.cpp
@@ -1200,7 +1200,7 @@ Use it at your own risk.\n\n");
     //
     InitVideo();			// setup video display
 #ifdef WITH_SOUND
-    if( InitSound() ) {			// setup sound card
+    if( !SoundOff && InitSound() ) {			// setup sound card
 	SoundOff=1;
 	SoundFildes=-1;
     }
diff --git a/src/ui/menus.cpp b/src/ui/menus.cpp
index 975cd8082..027aecbc5 100644
--- a/src/ui/menus.cpp
+++ b/src/ui/menus.cpp
@@ -125,6 +125,7 @@ local void SurrenderConfirmMenu(void);
 
 // Global Options
 local void GlobalOptionsInit(Menuitem *mi);
+local void GlobalOptionsExit(Menuitem *mi);
 local void GlobalOptionsResolutionGem(Menuitem *mi);
 local void GlobalOptionsFullscreenGem(Menuitem *mi);
 local void GlobalOptionsFogAlphaGem(Menuitem *mi);
@@ -204,6 +205,7 @@ local void EndScenarioQuitMenu(void);
 
 // Sound options
 local void SoundOptionsInit(Menuitem *mi);
+local void SoundOptionsExit(Menuitem *mi);
 local void MasterVolumeHSAction(Menuitem *mi, int i);
 local void SetMasterPower(Menuitem *mi);
 local void MusicVolumeHSAction(Menuitem *mi, int i);
@@ -215,10 +217,13 @@ local void SetCdModeRandom(Menuitem *mi);
 
 // Preferences
 local void PreferencesInit(Menuitem *mi);
+local void PreferencesExit(Menuitem *mi);
 local void SetFogOfWar(Menuitem *mi);
 local void SetCommandKey(Menuitem *mi);
 
 // Speed options
+local void SpeedOptionsInit(Menuitem *mi);
+local void SpeedOptionsExit(Menuitem *mi);
 local void GameSpeedHSAction(Menuitem *mi, int i);
 local void MouseScrollHSAction(Menuitem *mi, int i);
 local void KeyboardScrollHSAction(Menuitem *mi, int i);
@@ -485,6 +490,7 @@ global void InitMenuFuncHash(void) {
 
 // Global Options
     HASHADD(GlobalOptionsInit,"global-options-init");
+    HASHADD(GlobalOptionsExit,"global-options-exit");
     HASHADD(GlobalOptionsResolutionGem,"global-options-resolution-gem");
     HASHADD(GlobalOptionsFullscreenGem,"global-options-fullscreen-gem");
     HASHADD(GlobalOptionsFogAlphaGem,"global-options-fog-alpha-gem");
@@ -563,6 +569,7 @@ global void InitMenuFuncHash(void) {
 
 // Sound options
     HASHADD(SoundOptionsInit,"sound-options-init");
+    HASHADD(SoundOptionsExit,"sound-options-exit");
     HASHADD(MasterVolumeHSAction,"master-volume-hs-action");
     HASHADD(SetMasterPower,"set-master-power");
     HASHADD(MusicVolumeHSAction,"music-volume-hs-action");
@@ -574,10 +581,13 @@ global void InitMenuFuncHash(void) {
 
 // Preferences
     HASHADD(PreferencesInit,"preferences-init");
+    HASHADD(PreferencesExit,"preferences-exit");
     HASHADD(SetFogOfWar,"set-fog-of-war");
     HASHADD(SetCommandKey,"set-command-key");
 
 // Speed options
+    HASHADD(SpeedOptionsInit,"speed-options-init");
+    HASHADD(SpeedOptionsExit,"speed-options-exit");
     HASHADD(GameSpeedHSAction,"game-speed-hs-action");
     HASHADD(MouseScrollHSAction,"mouse-scroll-hs-action");
     HASHADD(KeyboardScrollHSAction,"keyboard-scroll-hs-action");
@@ -1555,6 +1565,15 @@ local void SoundOptionsInit(Menuitem *mi __attribute__((unused)))
 #endif // with sound
 }
 
+/**
+**	Exit callback for sound options menu
+*/
+local void SoundOptionsExit(Menuitem *mi __attribute__((unused)))
+{
+    // FIXME: Only save if something changed
+    SavePreferences();
+}
+
 /**
 **	Global options menu
 */
@@ -1603,6 +1622,15 @@ local void GlobalOptionsInit(Menuitem *mi __attribute__((unused)))
     }
 }
 
+/**
+**	Exit callback for global options menu
+*/
+local void GlobalOptionsExit(Menuitem *mi __attribute__((unused)))
+{
+    // FIXME: Only save if something changed
+    SavePreferences();
+}
+
 /**
 **	Global options resolution gem callback
 */
@@ -1635,6 +1663,7 @@ local void GlobalOptionsResolutionGem(Menuitem *mi)
 
 	VideoWidth = res;
 	VideoHeight = res * 3 / 4;
+	SavePreferences();
 	InitVideo();
 	DestroyCursorBackground();
 	SetClipping(0,0,VideoWidth-1,VideoHeight-1);
@@ -1711,9 +1740,11 @@ local void SetMusicPower(Menuitem *mi __attribute__((unused)))
 #ifdef WITH_SOUND
     SCM cb;
 
-    if (PlayingMusic == 1) {
+    if (!MusicOff) {
+	MusicOff = 1;
 	StopMusic();
     } else {
+	MusicOff = 0;
 	if (CallbackMusic) {
 	    cb = gh_symbol2scm("music-stopped");
 	    if (!gh_null_p(symbol_boundp(cb, NIL))) {
@@ -1829,12 +1860,20 @@ local void SetCdModeRandom(Menuitem *mi __attribute__((unused)))
 **	Speed settings menu
 */
 global void SpeedOptionsMenu(void)
+{
+    ProcessMenu("menu-speed-options", 1);
+}
+
+/**
+**	Init callback for speed settings menu
+*/
+global void SpeedOptionsInit(Menuitem *mi __attribute__((unused)))
 {
     Menu *menu;
     int i;
     
     i = 2;
-    menu = FindMenu("menu-speed-options");
+    menu = CurrentMenu;
 
     menu->items[i].d.hslider.percent = ((VideoSyncSpeed - MIN_GAME_SPEED) * 100) / (MAX_GAME_SPEED - MIN_GAME_SPEED);
     if (menu->items[i].d.hslider.percent < 0) {
@@ -1852,8 +1891,15 @@ global void SpeedOptionsMenu(void)
     if (TheUI.KeyScroll == 0) {
 	menu->items[i + 8].d.hslider.percent = 0;
     }
+}
 
-    ProcessMenu("menu-speed-options", 1);
+/**
+**	Exit callback for speed settings menu
+*/
+global void SpeedOptionsExit(Menuitem *mi __attribute__((unused)))
+{
+    // FIXME: Only save if something changed
+    SavePreferences();
 }
 
 /**
@@ -2022,6 +2068,15 @@ local void PreferencesInit(Menuitem *mi __attribute__((unused)))
     }
 }
 
+/**
+**	Preferences menu init callback
+*/
+local void PreferencesExit(Menuitem *mi __attribute__((unused)))
+{
+    // FIXME: Only save if something changed
+    SavePreferences();
+}
+
 /**
 **	Show the game options.
 */
@@ -2261,6 +2316,7 @@ local void TipsExit(Menuitem *mi __attribute__((unused)))
 {
     TipsCycleNextTip();
     TipsFreeTips();
+    SavePreferences();
 }
 
 /**
@@ -2891,6 +2947,9 @@ local void MultiPlayerGameMenu(void)
     memset(LocalPlayerName, 0, 16);
     strcpy(LocalPlayerName, NameBuf);
 
+    // FIXME: Only save if player name changed
+    SavePreferences();
+
     GuiGameStarted = 0;
     // Here we really go...
     // ProcessMenu("menu-create-join-menu", 1);
diff --git a/src/ui/script_ui.cpp b/src/ui/script_ui.cpp
index 8c68b3f2e..6fe90cc21 100644
--- a/src/ui/script_ui.cpp
+++ b/src/ui/script_ui.cpp
@@ -192,6 +192,39 @@ local SCM CclSetSaturation(SCM saturation)
     return old;
 }
 
+/**
+**	Set the video resolution.
+**
+**	@param width	Resolution width.
+**	@param height	Resolution height.
+*/
+local SCM CclSetVideoResolution(SCM width,SCM height)
+{
+    if( CclInConfigFile ) {
+	VideoWidth=gh_scm2int(width);
+	VideoHeight=gh_scm2int(height);
+    }
+    return SCM_UNSPECIFIED;
+}
+
+/**
+**	Set the video fullscreen mode.
+**
+**	@param fullscreen	True for fullscreen, false for window.
+**
+**	@return			Old fullscreen mode
+*/
+local SCM CclSetVideoFullscreen(SCM fullscreen)
+{
+    SCM old;
+
+    old=gh_int2scm(VideoFullScreen);
+    if( CclInConfigFile ) {
+	VideoFullScreen=gh_scm2bool(fullscreen);
+    }
+    return old;
+}
+
 /**
 **	Default title-screen.
 **
@@ -3338,6 +3371,9 @@ global void UserInterfaceCclRegister(void)
     gh_new_procedure1_0("set-brightness!",CclSetBrightness);
     gh_new_procedure1_0("set-saturation!",CclSetSaturation);
 
+    gh_new_procedure2_0("set-video-resolution!",CclSetVideoResolution);
+    gh_new_procedure1_0("set-video-fullscreen!",CclSetVideoFullscreen);
+
     gh_new_procedure1_0("set-title-screen!",CclSetTitleScreen);
     gh_new_procedure1_0("set-menu-background!",CclSetMenuBackground);
     gh_new_procedure1_0("set-menu-background-with-title!",