foxygit / doom Log in
commit b9b0c2abfbe194baf6d497f1c4a2165769f64ab3
Merge: 0ec9859e acd1a13a
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Sat Dec 20 20:25:22 2008 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Sat Dec 20 20:25:22 2008 +0000

    Merge from trunk.

    Subversion-branch: /branches/raven-branch
    Subversion-revision: 1423

 ChangeLog                       | 273 +++++++++++++++++++++++++++++
 NEWS                            |  42 +++++
 codeblocks/config.h             |   6 +-
 codeblocks/game-res.rc          |  10 +-
 codeblocks/setup-res.rc         |   8 +-
 configure.in                    |  24 ++-
 msvc/config.h                   |   6 +-
 msvc/win32.rc                   |  10 +-
 pcsound/Makefile.am             |   2 +-
 src/Makefile.am                 |   4 +-
 src/doom/d_main.c               |   2 +-
 src/doom/wi_stuff.c             |  34 ++--
 src/heretic/d_main.c            |   2 +-
 src/hexen/h2_main.c             |   2 +-
 src/i_endoom.c                  |   5 -
 src/i_main.c                    |  38 ++--
 src/i_video.c                   |  37 +++-
 src/i_video.h                   |   1 -
 src/m_config.c                  |   1 -
 src/w_file_win32.c              | 372 ++++++++++++++++++++--------------------
 textscreen/Makefile.am          |   2 +-
 textscreen/examples/Makefile.am |   2 +-
 22 files changed, 627 insertions(+), 256 deletions(-)

diff --cc src/Makefile.am
index 5a2267b9,63ddc98f..10f9c2c5
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@@ -1,30 -1,16 +1,30 @@@

 +SUBDIRS=doom heretic hexen setup
 +
  gamesdir = $(prefix)/games

 -games_PROGRAMS = chocolate-doom chocolate-server
 +games_PROGRAMS = chocolate-doom     \
 +                 chocolate-heretic  \
 +                 chocolate-hexen    \
 +                 chocolate-server   \
 +                 chocolate-setup

- AM_CFLAGS = -Idoom -I../textscreen -I../pcsound @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
+ AM_CFLAGS = -I../textscreen -I../pcsound @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@

 +# Common source files used by absolutely everything:
 +
 +COMMON_SOURCE_FILES=\
 +i_main.c                                   \
 +i_system.c           i_system.h            \
 +m_argv.c             m_argv.h              \
 +m_misc.c             m_misc.h
 +
 +# Dedicated server (chocolate-server):
 +
  DEDSERV_FILES=\
  d_dedicated.c                              \
 -i_main.c                                   \
 +d_mode.c             d_mode.h              \
  i_timer.c            i_timer.h             \
 -m_argv.c             m_argv.h              \
 -m_misc.c             m_misc.h              \
  net_common.c         net_common.h          \
  net_dedicated.c      net_dedicated.h       \
  net_io.c             net_io.h              \
@@@ -34,21 -20,35 +34,21 @@@ net_server.c         net_server.
  net_structrw.c       net_structrw.h        \
  z_native.c           z_zone.h

 -chocolate_server_SOURCES=$(DEDSERV_FILES)
 +chocolate_server_SOURCES=$(COMMON_SOURCE_FILES) $(DEDSERV_FILES)
- chocolate_server_LDADD = @LDFLAGS@ @SDL_LIBS@ @SDLNET_LIBS@
+ chocolate_server_LDADD = @LDFLAGS@ @SDLNET_LIBS@

 -MAIN_SOURCE_FILES=\
 -am_map.c             am_map.h              \
 -d_englsh.h                                 \
 -d_event.h                                  \
 -d_items.c            d_items.h             \
 +# Source files used by the game binaries (chocolate-doom, etc.)
 +
 +GAME_SOURCE_FILES=\
 +d_event.c            d_event.h             \
 +                     doomkeys.h            \
 +                     doomfeatures.h        \
 +                     doomtype.h            \
  d_iwad.c             d_iwad.h              \
 -d_main.c             d_main.h              \
 -d_net.c              d_net.h               \
 -doomdata.h                                 \
 -doomdef.c            doomdef.h             \
 -doomkeys.h                                 \
 -doomfeatures.h                             \
 -doomstat.c           doomstat.h            \
 -doomtype.h                                 \
 -d_player.h                                 \
 -dstrings.c           dstrings.h            \
 -d_textur.h                                 \
 -d_think.h                                  \
 -d_ticcmd.h                                 \
 -f_finale.c           f_finale.h            \
 -f_wipe.c             f_wipe.h              \
 -g_game.c             g_game.h              \
 -hu_lib.c             hu_lib.h              \
 -hu_stuff.c           hu_stuff.h            \
 -i_main.c                                   \
 -info.c               info.h                \
 +d_mode.c             d_mode.h              \
 +                     d_ticcmd.h            \
 +i_cdmus.c            i_cdmus.h             \
 +i_endoom.c           i_endoom.h            \
  i_joystick.c         i_joystick.h          \
  i_scale.c            i_scale.h             \
                       i_swap.h              \
diff --cc src/doom/d_main.c
index c8a91e74,849897fe..70518a75
--- a/src/doom/d_main.c
+++ b/src/doom/d_main.c
@@@ -422,12 -409,8 +422,12 @@@ void D_DoomLoop (void

      TryRunTics();

 -    I_InitGraphics ();
++    I_SetWindowTitle(gamedescription);
 +    I_InitGraphics();
 +    I_EnableLoadingDisk();
 +    I_SetGrabMouseCallback(D_GrabMouseCallback);
-     I_SetWindowTitle(gamedescription);

 +    V_RestoreBuffer();
      R_ExecuteSetViewSize();

      D_StartGameLoop();
diff --cc src/doom/wi_stuff.c
index 7cfbdfa9,5e87069e..dea5d71b
--- a/src/doom/wi_stuff.c
+++ b/src/doom/wi_stuff.c
@@@ -424,17 -427,34 +424,31 @@@ void WI_drawLF(void
  {
      int y = WI_TITLEY;

-     // draw <LevelName>
-     V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->last]->width))/2,
- 		y,
-                 lnames[wbs->last]);
+     if (gamemode != commercial || wbs->last < NUMCMAPS)
+     {
+         // draw <LevelName>
+         V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->last]->width))/2,
 -                    y, FB, lnames[wbs->last]);
++                    y, lnames[wbs->last]);

-     // draw "Finished!"
-     y += (5*SHORT(lnames[wbs->last]->height))/4;
-
-     V_DrawPatch((SCREENWIDTH - SHORT(finished->width))/2,
- 		y,
-                 finished);
+         // draw "Finished!"
+         y += (5*SHORT(lnames[wbs->last]->height))/4;
+     }
+     else if (wbs->last == NUMCMAPS)
+     {
+         // MAP33 - nothing is displayed!
+     }
+     else if (wbs->last > NUMCMAPS)
+     {
+         // > MAP33.  Doom bombs out here with a Bad V_DrawPatch error.
+         // I'm pretty sure that doom2.exe is just reading into random
+         // bits of memory at this point, but let's try to be accurate
+         // anyway.  This deliberately triggers a V_DrawPatch error.
+
+         patch_t tmp = { SCREENWIDTH, SCREENHEIGHT, 1, 1,
+                         { 0, 0, 0, 0, 0, 0, 0, 0 } };
+
 -        V_DrawPatch(0, y, FB, &tmp);
++        V_DrawPatch(0, y, &tmp);
+     }
 -
 -    V_DrawPatch((SCREENWIDTH - SHORT(finished->width))/2,
 -		y, FB, finished);
  }


