// Emacs style mode select   -*- C++ -*- 
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
//	DOOM main program (D_DoomMain) and game loop (D_DoomLoop),
//	plus functions to determine game mode (shareware, registered),
//	parse command line parameters, configure game parameters (turbo),
//	and call the startup functions.
//
//-----------------------------------------------------------------------------


static const char rcsid[] = "$Id: d_main.c,v 1.8 1997/02/03 22:45:09 b1 Exp $";

#define	BGCOLOR		7
#define	FGCOLOR		8


#ifdef NORMALUNIX
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif

#include <direct.h>
#include <malloc.h>
#include <io.h>
#include <fcntl.h>


#include "doomdef.h"
#include "doomstat.h"

#include "dstrings.h"
#include "sounds.h"


#include "z_zone.h"
#include "w_wad.h"
#include "s_sound.h"
#include "v_video.h"

#include "f_finale.h"
#include "f_wipe.h"

#include "m_argv.h"
#include "m_misc.h"
#include "m_menu.h"

#include "i_system.h"
#include "i_sound.h"
#include "i_video.h"

#include "g_game.h"

#include "hu_stuff.h"
#include "wi_stuff.h"
#include "st_stuff.h"
#include "am_map.h"

#include "p_setup.h"
#include "r_local.h"


#include "d_main.h"

//#include "d_console.h"
#include "dconsole.h"  //11.26.98 for compatibility

char MsgText[256];
void WriteDebug(char *);

UINT MCI_FIX_Mididevice;		//9.2.1999 dlw this is a global flagger for fixing midi


extern void dxStartText(char *textline);  //startup graphics
extern int dxStCount;
extern int  usemouse;
extern int	usejoystick;

//
// D-DoomLoop()
// Not a globally visible function,
//  just included for source reference,
//  called by D_DoomMain, never exits.
// Manages timing and IO,
//  calls all ?_Responder, ?_Ticker, and ?_Drawer,
//  calls I_GetTime, I_StartFrame, and I_StartTic
//

//void D_DoomLoop (void); 11.9.98 dlw - clean up opt


char*		wadfiles[MAXWADFILES];


boolean		devparm;	// started game with -devparm
boolean         nomonsters;	// checkparm of -nomonsters
boolean         respawnparm;	// checkparm of -respawn
boolean         fastparm;	// checkparm of -fast

boolean         drone;

boolean		singletics = false; // debug flag to cancel adaptiveness

extern boolean plutonia, tnt;

//extern int soundVolume;
//extern  int	sfxVolume;
//extern  int	musicVolume;

extern boolean	inhelpscreens;
extern boolean	helpfromkey; //10.14.98 workaround for shareware help
extern int GameMode;

skill_t		startskill;
int             startepisode;
int		startmap;
boolean		autostart;

FILE*		debugfile;

boolean		advancedemo;




char		wadfile[1024];		// primary wad file
char		mapdir[1024];           // directory of development maps
char		basedefault[1024];      // default file


void D_CheckNetGame (void);
void D_ProcessEvents (void);
void G_BuildTiccmd (ticcmd_t* cmd);
void D_DoAdvanceDemo (void);

void RenderScene(void);

//
// EVENT HANDLING
//
// Events are asynchronous inputs generally generated by the game user.
// Events can be discarded if no responder claims them
//
event_t         events[MAXEVENTS];
int             eventhead;
int             eventtail;

//
// D_PostEvent
// Called by the I/O functions when input is detected
//
void D_PostEvent(event_t* ev)
{
    events[eventhead] = *ev;
    eventhead = (++eventhead)&(MAXEVENTS-1);
}


//
// D_ProcessEvents
// Send all the events of the given timestamp down the responder chain
//

void D_ProcessEvents(void)
{
    event_t*	ev;
    // IF STORE DEMO, DO NOT ACCEPT INPUT
    if (( gamemode == commercial ) && (W_CheckNumForName("map01")<0))
        return;
	
    for (; eventtail != eventhead; eventtail = (++eventtail)&(MAXEVENTS-1))
	{
        ev = &events[eventtail];
        if(CO_Responder(ev)) continue; // console ate the event
        if(M_Responder(ev))  continue; // menu ate the event
        G_Responder(ev);
	}
}




//
// D_Display
//  draw current display, possibly wiping it from the previous
//

// wipegamestate can be set to -1 to force a wipe on the next draw
gamestate_t     wipegamestate = GS_DEMOSCREEN;
extern  boolean setsizeneeded;
extern  int             showMessages;
void R_ExecuteSetViewSize (void);


