shithub: choc

Download patch

ref: a7a435cb7d5756ebff87d5f965b27fcc28fd96f6
parent: a24944d4e45da4bf0ba808a40c9e0eca15fb8b41
author: James Haley <[email protected]>
date: Sat Feb 12 00:00:43 EST 2011

Savegame code complete, hubs functional. Chocolate Strife is playable!

Subversion-branch: /branches/strife-branch
Subversion-revision: 2255

--- a/src/strife/d_englsh.h
+++ b/src/strife/d_englsh.h
@@ -44,12 +44,16 @@
 #define PRESSKEY 	"press a key."
 #define PRESSYN 	"press y or n."
 #define QUITMSG	"are you sure you want to\nquit this great game?"
-#define LOADNET 	"you can't do load while in a net game!\n\n"PRESSKEY
+// [STRIFE] modified:
+#define LOADNET 	"you can't load while in a net game!\n\n"PRESSKEY
 #define QLOADNET	"you can't quickload during a netgame!\n\n"PRESSKEY
-#define QSAVESPOT	"you haven't picked a quicksave slot yet!\n\n"PRESSKEY
-#define SAVEDEAD 	"you can't save if you aren't playing!\n\n"PRESSKEY
+// [STRIFE] modified:
+#define QSAVESPOT	"you haven't picked a\nquicksave slot yet!\n\n"PRESSKEY
+// [STRIFE] modified:
+#define SAVEDEAD 	"you're not playing a game\n\n"PRESSKEY
 #define QSPROMPT 	"quicksave over your game named\n\n'%s'?\n\n"PRESSYN
-#define QLPROMPT	"do you want to quickload the game named\n\n'%s'?\n\n"PRESSYN
+// [STRIFE] modified:
+#define QLPROMPT	"do you want to quickload\n\n'%s'?\n\n"PRESSYN
 
 #define NEWGAME	\
 "you can't start a new game\n"\
--- a/src/strife/d_main.c
+++ b/src/strife/d_main.c
@@ -682,7 +682,7 @@
         wipegamestate = -1;
         break;
     case 8: // demo
-        //ClearTmp();  STRIFE-TODO
+        ClearTmp();
         pagetic = 9*TICRATE;
         G_DeferedPlayDemo(DEH_String("demo1"));
         break;
@@ -1284,23 +1284,20 @@
         // Draw the background
         D_IntroBackground();
     }
+    /*
+    // STRIFE-FIXME: This was actually displayed on a special textmode
+    // screen with ANSI color codes...
     else
     {
         puts(DEH_String("Conversation ON"));
-        puts("\n");
         puts(DEH_String("Rogue Entertainment"));
-        puts("\n");
         puts(DEH_String("and"));
-        puts("\n");
         puts(DEH_String("Velocity Games"));
-        puts("\n");
         puts(DEH_String("present"));
-        puts("\n");
         puts(DEH_String("S T R I F E"));
-        puts("\n");
         puts(DEH_String("Loading..."));
-        puts("\n");
     }
+    */
 }
 
 //
@@ -1987,8 +1984,8 @@
 
     if (startloadgame >= 0)
     {
-        strcpy(file, P_SaveGameFile(startloadgame));
-        G_LoadGame (file);
+        // [STRIFE]: different, for hubs
+        M_LoadSelect(startloadgame);
     }
     D_IntroTick(); // [STRIFE]
 
--- a/src/strife/g_game.c
+++ b/src/strife/g_game.c
@@ -87,12 +87,12 @@
  
 void	G_DoLoadLevel (void); 
 void	G_DoNewGame (void); 
-void	G_DoLoadGame (void); 
+void	G_DoLoadGame (boolean userload); 
 void	G_DoPlayDemo (void); 
 void	G_DoCompleted (void); 
 void	G_DoVictory (void); 
 void	G_DoWorldDone (void); 
-void	G_DoSaveGame (void); 
+void	G_DoSaveGame (char *path); 
  
 // Gamestate the last time G_Ticker was called.
 
@@ -231,7 +231,7 @@
 static boolean  joyarray[MAX_JOY_BUTTONS + 1]; 
 static boolean *joybuttons = &joyarray[1];		// allow [-1] 
  
-static int      savegameslot; 
+static int      savegameslot = 6; // [STRIFE] initialized to 6
 static char     savedescription[32]; 
  
 static int      testcontrols_mousespeed;
@@ -865,7 +865,7 @@
 { 
     // allow spy mode changes even during the demo
     if (gamestate == GS_LEVEL && ev->type == ev_keydown 
-        && ev->data1 == key_spy && (singledemo || !deathmatch) )
+        && ev->data1 == key_spy && (singledemo || !gameskill) ) // [STRIFE]: o_O
     {
         // spy mode 
         do 
@@ -886,7 +886,10 @@
             (ev->type == ev_mouse && ev->data1) || 
             (ev->type == ev_joystick && ev->data1) ) 
         { 
-            M_StartControlPanel (); 
+            if(devparm && ev->data1 == 'g')
+                D_PageTicker(); // [STRIFE]: wat? o_O
+            else
+                M_StartControlPanel (); 
             return true; 
         } 
         return false; 
@@ -1002,16 +1005,14 @@
             G_DoNewGame (); 
             break; 
         case ga_loadgame: 
-            G_DoLoadGame (); 
-            // [STRIFE-TODO]:
-            // M_SaveMoveHereToMap();
-            // M_ReadMisObj(...);
+            G_DoLoadGame(true); 
+            M_SaveMoveHereToMap(); // [STRIFE]
+            M_ReadMisObj();
             break; 
         case ga_savegame: 
-            // [STRIFE-TODO]:
-            // M_SaveMoveMapToHere(...);
-            // M_SaveMisObj(...);
-            G_DoSaveGame (); 
+            M_SaveMoveMapToHere(); // [STRIFE]
+            M_SaveMisObj(savepath);
+            G_DoSaveGame(savepath); 
             break; 
         case ga_playdemo: 
             G_DoPlayDemo (); 
@@ -1039,6 +1040,8 @@
     // and build new consistancy check
     buf = (gametic/ticdup)%BACKUPTICS; 
 