diff --cc src/heretic/d_main.c
index bba09e65,00000000..9e4558c1
mode 100644,000000..100644
--- a/src/heretic/d_main.c
+++ b/src/heretic/d_main.c
@@@ -1,1070 -1,0 +1,1070 @@@
 +// Emacs style mode select   -*- C++ -*-
 +//-----------------------------------------------------------------------------
 +//
 +// Copyright(C) 1993-1996 Id Software, Inc.
 +// Copyright(C) 1993-2008 Raven Software
 +// Copyright(C) 2008 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.
 +//
 +//-----------------------------------------------------------------------------
 +
 +// D_main.c
 +
 +#include <stdio.h>
 +#include <stdlib.h>
 +
 +#include "txt_main.h"
 +#include "txt_io.h"
 +
 +#include "config.h"
 +#include "ct_chat.h"
 +#include "doomdef.h"
 +#include "d_iwad.h"
 +#include "i_endoom.h"
 +#include "i_joystick.h"
 +#include "i_sound.h"
 +#include "i_system.h"
 +#include "i_timer.h"
 +#include "i_video.h"
 +#include "m_argv.h"
 +#include "m_config.h"
 +#include "m_controls.h"
 +#include "p_local.h"
 +#include "s_sound.h"
 +#include "v_video.h"
 +
 +#define STARTUP_WINDOW_X 17
 +#define STARTUP_WINDOW_Y 7
 +
 +GameMission_t gamemission = heretic;
 +GameMode_t gamemode = indetermined;
 +char *gamedescription = "unknown";
 +
 +boolean nomonsters;             // checkparm of -nomonsters
 +boolean respawnparm;            // checkparm of -respawn
 +boolean debugmode;              // checkparm of -debug
 +boolean ravpic;                 // checkparm of -ravpic
 +boolean cdrom;                  // true if cd-rom mode active
 +boolean singletics;             // debug flag to cancel adaptiveness
 +boolean noartiskip;             // whether shift-enter skips an artifact
 +
 +skill_t startskill;
 +int startepisode;
 +int startmap;
 +int UpdateState;
 +static int graphical_startup = 1;
 +static boolean using_graphical_startup;
 +boolean autostart;
 +extern boolean automapactive;
 +
 +boolean advancedemo;
 +
 +FILE *debugfile;
 +
 +static int show_endoom = 1;
 +
 +void D_CheckNetGame(void);
 +void D_ProcessEvents(void);
 +void G_BuildTiccmd(ticcmd_t * cmd);
 +void D_DoAdvanceDemo(void);
 +void D_PageDrawer(void);
 +void D_AdvanceDemo(void);
 +void F_Drawer(void);
 +boolean F_Responder(event_t * ev);
 +
 +//---------------------------------------------------------------------------
 +//
 +// PROC D_ProcessEvents
 +//
 +// Send all the events of the given timestamp down the responder chain.
 +//
 +//---------------------------------------------------------------------------
 +
 +void D_ProcessEvents(void)
 +{
 +    event_t *ev;
 +
 +    while ((ev = D_PopEvent()) != NULL)
 +    {
 +        if (F_Responder(ev))
 +        {
 +            continue;
 +        }
 +        if (MN_Responder(ev))
 +        {
 +            continue;
 +        }
 +        G_Responder(ev);
 +    }
 +}
 +
 +//---------------------------------------------------------------------------
 +//
 +// PROC DrawMessage
 +//
 +//---------------------------------------------------------------------------
 +
 +void DrawMessage(void)
 +{
 +    player_t *player;
 +
 +    player = &players[consoleplayer];
 +    if (player->messageTics <= 0 || !player->message)
 +    {                           // No message
 +        return;
 +    }
 +    MN_DrTextA(player->message, 160 - MN_TextAWidth(player->message) / 2, 1);
 +}
 +
 +//---------------------------------------------------------------------------
 +//
 +// PROC D_Display
 +//
 +// Draw current display, possibly wiping it from the previous.
 +//
 +//---------------------------------------------------------------------------
 +
 +void R_ExecuteSetViewSize(void);
 +
 +extern boolean finalestage;
 +
 +void D_Display(void)
 +{
 +    extern boolean MenuActive;
 +    extern boolean askforquit;
 +
 +    // Change the view size if needed
 +    if (setsizeneeded)
 +    {
 +        R_ExecuteSetViewSize();
 +    }
 +
 +//
 +// do buffered drawing
 +//
 +    switch (gamestate)
 +    {
 +        case GS_LEVEL:
 +            if (!gametic)
 +                break;
 +            if (automapactive)
 +                AM_Drawer();
 +            else
 +                R_RenderPlayerView(&players[displayplayer]);
 +            CT_Drawer();
 +            UpdateState |= I_FULLVIEW;
 +            SB_Drawer();
 +            break;
 +        case GS_INTERMISSION:
 +            IN_Drawer();
 +            break;
 +        case GS_FINALE:
 +            F_Drawer();
 +            break;
 +        case GS_DEMOSCREEN:
 +            D_PageDrawer();
 +            break;
 +    }
 +
 +    if (paused && !MenuActive && !askforquit)
 +    {
 +        if (!netgame)
 +        {
 +            V_DrawPatch(160, viewwindowy + 5, W_CacheLumpName("PAUSED",
 +                                                              PU_CACHE));
 +        }
 +        else
 +        {
 +            V_DrawPatch(160, 70, W_CacheLumpName("PAUSED", PU_CACHE));
 +        }
 +    }
 +    // Handle player messages
 +    DrawMessage();
 +
 +    // Menu drawing
 +    MN_Drawer();
 +
 +    // Send out any new accumulation
 +    NetUpdate();
 +
 +    // Flush buffered stuff to screen
 +    I_FinishUpdate();
 +}
 +
 +//
 +// D_GrabMouseCallback
 +//
 +// Called to determine whether to grab the mouse pointer
 +//
 +
 +boolean D_GrabMouseCallback(void)
 +{
 +    // when menu is active or game is paused, release the mouse
 +
 +    if (MenuActive || paused)
 +        return false;
 +
 +    // only grab mouse when playing levels (but not demos)
 +
 +    return (gamestate == GS_LEVEL) && !demoplayback;
 +}
 +
 +//---------------------------------------------------------------------------
 +//
 +// PROC D_DoomLoop
 +//
 +//---------------------------------------------------------------------------
 +
 +void D_DoomLoop(void)
 +{
 +    if (M_CheckParm("-debugfile"))
 +    {
 +        char filename[20];
 +        sprintf(filename, "debug%i.txt", consoleplayer);
 +        debugfile = fopen(filename, "w");
 +    }
-     I_InitGraphics();
 +    I_SetWindowTitle(gamedescription);
++    I_InitGraphics();
 +    I_SetGrabMouseCallback(D_GrabMouseCallback);
 +
 +    while (1)
 +    {
 +        // Frame syncronous IO operations
 +        I_StartFrame();
 +
 +        // Process one or more tics
 +        if (singletics)
 +        {
 +            I_StartTic();
 +            D_ProcessEvents();
 +            G_BuildTiccmd(&netcmds[consoleplayer][maketic % BACKUPTICS]);
 +            if (advancedemo)
 +                D_DoAdvanceDemo();
 +            G_Ticker();
 +            gametic++;
 +            maketic++;
 +        }
 +        else
 +        {
 +            // Will run at least one tic
 +            TryRunTics();
 +        }
 +
 +        // Move positional sounds
 +        S_UpdateSounds(players[consoleplayer].mo);
 +        D_Display();
 +    }
 +}
 +
 +/*
 +===============================================================================
 +
 +						DEMO LOOP
 +
 +===============================================================================
 +*/
 +
 +int demosequence;
 +int pagetic;
 +char *pagename;
 +
 +
 +/*
 +================
 +=
 += D_PageTicker
 +=
 += Handles timing for warped projection
 +=
 +================
 +*/
 +
 +void D_PageTicker(void)
 +{
 +    if (--pagetic < 0)
 +        D_AdvanceDemo();
 +}
 +
 +
 +/*
 +================
 +=
 += D_PageDrawer
 +=
 +================
 +*/
 +
 +extern boolean MenuActive;
 +
 +void D_PageDrawer(void)
 +{
 +    V_DrawRawScreen(W_CacheLumpName(pagename, PU_CACHE));
 +    if (demosequence == 1)
 +    {
 +        V_DrawPatch(4, 160, W_CacheLumpName("ADVISOR", PU_CACHE));
 +    }
 +    UpdateState |= I_FULLSCRN;
 +}
 +
 +/*
 +=================
 +=
 += D_AdvanceDemo
 +=
 += Called after each demo or intro demosequence finishes
 +=================
 +*/
 +
 +void D_AdvanceDemo(void)
 +{
 +    advancedemo = true;
 +}
 +
 +void D_DoAdvanceDemo(void)
 +{
 +    players[consoleplayer].playerstate = PST_LIVE;      // don't reborn
 +    advancedemo = false;
 +    usergame = false;           // can't save / end game here
 +    paused = false;
 +    gameaction = ga_nothing;
 +    demosequence = (demosequence + 1) % 7;
 +    switch (demosequence)
 +    {
 +        case 0:
 +            pagetic = 210;
 +            gamestate = GS_DEMOSCREEN;
 +            pagename = "TITLE";
 +            S_StartSong(mus_titl, false);
 +            break;
 +        case 1:
 +            pagetic = 140;
 +            gamestate = GS_DEMOSCREEN;
 +            pagename = "TITLE";
 +            break;
 +        case 2:
 +            BorderNeedRefresh = true;
 +            UpdateState |= I_FULLSCRN;
 +            G_DeferedPlayDemo("demo1");
 +            break;
 +        case 3:
 +            pagetic = 200;
 +            gamestate = GS_DEMOSCREEN;
 +            pagename = "CREDIT";
 +            break;
 +        case 4:
 +            BorderNeedRefresh = true;
 +            UpdateState |= I_FULLSCRN;
 +            G_DeferedPlayDemo("demo2");
 +            break;
 +        case 5:
 +            pagetic = 200;
 +            gamestate = GS_DEMOSCREEN;
 +            if (gamemode == shareware)
 +            {
 +                pagename = "ORDER";
 +            }
 +            else
 +            {
 +                pagename = "CREDIT";
 +            }
 +            break;
 +        case 6:
 +            BorderNeedRefresh = true;
 +            UpdateState |= I_FULLSCRN;
 +            G_DeferedPlayDemo("demo3");
 +            break;
 +    }
 +}
 +
 +
 +/*
 +=================
 +=
 += D_StartTitle
 +=
 +=================
 +*/
 +
 +void D_StartTitle(void)
 +{
 +    gameaction = ga_nothing;
 +    demosequence = -1;
 +    D_AdvanceDemo();
 +}
 +
 +
 +/*
 +==============
 +=
 += D_CheckRecordFrom
 +=
 += -recordfrom <savegame num> <demoname>
 +==============
 +*/
 +
 +void D_CheckRecordFrom(void)
 +{
 +    int p;
 +    char file[256];
 +
 +    p = M_CheckParm("-recordfrom");
 +    if (!p || p > myargc - 2)
 +        return;
 +
 +    if (cdrom)
 +    {
 +        sprintf(file, SAVEGAMENAMECD "%c.hsg", myargv[p + 1][0]);
 +    }
 +    else
 +    {
 +        sprintf(file, SAVEGAMENAME "%c.hsg", myargv[p + 1][0]);
 +    }
 +    G_LoadGame(file);
 +    G_DoLoadGame();             // load the gameskill etc info from savegame
 +
 +    G_RecordDemo(gameskill, 1, gameepisode, gamemap, myargv[p + 2]);
 +    D_DoomLoop();               // never returns
 +}
 +
 +/*
 +===============
 +=
 += D_AddFile
 +=
 +===============
 +*/
 +
 +// MAPDIR should be defined as the directory that holds development maps
 +// for the -wart # # command
 +
 +#define MAPDIR "\\data\\"
 +
 +#define SHAREWAREWADNAME "heretic1.wad"
 +
 +char *iwadfile;
 +
 +char *basedefault = "heretic.cfg";
 +
 +void wadprintf(void)
 +{
 +    if (debugmode)
 +    {
 +        return;
 +    }
 +#ifdef __WATCOMC__
 +    _settextposition(23, 2);
 +    _setbkcolor(1);
 +    _settextcolor(0);
 +    _outtext(exrnwads);
 +    _settextposition(24, 2);
 +    _outtext(exrnwads2);
 +#endif
 +}
 +
 +boolean D_AddFile(char *file)
 +{
 +    wad_file_t *handle;
 +
 +    printf("  adding %s\n", file);
 +
 +    handle = W_AddFile(file);
 +
 +    return handle != NULL;
 +}
 +
 +//==========================================================
 +//
 +//  Startup Thermo code
 +//
 +//==========================================================
 +#define MSG_Y       9
 +#define THERM_X     14
 +#define THERM_Y     14
 +
 +int thermMax;
 +int thermCurrent;
 +char smsg[80];                  // status bar line
 +
 +//
 +//  Heretic startup screen shit
 +//
 +
 +static int startup_line = STARTUP_WINDOW_Y;
 +
 +void hprintf(char *string)
 +{
 +    if (using_graphical_startup)
 +    {
 +        TXT_BGColor(TXT_COLOR_CYAN, 0);
 +        TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
 +
 +        TXT_GotoXY(STARTUP_WINDOW_X, startup_line);
 +        ++startup_line;
 +        TXT_Puts(string);
 +
 +        TXT_UpdateScreen();
 +    }
 +
 +#ifdef __WATCOMC__
 +    if (debugmode)
 +    {
 +        puts(string);
 +        return;
 +    }
 +#endif
 +}
 +
 +void drawstatus(void)
 +{
 +    int i;
 +
 +    TXT_GotoXY(1, 24);
 +    TXT_BGColor(TXT_COLOR_BLUE, 0);
 +    TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
 +
 +    for (i=0; smsg[i] != '\0'; ++i)
 +    {
 +        TXT_PutChar(smsg[i]);
 +    }
 +}
 +
 +void status(char *string)
 +{
 +    strcat(smsg, string);
 +    drawstatus();
 +}
 +
 +void DrawThermo(void)
 +{
 +    static int last_progress = -1;
 +    int progress;
 +    int i;
 +
 +    if (!using_graphical_startup)
 +    {
 +        return;
 +    }
 +
 +#if 0
 +    progress = (98 * thermCurrent) / thermMax;
 +    screen = (char *) 0xb8000 + (THERM_Y * 160 + THERM_X * 2);
 +    for (i = 0; i < progress / 2; i++)
 +    {
 +        switch (i)
 +        {
 +            case 4:
 +            case 9:
 +            case 14:
 +            case 19:
 +            case 29:
 +            case 34:
 +            case 39:
 +            case 44:
 +                *screen++ = 0xb3;
 +                *screen++ = (THERMCOLOR << 4) + 15;
 +                break;
 +            case 24:
 +                *screen++ = 0xba;
 +                *screen++ = (THERMCOLOR << 4) + 15;
 +                break;
 +            default:
 +                *screen++ = 0xdb;
 +                *screen++ = 0x40 + THERMCOLOR;
 +                break;
 +        }
 +    }
 +    if (progress & 1)
 +    {
 +        *screen++ = 0xdd;
 +        *screen++ = 0x40 + THERMCOLOR;
 +    }
 +#else
 +
 +    // No progress? Don't update the screen.
 +
 +    progress = (50 * thermCurrent) / thermMax + 2;
 +
 +    if (last_progress == progress)
 +    {
 +        return;
 +    }
 +
 +    last_progress = progress;
 +
 +    TXT_GotoXY(THERM_X, THERM_Y);
 +
 +    TXT_FGColor(TXT_COLOR_BRIGHT_GREEN);
 +    TXT_BGColor(TXT_COLOR_GREEN, 0);
 +
 +    for (i = 0; i < progress; i++)
 +    {
 +        TXT_PutChar(0xdb);
 +    }
 +
 +    TXT_UpdateScreen();
 +#endif
 +}
 +
 +void initStartup(void)
 +{
 +    byte *textScreen;
 +    byte *loading;
 +
 +    if (!graphical_startup || debugmode)
 +    {
 +        using_graphical_startup = false;
 +        return;
 +    }
 +
 +    if (!TXT_Init())
 +    {
 +        using_graphical_startup = false;
 +        return;
 +    }
 +
 +    // Blit main screen
 +    textScreen = TXT_GetScreenData();
 +    loading = W_CacheLumpName("LOADING", PU_CACHE);
 +    memcpy(textScreen, loading, 4000);
 +
 +    // Print version string
 +
 +    TXT_BGColor(TXT_COLOR_RED, 0);
 +    TXT_FGColor(TXT_COLOR_YELLOW);
 +    TXT_GotoXY(46, 2);
 +    TXT_Puts(HERETIC_VERSION_TEXT);
 +
 +    TXT_UpdateScreen();
 +
 +    using_graphical_startup = true;
 +}
 +
 +static void finishStartup(void)
 +{
 +    if (using_graphical_startup)
 +    {
 +        TXT_Shutdown();
 +    }
 +}
 +
 +char tmsg[300];
 +void tprintf(char *msg, int initflag)
 +{
 +#ifdef __WATCOMC__
 +    char temp[80];
 +    int start;
 +    int add;
 +    int i;
 +
 +    if (initflag)
 +        tmsg[0] = 0;
 +    strcat(tmsg, msg);
 +    blitStartup();
 +    DrawThermo();
 +    _setbkcolor(4);
 +    _settextcolor(15);
 +    for (add = start = i = 0; i <= strlen(tmsg); i++)
 +        if ((tmsg[i] == '\n') || (!tmsg[i]))
 +        {
 +            memset(temp, 0, 80);
 +            strncpy(temp, tmsg + start, i - start);
 +            _settextposition(MSG_Y + add, 40 - strlen(temp) / 2);
 +            _outtext(temp);
 +            start = i + 1;
 +            add++;
 +        }
 +    _settextposition(25, 1);
 +    drawstatus();
 +#else
 +    printf("%s", msg);
 +#endif
 +}
 +
 +void CheckAbortStartup(void)
 +{
 +#ifdef __WATCOMC__
 +    extern int lastpress;
 +
 +    if (lastpress == 1)
 +    {                           // Abort if escape pressed
 +        CleanExit();
 +    }
 +#endif
 +}
 +
 +void IncThermo(void)
 +{
 +    thermCurrent++;
 +    DrawThermo();
 +    CheckAbortStartup();
 +}
 +
 +void InitThermo(int max)
 +{
 +    thermMax = max;
 +    thermCurrent = 0;
 +}
 +
 +#ifdef __WATCOMC__
 +void CleanExit(void)
 +{
 +    union REGS regs;
 +
 +    I_ShutdownKeyboard();
 +    regs.x.eax = 0x3;
 +    int386(0x10, &regs, &regs);
 +    printf("Exited from HERETIC.\n");
 +    exit(1);
 +}
 +#endif
 +
 +//
 +// Add configuration file variable bindings.
 +//
 +
 +void D_BindVariables(void)
 +{
 +    extern int screenblocks;
 +    extern int snd_Channels;
 +    int i;
 +
 +    I_BindVideoVariables();
 +    I_BindJoystickVariables();
 +    I_BindSoundVariables();
 +    M_BindBaseControls();
 +    M_BindHereticControls();
 +
 +    M_BindVariable("mouse_sensitivity",      &mouseSensitivity);
 +    M_BindVariable("sfx_volume",             &snd_MaxVolume);
 +    M_BindVariable("music_volume",           &snd_MusicVolume);
 +    M_BindVariable("screenblocks",           &screenblocks);
 +    M_BindVariable("snd_channels",           &snd_Channels);
 +    M_BindVariable("show_endoom",            &show_endoom);
 +    M_BindVariable("graphical_startup",      &graphical_startup);
 +
 +    for (i=0; i<10; ++i)
 +    {
 +        char buf[12];
 +
 +        sprintf(buf, "chatmacro%i", i);
 +        M_BindVariable(buf, &chat_macros[i]);
 +    }
 +}
 +
 +//
 +// Called at exit to display the ENDOOM screen (ENDTEXT in Heretic)
 +//
 +
 +static void D_Endoom(void)
 +{
 +    byte *endoom_data;
 +
 +    // Disable ENDOOM?
 +
 +    if (!show_endoom)
 +    {
 +        return;
 +    }
 +
 +    endoom_data = W_CacheLumpName("ENDTEXT", PU_STATIC);
 +
 +    I_Endoom(endoom_data);
 +}
 +
 +//---------------------------------------------------------------------------
 +//
 +// PROC D_DoomMain
 +//
 +//---------------------------------------------------------------------------
 +
 +void D_DoomMain(void)
 +{
 +    int p;
 +    char file[256];
 +
 +    I_PrintBanner(PACKAGE_STRING);
 +
 +    I_AtExit(D_Endoom, false);
 +
 +    M_FindResponseFile();
 +    setbuf(stdout, NULL);
 +    nomonsters = M_CheckParm("-nomonsters");
 +    respawnparm = M_CheckParm("-respawn");
 +    ravpic = M_CheckParm("-ravpic");
 +    noartiskip = M_CheckParm("-noartiskip");
 +    debugmode = M_CheckParm("-debug");
 +    startskill = sk_medium;
 +    startepisode = 1;
 +    startmap = 1;
 +    autostart = false;
 +
 +    // Check for -CDROM
 +    cdrom = false;
 +#ifdef __WATCOMC__
 +    if (M_CheckParm("-cdrom"))
 +    {
 +        cdrom = true;
 +        mkdir("c:\\heretic.cd");
 +    }
 +#endif
 +
 +//
 +// get skill / episode / map from parms
 +//
 +    if (M_CheckParm("-deathmatch"))
 +    {
 +        deathmatch = true;
 +    }
 +
 +    p = M_CheckParm("-skill");
 +    if (p && p < myargc - 1)
 +    {
 +        startskill = myargv[p + 1][0] - '1';
 +        autostart = true;
 +    }
 +
 +    p = M_CheckParm("-episode");
 +    if (p && p < myargc - 1)
 +    {
 +        startepisode = myargv[p + 1][0] - '0';
 +        startmap = 1;
 +        autostart = true;
 +    }
 +
 +    p = M_CheckParm("-warp");
 +    if (p && p < myargc - 2)
 +    {
 +        startepisode = myargv[p + 1][0] - '0';
 +        startmap = myargv[p + 2][0] - '0';
 +        autostart = true;
 +    }
 +
 +//
 +// init subsystems
 +//
 +    printf("V_Init: allocate screens.\n");
 +    V_Init();
 +
 +    M_SetConfigDir();
 +
 +    // Load defaults before initing other systems
 +    printf("M_LoadDefaults: Load system defaults.\n");
 +    D_BindVariables();
 +    M_SetConfigFilenames("heretic.cfg", PROGRAM_PREFIX "heretic.cfg");
 +    M_LoadDefaults();
 +
 +    I_AtExit(M_SaveDefaults, false);
 +
 +    printf("Z_Init: Init zone memory allocation daemon.\n");
 +    Z_Init();
 +
 +    printf("W_Init: Init WADfiles.\n");
 +
 +    iwadfile = D_FindIWAD(IWAD_MASK_HERETIC, &gamemission);
 +
 +    if (iwadfile == NULL)
 +    {
 +        I_Error("Game mode indeterminate. No IWAD was found. Try specifying\n"
 +                "one with the '-iwad' command line parameter.");
 +    }
 +
 +    D_AddFile(iwadfile);
 +
 +    // -FILE [filename] [filename] ...
 +    // Add files to the wad list.
 +    p = M_CheckParm("-file");
 +
 +    if (p)
 +    {
 +        char *filename;
 +
 +        // the parms after p are wadfile/lump names, until end of parms
 +        // or another - preceded parm
 +
 +        while (++p != myargc && myargv[p][0] != '-')
 +        {
 +            filename = D_FindWADByName(myargv[p]);
 +            D_AddFile(filename);
 +        }
 +    }
 +
 +    p = M_CheckParm("-playdemo");
 +    if (!p)
 +    {
 +        p = M_CheckParm("-timedemo");
 +    }
 +    if (p && p < myargc - 1)
 +    {
 +        sprintf(file, "%s.lmp", myargv[p + 1]);
 +        D_AddFile(file);
 +        printf("Playing demo %s.lmp.\n", myargv[p + 1]);
 +    }
 +
 +    if (W_CheckNumForName("E2M1") == -1)
 +    {
 +        gamemode = shareware;
 +        gamedescription = "Heretic (shareware)";
 +    }
 +    else if (W_CheckNumForName("EXTENDED") != -1)
 +    {
 +        // Presence of the EXTENDED lump indicates the retail version
 +
 +        gamemode = retail;
 +        gamedescription = "Heretic: Shadow of the Serpent Riders";
 +    }
 +    else
 +    {
 +        gamemode = registered;
 +        gamedescription = "Heretic (registered)";
 +    }
 +
 +    I_PrintStartupBanner(gamedescription);
 +
 +#ifdef __WATCOMC__
 +    I_StartupKeyboard();
 +    I_StartupJoystick();
 +#endif
 +    initStartup();
 +
 +    //
 +    //  Build status bar line!
 +    //
 +    smsg[0] = 0;
 +    if (deathmatch)
 +        status("DeathMatch...");
 +    if (nomonsters)
 +        status("No Monsters...");
 +    if (respawnparm)
 +        status("Respawning...");
 +    if (autostart)
 +    {
 +        char temp[64];
 +        sprintf(temp, "Warp to Episode %d, Map %d, Skill %d ",
 +                startepisode, startmap, startskill + 1);
 +        status(temp);
 +    }
 +    wadprintf();                // print the added wadfiles
 +
 +    tprintf("MN_Init: Init menu system.\n", 1);
 +    MN_Init();
 +
 +    CT_Init();
 +
 +    tprintf("R_Init: Init Heretic refresh daemon.", 1);
 +    hprintf("Loading graphics");
 +    R_Init();
 +    tprintf("\n", 0);
 +
 +    tprintf("P_Init: Init Playloop state.\n", 1);
 +    hprintf("Init game engine.");
 +    P_Init();
 +    IncThermo();
 +
 +    tprintf("I_Init: Setting up machine state.\n", 1);
 +    I_CheckIsScreensaver();
 +    I_InitTimer();
 +    I_InitJoystick();
 +    IncThermo();
 +
 +    tprintf("S_Init: Setting up sound.\n", 1);
 +    S_Init();
 +    //IO_StartupTimer();
 +    S_Start();
 +
 +    tprintf("D_CheckNetGame: Checking network game status.\n", 1);
 +    hprintf("Checking network game status.");
 +    D_CheckNetGame();
 +    IncThermo();
 +
 +#ifdef __WATCOMC__
 +    I_CheckExternDriver();      // Check for an external device driver
 +#endif
 +
 +    tprintf("SB_Init: Loading patches.\n", 1);
 +    SB_Init();
 +    IncThermo();
 +
 +//
 +// start the apropriate game based on parms
 +//
 +
 +    D_CheckRecordFrom();
 +
 +    p = M_CheckParm("-record");
 +    if (p && p < myargc - 1)
 +    {
 +        G_RecordDemo(startskill, 1, startepisode, startmap, myargv[p + 1]);
 +        D_DoomLoop();           // Never returns
 +    }
 +
 +    p = M_CheckParm("-playdemo");
 +    if (p && p < myargc - 1)
 +    {
 +        singledemo = true;      // Quit after one demo
 +        G_DeferedPlayDemo(myargv[p + 1]);
 +        D_DoomLoop();           // Never returns
 +    }
 +
 +    p = M_CheckParm("-timedemo");
 +    if (p && p < myargc - 1)
 +    {
 +        G_TimeDemo(myargv[p + 1]);
 +        D_DoomLoop();           // Never returns
 +    }
 +
 +    p = M_CheckParm("-loadgame");
 +    if (p && p < myargc - 1)
 +    {
 +        if (cdrom)
 +        {
 +            sprintf(file, SAVEGAMENAMECD "%c.hsg", myargv[p + 1][0]);
 +        }
 +        else
 +        {
 +            sprintf(file, SAVEGAMENAME "%c.hsg", myargv[p + 1][0]);
 +        }
 +        G_LoadGame(file);
 +    }
 +
 +    // Check valid episode and map
 +    if (autostart || netgame)
 +    {
 +        if (!D_ValidEpisodeMap(gamemission, gamemode, startepisode, startmap))
 +        {
 +            startepisode = 1;
 +            startmap = 1;
 +        }
 +    }
 +
 +    if (gameaction != ga_loadgame)
 +    {
 +        UpdateState |= I_FULLSCRN;
 +        BorderNeedRefresh = true;
 +        if (autostart || netgame)
 +        {
 +            G_InitNew(startskill, startepisode, startmap);
 +        }
 +        else
 +        {
 +            D_StartTitle();
 +        }
 +    }
 +
 +    finishStartup();
 +
 +    D_DoomLoop();               // Never returns
 +}
