commit 8dab0a3e635db40359c8ddeb9afaa9eca626ee98
Merge: 005747a6 678a8f9a
Author: Simon Howard <fraggle@gmail.com>
AuthorDate: Fri Dec 10 22:44:01 2010 +0000
Commit: Simon Howard <fraggle@gmail.com>
CommitDate: Fri Dec 10 22:44:01 2010 +0000
Merge from trunk. This is slightly out of date as I did the merge
several days ago.
Subversion-branch: /branches/raven-branch
Subversion-revision: 2212
Makefile.am | 1 +
NEWS | 48 +++-
NOT-BUGS | 112 ++++++++
README | 10 +-
data/convert-icon | 7 +-
man/docgen | 25 +-
opl/opl_sdl.c | 4 +-
pkg/config.make.in | 1 +
pkg/wince/wince-cabgen | 40 ++-
src/Makefile.am | 1 +
src/d_iwad.c | 1 +
src/d_mode.h | 1 +
src/deh_io.c | 141 ++++++++--
src/deh_io.h | 1 +
src/deh_main.c | 49 +++-
src/deh_main.h | 2 +
src/doom/d_main.c | 86 ++++--
src/doom/d_net.c | 24 +-
src/doom/doomstat.h | 1 -
src/doom/m_menu.c | 2 +
src/doom/p_setup.c | 12 +-
src/doom/p_spec.c | 5 +-
src/doom/r_data.c | 20 +-
src/i_sdlsound.c | 41 ++-
src/i_video.c | 207 ++++++++++++---
src/i_video.h | 1 +
src/m_argv.c | 2 +-
src/m_config.c | 6 +
src/net_dedicated.c | 2 +-
src/net_defs.h | 8 +
src/net_loop.c | 22 +-
src/net_query.c | 691 +++++++++++++++++++++++++++++++++++++++----------
src/net_query.h | 15 +-
src/net_server.c | 73 +++++-
src/net_server.h | 4 +
src/setup/display.c | 243 ++++++++++++++++-
src/setup/joystick.c | 4 +-
textscreen/txt_sdl.c | 33 ++-
38 files changed, 1630 insertions(+), 316 deletions(-)
diff --cc src/d_iwad.c
index ab1dd823,89a7fba3..9bf53b9a
--- a/src/d_iwad.c
+++ b/src/d_iwad.c
@@@ -39,19 -39,6 +39,20 @@@
#include "w_wad.h"
#include "z_zone.h"
+static iwad_t iwads[] =
+{
+ { "doom2.wad", doom2, commercial, "Doom II" },
+ { "plutonia.wad", pack_plut, commercial, "Final Doom: Plutonia Experiment" },
+ { "tnt.wad", pack_tnt, commercial, "Final Doom: TNT: Evilution" },
+ { "doom.wad", doom, retail, "Doom" },
+ { "doom1.wad", doom, shareware, "Doom Shareware" },
+ { "chex.wad", doom, shareware, "Chex Quest" },
++ { "hacx.wad", doom2, commercial, "Hacx" },
+ { "heretic.wad", heretic, retail, "Heretic" },
+ { "heretic1.wad", heretic, shareware, "Heretic Shareware" },
+ { "hexen.wad", hexen, commercial, "Hexen" },
+};
+
// Array of locations to search for IWAD files
//
// "128 IWAD search directories should be enough for anybody".
diff --cc src/d_mode.h
index f7e93562,00000000..29f61c10
mode 100644,000000..100644
--- a/src/d_mode.h
+++ b/src/d_mode.h
@@@ -1,94 -1,0 +1,95 @@@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Functions and definitions relating to the game type and operational
+// mode.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __D_MODE__
+#define __D_MODE__
+
+#include "doomtype.h"
+
+// The "mission" controls what game we are playing.
+
+typedef enum
+{
+ doom, // Doom 1
+ doom2, // Doom 2
+ pack_tnt, // Final Doom: TNT: Evilution
+ pack_plut, // Final Doom: The Plutonia Experiment
+ heretic, // Heretic
+ hexen, // Hexen
+
+ none
+} GameMission_t;
+
+// The "mode" allows more accurate specification of the game mode we are
+// in: eg. shareware vs. registered. So doom1.wad and doom.wad are the
+// same mission, but a different mode.
+
+typedef enum
+{
+ shareware, // Doom/Heretic shareware
+ registered, // Doom/Heretic registered
+ commercial, // Doom II/Hexen
+ retail, // Ultimate Doom
+ indetermined // Unknown.
+} GameMode_t;
+
+// What version are we emulating?
+
+typedef enum
+{
+ exe_doom_1_9, // Doom 1.9: used for shareware, registered and commercial
++ exe_hacx, // Hacx
+ exe_ultimate, // Ultimate Doom (retail)
+ exe_final, // Final Doom
+ exe_chex, // Chex Quest executable (based on Final Doom)
+
+ exe_heretic_1_3, // Heretic 1.3
+
+ exe_hexen_1_1 // Hexen 1.1
+} GameVersion_t;
+
+// Skill level.
+
+typedef enum
+{
+ sk_noitems = -1, // the "-skill 0" hack
+ sk_baby = 0,
+ sk_easy,
+ sk_medium,
+ sk_hard,
+ sk_nightmare
+} skill_t;
+
+boolean D_ValidGameMode(GameMission_t mission, GameMode_t mode);
+boolean D_ValidGameVersion(GameMission_t mission, GameVersion_t version);
+boolean D_ValidEpisodeMap(GameMission_t mission, GameMode_t mode,
+ int episode, int map);
+int D_GetNumEpisodes(GameMission_t mission, GameMode_t mode);
+boolean D_IsEpisodeMap(GameMission_t mission);
+
+#endif /* #ifndef __D_MODE__ */
+
diff --cc src/doom/d_main.c
index fed6a1b4,032c5caa..69dd6e9f
--- a/src/doom/d_main.c
+++ b/src/doom/d_main.c
@@@ -424,22 -397,10 +422,14 @@@ void D_DoomLoop (void
if (demorecording)
G_BeginRecording ();
- if (M_CheckParm ("-debugfile"))
- {
- char filename[20];
- sprintf (filename,"debug%i.txt",consoleplayer);
- printf ("debug output to: %s\n",filename);
- debugfile = fopen (filename,"w");
- }
-
TryRunTics();
- I_InitGraphics ();
+ I_SetWindowTitle(gamedescription);
+ I_InitGraphics();
+ I_EnableLoadingDisk();
+ I_SetGrabMouseCallback(D_GrabMouseCallback);
+ V_RestoreBuffer();
R_ExecuteSetViewSize();
D_StartGameLoop();
@@@ -606,233 -564,9 +596,245 @@@ void D_StartTitle (void
D_AdvanceDemo ();
}
+// Strings for dehacked replacements of the startup banner
+//
+// These are from the original source: some of them are perhaps
+// not used in any dehacked patches
+
- static char *banners[] =
++static char *banners[] =
+{
++ // doom2.wad
++ " "
++ "DOOM 2: Hell on Earth v%i.%i"
++ " ",
+ // doom1.wad
+ " "
+ "DOOM Shareware Startup v%i.%i"
+ " ",
+ // doom.wad
+ " "
+ "DOOM Registered Startup v%i.%i"
+ " ",
+ // Registered DOOM uses this
+ " "
+ "DOOM System Startup v%i.%i"
+ " ",
+ // doom.wad (Ultimate DOOM)
+ " "
+ "The Ultimate DOOM Startup v%i.%i"
+ " ",
- // doom2.wad
- " "
- "DOOM 2: Hell on Earth v%i.%i"
- " ",
+ // tnt.wad
+ " "
+ "DOOM 2: TNT - Evilution v%i.%i"
+ " ",
+ // plutonia.wad
+ " "
+ "DOOM 2: Plutonia Experiment v%i.%i"
+ " ",
+};
+//
+// Get game name: if the startup banner has been replaced, use that.
+// Otherwise, use the name given
+//
+static char *GetGameName(char *gamename)
+{
+ size_t i;
+ char *deh_sub;
+
+ for (i=0; i<arrlen(banners); ++i)
+ {
+ // Has the banner been replaced?
+
+ deh_sub = DEH_String(banners[i]);
+
+ if (deh_sub != banners[i])
+ {
+ // Has been replaced
+ // We need to expand via printf to include the Doom version
+ // number
+ // We also need to cut off spaces to get the basic name
+
+ gamename = Z_Malloc(strlen(deh_sub) + 10, PU_STATIC, 0);
+ sprintf(gamename, deh_sub, DOOM_VERSION / 100, DOOM_VERSION % 100);
+
+ while (gamename[0] != '\0' && isspace(gamename[0]))
+ strcpy(gamename, gamename+1);
+
+ while (gamename[0] != '\0' && isspace(gamename[strlen(gamename)-1]))
+ gamename[strlen(gamename) - 1] = '\0';
+
+ return gamename;
+ }
+ }
+
+ return gamename;
+}
+
+//
+// Find out what version of Doom is playing.
+//
+
+void D_IdentifyVersion(void)
+{
+ // gamemission is set up by the D_FindIWAD function. But if
+ // we specify '-iwad', we have to identify using
+ // IdentifyIWADByName. However, if the iwad does not match
+ // any known IWAD name, we may have a dilemma. Try to
+ // identify by its contents.
+
+ if (gamemission == none)
+ {
+ unsigned int i;
+
+ for (i=0; i<numlumps; ++i)
+ {
+ if (!strncasecmp(lumpinfo[i].name, "MAP01", 8))
+ {
+ gamemission = doom2;
+ break;
+ }
+ else if (!strncasecmp(lumpinfo[i].name, "E1M1", 8))
+ {
+ gamemission = doom;
+ break;
+ }
+ }
+
+ if (gamemission == none)
+ {
+ // Still no idea. I don't think this is going to work.
+
+ I_Error("Unknown or invalid IWAD file.");
+ }
+ }
+
+ // Make sure gamemode is set up correctly
+
+ if (gamemission == doom)
+ {
+ // Doom 1. But which version?
+
+ if (W_CheckNumForName("E4M1") > 0)
+ {
+ // Ultimate Doom
+
+ gamemode = retail;
+ }
+ else if (W_CheckNumForName("E3M1") > 0)
+ {
+ gamemode = registered;
+ }
+ else
+ {
+ gamemode = shareware;
+ }
+ }
+ else
+ {
+ // Doom 2 of some kind.
+
+ gamemode = commercial;
+ }
+}
+
+// Set the gamedescription string
+
+void D_SetGameDescription(void)
+{
+ gamedescription = "Unknown";
+
+ if (gamemission == doom)
+ {
+ // Doom 1. But which version?
+
+ if (gamemode == retail)
+ {
+ // Ultimate Doom
+
+ gamedescription = GetGameName("The Ultimate DOOM");
+ }
+ else if (gamemode == registered)
+ {
+ gamedescription = GetGameName("DOOM Registered");
+ }
+ else if (gamemode == shareware)
+ {
+ gamedescription = GetGameName("DOOM Shareware");
+ }
+ }
+ else
+ {
+ // Doom 2 of some kind. But which mission?
+
+ if (gamemission == doom2)
+ gamedescription = GetGameName("DOOM 2: Hell on Earth");
+ else if (gamemission == pack_plut)
+ gamedescription = GetGameName("DOOM 2: Plutonia Experiment");
+ else if (gamemission == pack_tnt)
+ gamedescription = GetGameName("DOOM 2: TNT - Evilution");
+ }
+}
+
+static void SetSaveGameDir(char *iwad_filename)
+{
+ char *sep;
+ char *basefile;
+
+ // Extract the base filename
+
+ sep = strrchr(iwad_filename, DIR_SEPARATOR);
+
+ if (sep == NULL)
+ {
+ basefile = iwad_filename;
+ }
+ else
+ {
+ basefile = sep + 1;
+ }
+
+ // ~/.chocolate-doom/savegames/
+
+ savegamedir = Z_Malloc(strlen(configdir) + 30, PU_STATIC, 0);
+ sprintf(savegamedir, "%ssavegames%c", configdir,
+ DIR_SEPARATOR);
+
+ M_MakeDirectory(savegamedir);
+
+ // eg. ~/.chocolate-doom/savegames/doom2.wad/
+
+ sprintf(savegamedir + strlen(savegamedir), "%s%c",
+ basefile, DIR_SEPARATOR);
+
+ M_MakeDirectory(savegamedir);
+}
+
+// Check if the IWAD file is the Chex Quest IWAD.
+// Returns true if this is chex.wad.
+
+static boolean CheckChex(char *iwadname)
+{
+ char *chex_iwadname = "chex.wad";
+
+ return (strlen(iwadname) > strlen(chex_iwadname)
+ && !strcasecmp(iwadname + strlen(iwadname) - strlen(chex_iwadname),
+ chex_iwadname));
+}
+
++// Check if the IWAD file is the Hacx IWAD.
++// Returns true if this is hacx.wad.
++
++static boolean CheckHacx(char *iwadname)
++{
++ char *hacx_iwadname = "hacx.wad";
++
++ return (strlen(iwadname) > strlen(hacx_iwadname)
++ && !strcasecmp(iwadname + strlen(iwadname) - strlen(hacx_iwadname),
++ hacx_iwadname));
++}
+
// print title for every printed line
char title[128];
@@@ -954,12 -702,10 +957,18 @@@ static void InitGameVersion(void
{
// Determine automatically
- if (gameversion == exe_chex || gameversion == exe_hacx)
+ if (CheckChex(iwadfile))
{
- // Already determined
+ // chex.exe - identified by iwad filename
+
+ gameversion = exe_chex;
+ }
++ else if (CheckHacx(iwadfile))
++ {
++ // hacx exe: identified by iwad filename
++
++ gameversion = exe_hacx;
+ }
else if (gamemode == shareware || gamemode == registered)
{
// original
@@@ -1041,25 -787,20 +1050,39 @@@ static void LoadChexDeh(void
}
}
+// Function called at exit to display the ENDOOM screen
+
+static void D_Endoom(void)
+{
+ byte *endoom;
+
+ // Don't show ENDOOM if we have it disabled, or we're running
+ // in screensaver or control test mode.
+
+ if (!show_endoom || screensaver_mode || M_CheckParm("-testcontrols") > 0)
+ {
+ return;
+ }
+
+ endoom = W_CacheLumpName(DEH_String("ENDOOM"), PU_STATIC);
+
+ I_Endoom(endoom);
+}
+
+ static void LoadHacxDeh(void)
+ {
+ // If this is the HACX IWAD, we need to load the DEHACKED lump.
+
+ if (gameversion == exe_hacx)
+ {
+ if (!DEH_LoadLumpByName("DEHACKED"))
+ {
+ I_Error("DEHACKED lump not found. Please check that this is the "
+ "Hacx v1.2 IWAD.");
+ }
+ }
+ }
+
//
// D_DoomMain
//
@@@ -1365,8 -1253,9 +1409,9 @@@ void D_DoomMain (void
D_IdentifyVersion();
InitGameVersion();
LoadChexDeh();
+ LoadHacxDeh();
D_SetGameDescription();
- D_SetSaveGameDir();
+ SetSaveGameDir(iwadfile);
// Check for -file in shareware
if (modifiedgame)
diff --cc src/doom/d_net.c
index 05d1875f,00000000..b307d97f
mode 100644,000000..100644
--- a/src/doom/d_net.c
+++ b/src/doom/d_net.c
@@@ -1,921 -1,0 +1,929 @@@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// DOOM Network game communication and protocol,
+// all OS independend parts.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+
+#include "doomfeatures.h"
+
+#include "d_main.h"
+#include "m_argv.h"
+#include "m_menu.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "i_video.h"
+#include "g_game.h"
+#include "doomdef.h"
+#include "doomstat.h"
+
+#include "deh_main.h"
+
+#include "net_client.h"
+#include "net_gui.h"
+#include "net_io.h"
+#include "net_query.h"
+#include "net_server.h"
+#include "net_sdl.h"
+#include "net_loop.h"
+
+// The complete set of data for a particular tic.
+
+typedef struct
+{
+ ticcmd_t cmds[MAXPLAYERS];
+ boolean ingame[MAXPLAYERS];
+} ticcmd_set_t;
+
+//
+// NETWORKING
+//
+// gametic is the tic about to (or currently being) run
+// maketic is the tic that hasn't had control made for it yet
+// recvtic is the latest tic received from the server.
+//
+// a gametic cannot be run until ticcmds are received for it
+// from all players.
+//
+
+ticcmd_set_t ticdata[BACKUPTICS];
+ticcmd_t *netcmds;
+
+int maketic;
+int recvtic;
+
+// Used for original sync code.
+
+static int skiptics = 0;
+
+// Reduce the bandwidth needed by sampling game input less and transmitting
+// less. If ticdup is 2, sample half normal, 3 = one third normal, etc.
+
+int ticdup;
+
+// Send this many extra (backup) tics in each packet.
+
+int extratics;
+
+// Amount to offset the timer for game sync.
+
+fixed_t offsetms;
+
+// Use new client syncronisation code
+
+boolean new_sync = true;
+
+// 35 fps clock adjusted by offsetms milliseconds
+
+static int GetAdjustedTime(void)
+{
+ int time_ms;
+
+ time_ms = I_GetTimeMS();
+
+ if (new_sync)
+ {
+ // Use the adjustments from net_client.c only if we are
+ // using the new sync mode.
+
+ time_ms += (offsetms / FRACUNIT);
+ }
+
+ return (time_ms * TICRATE) / 1000;
+}
+
+//
+// NetUpdate
+// Builds ticcmds for console player,
+// sends out a packet
+//
+int lasttime;
+
+void NetUpdate (void)
+{
+ int nowtime;
+ int newtics;
+ int i;
+ int gameticdiv;
+
+ // If we are running with singletics (timing a demo), this
+ // is all done separately.
+
+ if (singletics)
+ return;
+
+#ifdef FEATURE_MULTIPLAYER
+
+ // Run network subsystems
+
+ NET_CL_Run();
+ NET_SV_Run();
+
+#endif
+
+ // check time
+ nowtime = GetAdjustedTime() / ticdup;
+ newtics = nowtime - lasttime;
+
+ lasttime = nowtime;
+
+ if (skiptics <= newtics)
+ {
+ newtics -= skiptics;
+ skiptics = 0;
+ }
+ else
+ {
+ skiptics -= newtics;
+ newtics = 0;
+ }
+
+ // build new ticcmds for console player
+ gameticdiv = gametic/ticdup;
+
+ for (i=0 ; i<newtics ; i++)
+ {
+ ticcmd_t cmd;
+
+ I_StartTic ();
+ D_ProcessEvents ();
+
+ // Always run the menu
+
+ M_Ticker ();
+
+ if (drone)
+ {
+ // In drone mode, do not generate any ticcmds.
+
+ continue;
+ }
+
+ if (new_sync)
+ {
+ // If playing single player, do not allow tics to buffer
+ // up very far
+
+ if ((!netgame || demoplayback) && maketic - gameticdiv > 2)
+ break;
+
+ // Never go more than ~200ms ahead
+
+ if (maketic - gameticdiv > 8)
+ break;
+ }
+ else
+ {
+ if (maketic - gameticdiv >= 5)
+ break;
+ }
+
+ //printf ("mk:%i ",maketic);
+ G_BuildTiccmd(&cmd);
+
+#ifdef FEATURE_MULTIPLAYER
+
+ if (netgame && !demoplayback)
+ {
+ NET_CL_SendTiccmd(&cmd, maketic);
+ }
+
+#endif
+ ticdata[maketic % BACKUPTICS].cmds[consoleplayer] = cmd;
+ ticdata[maketic % BACKUPTICS].ingame[consoleplayer] = true;
+
+ ++maketic;
+ }
+}
+
+// Called when a player leaves the game
+
+static void D_PlayerQuitGame(player_t *player)
+{
+ static char exitmsg[80];
+ unsigned int player_num;
+
+ player_num = player - players;
+
+ // Do this the same way as Vanilla Doom does, to allow dehacked
+ // replacements of this message
+
+ strncpy(exitmsg, DEH_String("Player 1 left the game"), sizeof(exitmsg));
+ exitmsg[sizeof(exitmsg) - 1] = '\0';
+
+ exitmsg[7] += player_num;
+
+ playeringame[player_num] = false;
+ players[consoleplayer].message = exitmsg;
+
+ // TODO: check if it is sensible to do this:
+
+ if (demorecording)
+ {
+ G_CheckDemoStatus ();
+ }
+}
+
+static void D_Disconnected(void)
+{
+ // In drone mode, the game cannot continue once disconnected.
+
+ if (drone)
+ {
+ I_Error("Disconnected from server in drone mode.");
+ }
+
+ // disconnected from server
+
+ printf("Disconnected from server.\n");
+}
+
+//
+// Invoked by the network engine when a complete set of ticcmds is
+// available.
+//
+
+void D_ReceiveTic(ticcmd_t *ticcmds, boolean *players_mask)
+{
+ int i;
+
+ // Disconnected from server?
+
+ if (ticcmds == NULL && players_mask == NULL)
+ {
+ D_Disconnected();
+ return;
+ }
+
+ for (i = 0; i < MAXPLAYERS; ++i)
+ {
+ if (!drone && i == consoleplayer)
+ {
+ // This is us. Don't overwrite it.
+ }
+ else
+ {
+ ticdata[recvtic % BACKUPTICS].cmds[i] = ticcmds[i];
+ ticdata[recvtic % BACKUPTICS].ingame[i] = players_mask[i];
+ }
+ }
+
+ ++recvtic;
+}
+
+//
+// Start game loop
+//
+// Called after the screen is set but before the game starts running.
+//
+
+void D_StartGameLoop(void)
+{
+ lasttime = GetAdjustedTime() / ticdup;
+}
+
+// Load game settings from the specified structure and
+// set global variables.
+
+static void LoadGameSettings(net_gamesettings_t *settings)
+{
+ unsigned int i;
+
+ deathmatch = settings->deathmatch;
+ ticdup = settings->ticdup;
+ extratics = settings->extratics;
+ startepisode = settings->episode;
+ startmap = settings->map;
+ startskill = settings->skill;
+ startloadgame = settings->loadgame;
+ lowres_turn = settings->lowres_turn;
+ nomonsters = settings->nomonsters;
+ fastparm = settings->fast_monsters;
+ respawnparm = settings->respawn_monsters;
+ timelimit = settings->timelimit;
+
+ if (lowres_turn)
+ {
+ printf("NOTE: Turning resolution is reduced; this is probably "
+ "because there is a client recording a Vanilla demo.\n");
+ }
+
+ new_sync = settings->new_sync;
+
+ if (new_sync == false)
+ {
+ printf("Syncing netgames like Vanilla Doom.\n");
+ }
+
+ netgame = true;
+ autostart = true;
+
+ if (!drone)
+ {
+ consoleplayer = settings->consoleplayer;
+ }
+ else
+ {
+ consoleplayer = 0;
+ }
+
+ for (i=0; i<MAXPLAYERS; ++i)
+ {
+ playeringame[i] = i < settings->num_players;
+ }
+}
+
+// Save the game settings from global variables to the specified
+// game settings structure.
+
+static void SaveGameSettings(net_gamesettings_t *settings,
+ net_connect_data_t *connect_data)
+{
+ int i;
+
+ // Fill in game settings structure with appropriate parameters
+ // for the new game
+
+ settings->deathmatch = deathmatch;
+ settings->episode = startepisode;
+ settings->map = startmap;
+ settings->skill = startskill;
+ settings->loadgame = startloadgame;
+ settings->gameversion = gameversion;
+ settings->nomonsters = nomonsters;
+ settings->fast_monsters = fastparm;
+ settings->respawn_monsters = respawnparm;
+ settings->timelimit = timelimit;
+
+ settings->lowres_turn = M_CheckParm("-record") > 0
+ && M_CheckParm("-longtics") == 0;
+
+ //!
+ // @category net
+ //
+ // Use original game sync code.
+ //
+
+ if (M_CheckParm("-oldsync") > 0)
+ settings->new_sync = 0;
+ else
+ settings->new_sync = 1;
+
+ //!
+ // @category net
+ // @arg <n>
+ //
+ // Send n extra tics in every packet as insurance against dropped
+ // packets.
+ //
+
+ i = M_CheckParm("-extratics");
+
+ if (i > 0)
+ settings->extratics = atoi(myargv[i+1]);
+ else
+ settings->extratics = 1;
+
+ //!
+ // @category net
+ // @arg <n>
+ //
+ // Reduce the resolution of the game by a factor of n, reducing
+ // the amount of network bandwidth needed.
+ //
+
+ i = M_CheckParm("-dup");
+
+ if (i > 0)
+ settings->ticdup = atoi(myargv[i+1]);
+ else
+ settings->ticdup = 1;
+
+ //
+ // Connect data
+ //
+
+ // Game type fields:
+
+ connect_data->gamemode = gamemode;
+ connect_data->gamemission = gamemission;
+
+ // Drone mode?
+
+ connect_data->drone = M_CheckParm("-drone") > 0;
+
+ // Are we recording a demo? Possibly set lowres turn mode
+
+ connect_data->lowres_turn = settings->lowres_turn;
+}
+
+void D_InitSinglePlayerGame(void)
+{
+ int i;
+
+ // default values for single player
+
+ consoleplayer = 0;
+ netgame = false;
+ ticdup = 1;
+ extratics = 1;
+ lowres_turn = false;
+ offsetms = 0;
+
+ for (i=0; i<MAXPLAYERS; i++)
+ {
+ playeringame[i] = false;
+ }
+
+ recvtic = 0;
+
+ playeringame[0] = true;
+}
+
+boolean D_InitNetGame(net_connect_data_t *connect_data,
+ net_gamesettings_t *settings)
+{
+ net_addr_t *addr = NULL;
+ int i;
+
+#ifdef FEATURE_MULTIPLAYER
+
+ //!
+ // @category net
+ //
+ // Start a multiplayer server, listening for connections.
+ //
+
+ if (M_CheckParm("-server") > 0)
+ {
+ NET_SV_Init();
+ NET_SV_AddModule(&net_loop_server_module);
+ NET_SV_AddModule(&net_sdl_module);
+
+ net_loop_client_module.InitClient();
+ addr = net_loop_client_module.ResolveAddress(NULL);
+ }
+ else
+ {
+ //!
+ // @category net
+ //
+ // Automatically search the local LAN for a multiplayer
+ // server and join it.
+ //
+
+ i = M_CheckParm("-autojoin");
+
+ if (i > 0)
+ {
+ addr = NET_FindLANServer();
++ NET_SV_RegisterWithMaster();
+
+ if (addr == NULL)
+ {
+ I_Error("No server found on local LAN");
+ }
+ }
+
+ //!
+ // @arg <address>
+ // @category net
+ //
+ // Connect to a multiplayer server running on the given
+ // address.
+ //
+
+ i = M_CheckParm("-connect");
+
+ if (i > 0)
+ {
+ net_sdl_module.InitClient();
+ addr = net_sdl_module.ResolveAddress(myargv[i+1]);
+
+ if (addr == NULL)
+ {
+ I_Error("Unable to resolve '%s'\n", myargv[i+1]);
+ }
+ }
+ }
+
+ if (addr != NULL)
+ {
+ if (M_CheckParm("-drone") > 0)
+ {
+ connect_data->drone = true;
+ }
+
+ //!
+ // @category net
+ //
+ // Run as the left screen in three screen mode.
+ //
+
+ if (M_CheckParm("-left") > 0)
+ {
+ viewangleoffset = ANG90;
+ connect_data->drone = true;
+ }
+
+ //!
+ // @category net
+ //
+ // Run as the right screen in three screen mode.
+ //
+
+ if (M_CheckParm("-right") > 0)
+ {
+ viewangleoffset = ANG270;
+ connect_data->drone = true;
+ }
+
+ if (!NET_CL_Connect(addr, connect_data))
+ {
+ I_Error("D_CheckNetGame: Failed to connect to %s\n",
+ NET_AddrToString(addr));
+ }
+
+ printf("D_CheckNetGame: Connected to %s\n", NET_AddrToString(addr));
+
+ // Wait for game start message received from server.
+
+ NET_WaitForStart(settings);
+
+ // Read the game settings that were received.
+
+ NET_CL_GetSettings(settings);
+
+ return true;
+ }
+
+#endif
+
+ return false;
+}
+
+//
+// D_CheckNetGame
+// Works out player numbers among the net participants
+//
+extern int viewangleoffset;
+
+void D_CheckNetGame (void)
+{
+ net_connect_data_t connect_data;
+ net_gamesettings_t settings;
+
+ // Call D_QuitNetGame on exit
+
+ I_AtExit(D_QuitNetGame, true);
+
+ SaveGameSettings(&settings, &connect_data);
+
+ if (D_InitNetGame(&connect_data, &settings))
+ {
+ LoadGameSettings(&settings);
+ }
+ else
+ {
+ D_InitSinglePlayerGame();
+ }
+
+ DEH_printf("startskill %i deathmatch: %i startmap: %i startepisode: %i\n",
+ startskill, deathmatch, startmap, startepisode);
+
+ DEH_printf("player %i of %i (%i nodes)\n",
+ consoleplayer+1, settings.num_players, settings.num_players);
+
+ // Show players here; the server might have specified a time limit
+
- if (timelimit > 0)
++ if (timelimit > 0 && deathmatch)
+ {
- DEH_printf("Levels will end after %d minute", timelimit);
- if (timelimit > 1)
- printf("s");
- printf(".\n");
++ // Gross hack to work like Vanilla:
++
++ if (timelimit == 20 && M_CheckParm("-avg"))
++ {
++ DEH_printf("Austin Virtual Gaming: Levels will end "
++ "after 20 minutes\n");
++ }
++ else
++ {
++ DEH_printf("Levels will end after %d minute", timelimit);
++ if (timelimit > 1)
++ printf("s");
++ printf(".\n");
++ }
+ }
+}
+
+
+//
+// D_QuitNetGame
+// Called before quitting to leave a net game
+// without hanging the other players
+//
+void D_QuitNetGame (void)
+{
- if (debugfile)
- fclose (debugfile);
-
+#ifdef FEATURE_MULTIPLAYER
+
+ NET_SV_Shutdown();
+ NET_CL_Disconnect();
+
+#endif
+
+}
+
+static int GetLowTic(void)
+{
+ int lowtic;
+
+ lowtic = maketic;
+
+#ifdef FEATURE_MULTIPLAYER
+ if (net_client_connected)
+ {
+ if (drone || recvtic < lowtic)
+ {
+ lowtic = recvtic;
+ }
+ }
+#endif
+
+ return lowtic;
+}
+
+int frametics[4];
+int frameon;
+int frameskip[4];
+int oldnettics;
+
+static void OldNetSync(void)
+{
+ unsigned int i;
+ unsigned int keyplayer = -1;
+
+ frameon++;
+
+ // ideally maketic should be 1 - 3 tics above lowtic
+ // if we are consistantly slower, speed up time
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ // TODO: playeringame should not be used here.
+
+ if (playeringame[i])
+ {
+ keyplayer = i;
+ break;
+ }
+ }
+
+ if (keyplayer < 0)
+ {
+ // If there are no players, we can never advance anyway
+
+ return;
+ }
+
+ if (consoleplayer == keyplayer)
+ {
+ // the key player does not adapt
+ }
+ else
+ {
+ if (maketic <= recvtic)
+ {
+ lasttime--;
+ // printf ("-");
+ }
+
+ frameskip[frameon & 3] = oldnettics > recvtic;
+ oldnettics = maketic;
+
+ if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
+ {
+ skiptics = 1;
+ // printf ("+");
+ }
+ }
+}
+
+// Returns true if there are players in the game:
+
+static boolean PlayersInGame(void)
+{
+ boolean result = false;
+ unsigned int i;
+
+ // If we are connected to a server, check if there are any players
+ // in the game.
+
+ if (net_client_connected)
+ {
+ for (i = 0; i < MAXPLAYERS; ++i)
+ {
+ result = result || playeringame[i];
+ }
+ }
+
+ // Whether single or multi-player, unless we are running as a drone,
+ // we are in the game.
+
+ if (!drone)
+ {
+ result = true;
+ }
+
+ return result;
+}
+
+// When using ticdup, certain values must be cleared out when running
+// the duplicate ticcmds.
+
+static void TicdupSquash(ticcmd_set_t *set)
+{
+ ticcmd_t *cmd;
+ unsigned int i;
+
+ for (i = 0; i < MAXPLAYERS ; ++i)
+ {
+ cmd = &set->cmds[i];
+ cmd->chatchar = 0;
+ if (cmd->buttons & BT_SPECIAL)
+ cmd->buttons = 0;
+ }
+}
+
+static void D_RunTic(ticcmd_set_t *set)
+{
+ extern boolean advancedemo;
+ unsigned int i;
+
+ // Check for player quits.
+
+ for (i = 0; i < MAXPLAYERS; ++i)
+ {
+ if (playeringame[i] && !set->ingame[i])
+ {
+ D_PlayerQuitGame(&players[i]);
+ }
+ }
+
+ netcmds = set->cmds;
+
+ // check that there are players in the game. if not, we cannot
+ // run a tic.
+
+ if (advancedemo)
+ D_DoAdvanceDemo ();
+
+ G_Ticker ();
+}
+
+// When running in single player mode, clear all the ingame[] array
+// except the consoleplayer.
+
+static void SinglePlayerClear(ticcmd_set_t *set)
+{
+ unsigned int i;
+
+ for (i = 0; i < MAXPLAYERS; ++i)
+ {
+ if (i != consoleplayer)
+ {
+ set->ingame[i] = false;
+ }
+ }
+}
+
+//
+// TryRunTics
+//
+
+void TryRunTics (void)
+{
+ int i;
+ int lowtic;
+ int entertic;
+ static int oldentertics;
+ int realtics;
+ int availabletics;
+ int counts;
+
+ // get real tics
+ entertic = I_GetTime() / ticdup;
+ realtics = entertic - oldentertics;
+ oldentertics = entertic;
+
+ // get available tics
+ NetUpdate ();
+
+ lowtic = GetLowTic();
+
+ availabletics = lowtic - gametic/ticdup;
+
+ // decide how many tics to run
+
+ if (new_sync)
+ {
+ counts = availabletics;
+ }
+ else
+ {
+ // decide how many tics to run
+ if (realtics < availabletics-1)
+ counts = realtics+1;
+ else if (realtics < availabletics)
+ counts = realtics;
+ else
+ counts = availabletics;
+
+ if (counts < 1)
+ counts = 1;
+
+ if (net_client_connected)
+ {
+ OldNetSync();
+ }
+ }
+
+ if (counts < 1)
+ counts = 1;
+
+ // wait for new tics if needed
+
+ while (!PlayersInGame() || lowtic < gametic/ticdup + counts)
+ {
+ NetUpdate ();
+
+ lowtic = GetLowTic();
+
+ if (lowtic < gametic/ticdup)
+ I_Error ("TryRunTics: lowtic < gametic");
+
+ // Don't stay in this loop forever. The menu is still running,
+ // so return to update the screen
+
+ if (I_GetTime() / ticdup - entertic > 0)
+ {
+ return;
+ }
+
+ I_Sleep(1);
+ }
+
+ // run the count * ticdup dics
+ while (counts--)
+ {
+ ticcmd_set_t *set;
+
+ if (!PlayersInGame())
+ {
+ return;
+ }
+
+ set = &ticdata[(gametic / ticdup) % BACKUPTICS];
+
+ if (!net_client_connected)
+ {
+ SinglePlayerClear(set);
+ }
+
+ for (i=0 ; i<ticdup ; i++)
+ {
+ if (gametic/ticdup > lowtic)
+ I_Error ("gametic>lowtic");
+
+ D_RunTic(set);
+ gametic++;
+
+ // modify command for duplicated tics
+
+ TicdupSquash(set);
+ }
+
+ NetUpdate (); // check for new console commands
+ }
+}
+
diff --cc src/i_sdlsound.c
index 7deb683d,a26a81dd..1cfafa6f
--- a/src/i_sdlsound.c
+++ b/src/i_sdlsound.c
@@@ -53,9 -53,12 +53,11 @@@
#define MAX_SOUND_SLICE_TIME 70 /* ms */
#define NUM_CHANNELS 16
+ static boolean setpanning_workaround = false;
+
static boolean sound_initialized = false;
-static Mix_Chunk sound_chunks[NUMSFX];
-static int channels_playing[NUM_CHANNELS];
+static sfxinfo_t *channels_playing[NUM_CHANNELS];
static int mixer_freq;
static Uint16 mixer_format;
@@@ -627,11 -622,16 +629,21 @@@ static void I_SDL_UpdateSoundParams(in
left = ((254 - sep) * vol) / 127;
right = ((sep) * vol) / 127;
+ if (left < 0) left = 0;
+ else if ( left > 255) left = 255;
+ if (right < 0) right = 0;
+ else if (right > 255) right = 255;
+
+ // SDL_mixer version 1.2.8 and earlier has a bug in the Mix_SetPanning
+ // function. A workaround is to call Mix_UnregisterAllEffects for
+ // the channel before calling it. This is undesirable as it may lead
+ // to the channel volumes resetting briefly.
+
+ if (setpanning_workaround)
+ {
+ Mix_UnregisterAllEffects(handle);
+ }
+
Mix_SetPanning(handle, left, right);
}
diff --cc src/i_video.c
index 733af899,488c08a0..aa9640bf
--- a/src/i_video.c
+++ b/src/i_video.c
@@@ -131,14 -91,14 +131,20 @@@ static screen_mode_t *screen_modes_corr
char *video_driver = "";
+// SDL surface for the screen.
+
static SDL_Surface *screen;
+// Window title
+
+static char *window_title = "";
+
+ // Intermediate 8-bit buffer that we draw to instead of 'screen'.
+ // This is used when we are rendering in 32-bit screen mode.
+ // When in a real 8-bit screen mode, screenbuffer == screen.
+
+ static SDL_Surface *screenbuffer;
+
// palette
static SDL_Color palette[256];
@@@ -169,9 -123,13 +175,13 @@@ static boolean native_surface
// Screen width and height, from configuration file.
-int screen_width = SCREENWIDTH;
-int screen_height = SCREENHEIGHT;
+static int screen_width = SCREENWIDTH;
+static int screen_height = SCREENHEIGHT;
+ // Color depth.
+
+ int screen_bpp = 8;
+
// Automatically adjust video settings if the selected mode is
// not a valid video mode.
@@@ -911,17 -760,18 +921,18 @@@ static boolean BlitArea(int x1, int y1
return true;
}
- x_offset = (screen->w - screen_mode->width) / 2;
- y_offset = (screen->h - screen_mode->height) / 2;
+ x_offset = (screenbuffer->w - screen_mode->width) / 2;
+ y_offset = (screenbuffer->h - screen_mode->height) / 2;
- if (SDL_LockSurface(screen) >= 0)
+ if (SDL_LockSurface(screenbuffer) >= 0)
{
- I_InitScale(screens[0],
+ I_InitScale(I_VideoBuffer,
- (byte *) screen->pixels + (y_offset * screen->pitch)
- + x_offset,
+ (byte *) screenbuffer->pixels
- + (y_offset * screenbuffer->pitch)
++ + (y_offset * screen->pitch)
+ + x_offset,
- screenbuffer->pitch);
+ screen->pitch);
result = screen_mode->DrawScreen(x1, y1, x2, y2);
- SDL_UnlockSurface(screen);
+ SDL_UnlockSurface(screenbuffer);
}
else
{
@@@ -1993,30 -1915,5 +2113,51 @@@ void I_InitGraphics(void
}
initialized = true;
+
+ // Call I_ShutdownGraphics on quit
+
+ I_AtExit(I_ShutdownGraphics, true);
+}
+
+// Bind all variables controlling video options into the configuration
+// file system.
+
+void I_BindVideoVariables(void)
+{
+ M_BindVariable("use_mouse", &usemouse);
+ M_BindVariable("autoadjust_video_settings", &autoadjust_video_settings);
+ M_BindVariable("fullscreen", &fullscreen);
+ M_BindVariable("aspect_ratio_correct", &aspect_ratio_correct);
+ M_BindVariable("startup_delay", &startup_delay);
+ M_BindVariable("screen_width", &screen_width);
+ M_BindVariable("screen_height", &screen_height);
+ M_BindVariable("grabmouse", &grabmouse);
+ M_BindVariable("mouse_acceleration", &mouse_acceleration);
+ M_BindVariable("mouse_threshold", &mouse_threshold);
+ M_BindVariable("video_driver", &video_driver);
+ M_BindVariable("usegamma", &usegamma);
+ M_BindVariable("vanilla_keyboard_mapping", &vanilla_keyboard_mapping);
+ M_BindVariable("novert", &novert);
++
++ // Windows Vista or later? Set screen color depth to
++ // 32 bits per pixel, as 8-bit palettized screen modes
++ // don't work properly in recent versions.
++
++#if defined(_WIN32) && !defined(_WIN32_WCE)
++ {
++ OSVERSIONINFOEX version_info;
++
++ ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX));
++ version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
++
++ GetVersionEx((OSVERSIONINFO *) &version_info);
++
++ if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT
++ && version_info.dwMajorVersion >= 6)
++ {
++ screen_bpp = 32;
++ }
++ }
++#endif
}
diff --cc src/i_video.h
index 82368967,44fe1cd2..c3c50c4b
--- a/src/i_video.h
+++ b/src/i_video.h
@@@ -92,36 -80,23 +92,37 @@@ void I_ReadScreen (byte* scr)
void I_BeginRead (void);
void I_EndRead (void);
-void I_SetWindowCaption(void);
-void I_SetWindowIcon(void);
+void I_SetWindowTitle(char *title);
void I_CheckIsScreensaver(void);
+void I_SetGrabMouseCallback(grabmouse_callback_t func);
+
+void I_DisplayFPSDots(boolean dots_on);
+void I_BindVideoVariables(void);
+
+// Called before processing any tics in a frame (just after displaying a frame).
+// Time consuming syncronous operations are performed here (joystick reading).
+
+void I_StartFrame (void);
+
+// Called before processing each tic in a frame.
+// Quick syncronous operations are performed here.
+
+void I_StartTic (void);
+
+// Enable the loading disk image displayed when reading from disk.
+
+void I_EnableLoadingDisk(void);
extern char *video_driver;
-extern int autoadjust_video_settings;
extern boolean screenvisible;
-extern int screen_width, screen_height;
-extern int screen_bpp;
-extern int fullscreen;
-extern int aspect_ratio_correct;
-extern int grabmouse;
++
extern float mouse_acceleration;
extern int mouse_threshold;
-extern int startup_delay;
extern int vanilla_keyboard_mapping;
+extern boolean screensaver_mode;
+extern int usegamma;
+extern byte *I_VideoBuffer;
#endif
diff --cc src/m_config.c
index a277fc38,3abe7c63..cb7d449c
--- a/src/m_config.c
+++ b/src/m_config.c
@@@ -552,8 -613,14 +552,14 @@@ static default_t extra_defaults_list[]
// will run.
//
- CONFIG_VARIABLE_INT(screen_height, screen_height),
+ CONFIG_VARIABLE_INT(screen_height),
+ //!
+ // Color depth of the screen, in bits.
+ //
+
- CONFIG_VARIABLE_INT(screen_bpp, screen_bpp),
++ CONFIG_VARIABLE_INT(screen_bpp),
+
//!
// If this is non-zero, the mouse will be "grabbed" when running
// in windowed mode so that it can be used as an input device.
diff --cc src/net_defs.h
index 72e0e6d2,d9e3b920..1fa9a9af
--- a/src/net_defs.h
+++ b/src/net_defs.h
@@@ -128,22 -113,14 +128,30 @@@ typedef enu
NET_PACKET_TYPE_QUERY_RESPONSE,
} net_packet_type_t;
+ typedef enum
+ {
+ NET_MASTER_PACKET_TYPE_ADD,
+ NET_MASTER_PACKET_TYPE_ADD_RESPONSE,
+ NET_MASTER_PACKET_TYPE_QUERY,
+ NET_MASTER_PACKET_TYPE_QUERY_RESPONSE
+ } net_master_packet_type_t;
+
+// Settings specified when the client connects to the server.
+
+typedef struct
+{
+ int gamemode;
+ int gamemission;
+ int lowres_turn;
+ int drone;
+ // TODO: is_freedoom in here? WAD/DEH checksums?
+ // TODO: [Hexen] Requested player class
+
+} net_connect_data_t;
+
+// Game settings sent by client to server when initiating game start,
+// and received from the server by clients when the game starts.
+
typedef struct
{
int ticdup;
diff --cc src/setup/display.c
index 9fd0963b,42a1dced..0def546f
--- a/src/setup/display.c
+++ b/src/setup/display.c
@@@ -72,16 -90,15 +93,17 @@@ static screen_mode_t *screen_modes_full
static int vidmode = 0;
-char *video_driver = "";
-int autoadjust_video_settings = 1;
-int aspect_ratio_correct = 1;
-int fullscreen = 1;
-int screen_width = 320;
-int screen_height = 200;
-int screen_bpp = 8;
-int startup_delay = 1000;
-int show_endoom = 1;
+static char *video_driver = "";
+static int autoadjust_video_settings = 1;
+static int aspect_ratio_correct = 1;
+static int fullscreen = 1;
+static int screen_width = 320;
+static int screen_height = 200;
++static int screen_bpp = 8;
+static int startup_delay = 1000;
+static int graphical_startup = 1;
+static int show_endoom = 1;
+static int usegamma = 0;
// These are the last screen width/height values that were chosen by the
// user. These are used when finding the "nearest" mode, so when
@@@ -442,49 -644,24 +649,79 @@@ void ConfigDisplay(void
TXT_AddWidgets(window,
TXT_NewSeparator("Screen mode"),
+ bpp_table = TXT_NewTable(2),
modes_table,
TXT_NewSeparator("Misc."),
- TXT_NewCheckBox("Show ENDOOM screen", &show_endoom),
NULL);
+ if (gamemission == heretic || gamemission == hexen)
+ {
+ TXT_AddWidget(window,
+ TXT_NewCheckBox("Graphical startup", &graphical_startup));
+ }
+
+ if (gamemission == doom || gamemission == heretic)
+ {
+ TXT_AddWidget(window,
+ TXT_NewCheckBox("Show ENDOOM screen", &show_endoom));
+ }
+
+ TXT_AddWidgets(bpp_table,
+ TXT_NewLabel("Color depth: "),
+ bpp_selector = TXT_NewDropdownList(&selected_bpp,
+ supported_bpps,
+ num_supported_bpps),
+ NULL);
+
+
+ TXT_SignalConnect(bpp_selector, "changed", UpdateBPP, modes_table);
TXT_SignalConnect(fs_checkbox, "changed", GenerateModesTable, modes_table);
TXT_SignalConnect(ar_checkbox, "changed", GenerateModesTable, modes_table);
GenerateModesTable(NULL, modes_table);
}
+void BindDisplayVariables(void)
+{
+ M_BindVariable("autoadjust_video_settings", &autoadjust_video_settings);
+ M_BindVariable("aspect_ratio_correct", &aspect_ratio_correct);
+ M_BindVariable("fullscreen", &fullscreen);
+ M_BindVariable("screen_width", &screen_width);
+ M_BindVariable("screen_height", &screen_height);
+ M_BindVariable("startup_delay", &startup_delay);
+ M_BindVariable("video_driver", &video_driver);
+ M_BindVariable("usegamma", &usegamma);
+
+
+ if (gamemission == doom || gamemission == heretic)
+ {
+ M_BindVariable("show_endoom", &show_endoom);
+ }
+
+ if (gamemission == heretic || gamemission == hexen)
+ {
+ M_BindVariable("graphical_startup", &graphical_startup);
+ }
+
++ // Windows Vista or later? Set screen color depth to
++ // 32 bits per pixel, as 8-bit palettized screen modes
++ // don't work properly in recent versions.
++
++#if defined(_WIN32) && !defined(_WIN32_WCE)
++ {
++ OSVERSIONINFOEX version_info;
++
++ ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX));
++ version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
++
++ GetVersionEx((OSVERSIONINFO *) &version_info);
++
++ if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT
++ && version_info.dwMajorVersion >= 6)
++ {
++ screen_bpp = 32;
++ }
++ }
++#endif
+}
+
diff --cc src/setup/joystick.c
index fbe3a3f3,1fc9a7a9..0fc00ea1
--- a/src/setup/joystick.c
+++ b/src/setup/joystick.c
@@@ -65,8 -72,8 +65,8 @@@ static int joystick_y_invert = 0
static txt_button_t *joystick_button;
static int *all_joystick_buttons[] = {
- &joybstraferight, &joybstrafeleft, &joybfire, &joybspeed,
- &joybuse, &joybstrafe, &joybjump
+ &joybstraferight, &joybstrafeleft, &joybfire, &joybspeed,
- &joybuse, &joybstrafe, &joybprevweapon, &joybnextweapon
++ &joybuse, &joybstrafe, &joybprevweapon, &joybnextweapon, &joybjump
};
//