shithub: choc

Download patch

ref: c358f7eb00154e58ae3c88d1cc7d4b7be856ccfa
parent: 228ea81c511dc2600def5b66a20b7e46f9c1da43
parent: 42e8b05aa46936ada3de4ee68c6dc005fccadfb4
author: Simon Howard <[email protected]>
date: Fri Oct 21 07:13:12 EDT 2016

Merge pull request #784 from CapnClever/raven-demo-expansion

Additional Heretic/Hexen demo support

--- a/NEWS.md
+++ b/NEWS.md
@@ -18,6 +18,10 @@
   * The vanilla limit of 4046 lumps per WAD is now enforced. (thanks
     Jon, Quasar, Edward-san)
   * Solidsegs overflow is emulated like in vanilla. (thanks Quasar)
+  * Heretic/Hexen demo support has expanded. "-demoextend" allows
+    demos to last longer than a single level; "-shortticfix" adjusts
+    low-resolution turning to match Doom's handling; "-maxdemo" and
+    "-longtics" support. (thanks CapnClever)
 
 ### Build systems
   * Improved compatibility with BSD Make. (thanks R.Rebello)
--- a/src/heretic/d_main.c
+++ b/src/heretic/d_main.c
@@ -1035,6 +1035,15 @@
         printf("Playing demo %s.\n", file);
     }
 
+    //!
+    // @category demo
+    //
+    // Record or playback a demo without automatically quitting
+    // after either level exit or player respawn.
+    //
+
+    demoextend = M_ParmExists("-demoextend");
+
     if (W_CheckNumForName(DEH_String("E2M1")) == -1)
     {
         gamemode = shareware;
--- a/src/heretic/d_net.c
+++ b/src/heretic/d_net.c
@@ -115,10 +115,17 @@
     startmap = settings->map;
     startskill = settings->skill;
     // TODO startloadgame = settings->loadgame;
+    lowres_turn = settings->lowres_turn;
     nomonsters = settings->nomonsters;
     respawnparm = settings->respawn_monsters;
     consoleplayer = settings->consoleplayer;
 
+    if (lowres_turn)
+    {
+        printf("NOTE: Turning resolution is reduced; this is probably "
+               "because there is a client recording a Vanilla demo.\n");
+    }
+
     for (i = 0; i < MAXPLAYERS; ++i)
     {
         playeringame[i] = i < settings->num_players;
@@ -142,7 +149,9 @@
     settings->nomonsters = nomonsters;
     settings->respawn_monsters = respawnparm;
     settings->timelimit = 0;
-    settings->lowres_turn = false;
+
+    settings->lowres_turn = M_ParmExists("-record")
+                         && !M_ParmExists("-longtics");
 }
 
 static void InitConnectData(net_connect_data_t *connect_data)
@@ -159,7 +168,10 @@
     connect_data->gamemode = gamemode;
     connect_data->gamemission = heretic;
 
-    connect_data->lowres_turn = false;
+    // Are we recording a demo? Possibly set lowres turn mode
+
+    connect_data->lowres_turn = M_ParmExists("-record")
+                             && !M_ParmExists("-longtics");
 
     // Read checksums of our WAD directory and dehacked information
 
--- a/src/heretic/doomdef.h
+++ b/src/heretic/doomdef.h
@@ -528,7 +528,12 @@
 
 extern boolean demorecording;
 extern boolean demoplayback;
+extern boolean demoextend;      // allow demos to persist through exit/respawn
 extern int skytexture;
+
+// Truncate angleturn in ticcmds to nearest 256.
+// Used when recording Vanilla demos in netgames.
+extern boolean lowres_turn;
 
 extern gamestate_t gamestate;
 extern skill_t gameskill;
--- a/src/heretic/g_game.c
+++ b/src/heretic/g_game.c
@@ -24,6 +24,7 @@
 #include "deh_str.h"
 #include "i_timer.h"
 #include "i_system.h"
+#include "m_argv.h"
 #include "m_controls.h"
 #include "m_misc.h"
 #include "m_random.h"
@@ -109,8 +110,12 @@
 
 char demoname[32];
 boolean demorecording;
+boolean longtics;               // specify high resolution turning in demos
+boolean lowres_turn;
+boolean shortticfix;            // calculate lowres turning like doom
 boolean demoplayback;
-byte *demobuffer, *demo_p;
+boolean demoextend;
+byte *demobuffer, *demo_p, *demoend;
 boolean singledemo;             // quit after playing a demo from cmdline
 
 boolean precache = true;        // if true, load all graphics at start
@@ -621,6 +626,32 @@
             BT_SPECIAL | BTS_SAVEGAME | (savegameslot << BTS_SAVESHIFT);
     }
 