+    // STRIFE-TODO: pnameprefixes bullcrap
+
     for (i=0 ; i<MAXPLAYERS ; i++)
     {
         if (playeringame[i]) 
@@ -1110,8 +1113,8 @@
                     break; 
 
                 case BTS_SAVEGAME: 
-                    if (!savedescription[0]) 
-                        strcpy (savedescription, "NET GAME"); 
+                    if (!character_name[0]) // [STRIFE]
+                        strcpy (character_name, "NET GAME"); 
                     savegameslot =  
                         (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT; 
                     gameaction = ga_savegame; 
@@ -1364,12 +1367,19 @@
 // G_LoadPath
 //
 // haleyjd 10/03/10: [STRIFE] New function
-// Sets loadpath based on the map and "savepath2"
+// Sets loadpath based on the map and "savepathtemp"
 //
 void G_LoadPath(int map)
 {
-    // STRIFE-TODO:
-    // sprintf(loadpath, "%s%d", savepath2, map)
+    char mapbuf[33];
+
+    memset(mapbuf, 0, sizeof(mapbuf));
+    sprintf(mapbuf, "%d", map);
+
+    // haleyjd: free if already set, and use M_SafeFilePath
+    if(loadpath)
+        Z_Free(loadpath);
+    loadpath = M_SafeFilePath(savepathtemp, mapbuf);
 }
 
 //
@@ -1382,10 +1392,9 @@
     if (!netgame)
     {
         // reload the level from scratch
-        // STRIFE-TODO: HUB REBORN
-        // G_LoadPath(gamemap);
-        // gameaction = 3;
-        gameaction = ga_loadlevel;  // STRIFE-TODO: temporary
+        // [STRIFE] Reborn level load
+        G_LoadPath(gamemap);
+        gameaction = ga_loadgame;
     }
     else 
     {
@@ -1425,7 +1434,11 @@
     } 
 } 
  
- 
+//
+// G_ScreenShot
+//
+// [STRIFE] Verified unmodified
+//
 void G_ScreenShot (void) 
 { 
     gameaction = ga_screenshot; 
@@ -1560,9 +1573,9 @@
     if (automapactive) 
         AM_Stop (); 
 
-    // STRIFE-TODO: needs call to G_DoSaveGame for hubs
-    // if(!deathmatch)
-    //     G_DoSaveGame(savepath2);
+    // [STRIFE] HUB SAVE
+    if(!deathmatch)
+        G_DoSaveGame(savepathtemp);
     
     gameaction = ga_worlddone;
 } 
@@ -1634,41 +1647,44 @@
 // G_DoWorldDone
 //
 // haleyjd 08/24/10: [STRIFE] Added destmap -> gamemap set.
-// STRIFE-TODO: Load hub save and other changes.
 //
 void G_DoWorldDone (void) 
 {        
     int temp_leveltime = leveltime;
+    boolean temp_shadow = false;
+    boolean temp_mvis   = false;
 
     gamestate = GS_LEVEL; 
     gamemap = destmap;
 
-    // STRIFE-TODO: hubs bullshit
-    // G_LoadPath();
-    // if (!deathmatch)
-    //  ebx0 = (*(_DWORD *)(players[0].mo + 104) & 0x8000000) > 0;
-    // G_DoLoadGame(...);
+    // [STRIFE] HUB LOAD
+    G_LoadPath(destmap);
+    if (!deathmatch)
+    {
+        // Remember Shadowarmor across hub loads
+        if(players[0].mo->flags & MF_SHADOW)
+            temp_shadow = true;
+        if(players[0].mo->flags & MF_MVIS)
+            temp_mvis = true;
+    }
+    G_DoLoadGame(false);
 
-    // temporary substitute:
-    G_DoLoadLevel (); 
-
     // [STRIFE] leveltime carries over between maps
     leveltime = temp_leveltime;
 
     if(!deathmatch)
     {
-        // STRIFE-TODO: powerup transfers etc
-        // *(_WORD *)(players[0].mo + 106) &= 0xF7FBu;
-        // if (v1)
-        //    *(_BYTE *)(plaeyrs[0].mo + 106) |= 4u;
-        // if (ebx0)
-        //    *(_BYTE *)(players[0].mo + 107) |= 8u;
+        // [STRIFE]: transfer saved powerups
+        players[0].mo->flags &= ~(MF_SHADOW|MF_MVIS);
+        if(temp_shadow)
+            players[0].mo->flags |= MF_SHADOW;
+        if(temp_mvis)
+            players[0].mo->flags |= MF_MVIS;
 
+        // [STRIFE] HUB SAVE
         G_RiftPlayer();
-
-        // STRIFE-TODO:
-        // G_DoSaveGame(savepath2);
-        // M_SaveMisObj(savepath2, v6);
+        G_DoSaveGame(savepathtemp);
+        M_SaveMisObj(savepathtemp);
     }
 
     gameaction = ga_nothing; 
@@ -1696,33 +1712,26 @@
 //
 void G_ReadCurrent(const char *path)
 {
-    // STRIFE-TODO: Can't go live. Too much bullshit.
-    // Without any kind of framework to work with file paths and directories
-    // this stuff is nearly hopeless, and I am already getting fed up with the
-    // idea of trying to make this work on 200 different platforms when there
-    // is nothing I can find in this thing to facilitate portable programming!
-#if 0
-    char temppath[108]; // WARNING: not big enough for modern file paths!
+    char *temppath = NULL;
+    byte *buffer = NULL;
 
-    // STRIFE-TODO: SYSTEM SPECIFIC DIRECTORY SEPARATORS!!!!!!!!!!!!!!!!
-    // What takes precedence? SeHackEd or Linux support?
-    // Where is the godforsaken global that will tell me what character to
-    // use in the first place?????
-    DEH_snprintf(temppath, "%s\\current", path);
-    
-    // STRIFE-TODO: MOVE TO P_SAVEG.C ???? NO SAVEBUFFER OR SAVE_P HERE!
-    // STRIFE-TODO: Read int from file with an appropriate routine
-    if(M_ReadFile(temppath, &savebuffer) <= 0)
+    temppath = M_SafeFilePath(path, "\\current");
+
+    if(M_ReadFile(temppath, &buffer) <= 0)
         gameaction = ga_newgame;
     else
     {
-        save_p = savebuffer;
-        gamemap = *(int *)savebuffer;
-        gameaction = 3;
-        Z_Free(savebuffer);
+        // haleyjd 20110211: do endian-correct read
+        gamemap = (((int)buffer[0])       |
+                   ((int)buffer[1] <<  8) |
+                   ((int)buffer[2] << 16) |
+                   ((int)buffer[3] << 24));
+        gameaction = ga_loadgame;
+        Z_Free(buffer);
     }
-#endif
 
+    Z_Free(temppath);
+    
     G_LoadPath(gamemap);
 }
 
@@ -1735,22 +1744,26 @@
 
 char	savename[256];
 
+// [STRIFE]: No such function, at least in v1.2
+// STRIFE-TODO: Does this come back in v1.31?
+/*
 void G_LoadGame (char* name) 
 { 
     strcpy (savename, name); 
     gameaction = ga_loadgame; 
 } 
+*/
  
 // haleyjd 09/28/10: [STRIFE] VERSIONSIZE == 8
 #define VERSIONSIZE             8
 
-void G_DoLoadGame (void) 
+void G_DoLoadGame (boolean userload) 
 {
-    //int savedleveltime;
+    int savedleveltime;
 
     gameaction = ga_nothing;
 
-    save_stream = fopen(savename, "rb");
+    save_stream = fopen(loadpath, "rb");
 
     // [STRIFE] If the file does not exist, G_DoLoadLevel is called.
     if (save_stream == NULL)
@@ -1767,25 +1780,25 @@
         return;
     }
 
-    // haleyjd: where did this come from? Was this in vanilla? o_O
-    //savedleveltime = leveltime;
+    // haleyjd: A comment would be good here, fraggle...
+    // Evidently this is a Choco-ism, necessitated by reading the savegame
+    // header *before* calling G_DoLoadLevel.
+    savedleveltime = leveltime;
     
     // load a base level
 
     // STRIFE-TODO: ????
-    // if(v4)
-         G_InitNew (gameskill, gamemap); 
-    // else
-    //   G_DoLoadLevel();
+    if(userload)
+        G_InitNew(gameskill, gamemap); 
+    else
+        G_DoLoadLevel();
  
-    // haleyjd: As above, no clue. leveltime is supposed to be saved into
-    // and restored from savegames, not carried over from whatever level 
-    // was  being previously played. The fact this is here at all is 
-    // bizarre.
-    //leveltime = savedleveltime;
+    leveltime = savedleveltime;
 
     // dearchive all the modifications
-    P_UnArchivePlayers (); 
+    // [STRIFE] some portions of player_t are not overwritten when loading
+    //   between hub levels
+    P_UnArchivePlayers (userload); 
     P_UnArchiveWorld (); 
     P_UnArchiveThinkers (); 
     P_UnArchiveSpecials (); 
@@ -1799,49 +1812,51 @@
         R_ExecuteSetViewSize ();
     
     // draw the pattern into the back screen
-    R_FillBackScreen ();   
+    R_FillBackScreen ();
 } 
 
 //
 // G_WriteSaveName
 //
-// haleyjd 10/03/10: [STRIFE] New function
+// haleyjd 2010103: [STRIFE] New function
 //
 // Writes the character name to the NAME file.
 //
-boolean G_WriteSaveName()
+boolean G_WriteSaveName(int slot, const char *charname)
 {
-    // STRIFE-TODO: Yeah right. This is gonna happen really soon...
-#if 0
-    const char *dirstr;
+    //char savedir[16];
+    char *tmpname;
+    boolean retval;
 
-    dword_86280 = eax0;
+    savegameslot = slot;
 
-#ifdef _WIN32
-    if(M_CheckParm("-cdrom") > 0)
-    {
-        sprintf(savepath2, "c:\\strife.cd\\strfsav%d.ssg\\", 6);
-        v5 = dword_86280;
-        dirstr = "c:\\strife.cd\\strfsav%d.ssg\\";
-    }
-    else
-#endif
-    {
-        sprintf(savepath2, "strfsav%d.ssg\\", 6);
-        v5 = dword_86280;
-        dirstr = "strfsav%d.ssg\\";
-    }
+    // haleyjd: removed special -cdrom treatment, as I believe it is taken
+    // care of automatically via using Choco's savegamedir setting.
 
-    sprintf(savepath, dirstr, v5);
+    // haleyjd: free previous path, if any, and allocate new one using
+    // M_SafeFilePath routine, which isn't limited to 128 characters.
+    if(savepathtemp)
+        Z_Free(savepathtemp);
+    savepathtemp = M_SafeFilePath(savegamedir, "strfsav6.ssg");
 
-    *character_name = 0;
-    strcpy(character_name, edx);
+    // haleyjd: as above.
+    if(savepath)
+        Z_Free(savepath);
+    savepath = M_SafeFilePath(savegamedir, M_MakeStrifeSaveDir(savegameslot, ""));
 
-    sprintf(hellifiknow, "%sname", savepath2);
+    // haleyjd: memset full character_name for safety
+    memset(character_name, 0, CHARACTER_NAME_LEN);
+    strcpy(character_name, charname);
 
-    return M_WriteFile(hellifiknow, character_name, 32);
-#endif
-    return false;
+    // haleyjd: use M_SafeFilePath
+    tmpname = M_SafeFilePath(savepathtemp, "name");
+
+    // Write the "name" file under the directory
+    retval = M_WriteFile(tmpname, character_name, 32);
+
+    Z_Free(tmpname);
+
+    return retval;
 }
 
 //
@@ -1849,6 +1864,9 @@
 // Called by the menu task.
 // Description is a 24 byte text string 
 //
+// [STRIFE] No such function, at least in v1.2
+// STRIFE-TODO: Does this make a comeback in v1.31?
+/*
 void
 G_SaveGame
 ( int	slot,
@@ -1858,16 +1876,33 @@
     strcpy (savedescription, description); 
     sendsave = true; 
 } 
+*/
  
-void G_DoSaveGame (void) 
+void G_DoSaveGame (char *path)
 { 
+    char *current_path;
     char *savegame_file;
     char *temp_savegame_file;
+    byte gamemapbytes[4];
+    char gamemapstr[33];
 
     temp_savegame_file = P_TempSaveGameFile();
-    savegame_file = P_SaveGameFile(savegameslot);
+    
+    // [STRIFE] custom save file path logic
+    memset(gamemapstr, 0, sizeof(gamemapstr));
+    sprintf(gamemapstr, "%d", gamemap);
+    savegame_file = M_SafeFilePath(path, gamemapstr);
 
-    // STRIFE-TODO: save the "current" file?
+    // [STRIFE] write the "current" file, which tells which hub map
+    //   the save slot is currently on.
+    current_path = M_SafeFilePath(path, "current");
+    // haleyjd: endian-agnostic IO
+    gamemapbytes[0] = (byte)( gamemap        & 0xff);
+    gamemapbytes[1] = (byte)((gamemap >>  8) & 0xff);
+    gamemapbytes[2] = (byte)((gamemap >> 16) & 0xff);
+    gamemapbytes[3] = (byte)((gamemap >> 24) & 0xff);
+    M_WriteFile(current_path, gamemapbytes, 4);
+    Z_Free(current_path);
 
     // Open the savegame file for writing.  We write to a temporary file
     // and then rename it at the end if it was successfully written.
@@ -1889,11 +1924,12 @@
     P_ArchiveWorld (); 
     P_ArchiveThinkers (); 
     P_ArchiveSpecials (); 
-	 
+
     P_WriteSaveGameEOF();
-	 
+
     // Enforce the same savegame size limit as in Vanilla Doom, 
     // except if the vanilla_savegame_limit setting is turned off.
+    // [STRIFE]: Verified subject to same limit.
 
     if (vanilla_savegame_limit && ftell(save_stream) > SAVEGAMESIZE)
     {
@@ -1910,19 +1946,27 @@
     remove(savegame_file);
     rename(temp_savegame_file, savegame_file);
     
+    // haleyjd: free the savegame_file path
+    Z_Free(savegame_file);
+
     gameaction = ga_nothing; 
-    strcpy(savedescription, "");
+    //strcpy(savedescription, "");
 
-    players[consoleplayer].message = DEH_String(GGSAVED);
+    // [STRIFE]: custom message logic
+    if(!strcmp(path, savepath))
+    {
+        sprintf(savename, "%s saved.", character_name);
+        players[consoleplayer].message = savename;
+    }
 
     // draw the pattern into the back screen
-    R_FillBackScreen ();	
+    R_FillBackScreen ();
 } 
  
 
 //
-skill_t	d_skill; 
-int     d_episode; 
+skill_t d_skill; 
+//int     d_episode; [STRIFE] No such thing as episodes in Strife
 int     d_map; 
 
 //
@@ -1936,7 +1980,6 @@
 void G_DeferedInitNew(skill_t skill, int map)
 { 
     d_skill = skill; 
-    d_episode = 1; // STRIFE-TODO: no such thing as episodes.
     d_map = map; 
     gameaction = ga_newgame; 
 } 
@@ -1945,6 +1988,7 @@
 // G_DoNewGame
 //
 // [STRIFE] Code added to turn off the stonecold effect.
+//   Someone also removed the nomonsters reset...
 //
 void G_DoNewGame (void) 
 {
@@ -1956,7 +2000,7 @@
     respawnparm = false;
     fastparm = false;
     stonecold = false;      // villsa [STRIFE]
-    nomonsters = false;
+    //nomonsters = false;   [STRIFE] not set here!?!
     consoleplayer = 0;
     G_InitNew (d_skill, d_map);
     gameaction = ga_nothing; 
@@ -1986,7 +2030,6 @@
         S_ResumeSound (); 
     } 
 
-
     if (skill > sk_nightmare) 
         skill = sk_nightmare;
 
@@ -2091,13 +2134,11 @@
     demoplayback = false; 
     automapactive = false; 
     viewactive = true; 
-    //gameepisode = episode; 
+    //gameepisode = episode; [STRIFE] no episodes
     gamemap = map; 
     gameskill = skill; 
     riftdest = 0; // haleyjd 08/24/10: [STRIFE] init riftdest to zero on new game
 
-    viewactive = true;
-
     // Set the sky to use.
     //
     // Note: This IS broken, but it is how Vanilla Doom behaves.  
@@ -2118,9 +2159,9 @@
 
     skytexture = R_TextureNumForName(skytexturename);
 
-    // STRIFE-TODO:
-    // G_LoadPath(gamemap)
-    G_DoLoadLevel ();
+    // [STRIFE] HUBS
+    G_LoadPath(gamemap);
+    G_DoLoadLevel();
 } 
  
 
@@ -2310,6 +2351,11 @@
 
 char*	defdemoname; 
  
+//
+// G_DeferedPlayDemo
+//
+// [STRIFE] Verified unmodified
+//
 void G_DeferedPlayDemo (char* name) 
 { 
     defdemoname = name; 
@@ -2414,7 +2460,9 @@
     precache = false;
     G_InitNew(skill, map); 
     precache = true; 
-    starttime = I_GetTime (); 
+    
+    // [STRIFE] not here...
+    //starttime = I_GetTime (); 
 
     usergame = false; 
     demoplayback = true; 
@@ -2435,6 +2483,8 @@
 
     nodrawers = M_CheckParm ("-nodraw"); 
 
+    // haleyjd: STRIFE-TODO: where's -noblit?
+
     timingdemo = true; 
     singletics = true; 
 
@@ -2452,7 +2502,9 @@
 = Returns true if a new demo loop action will take place 
 =================== 
 */ 
+//
 // [STRIFE] Verified unmodified
+//
 boolean G_CheckDemoStatus (void) 
 { 
     int             endtime; 
@@ -2501,7 +2553,7 @@
         M_WriteFile (demoname, demobuffer, demo_p - demobuffer); 
         Z_Free (demobuffer); 
         demorecording = false; 
-        I_Error ("Demo %s recorded",demoname); 
+        I_Error ("Demo %s recorded", demoname); 
     } 
 
     return false; 
--- a/src/strife/g_game.h
+++ b/src/strife/g_game.h
@@ -53,7 +53,7 @@
 // calls P_SetupLevel or W_EnterWorld.
 void G_LoadGame (char* name);
 
-void G_DoLoadGame (void);
+void G_DoLoadGame (boolean userload);
 
 // Called by M_Responder.
 void G_SaveGame (int slot, char* description);
@@ -87,6 +87,10 @@
 void G_ScreenShot (void);
 
 void G_DrawMouseSpeedBox(void);
+
+// [STRIFE]
+boolean G_WriteSaveName(int slot, const char *charname);
+void    G_ReadCurrent(const char *path);
 
 extern int vanilla_savegame_limit;
 extern int vanilla_demo_limit;
--- a/src/strife/m_menu.c
+++ b/src/strife/m_menu.c
@@ -54,6 +54,7 @@
 
 #include "m_argv.h"
 #include "m_controls.h"
+#include "m_saves.h"    // [STRIFE]
 #include "p_saveg.h"
 
 #include "s_sound.h"
@@ -69,10 +70,11 @@
 
 extern void M_QuitStrife(int);
 
-extern patch_t*		hu_font[HU_FONTSIZE];
-extern boolean		message_dontfuckwithme;
+extern patch_t*         hu_font[HU_FONTSIZE];
+extern boolean          message_dontfuckwithme;
 
-extern boolean		chat_on;		// in heads-up code
+extern boolean          chat_on;        // in heads-up code
+extern boolean          sendsave;       // [STRIFE]
 
 //
 // defaulted values
@@ -152,6 +154,9 @@
 char    *cursorName[8] = {"M_CURS1", "M_CURS2", "M_CURS3", "M_CURS4", 
                           "M_CURS5", "M_CURS6", "M_CURS7", "M_CURS8" };
 
+// haleyjd 20110210 [STRIFE]: skill level for menus
+int menuskill;
+
 // current menudef
 menu_t*	currentMenu;                          
 
@@ -296,11 +301,11 @@
 menuitem_t NewGameMenu[]=
 {
     // haleyjd 08/28/10: [STRIFE] changed all shortcut letters
-    {1,"M_JKILL",	M_ChooseSkill, 't'},
-    {1,"M_ROUGH",	M_ChooseSkill, 'r'},
-    {1,"M_HURT",	M_ChooseSkill, 'v'},
-    {1,"M_ULTRA",	M_ChooseSkill, 'e'},
-    {1,"M_NMARE",	M_ChooseSkill, 'b'}
+    {1,"M_JKILL",   M_ChooseSkill, 't'},
+    {1,"M_ROUGH",   M_ChooseSkill, 'r'},
+    {1,"M_HURT",    M_ChooseSkill, 'v'},
+    {1,"M_ULTRA",   M_ChooseSkill, 'e'},
+    {1,"M_NMARE",   M_ChooseSkill, 'b'}
 };
 
 menu_t  NewDef =
@@ -313,8 +318,6 @@
     toorough            // lastOn - haleyjd [STRIFE]: default to skill 1
 };
 
-
-
 //
 // OPTIONS MENU
 //
@@ -513,33 +516,59 @@
     0
 };
 