// 11.4.98 dlw: I've been optimizing and this thing is a mess.
// There's just too much redundant checking throughout
// There'd be a meg of comments if I noted every little fix
// so it's pretty much gonna be: orinal code pushed down...
// new fast code up top.
void D_Display(void)
{
    static  boolean		viewactivestate = false;
    static  boolean		menuactivestate = false;
    static  boolean		inhelpscreensstate = false;
    static  boolean		fullscreen = false;
    static  gamestate_t		oldgamestate = -1;
    static  int			borderdrawcount;
    int				nowtime;
    int				tics;
    int				wipestart;
    int				y;
    boolean			done;
    boolean			wipe;
    boolean			redrawsbar;

    //if (nodrawers) return; // for comparative timing / profiling
		
    redrawsbar = false;
    
    // change the view size if needed
    if(setsizeneeded)
	{
        //WriteDebug("setsizeneeded...\n");
        R_ExecuteSetViewSize();
        oldgamestate = -1;     // force background redraw
        //borderdrawcount = 3;	//11.4.98 why 3 times? dlw
		borderdrawcount = 1;
	}

    // save the current screen if about to wipe
    if (gamestate != wipegamestate)
	{
        //WriteDebug("wipe_StartScreen...\n");
        wipe = true;
        // wipe_StartScreen(0, 0, SCREENWIDTH, SCREENHEIGHT);
		wipe_StartScreen();  //11.4.98 dlw optimized version
	}
    else
	{
		wipe = false;
		//WriteDebug("wipe=false\n");
	}

    
	//11.4.98 does this need doing at all? dlw
	//11.4.98 NO.  screen is erased anyway
	//if (gamestate == GS_LEVEL && gametic)
	//{
        //WriteDebug("HU_Erase...\n");
		//11.4.98 does this need doing at all?
        //HU_Erase();
	//}
    
    // do buffered drawing
    switch (gamestate)
	{
	case GS_LEVEL:
		//WriteDebug("GS_LEVEL - 1...\n");
		if(!gametic) break;
		//WriteDebug("GS_LEVEL - 2...\n");
		if(automapactive) AM_Drawer();
		//WriteDebug("GS_LEVEL - 3...\n");
		if (wipe || (viewheight != SCREENHEIGHT && fullscreen) )
			redrawsbar = true;
		if(inhelpscreensstate && !inhelpscreens)
		{
			redrawsbar = true;  // just put away the help screen
			if(DOUBLESTUFF) // 10.13.98 hi-res leaving help and map at edges
				R_DrawViewBorder();
		}
		//WriteDebug("GS_LEVEL - 4...\n");
		ST_Drawer(viewheight == SCREENHEIGHT, redrawsbar );
		//WriteDebug("GS_LEVEL - 5...\n");
		fullscreen = viewheight == SCREENHEIGHT;
		break;
	case GS_INTERMISSION:
		WI_Drawer();
		break;
    case GS_FINALE:
		F_Drawer();
		break;
	case GS_DEMOSCREEN:
		D_PageDrawer();
		break;
	}
    
	// draw the view directly 11.4.98 Optimized
	// and while yer laffing at me for picking C nits in here...
	// these changes made this thing go from 24FPS to 28/29
	if(gamestate == GS_LEVEL)
	{
		if(gametic)
		{
			if(!automapactive) R_RenderPlayerView(&players[displayplayer]);
			HU_Drawer();
		}
		if(oldgamestate != GS_LEVEL)  //11.4.98 redundant see below
		{
			viewactivestate = false;        // view was not active
			R_FillBackScreen();    // draw the pattern into the back screen
		}
		// see if the border needs to be updated to the screen
		if(!automapactive && scaledviewwidth != SCREENWIDTH && viewheight != SCREENHEIGHT)
		{
			if (menuactive || menuactivestate || !viewactivestate)
				borderdrawcount = 1;
			if (borderdrawcount)
			{
				R_DrawViewBorder();    // erase old menu stuff
				borderdrawcount--;
			}
		}
	}
	else // gamestate!=GSLEVEL  11.5.98 optimize
	{
		// clean up border stuff
		if(gamestate != oldgamestate)
			I_SetPalette(W_CacheLumpName("PLAYPAL",PU_CACHE));
	}
    // clean up border stuff  11.5.98 optimized
    //if (gamestate != oldgamestate && gamestate != GS_LEVEL)
	//{
    //    I_SetPalette(W_CacheLumpName("PLAYPAL",PU_CACHE));
	//}

    // draw buffered stuff to screen
    // I_UpdateNoBlit();  10.19.98 dlw unused (dead loop)
    
	// 11.4.98 dlw Optimize: original code redundant checking
	//	gamestate==GSLEVEL && gametic.  Fixed up so only test
	//	once
	// draw the view directly
    //if (gamestate == GS_LEVEL && !automapactive && gametic)
	//{
        //WriteDebug("R_RenderPlayerView...\n");
    //    R_RenderPlayerView(&players[displayplayer]);
	//}
    //if (gamestate == GS_LEVEL && gametic)
	//{
    //    HU_Drawer();
	//}

	// 11.4.98 optimizer -> up in the GSLEVEL stuff above
	// see if the border needs to be initially drawn
    //if (gamestate == GS_LEVEL && oldgamestate != GS_LEVEL)
	//{
    //    viewactivestate = false;        // view was not active
    //    R_FillBackScreen();    // draw the pattern into the back screen
	//}

    // see if the border needs to be updated to the screen
    //if (gamestate == GS_LEVEL && !automapactive && scaledviewwidth != SCREENWIDTH && viewheight != SCREENHEIGHT)
	//{
    //    if (menuactive || menuactivestate || !viewactivestate)
    //        borderdrawcount = 3;
    //    if (borderdrawcount)
	//	{
    //        R_DrawViewBorder();    // erase old menu stuff
    //        borderdrawcount--;
	//	}
	//}

    menuactivestate = menuactive;
    viewactivestate = viewactive;
    inhelpscreensstate = inhelpscreens;
    oldgamestate = wipegamestate = gamestate;
    
    // draw pause pic
    if(paused)
	{
        if (automapactive)
            y = 4;
        else
            y = viewwindowy+4;
        //V_DrawPatchDirect(viewwindowx+(scaledviewwidth-68)/2,y,0,W_CacheLumpName ("M_PAUSE", PU_CACHE));
		V_DrawPatch(viewwindowx+(scaledviewwidth-68)/2,y,0,W_CacheLumpName ("M_PAUSE", PU_CACHE));
	}

    // menus go directly to the screen
    M_Drawer();          // menu is drawn even on top of everything
    CO_Drawer();         // Console is drawn on top of even the menu...
    
	if(!internetgame)  //11.12.98 dlw less x-mit for internet
		NetUpdate(); // send out any new accumulation

    // normal update  -- 11.4.98 since -devparm doesn't do anything
	//		but draw dots--hell with it  OPTIMIZE
    if (!wipe)
	{
        //I_FinishUpdate();              // page flip or blit buffer
		RenderScene();
        return;
	}
    
    // wipe update -- 11.4.98 optimized version
    // wipe_EndScreen(0, 0, SCREENWIDTH, SCREENHEIGHT);
	wipe_EndScreen();

    wipestart = I_GetTime () - 1;
    do
	{
        do
		{
            nowtime = I_GetTime();
            tics = nowtime - wipestart;
		}while(!tics);
        wipestart = nowtime;
        done = wipe_ScreenWipe(wipe_Melt, 0, 0, SCREENWIDTH, SCREENHEIGHT, tics);
        // 11.4.98 Unused -- I_UpdateNoBlit ();
        M_Drawer();   // menu is drawn even on top of wipes
        CO_Drawer();  // Console is drawn on top of even the menu...
        //	I_FinishUpdate (); //11.4.98 no dots
        RenderScene();	// page flip or blit buffer
	}while(!done);
}



