foxygit / doom Log in
commit d91e3e86736f710265629e56dc77c1dec0b425e7
Merge: 0f5de61b d4863b4c
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Sat Jun 13 15:36:20 2009 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Sat Jun 13 15:36:20 2009 +0000

    Merge from trunk.

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

 src/doom/d_main.c    |  2 ++
 src/heretic/d_main.c |  2 ++
 src/hexen/h2_main.c  |  2 ++
 src/i_video.c        | 17 ++++++++++--
 src/m_controls.c     | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/m_controls.h     |  2 ++
 src/setup/mode.c     |  2 ++
 wince/env.c          | 37 +++++++++++++++++++++----
 8 files changed, 133 insertions(+), 7 deletions(-)

diff --cc src/doom/d_main.c
index ce9b667d,c59a8fb7..9fa9ae3b
--- a/src/doom/d_main.c
+++ b/src/doom/d_main.c
@@@ -340,71 -387,7 +340,73 @@@ void D_Display (void
      } while (!done);
  }

 +//
 +// Add configuration file variable bindings.
 +//
 +
 +void D_BindVariables(void)
 +{
 +    int i;
 +
++    M_ApplyPlatformDefaults();
++
 +    I_BindVideoVariables();
 +    I_BindJoystickVariables();
 +    I_BindSoundVariables();
 +
 +    M_BindBaseControls();
 +    M_BindWeaponControls();
 +    M_BindMapControls();
 +    M_BindMenuControls();
 +
 +#ifdef FEATURE_MULTIPLAYER
 +    NET_BindVariables();
 +#endif
 +
 +    M_BindVariable("mouse_sensitivity",      &mouseSensitivity);
 +    M_BindVariable("sfx_volume",             &sfxVolume);
 +    M_BindVariable("music_volume",           &musicVolume);
 +    M_BindVariable("show_messages",          &showMessages);
 +    M_BindVariable("screenblocks",           &screenblocks);
 +    M_BindVariable("detaillevel",            &detailLevel);
 +    M_BindVariable("snd_channels",           &snd_channels);
 +    M_BindVariable("vanilla_savegame_limit", &vanilla_savegame_limit);
 +    M_BindVariable("vanilla_demo_limit",     &vanilla_demo_limit);
 +    M_BindVariable("show_endoom",            &show_endoom);

 +    // Multiplayer chat macros
 +
 +    for (i=0; i<10; ++i)
 +    {
 +        char buf[12];
 +
 +        sprintf(buf, "chatmacro%i", i);
 +        M_BindVariable(buf, &chat_macros[i]);
 +    }
 +}
 +
 +//
 +// D_GrabMouseCallback
 +//
 +// Called to determine whether to grab the mouse pointer
 +//
 +
 +boolean D_GrabMouseCallback(void)
 +{
 +    // Drone players don't need mouse focus
 +
 +    if (drone)
 +        return false;
 +
 +    // 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;
 +}

  //
  //  D_DoomLoop