+void M_DrawNameChar(void);
 
 //
+// NAME CHARACTER MENU
+//
+// [STRIFE]
+// haleyjd 20110210: New "Name Your Character" Menu
+//
+menu_t NameCharDef =
+{
+    load_end,
+    &NewDef,
+    SaveMenu,
+    M_DrawNameChar,
+    80,54,
+    0
+};
+
+
+//
 // M_ReadSaveStrings
 //  read the strings from the savegame files
 //
+// [STRIFE]
+// haleyjd 20110210: Rewritten to read "name" file in each slot directory
+//
 void M_ReadSaveStrings(void)
 {
-    FILE   *handle;
-    int     count;
-    int     i;
-    char    name[256];
-	
-    for (i = 0;i < load_end;i++)
+    FILE *handle;
+    int   count;
+    int   i;
+    char *fname = NULL;
+
+    for(i = 0; i < load_end; i++)
     {
-        strcpy(name, P_SaveGameFile(i));
+        if(fname)
+            Z_Free(fname);
+        fname = M_SafeFilePath(savegamedir, M_MakeStrifeSaveDir(i, "\\name"));
 
-	handle = fopen(name, "rb");
-	if (handle == NULL)
-	{
-	    strcpy(&savegamestrings[i][0], EMPTYSTRING);
-	    LoadMenu[i].status = 0;
-	    continue;
-	}
-	count = fread(&savegamestrings[i], 1, SAVESTRINGSIZE, handle);
-	fclose(handle);
-	LoadMenu[i].status = 1;
+        handle = fopen(fname, "rb");
+        if(handle == NULL)
+        {
+            strcpy(savegamestrings[i], EMPTYSTRING);
+            LoadMenu[i].status = 0;
+            continue;
+        }
+        count = fread(savegamestrings[i], 1, SAVESTRINGSIZE, handle);
+        fclose(handle);
+        LoadMenu[i].status = 1;
     }
+
+    if(fname)
+        Z_Free(fname);
 }
 
 //