//
//  D_DoomLoop
//
extern  int             demotype;
extern  boolean         demorecording;

/*void D_DoomLoop(void)  11.8.98 dlw clean up opt (My_DoomLoop) 
{
    if (demorecording) G_BeginRecording();
    if (M_CheckParm ("-debugfile"))
	{
        char    filename[20];
        sprintf (filename,"debug%i.txt",consoleplayer);
	    //printf ("debug output to: %s\n",filename);
        sprintf(MsgText, "debug output to: %s\n",filename);
        WriteDebug(MsgText);
        debugfile = fopen (filename,"w");
	}
    I_InitGraphics();
    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();
            M_Ticker ();
            G_Ticker ();
            gametic++;
            maketic++;
		}
        else
		{
            TryRunTics (); // will run at least one tic
		}
		
        S_UpdateSounds (players[consoleplayer].mo);// move positional sounds

        // Update display, next frame, with current state.
        D_Display();

//#ifndef SNDSERV
        // Sound mixing for the buffer is snychronous.
        //I_UpdateSound();
//#endif	
        // Synchronous sound output is explicitly called.
//#ifndef SNDINTR
        // Update sound output.
        //I_SubmitSound();
//#endif
       }
} */

void MY_DoomSetup(void)
{
    if (demorecording)
        G_BeginRecording();
		
    //WriteDebug("MY_DoomSetup...\n");
    if(M_CheckParm ("-debugfile"))
	{
        char    filename[20];
        sprintf (filename,"debug%i.txt",consoleplayer);
		//printf ("debug output to: %s\n",filename);
        sprintf(MsgText, "debug output to: %s\n",filename);
        WriteDebug(MsgText);
        debugfile = fopen (filename,"w");
	}
	if(gamemode != indetermined) //11.9.98 bug catcher
		I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
}

void MY_DoomLoop(void)
{
    //WriteDebug("MY_DoomLoop...\n");
    // frame syncronous IO operations
    // UNUSED:   I_StartFrame();

	// process one or more tics
    if(singletics)
	{
        //WriteDebug("singletics...\n");
		//WriteDebug("I_StartTic...\n");
        // 11.4.98 dlw UNUSED EMPTY:	I_StartTic();
        //WriteDebug("D_ProcessEvents...\n");
        D_ProcessEvents();
        //WriteDebug("MY_DoomLoop calling G_BuildTiccmd...\n");
        G_BuildTiccmd(&netcmds[consoleplayer][maketic%BACKUPTICS]);
        if(advancedemo)
		{
            //WriteDebug("D_DoAdvanceDemo...\n");
            D_DoAdvanceDemo();
		}
        CO_Ticker();
        //WriteDebug("M_Ticker...\n");
        M_Ticker();
        //WriteDebug("G_Ticker...\n");
        G_Ticker();
        gametic++;
        maketic++;
	}
    else
	{
        //WriteDebug("TryRunTics...\n");
        TryRunTics(); // will run at least one tic
	}

	//WriteDebug("S_UpdateSounds...\n");
    S_UpdateSounds(players[consoleplayer].mo);// move positional sounds

    // Update display, next frame, with current state.
    //WriteDebug("D_Display...\n");
    D_Display();

	
//#ifndef SNDSERV
    // Sound mixing for the buffer is snychronous.
    //I_UpdateSound();
//#endif	
    // Synchronous sound output is explicitly called.
//#ifndef SNDINTR
    // Update sound output.
    //I_SubmitSound();
//#endif
}



//
//  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
//
void D_PageDrawer (void)
{
    int i;
    __int64 *d;

    d = (__int64 *)screens[0];
    for (i = 0; i < (SCREENMULT/8); i++)
       d[i] = 0;

    
	//10.13.98-- big demo/menu screens for double mode 640x400
	//	updated once more for the way up modes, since center code same
	if( DOUBLESTUFF )
		V_DrawPatchDouble( ((SCREENWIDTH-640)/2),((SCREENHEIGHT-400)/2),0, W_CacheLumpName(pagename, PU_CACHE));
	else  // or any other screen size
		V_DrawPatch(((SCREENWIDTH-320)/2),((SCREENHEIGHT-200)/2), 0, W_CacheLumpName(pagename, PU_CACHE));
}


//
// D_AdvanceDemo
// Called after each demo or intro demosequence finishes
//
void D_AdvanceDemo (void)
{
    advancedemo = true;
}