+    if (lowres_turn)
+    {
+        if (shortticfix)
+        {
+            static signed short carry = 0;
+            signed short desired_angleturn;
+
+            desired_angleturn = cmd->angleturn + carry;
+
+            // round angleturn to the nearest 256 unit boundary
+            // for recording demos with single byte values for turn
+
+            cmd->angleturn = (desired_angleturn + 128) & 0xff00;
+
+            // Carry forward the error from the reduced resolution to the
+            // next tic, so that successive small movements can accumulate.
+
+            carry = desired_angleturn - cmd->angleturn;
+        }
+        else
+        {
+            // truncate angleturn to the nearest 256 boundary
+            // for recording demos with single byte values for turn
+            cmd->angleturn &= 0xff00;
+        }
+    }
 }
 
 
@@ -647,7 +678,6 @@
 
     P_SetupLevel(gameepisode, gamemap, 0, gameskill);
     displayplayer = consoleplayer;      // view the guy you are playing
-    starttime = I_GetTime();
     gameaction = ga_nothing;
     Z_CheckHeap();
 
@@ -1290,7 +1320,8 @@
 {
     int i;
 
-    if (G_CheckDemoStatus())
+    // quit demo unless -demoextend
+    if (!demoextend && G_CheckDemoStatus())
         return;
     if (!netgame)
         gameaction = ga_loadlevel;      // reload the level from scratch
@@ -1359,7 +1390,9 @@
     static int afterSecret[5] = { 7, 5, 5, 5, 4 };
 
     gameaction = ga_nothing;
-    if (G_CheckDemoStatus())
+
+    // quit demo unless -demoextend
+    if (!demoextend && G_CheckDemoStatus())
     {
         return;
     }
@@ -1619,6 +1652,9 @@
 */
 
 #define DEMOMARKER      0x80
+#define DEMOHEADER_RESPAWN    0x20
+#define DEMOHEADER_LONGTICS   0x10
+#define DEMOHEADER_NOMONSTERS 0x02
 
 void G_ReadDemoTiccmd(ticcmd_t * cmd)
 {
@@ -1629,7 +1665,19 @@
     }
     cmd->forwardmove = ((signed char) *demo_p++);
     cmd->sidemove = ((signed char) *demo_p++);
-    cmd->angleturn = ((unsigned char) *demo_p++) << 8;
+
+    // If this is a longtics demo, read back in higher resolution
+
+    if (longtics)
+    {
+        cmd->angleturn = *demo_p++;
+        cmd->angleturn |= (*demo_p++) << 8;
+    }
+    else
+    {
+        cmd->angleturn = ((unsigned char) *demo_p++) << 8;
+    }
+
     cmd->buttons = (unsigned char) *demo_p++;
     cmd->lookfly = (unsigned char) *demo_p++;
     cmd->arti = (unsigned char) *demo_p++;
@@ -1637,15 +1685,42 @@
 
 void G_WriteDemoTiccmd(ticcmd_t * cmd)
 {
+    byte *demo_start;
+
     if (gamekeydown[key_demo_quit]) // press to end demo recording
         G_CheckDemoStatus();
+
+    demo_start = demo_p;
+
     *demo_p++ = cmd->forwardmove;
     *demo_p++ = cmd->sidemove;
-    *demo_p++ = cmd->angleturn >> 8;
+
+    // If this is a longtics demo, record in higher resolution
+
+    if (longtics)
+    {
+        *demo_p++ = (cmd->angleturn & 0xff);
+        *demo_p++ = (cmd->angleturn >> 8) & 0xff;
+    }
+    else
+    {
+        *demo_p++ = cmd->angleturn >> 8;
+    }
+
     *demo_p++ = cmd->buttons;
     *demo_p++ = cmd->lookfly;
     *demo_p++ = cmd->arti;
-    demo_p -= 6;
+
+    // reset demo pointer back
+    demo_p = demo_start;
+
+    if (demo_p > demoend - 16)
+    {
+        // no more space
+        G_CheckDemoStatus();
+        return;
+    }
+
     G_ReadDemoTiccmd(cmd);      // make SURE it is exactly the same
 }
 
@@ -1663,17 +1738,76 @@
                   char *name)
 {
     int i;
+    int maxsize;
 
+    //!
+    // @category demo
+    //
+    // Record or playback a demo with high resolution turning.
+    //
+
+    longtics = M_ParmExists("-longtics");
+
+    // If not recording a longtics demo, record in low res
+
+    lowres_turn = !longtics;
+
+    //!
+    // @category demo
+    //
+    // Smooth out low resolution turning when recording a demo.
+    //
+
+    shortticfix = M_ParmExists("-shortticfix");
+
     G_InitNew(skill, episode, map);
     usergame = false;
     M_StringCopy(demoname, name, sizeof(demoname));
     M_StringConcat(demoname, ".lmp", sizeof(demoname));
-    demobuffer = demo_p = Z_Malloc(0x20000, PU_STATIC, NULL);
+    maxsize = 0x20000;
+
+    //!
+    // @arg <size>
+    // @category demo
+    // @vanilla
+    //
+    // Specify the demo buffer size (KiB)
+    //
+
+    i = M_CheckParmWithArgs("-maxdemo", 1);
+    if (i)
+        maxsize = atoi(myargv[i + 1]) * 1024;
+    demobuffer = Z_Malloc(maxsize, PU_STATIC, NULL);
+    demoend = demobuffer + maxsize;
+
+    demo_p = demobuffer;
     *demo_p++ = skill;
     *demo_p++ = episode;
     *demo_p++ = map;
 
-    for (i = 0; i < MAXPLAYERS; i++)
+    // Write special parameter bits onto player one byte.
+    // This aligns with vvHeretic demo usage:
+    //   0x20 = -respawn
+    //   0x10 = -longtics
+    //   0x02 = -nomonsters
+
+    *demo_p = 1; // assume player one exists
+    if (respawnparm)
+    {
+        *demo_p |= DEMOHEADER_RESPAWN;
+    }
+    if (longtics)
+    {
+        *demo_p |= DEMOHEADER_LONGTICS;
+    }
+    if (nomonsters)
+    {
+        *demo_p |= DEMOHEADER_NOMONSTERS;
+    }
+    demo_p++;
+    demo_p++;
+
+    for (i = 1; i < MAXPLAYERS; i++)
         *demo_p++ = playeringame[i];
 
     demorecording = true;
@@ -1707,8 +1841,13 @@
     episode = *demo_p++;
     map = *demo_p++;
 
+    // Read special parameter bits: see G_RecordDemo() for details.
+    respawnparm = (*demo_p & DEMOHEADER_RESPAWN) != 0;
+    longtics    = (*demo_p & DEMOHEADER_LONGTICS) != 0;
+    nomonsters  = (*demo_p & DEMOHEADER_NOMONSTERS) != 0;
+
     for (i = 0; i < MAXPLAYERS; i++)
-        playeringame[i] = *demo_p++;
+        playeringame[i] = (*demo_p++) != 0;
 
     precache = false;           // don't spend a lot of time in loadlevel
     G_InitNew(skill, episode, map);
@@ -1736,12 +1875,19 @@
     episode = *demo_p++;
     map = *demo_p++;
 
+    // Read special parameter bits: see G_RecordDemo() for details.
+    respawnparm = (*demo_p & DEMOHEADER_RESPAWN) != 0;
+    longtics    = (*demo_p & DEMOHEADER_LONGTICS) != 0;
+    nomonsters  = (*demo_p & DEMOHEADER_NOMONSTERS) != 0;
+
     for (i = 0; i < MAXPLAYERS; i++)
     {
-        playeringame[i] = *demo_p++;
+        playeringame[i] = (*demo_p++) != 0;
     }
 
     G_InitNew(skill, episode, map);
+    starttime = I_GetTime();
+
     usergame = false;
     demoplayback = true;
     timingdemo = true;
--- a/src/hexen/d_net.c
+++ b/src/hexen/d_net.c
@@ -116,10 +116,17 @@
     startmap = settings->map;
     startskill = settings->skill;
     // TODO startloadgame = settings->loadgame;
+    lowres_turn = settings->lowres_turn;
     nomonsters = settings->nomonsters;
     respawnparm = settings->respawn_monsters;
     consoleplayer = settings->consoleplayer;
 
+    if (lowres_turn)
+    {
+        printf("NOTE: Turning resolution is reduced; this is probably "
+               "because there is a client recording a Vanilla demo.\n");
+    }
+
     for (i=0; i<maxplayers; ++i)
     {
         playeringame[i] = i < settings->num_players;
@@ -154,7 +161,9 @@
     settings->nomonsters = nomonsters;
     settings->respawn_monsters = respawnparm;
     settings->timelimit = 0;
-    settings->lowres_turn = false;
+
+    settings->lowres_turn = M_ParmExists("-record")
+                         && !M_ParmExists("-longtics");
 }
 
 static void InitConnectData(net_connect_data_t *connect_data)
@@ -170,7 +179,11 @@
     connect_data->gamemode = gamemode;
     connect_data->gamemission = hexen;
 
-    connect_data->lowres_turn = false;
+    // Are we recording a demo? Possibly set lowres turn mode
+
+    connect_data->lowres_turn = M_ParmExists("-record")
+                             && !M_ParmExists("-longtics");
+
     connect_data->drone = false;
     connect_data->max_players = maxplayers;
 
--- a/src/hexen/g_game.c
+++ b/src/hexen/g_game.c
@@ -23,6 +23,7 @@
 #include "i_video.h"
 #include "i_system.h"
 #include "i_timer.h"
+#include "m_argv.h"
 #include "m_controls.h"
 #include "m_misc.h"
 #include "p_local.h"
@@ -92,8 +93,12 @@
 
 char demoname[32];
 boolean demorecording;
+boolean longtics;               // specify high resolution turning in demos
+boolean lowres_turn;
+boolean shortticfix;            // calculate lowres turning like doom
 boolean demoplayback;
-byte *demobuffer, *demo_p;
+boolean demoextend;
+byte *demobuffer, *demo_p, *demoend;
 boolean singledemo;             // quit after playing a demo from cmdline
 
 boolean precache = true;        // if true, load all graphics at start
@@ -621,6 +626,33 @@
         cmd->buttons =
             BT_SPECIAL | BTS_SAVEGAME | (savegameslot << BTS_SAVESHIFT);
     }