diff --cc src/heretic/d_main.c
index d501c496,00000000..10f5fd3e
mode 100644,000000..100644
--- a/src/heretic/d_main.c
+++ b/src/heretic/d_main.c
@@@ -1,1081 -1,0 +1,1083 @@@
 +// 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_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;
 +    }
 +    // haleyjd FIXME: convert to textscreen code?
 +#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();
 +    }
 +
 +    // haleyjd: shouldn't be WATCOMC-only
 +    if (debugmode)
 +        puts(string);
 +}
 +
 +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)
 +{
 +    if (using_graphical_startup)
 +    {
 +        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)
 +{
 +    // haleyjd FIXME: convert to textscreen code?
 +#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
 +}
 +
 +// haleyjd: moved up, removed WATCOMC code
 +void CleanExit(void)
 +{
 +    printf("Exited from HERETIC.\n");
 +    exit(1);
 +}
 +
 +void CheckAbortStartup(void)
 +{
 +    // haleyjd: removed WATCOMC
 +    // haleyjd FIXME: this should actually work in text mode too, but how to
 +    // get input before SDL video init?
 +    if(using_graphical_startup)
 +    {
 +        if(TXT_GetChar() == 27)
 +            CleanExit();
 +    }
 +}
 +
 +void IncThermo(void)
 +{
 +    thermCurrent++;
 +    DrawThermo();
 +    CheckAbortStartup();
 +}
 +
 +void InitThermo(int max)
 +{
 +    thermMax = max;
 +    thermCurrent = 0;
 +}
 +
 +//
 +// Add configuration file variable bindings.
 +//
 +
 +void D_BindVariables(void)
 +{
 +    extern int screenblocks;
 +    extern int snd_Channels;
 +    int i;
 +
++    M_ApplyPlatformDefaults();
++
 +    I_BindVideoVariables();
 +    I_BindJoystickVariables();
 +    I_BindSoundVariables();
 +
 +    M_BindBaseControls();
 +    M_BindHereticControls();
 +    M_BindWeaponControls();
 +
 +    M_BindMenuControls();
 +    M_BindMapControls();
 +
 +    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();
 +    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;
 +
 +//
 +// 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();
 +
 +    // Check for -CDROM
 +
 +    cdrom = false;
 +
 +#ifdef _WIN32
 +
 +    //!
 +    // @platform windows
 +    // @vanilla
 +    //
 +    // Save configuration data and savegames in c:\heretic.cd,
 +    // allowing play from CD.
 +    //
 +
 +    if (M_CheckParm("-cdrom"))
 +    {
 +        cdrom = true;
 +    }
 +#endif
 +
 +    if (cdrom)
 +    {
 +        M_SetConfigDir("c:\\heretic.cd\\");
 +    }
 +    else
 +    {
 +        M_SetConfigDir(NULL);
 +    }
 +
 +    // 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);
 +
 +    // haleyjd: removed WATCOMC
 +    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();
 +
 +    // haleyjd: removed WATCOMC
 +
 +    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 656ab80c,00000000..ef223c0e
mode 100644,000000..100644
--- a/src/hexen/h2_main.c
+++ b/src/hexen/h2_main.c
@@@ -1,879 -1,0 +1,881 @@@
 +// 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 ------------------------------------------------------------
 +
 +// haleyjd: removed WATCOMC
 +#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 = false;          // 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;
 +
++    M_ApplyPlatformDefaults();
++
 +    I_BindVideoVariables();
 +    I_BindJoystickVariables();
 +    I_BindSoundVariables();
 +
 +    M_BindBaseControls();
 +    M_BindMapControls();
 +    M_BindMenuControls();
 +    M_BindWeaponControls();
 +    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();
 +    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();
 +
 +#ifdef _WIN32
 +
 +    //!
 +    // @platform windows
 +    // @vanilla
 +    //
 +    // Save configuration data and savegames in c:\hexndata,
 +    // allowing play from CD.
 +    //
 +
 +    cdrom = M_ParmExists("-cdrom");
 +#endif
 +
 +    if (cdrom)
 +    {
 +        M_SetConfigDir("c:\\hexndata\\");
 +    }
 +    else
 +    {
 +        M_SetConfigDir(NULL);
 +    }
 +
 +    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();
 +
 +    // haleyjd: removed WATCOMC
 +
 +    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");
 +
 +    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);
 +
 +    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
 +}
 +
 +// haleyjd: removed 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);
 +}
 +*/
 +
 +//==========================================================================
 +//
 +// CreateSavePath
 +//
 +//==========================================================================
 +
 +static void CreateSavePath(void)
 +{
 +    M_MakeDirectory(SavePath);
 +}
 +
diff --cc src/i_video.c
index a41f523b,aaefd922..a938b1f8
--- a/src/i_video.c
+++ b/src/i_video.c
@@@ -282,34 -209,26 +293,36 @@@ static boolean MouseShouldBeGrabbed(
      if (!usemouse || nomouse)
          return false;

 -    // Drone players don't need mouse focus
 -
 -    if (drone)
 -        return false;
 -
      // if we specify not to grab the mouse, never grab
-
+
      if (!grabmouse)
          return false;

 -    // when menu is active or game is paused, release the mouse
 +    // Invoke the grabmouse callback function to determine whether
 +    // the mouse should be grabbed

 -    if (menuactive || paused)
 -        return false;
 +    if (grabmouse_callback != NULL)
 +    {
 +        return grabmouse_callback();
 +    }
 +    else
 +    {
 +        return true;
 +    }
+
 -    // only grab mouse when playing levels (but not demos)
++#endif /* #ifndef _WIN32_WCE */
 +}

 -    return (gamestate == GS_LEVEL) && !demoplayback;
 +void I_SetGrabMouseCallback(grabmouse_callback_t func)
 +{
 +    grabmouse_callback = func;
 +}

 -#endif /* #ifndef _WIN32_WCE */
 +// Set the variable controlling FPS dots.
 +
 +void I_DisplayFPSDots(boolean dots_on)
 +{
 +    display_fps_dots = dots_on;
  }

  // Update the value of window_focused when we get a focus event