//
// This cycles through the demo sequences.
// FIXME - version dependend demo numbers?
//
void D_DoAdvanceDemo(void)
{
	players[consoleplayer].playerstate = PST_LIVE;  // not reborn
	advancedemo = false;
	usergame = false;               // no save / end game here
	paused = false;
	gameaction = ga_nothing;
	
	if ( gamemode == retail )
		demosequence = (demosequence+1)%7;
	else
		demosequence = (demosequence+1)%6;
	//sprintf(MsgText, "Changing screen to %d...\n", demosequence);
	//WriteDebug(MsgText);

	switch (demosequence)
	{
	case 0:
		if ( gamemode == commercial )
			pagetic = 35 * 11;
		else
			pagetic = 170;
		gamestate = GS_DEMOSCREEN;
		pagename = "TITLEPIC";
		if ( gamemode == commercial )
			S_StartMusic(mus_dm2ttl);
		else
			S_StartMusic (mus_intro);
		break;
	case 1:
		G_DeferedPlayDemo ("demo1");
		break;
	case 2:
		pagetic = 200;
		gamestate = GS_DEMOSCREEN;
		pagename = "CREDIT";
		break;
	case 3:
		G_DeferedPlayDemo ("demo2");
		break;
	case 4:
		gamestate = GS_DEMOSCREEN;
		if ( gamemode == commercial)
		{
			pagetic = 35 * 11;
			pagename = "TITLEPIC";
			S_StartMusic(mus_dm2ttl);
		}
		else
		{
			pagetic = 200;
			if ( gamemode == retail )
				pagename = "CREDIT";
			else
				pagename = "HELP2";
		}
		break;
	case 5:
		G_DeferedPlayDemo ("demo3");
		break;
    // THE DEFINITIVE DOOM Special Edition demo
	case 6:
		G_DeferedPlayDemo ("demo4");
		break;
	}
}



//
// D_StartTitle
//
void D_StartTitle (void)
{
    gameaction = ga_nothing;
    demosequence = -1;
    D_AdvanceDemo();
}




//      print title for every printed line
char            title[128];



//
// D_AddFile
//
void D_AddFile (char *file)
{
    int     numwadfiles;
    char    *newfile;
	
    for (numwadfiles = 0 ; wadfiles[numwadfiles] ; numwadfiles++)
	;

    newfile = malloc (strlen(file)+1);
    strcpy (newfile, file);
	
    wadfiles[numwadfiles] = newfile;
}

#define R_OK 4
//
// IdentifyVersion
// Checks availability of IWAD files by name,
// to determine whether registered/commercial features
// should be executed (notably loading PWAD's).
//
void IdentifyVersion(void)
{

    char*	doom1wad;
    char*	doomwad;
    char*	doomuwad;
    char*	doom2wad;

    char*	doom2fwad;
    char*	plutoniawad;
    char*	tntwad;

//#ifdef NORMALUNIX
//    char *home;
    char *doomwaddir;
    doomwaddir = getenv("DOOMWADDIR");
    if (!doomwaddir) doomwaddir = ".";

    // Commercial.
    doom2wad = malloc(strlen(doomwaddir)+1+9+1);
    sprintf(doom2wad, "%s/doom2.wad", doomwaddir);

    // Retail.   // Bug here too...
    doomuwad = malloc(strlen(doomwaddir)+1+9+1);
    sprintf(doomuwad, "%s/doomu.wad", doomwaddir);
    
    // Registered.
    doomwad = malloc(strlen(doomwaddir)+1+8+1);
    sprintf(doomwad, "%s/doom.wad", doomwaddir);
    
    // Shareware.
    doom1wad = malloc(strlen(doomwaddir)+1+9+1);
    sprintf(doom1wad, "%s/doom1.wad", doomwaddir);

     // Bug, dear Shawn.
    // Insufficient malloc, caused spurious realloc errors.
    plutoniawad = malloc(strlen(doomwaddir)+1+/*9*/12+1);
    sprintf(plutoniawad, "%s/plutonia.wad", doomwaddir);

    tntwad = malloc(strlen(doomwaddir)+1+9+1);
    sprintf(tntwad, "%s/tnt.wad", doomwaddir);

    // French stuff.
    doom2fwad = malloc(strlen(doomwaddir)+1+10+1);
    sprintf(doom2fwad, "%s/doom2f.wad", doomwaddir);


/*  Don't HAVE home directory on a single user OS...
    home = getenv("HOME");
    if (!home)
      I_Error("Please set $HOME to your home directory");

    sprintf(basedefault, "%s/.doomrc", home);

#endif
*/

    if (M_CheckParm ("-shdev"))
    {
	gamemode = shareware;
	devparm = true;
	D_AddFile (DEVDATA"doom1.wad");
	D_AddFile (DEVMAPS"data_se/texture1.lmp");
	D_AddFile (DEVMAPS"data_se/pnames.lmp");
	strcpy (basedefault,DEVDATA"default.cfg");
	return;
    }

    if (M_CheckParm ("-regdev"))
    {
	gamemode = registered;
	devparm = true;
	D_AddFile (DEVDATA"doom.wad");
	D_AddFile (DEVMAPS"data_se/texture1.lmp");
	D_AddFile (DEVMAPS"data_se/texture2.lmp");
	D_AddFile (DEVMAPS"data_se/pnames.lmp");
	strcpy (basedefault,DEVDATA"default.cfg");
	return;
    }

    if (M_CheckParm ("-comdev"))
    {
	gamemode = commercial;
	devparm = true;
/*
	if(plutonia)
	    D_AddFile (DEVDATA"plutonia.wad");
	else if(tnt)
	    D_AddFile (DEVDATA"tnt.wad");
	else*/
	    D_AddFile (DEVDATA"doom2.wad");
	    
	D_AddFile (DEVMAPS"cdata/texture1.lmp");
	D_AddFile (DEVMAPS"cdata/pnames.lmp");
	strcpy (basedefault,DEVDATA"default.cfg");
	return;
    }

    if( !access(doom2fwad,R_OK) )
    {
		gamemode = commercial;
		// C'est ridicule!
		// Let's handle languages in config files, okay?
		language = french;
		//printf("French version\n");
		WriteDebug("French version?\n");
		++dxStCount;
		dxStartText("French version?");  //10.20.98 dlw
		D_AddFile(doom2fwad);
		return;
    }
    if( !access(doom2wad,R_OK) )
    {
		gamemode = commercial;
		D_AddFile(doom2wad);
		return;
    }

    if( !access(plutoniawad, R_OK ) )
    {
		gamemode = commercial;
		plutonia = TRUE;
		tnt = FALSE;
		D_AddFile (plutoniawad);
		return;
    }

    if( !access( tntwad, R_OK ) )
    {
		gamemode = commercial;
		tnt = TRUE;
		plutonia = FALSE;
		D_AddFile(tntwad);
		return;
    }

    if( !access(doomuwad,R_OK) )
	{
        gamemode = retail;
        D_AddFile(doomuwad);
        return;
	}

    if( !access(doomwad,R_OK) )
	{
        gamemode = registered;
        D_AddFile (doomwad);
        return;
	}

    if( !access(doom1wad,R_OK) )
    {
		gamemode = shareware;
		D_AddFile (doom1wad);
		return;
    }

    //printf("Game mode indeterminate.\n");
    WriteDebug("Game mode indeterminate.\n");
	dxStCount++;
	dxStartText("Game mode indeterminate.");  //10.20.98 dlw

    gamemode = indetermined;

    // We don't abort. Let's see what the PWAD contains.
    //exit(1);
    //I_Error("Game mode indeterminate\n");
	//11.9.98 dlw bug-fix
	I_Error("No wad file in installation directory.\n");
}