+
+    if (lowres_turn)
+    {
+        if (shortticfix)
+        {
+            static signed short carry = 0;
+            signed short desired_angleturn;
+
+            desired_angleturn = cmd->angleturn + carry;
+
+            // round angleturn to the nearest 256 unit boundary
+            // for recording demos with single byte values for turn
+
+            cmd->angleturn = (desired_angleturn + 128) & 0xff00;
+
+            // Carry forward the error from the reduced resolution to the
+            // next tic, so that successive small movements can accumulate.
+
+            carry = desired_angleturn - cmd->angleturn;
+        }
+        else
+        {
+            // truncate angleturn to the nearest 256 boundary
+            // for recording demos with single byte values for turn
+            cmd->angleturn &= 0xff00;
+        }
+    }
 }
 
 
@@ -648,7 +680,6 @@
     SN_StopAllSequences();
     P_SetupLevel(gameepisode, gamemap, 0, gameskill);
     displayplayer = consoleplayer;      // view the guy you are playing   
-    starttime = I_GetTime();
     gameaction = ga_nothing;
     Z_CheckHeap();
 
@@ -1292,7 +1323,8 @@
     boolean foundSpot;
     int bestWeapon;
 
-    if (G_CheckDemoStatus())
+    // quit demo unless -demoextend
+    if (!demoextend && G_CheckDemoStatus())
     {
         return;
     }