@@ -577,14 +606,13 @@
 {
     int map;
 
-    // STRIFE-TODO
-    // dword_9F144 = 1;
-    // ClearTmp();
-    // G_WriteSaveName(...);
-    // quickSaveSlot = v5;  // VERIFY VARIABLE
-    // SaveDef.lastOn = v5;
-    // ClearSlot();
-    // FromCurr(...);
+    sendsave = 1;
+    ClearTmp();
+    G_WriteSaveName(choice, savegamestrings[choice]);
+    quickSaveSlot = choice;  // VERIFY VARIABLE
+    SaveDef.lastOn = choice;
+    ClearSlot();
+    FromCurr();
     
     if(isdemoversion)
         map = 33;
@@ -591,7 +619,7 @@
     else
         map = 2;
 
-    //G_DeferedInitNew(skill, map);
+    G_DeferedInitNew(menuskill, map);
     M_ClearMenus(0);
 }
 
@@ -601,7 +629,7 @@
 void M_DrawLoad(void)
 {
     int             i;
-	
+
     V_DrawPatchDirect(72, 28, 
                       W_CacheLumpName(DEH_String("M_LOADG"), PU_CACHE));
 
@@ -642,6 +670,7 @@
 //
 void M_LoadSelect(int choice)
 {
+    /*
     char    name[256];
 
     strcpy(name, P_SaveGameFile(choice));
@@ -648,16 +677,33 @@
 
     G_LoadGame (name);
     M_ClearMenus (0);
+    */
+    
+    // [STRIFE] (v1.2) - TODO: v1.31
+    char *name = NULL;
+
+    G_WriteSaveName(choice, savegamestrings[choice]);
+    ToCurr();
+
+    name = M_SafeFilePath(savegamedir, M_MakeStrifeSaveDir(choice, ""));
+
+    G_ReadCurrent(name);
+    quickSaveSlot = choice;
+    M_ClearMenus(0);
+
+    Z_Free(name);
 }
 
 //
 // Selected from DOOM menu
 //
+// [STRIFE] Verified unmodified (v1.2) - TODO: v1.31
+//
 void M_LoadGame (int choice)
 {
     if (netgame)
     {
-        M_StartMessage(DEH_String(LOADNET),NULL,false);
+        M_StartMessage(DEH_String(LOADNET), NULL, false);
         return;
     }
 
@@ -692,12 +738,25 @@
 //
 void M_DoSave(int slot)
 {
+    /*
     G_SaveGame (slot,savegamestrings[slot]);
     M_ClearMenus (0);
 
     // PICK QUICKSAVE SLOT YET?
     if (quickSaveSlot == -2)
-	quickSaveSlot = slot;
+        quickSaveSlot = slot;
+    */
+    // [STRIFE] (v1.2) - TODO: v1.31
+    if(slot >= 0)
+    {
+        sendsave = 1;
+        G_WriteSaveName(slot, savegamestrings[slot]);
+        M_ClearMenus(0);
+        quickSaveSlot = slot;
+        FromCurr();
+    }
+    else
+        M_StartMessage(DEH_String(QSAVESPOT), NULL, false);
 }
 
 //
@@ -707,11 +766,14 @@
 {
     // we are going to be intercepting all chars
     saveStringEnter = 1;
-    
-    saveSlot = choice;
+
+    // [STRIFE] (v1.2) - TODO: 1.31
+    quickSaveSlot = choice;
+    //saveSlot = choice;
+
     strcpy(saveOldString,savegamestrings[choice]);
     if (!strcmp(savegamestrings[choice],EMPTYSTRING))
-	savegamestrings[choice][0] = 0;
+        savegamestrings[choice][0] = 0;
     saveCharIndex = strlen(savegamestrings[choice]);
 }
 
@@ -720,17 +782,26 @@
 //
 void M_SaveGame (int choice)
 {
+    // [STRIFE] (v1.2) - TODO: v1.31
+    if (netgame)
+    {
+        // haleyjd 20110211: Hooray for Rogue's awesome multiplayer support...
+        M_StartMessage(DEH_String("You can't save a netgame"), NULL, false);
+        return;
+    }
     if (!usergame)
     {
-	M_StartMessage(DEH_String(SAVEDEAD),NULL,false);
-	return;
+        M_StartMessage(DEH_String(SAVEDEAD),NULL,false);
+        return;
     }
-	
+
     if (gamestate != GS_LEVEL)
-	return;
-	
-    M_SetupNextMenu(&SaveDef);
+        return;
+
+    // [STRIFE] (v1.2) - TODO: v1.31
+    //M_SetupNextMenu(&SaveDef);
     M_ReadSaveStrings();
+    M_DoSave(quickSaveSlot);
 }
 
 
@@ -751,22 +822,29 @@
 
 void M_QuickSave(void)
 {
+    if (netgame)
+    {
+        // haleyjd 20110211 [STRIFE]: More fun...
+        M_StartMessage(DEH_String("You can't save a netgame"), NULL, false);
+        return;
+    }
+
     if (!usergame)
     {
-	S_StartSound(NULL, sfx_oof);
-	return;
+        S_StartSound(NULL, sfx_oof);
+        return;
     }
 
     if (gamestate != GS_LEVEL)
-	return;
-	
+        return;
+
     if (quickSaveSlot < 0)
     {
-	M_StartControlPanel();
-	M_ReadSaveStrings();
-	M_SetupNextMenu(&SaveDef);
-	quickSaveSlot = -2;	// means to pick a slot now
-	return;
+        M_StartControlPanel();
+        M_ReadSaveStrings();
+        M_SetupNextMenu(&SaveDef);
+        quickSaveSlot = -2;	// means to pick a slot now
+        return;
     }
     DEH_snprintf(tempstring, 80, QSPROMPT, savegamestrings[quickSaveSlot]);
     M_StartMessage(tempstring,M_QuickSaveResponse,true);
@@ -775,7 +853,7 @@
 
 
 //
-// M_QuickLoad
+// M_QuickLoadResponse
 //
 void M_QuickLoadResponse(int key)
 {
@@ -786,19 +864,23 @@
     }
 }
 
-
+//
+// M_QuickLoad
+//
+// [STRIFE] Verified unmodified (v1.2) - TODO: v1.31
+//
 void M_QuickLoad(void)
 {
     if (netgame)
     {
-	M_StartMessage(DEH_String(QLOADNET),NULL,false);
-	return;
+        M_StartMessage(DEH_String(QLOADNET),NULL,false);
+        return;
     }
-	
+
     if (quickSaveSlot < 0)
     {
-	M_StartMessage(DEH_String(QSAVESPOT),NULL,false);
-	return;
+        M_StartMessage(DEH_String(QSAVESPOT),NULL,false);
+        return;
     }
     DEH_snprintf(tempstring, 80, QLPROMPT, savegamestrings[quickSaveSlot]);
     M_StartMessage(tempstring,M_QuickLoadResponse,true);
@@ -877,16 +959,16 @@
 {
     switch(choice)
     {
-      case 0:
-	if (sfxVolume)
-	    sfxVolume--;
-	break;
-      case 1:
-	if (sfxVolume < 15)
-	    sfxVolume++;
-	break;
+    case 0:
+        if (sfxVolume)
+            sfxVolume--;
+        break;
+    case 1:
+        if (sfxVolume < 15)
+            sfxVolume++;
+        break;
     }
-	
+
     S_SetSfxVolume(sfxVolume * 8);
 }
 
@@ -918,16 +1000,16 @@
 {
     switch(choice)
     {
-      case 0:
-	if (musicVolume)
-	    musicVolume--;
-	break;
-      case 1:
-	if (musicVolume < 15)
-	    musicVolume++;
-	break;
+    case 0:
+        if (musicVolume)
+            musicVolume--;
+        break;
+    case 1:
+        if (musicVolume < 15)
+            musicVolume++;
+        break;
     }
-	
+
     S_SetMusicVolume(musicVolume * 8);
 }
 
@@ -996,10 +1078,11 @@
 void M_ChooseSkill(int choice)
 {
     // haleyjd 09/07/10: Removed nightmare confirmation
-    // STRIFE-TODO: This is not done here, but on the "Name your Character" menu.
-    // I have modified the starting map to 2 until the naming menu is functional.
-    G_DeferedInitNew(choice, 2);
-    M_ClearMenus (0);
+    // [STRIFE]: start "Name Your Character" menu
+    menuskill = choice;
+    currentMenu = &NameCharDef;
+    itemOn = NameCharDef.lastOn;
+    M_ReadSaveStrings();
 }
 
 /*
@@ -1053,9 +1136,41 @@
     M_SetupNextMenu(&OptionsDef);
 }
 
+//
+// M_AutoUseHealth
+//
+// [STRIFE] New function
+// haleyjd 20110211: toggle autouse health state
+//
+void M_AutoUseHealth(void)
+{
+    if(!netgame && usergame)
+    {
+        players[consoleplayer].cheats ^= CF_AUTOHEALTH;
 
+        if(players[consoleplayer].cheats & CF_AUTOHEALTH)
+            players[consoleplayer].message = DEH_String("Auto use health ON");
+        else
+            players[consoleplayer].message = DEH_String("Auto use health OFF");
+    }
+}
 
 //
+// M_ChangeShowText
+//
+// [STRIFE] New function
+//
+void M_ChangeShowText(void)
+{
+    dialogshowtext ^= true;
+
+    if(dialogshowtext)
+        players[consoleplayer].message = DEH_String("Conversation Text On");
+    else
+        players[consoleplayer].message = DEH_String("Conversation Text Off");
+}
+
+//
 //      Toggle messages on/off
 //
 void M_ChangeMessages(int choice)
@@ -1063,11 +1178,11 @@
     // warning: unused parameter `int choice'
     choice = 0;
     showMessages = 1 - showMessages;
-	
+
     if (!showMessages)
-	players[consoleplayer].message = DEH_String(MSGOFF);
+        players[consoleplayer].message = DEH_String(MSGOFF);
     else
-	players[consoleplayer].message = DEH_String(MSGON);
+        players[consoleplayer].message = DEH_String(MSGON);
 
     message_dontfuckwithme = true;
 }
@@ -1079,8 +1194,8 @@
 void M_EndGameResponse(int key)
 {
     if (key != key_menu_confirm)
-	return;
-		
+        return;
+
     currentMenu->lastOn = itemOn;
     M_ClearMenus (0);
     D_StartTitle ();
@@ -1091,16 +1206,16 @@
     choice = 0;
     if (!usergame)
     {
-	S_StartSound(NULL,sfx_oof);
-	return;
+        S_StartSound(NULL,sfx_oof);
+        return;
     }
-	
+
     if (netgame)
     {
-	M_StartMessage(DEH_String(NETEND),NULL,false);
-	return;
+        M_StartMessage(DEH_String(NETEND),NULL,false);
+        return;
     }
-	
+
     M_StartMessage(DEH_String(ENDGAME),M_EndGameResponse,true);
 }
 
@@ -1200,14 +1315,14 @@
 {
     switch(choice)
     {
-      case 0:
-	if (mouseSensitivity)
-	    mouseSensitivity--;
-	break;
-      case 1:
-	if (mouseSensitivity < 9)
-	    mouseSensitivity++;
-	break;
+    case 0:
+        if (mouseSensitivity)
+            mouseSensitivity--;
+        break;
+    case 1:
+        if (mouseSensitivity < 9)
+            mouseSensitivity++;
+        break;
     }
 }
 
@@ -1232,22 +1347,21 @@
 {
     switch(choice)
     {
-      case 0:
-	if (screenSize > 0)
-	{
-	    screenblocks--;
-	    screenSize--;
-	}
-	break;
-      case 1:
-	if (screenSize < 8)
-	{
-	    screenblocks++;
-	    screenSize++;
-	}
-	break;
+    case 0:
+        if (screenSize > 0)
+        {
+            screenblocks--;
+            screenSize--;
+        }
+        break;
+    case 1:
+        if (screenSize < 8)
+        {
+            screenblocks++;
+            screenSize++;
+        }
+        break;
     }
-	
 
     R_SetViewSize (screenblocks, detailLevel);
 }
@@ -1346,16 +1460,16 @@
     size_t             i;
     int             w = 0;
     int             c;
-	
+
     for (i = 0;i < strlen(string);i++)
     {
-	c = toupper(string[i]) - HU_FONTSTART;
-	if (c < 0 || c >= HU_FONTSIZE)
-	    w += 4;
-	else
-	    w += SHORT (hu_font[c]->width);
+        c = toupper(string[i]) - HU_FONTSTART;
+        if (c < 0 || c >= HU_FONTSIZE)
+            w += 4;
+        else
+            w += SHORT (hu_font[c]->width);
     }
-		
+
     return w;
 }
 
@@ -1369,12 +1483,12 @@
     size_t             i;
     int             h;
     int             height = SHORT(hu_font[0]->height);
-	
+
     h = height;
     for (i = 0;i < strlen(string);i++)
-	if (string[i] == '\n')
-	    h += height;
-		
+        if (string[i] == '\n')
+            h += height;
+
     return h;
 }
 
@@ -1689,9 +1803,10 @@
             break;
 
         case KEY_ENTER:
+            // [STRIFE] v1.2 - TODO: v1.31
             saveStringEnter = 0;
-            if (savegamestrings[saveSlot][0])
-                M_DoSave(saveSlot);
+            if (savegamestrings[quickSaveSlot][0])
+                M_DoNameChar(quickSaveSlot);
             break;
 
         default:
@@ -1741,11 +1856,17 @@
         return true;
     }
 
+    // [STRIFE]:
+    // * In v1.2 this is moved to F9 (quickload)
+    // * In v1.31 it is moved to a different button and quicksave
+    //   functionality is restored separate from normal saving (STRIFE-TODO)
+    /*
     if (devparm && key == key_menu_help)
     {
         G_ScreenShot ();
         return true;
     }
+    */
 
     // F-Keys
     if (!menuactive)
@@ -1778,16 +1899,35 @@
         }
         else if (key == key_menu_save)     // Save
         {
+            /*
             M_StartControlPanel();
             S_StartSound(NULL, sfx_swtchn);
             M_SaveGame(0);
+            */
+            // [STRIFE] (v1.2) - TODO: v1.31
+            if(netgame || players[consoleplayer].health <= 0 ||
+                players[consoleplayer].cheats & CF_ONFIRE)
+            {
+                S_StartSound(NULL, sfx_oof);
+            }
+            else
+            {
+                M_StartControlPanel();
+                S_StartSound(NULL, sfx_swtchn);
+                M_SaveGame(0);
+            }
             return true;
         }
         else if (key == key_menu_load)     // Load
         {
+            /*
             M_StartControlPanel();
             S_StartSound(NULL, sfx_swtchn);
             M_LoadGame(0);
+            */
+            // [STRIFE] (v1.2) - TODO: v1.31
+            S_StartSound(NULL, sfx_swtchn);
+            M_QuickLoad();
             return true;
         }
         else if (key == key_menu_volume)   // Sound Volume
@@ -1798,18 +1938,29 @@
             S_StartSound(NULL, sfx_swtchn);
             return true;
         }
-        /*
         else if (key == key_menu_detail)   // Detail toggle
         {
-            M_ChangeDetail(0);
+            //M_ChangeDetail(0);
+            M_AutoUseHealth(); // [STRIFE]
             S_StartSound(NULL,sfx_swtchn);
             return true;
         }
-        */
+        // STRIFE-TODO: autouse health toggle
         else if (key == key_menu_qsave)    // Quicksave
         {
-            S_StartSound(NULL, sfx_swtchn);
-            M_QuickSave();
+            //S_StartSound(NULL, sfx_swtchn);
+            //M_QuickSave();
+            // [STRIFE] (v1.2) - TODO: v1.31
+            if(netgame || players[consoleplayer].health <= 0 ||
+               players[consoleplayer].cheats & CF_ONFIRE)
+            {
+                S_StartSound(NULL, sfx_oof);
+            }
+            else
+            {
+                S_StartSound(NULL, sfx_swtchn);
+                M_QuickSave();
+            }
             return true;
         }
         else if (key == key_menu_endgame)  // End game
@@ -1820,14 +1971,21 @@
         }
         else if (key == key_menu_messages) // Toggle messages
         {
-            M_ChangeMessages(0);
+            //M_ChangeMessages(0);
+            M_ChangeShowText(); // [STRIFE]
             S_StartSound(NULL, sfx_swtchn);
             return true;
         }
         else if (key == key_menu_qload)    // Quickload
         {
+            // [STRIFE]
+            // * v1.2: takes a screenshot
+            // * v1.31: does quickload again... (STRIFE-TODO)
+            /*
             S_StartSound(NULL, sfx_swtchn);
             M_QuickLoad();
+            */
+            G_ScreenShot();
             return true;
         }
         else if (key == key_menu_quit)     // Quit DOOM