diff --cc src/hexen/h2_main.c
index 72e323c5,00000000..166c3064
mode 100644,000000..100644
--- a/src/hexen/h2_main.c
+++ b/src/hexen/h2_main.c
@@@ -1,862 -1,0 +1,862 @@@
 +// Emacs style mode select   -*- C++ -*-
 +//-----------------------------------------------------------------------------
 +//
 +// Copyright(C) 1993-1996 Id Software, Inc.
 +// Copyright(C) 1993-2008 Raven Software
 +// Copyright(C) 2008 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.
 +//
 +//-----------------------------------------------------------------------------
 +
 +
 +// HEADER FILES ------------------------------------------------------------
 +
 +#ifdef __WATCOMC__
 +#include <dos.h>
 +#include <sys\types.h>
 +#include <direct.h>
 +#endif
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <time.h>
 +
 +#include "config.h"
 +
 +#include "h2def.h"
 +#include "ct_chat.h"
 +#include "d_iwad.h"
 +#include "d_mode.h"
 +#include "m_misc.h"
 +#include "s_sound.h"
 +#include "i_joystick.h"
 +#include "i_system.h"
 +#include "i_timer.h"
 +#include "m_argv.h"
 +#include "m_config.h"
 +#include "m_controls.h"
 +#include "p_local.h"
 +#include "v_video.h"
 +
 +// MACROS ------------------------------------------------------------------
 +
 +#define MAXWADFILES 20
 +
 +// TYPES -------------------------------------------------------------------
 +
 +typedef struct
 +{
 +    char *name;
 +    void (*func) (char **args, int tag);
 +    int requiredArgs;
 +    int tag;
 +} execOpt_t;
 +
 +// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
 +
 +void R_ExecuteSetViewSize(void);
 +void D_CheckNetGame(void);
 +void G_BuildTiccmd(ticcmd_t * cmd);
 +void F_Drawer(void);
 +boolean F_Responder(event_t * ev);
 +void I_StartupKeyboard(void);
 +void I_StartupJoystick(void);
 +void I_ShutdownKeyboard(void);
 +void S_InitScript(void);
 +
 +// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
 +
 +void H2_ProcessEvents(void);
 +void H2_DoAdvanceDemo(void);
 +void H2_AdvanceDemo(void);
 +void H2_StartTitle(void);
 +void H2_PageTicker(void);
 +
 +// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
 +
 +static void DrawMessage(void);
 +static void PageDrawer(void);
 +static void HandleArgs(void);
 +static void CheckRecordFrom(void);
 +static void DrawAndBlit(void);
 +static void ExecOptionFILE(char **args, int tag);
 +static void ExecOptionSCRIPTS(char **args, int tag);
 +static void ExecOptionSKILL(char **args, int tag);
 +static void ExecOptionPLAYDEMO(char **args, int tag);
 +static void CreateSavePath(void);
 +static void WarpCheck(void);
 +
 +// EXTERNAL DATA DECLARATIONS ----------------------------------------------
 +
 +extern boolean automapactive;
 +extern boolean MenuActive;
 +extern boolean askforquit;
 +extern char *SavePath;
 +
 +// PUBLIC DATA DEFINITIONS -------------------------------------------------
 +
 +GameMode_t gamemode;
 +GameMission_t gamemission;
 +char *iwadfile;
 +boolean nomonsters;             // checkparm of -nomonsters
 +boolean respawnparm;            // checkparm of -respawn
 +boolean randomclass;            // checkparm of -randclass
 +boolean debugmode;              // checkparm of -debug
 +boolean ravpic;                 // checkparm of -ravpic
 +boolean cdrom;                  // true if cd-rom mode active
 +boolean cmdfrag;                // true if a CMD_FRAG packet should be sent out
 +boolean singletics;             // debug flag to cancel adaptiveness
 +boolean artiskip;               // whether shift-enter skips an artifact
 +int maxzone = 0x800000;         // Maximum allocated for zone heap (8meg default)
 +skill_t startskill;
 +int startepisode;
 +int startmap;
 +boolean autostart;
 +boolean advancedemo;
 +FILE *debugfile;
 +int UpdateState;
 +
 +// PRIVATE DATA DEFINITIONS ------------------------------------------------
 +
 +static int WarpMap;
 +static int demosequence;
 +static int pagetic;
 +static char *pagename;
 +
 +static execOpt_t ExecOptions[] = {
 +    {"-file", ExecOptionFILE, 1, 0},
 +    {"-scripts", ExecOptionSCRIPTS, 1, 0},
 +    {"-skill", ExecOptionSKILL, 1, 0},
 +    {"-playdemo", ExecOptionPLAYDEMO, 1, 0},
 +    {"-timedemo", ExecOptionPLAYDEMO, 1, 0},
 +    {NULL, NULL, 0, 0}          // Terminator
 +};
 +
 +// CODE --------------------------------------------------------------------
 +
 +void D_BindVariables(void)
 +{
 +    int i;
 +
 +    I_BindVideoVariables();
 +    I_BindJoystickVariables();
 +    I_BindSoundVariables();
 +    M_BindBaseControls();
 +    M_BindHereticControls();
 +    M_BindHexenControls();
 +
 +    M_BindVariable("graphical_startup",      &graphical_startup);
 +    M_BindVariable("mouse_sensitivity",      &mouseSensitivity);
 +    M_BindVariable("sfx_volume",             &snd_MaxVolume);
 +    M_BindVariable("music_volume",           &snd_MusicVolume);
 +    M_BindVariable("messageson",             &messageson);
 +    M_BindVariable("screenblocks",           &screenblocks);
 +    M_BindVariable("snd_channels",           &snd_Channels);
 +    M_BindVariable("savedir",                &SavePath);
 +
 +    // Multiplayer chat macros
 +
 +    for (i=0; i<10; ++i)
 +    {
 +        char buf[12];
 +
 +        sprintf(buf, "chatmacro%i", i);
 +        M_BindVariable(buf, &chat_macros[i]);
 +    }
 +}
 +
 +// Set the default directory where hub savegames are saved.
 +
 +static void D_SetDefaultSavePath(void)
 +{
 +    SavePath = malloc(strlen(configdir) + 10);
 +    sprintf(SavePath, "%shexndata%c", configdir, DIR_SEPARATOR);
 +}
 +
 +//
 +// D_GrabMouseCallback
 +//
 +// Called to determine whether to grab the mouse pointer
 +//
 +
 +static boolean D_GrabMouseCallback(void)
 +{
 +    // when menu is active or game is paused, release the mouse
 +
 +    if (MenuActive || paused)
 +        return false;
 +
 +    // only grab mouse when playing levels (but not demos)
 +
 +    return (gamestate == GS_LEVEL) && !demoplayback;
 +}
 +
 +// Message displayed when quitting Hexen
 +
 +static void D_HexenQuitMessage(void)
 +{
 +    printf("\nHexen: Beyond Heretic\n");
 +}
 +
 +static void D_AddFile(char *filename)
 +{
 +    printf("  adding %s\n", filename);
 +
 +    W_AddFile(filename);
 +}
 +
 +//==========================================================================
 +//
 +// H2_Main
 +//
 +//==========================================================================
 +void InitMapMusicInfo(void);
 +
 +void D_DoomMain(void)
 +{
 +    int p;
 +
 +    I_AtExit(D_HexenQuitMessage, false);
 +    M_FindResponseFile();
 +    setbuf(stdout, NULL);
 +    startepisode = 1;
 +    autostart = false;
 +    startskill = sk_medium;
 +    startmap = 1;
 +    gamemode = commercial;
 +
 +    // Initialize subsystems
 +
 +    ST_Message("V_Init: allocate screens.\n");
 +    V_Init();
 +
 +    // Load defaults before initing other systems
 +    ST_Message("M_LoadDefaults: Load system defaults.\n");
 +    D_BindVariables();
 +    M_SetConfigDir();
 +    D_SetDefaultSavePath();
 +    M_SetConfigFilenames("hexen.cfg", PROGRAM_PREFIX "hexen.cfg");
 +    M_LoadDefaults();
 +
 +    I_AtExit(M_SaveDefaults, false);
 +
 +
 +    // Now that the savedir is loaded from .CFG, make sure it exists
 +    CreateSavePath();
 +
 +    ST_Message("Z_Init: Init zone memory allocation daemon.\n");
 +    Z_Init();
 +
 +#ifdef __WATCOMC__
 +    I_StartupKeyboard();
 +    I_StartupJoystick();
 +#endif
 +
 +    ST_Message("W_Init: Init WADfiles.\n");
 +
 +    iwadfile = D_FindIWAD(IWAD_MASK_HEXEN, &gamemission);
 +
 +    if (iwadfile == NULL)
 +    {
 +        I_Error("Game mode indeterminate. No IWAD was found. Try specifying\n"
 +                "one with the '-iwad' command line parameter.");
 +    }
 +
 +    D_AddFile(iwadfile);
 +
 +    HandleArgs();
 +
 +    I_PrintStartupBanner("Hexen");
 +
 +    ST_Message("MN_Init: Init menu system.\n");
 +    MN_Init();
 +
 +    ST_Message("CT_Init: Init chat mode data.\n");
 +    CT_Init();
 +
 +    InitMapMusicInfo();         // Init music fields in mapinfo
 +
 +    ST_Message("S_InitScript\n");
 +    S_InitScript();
 +
 +    ST_Message("SN_InitSequenceScript: Registering sound sequences.\n");
 +    SN_InitSequenceScript();
 +    ST_Message("I_Init: Setting up machine state.\n");
 +    I_CheckIsScreensaver();
 +    I_InitTimer();
 +    I_InitJoystick();
 +
 +    S_Init();
 +    S_Start();
 +
 +    ST_Message("ST_Init: Init startup screen.\n");
 +    ST_Init();
 +
 +    // Show version message now, so it's visible during R_Init()
 +    ST_Message("R_Init: Init Hexen refresh daemon");
 +    R_Init();
 +    ST_Message("\n");
 +
 +    if (M_CheckParm("-net"))
 +        ST_NetProgress();       // Console player found
 +
 +    ST_Message("P_Init: Init Playloop state.\n");
 +    P_Init();
 +
 +    // Check for command line warping. Follows P_Init() because the
 +    // MAPINFO.TXT script must be already processed.
 +    WarpCheck();
 +
 +    if (autostart)
 +    {
 +        ST_Message("Warp to Map %d (\"%s\":%d), Skill %d\n",
 +                   WarpMap, P_GetMapName(startmap), startmap, startskill + 1);
 +    }
 +
 +    ST_Message("D_CheckNetGame: Checking network game status.\n");
 +    D_CheckNetGame();
 +
 +    ST_Message("SB_Init: Loading patches.\n");
 +    SB_Init();
 +
 +    ST_Done();
 +
 +    CheckRecordFrom();
 +
 +    p = M_CheckParm("-record");
 +    if (p && p < myargc - 1)
 +    {
 +        G_RecordDemo(startskill, 1, startepisode, startmap, myargv[p + 1]);
 +        H2_GameLoop();          // Never returns
 +    }
 +
 +    p = M_CheckParm("-playdemo");
 +    if (p && p < myargc - 1)
 +    {
 +        singledemo = true;      // Quit after one demo
 +        G_DeferedPlayDemo(myargv[p + 1]);
 +        H2_GameLoop();          // Never returns
 +    }
 +
 +    p = M_CheckParm("-timedemo");
 +    if (p && p < myargc - 1)
 +    {
 +        G_TimeDemo(myargv[p + 1]);
 +        H2_GameLoop();          // Never returns
 +    }
 +
 +    p = M_CheckParm("-loadgame");
 +    if (p && p < myargc - 1)
 +    {
 +        G_LoadGame(atoi(myargv[p + 1]));
 +    }
 +
 +    if (gameaction != ga_loadgame)
 +    {
 +        UpdateState |= I_FULLSCRN;
 +        BorderNeedRefresh = true;
 +        if (autostart || netgame)
 +        {
 +            G_StartNewInit();
 +            G_InitNew(startskill, startepisode, startmap);
 +        }
 +        else
 +        {
 +            H2_StartTitle();
 +        }
 +    }
 +    H2_GameLoop();              // Never returns
 +}
 +
 +//==========================================================================
 +//
 +// HandleArgs
 +//
 +//==========================================================================
 +
 +static void HandleArgs(void)
 +{
 +    int p;
 +    execOpt_t *opt;
 +
 +    nomonsters = M_ParmExists("-nomonsters");
 +    respawnparm = M_ParmExists("-respawn");
 +    randomclass = M_ParmExists("-randclass");
 +    ravpic = M_ParmExists("-ravpic");
 +    artiskip = M_ParmExists("-artiskip");
 +    debugmode = M_ParmExists("-debug");
 +    deathmatch = M_ParmExists("-deathmatch");
 +    cdrom = M_ParmExists("-cdrom");
 +    cmdfrag = M_ParmExists("-cmdfrag");
 +
 +    // Process command line options
 +    for (opt = ExecOptions; opt->name != NULL; opt++)
 +    {
 +        p = M_CheckParm(opt->name);
 +        if (p && p < myargc - opt->requiredArgs)
 +        {
 +            opt->func(&myargv[p], opt->tag);
 +        }
 +    }
 +}
 +
 +//==========================================================================
 +//
 +// WarpCheck
 +//
 +//==========================================================================
 +
 +static void WarpCheck(void)
 +{
 +    int p;
 +    int map;
 +
 +    p = M_CheckParm("-warp");
 +    if (p && p < myargc - 1)
 +    {
 +        WarpMap = atoi(myargv[p + 1]);
 +        map = P_TranslateMap(WarpMap);
 +        if (map == -1)
 +        {                       // Couldn't find real map number
 +            startmap = 1;
 +            ST_Message("-WARP: Invalid map number.\n");
 +        }
 +        else
 +        {                       // Found a valid startmap
 +            startmap = map;
 +            autostart = true;
 +        }
 +    }
 +    else
 +    {
 +        WarpMap = 1;
 +        startmap = P_TranslateMap(1);
 +        if (startmap == -1)
 +        {
 +            startmap = 1;
 +        }
 +    }
 +}
 +
 +//==========================================================================
 +//
 +// ExecOptionSKILL
 +//
 +//==========================================================================
 +
 +static void ExecOptionSKILL(char **args, int tag)
 +{
 +    startskill = args[1][0] - '1';
 +    autostart = true;
 +}
 +
 +//==========================================================================
 +//
 +// ExecOptionFILE
 +//
 +//==========================================================================
 +
 +static void ExecOptionFILE(char **args, int tag)
 +{
 +    char *filename;
 +    int p;
 +
 +    p = M_CheckParm("-file");
 +    while (++p != myargc && myargv[p][0] != '-')
 +    {
 +        filename = D_TryFindWADByName(myargv[p]);
 +
 +        D_AddFile(filename);
 +    }
 +}
 +
 +
 +//==========================================================================
 +//
 +// ExecOptionPLAYDEMO
 +//
 +//==========================================================================
 +
 +static void ExecOptionPLAYDEMO(char **args, int tag)
 +{
 +    char file[256];
 +
 +    strcpy(file, args[1]);
 +
 +    if (strcasecmp(file + strlen(file) - 4, ".lmp") != 0)
 +    {
 +        strcat(file, ".lmp");
 +    }
 +
 +    W_AddFile(file);
 +    ST_Message("Playing demo %s.\n", file);
 +}
 +
 +//==========================================================================
 +//
 +// ExecOptionSCRIPTS
 +//
 +//==========================================================================
 +
 +static void ExecOptionSCRIPTS(char **args, int tag)
 +{
 +    sc_FileScripts = true;
 +    sc_ScriptsDir = args[1];
 +}
 +
 +
 +//==========================================================================
 +//
 +// H2_GameLoop
 +//
 +//==========================================================================
 +
 +void H2_GameLoop(void)
 +{
 +    if (M_CheckParm("-debugfile"))
 +    {
 +        char filename[20];
 +        sprintf(filename, "debug%i.txt", consoleplayer);
 +        debugfile = fopen(filename, "w");
 +    }
++    I_SetWindowTitle("Hexen");
 +    I_InitGraphics();
 +    I_SetGrabMouseCallback(D_GrabMouseCallback);
-     I_SetWindowTitle("Hexen");
 +
 +    while (1)
 +    {
 +        // Frame syncronous IO operations
 +        I_StartFrame();
 +
 +        // Process one or more tics
 +        if (singletics)
 +        {
 +            I_StartTic();
 +            H2_ProcessEvents();
 +            G_BuildTiccmd(&netcmds[consoleplayer][maketic % BACKUPTICS]);
 +            if (advancedemo)
 +            {
 +                H2_DoAdvanceDemo();
 +            }
 +            G_Ticker();
 +            gametic++;
 +            maketic++;
 +        }
 +        else
 +        {
 +            // Will run at least one tic
 +            TryRunTics();
 +        }
 +
 +        // Move positional sounds
 +        S_UpdateSounds(players[displayplayer].mo);
 +
 +        DrawAndBlit();
 +    }
 +}
 +
 +//==========================================================================
 +//
 +// H2_ProcessEvents
 +//
 +// Send all the events of the given timestamp down the responder chain.
 +//
 +//==========================================================================
 +
 +void H2_ProcessEvents(void)
 +{
 +    event_t *ev;
 +
 +    for (;;)
 +    {
 +        ev = D_PopEvent();
 +
 +        if (ev == NULL)
 +        {
 +            break;
 +        }
 +
 +        if (F_Responder(ev))
 +        {
 +            continue;
 +        }
 +        if (MN_Responder(ev))
 +        {
 +            continue;
 +        }
 +        G_Responder(ev);
 +    }
 +}
 +
 +//==========================================================================
 +//
 +// DrawAndBlit
 +//
 +//==========================================================================
 +
 +static void DrawAndBlit(void)
 +{
 +    // Change the view size if needed
 +    if (setsizeneeded)
 +    {
 +        R_ExecuteSetViewSize();
 +    }
 +
 +    // Do buffered drawing
 +    switch (gamestate)
 +    {
 +        case GS_LEVEL:
 +            if (!gametic)
 +            {
 +                break;
 +            }
 +            if (automapactive)
 +            {
 +                AM_Drawer();
 +            }
 +            else
 +            {
 +                R_RenderPlayerView(&players[displayplayer]);
 +            }
 +            CT_Drawer();
 +            UpdateState |= I_FULLVIEW;
 +            SB_Drawer();
 +            break;
 +        case GS_INTERMISSION:
 +            IN_Drawer();
 +            break;
 +        case GS_FINALE:
 +            F_Drawer();
 +            break;
 +        case GS_DEMOSCREEN:
 +            PageDrawer();
 +            break;
 +    }
 +
 +    if (paused && !MenuActive && !askforquit)
 +    {
 +        if (!netgame)
 +        {
 +            V_DrawPatch(160, viewwindowy + 5, W_CacheLumpName("PAUSED",
 +                                                              PU_CACHE));
 +        }
 +        else
 +        {
 +            V_DrawPatch(160, 70, W_CacheLumpName("PAUSED", PU_CACHE));
 +        }
 +    }
 +
 +    // Draw current message
 +    DrawMessage();
 +
 +    // Draw Menu
 +    MN_Drawer();
 +
 +    // Send out any new accumulation
 +    NetUpdate();
 +
 +    // Flush buffered stuff to screen
 +    I_FinishUpdate();
 +}
 +
 +//==========================================================================
 +//
 +// DrawMessage
 +//
 +//==========================================================================
 +
 +static void DrawMessage(void)
 +{
 +    player_t *player;
 +
 +    player = &players[consoleplayer];
 +    if (player->messageTics <= 0 || !player->message)
 +    {                           // No message
 +        return;
 +    }
 +    if (player->yellowMessage)
 +    {
 +        MN_DrTextAYellow(player->message,
 +                         160 - MN_TextAWidth(player->message) / 2, 1);
 +    }
 +    else
 +    {
 +        MN_DrTextA(player->message, 160 - MN_TextAWidth(player->message) / 2,
 +                   1);
 +    }
 +}
 +
 +//==========================================================================
 +//
 +// H2_PageTicker
 +//
 +//==========================================================================
 +
 +void H2_PageTicker(void)
 +{
 +    if (--pagetic < 0)
 +    {
 +        H2_AdvanceDemo();
 +    }
 +}
 +
 +//==========================================================================
 +//
 +// PageDrawer
 +//
 +//==========================================================================
 +
 +static void PageDrawer(void)
 +{
 +    V_DrawRawScreen(W_CacheLumpName(pagename, PU_CACHE));
 +    if (demosequence == 1)
 +    {
 +        V_DrawPatch(4, 160, W_CacheLumpName("ADVISOR", PU_CACHE));
 +    }
 +    UpdateState |= I_FULLSCRN;
 +}
 +
 +//==========================================================================
 +//
 +// H2_AdvanceDemo
 +//
 +// Called after each demo or intro demosequence finishes.
 +//
 +//==========================================================================
 +
 +void H2_AdvanceDemo(void)
 +{
 +    advancedemo = true;
 +}
 +
 +//==========================================================================
 +//
 +// H2_DoAdvanceDemo
 +//
 +//==========================================================================
 +
 +void H2_DoAdvanceDemo(void)
 +{
 +    players[consoleplayer].playerstate = PST_LIVE;      // don't reborn
 +    advancedemo = false;
 +    usergame = false;           // can't save/end game here
 +    paused = false;
 +    gameaction = ga_nothing;
 +    demosequence = (demosequence + 1) % 7;
 +    switch (demosequence)
 +    {
 +        case 0:
 +            pagetic = 280;
 +            gamestate = GS_DEMOSCREEN;
 +            pagename = "TITLE";
 +            S_StartSongName("hexen", true);
 +            break;
 +        case 1:
 +            pagetic = 210;
 +            gamestate = GS_DEMOSCREEN;
 +            pagename = "TITLE";
 +            break;
 +        case 2:
 +            BorderNeedRefresh = true;
 +            UpdateState |= I_FULLSCRN;
 +            G_DeferedPlayDemo("demo1");
 +            break;
 +        case 3:
 +            pagetic = 200;
 +            gamestate = GS_DEMOSCREEN;
 +            pagename = "CREDIT";
 +            break;
 +        case 4:
 +            BorderNeedRefresh = true;
 +            UpdateState |= I_FULLSCRN;
 +            G_DeferedPlayDemo("demo2");
 +            break;
 +        case 5:
 +            pagetic = 200;
 +            gamestate = GS_DEMOSCREEN;
 +            pagename = "CREDIT";
 +            break;
 +        case 6:
 +            BorderNeedRefresh = true;
 +            UpdateState |= I_FULLSCRN;
 +            G_DeferedPlayDemo("demo3");
 +            break;
 +    }
 +}
 +
 +//==========================================================================
 +//
 +// H2_StartTitle
 +//
 +//==========================================================================
 +
 +void H2_StartTitle(void)
 +{
 +    gameaction = ga_nothing;
 +    demosequence = -1;
 +    H2_AdvanceDemo();
 +}
 +
 +//==========================================================================
 +//
 +// CheckRecordFrom
 +//
 +// -recordfrom <savegame num> <demoname>
 +//
 +//==========================================================================
 +
 +static void CheckRecordFrom(void)
 +{
 +    int p;
 +
 +    p = M_CheckParm("-recordfrom");
 +    if (!p || p > myargc - 2)
 +    {                           // Bad args
 +        return;
 +    }
 +    G_LoadGame(atoi(myargv[p + 1]));
 +    G_DoLoadGame();             // Load the gameskill etc info from savegame
 +    G_RecordDemo(gameskill, 1, gameepisode, gamemap, myargv[p + 2]);
 +
 +    H2_GameLoop();              // Never returns
 +}
 +
 +#ifdef __WATCOMC__
 +/*
 +void CleanExit(void)
 +{
 +	union REGS regs;
 +
 +	I_ShutdownKeyboard();
 +	regs.x.eax = 0x3;
 +	int386(0x10, &regs, &regs);
 +	printf("Exited from HEXEN: Beyond Heretic.\n");
 +	exit(1);
 +}
 +*/
 +#endif
 +
 +//==========================================================================
 +//
 +// CreateSavePath
 +//
 +//==========================================================================
 +
 +static void CreateSavePath(void)
 +{
 +    M_MakeDirectory(SavePath);
 +}
 +