//
// Find a Response File
//
void FindResponseFile (void)
{
    int             i;
#define MAXARGVS        100
	
    for (i = 1;i < myargc;i++)
	if (myargv[i][0] == '@')
	{
	    FILE *          handle;
	    int             size;
	    int             k;
	    int             index;
	    int             indexinfile;
	    char    *infile;
	    char    *file;
	    char    *moreargs[20];
	    char    *firstargv;
			
	    // READ THE RESPONSE FILE INTO MEMORY
	    handle = fopen (&myargv[i][1],"rb");
	    if (!handle)
	    {
		printf ("\nNo such response file!");
		exit(1);
	    }
	    printf("Found response file %s!\n",&myargv[i][1]);
	    fseek (handle,0,SEEK_END);
	    size = ftell(handle);
	    fseek (handle,0,SEEK_SET);
	    file = malloc (size);
	    fread (file,size,1,handle);
	    fclose (handle);
			
	    // KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG
	    for (index = 0,k = i+1; k < myargc; k++)
		moreargs[index++] = myargv[k];
			
	    firstargv = myargv[0];
	    myargv = malloc(sizeof(char *)*MAXARGVS);
	    memset(myargv,0,sizeof(char *)*MAXARGVS);
	    myargv[0] = firstargv;
			
	    infile = file;
	    indexinfile = k = 0;
	    indexinfile++;  // SKIP PAST ARGV[0] (KEEP IT)
	    do
	    {
		myargv[indexinfile++] = infile+k;
		while(k < size &&
		      ((*(infile+k)>= ' '+1) && (*(infile+k)<='z')))
		    k++;
		*(infile+k) = 0;
		while(k < size &&
		      ((*(infile+k)<= ' ') || (*(infile+k)>'z')))
		    k++;
	    } while(k < size);
			
	    for (k = 0;k < index;k++)
		myargv[indexinfile++] = moreargs[k];
	    myargc = indexinfile;
	
	    // DISPLAY ARGS
	    printf("%d command-line args:\n",myargc);
	    for (k=1;k<myargc;k++)
		printf("%s\n",myargv[k]);

	    break;
	}
}