@@ -2145,6 +2303,10 @@
     messageString = NULL;
     messageLastMenuActive = menuactive; // STRIFE-FIXME: assigns 0 here...
     quickSaveSlot = -1;
+
+    // [STRIFE]: Initialize savegame paths and clear temporary directory
+    G_WriteSaveName(5, "ME");
+    ClearTmp();
 
     // Here we could catch other version dependencies,
     //  like HELP1/2, and four episodes.
--- a/src/strife/m_menu.h
+++ b/src/strife/m_menu.h
@@ -101,6 +101,7 @@
 
 // haleyjd [STRIFE] Externalized
 void M_ClearMenus (int choice);
+void M_LoadSelect(int choice);
 
 extern int detailLevel;
 extern int screenblocks;
--- a/src/strife/m_saves.c
+++ b/src/strife/m_saves.c
@@ -54,10 +54,12 @@
 //
 // Strife maintains multiple file paths related to savegames.
 //
-char *savepath;   // The actual path of the saveslot?
-char *savepath2;  // The path of the temporary saveslot?
-char *loadpath;   // Path used while loading the game
+char *savepath;     // The actual path of the selected saveslot
+char *savepathtemp; // The path of the temporary saveslot (strfsav6.ssg)
+char *loadpath;     // Path used while loading the game
 