@@ -1487,7 +1519,9 @@
     int i;
 
     gameaction = ga_nothing;
-    if (G_CheckDemoStatus())
+
+    // quit demo unless -demoextend
+    if (!demoextend && G_CheckDemoStatus())
     {
         return;
     }
@@ -1738,10 +1772,16 @@
     }
 
     // Set up a bunch of globals
-    usergame = true;            // will be set false if a demo
+    if (!demoextend)
+    {
+        // This prevents map-loading from interrupting a demo.
+        // demoextend is set back to false only if starting a new game or
+        // loading a saved one from the menu, and only during playback.
+        demorecording = false;
+        demoplayback = false;
+        usergame = true;            // will be set false if a demo
+    }
     paused = false;
-    demorecording = false;
-    demoplayback = false;
     viewactive = true;
     gameepisode = episode;
     gamemap = map;
@@ -1771,6 +1811,9 @@
 */
 
 #define DEMOMARKER      0x80
+#define DEMOHEADER_RESPAWN    0x20
+#define DEMOHEADER_LONGTICS   0x10
+#define DEMOHEADER_NOMONSTERS 0x02
 
 void G_ReadDemoTiccmd(ticcmd_t * cmd)
 {
@@ -1781,7 +1824,19 @@
     }
     cmd->forwardmove = ((signed char) *demo_p++);
     cmd->sidemove = ((signed char) *demo_p++);