diff --cc src/m_controls.c
index 1cca6263,00000000..98b1e51b
mode 100644,000000..100644
--- a/src/m_controls.c
+++ b/src/m_controls.c
@@@ -1,274 -1,0 +1,350 @@@
 +// Emacs style mode select   -*- C++ -*-
 +//-----------------------------------------------------------------------------
 +//
 +// Copyright(C) 1993-1996 Id Software, Inc.
 +// Copyright(C) 1993-2008 Raven Software
 +// 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.
 +//
 +//-----------------------------------------------------------------------------
 +
 +#include "doomtype.h"
 +#include "doomkeys.h"
 +
 +#include "m_config.h"
 +
 +//
 +// Keyboard controls
 +//
 +
 +int key_right = KEY_RIGHTARROW;
 +int key_left = KEY_LEFTARROW;
 +
 +int key_up = KEY_UPARROW;
 +int key_down = KEY_DOWNARROW;
 +int key_strafeleft = ',';
 +int key_straferight = '.';
 +int key_fire = KEY_RCTRL;
 +int key_use = ' ';
 +int key_strafe = KEY_RALT;
 +int key_speed = KEY_RSHIFT;
 +
 +//
 +// Heretic keyboard controls
 +//
 +
 +int key_flyup = KEY_PGUP;
 +int key_flydown = KEY_INS;
 +int key_flycenter = KEY_HOME;
 +
 +int key_lookup = KEY_PGDN;
 +int key_lookdown = KEY_DEL;
 +int key_lookcenter = KEY_END;
 +
 +int key_invleft = '[';
 +int key_invright = ']';
 +int key_useartifact = KEY_ENTER;
 +
 +//
 +// Hexen key controls
 +//
 +
 +int key_jump = '/';
 +
 +//
 +// Mouse controls
 +//
 +
 +int mousebfire = 0;
 +int mousebstrafe = 1;
 +int mousebforward = 2;
 +
 +int mousebjump = -1;
 +
 +int mousebstrafeleft = -1;
 +int mousebstraferight = -1;
 +int mousebbackward = -1;
 +int mousebuse = -1;
 +
 +int key_message_refresh = KEY_ENTER;
 +int key_pause = KEY_PAUSE;
 +
 +// Weapon selection keys:
 +
 +int key_weapon1 = '1';
 +int key_weapon2 = '2';
 +int key_weapon3 = '3';
 +int key_weapon4 = '4';
 +int key_weapon5 = '5';
 +int key_weapon6 = '6';
 +int key_weapon7 = '7';
 +int key_weapon8 = '8';
 +
 +// Map cotnrols keys:
 +
 +int key_map_north     = KEY_UPARROW;
 +int key_map_south     = KEY_DOWNARROW;
 +int key_map_east      = KEY_RIGHTARROW;
 +int key_map_west      = KEY_LEFTARROW;
 +int key_map_zoomin    = '=';
 +int key_map_zoomout   = '-';
 +int key_map_toggle    = KEY_TAB;
 +int key_map_maxzoom   = '0';
 +int key_map_follow    = 'f';
 +int key_map_grid      = 'g';
 +int key_map_mark      = 'm';
 +int key_map_clearmark = 'c';
 +
 +// menu keys:
 +
 +int key_menu_activate  = KEY_ESCAPE;
 +int key_menu_up        = KEY_UPARROW;
 +int key_menu_down      = KEY_DOWNARROW;
 +int key_menu_left      = KEY_LEFTARROW;
 +int key_menu_right     = KEY_RIGHTARROW;
 +int key_menu_back      = KEY_BACKSPACE;
 +int key_menu_forward   = KEY_ENTER;
 +int key_menu_confirm   = 'y';
 +int key_menu_abort     = 'n';
 +
 +int key_menu_help      = KEY_F1;
 +int key_menu_save      = KEY_F2;
 +int key_menu_load      = KEY_F3;
 +int key_menu_volume    = KEY_F4;
 +int key_menu_detail    = KEY_F5;
 +int key_menu_qsave     = KEY_F6;
 +int key_menu_endgame   = KEY_F7;
 +int key_menu_messages  = KEY_F8;
 +int key_menu_qload     = KEY_F9;
 +int key_menu_quit      = KEY_F10;
 +int key_menu_gamma     = KEY_F11;
 +
 +int key_menu_incscreen = KEY_EQUALS;
 +int key_menu_decscreen = KEY_MINUS;
 +
 +//
 +// Joystick controls
 +//
 +
 +int joybfire = 0;
 +int joybstrafe = 1;
 +int joybuse = 3;
 +int joybspeed = 2;
 +
 +int joybstrafeleft = -1;
 +int joybstraferight = -1;
 +
 +int joybjump = -1;
 +
 +// Control whether if a mouse button is double clicked, it acts like
 +// "use" has been pressed
 +
 +int dclick_use = 1;
 +
 +//
 +// Bind all of the common controls used by Doom and all other games.
 +//
 +
 +void M_BindBaseControls(void)
 +{
 +    M_BindVariable("key_right",          &key_right),
 +    M_BindVariable("key_left",           &key_left),
 +    M_BindVariable("key_up",             &key_up),
 +    M_BindVariable("key_down",           &key_down),
 +    M_BindVariable("key_strafeleft",     &key_strafeleft),
 +    M_BindVariable("key_straferight",    &key_straferight),
 +    M_BindVariable("key_fire",           &key_fire),
 +    M_BindVariable("key_use",            &key_use),
 +    M_BindVariable("key_strafe",         &key_strafe),
 +    M_BindVariable("key_speed",          &key_speed),
 +
 +    M_BindVariable("mouseb_fire",        &mousebfire),
 +    M_BindVariable("mouseb_strafe",      &mousebstrafe),
 +    M_BindVariable("mouseb_forward",     &mousebforward),
 +
 +    M_BindVariable("joyb_fire",          &joybfire),
 +    M_BindVariable("joyb_strafe",        &joybstrafe),
 +    M_BindVariable("joyb_use",           &joybuse),
 +    M_BindVariable("joyb_speed",         &joybspeed),
 +
 +    // Extra controls that are not in the Vanilla versions:
 +
 +    M_BindVariable("joyb_strafeleft",    &joybstrafeleft);
 +    M_BindVariable("joyb_straferight",   &joybstraferight);
 +    M_BindVariable("mouseb_strafeleft",  &mousebstrafeleft);
 +    M_BindVariable("mouseb_straferight", &mousebstraferight);
 +    M_BindVariable("mouseb_use",         &mousebuse);
 +    M_BindVariable("mouseb_backward",    &mousebbackward);
 +    M_BindVariable("dclick_use",         &dclick_use);
 +    M_BindVariable("key_pause",          &key_pause);
 +    M_BindVariable("key_message_refresh", &key_message_refresh);
 +}
 +
 +void M_BindHereticControls(void)
 +{
 +    M_BindVariable("key_flyup",          &key_flyup);
 +    M_BindVariable("key_flydown",        &key_flydown);
 +    M_BindVariable("key_flycenter",      &key_flycenter);
 +
 +    M_BindVariable("key_lookup",         &key_lookup);
 +    M_BindVariable("key_lookdown",       &key_lookdown);
 +    M_BindVariable("key_lookcenter",     &key_lookcenter);
 +
 +    M_BindVariable("key_invleft",        &key_invleft);
 +    M_BindVariable("key_invright",       &key_invright);
 +    M_BindVariable("key_useartifact",    &key_useartifact);
 +}
 +
 +void M_BindHexenControls(void)
 +{
 +    M_BindVariable("key_jump",           &key_jump);
 +    M_BindVariable("mouseb_jump",        &mousebjump);
 +    M_BindVariable("joyb_jump",          &joybjump);
 +}
 +
 +void M_BindWeaponControls(void)
 +{
 +    M_BindVariable("key_weapon1",        &key_weapon1);
 +    M_BindVariable("key_weapon2",        &key_weapon2);
 +    M_BindVariable("key_weapon3",        &key_weapon3);
 +    M_BindVariable("key_weapon4",        &key_weapon4);
 +    M_BindVariable("key_weapon5",        &key_weapon5);
 +    M_BindVariable("key_weapon6",        &key_weapon6);
 +    M_BindVariable("key_weapon7",        &key_weapon7);
 +    M_BindVariable("key_weapon8",        &key_weapon8);
 +}
 +
 +void M_BindMapControls(void)
 +{
 +    M_BindVariable("key_map_north",      &key_map_north);
 +    M_BindVariable("key_map_south",      &key_map_south);
 +    M_BindVariable("key_map_east",       &key_map_east);
 +    M_BindVariable("key_map_west",       &key_map_west);
 +    M_BindVariable("key_map_zoomin",     &key_map_zoomin);
 +    M_BindVariable("key_map_zoomout",    &key_map_zoomout);
 +    M_BindVariable("key_map_toggle",     &key_map_toggle);
 +    M_BindVariable("key_map_maxzoom",    &key_map_maxzoom);
 +    M_BindVariable("key_map_follow",     &key_map_follow);
 +    M_BindVariable("key_map_grid",       &key_map_grid);
 +    M_BindVariable("key_map_mark",       &key_map_mark);
 +    M_BindVariable("key_map_clearmark",  &key_map_clearmark);
 +}
 +
 +void M_BindMenuControls(void)
 +{
 +    M_BindVariable("key_menu_activate",  &key_menu_activate);
 +    M_BindVariable("key_menu_up",        &key_menu_up);
 +    M_BindVariable("key_menu_down",      &key_menu_down);
 +    M_BindVariable("key_menu_left",      &key_menu_left);
 +    M_BindVariable("key_menu_right",     &key_menu_right);
 +    M_BindVariable("key_menu_back",      &key_menu_back);
 +    M_BindVariable("key_menu_forward",   &key_menu_forward);
 +    M_BindVariable("key_menu_confirm",   &key_menu_confirm);
 +    M_BindVariable("key_menu_abort",     &key_menu_abort);
 +
 +    M_BindVariable("key_menu_help",      &key_menu_help);
 +    M_BindVariable("key_menu_save",      &key_menu_save);
 +    M_BindVariable("key_menu_load",      &key_menu_load);
 +    M_BindVariable("key_menu_volume",    &key_menu_volume);
 +    M_BindVariable("key_menu_detail",    &key_menu_detail);
 +    M_BindVariable("key_menu_qsave",     &key_menu_qsave);
 +    M_BindVariable("key_menu_endgame",   &key_menu_endgame);
 +    M_BindVariable("key_menu_messages",  &key_menu_messages);
 +    M_BindVariable("key_menu_qload",     &key_menu_qload);
 +    M_BindVariable("key_menu_quit",      &key_menu_quit);
 +    M_BindVariable("key_menu_gamma",     &key_menu_gamma);
 +
 +    M_BindVariable("key_menu_incscreen", &key_menu_incscreen);
 +    M_BindVariable("key_menu_decscreen", &key_menu_decscreen);
 +}
 +