diff --cc src/i_endoom.c
index b943e47c,00000000..b053b433
mode 100644,000000..100644
--- a/src/i_endoom.c
+++ b/src/i_endoom.c
@@@ -1,71 -1,0 +1,66 @@@
 +// Emacs style mode select   -*- C++ -*-
 +//-----------------------------------------------------------------------------
 +//
 +// Copyright(C) 2005-8 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:
 +//    Exit text-mode ENDOOM screen.
 +//
 +//-----------------------------------------------------------------------------
 +
 +#include "doomtype.h"
 +#include "i_video.h"
 +
 +#include "txt_main.h"
 +
 +//
 +// Displays the text mode ending screen after the game quits
 +//
 +
 +void I_Endoom(byte *endoom_data)
 +{
 +    unsigned char *screendata;
 +
 +    // Set up text mode screen
 +
 +    TXT_Init();
 +
-     // Make sure the new window has the right title and icon
-
-     I_SetWindowTitle("Exit screen");
-     I_SetWindowIcon();
-
 +    // Write the data to the screen memory
 +
 +    screendata = TXT_GetScreenData();
 +    memcpy(screendata, endoom_data, 4000);
 +
 +    // Wait for a keypress
 +
 +    while (true)
 +    {
 +        TXT_UpdateScreen();
 +
 +        if (TXT_GetChar() >= 0)
 +        {
 +            break;
 +        }
 +
 +        TXT_Sleep(0);
 +    }
 +
 +    // Shut down text mode screen
 +
 +    TXT_Shutdown();
 +}
 +