//
// D_DoomMain
//
void D_DoomMain(void)
{
    int		p;
    char	file[256];

    //FindResponseFile();

    IdentifyVersion();
    if(gamemode == indetermined) return; //11.9.98 bugcatcher dlw

    setbuf(stdout, NULL);
    modifiedgame = false;

    nomonsters = M_CheckParm ("-nomonsters");
    respawnparm = M_CheckParm ("-respawn");
    fastparm = M_CheckParm ("-fast");
    devparm = M_CheckParm ("-devparm");
    if (M_CheckParm ("-altdeath"))
		deathmatch = 2;
    else if (M_CheckParm ("-deathmatch"))
		deathmatch = 1;

    if (devparm)
	{
		WriteDebug(D_DEVSTR);
		WriteDebug("\n");
		//	printf(D_DEVSTR);
		dxStCount++;
		dxStartText(D_DEVSTR);
	}
    
    if (M_CheckParm("-cdrom"))
    {
		WriteDebug(D_CDROM);
		WriteDebug("\n");
		dxStCount++;
		dxStartText(D_CDROM); //10.20.98 dlw

		//printf(D_CDROM);
		//mkdir("c:\\doomdata",0); // What's the ",0" for? Oh yeah, permissions...
		mkdir("c:\\doomdata");
		strcpy (basedefault,"c:/doomdata/default.cfg");
    }	
    
    // turbo option
    if ( (p=M_CheckParm ("-turbo")) )
    {
		int     scale = 200;
		extern int forwardmove[2];
		extern int sidemove[2];
		if (p<myargc-1)
			scale = atoi (myargv[p+1]);
		if (scale < 10)
			scale = 10;
		if (scale > 400)
			scale = 400;
		//printf ("turbo scale: %i%%\n",scale);
		forwardmove[0] = forwardmove[0]*scale/100;
		forwardmove[1] = forwardmove[1]*scale/100;
		sidemove[0] = sidemove[0]*scale/100;
		sidemove[1] = sidemove[1]*scale/100;
    }
    
    // add any files specified on the command line with -file wadfile
    // to the wad list
    //
    // convenience hack to allow -wart e m to add a wad file
    // prepend a tilde to the filename so wadfile will be reloadable
    p = M_CheckParm ("-wart");
    if (p)
    {
		myargv[p][4] = 'p';     // big hack, change to -warp

		// Map name handling.
		switch (gamemode)
		{
		case shareware:
		case retail:
		case registered:
			sprintf (file,"~"DEVMAPS"E%cM%c.wad", myargv[p+1][0], myargv[p+2][0]);
			//	    printf("Warping to Episode %s, Map %s.\n",
			//		   myargv[p+1],myargv[p+2]);
			sprintf(MsgText, "Warping to Episode %s, Map %s.",
				myargv[p+1],myargv[p+2]);
			WriteDebug(MsgText);
			WriteDebug("\n");
			dxStCount++;
			dxStartText(MsgText); //10.20.98 dlw
			break;
		case commercial:
		default:
			p = atoi (myargv[p+1]);
			if (p<10)
				sprintf (file,"~"DEVMAPS"cdata/map0%i.wad", p);
			else
				sprintf (file,"~"DEVMAPS"cdata/map%i.wad", p);
			break;
		}
		D_AddFile(file);
    }
	
    p = M_CheckParm ("-file");
    if(p)
    {
		// the parms after p are wadfile/lump names,
		// until end of parms or another - preceded parm
		modifiedgame = true;            // homebrew levels
		while (++p != myargc && myargv[p][0] != '-')
		{
			//score keeping has to have a way to know if user wads
			strncpy(scoreuserwad, myargv[p], strlen(myargv[p]));
			D_AddFile(myargv[p]);
		}
    }

    p = M_CheckParm ("-playdemo");
    if(!p)
	{
		p = M_CheckParm ("-playdemo2");
		demotype = DEMO_II;
	}
    else
	{
        demotype = DEMO_I;
	}
    if(!p)
	{
		p = M_CheckParm ("-timedemo");
        demotype = DEMO_I;
	}
    if (!p)
	{
		p = M_CheckParm ("-timedemo2");
        demotype = DEMO_II;
	}
    if (p && p < myargc-1)
	{
        if (demotype == DEMO_I)
		{
			sprintf (file,"%s.lmp", myargv[p+1]);
			D_AddFile(file);
			//printf("Playing demo %s.lmp.\n",myargv[p+1]);
			sprintf(MsgText, "Playing demo %s.lmp.",myargv[p+1]);
            WriteDebug(MsgText);
			WriteDebug("\n");
			dxStCount++;
			dxStartText(MsgText); //10.20.98 dlw
		}
        else
		{
			sprintf(MsgText, "Playing demo II %s.dem.",myargv[p+1]);
            WriteDebug(MsgText);
			WriteDebug("\n");
			dxStCount++;
			dxStartText(MsgText); //10.20.98 dlw
		}
	}    
    // get skill / episode / map from parms
    startskill = sk_medium;
    startepisode = 1;
    startmap = 1;
    autostart = false;

		
    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 ("-timer");
    if (p && p < myargc-1 && deathmatch)
    {
		int     time;
		time = atoi(myargv[p+1]);
		// Change over to buffered output...
		//printf("Levels will end after %d minute",time);
		sprintf(MsgText, "Levels will end after %d minute",time);
		if (time>1)
			strcat(MsgText, "s");
		//printf("s");
		strcat(MsgText, ".");
		//printf(".\n");
		WriteDebug(MsgText);
			WriteDebug("\n");
			dxStCount++;
			dxStartText(MsgText); //10.20.98 dlw

    }

    p = M_CheckParm ("-avg");
    if (p && p < myargc-1 && deathmatch)
	{
		WriteDebug("Austin Virtual Gaming: Levels will end after 20 minutes\n");
		dxStCount++;
		dxStartText("Austin Virtual Gaming: Levels will end after 20 minutes."); //10.20.98 dlw
	}


    p = M_CheckParm ("-warp");
    if (p && p < myargc-1)
    {
		if (gamemode == commercial) startmap = atoi (myargv[p+1]);
	else
	{
		startepisode = myargv[p+1][0]-'0';
		startmap = myargv[p+2][0]-'0';
	}
	autostart = true;
    }

	//10.15.98 dlw Score keeping command lines now added
	keepscore=0;
	showscoreHUD=0;
	keepscore = M_CheckParm("-keepscore");

	//10.15.98 dlw Score showing adds keeping by default
	p = M_CheckParm("-showscore");
	if(p)
	{
		showscoreHUD=1;
		keepscore=1;
	}

	//9.2.1999 dlw forced midi for playing back accurately
	MCI_FIX_Mididevice = (UINT)9999;
	p = M_CheckParm("-mididev");
    if (p && p < myargc-1)
    {
		MCI_FIX_Mididevice = atoi(myargv[p+1]);
		//WriteDebug("------>>>>>>>>>>>>>> MCI FIX <<<<<<<<<<<<<<\n");
	}



    // init subsystems
    //printf ("V_Init: allocate screens.\n");
    WriteDebug("V_Init: allocate screens.\n");
	dxStCount++;
	dxStartText("V_Init: allocate screens."); //10.20.98 dlw
    V_Init();

    //printf ("M_LoadDefaults: Load system defaults.\n");
    WriteDebug("M_LoadDefaults: Load system defaults.\n");
	dxStCount++;
	dxStartText("M_LoadDefaults: Load system defaults."); //10.20.98 dlw
    M_LoadDefaults();        // load before initing other systems

	//11.8.98 now fix the input for command line
	p = M_CheckParm("-nomouse");
	if(p) usemouse=0;
	p = M_CheckParm("-joystick");
	if(p) usejoystick=1;


    //printf ("Z_Init: Init zone memory allocation daemon. \n");
    WriteDebug("Z_Init: Init zone memory allocation daemon. \n");
	dxStCount++;
	dxStartText("Z_Init: Init zone memory allocation daemon."); //10.20.98 dlw
    Z_Init();

    //printf ("W_Init: Init WADfiles.\n");
    WriteDebug("W_Init: Init WADfiles.\n");
	dxStCount++;
	dxStartText("W_Init: Init WADfiles."); //10.20.98 dlw
    W_InitMultipleFiles(wadfiles);
    
    if ((gamemode == retail) || (gamemode == registered))
	{
        char name[10][8] = { "e4m1","e4m2","e4m3","e4m4","e4m5","e4m6","e4m7","e4m8","e4m9", "m_epi4" };
        int i;
        
		WriteDebug("Checking for Ultimate Doom...\n");
		dxStCount++;
		dxStartText("Checking for Ultimate Doom..."); //10.20.98 dlw
        gamemode = retail;
        for (i = 0;i < 10; i++)
		{
            if (W_CheckNumForName(name[i]) < 0)
			{
                gamemode = registered;
                break;
			}
		}
        if (gamemode == registered)
		{
            WriteDebug("Normal Doom WAD file...\n");
			dxStCount++;
			dxStartText("Normal Doom WAD file..."); //10.20.98 dlw
		}
        else
		{
            WriteDebug("Ultimate Doom WAD - fourth episode enabled...\n");
			dxStCount++;
			dxStartText("Ultimate Doom WAD - fourth episode enabled..."); //10.20.98 dlw
		}
	}

    switch ( gamemode )
    {
	case retail:
		sprintf (title,
		 "                         "
		 "The Ultimate DOOM Startup v%i.%i"
		 "                           ",
		 VERSION/100,VERSION%100);
		break;
	case shareware:
		sprintf (title,
		 "                            "
		 "DOOM Shareware Startup v%i.%i"
		 "                           ",
		 VERSION/100,VERSION%100);
		break;
	case registered:
		sprintf (title,
		 "                            "
		 "DOOM Registered Startup v%i.%i"
		 "                           ",
		 VERSION/100,VERSION%100);
		break;
	case commercial:
		if (plutonia == TRUE)
			sprintf (title, "                   DOOM 2: Plutonia Experiment v%i.%i                        ", VERSION/100,VERSION%100);
		else
			if (tnt == TRUE)
				sprintf (title, "                     DOOM 2: TNT - Evilution v%i.%i                          ", VERSION/100,VERSION%100);
			else
				sprintf (title, "                      DOOM 2: Hell on Earth v%i.%i                           ", VERSION/100,VERSION%100);
		break;
	default:
		sprintf (title,
		 "                     "
		 "Public DOOM - v%i.%i"
		 "                           ",
		 VERSION/100,VERSION%100);
		break;
    }
    
    //printf ("%s\n",title);
    WriteDebug(title);
    WriteDebug("\n");
	dxStCount++;
	dxStartText(title); //10.20.98 dlw

    // Check for -file in shareware
    if (modifiedgame)
    {
	// These are the lumps that will be checked in IWAD,
	// if any one is not present, execution will be aborted.
	char name[23][8]=
	{
	    "e2m1","e2m2","e2m3","e2m4","e2m5","e2m6","e2m7","e2m8","e2m9",
	    "e3m1","e3m3","e3m3","e3m4","e3m5","e3m6","e3m7","e3m8","e3m9",
	    "dphoof","bfgga0","heada1","cybra1","spida1d1"
	};
	int i;
	
	if ( gamemode == shareware)
	    I_Error("\nYou cannot -file with the shareware "
		    "version. Register!");

	// Check for fake IWAD with right name,
	// but w/o all the lumps of the registered version. 
	if (gamemode == registered)
	    for (i = 0;i < 23; i++)
		if (W_CheckNumForName(name[i])<0)
		    I_Error("\nThis is not the registered version.");
    }
    
    // If additonal PWAD files are used, print modified banner
    if (modifiedgame)
    {
	 //printf (
	    WriteDebug("===========================================================================\n");
	    WriteDebug("ATTENTION:  This version of DOOM has been modified.  If you would like to\n");
	    WriteDebug("get a copy of the original game, call 1-800-IDGAMES or see the readme file.\n");
	    WriteDebug("        You will not receive technical support for modified games.\n");
	    //WriteDebug("                      press enter to continue\n");
	    WriteDebug("===========================================================================\n");
	//    );
	//getchar ();
		//added treasures 10.20.98 dlw... y did I do this to me?
		++dxStCount;
	    dxStartText("ATTENTION:This version of DOOM has been modified.");
    }
	

    // Check and print which version is executed.
    switch ( gamemode )
    {
      case shareware:
      case indetermined:
		//printf (
	    WriteDebug("===========================================================================\n");
	    WriteDebug("                                Shareware!\n");
	    WriteDebug("===========================================================================\n");

	    dxStCount++;
	    dxStartText("        Shareware!");
		//);
		break;
      case registered:
      case retail:
      case commercial:
	//printf (
	    WriteDebug("===========================================================================\n");
	    WriteDebug("                 Commercial product - do not distribute!\n");
	    WriteDebug("         Please report software piracy to the SPA: 1-800-388-PIR8\n");
	    WriteDebug("===========================================================================\n");

	    dxStCount++;
	    dxStartText("*Commercial product - do not distribute!*");
	    dxStCount++;
	    dxStartText("Please report software piracy to the SPA");
	//);
	break;
	
      default:
	// Ouch.
	break;
    }

    //printf ("M_Init: Init miscellaneous info.\n");
    WriteDebug("M_Init: Init miscellaneous info.\n");
    dxStCount++;
    dxStartText("M_Init: Init miscellaneous info.");
    M_Init();

    //printf ("R_Init: Init DOOM refresh daemon - ");
    WriteDebug("R_Init: Init DOOM refresh daemon - ");
    dxStCount++;
    dxStartText("R_Init: Init DOOM refresh daemon -");
    R_Init();

    //printf ("\nP_Init: Init Playloop state.\n");
    WriteDebug("\nP_Init: Init Playloop state.\n");
    dxStCount++;
    dxStartText("P_Init: Init Playloop state.");
    P_Init();

    //printf ("I_Init: Setting up machine state.\n");
    WriteDebug("I_Init: Setting up machine state.\n");
    dxStCount++;
    dxStartText("I_Init: Setting up machine state.");
    I_Init();

    //printf ("D_CheckNetGame: Checking network game status.\n");
    WriteDebug("D_CheckNetGame: Checking network game status.\n");
    dxStCount++;
    dxStartText("D_CheckNetGame:");
    dxStCount++;
	dxStartText("      Checking network game status.");  //fudge for little screens
    D_CheckNetGame();

    //printf ("S_Init: Setting up sound.\n");
    WriteDebug("S_Init: Setting up sound.\n");
    dxStCount++;
    dxStartText("S_Init: Setting up sound.");
    //S_Init (snd_SfxVolume*8, snd_MusicVolume*8 );
    S_Init(snd_SfxVolume, snd_MusicVolume );

    //printf ("HU_Init: Setting up heads up display.\n");
    WriteDebug("HU_Init: Setting up heads up display.\n");
    dxStCount++;
    dxStartText("S_Init: Setting up heads up display.");
    HU_Init();

    //printf ("ST_Init: Init status bar.\n");
    WriteDebug("ST_Init: Init status bar.\n");
    dxStCount++;
    dxStartText("ST_Init: Init status bar.");
    ST_Init();

    //printf ("ST_Init: Init status bar.\n");
    WriteDebug("CO_Init: Init console.\n");
    dxStCount++;
    dxStartText("CO_Init: Init console.");
    CO_Init();

    // check for a driver that wants intermission stats
    p = M_CheckParm ("-statcopy");
    if (p && p<myargc-1)
    {
		// for statistics driver
		extern  void*	statcopy;                            
		
		statcopy = (void*)atoi(myargv[p+1]);
		//printf ("External statistics registered.\n");
		WriteDebug("External statistics registered.\n");
    }
    
    // start the apropriate game based on parms
    p = M_CheckParm("-record");
    if (p && p < myargc-1)
    {
		G_RecordDemo(myargv[p+1]);
		autostart = true;
    }
	
    p = M_CheckParm("-playdemo");
    if (p && p < myargc-1)
    {
		singledemo = true;              // quit after one demo
		G_DeferedPlayDemo (myargv[p+1]);
		return;
		//    D_DoomLoop ();  // never returns
    }
	
    p = M_CheckParm("-playdemo2");
	if (p && p < myargc-1)
    {
		singledemo = true;              // quit after one demo
		if (G_DeferedPlayDemo_II(myargv[p+1]) == true)
			return;
		else
		{
			sprintf(MsgText, "DEMO II [%s.dem] - BAD FILE.\n", myargv[p+1]);
			WriteDebug(MsgText);
		}
		//    D_DoomLoop ();  // never returns
    }
	
    p = M_CheckParm("-timedemo");
    if (p && p < myargc-1)
    {
		WriteDebug("-timedemo\n");
		G_TimeDemo (myargv[p+1]);
		return;
		//    D_DoomLoop ();  // never returns
    }
	
    p = M_CheckParm("-timedemo2");
    if (p && p < myargc-1)
    {
		WriteDebug("-timedemo2\n");
		if (G_TimeDemo_II(myargv[p+1]) == true)
			return;
		else
		{
			sprintf(MsgText, "DEMO II [%s.dem] - BAD FILE.\n", myargv[p+1]);
			WriteDebug(MsgText);
		}
		//    D_DoomLoop ();  // never returns
    }
	
    p = M_CheckParm ("-loadgame");
    if (p && p < myargc-1)
    {
		if (M_CheckParm("-cdrom"))
			sprintf(file, "c:\\doomdata\\"SAVEGAMENAME"%c.dsg",myargv[p+1][0]);
		else
			sprintf(file, SAVEGAMENAME"%c.dsg",myargv[p+1][0]);
		G_LoadGame (file);
    }
	
    if ( gameaction != ga_loadgame )
    {
		if (autostart || netgame)
			G_InitNew(startskill, startepisode, startmap);
		else
			D_StartTitle();                // start up intro loop
	}
//    D_DoomLoop ();  // never returns
}