++#ifdef _WIN32_WCE
++
++#define WIN32_LEAN_AND_MEAN
++#include <windows.h>
++
++static int SystemHasKeyboard(void)
++{
++    HKEY key;
++    DWORD valtype;
++    DWORD valsize;
++    DWORD result;
++
++    if (RegOpenKeyExW(HKEY_CURRENT_USER,
++                      L"\\Software\\Microsoft\\Shell", 0,
++                      KEY_READ, &key) != ERROR_SUCCESS)
++    {
++        return 0;
++    }
++
++    valtype = REG_SZ;
++    valsize = sizeof(DWORD);
++
++    if (RegQueryValueExW(key, L"HasKeyboard", NULL, &valtype,
++                         (LPBYTE) &result, &valsize) != ERROR_SUCCESS)
++    {
++        result = 0;
++    }
++
++    // Close the key
++
++    RegCloseKey(key);
++
++    return result;
++}
++
++//
++// Apply custom defaults for Windows CE.
++//
++
++static void M_ApplyWindowsCEDefaults(void)
++{
++    // If the system doesn't have a keyboard, patch the default
++    // configuration to use the hardware keys.
++
++    if (!SystemHasKeyboard())
++    {
++        key_use = KEY_F1;
++        key_fire = KEY_F2;
++        key_menu_activate = KEY_F3;
++        key_map_toggle = KEY_F4;
++
++        key_menu_help = 0;
++        key_menu_save = 0;
++        key_menu_load = 0;
++        key_menu_volume = 0;
++
++        key_menu_confirm = KEY_ENTER;
++        key_menu_back = KEY_F2;
++        key_menu_abort = KEY_F2;
++    }
++}
++
++#endif
++
++//
++// Apply custom patches to the default values depending on the
++// platform we are running on.
++//
++
++void M_ApplyPlatformDefaults(void)
++{
++#ifdef _WIN32_WCE
++    M_ApplyWindowsCEDefaults();
++#endif
++}
++
diff --cc src/m_controls.h
index 5054212e,00000000..2a4aa3df
mode 100644,000000..100644
--- a/src/m_controls.h
+++ b/src/m_controls.h
@@@ -1,148 -1,0 +1,150 @@@
 +// Emacs style mode select   -*- C++ -*-
 +//-----------------------------------------------------------------------------
 +//
 +// Copyright(C) 1993-1996 Id Software, Inc.
 +// Copyright(C) 1993-2008 Raven Software
 +// 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.
 +//
 +//-----------------------------------------------------------------------------
 +
 +#ifndef __M_CONTROLS_H__
 +#define __M_CONTROLS_H__
 +
 +extern int key_right;
 +extern int key_left;
 +
 +extern int key_up;
 +extern int key_down;
 +extern int key_strafeleft;
 +extern int key_straferight;
 +extern int key_fire;
 +extern int key_use;
 +extern int key_strafe;
 +extern int key_speed;
 +
 +extern int key_jump;
 +
 +extern int key_flyup;
 +extern int key_flydown;
 +extern int key_flycenter;
 +extern int key_lookup;
 +extern int key_lookdown;
 +extern int key_lookcenter;
 +extern int key_invleft;
 +extern int key_invright;
 +extern int key_useartifact;
 +
 +extern int key_message_refresh;
 +extern int key_pause;
 +
 +extern int key_weapon1;
 +extern int key_weapon2;
 +extern int key_weapon3;
 +extern int key_weapon4;
 +extern int key_weapon5;
 +extern int key_weapon6;
 +extern int key_weapon7;
 +extern int key_weapon8;
 +
 +extern int key_map_north;
 +extern int key_map_south;
 +extern int key_map_east;
 +extern int key_map_west;
 +extern int key_map_zoomin;
 +extern int key_map_zoomout;
 +extern int key_map_toggle;
 +extern int key_map_maxzoom;
 +extern int key_map_follow;
 +extern int key_map_grid;
 +extern int key_map_mark;
 +extern int key_map_clearmark;
 +
 +extern int key_map_north;
 +extern int key_map_south;
 +extern int key_map_east;
 +extern int key_map_west;
 +extern int key_map_zoomin;
 +extern int key_map_zoomout;
 +extern int key_map_toggle;
 +extern int key_map_maxzoom;
 +extern int key_map_follow;
 +extern int key_map_grid;
 +extern int key_map_mark;
 +extern int key_map_clearmark;
 +
 +// menu keys:
 +
 +extern int key_menu_activate;
 +extern int key_menu_up;
 +extern int key_menu_down;
 +extern int key_menu_left;
 +extern int key_menu_right;
 +extern int key_menu_back;
 +extern int key_menu_forward;
 +extern int key_menu_confirm;
 +extern int key_menu_abort;
 +
 +extern int key_menu_help;
 +extern int key_menu_save;
 +extern int key_menu_load;
 +extern int key_menu_volume;
 +extern int key_menu_detail;
 +extern int key_menu_qsave;
 +extern int key_menu_endgame;
 +extern int key_menu_messages;
 +extern int key_menu_qload;
 +extern int key_menu_quit;
 +extern int key_menu_gamma;
 +
 +extern int key_menu_incscreen;
 +extern int key_menu_decscreen;
 +
 +extern int mousebfire;
 +extern int mousebstrafe;
 +extern int mousebforward;
 +
 +extern int mousebjump;
 +
 +extern int mousebstrafeleft;
 +extern int mousebstraferight;
 +extern int mousebbackward;
 +extern int mousebuse;
 +
 +extern int joybfire;
 +extern int joybstrafe;
 +extern int joybuse;
 +extern int joybspeed;
 +
 +extern int joybjump;
 +
 +extern int joybstrafeleft;
 +extern int joybstraferight;
 +
 +extern int dclick_use;
 +
 +void M_BindBaseControls(void);
 +void M_BindHereticControls(void);
 +void M_BindHexenControls(void);
 +void M_BindWeaponControls(void);
 +void M_BindMapControls(void);
 +void M_BindMenuControls(void);
 +