-    cmd->angleturn = ((unsigned char) *demo_p++) << 8;
+
+    // If this is a longtics demo, read back in higher resolution
+
+    if (longtics)
+    {
+        cmd->angleturn = *demo_p++;
+        cmd->angleturn |= (*demo_p++) << 8;
+    }
+    else
+    {
+        cmd->angleturn = ((unsigned char) *demo_p++) << 8;
+    }
+
     cmd->buttons = (unsigned char) *demo_p++;
     cmd->lookfly = (unsigned char) *demo_p++;
     cmd->arti = (unsigned char) *demo_p++;
@@ -1789,15 +1844,42 @@
 
 void G_WriteDemoTiccmd(ticcmd_t * cmd)
 {
+    byte *demo_start;
+
     if (gamekeydown[key_demo_quit]) // press to end demo recording
         G_CheckDemoStatus();
+
+    demo_start = demo_p;
+
     *demo_p++ = cmd->forwardmove;
     *demo_p++ = cmd->sidemove;
-    *demo_p++ = cmd->angleturn >> 8;
+
+    // If this is a longtics demo, record in higher resolution
+
+    if (longtics)
+    {
+        *demo_p++ = (cmd->angleturn & 0xff);
+        *demo_p++ = (cmd->angleturn >> 8) & 0xff;
+    }
+    else
+    {
+        *demo_p++ = cmd->angleturn >> 8;
+    }
+
     *demo_p++ = cmd->buttons;
     *demo_p++ = cmd->lookfly;
     *demo_p++ = cmd->arti;
-    demo_p -= 6;
+
+    // reset demo pointer back
+    demo_p = demo_start;
+
+    if (demo_p > demoend - 16)
+    {
+        // no more space
+        G_CheckDemoStatus();
+        return;
+    }
+
     G_ReadDemoTiccmd(cmd);      // make SURE it is exactly the same
 }
 
@@ -1815,21 +1897,82 @@
                   char *name)
 {
     int i;
+    int maxsize;
 
+    //!
+    // @category demo
+    //
+    // Record or playback a demo with high resolution turning.
+    //
+
+    longtics = M_ParmExists("-longtics");
+
+    // If not recording a longtics demo, record in low res
+
+    lowres_turn = !longtics;
+
+    //!
+    // @category demo
+    //
+    // Smooth out low resolution turning when recording a demo.
+    //
+
+    shortticfix = M_ParmExists("-shortticfix");
+
     G_InitNew(skill, episode, map);
     usergame = false;
     M_StringCopy(demoname, name, sizeof(demoname));
     M_StringConcat(demoname, ".lmp", sizeof(demoname));
-    demobuffer = demo_p = Z_Malloc(0x20000, PU_STATIC, NULL);
+    maxsize = 0x20000;
+
+    //!
+    // @arg <size>
+    // @category demo
+    // @vanilla
+    //
+    // Specify the demo buffer size (KiB)
+    //
+
+    i = M_CheckParmWithArgs("-maxdemo", 1);
+    if (i)
+        maxsize = atoi(myargv[i + 1]) * 1024;
+    demobuffer = Z_Malloc(maxsize, PU_STATIC, NULL);
+    demoend = demobuffer + maxsize;
+
+    demo_p = demobuffer;
     *demo_p++ = skill;
     *demo_p++ = episode;
     *demo_p++ = map;
 
-    for (i = 0; i < maxplayers; i++)
+    // Write special parameter bits onto player one byte.
+    // This aligns with vvHeretic demo usage. Hexen demo support has no
+    // precedent here so consistency with another game is chosen:
+    //   0x20 = -respawn
+    //   0x10 = -longtics
+    //   0x02 = -nomonsters
+
+    *demo_p = 1; // assume player one exists
+    if (respawnparm)
     {
+        *demo_p |= DEMOHEADER_RESPAWN;
+    }
+    if (longtics)
+    {
+        *demo_p |= DEMOHEADER_LONGTICS;
+    }
+    if (nomonsters)
+    {
+        *demo_p |= DEMOHEADER_NOMONSTERS;
+    }
+    demo_p++;
+    *demo_p++ = PlayerClass[0];
+
+    for (i = 1; i < maxplayers; i++)
+    {
         *demo_p++ = playeringame[i];
         *demo_p++ = PlayerClass[i];
     }
+
     demorecording = true;
 }
 