diff --cc src/i_main.c
index bab514dd,c103296b..d7cdcef6
--- a/src/i_main.c
+++ b/src/i_main.c
@@@ -37,37 -41,40 +41,46 @@@
  #include <sched.h>
  #endif

 -#include "doomdef.h"
 +#include "doomtype.h"
  #include "i_system.h"
  #include "m_argv.h"
 -#include "d_main.h"
 +
 +//
 +// D_DoomMain()
 +// Not a globally visible function, just included for source reference,
 +// calls all startup code, parses command line options.
 +//
 +
 +void D_DoomMain (void);

- int main(int argc, char **argv)
- {
+ #if !defined(_WIN32) && !defined(HAVE_SCHED_SETAFFINITY)
+ #warning No known way to set processor affinity on this platform.
+ #warning You may experience crashes due to SDL_mixer.
+ #endif
+
+ int main(int argc, char **argv)
+ {
      // save arguments

-     myargc = argc;
-     myargv = argv;
+     myargc = argc;
+     myargv = argv;
+
+ #ifdef _WIN32

      // Set the process affinity mask so that all threads
-     // run on the same processor.  This is a workaround for a bug in
+     // run on the same processor.  This is a workaround for a bug in
      // SDL_mixer that causes occasional crashes.

- #ifdef _WIN32
      if (!SetProcessAffinityMask(GetCurrentProcess(), 1))
      {
          fprintf(stderr, "Failed to set process affinity mask (%d)\n",
                  (int) GetLastError());
      }
- #elif !defined(__APPLE__)
-     // POSIX version:
 -
+ #endif
+
+ #ifdef HAVE_SCHED_SETAFFINITY
+
+     // Linux version:

      {
          cpu_set_t set;
diff --cc src/i_video.c
index 39aedc0c,0ed4d716..8360ab9e
--- a/src/i_video.c
+++ b/src/i_video.c
@@@ -128,8 -87,8 +128,14 @@@ 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 = "";
++
  // palette

  static SDL_Color palette[256];
@@@ -994,16 -836,16 +1005,26 @@@ void I_SetPalette (byte *doompalette
  }

  //
 -// Set the window caption
 +// Set the window title
 +//
 +
 +void I_SetWindowTitle(char *title)
++{
++    window_title = title;
++}
++
++//
++// Call the SDL function to set the window title, based on
++// the title set with I_SetWindowTitle.
+ //
+
 -void I_SetWindowCaption(void)
++static void I_InitWindowTitle(void)
  {
      char *buf;

-     buf = Z_Malloc(strlen(title) + strlen(PACKAGE_STRING) + 5,
 -    buf = Z_Malloc(strlen(gamedescription) + strlen(PACKAGE_STRING) + 10,
++    buf = Z_Malloc(strlen(window_title) + strlen(PACKAGE_STRING) + 5,
                     PU_STATIC, NULL);
-     sprintf(buf, "%s - %s", title, PACKAGE_STRING);
 -    sprintf(buf, "%s - %s", gamedescription, PACKAGE_STRING);
++    sprintf(buf, "%s - %s", window_title, PACKAGE_STRING);

      SDL_WM_SetCaption(buf, NULL);

@@@ -1012,7 -854,7 +1033,7 @@@

  // Set the application icon

--void I_SetWindowIcon(void)
++static void I_InitWindowIcon(void)
  {
      SDL_Surface *surface;
      Uint8 *mask;
@@@ -1669,6 -1481,12 +1690,12 @@@ void I_InitGraphics(void
          }
      }

+     // Set up title and icon.  Windows cares about the ordering; this
+     // has to be done before the call to SDL_SetVideoMode.
+
 -    I_SetWindowCaption();
 -    I_SetWindowIcon();
++    I_InitWindowTitle();
++    I_InitWindowIcon();
+
      // Set the video mode.

      flags |= SDL_SWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF;
diff --cc src/i_video.h
index 1c668474,bd5de24a..af865287
--- a/src/i_video.h
+++ b/src/i_video.h
@@@ -90,37 -79,22 +90,36 @@@ 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_SetWindowIcon(void);

  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 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 a4db1c98,4066cb3c..cfdf12a5
--- a/src/m_config.c
+++ b/src/m_config.c
@@@ -33,16 -32,34 +33,15 @@@
  #include <errno.h>

  #include "config.h"
 -#include "deh_main.h"
 -#include "doomdef.h"
 -#include "doomfeatures.h"
 -
 -#include "z_zone.h"
 -
 -#include "m_menu.h"
 -#include "m_argv.h"
 -#include "net_client.h"

- #include "d_englsh.h"
 -#include "w_wad.h"
 -
 -#include "i_joystick.h"
 -#include "i_swap.h"
 +#include "doomtype.h"
 +#include "doomkeys.h"
 +#include "doomfeatures.h"
  #include "i_system.h"
 -#include "i_video.h"
 -#include "v_video.h"
 -
 -#include "hu_stuff.h"
 -
 -// State.
 -#include "doomstat.h"
 -
 -// Data.
 -#include "dstrings.h"
 -
 +#include "m_argv.h"
  #include "m_misc.h"

 +#include "z_zone.h"

  //
  // DEFAULTS