++void M_ApplyPlatformDefaults(void);
++
 +#endif /* #ifndef __M_CONTROLS_H__ */
 +
diff --cc src/setup/mode.c
index 9d900319,00000000..e300dc9f
mode 100644,000000..100644
--- a/src/setup/mode.c
+++ b/src/setup/mode.c
@@@ -1,309 -1,0 +1,311 @@@
 +// Emacs style mode select   -*- C++ -*-
 +//-----------------------------------------------------------------------------
 +//
 +// Copyright(C) 2006 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.
 +//
 +
 +#include <stdlib.h>
 +#include <string.h>
 +
 +#include "doomtype.h"
 +
 +#include "config.h"
 +#include "textscreen.h"
 +
 +#include "doomtype.h"
 +#include "d_mode.h"
 +#include "d_iwad.h"
 +#include "i_system.h"
 +#include "m_argv.h"
 +#include "m_config.h"
 +#include "m_controls.h"
 +
 +#include "compatibility.h"
 +#include "display.h"
 +#include "joystick.h"
 +#include "keyboard.h"
 +#include "mouse.h"
 +#include "multiplayer.h"
 +#include "sound.h"
 +
 +#include "mode.h"
 +
 +GameMission_t gamemission;
 +static iwad_t **iwads;
 +
 +typedef struct
 +{
 +    char *label;
 +    GameMission_t mission;
 +    int mask;
 +    char *name;
 +    char *config_file;
 +    char *extra_config_file;
 +    char *executable;
 +} mission_config_t;
 +
 +// Default mission to fall back on, if no IWADs are found at all:
 +
 +#define DEFAULT_MISSION (&mission_configs[0])
 +
 +static mission_config_t mission_configs[] =
 +{
 +    {
 +        "Doom",
 +        doom,
 +        IWAD_MASK_DOOM,
 +        "doom",
 +        "default.cfg",
 +        PROGRAM_PREFIX "doom.cfg",
 +        PROGRAM_PREFIX "doom"
 +    },
 +    {
 +        "Heretic",
 +        heretic,
 +        IWAD_MASK_HERETIC,
 +        "heretic",
 +        "heretic.cfg",
 +        PROGRAM_PREFIX "heretic.cfg",
 +        PROGRAM_PREFIX "heretic"
 +    },
 +    {
 +        "Hexen",
 +        hexen,
 +        IWAD_MASK_HEXEN,
 +        "hexen",
 +        "hexen.cfg",
 +        PROGRAM_PREFIX "hexen.cfg",
 +        PROGRAM_PREFIX "hexen"
 +    }
 +};
 +
 +static GameSelectCallback game_selected_callback;
 +
 +// Miscellaneous variables that aren't used in setup.
 +
 +static int showMessages = 1;
 +static int screenblocks = 9;
 +static int detailLevel = 0;
 +static char *savedir = NULL;
 +static char *executable = NULL;
 +
 +static void BindMiscVariables(void)
 +{
 +    M_BindVariable("screenblocks",      &screenblocks);
 +
 +    if (gamemission == doom)
 +    {
 +        M_BindVariable("detaillevel",       &detailLevel);
 +        M_BindVariable("show_messages",     &showMessages);
 +    }
 +
 +    if (gamemission == hexen)
 +    {
 +        M_BindVariable("savedir",           &savedir);
 +        M_BindVariable("messageson",        &showMessages);
 +    }
 +}
 +
 +//
 +// Initialise all configuration file bindings.
 +//
 +
 +void InitBindings(void)
 +{
++    M_ApplyPlatformDefaults();
++
 +    // Keyboard, mouse, joystick controls
 +
 +    M_BindBaseControls();
 +    M_BindWeaponControls();
 +    M_BindMapControls();
 +    M_BindMenuControls();
 +
 +    if (gamemission == heretic || gamemission == hexen)
 +    {
 +        M_BindHereticControls();
 +    }
 +
 +    if (gamemission == hexen)
 +    {
 +        M_BindHexenControls();
 +    }
 +
 +    // All other variables
 +
 +    BindCompatibilityVariables();
 +    BindDisplayVariables();
 +    BindJoystickVariables();
 +    BindKeyboardVariables();
 +    BindMouseVariables();
 +    BindSoundVariables();
 +    BindMiscVariables();
 +    BindMultiplayerVariables();
 +}
 +
 +// Set the name of the executable program to run the game:
 +
 +static void SetExecutable(mission_config_t *config)
 +{
 +    free(executable);
 +
 +#ifdef _WIN32
 +    executable = malloc(strlen(config->executable) + 5);
 +    sprintf(executable, "%s.exe", config->executable);
 +#else
 +    executable = malloc(strlen(INSTALL_DIR) + strlen(config->executable) + 2);
 +    sprintf(executable, "%s%c%s", INSTALL_DIR, DIR_SEPARATOR,
 +                                  config->executable);
 +#endif
 +}
 +
 +static void SetMission(mission_config_t *config)
 +{
 +    iwads = D_FindAllIWADs(config->mask);
 +    gamemission = config->mission;
 +    SetExecutable(config);
 +    M_SetConfigFilenames(config->config_file, config->extra_config_file);
 +}
 +
 +static mission_config_t *GetMissionForName(char *name)
 +{
 +    int i;
 +
 +    for (i=0; i<arrlen(mission_configs); ++i)
 +    {
 +        if (!strcmp(mission_configs[i].name, name))
 +        {
 +            return &mission_configs[i];
 +        }
 +    }
 +
 +    return NULL;
 +}
 +
 +static void GameSelected(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(config))
 +{
 +    TXT_CAST_ARG(mission_config_t, config);
 +
 +    SetMission(config);
 +    game_selected_callback();
 +}
 +
 +static void OpenGameSelectDialog(GameSelectCallback callback)
 +{
 +    mission_config_t *mission = NULL;
 +    txt_window_t *window;
 +    iwad_t **iwads;
 +    int num_games;
 +    int i;
 +
 +    window = TXT_NewWindow("Select game");
 +
 +    TXT_AddWidget(window, TXT_NewLabel("Select a game to configure:\n"));
 +    num_games = 0;
 +
 +    // Add a button for each game.
 +
 +    for (i=0; i<arrlen(mission_configs); ++i)
 +    {
 +        // Do we have any IWADs for this game installed?
 +        // If so, add a button.
 +
 +        iwads = D_FindAllIWADs(mission_configs[i].mask);
 +
 +        if (iwads[0] != NULL)
 +        {
 +            mission = &mission_configs[i];
 +            TXT_AddWidget(window, TXT_NewButton2(mission_configs[i].label,
 +                                                 GameSelected,
 +                                                 &mission_configs[i]));
 +            ++num_games;
 +        }
 +
 +        free(iwads);
 +    }
 +
 +    TXT_AddWidget(window, TXT_NewStrut(0, 1));
 +
 +    // No IWADs found at all?  Fall back to doom, then.
 +
 +    if (num_games == 0)
 +    {
 +        TXT_CloseWindow(window);
 +        SetMission(DEFAULT_MISSION);
 +        callback();
 +        return;
 +    }
 +
 +    // Only one game? Use that game, and don't bother with a dialog.
 +
 +    if (num_games == 1)
 +    {
 +        TXT_CloseWindow(window);
 +        SetMission(mission);
 +        callback();
 +        return;
 +    }
 +
 +    game_selected_callback = callback;
 +}
 +
 +void SetupMission(GameSelectCallback callback)
 +{
 +    mission_config_t *config;
 +    char *mission_name;
 +    int p;
 +
 +    //!
 +    // @arg <game>
 +    //
 +    // Specify the game to configure the settings for.  Valid
 +    // values are 'doom', 'heretic' and 'hexen'.
 +    //
 +
 +    p = M_CheckParm("-game");
 +
 +    if (p > 0)
 +    {
 +        mission_name = myargv[p + 1];
 +
 +        config = GetMissionForName(mission_name);
 +
 +        if (config == NULL)
 +        {
 +            I_Error("Invalid parameter - '%s'", mission_name);
 +        }
 +
 +        SetMission(config);
 +        callback();
 +    }
 +    else
 +    {
 +        OpenGameSelectDialog(callback);
 +    }
 +}
 +
 +char *GetExecutableName(void)
 +{
 +    return executable;
 +}
 +
 +iwad_t **GetIwads(void)
 +{
 +    return iwads;
 +}
 +