@@ -1861,9 +2004,14 @@
     episode = *demo_p++;
     map = *demo_p++;
 
+    // Read special parameter bits: see G_RecordDemo() for details.
+    respawnparm = (*demo_p & DEMOHEADER_RESPAWN) != 0;
+    longtics    = (*demo_p & DEMOHEADER_LONGTICS) != 0;
+    nomonsters  = (*demo_p & DEMOHEADER_NOMONSTERS) != 0;
+
     for (i = 0; i < maxplayers; i++)
     {
-        playeringame[i] = *demo_p++;
+        playeringame[i] = (*demo_p++) != 0;
         PlayerClass[i] = *demo_p++;
     }
 
@@ -1896,13 +2044,20 @@
     episode = *demo_p++;
     map = *demo_p++;
 
+    // Read special parameter bits: see G_RecordDemo() for details.
+    respawnparm = (*demo_p & DEMOHEADER_RESPAWN) != 0;
+    longtics    = (*demo_p & DEMOHEADER_LONGTICS) != 0;
+    nomonsters  = (*demo_p & DEMOHEADER_NOMONSTERS) != 0;
+
     for (i = 0; i < maxplayers; i++)
     {
-        playeringame[i] = *demo_p++;
+        playeringame[i] = (*demo_p++) != 0;
         PlayerClass[i] = *demo_p++;
     }
 
     G_InitNew(skill, episode, map);
+    starttime = I_GetTime();
+
     usergame = false;
     demoplayback = true;
     timingdemo = true;
--- a/src/hexen/h2_main.c
+++ b/src/hexen/h2_main.c
@@ -680,6 +680,15 @@
         ST_Message("Playing demo %s.\n", myargv[p+1]);
     }
 
+    //!
+    // @category demo
+    //
+    // Record or playback a demo without automatically quitting
+    // after either level exit or player respawn.
+    //
+
+    demoextend = M_ParmExists("-demoextend");
+
     if (M_ParmExists("-testcontrols"))
     {
         autostart = true;
--- a/src/hexen/h2def.h
+++ b/src/hexen/h2def.h
@@ -633,7 +633,12 @@
 extern boolean DebugSound;      // debug flag for displaying sound info
 
 extern boolean demoplayback;
+extern boolean demoextend;      // allow demos to persist through exit/respawn
 extern int maxzone;             // Maximum chunk allocated for zone heap
+
+// Truncate angleturn in ticcmds to nearest 256.
+// Used when recording Vanilla demos in netgames.
+extern boolean lowres_turn;
 
 extern int Sky1Texture;
 extern int Sky2Texture;
--- a/src/hexen/mn_menu.c
+++ b/src/hexen/mn_menu.c
@@ -130,6 +130,7 @@
 int InfoType;
 int messageson = true;
 boolean mn_SuicideConsole;
+boolean demoextend; // from h2def.h
 
 // PRIVATE DATA DEFINITIONS ------------------------------------------------
 
@@ -895,6 +896,11 @@
 
 static void SCLoadGame(int option)
 {
+    if (demoplayback)
+    {
+        // deactivate playback, return control to player
+        demoextend = false;
+    }
     if (!SlotStatus[option])
     {                           // Don't try to load from an empty slot
         return;
@@ -1003,6 +1009,12 @@
 
 static void SCSkill(int option)
 {
+    if (demoplayback)
+    {
+        // deactivate playback, return control to player
+        demoextend = false;
+    }
+
     PlayerClass[consoleplayer] = MenuPClass;
     G_DeferredNewGame(option);
     SB_SetClassData();