+char character_name[CHARACTER_NAME_LEN]; // Name of "character" for saveslot
+
 //
 // ClearTmp
 //
@@ -68,11 +70,11 @@
     DIR *sp2dir = NULL;
     struct dirent *f = NULL;
 
-    if(savepath2 == NULL)
+    if(savepathtemp == NULL)
         I_Error("you fucked up savedir man!");
 
-    if(!(sp2dir = opendir(savepath2)))
-        I_Error("ClearTmp: Couldn't open dir %s", savepath2);
+    if(!(sp2dir = opendir(savepathtemp)))
+        I_Error("ClearTmp: Couldn't open dir %s", savepathtemp);
 
     while((f = readdir(sp2dir)))
     {
@@ -84,7 +86,7 @@
             continue;
 
         // haleyjd: use M_SafeFilePath, not sprintf
-        filepath = M_SafeFilePath(savepath2, f->d_name);
+        filepath = M_SafeFilePath(savepathtemp, f->d_name);
         remove(filepath);
 
         Z_Free(filepath);
@@ -129,7 +131,7 @@
 //
 // FromCurr
 //
-// Copying files from savepath2 to savepath
+// Copying files from savepathtemp to savepath
 //
 void FromCurr(void)
 {
@@ -136,8 +138,8 @@
     DIR *sp2dir = NULL;
     struct dirent *f = NULL;
 
-    if(!(sp2dir = opendir(savepath2)))
-        I_Error("FromCurr: Couldn't open dir %s", savepath2);
+    if(!(sp2dir = opendir(savepathtemp)))
+        I_Error("FromCurr: Couldn't open dir %s", savepathtemp);
 
     while((f = readdir(sp2dir)))
     {
@@ -152,8 +154,8 @@
             continue;
 
         // haleyjd: use M_SafeFilePath, NOT sprintf.
-        srcfilename = M_SafeFilePath(savepath2, f->d_name);
-        dstfilename = M_SafeFilePath(savepath,  f->d_name);
+        srcfilename = M_SafeFilePath(savepathtemp, f->d_name);
+        dstfilename = M_SafeFilePath(savepath,     f->d_name);
 
         filelen = M_ReadFile(srcfilename, &filebuffer);
         M_WriteFile(dstfilename, filebuffer, filelen);
@@ -169,7 +171,7 @@
 //
 // ToCurr
 //
-// Copying files from savepath to savepath2
+// Copying files from savepath to savepathtemp
 //
 void ToCurr(void)
 {
@@ -194,8 +196,8 @@
             continue;
 
         // haleyjd: use M_SafeFilePath, NOT sprintf.
-        srcfilename = M_SafeFilePath(savepath,  f->d_name);
-        dstfilename = M_SafeFilePath(savepath2, f->d_name);
+        srcfilename = M_SafeFilePath(savepath,     f->d_name);
+        dstfilename = M_SafeFilePath(savepathtemp, f->d_name);
 
         filelen = M_ReadFile(srcfilename, &filebuffer);
         M_WriteFile(dstfilename, filebuffer, filelen);
@@ -253,8 +255,8 @@
     memset(tmpnum, 0, sizeof(tmpnum));
     sprintf(tmpnum, "%d", gamemap);
 
-    mapsave  = M_SafeFilePath(savepath2, tmpnum);
-    heresave = M_SafeFilePath(savepath2, "here");
+    mapsave  = M_SafeFilePath(savepathtemp, tmpnum);
+    heresave = M_SafeFilePath(savepathtemp, "here");
 
     if(M_FileExists(heresave))
     {
@@ -295,7 +297,7 @@
     char *srcpath = NULL;
 
     // haleyjd: use M_SafeFilePath, not sprintf
-    srcpath = M_SafeFilePath(savepath2, "mis_obj");
+    srcpath = M_SafeFilePath(savepathtemp, "mis_obj");
 
     if((f = fopen(srcpath, "rb")))
     {
@@ -452,19 +454,30 @@
 
     for(i = 0; i < 7; i++)
     {
-        char dirname[16];
         char *compositedir;
 
-        memset(dirname, 0, sizeof(dirname));
-        sprintf(dirname, "STRFSAV%d.SSG", i);
-
         // compose the full path by concatenating with savedir
-        compositedir = M_SafeFilePath(savedir, dirname);
+        compositedir = M_SafeFilePath(savedir, M_MakeStrifeSaveDir(i, ""));
 
         M_MakeDirectory(compositedir);
 
         Z_Free(compositedir);
     }
+}
+
+//
+// M_MakeStrifeSaveDir
+//
+// haleyjd 20110211: Convenience routine
+//
+char *M_MakeStrifeSaveDir(int slotnum, const char *extra)
+{
+    static char tmpbuffer[32];
+
+    memset(tmpbuffer, 0, sizeof(tmpbuffer));
+    sprintf(tmpbuffer, "strfsav%d.ssg%s", slotnum, extra);
+
+    return tmpbuffer;
 }
 
 // 
--- a/src/strife/m_saves.h
+++ b/src/strife/m_saves.h
@@ -30,9 +30,12 @@
 #ifndef M_SAVES_H__
 #define M_SAVES_H__
 
+#define CHARACTER_NAME_LEN 32
+
 extern char *savepath;
-extern char *savepath2;
+extern char *savepathtemp;
 extern char *loadpath;
+extern char character_name[CHARACTER_NAME_LEN];
 
 // Strife Savegame Functions
 void ClearTmp(void);
@@ -51,6 +54,7 @@
 int   M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...);
 char *M_SafeFilePath(const char *basepath, const char *newcomponent);
 char  M_GetFilePath(const char *fn, char *dest, size_t len);
+char *M_MakeStrifeSaveDir(int slotnum, const char *extra);
 void  M_CreateSaveDirs(const char *savedir);
 
 #endif
--- a/src/strife/p_dialog.h
+++ b/src/strife/p_dialog.h
@@ -45,6 +45,8 @@
 
 extern char mission_objective[OBJECTIVE_LEN];
 
+extern boolean dialogshowtext;
+
 // villsa - convenient macro for giving objective logs to player
 #define GiveObjective(x, minlumpnum) \
 do { \
--- a/src/strife/p_saveg.c
+++ b/src/strife/p_saveg.c
@@ -1720,21 +1720,32 @@
 //
 // [STRIFE] Verified unmodified.
 //
-void P_UnArchivePlayers (void)
+void P_UnArchivePlayers (boolean userload)
 {
     int         i;
 
     for (i=0 ; i<MAXPLAYERS ; i++)
     {
+        player_t dummy;
+
         if (!playeringame[i])
             continue;
 
         saveg_read_pad();
 
-        saveg_read_player_t(&players[i]);
+        // haleyjd [STRIFE]: not exactly how vanilla did it, but this is
+        // necessary because of Choco's change to the savegame code which
+        // reads it directly from file. When not a userload, all the player_t
+        // data loaded from the save is thrown away.
+        if(userload)
+        {
+            saveg_read_player_t(&players[i]);
+            players[i].mo = NULL;
+        }
+        else
+            saveg_read_player_t(&dummy);
 
         // will be set when unarc thinker
-        players[i].mo = NULL;	
         players[i].message = NULL;
         players[i].attacker = NULL;
     }
--- a/src/strife/p_saveg.h
+++ b/src/strife/p_saveg.h
@@ -55,7 +55,7 @@
 // Persistent storage/archiving.
 // These are the load / save game routines.
 void P_ArchivePlayers (void);
-void P_UnArchivePlayers (void);
+void P_UnArchivePlayers (boolean userload);
 void P_ArchiveWorld (void);
 void P_UnArchiveWorld (void);
 void P_ArchiveThinkers (void);