home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Demon Gate 666
/
DemonGate666.bin
/
pc
/
easyw111
/
easywad.c
next >
Wrap
C/C++ Source or Header
|
1994-10-01
|
205KB
|
3,590 lines
/**********************************************************************************************************************************/
/* File : EASYWAD.C */
/* Executable : EASYWAD.EXE */
/* Helpfile : EASYWAD.CFG */
/* Doc file : EASYWAD.DOC */
/* Version num : 1.11 */
/* Last changed : 26-09-1994 8:59 */
/* Update count : 13 */
/* OS type : PC (DOS) */
/* Description : Menu handler for multiple WAD files for DOOM (Trademark of Id Software) */
/* Compiler : Microsoft (R) Quick C Compiler Version 2.00 */
/* Linker : Microsoft (R) QuickC Linker Version 4.06 */
/* QCL attribs : /AC /G2 /Ot /Zr (Compact model, optimized 80286 code, enable pointer checking) */
/* Other : WM.BAT : start file */
/* START.BAT : the result */
/* START.OPT : response file */
/* Remarks : Credits go to Brendon Wyber & Raphael Quinet (Doom Editor Utilities) for WadHeader and WadDirectory structures. */
/* */
/* By M. van der Heide of ThunderWare Research Center */
/**********************************************************************************************************************************/
#include <bios.h>
#include <ctype.h>
#include <direct.h>
#include <dos.h>
#include <graph.h>
#include <malloc.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define boolean char
#define TRUE 1
#define FALSE 0
#define DBLACK 0 /* Define names for the standard (VGA) palette colors */
#define DBLUE 1
#define DGREEN 2
#define DCYAN 3
#define DRED 4
#define DMAGENTA 5
#define DYELLOW 6
#define DWHITE 7
#define LBLACK 8
#define LBLUE 9
#define LGREEN 10
#define LCYAN 11
#define LRED 12
#define LMAGENTA 13
#define LYELLOW 14
#define LWHITE 15
#define ANYATTR _A_NORMAL|_A_RDONLY|_A_HIDDEN|_A_SYSTEM|_A_ARCH /* File attributes */
#define SUBATTR _A_NORMAL|_A_RDONLY|_A_HIDDEN|_A_SYSTEM|_A_ARCH|_A_SUBDIR /* Subdirectory attributes */
#define MAXWADS 1000 /* Max number of WAD files the program can handle */
#define MAXAUTOINCLUDE 5 /* Maximum number of autoinclude-WAD files in a CONFIGFILE */
#define MAXWADDIRS 400 /* Max number of WAD file directories a CONFIGFILE may contain */
#define PAGE 54 /* Max number of WAD files on screen */
#define WADHEIGHT 18 /* Max number of filenames vertically */
#define WADWIDTH 27 /* Max positions taken for a filename+info horizontally */
#define MAXINFOLEN 16 /* Max length of a WAD file info field */
#define ENTRYLEN 8 /* Length of the name of a 'directory' entry in a WAD file */
#define NOMEM (void far *)0 /* Memory allocation error */
#define DEFAULTCONFIGFILE "EASYWAD.CFG"
#define OTHERCONFIGFILE '+' /* Used on the command line: use other config file than EASYWAD.CFG */
#define COMMENT '#' /* All characters in a line following this one are ignored in a CONFIGFILE */
#define WADFILE "*.WAD"
#define BATFILE "START.BAT" /* This file is built at the end */
#define RESPONSEFILE "START.OPT" /* Response file if DOOMVERSION is 1.5 or higher */
#define DOSUB1 "/S" /* Used in CONFIGFILE in a WADDIR entry: do subdirs too */
#define DOSUB2 "-S"
#define RESCAN1 "/R" /* Used on the command line: rebuild WAD InfoFile */
#define RESCAN2 "-R"
#define MAINWAD1 "DOOM.WAD" /* Main WAD file (registered version) */
#define MAINWAD2 "DOOM1.WAD" /* Main WAD file (shareware version) */
#define STARTALONE "DOOM" /* Define the start commands for DOOM */
#define STARTIPX "IPXSETUP"
#define STARTLINK "SERSETUP"
#define DMATCH "-DEATHMATCH" /* Define the command parameters for DOOM */
#define INCFILE "-FILE"
#define DEVPARM "-DEVPARM"
#define GOTOEPISODE "-EPISODE"
#define GOTOANYTHING "-WARP"
#define SKILL "-SKILL"
#define NUMPLAYERS "-NODES"
#define COMPORT "-COM"
#define NOMONSTERS "-NOMONSTERS"
#define RESPAWNMONSTERS "-RESPAWN"
#define FASTMONSTERS "-FAST"
#define DMATCHV2 "-ALTDEATH"
#define NWSOCKET "-SOCKET"
#define NOFIELD 0 /* Number the FIELDs on the screen */
#define FILEFIELD 1
#define EPISODEFIELD 2
#define DIFFICULTYFIELD 3
#define PLAYTYPEFIELD 4
#define LEVELFIELD 5
#define DEATHMATCHFIELD 6
#define PAGERFIELD 7
#define RDPREVFIELD 8
#define STARTFIELD 9
#define AUTOMATICFIELD 10
#define DEATHMATCHV2FIELD 11
#define RESPAWNFIELD 12
#define NOMONSTERSFIELD 13
#define FASTMONSTERSFIELD 14
#define DEFAULTVERSION 0 /* This effectively means 1.0 */
#define DEFAULTEPISODE 1
#define DEFAULTDIFFICULTY 3
#define DEFAULTPLAYTYPE 1
#define DEFAULTLEVEL 1
#define DEFAULTDMATCH FALSE
#define DEFAULTDMATCHV2 FALSE
#define DEFAULTRESPAWN FALSE
#define DEFAULTNOMONSTERS FALSE
#define DEFAULTFASTMONST FALSE
#define DEFAULTSOCKET 0
#define DEFAULTNODES 2
#define DEFAULTCOMPORT 1
#define DEFAULTWADDIR "." /* Current directory */
#define DEFAULTINFOFILE "WADS.DSC"
#define KEY_EPISODE 'E' /* Keyboard equivalents of mouse selections */
#define KEY_LEVEL 'L'
#define KEY_DIFFICULTY 'S' /* (Skill) */
#define KEY_PLAYTYPE 'T'
#define KEY_NODES 'N'
#define KEY_COMPORT 'C'
#define KEY_DEATHMATCH 'D'
#define KEY_DEATHMATCHV2 'V'
#define KEY_AUTO 'A'
#define KEY_READPREVIOUS 'R'
#define KEY_NOMONSTERS 'M'
#define KEY_RESPAWNMONST 'P'
#define KEY_FASTMONSTERS 'F'
#define KEY_ABORT 0x1B /* [ESC] */
#define KEY_STARTGAME 0x0D /* [RETURN] */
#define KEY_PAGEUP 0x4900
#define KEY_PAGEDOWN 0x5100
#define KEY_DELETEWAD 0x5300 /* [DEL] */
#define KEY_HELP 0x3B00 /* [F1] */
#define KEY_RESCAN 0x3F00 /* [F5] */
#define KEY_TOGGLEFULL 0x4100 /* [F7] */
#define KEY_TOGGLESORT 0x4200 /* [F8] */
#define KEY_CURSLEFT 0x4B00
#define KEY_CURSRIGHT 0x4D00
#define KEY_CURSUP 0x4800
#define KEY_CURSDOWN 0x5000
#define KEY_SELECTFILE 0x3900 /* [SPACE] */
#define RETURNERROR 1 /* Define exit codes */
#define RETURNABORT 1
#define RETURNSTART 0
#define NUMEPISODE 3 /* Define the number of possible episodes */
#define NUMLEVEL 9 /* Define the number of possible levels */
#define NUMDIFFICULTY 5
#define NUMPLAYTYPE 3
#define NUMOPTIONS 18 /* Define the number of CONFIGFILE options */
#define MAXIGNORE 12 /* Define number of WAD 'directory' identifiers per type */
#define MAXCOLORS 2
#define MAXDEMOS 1
#define MAXLEVELS NUMEPISODE * NUMLEVEL
#define MAXSPRITES 74
#define MAXSOUNDS 2
#define MAXMUSIC 3
#define MAXGRAPHS 0
#define MAXADDSWITCHES 5
#define NEWCOLORS 0x01 /* Define bits for the 'NewStuff' field in the 'wadinfo' structure */
#define NEWDEMOS 0x02
#define NEWSOUNDS 0x04
#define NEWMUSIC 0x08
#define NEWSPRITES 0x10
#define NEWGRAPHS 0x20
#define ToNumber(_Drv) (toupper ((_Drv)) - 'A' + 1) /* Convert drive name to drive number */
#define ToName(_Drv) ((_Drv) + 'A' - 1) /* Convert drive number to drive name */
struct Mouse_s /* Define mouse info */
{
int OldXx; /* Coordinates stored from previous status check */
int OldYy;
int Xx; /* 0 - 79 */
int Yy; /* 0 - 29 */
boolean CoChange; /* TRUE if coordinates have changed (mouse moved to a next character) */
boolean Left; /* Status of the 3 mouse buttons; TRUE if pressed */
boolean Middle;
boolean Right;
boolean LeftStillPressed; /* TRUE if the left button was also pressed in previous status check */
} Mouse;
struct WadDir_s /* Define info for a WADDIR entry */
{
char Drive; /* 1 = A, etc., 0 means: no drive given */
char Name[_MAX_DIR];
boolean DoSubDirs; /* TRUE if the subdirectories should be searched as well */
};
struct WadInfo_s /* Define info for a WADFILE entry (also used for AUTOINCLUDE files) */
{
char Drive; /* 1 = A, etc., 0 means: no drive given */
char Path[_MAX_DIR];
char OrigName[_MAX_FNAME + _MAX_EXT - 1]; /* The original name, with extension */
char Name[_MAX_FNAME]; /* Filled out, no extension (as this is always *.WAD) */
char Info[MAXINFOLEN + 1]; /* Info as found in a WADINFOFILE file */
char NewStuff; /* Each bit represents an identifier type (demo, sound, etc) */
long NewLevels; /* Each bit represents a level: */
/* bits 0- 8 = episode 1 */
/* bits 9-17 = episode 2 */
/* bits 18-26 = episode 3 */
/* bits 27-31 = unused */
boolean Selected; /* TRUE if the WAD is selected on screen */
};
struct WadHeader_s /* The first 12 bytes of a WAD file */
{
char Type[4]; /* "PWAD" for a patch WAD, "IWAD" for an initial WAD */
long DirSize; /* Number of entries in the WAD 'directory' */
long DirStart; /* Pointer to the location (offset) of the 'directory' in the WAD file */
};
struct WadDirectory_s /* A 'directory' entry in the WAD file */
{
long Start; /* Pointer to the data of this entry in the WAD file */
long Size; /* Length in bytes of the data */
char Name[ENTRYLEN]; /* Identifier (name) of this entry */
};
struct ExtCom_s /* The commands that are available for the ADDSWITCHES keyword */
{
char *Command; /* The name of the switch */
boolean InUse; /* TRUE if this switch was given in the CONFIGFILE */
};
struct ConfOp_s /* The commands available in a CONFIGFILE */
{
char *OptionName;
enum
{
OPT_VERSION,
OPT_DOOMDIR,
OPT_WADDIR,
OPT_AUTOINC,
OPT_ADDSWIT,
OPT_PLAYTYP,
OPT_SET,
OPT_NUM,
OPT_STRING,
OPT_FILE,
OPT_SORTFIL
} OptionType;
void far *DataPtr;
};
struct WadDir_s far *WadDir[MAXWADDIRS];
struct WadInfo_s far *WadInfo[MAXWADS];
struct WadInfo_s far *AutoInc[MAXAUTOINCLUDE];
char CurPath[_MAX_DIR]; /* Current directory (preceded by drive:) */
char ConfigFile[_MAX_PATH]; /* Filename of the CONFIGFILE */
char InfoFile[_MAX_PATH]; /* Filename of WADINFOFILE as found in the CONFIGFILE */
char DoomDirectory[_MAX_PATH]; /* The main DOOM directory as found in the CONFIGFILE */
char IpxDriver[256]; /* Different IPX driver as found in the CONFIGFILE */
char SerDriver[256]; /* Different SER driver as found in the CONFIGFILE */
char S[256]; /* All-purpose string */
char CurrentField; /* Current FIELD type (see defines) */
char SelectionChange; /* Used in file FIELD; TRUE if selection toggled */
char CurrentPage; /* Current file FIELD page */
char LastPage; /* Last file FIELD page */
int CurDrive; /* Current drive */
int DoomDrive; /* Drive of main DOOM directory */
int TotalWads; /* Total number of found WAD files */
int TotalWadDirs; /* Total number of read WADDIR entries in the CONFIGFILE */
int TotalAutoInc; /* Total number of read AUTOINCLUDE entries in a CONFIGFILE */
int M;
int N;
int Dummy; /* Used in _dos_setdrive function */
boolean OtherSerDriver; /* TRUE if a different SERDRIVER was found in a CONFIGFILE */
boolean OtherIpxDriver; /* TRUE if a different IPXDRIVER was found in a CONFIGFILE */
boolean UseMouse; /* TRUE if a mouse has been found */
boolean MouseHidden; /* TRUE if the mouse pointer is temporarely hidden */
boolean Rescan = FALSE; /* TRUE if '-R' was given on the command line */
boolean ConfigChange = FALSE; /* TRUE if a different CONFIGFILE was given on the command line */
boolean ScreenOpen = FALSE;
boolean DoNotSearch = FALSE; /* TRUE if NOSEARCH was found in the CONFIGFILE */
boolean SortWadFiles = FALSE; /* TRUE if SORTFILES was found in the CONFIGFILE */
boolean SortByName = TRUE; /* TRUE for "NAME", FALSE for "INFO" */
boolean NoFullName = FALSE; /* TRUE if NOFULLNAME was found in the CONFIGFILE */
boolean NoAutoReturn = FALSE; /* TRUE if NOAUTORETURN was found in the CONFIGFILE */
int CurrentSelected = 0; /* Current pointed WAD file, 0 if none */
int PreviousWad = 0; /* Previous pointed WAD file, 0 if none */
int EpisodeActive = DEFAULTEPISODE; /* Initialize selection FIELDs */
int DifficultyActive = DEFAULTDIFFICULTY;
int PlayTypeActive = DEFAULTPLAYTYPE;
int NumNodesActive = DEFAULTNODES;
int NetworkSocket = DEFAULTSOCKET;
int CommPortActive = DEFAULTCOMPORT;
int CurrentLevel = DEFAULTLEVEL;
int DoomVersion = DEFAULTVERSION; /* 'DoomVersion' holds the decimal 0, 1, 2, 4, 5, 6 or 666 */
boolean DeathmatchOn = DEFAULTDMATCH;
boolean DeathmatchV2On = DEFAULTDMATCHV2;
boolean RespMonstersOn = DEFAULTRESPAWN;
boolean NoMonstersOn = DEFAULTNOMONSTERS;
boolean FastMonstersOn = DEFAULTFASTMONST;
char *Episodes[] = {"Knee-Deep in the Dead", "The Shores of Hell ", "Inferno "};
char *Difficulties[] = {"I'm too young to die ", "Hey, not too rough ", "Hurt me plenty ", "Ultra-Violence! ",
"NIGHTMARE "};
char *PlayTypes[] = {"Alone ", "IPX-compatible ", "Serial link "};
char *NumberNodes = "Number of players ";
char *CommPort = "COM port ";
char *Level = "LEVEL ";
char *Deathmatch = "DEATHMATCH! ";
char *DeathmatchV2 = "DEATHMATCH! V2.0 ";
char *NoMonsters = "No Monsters ";
char *RespawnMonsters = "Respawn monsters ";
char *FastMonsters = "Fast monsters ";
char *Boxes[] = {"( ) ", "(\x07) "};
char *PreviousPage = "<<<";
char *NextPage = ">>>";
char *StartGame = "( START DOOM! )";
char *Automatic = "( AUTO SELECT )";
char *ReadPrevious = "(READ PREVIOUS)";
char *NoLevel = "- ";
char *IdIgnore[] = {"THINGS", "LINEDEFS", "SIDEDEFS", "VERTEXES", "SEGS", "SSECTORS", "NODES", "SECTORS", "REJECT",
"BLOCKMAP", "INFOPACK", "PLATFORM"}; /* Last 2 are NOT from Id Software! */
char *IdColors[] = {"PLAYPAL", "COLORMAP", "c", "palette"};
char *IdDemos[] = {"DEMO", "d", "demos"};
char *IdLevels[] = {"E1M1", "E1M2", "E1M3", "E1M4", "E1M5", "E1M6", "E1M7", "E1M8", "E1M9",
"E2M1", "E2M2", "E2M3", "E2M4", "E2M5", "E2M6", "E2M7", "E2M8", "E2M9",
"E3M1", "E3M2", "E3M3", "E3M4", "E3M5", "E3M6", "E3M7", "E3M8", "E3M9", "E", "M"};
char *IdSprites[] = {"SARG", "TROO", "BOSS", "PLAY", "POSS", "SPOS", "SKUL", "HEAD", "CYBR", "SPID", "CHG", "SAW",
"PIS", "PBU", "PSH", "BAL", "PUF", "BLU", "MIS", "TFO", "PUN", "SHT", "PLS", "BFG",
"BFS", "BFE", "POL", "CAND", "CBRA", "SHOT", "MGUN", "LAUN", "CSAW", "CLIP", "SHEL", "ROCK",
"STIM", "MEDI", "ARM", "BAR", "BPAK", "BROK", "AMMO", "SBOX", "ELEC", "BKEY", "YKEY", "RKEY",
"SUIT", "PVIS", "BEXP", "PMAP", "PIN", "BON", "SOUL", "COL", "FSKU", "CEYE", "TRE", "SMI",
"BSKU", "RSKU", "YSKU", "PLAS", "BFUG", "CELL", "PSTR", "CELP", "GOR", "TGRN", "TBLU", "SMRT",
"SMBT", "SMGT", "p", "sprites"};
char *IdSounds[] = {"DS", "DP", "s", "sounds"};
char *IdMusic[] = {"D_", "GENMIDI", "DMXGUS", "m", "music"};
char *IdGraphics[] = {"g", "graphics"};
struct ConfOp_s ConfOp[] = {{"DOOMDIR", OPT_DOOMDIR, NOMEM},
{"DOOMVERSION", OPT_VERSION, NOMEM},
{"WADDIR", OPT_WADDIR, NOMEM},
{"WADINFOFILE", OPT_FILE, InfoFile},
{"SETSKILL", OPT_NUM, &DifficultyActive},
{"DEATHMATCH", OPT_SET, &DeathmatchOn},
{"AUTOINCLUDE", OPT_AUTOINC, NOMEM},
{"NOSEARCH", OPT_SET, &DoNotSearch},
{"SETCOMPORT", OPT_NUM, &CommPortActive},
{"SETNODES", OPT_NUM, &NumNodesActive},
{"SETPLAYTYPE", OPT_PLAYTYP, NOMEM},
{"ADDSWITCHES", OPT_ADDSWIT, NOMEM},
{"SORTFILES", OPT_SORTFIL, NOMEM},
{"SETSOCKET", OPT_NUM, &NetworkSocket},
{"IPXDRIVER", OPT_STRING, IpxDriver},
{"SERDRIVER", OPT_STRING, SerDriver},
{"NOFULLNAME", OPT_SET, &NoFullName},
{"NOAUTORETURN",OPT_SET, &NoAutoReturn}};
struct ExtCom_s ExtCom[] = {{"-NOJOY", FALSE},
{"-NOMOUSE", FALSE},
{"-NOMUSIC", FALSE},
{"-NOSFX", FALSE},
{"-NOSOUND", FALSE}};
int ResetMouse (void)
/**********************************************************************************************************************************/
/* Pre : None. */
/* Post : The mouse driver has been reset. If no mouse was found, then 0 is returned. Anything else means success. */
/* Import: None. */
/**********************************************************************************************************************************/
{
int Result;
_asm
{
mov ax, 0x0000
int 0x33
mov Result, ax
}
return (Result);
}
void ShowMouse (void)
/**********************************************************************************************************************************/
/* Pre : (global) 'UseMouse' is TRUE if a mouse has been detected. */
/* Post : The mouse pointer is made visable. */
/* Import: None. */
/**********************************************************************************************************************************/
{
if (UseMouse)
_asm
{
mov ax, 0x0001
int 0x33
}
}
void HideMouse (void)
/**********************************************************************************************************************************/
/* Pre : (global) 'UseMouse' is TRUE if a mouse has been detected. */
/* Post : The mouse pointer is made invisable. */
/* Import: None. */
/**********************************************************************************************************************************/
{
if (UseMouse)
_asm
{
mov ax, 0x0002
int 0x33
}
}
void MouseStatus (void)
/**********************************************************************************************************************************/
/* Pre : None. */
/* Post : The mouse driver has been read, which returns the status of the buttons and the x and y coordinates of the mouse. */
/* All this information is stored in the 'Mouse' structure. */
/* Import: None. */
/**********************************************************************************************************************************/
{
int Result;
Mouse.LeftStillPressed = Mouse.Left;
_asm
{
mov ax, 0x0003
int 0x33
mov Mouse.Xx, cx
mov Mouse.Yy, dx
mov Result, bx
}
Mouse.Left = (Result & 0x0001); /* Store the status of the mouse buttons */
Mouse.Right = (Result & 0x0002);
Mouse.Middle = (Result & 0x0004);
Mouse.Xx /= 0x0008; /* Convert pixel coordinates to character coordinates */
Mouse.Yy /= 0x0010;
Mouse.CoChange = (Mouse.OldXx != Mouse.Xx || Mouse.OldYy != Mouse.Yy);
if (!Mouse.Left)
Mouse.LeftStillPressed = FALSE;
}
void DeAllocateAll (void)
/**********************************************************************************************************************************/
/* Pre : None. */
/* Post : If any WadDirs were initialized yet, then the memory is deallocated completely. */
/* If any WadInfos were initialized yet, then the memory is deallocated completely. */
/* If any AutoIncs were initialized yet, then the memory is deallocated completely. */
/* Import: None. */
/**********************************************************************************************************************************/
{
fcloseall ();
flushall ();
while (-- TotalWadDirs >= 0)
_ffree (WadDir[TotalWadDirs]);
while (-- TotalWads >= 0)
_ffree (WadInfo[TotalWads]);
while (-- TotalAutoInc >= 0)
_ffree (AutoInc[TotalAutoInc]);
}
void Bye (int ReturnType, char *Message, ...)
/**********************************************************************************************************************************/
/* Pre : 'ReturnType' holds the exit code, 'Message' holds the error message. */
/* Post : The error message has been printed, all memory is freed and the program has been aborted. */
/* Import: DeAllocateAll. */
/**********************************************************************************************************************************/
{
va_list Args;
if (ScreenOpen) /* Still in graphics mode ? */
_setvideomode (_DEFAULTMODE); /* Then close the screen */
va_start (Args, Message);
vfprintf (stderr, Message, Args); /* Print the (formatted) error message */
va_end (Args);
_dos_setdrive (CurDrive, &Dummy); /* Return to home drive and directory */
chdir (CurPath);
DeAllocateAll ();
exit (ReturnType);
}
void PrText (short UseBox, short Y0, short X0, unsigned char Color, char *Msg, ...)
/**********************************************************************************************************************************/
/* Pre : 'Y0' and 'X0' hold the coordinates, 'Color' holds the (VGA) color and 'Msg' holds the message to print. */
/* UseBox < 0: no selection box is printed first; */
/* UseBox = 0: an empty selection box is printed first; */
/* UseBox > 0: a filled selection box is printed first; */
/* If Y0 is 0, then the coordinates are not used; the text is written directly after the previous. */
/* Post : If the coordinates were non-zero, then the message is printed at these coordinates in the given color. The coordinates */
/* are first converted to the pixel coordinates according to the used font. */
/* Import: None. */
/**********************************************************************************************************************************/
{
char Message[80];
va_list Args;
va_start (Args, Msg);
vsprintf (Message, Msg, Args); /* Convert the message into one string */
va_end (Args);
if (Y0 != 0)
_settextposition (Y0, X0);
_settextcolor (Color);
if (UseBox == 0)
_outtext (Boxes[0]);
if (UseBox > 0)
_outtext (Boxes[1]);
_outtext (Message);
}
void InitVideo (void)
/**********************************************************************************************************************************/
/* Pre : None. */
/* Post : A VGA display of 640 x 480 x 16 colors has been opened and the screen has been cleared. */
/* Import: Bye. */
/**********************************************************************************************************************************/
{
if (!_setvideomode (_VRES16COLOR))
Bye (RETURNERROR, "ERROR - You need a VGA videocard for this utility\n");
_clearscreen (_GCLEARSCREEN);
}
char *TestName (char *OldName)
/**********************************************************************************************************************************/
/* Pre : 'OldName' holds the name to be tested. */
/* Post : The name is tested. The return value is a string of the (adapted) input with the following specifications: */
/* - Each part (subdirname) has at most 8 characters, possibly followed by a '.' and at most 3 characters. */
/* - Each of the characters is valid to the DOS system. */
/* - Trailing backslashes have been cut, except when it was the only path character. */
/* Import: Bye. */
/**********************************************************************************************************************************/
{
char Level[_MAX_PATH];
char NewName[_MAX_PATH];
char Part[_MAX_FNAME];
int LvlCnt;
int Ex;
int PathLenOldName;
int CharCnt;
int PartChar;
boolean PointDone;
boolean NError = FALSE;
boolean DriveFound = FALSE;
boolean Ready = FALSE;
PathLenOldName = strlen (OldName);
CharCnt = -1;
NewName[0] = '\0';
while (!Ready && !NError)
{
LvlCnt = 0;
while ((++ CharCnt < PathLenOldName) && OldName[CharCnt] != '\\' && OldName[CharCnt] != ':')
Level[LvlCnt ++] = OldName[CharCnt];
Level[LvlCnt] = '\0';
if (OldName[CharCnt] == ':') /* Preceded by drive: ? */
if (DriveFound) /* Already a drive found! */
NError = TRUE;
else
{
DriveFound = TRUE;
strncpy (NewName, OldName, CharCnt + 1);
NewName[CharCnt + 1] = '\0';
if (CharCnt != 1 || toupper (OldName[0]) < 'A' || toupper (OldName[0]) > 'Z') /* Test drive validity */
Bye (RETURNERROR, "\nERROR - Invalid drivename %s\n", NewName);
if (CharCnt == PathLenOldName - 1)
Ready = TRUE; /* Only a driveletter given */
else
if (CharCnt == PathLenOldName - 2 && OldName[CharCnt + 1] == '\\')
{
Ready = TRUE; /* Exceptional case: only drive:\ given */
strcpy (NewName, OldName);
}
}
else
{
if (CharCnt == PathLenOldName) /* Handling last part ? */
Ready = TRUE;
if (CharCnt == PathLenOldName - 1 && OldName[CharCnt] == '\\')
Ready = TRUE; /* Ended with backslash */
PointDone = FALSE;
for (PartChar = 0 ; PartChar < strlen (Level) ; PartChar ++)
switch (Level[PartChar])
{
case '.' : if (!PointDone)
{
strncpy (Part, Level, PartChar < 8 ? PartChar : 8);
Part[PartChar < 8 ? PartChar : 8] = '\0'; /* Cut >8 characters */
strcat (NewName, Part);
strcat (NewName, "."); /* Add the '.' */
Ex = PartChar + 1;
PointDone = TRUE;
}
else
if (strcmp (Level, "..")) /* Exceptional case */
NError = TRUE;
break;
case ';' :
case ',' :
case '\'' :
case '/' :
case '(' :
case ')' :
case '[' :
case ']' : /* Characters '>', '<', '|' '"' and '\' have already been taken out */
case '=' : NError = TRUE; /* All bad characters */
break;
}
if (!PointDone) /* Finish filenames without extension */
{
strncpy (Part, Level, PartChar < 8 ? PartChar : 8);
Part[PartChar < 8 ? PartChar : 8] = '\0';
strcat (NewName, Part);
PointDone = TRUE;
}
else /* This also deals with the second point in '..' */
{
strncpy (Part, Level + Ex, PartChar - Ex < 3 ? PartChar - Ex : 3); /* Cut >3 characters */
Part[PartChar - Ex < 3 ? PartChar - Ex : 3] = '\0';
strcat (NewName, Part);
}
if (!Ready)
strcat (NewName, "\\"); /* Add the subdir character */
}
}
if (NError) /* Report bad characters */
Bye (RETURNERROR, "\nERROR - Invalid name %s\n", OldName);
if (!strlen (NewName) && OldName[0] == '\\') /* Input was root dir */
return ("\\"); /* Which should be treated differently */
else
return (NewName); /* Return (modified) string */
}
void GetWadInfo (int WadNumber, boolean GoThere)
/**********************************************************************************************************************************/
/* Pre : 'WadNumber' holds the WAD file number in memory that should be checked. */
/* 'GoThere' is TRUE if the routine should first go to the required drive and directory. */
/* Post : The WAD directory of the file has been found and read out. The structure 'wadinfo' has been updated. */
/* Import: Bye. */
/**********************************************************************************************************************************/
{
FILE *Fp;
struct WadDirectory_s WadDirectory;
struct WadHeader_s WadHeader;
char Identifier[9];
char DrivePath[_MAX_DIR];
int O;
long Entries;
boolean More;
if (GoThere) /* Jump to the directory if needed */
{
_dos_setdrive (WadInfo[WadNumber]->Drive, &Dummy);
free (getcwd (DrivePath, _MAX_DIR - 1)); /* Collect current directory */
chdir (WadInfo[WadNumber]->Path);
}
if (!(Fp = fopen (WadInfo[WadNumber]->OrigName, "rb")))
Bye (RETURNERROR, "\nERROR - Error opening file %s\n", WadInfo[WadNumber]->OrigName);
if (fread (&WadHeader, 1, sizeof (struct WadHeader_s), Fp) != sizeof (struct WadHeader_s)) /* Read the WAD header */
Bye (RETURNERROR, "\nERROR - Error reading file %s\n", WadInfo[WadNumber]->OrigName);
if (strnicmp (WadHeader.Type, "PWAD", 4) && strnicmp (WadHeader.Type, "IWAD", 4)) /* Is it a WAD file ? */
Bye (RETURNERROR, "\nERROR - File %s is not a WAD file\n", WadInfo[WadNumber]->OrigName);
if (fseek (Fp, WadHeader.DirStart, SEEK_SET)) /* Go to the WAD 'directory' part of the file */
Bye (RETURNERROR, "\nERROR - Error reading file %s\n", WadInfo[WadNumber]->OrigName);
WadInfo[WadNumber]->NewStuff = 0x00; /* Clear all entries */
WadInfo[WadNumber]->NewLevels = 0x00000000;
Entries = -1; /* Count all WAD 'directory' entries */
while (++ Entries < WadHeader.DirSize) /* The number of entries was found in the WAD header */
{
if (fread (&WadDirectory, 1, sizeof (struct WadDirectory_s), Fp) != sizeof (struct WadDirectory_s)) /* Read an entry */
Bye (RETURNERROR, "\nERROR - Error reading file %s\n", WadInfo[WadNumber]->OrigName);
for (O = 0 ; O < ENTRYLEN ; O ++) /* Fill the identifier to 8 positions */
Identifier[O] = WadDirectory.Name[O];
Identifier[ENTRYLEN] = '\0'; /* And make it a string */
More = TRUE; /* Now test it against all types and signal successes */
for (O = 0 ; O < MAXIGNORE && More ; O ++)
if (!strnicmp (Identifier, IdIgnore[O], strlen (IdIgnore[O])))
More = FALSE;
if (More)
for (O = 0 ; O < MAXCOLORS && More ; O ++)
if (!strnicmp (Identifier, IdColors[O], strlen (IdColors[O])))
{
More = FALSE;
WadInfo[WadNumber]->NewStuff |= NEWCOLORS;
}
if (More)
for (O = 0 ; O < MAXDEMOS && More ; O ++)
if (!strnicmp (Identifier, IdDemos[O], strlen (IdDemos[O])))
{
More = FALSE;
WadInfo[WadNumber]->NewStuff |= NEWDEMOS;
}
if (More)
for (O = 0 ; O < MAXLEVELS && More ; O ++)
if (!strnicmp (Identifier, IdLevels[O], strlen (IdLevels[O])))
{
More = FALSE;
WadInfo[WadNumber]->NewLevels |= ((long)1 << O);
}
if (More)
for (O = 0 ; O < MAXSPRITES && More ; O ++)
if (!strnicmp (Identifier, IdSprites[O], strlen (IdSprites[O])))
{
More = FALSE;
WadInfo[WadNumber]->NewStuff |= NEWSPRITES;
}
if (More)
for (O = 0 ; O < MAXSOUNDS && More ; O ++)
if (!strnicmp (Identifier, IdSounds[O], strlen (IdSounds[O])))
{
More = FALSE;
WadInfo[WadNumber]->NewStuff |= NEWSOUNDS;
}
if (More)
for (O = 0 ; O < MAXMUSIC && More ; O ++)
if (!strnicmp (Identifier, IdMusic[O], strlen (IdMusic[O])))
{
More = FALSE;
WadInfo[WadNumber]->NewStuff |= NEWMUSIC;
}
if (More && WadDirectory.Start != NULL && Identifier[0] != '\0') /* All other identifiers are counted as graphics */
WadInfo[WadNumber]->NewStuff |= NEWGRAPHS;
}
fclose (Fp);
if (GoThere)
{
chdir (DrivePath);
_dos_setdrive (CurDrive, &Dummy); /* Return to home location */
}
}
void WriteWadInfo (char *FileName)
/**********************************************************************************************************************************/
/* Pre : 'FileName' holds the name of the file (which is the same as set in 'InfoFile'). */
/* Post : All found WAD files are considered. All files have their fields 'NewStuff' and 'NewLevels' initialized. This info is */
/* converted into readable text and written to the file, together with the path information of the WAD file. */
/* Import: None. */
/**********************************************************************************************************************************/
{
FILE *Fp;
char Memory;
char P;
char Q;
char T[81];
int WadNumber;
boolean First;
boolean New;
boolean More;
if (!(Fp = fopen (FileName, "w")))
Bye (RETURNERROR, "\nERROR - Cannot write WAD info file\n");
for (WadNumber = 0 ; WadNumber < TotalWads ; WadNumber ++)
{
More = FALSE;
S[0] = '\0';
fprintf (Fp, "%d %s %s ", WadInfo[WadNumber]->Drive, WadInfo[WadNumber]->Path, WadInfo[WadNumber]->OrigName);
More = (WadInfo[WadNumber]->NewLevels != 0x00000000); /* Are their any patch levels in this file ? */
if (More) /* Skip if not */
{
for (P = 0 ; P < NUMEPISODE ; P ++)
{
Memory = -1;
First = TRUE;
if ((WadInfo[WadNumber]->NewLevels & ((long)0x1ff << (P * NUMLEVEL))) == ((long)0x1ff << (P * NUMLEVEL)))
{ /* All 9 level-bits of an episode set */
sprintf (T, "%s%d-", IdLevels[MAXLEVELS], (int)P + 1);
strcat (S, T);
}
else /* Possibly a partial episode */
for (Q = 0 ; Q < NUMLEVEL ; Q ++) /* Handle all level-bits in this episode */
if (WadInfo[WadNumber]->NewLevels & ((long)1 << (P * NUMLEVEL + Q)))
{
if (Memory == -1)
if (First)
{
sprintf (T, "%s%d%s%d", IdLevels[MAXLEVELS], (int)P + 1, IdLevels[MAXLEVELS + 1], (int)Q + 1);
strcat (S, T);
First = FALSE;
Memory = 1;
New = FALSE;
}
else
{
sprintf (T, ",%d", (int)Q + 1);
strcat (S, T);
Memory = Q + 1;
New = FALSE;
}
else
{
Memory ++;
New = TRUE;
}
}
else
{
if (Memory > 0 && New)
{
sprintf (T, "-%d", (int)Memory);
strcat (S, T);
}
Memory = -1;
}
if (Memory > 0 && New)
{
sprintf (T, "-%d", (int)Memory);
strcat (S, T);
}
}
sprintf (T, "%-10s", S);
strcpy (S, T);
} /* No new levels in this WAD file */
else /* If only one type was found (for example, only sounds) */
if (!(WadInfo[WadNumber]->NewStuff ^ NEWCOLORS)) /* Then use the complete word ('sounds' in this example) */
sprintf (S, "%s", IdColors[MAXCOLORS + 1]);
else
if (!(WadInfo[WadNumber]->NewStuff ^ NEWDEMOS))
sprintf (S, "%s", IdDemos[MAXDEMOS + 1]);
else
if (!(WadInfo[WadNumber]->NewStuff ^ NEWSOUNDS))
sprintf (S, "%s", IdSounds[MAXSOUNDS + 1]);
else
if (!(WadInfo[WadNumber]->NewStuff ^ NEWMUSIC))
sprintf (S, "%s", IdMusic[MAXMUSIC + 1]);
else
if (!(WadInfo[WadNumber]->NewStuff ^ NEWSPRITES))
sprintf (S, "%s", IdSprites[MAXSPRITES + 1]);
else
if (!(WadInfo[WadNumber]->NewStuff ^ NEWGRAPHS))
sprintf (S, "%s", IdGraphics[MAXGRAPHS + 1]);
else
{
More = TRUE; /* More than one type found */
strcpy (S, NoLevel); /* Clear level string-part */
}
if (More) /* Levels found or more types than 1 */
{
if (WadInfo[WadNumber]->NewStuff & NEWCOLORS) /* Print one character to indicate the type */
strcat (S, IdColors[MAXCOLORS]);
if (WadInfo[WadNumber]->NewStuff & NEWDEMOS)
strcat (S, IdDemos[MAXDEMOS]);
if (WadInfo[WadNumber]->NewStuff & NEWSOUNDS)
strcat (S, IdSounds[MAXSOUNDS]);
if (WadInfo[WadNumber]->NewStuff & NEWMUSIC)
strcat (S, IdMusic[MAXMUSIC]);
if (WadInfo[WadNumber]->NewStuff & NEWSPRITES)
strcat (S, IdSprites[MAXSPRITES]);
if (WadInfo[WadNumber]->NewStuff & NEWGRAPHS)
strcat (S, IdGraphics[MAXGRAPHS]);
}
sprintf (WadInfo[WadNumber]->Info, "%-16s", S); /* MAXINFOLEN */
fprintf (Fp, "%-16s\n", S);
}
fclose (Fp);
}
int NextString (FILE *Fp, char *String)
/**********************************************************************************************************************************/
/* Pre : 'Fp' points to the open CONFIGFILE, 'String' holds the address of the string to be read. */
/* Post : Any string is read. If it started with a '#' (COMMENT character), then the rest of the line has been ignored. The */
/* function does not return before a string was read WITHOUT this character or EOF has been reached. The result of the */
/* function is the length of the read string, or 0 if EOF was encountered. */
/* Import: None. */
/**********************************************************************************************************************************/
{
char Ch;
char Cnt;
boolean Ready = FALSE;
boolean SkipSpaces;
while (!Ready) /* Read until a valid string is found */
{
SkipSpaces = TRUE;
while (SkipSpaces)
{
fscanf (Fp, "%c", &Ch); /* Read until no white-spaces found */
if (feof (Fp))
{
String[0] = '\0'; /* Or until EOF */
return (0);
}
SkipSpaces = isspace (Ch);
}
if (Ch == COMMENT) /* First character is the COMMENT character ? */
do
{
fscanf (Fp, "%c", &Ch); /* Ignore until end of the line */
if (feof (Fp))
{
String[0] = '\0'; /* Or until EOF */
return (0);
}
}
while (Ch != '\n');
else
Ready = TRUE;
}
Cnt = 0;
Ready = FALSE;
while (!Ready)
{
while (!isspace (Ch) && Ch != '"') /* Trap quoted argument(part)s */
{
String[Cnt ++] = Ch;
fscanf (Fp, "%c", &Ch); /* Read until first white-space */
if (feof (Fp))
{
String[Cnt] = '\0'; /* Or until EOF */
return (Cnt);
}
}
if (Ch == '"') /* Handle quoted part */
{
do
{
fscanf (Fp, "%c", &Ch);
if (feof (Fp))
Bye (RETURNERROR, "ERROR - Unexpected end of configuration file\n");
if (Ch == '\n')
Bye (RETURNERROR, "ERROR - Unexpected end of line in configuration file\n");
String[Cnt ++] = Ch;
}
while (Ch != '"');
Cnt --;
fscanf (Fp, "%c", &Ch); /* Read first after */
if (feof (Fp))
{
String[Cnt] = '\0'; /* Or until EOF */
return (Cnt);
}
}
else
Ready = TRUE;
}
String[Cnt] = '\0';
return (Cnt);
}
void HandleOptWaddir (char *Item)
/**********************************************************************************************************************************/
/* Pre : 'Item' holds an operand that has been read following an 'WADDIR' option. */
/* Post : If 'Item' holds '/S' (or '-S'), then the previously declared WadDir is flagged 'DoSubDirs'. Otherwise, 'Item' holds a */
/* filename, that is included in the WadDir list. If any error occurs, then no return is made. */
/* Import: TestName, Bye. */
/**********************************************************************************************************************************/
{
int DriveNo;
if (!stricmp (Item, DOSUB1) || !stricmp (Item, DOSUB2))
if (TotalWadDirs == 0)
Bye (RETURNERROR, "ERROR - Badly placed switch %s in WADDIR field\n", DOSUB1);
else
WadDir[TotalWadDirs - 1]->DoSubDirs = TRUE;
else
{
if (TotalWadDirs == MAXWADDIRS)
Bye (RETURNERROR, "ERROR - Too many WADDIR entries\n");
if ((WadDir[TotalWadDirs] = ((struct WadDir_s far *)_fmalloc ((size_t)sizeof (struct WadDir_s)))) == NOMEM)
Bye (RETURNERROR, "FATAL ERROR - Out of memory\n");
strcpy (S, TestName (Item));
if (S[1] == ':') /* Preceded by drive: ? */
{
if (strlen (S) == 2) /* Just a drive, no path ? */
Bye (RETURNERROR, "ERROR - Missing path for WADDIR in configuration file\n");
DriveNo = ToNumber (S[0]);
if (DriveNo != CurDrive) /* A new drive ? */
WadDir[TotalWadDirs]->Drive = DriveNo; /* Store drive number */
else
WadDir[TotalWadDirs]->Drive = 0; /* Signal: no new drive given */
strcpy (WadDir[TotalWadDirs]->Name, strupr (S + 2)); /* Store path */
}
else
{
WadDir[TotalWadDirs]->Drive = 0; /* Signal: no drive given */
strcpy (WadDir[TotalWadDirs]->Name, strupr (S));
}
WadDir[TotalWadDirs]->DoSubDirs = FALSE;
TotalWadDirs ++;
}
}
void HandleOptDoomdir (char *Item)
/**********************************************************************************************************************************/
/* Pre : 'Item' holds the operand that has been read following a 'DOOMDIR' option. */
/* Post : The (global) variables 'DoomDrive' and 'DoomDirectory' have been initialized. */
/* Import: TestName, Bye. */
/**********************************************************************************************************************************/
{
int DriveNo;
strcpy (S, TestName (Item));
if (S[1] == ':') /* Preceded by drive: ? */
{
if (strlen (S) == 2) /* Just a drive, no path ? */
Bye (RETURNERROR, "ERROR - Missing path for DOOMDIR in configuration file\n");
DriveNo = ToNumber (S[0]);
if (DriveNo != CurDrive) /* A new drive ? */
DoomDrive = DriveNo; /* Store drive number */
else
DoomDrive = 0; /* Signal: no new drive given */
strcpy (DoomDirectory, strupr (S + 2)); /* Store path */
}
else
{
DoomDrive = 0; /* Signal: no drive given */
strcpy (DoomDirectory, strupr (S));
}
}
void HandleOptAutoinc (char *Item)
/**********************************************************************************************************************************/
/* Pre : 'Item' holds a filename that has been read following an 'AUTOINCLUDE' option. */
/* Post : The filename is include in the AutoInc list. If any error occurs, then no return is made. */
/* Import: TestName, Bye. */
/**********************************************************************************************************************************/
{
int DriveNo;
int Index;
if (TotalAutoInc == MAXAUTOINCLUDE)
Bye (RETURNERROR, "ERROR - Too many AUTOINCLUDE entries\n");
if ((AutoInc[TotalAutoInc] = ((struct WadInfo_s far *)_fmalloc ((size_t)sizeof (struct WadInfo_s)))) == NOMEM)
Bye (RETURNERROR, "FATAL ERROR - Out of memory\n");
strcpy (S, TestName (Item));
if (S[1] == ':') /* Preceded by drive: ? */
{
if (strlen (S) == 2) /* Just a drive, no path ? */
Bye (RETURNERROR, "ERROR - Missing path for AUTOINCLUDE in configuration file\n");
DriveNo = ToNumber (S[0]);
if (DriveNo != CurDrive) /* A new drive ? */
AutoInc[TotalAutoInc]->Drive = DriveNo; /* Store drive number */
else
AutoInc[TotalAutoInc]->Drive = 0; /* Signal: no new drive given */
strcpy (AutoInc[TotalAutoInc]->Path, strupr (S + 2)); /* Store path */
}
else
{
AutoInc[TotalAutoInc]->Drive = 0; /* Signal: no drive given */
strcpy (AutoInc[TotalAutoInc]->Path, strupr (S));
}
Index = strlen (AutoInc[TotalAutoInc]->Path) - 1;
while (AutoInc[TotalAutoInc]->Path[Index] != '\\' && Index > 0)
Index --;
if (Index == 0)
{
strcpy (AutoInc[TotalAutoInc]->OrigName, AutoInc[TotalAutoInc]->Path); /* No preceding path */
strcpy (AutoInc[TotalAutoInc]->Path, DEFAULTWADDIR);
}
else
{
strcpy (AutoInc[TotalAutoInc]->OrigName, AutoInc[TotalAutoInc]->Path + Index + 1); /* Copy over last part (filename) */
AutoInc[TotalAutoInc]->Path[Index] = '\0'; /* Cut filename from path */
}
TotalAutoInc ++;
}
void HandleOptAddSwitches (char *Item)
/**********************************************************************************************************************************/
/* Pre : 'Item' holds the operand that has been read following an 'ADDSWITCHES' option. */
/* Post : If 'Item' holds a valid switch, then the 'InUse' flag of that switch is set. Otherwise no return is made. */
/* Import: Bye. */
/**********************************************************************************************************************************/
{
int Index;
if (Item[0] == '-') /* Remember that all switches start with a '-' character */
{
Index = 0;
while (Index < MAXADDSWITCHES && stricmp (Item, ExtCom[Index].Command)) /* Test the name against all allowed switches */
Index ++;
if (Index == MAXADDSWITCHES)
Bye (RETURNERROR, "ERROR - Switch %s not supported in ADDSWITCHES\n", Item);
ExtCom[Index].InUse = TRUE;
}
else
Bye (RETURNERROR, "ERROR - Unrecognised ADDSWITCHES %s in configuration file\n", Item);
}
void ReadConfig (void)
/**********************************************************************************************************************************/
/* Pre : The (global) 'ConfigFile' should be initialized. */
/* Post : If a configuration file is found, then it has been read out. Only 8 keywords are recognised: */
/* - DOOMDIR, after which the name of the main DOOM directory should be given. */
/* - DOOMVERSION, after which the (float) DOOM version should be typed. */
/* - WADDIR, after which a maximum of 400 WAD directories may be given; If an entry '/S' or '-S' is encountered, then all */
/* subdirectories of the previously declared directory will also be used as WADDIRs. */
/* - WADINFOFILE, after which a WAD info file may be given. All simple errors are reported. */
/* - SERDRIVER, after which a new serial driver should be given (in stead of SERSETUP); */
/* - IPXDRIVER, after which a new network driver should be given (in stead of IPXSETUP); */
/* - SETSKILL, after which the default skill (1-5) must be given. */
/* - DEATHMATCH (no parameters). This means that deathmatch will be set as default. */
/* - AUTOINCLUDE, after which a maximum of 5 WAD files (complete with (partial) path) may be given. These files will then */
/* automatically be selected when starting. If the file is not crossed when reading the directories (WADDIRs), then the */
/* file is just not selected (no error will be generated). */
/* - NOSEARCH (no parameters). If this keyword is given, then the program will not search all given WADDIR directories, */
/* it will use the WADINFOFILE instead and use all named entries instead. (This should be used with caution!) */
/* - SETCOMPORT, after which the default COM port (1-4) must be given for null-modem link. */
/* - SETNODES, after which the default number of players (2-4) must be given for IPX link. */
/* - SETSOCKET, after which a network socket (0-255) must be given. */
/* - SETPLAYTYPE, after which one of the keywords "ALONE", "IPX" or "SERIAL" must be given. */
/* - ADDSWITCHES, after which all the direct DOOM switches should be typed. */
/* - SORTFILES, after which one of the keywords "NAME" or "INFO" must be given. */
/* - NOFULLNAME (no parameters). Will stop using "music" i.s.o. "- m". */
/* - NOAUTORETURN (no parameters). If this option is given, then no <CR> is passed to DOOM at startup. */
/* */
/* If one (or all) are not found, then they are initialized with the defaults. */
/* */
/* If a character '#' is encountered, then the rest of this line is ignored (comment). */
/* Before returning, a test has been made if all selected switches are implemented in the given DOOM version. */
/* Import: NextString, HandleOptWaddir, HandleOptAutoinc, HandleOptAddSwitches, HandleOptDoomdir, Bye. */
/**********************************************************************************************************************************/
{
FILE *Fp;
char Item[256];
char ContinueOption;
boolean Handled;
TotalWadDirs = 0; /* Initialize all counters */
TotalAutoInc = 0;
strcpy (DoomDirectory, DEFAULTWADDIR); /* Use the current directory as default */
strcpy (InfoFile, DEFAULTINFOFILE); /* Initialize a default file name */
strcpy (IpxDriver, STARTIPX);
strcpy (SerDriver, STARTLINK);
if (Fp = fopen (ConfigFile, "r")) /* Skip if no CONFIGFILE was found */
{
NextString (Fp, Item); /* Read-ahead first string: must be a keyword */
while (!feof (Fp))
{
Handled = FALSE;
for (M = 0 ; !Handled && M < NUMOPTIONS ; M ++)
if (!stricmp (Item, ConfOp[M].OptionName))
{
if (ConfOp[M].OptionType != OPT_SET) /* Option takes one (or more) operand(s) ? */
{
NextString (Fp, Item); /* Read the operand */
if (feof (Fp))
Bye (RETURNERROR, "ERROR - Missing operand after switch %s\n", ConfOp[M].OptionName);
}
ContinueOption = 0; /* Signal: no option has more than one operand */
switch (ConfOp[M].OptionType)
{
case OPT_DOOMDIR : HandleOptDoomdir (Item);
break;
case OPT_FILE : strcpy (S, TestName (Item));
if (S[1] == ':' && S[2] == '\0') /* Only a drive given */
Bye (RETURNERROR, "ERROR - Missing pathname after %s in switch %s\n", S, ConfOp[M].OptionName);
strcpy ((char *)ConfOp[M].DataPtr, S);
break;
case OPT_NUM : for (N = 0 ; N < strlen (Item) ; N ++)
if (strlen (Item) > 3 || !isdigit (Item[N]))
Bye (RETURNERROR, "ERROR - Invalid number %s after switch %s\n", Item, ConfOp[M].OptionName);
*((int *)ConfOp[M].DataPtr) = atoi (Item);
break;
case OPT_SET : *((char *)ConfOp[M].DataPtr) = TRUE;
break;
case OPT_STRING : strcpy ((char *)ConfOp[M].DataPtr, Item);
break;
case OPT_WADDIR : ContinueOption = 1;
HandleOptWaddir (Item);
break;
case OPT_AUTOINC : ContinueOption = 2;
HandleOptAutoinc (Item);
break;
case OPT_ADDSWIT : ContinueOption = 3;
HandleOptAddSwitches (Item);
break;
case OPT_PLAYTYP : if (!stricmp (Item, "ALONE"))
PlayTypeActive = 1;
else
if (!stricmp (Item, "IPX"))
PlayTypeActive = 2;
else
if (!stricmp (Item, "SERIAL"))
PlayTypeActive = 3;
else
Bye (RETURNERROR, "ERROR - Unknown playtype %s\n", Item);
break;
case OPT_SORTFIL : SortWadFiles = TRUE;
if (!stricmp (Item, "NAME") || !stricmp (Item, "INFO"))
SortByName = !stricmp (Item, "NAME");
else
Bye (RETURNERROR, "ERROR - Unknown sort criteria %s after keyword SORTFILES\n", Item);
break;
case OPT_VERSION : DoomVersion = 0;
if (Item[0] != '1' || Item[1] != '.') /* Version number must be one of 1.x */
Bye (RETURNERROR, "ERROR - Invalid DOOM version number %s\n", Item);
for (N = 2 ; N < strlen (Item) && isdigit (Item[N]) ; N ++)
DoomVersion = DoomVersion * 10 + Item[N] - '0';
if (Item[N] != '\0')
Bye (RETURNERROR, "ERROR - Invalid DOOM version number %s\n", Item);
if (DoomVersion == 3 || (DoomVersion > 6 && DoomVersion != 666)) /* Non-existing version numbers */
Bye (RETURNERROR, "ERROR - DOOM version number %s does not exist!\n", Item);
}
Handled = TRUE;
}
if (!Handled) /* Read item is not one of the keywords */
switch (ContinueOption)
{
case 0 : Bye (RETURNERROR, "ERROR - Unknown keyword %s in configuration file\n", Item);
case 1 : HandleOptWaddir (Item);
break;
case 2 : HandleOptAutoinc (Item);
break;
case 3 : HandleOptAddSwitches (Item);
}
NextString (Fp, Item); /* Read next option */
}
fclose (Fp);
}
else
if (ConfigChange) /* It is an error if a different file was given */
Bye (RETURNERROR, "ERROR - configuration file not found\n");
OtherSerDriver = strcmp (SerDriver, STARTLINK);
OtherIpxDriver = strcmp (IpxDriver, STARTIPX);
if (TotalWadDirs == 0) /* No CONFIGFILE or WADDIR entries found ? */
{
if ((WadDir[0] = ((struct WadDir_s far *)_fmalloc ((size_t)sizeof (struct WadDir_s)))) == NOMEM)
Bye (RETURNERROR, "FATAL ERROR - Out of memory\n");
WadDir[0]->Drive = 0; /* Then use the DOOM directory as default */
strcpy (WadDir[0]->Name, DoomDirectory);
TotalWadDirs = 1;
}
if (DifficultyActive == 0 || DifficultyActive > 5) /* Filter out nonsense numerical options */
Bye (RETURNERROR, "ERROR - Invalid skill number %d\n", DifficultyActive);
if (CommPortActive == 0 || CommPortActive > 4)
Bye (RETURNERROR, "ERROR - Invalid COM port number %d\n", CommPortActive);
if (NumNodesActive < 2 || NumNodesActive > 4)
Bye (RETURNERROR, "ERROR - You cannot play network DOOM with %d player(s)\n", NumNodesActive);
if (DoomVersion < 2)
{
if (DeathmatchOn)
Bye (RETURNERROR, "ERROR - Switch DEATHMATCH needs DOOM version 1.2\n");
if (DifficultyActive == 5)
Bye (RETURNERROR, "ERROR - Skill level 5 needs DOOM version 1.2\n");
if (CommPortActive != DEFAULTCOMPORT)
Bye (RETURNERROR, "ERROR - Switch SETCOMPORT needs DOOM version 1.2\n");
if (PlayTypeActive == 3)
Bye (RETURNERROR, "ERROR - Switch SETPLAYTYPE SERIAL needs DOOM version 1.2\n");
if (strcmp (SerDriver, STARTLINK))
Bye (RETURNERROR, "ERROR - Switch SERDRIVER needs DOOM version 1.2\n");
if (PlayTypeActive == 2 && DoomVersion == 0)
Bye (RETURNERROR, "ERROR - Switch SETPLAYTYPE IPX needs DOOM version 1.1\n");
if (strcmp (IpxDriver, STARTIPX) && DoomVersion == 0)
Bye (RETURNERROR, "ERROR - Switch IPXDRIVER needs DOOM version 1.1\n");
if (NetworkSocket != DEFAULTSOCKET && DoomVersion == 0)
Bye (RETURNERROR, "ERROR - Switch SETSOCKET needs DOOM version 1.1\n");
if (NumNodesActive != DEFAULTNODES && DoomVersion == 0)
Bye (RETURNERROR, "ERROR - Switch SETNODES needs DOOM version 1.1\n");
}
if (DoomVersion >= 5 && DeathmatchOn)
{
DeathmatchOn = FALSE; /* Select the better deathmatch version if available */
DeathmatchV2On = TRUE;
}
}
void PrintEpisodes (char HighLite)
/**********************************************************************************************************************************/
/* Pre : 'HighLite' contains the pointed episode, or 0 if none was pointed to. */
/* Post : The episodes have been printed. The active episode has a checked box, all others have empty boxes. The pointed episode */
/* is printed in a different color. */
/* Import: PrText. */
/**********************************************************************************************************************************/
{
for (M = 0 ; M < NUMEPISODE ; M ++)
{
if (M == HighLite - 1)
PrText ((M == EpisodeActive - 1), 3 + M, 1, LRED, Episodes[M]);
else
PrText ((M == EpisodeActive - 1), 3 + M, 1, LMAGENTA, Episodes[M]);
}
}
void PrintDifficulties (char HighLite)
/**********************************************************************************************************************************/
/* Pre : 'HighLite' contains the pointed difficulty, or 0 if none was pointed to. */
/* Post : The difficulties have been printed. The active difficulty has a checked box, all others have empty boxes. The pointed */
/* difficulty is printed in a different color. */
/* If (global) 'DoomVersion' is less than 1.2, then the difficulty 'Nightmare' (the last in the row) is not printed. */
/* Import: PrText. */
/**********************************************************************************************************************************/
{
int MaxDiff;
MaxDiff = (DoomVersion >= 2) ? NUMDIFFICULTY : NUMDIFFICULTY - 1; /* NIGHTMARE only available from v1.2 */
for (M = 0 ; M < MaxDiff ; M ++)
{
if (M == HighLite - 1)
PrText ((M == DifficultyActive - 1), 3 + M, 28, LRED, Difficulties[M]);
else
PrText ((M == DifficultyActive - 1), 3 + M, 28, LMAGENTA, Difficulties[M]);
}
if (DoomVersion < 2)
PrText (0, 7, 28, LBLACK, Difficulties[4]);
}
void PrintPlayTypes (char HighLite)
/**********************************************************************************************************************************/
/* Pre : 'HighLite' contains the pointed playtype, or 0 if none was pointed to. */
/* Post : The playtypes have been printed. The active playtype has a checked box, all others have empty boxes. The pointed */
/* playtype is printed in a different color. */
/* Import: PrText. */
/**********************************************************************************************************************************/
{
unsigned char PType[NUMPLAYTYPE] = {LMAGENTA, LMAGENTA, LMAGENTA};
if (DoomVersion == 0) /* Doom v1.0 could only be played alone */
for (M = 0 ; M < NUMPLAYTYPE ; M ++)
PType[M] = LBLACK;
if (DoomVersion == 1)
PType[NUMPLAYTYPE - 1] = LBLACK;
for (M = 0 ; M < NUMPLAYTYPE ; M ++) /* v1.1 had IPX, v1.2 also had modem */
{
if (M == HighLite - 1)
PrText ((M == PlayTypeActive - 1), 3 + M, 55, LRED, PlayTypes[M]);
else
PrText ((M == PlayTypeActive - 1), 3 + M, 55, PType[M], PlayTypes[M]);
}
switch (PlayTypeActive)
{
case 1: PrText (-1, 6, 55, DBLACK, " "); /* Alone */
break;
case 2: if (!OtherIpxDriver) /* IPX compatible */
if (HighLite == 4)
PrText (-1, 6, 55, LRED, "(%c) %s", NumNodesActive + '0', NumberNodes);
else
PrText (-1, 6, 55, LMAGENTA, "(%c) %s", NumNodesActive + '0', NumberNodes);
else
PrText (-1, 6, 55, LBLACK, "(%c) %s", NumNodesActive + '0', NumberNodes);
break;
case 3: if (!OtherSerDriver) /* Null-modem link */
if (HighLite == 4)
PrText (-1, 6, 55, LRED, "(%c) %s", CommPortActive + '0', CommPort);
else
PrText (-1, 6, 55, LMAGENTA, "(%c) %s", CommPortActive + '0', CommPort);
else
PrText (-1, 6, 55, LBLACK, "(%c) %s", CommPortActive + '0', CommPort);
}
}
void PrintRespawnMonsters (boolean HighLite)
/**********************************************************************************************************************************/
/* Pre : 'HighLite' is TRUE if this item was pointed to. */
/* Post : The RESPAWN text has been printed, with a checked box before it if it was selected, or empty otherwise. */
/* If 'HighLite' was TRUE, then the text is printed in a different color. */
/* If (global) 'DoomVersion' is less than 1.2, then nothing has been done here. */
/* Import: PrText. */
/**********************************************************************************************************************************/
{
if (DoomVersion >= 2) /* Respawn only available from v1.2 */
if (HighLite)
PrText (RespMonstersOn, 10, 28, LRED, RespawnMonsters);
else
PrText (RespMonstersOn, 10, 28, LMAGENTA, RespawnMonsters);
else
PrText (RespMonstersOn, 10, 28, LBLACK, RespawnMonsters);
}
void PrintNoMonsters (boolean HighLite)
/**********************************************************************************************************************************/
/* Pre : 'HighLite' is TRUE if this item was pointed to. */
/* Post : The NOMONSTERS text has been printed, with a checked box before it if it was selected, or empty otherwise. */
/* If 'HighLite' was TRUE, then the text is printed in a different color. */
/* If (global) 'DoomVersion' is less than 1.2, then nothing has been done here. */
/* Import: PrText. */
/**********************************************************************************************************************************/
{
if (DoomVersion >= 2) /* NoMonsters only available from v1.2 */
if (HighLite)
PrText (NoMonstersOn, 9, 28, LRED, NoMonsters);
else
PrText (NoMonstersOn, 9, 28, LMAGENTA, NoMonsters);
else
PrText (NoMonstersOn, 9, 28, LBLACK, NoMonsters);
}
void PrintFastMonsters (boolean HighLite)
/**********************************************************************************************************************************/
/* Pre : 'HighLite' is TRUE if this item was pointed to. */
/* Post : The FASTMONSTERS text has been printed, with a checked box before it if it was selected, or empty otherwise. */
/* If 'HighLite' was TRUE, then the text is printed in a different color. */
/* If (global) 'DoomVersion' is less than 1.5, then nothing has been done here. */
/* Import: PrText. */
/**********************************************************************************************************************************/
{
if (DoomVersion >= 5) /* FastMonsters only available from v1.5 */
if (HighLite)
PrText (FastMonstersOn, 11, 28, LRED, FastMonsters);
else
PrText (FastMonstersOn, 11, 28, LMAGENTA, FastMonsters);
else
PrText (FastMonstersOn, 11, 28, LBLACK, FastMonsters);
}
void PrintDeathmatch (boolean HighLite)
/**********************************************************************************************************************************/
/* Pre : 'HighLite' is TRUE if this item was pointed to. */
/* Post : The DEATHMATCH text has been printed, with a checked box before it if it was selected, or empty otherwise. */
/* If 'HighLite' was TRUE, then the text is printed in a different color. */
/* If (global) 'DoomVersion' is less than 1.2, then nothing has been done here. */
/* Import: PrText. */
/**********************************************************************************************************************************/
{
if (DoomVersion >= 2) /* Deathmatch only available from v1.2 */
if (HighLite)
PrText (DeathmatchOn, 8, 55, LRED, Deathmatch);
else
PrText (DeathmatchOn, 8, 55, LMAGENTA, Deathmatch);
else
PrText (DeathmatchOn, 8, 55, LBLACK, Deathmatch);
}
void PrintV2Deathmatch (boolean HighLite)
/**********************************************************************************************************************************/
/* Pre : 'HighLite' is TRUE if this item was pointed to. */
/* Post : The DEATHMATCH V2 text has been printed, with a checked box before it if it was selected, or empty otherwise. */
/* If 'HighLite' was TRUE, then the text is printed in a different color. */
/* If (global) 'DoomVersion' is less than 1.5, then nothing has been done here. */
/* Import: PrText. */
/**********************************************************************************************************************************/
{
if (DoomVersion >= 5) /* Deathmatch only available from v1.2 */
if (HighLite)
PrText (DeathmatchV2On, 9, 55, LRED, DeathmatchV2);
else
PrText (DeathmatchV2On, 9, 55, LMAGENTA, DeathmatchV2);
else
PrText (DeathmatchV2On, 9, 55, LBLACK, DeathmatchV2);
}
void PrintLevel (boolean HighLite)
/**********************************************************************************************************************************/
/* Pre : 'HighLite' is TRUE if this item was pointed to. */
/* Post : The LEVEL text has been printed, with a box before it, containing the current level. */
/* If 'HighLite' was TRUE, then the text is printed in a different color. */
/* Import: PrText. */
/**********************************************************************************************************************************/
{
if (HighLite)
PrText (-1, 7, 1, LRED, "(%c) %s", CurrentLevel + '0', Level);
else
PrText (-1, 7, 1, LMAGENTA, "(%c) %s", CurrentLevel + '0', Level);
}
void PrintWadFiles (void)
/**********************************************************************************************************************************/
/* Pre : None. */
/* Post : The active page with WAD files has been printed (as determined by 'CurrentPage') has been printed. All selected WAD */
/* files are printed in a different color, any unused part of the page has been cleared from the screen. After each name */
/* is the read info printed. Highliting of a pointed wadfile is not handled here. */
/* Import: PrText. */
/**********************************************************************************************************************************/
{
int PositionX;
int PositionY;
for (M = CurrentPage * PAGE ; M < (CurrentPage + 1) * PAGE ; M += WADHEIGHT) /* Handle each column */
for (N = M ; N < M + WADHEIGHT ; N ++) /* Handle each row in the column */
{
PositionY = 13 + (N % WADHEIGHT);
PositionX = ((M - CurrentPage * PAGE) / WADHEIGHT) * WADWIDTH + 1;
if (N < TotalWads) /* WAD file number exists ? */
{
if (WadInfo[N]->Selected)
PrText (-1, PositionY, PositionX, DGREEN, WadInfo[N]->Name); /* Print filename */
else
PrText (-1, PositionY, PositionX, DWHITE, WadInfo[N]->Name);
PrText (-1, PositionY, PositionX + _MAX_FNAME, DCYAN, WadInfo[N]->Info); /* Print info */
}
else /* WAD file number after the last WAD file */
PrText (-1, PositionY, PositionX, DBLACK, " "); /* Clear this screen part */
}
}
void PrintPagers (char HighLite)
/**********************************************************************************************************************************/
/* Pre : 'HighLite' is 1 for left, 2 for right or 0 for no pager. */
/* Post : The pagers have been printed. The 'HighLite' pager in a different color. */
/* Import: PrText. */
/**********************************************************************************************************************************/
{
if (CurrentPage > 0) /* Are there previous pages ? */
if (HighLite == 1) /* Print pager for 'previous' page (left) */
PrText (-1, 11, 60, LRED, PreviousPage);
else
PrText (-1, 11, 60, LWHITE, PreviousPage);
else
PrText (-1, 11, 60, LBLACK, PreviousPage);
if (CurrentPage < LastPage) /* Are there next pages ? */
if (HighLite == 2) /* Print pager for 'next' page (right) */
PrText (-1, 11, 78, LRED, NextPage);
else
PrText (-1, 11, 78, LWHITE, NextPage);
else
PrText (-1, 11, 78, LBLACK, NextPage);
}
void PrintRdPrev (boolean HighLite)
/**********************************************************************************************************************************/
/* Pre : 'HighLite' is TRUE if this item is selected. */
/* Post : The read previous text has been printed. If 'HighLite' was TRUE, than in a different color. */
/* Import: PrText. */
/**********************************************************************************************************************************/
{
if (HighLite)
PrText (-1, 11, 1, LRED, ReadPrevious);
else
PrText (-1, 11, 1, LMAGENTA, ReadPrevious);
}
void PrintAutomatic (boolean HighLite)
/**********************************************************************************************************************************/
/* Pre : 'HighLite' is TRUE if this item is selected. */
/* Post : The automatic text has been printed. If 'HighLite' was TRUE, than in a different color. */
/* Import: PrText. */
/**********************************************************************************************************************************/
{
if (HighLite)
PrText (-1, 10, 1, LRED, Automatic);
else
PrText (-1, 10, 1, LMAGENTA, Automatic);
}
void PrintStart (boolean HighLite)
/**********************************************************************************************************************************/
/* Pre : 'HighLite' is TRUE if this item is selected. */
/* Post : The start text has been printed. If 'HighLite' was TRUE, than in a different color. */
/* Import: PrText. */
/**********************************************************************************************************************************/
{
if (HighLite)
PrText (-1, 9, 1, LRED, StartGame);
else
PrText (-1, 9, 1, LMAGENTA, StartGame);
}
void UnselectPreviousField (char SkipFieldNum)
/**********************************************************************************************************************************/
/* Pre : 'SkipFieldNum' holds the field number that should NOT be unselected. */
/* Post : The previous selected field has been unselected, if one was pointed to and it was not 'SkipFieldNum'. */
/* Import: PrintEpisodes, PrintDifficulties, PrintPlayTypes, PrintLevel, PrintDeathmatch, PrintPagers, PrintRdPrev, PrintStart, */
/* PrintAutomatic, PrintDeathmatchV2, PrintRespawnMonsters, PrintNoMonsters, PrintFastMonsters, PrText, HideMouse, */
/* ShowMouse. */
/**********************************************************************************************************************************/
{
int PositionX;
int PositionY;
int OldWadNumber;
if (CurrentField != NOFIELD && CurrentField != SkipFieldNum)
{
switch (CurrentField)
{
case EPISODEFIELD : PrintEpisodes (0);
break;
case DIFFICULTYFIELD : PrintDifficulties (0);
break;
case PLAYTYPEFIELD : PrintPlayTypes (0);
break;
case LEVELFIELD : PrintLevel (FALSE);
break;
case DEATHMATCHFIELD : PrintDeathmatch (FALSE);
break;
case DEATHMATCHV2FIELD : PrintV2Deathmatch (FALSE);
break;
case RESPAWNFIELD : PrintRespawnMonsters (FALSE);
break;
case NOMONSTERSFIELD : PrintNoMonsters (FALSE);
break;
case FASTMONSTERSFIELD : PrintFastMonsters (FALSE);
break;
case PAGERFIELD : PrintPagers (0);
break;
case RDPREVFIELD : PrintRdPrev (FALSE);
break;
case STARTFIELD : PrintStart (FALSE);
break;
case AUTOMATICFIELD : PrintAutomatic (FALSE);
break;
case FILEFIELD : PositionY = 13 + ((PreviousWad - 1) % WADHEIGHT); /* Location of previously selected WAD */
PositionX = ((PreviousWad - 1) / WADHEIGHT) * WADWIDTH + 1;
OldWadNumber = CurrentPage * PAGE + PreviousWad - 1; /* Number of that WAD */
HideMouse ();
if (WadInfo[OldWadNumber]->Selected)
PrText (-1, PositionY, PositionX, DGREEN, WadInfo[OldWadNumber]->Name);
else
PrText (-1, PositionY, PositionX, DWHITE, WadInfo[OldWadNumber]->Name);
ShowMouse ();
}
}
}
boolean WaitForConfirmation (void)
/**********************************************************************************************************************************/
/* Pre : None. */
/* Post : The user must press a key. If this key is 'Y', then TRUE is returned, otherwise FALSE. */
/* Import: None. */
/**********************************************************************************************************************************/
{
unsigned int Key;
while (!_bios_keybrd (_KEYBRD_READY)) /* Wait for a key */
;
Key = _bios_keybrd (_KEYBRD_READ) & 0x00FF; /* Read pressed key */
return (toupper ((char)Key) == 'Y'); /* Return TRUE if it is 'Y' */
}
boolean Requester (short Y0, short X0, short DY, short DX)
/**********************************************************************************************************************************/
/* Pre : 'Y0' and 'X0' hold the top-left coordinates of the requester that is to be printed. The hight will be 'DY' lines, the */
/* width will be 'DX' columns. */
/* Post : The requester has been drawn. */
/* Note that the requester is surrounded with an empty zone. */
/* Import: HideMouse, UnselectPreviousField, PrText. */
/**********************************************************************************************************************************/
{
HideMouse (); /* Clear mousepointer and hi-light bars */
UnselectPreviousField (NOFIELD);
CurrentField = NOFIELD;
Mouse.CoChange = TRUE; /* Signal: re-hi-light on return */
for (M = 0 ; M < DX ; M ++)
PrText (-1, Y0, X0 + M, DBLACK, " ");
PrText (-1, Y0 + 1, X0, LRED, " \xC9");
for (M = 0 ; M < (DX - 4) ; M ++)
PrText (-1, 0, 0, LRED, "\xCD");
PrText (-1, 0, 0, LRED, "\xBB ");
for (M = 2 ; M < (DY - 2) ; M ++)
{
PrText (-1, Y0 + M, X0, LRED, " \xBA");
for (N = 0 ; N < (DX - 4) ; N ++)
PrText (-1, 0, 0, DBLACK, " ");
PrText (-1, 0, 0, LRED, "\xBA ");
}
PrText (-1, Y0 + DY - 2, X0, LRED, " \xC8");
for (M = 0 ; M < (DX - 4) ; M ++)
PrText (-1, 0, 0, LRED, "\xCD");
PrText (-1, 0, 0, LRED, "\xBC ");
for (M = 0 ; M < DX ; M ++)
PrText (-1, Y0 + DY - 1, X0 + M, DBLACK, " ");
}
void GiveHelp (void)
/**********************************************************************************************************************************/
/* Pre : The user pressed [F1]. */
/* Post : A requester has been drawn, containing a listing of all available keys (depending on DOOM version number and whether a */
/* mouse has been found). The user must press a key to return. */
/* Import: Requester, PrText, WaitForConfirmation, PrintWadFiles, ShowMouse. */
/**********************************************************************************************************************************/
{
Requester (14, 2, 16, 78);
PrText (-1, 17, 24, DCYAN, "The following keys are available:");
PrText (-1, 19, 5, DWHITE, "%c ", KEY_EPISODE);
PrText (-1, 0, 0, DCYAN, "Episode");
PrText (-1, 20, 5, DWHITE, "%c ", KEY_LEVEL);
PrText (-1, 0, 0, DCYAN, "Level");
PrText (-1, 21, 5, DWHITE, "%c ", KEY_DIFFICULTY);
PrText (-1, 0, 0, DCYAN, "Skill");
if (DoomVersion >= 1)
{
PrText (-1, 22, 5, DWHITE, "%c ", KEY_PLAYTYPE);
PrText (-1, 0, 0, DCYAN, "Playtype");
if (!OtherIpxDriver)
{
PrText (-1, 25, 5, DWHITE, "%c ", KEY_NODES);
PrText (-1, 0, 0, DCYAN, "Number of players");
}
}
if (DoomVersion >= 2)
{
PrText (-1, 23, 5, DWHITE, "%c ", KEY_DEATHMATCH);
PrText (-1, 0, 0, DCYAN, "Deathmatch");
if (!OtherSerDriver)
{
PrText (-1, 26, 5, DWHITE, "%c ", KEY_COMPORT);
PrText (-1, 0, 0, DCYAN, "COM port");
}
PrText (-1, 19, 28, DWHITE, "%c ", KEY_NOMONSTERS);
PrText (-1, 0, 0, DCYAN, "No monsters");
PrText (-1, 20, 28, DWHITE, "%c ", KEY_RESPAWNMONST);
PrText (-1, 0, 0, DCYAN, "Respawn monsters");
}
if (DoomVersion >= 5)
{
PrText (-1, 24, 5, DWHITE, "%c ", KEY_DEATHMATCHV2);
PrText (-1, 0, 0, DCYAN, "Deathmatch v2.0");
PrText (-1, 21, 28, DWHITE, "%c ", KEY_FASTMONSTERS);
PrText (-1, 0, 0, DCYAN, "Fast monsters");
}
PrText (-1, 22, 28, DWHITE, "%c ", KEY_AUTO);
PrText (-1, 0, 0, DCYAN, "AUTO SELECT");
PrText (-1, 23, 28, DWHITE, "%c ", KEY_READPREVIOUS);
PrText (-1, 0, 0, DCYAN, "READ PREVIOUS");
PrText (-1, 24, 28, DWHITE, "[ENTER] ");
PrText (-1, 0, 0, DCYAN, "START DOOM!");
PrText (-1, 25, 28, DWHITE, "[ESC] ");
PrText (-1, 0, 0, DCYAN, "Abort EasyWAD");
PrText (-1, 26, 28, DWHITE, "[DEL] ");
PrText (-1, 0, 0, DCYAN, "Delete WAD");
PrText (-1, 19, 55, DWHITE, "[PG UP] ");
PrText (-1, 0, 0, DCYAN, "Next WAD page");
PrText (-1, 20, 55, DWHITE, "[PG DN] ");
PrText (-1, 0, 0, DCYAN, "Previous page");
PrText (-1, 21, 55, DWHITE, "[F1] ");
PrText (-1, 0, 0, DCYAN, "This help page");
PrText (-1, 22, 55, DWHITE, "[F5] ");
PrText (-1, 0, 0, DCYAN, "Rescan WADDIRs");
PrText (-1, 23, 55, DWHITE, "[F7] ");
PrText (-1, 0, 0, DCYAN, "Reset fullname");
PrText (-1, 24, 55, DWHITE, "[F8] ");
PrText (-1, 0, 0, DCYAN, "Resort WADs");
if (!UseMouse)
{
PrText (-1, 25, 55, DWHITE, "[CURS] ");
PrText (-1, 0, 0, DCYAN, "Move around");
PrText (-1, 26, 55, DWHITE, "[SPACE] ");
PrText (-1, 0, 0, DCYAN, "Select WAD");
}
WaitForConfirmation ();
for (M = 15 ; M < 29 ; M ++) /* Erase requester */
PrText (-1, M, 3, DBLACK, " ");
PrintWadFiles ();
ShowMouse ();
}
void SortFiles (void)
/**********************************************************************************************************************************/
/* Pre : None. */
/* Post : If (global) 'SortWadFiles' is TRUE, then the WAD files in memory have been sorted according to the sorttype. */
/* If (global) 'SortByName' is TRUE, then they have been sorted by name, otherwise they have been sorted by info field. */
/* Import: None. */
/**********************************************************************************************************************************/
{
boolean More;
struct WadInfo_s far *TmpPtr; /* Entry as read from the WADINFOFILE */
if (SortWadFiles) /* SORTFILES given in CONFIGFILE ? */
{
More = TRUE;
for (N = 0 ; N < TotalWads - 1 && More ; N ++) /* Perform a bubblesort */
{
More = FALSE;
for (M = 0 ; M < TotalWads - 1 ; M ++)
if (SortByName) /* Sort by 'Name' field */
{
if (strcmp (WadInfo[M]->Name, WadInfo[M + 1]->Name) > 0) /* Next 'larger' than current ? */
{
More = TRUE;
TmpPtr = WadInfo[M]; /* Then flip the pointers */
WadInfo[M] = WadInfo[M + 1];
WadInfo[M + 1] = TmpPtr;
}
}
else /* Sort by 'Info' field */
{
if (strcmp (WadInfo[M]->Info, WadInfo[M + 1]->Info) > 0)
{
More = TRUE;
TmpPtr = WadInfo[M];
WadInfo[M] = WadInfo[M + 1];
WadInfo[M + 1] = TmpPtr;
}
}
}
}
}
void ConvertFullName (struct WadInfo_s far *ConInfo)
/**********************************************************************************************************************************/
/* Pre : 'ConInfo' points to the WadInfo structure that should have its Info field re-examined. */
/* Post : If the Info field contained a full name (e.g. 'music'), then it is converted to the short name (e.g. '- m'). */
/* Before returning, the Info field is expanded to contain exactly MAXINFOLEN characters. */
/* Import: None. */
/**********************************************************************************************************************************/
{
int Index;
int SLNoLevel; /* StrLen NoLevel */
for (Index = strlen (ConInfo->Info) - 1 ; ConInfo->Info[Index] == ' ' && Index > 0 ; Index --) /* Cut trailing spaces */
ConInfo->Info[Index] = '\0';
if (NoFullName) /* Convert full names to short name if wanted */
{
if (!strcmp (ConInfo->Info, IdColors[MAXCOLORS + 1]))
sprintf (ConInfo->Info, "%s%s", NoLevel, IdColors[MAXCOLORS]);
else
if (!strcmp (ConInfo->Info, IdDemos[MAXDEMOS + 1]))
sprintf (ConInfo->Info, "%s%s", NoLevel, IdDemos[MAXDEMOS]);
else
if (!strcmp (ConInfo->Info, IdSounds[MAXSOUNDS + 1]))
sprintf (ConInfo->Info, "%s%s", NoLevel, IdSounds[MAXSOUNDS]);
else
if (!strcmp (ConInfo->Info, IdMusic[MAXMUSIC + 1]))
sprintf (ConInfo->Info, "%s%s", NoLevel, IdMusic[MAXMUSIC]);
else
if (!strcmp (ConInfo->Info, IdSprites[MAXSPRITES + 1]))
sprintf (ConInfo->Info, "%s%s", NoLevel, IdSprites[MAXSPRITES]);
else
if (!strcmp (ConInfo->Info, IdGraphics[MAXGRAPHS + 1]))
sprintf (ConInfo->Info, "%s%s", NoLevel, IdGraphics[MAXGRAPHS]);
}
else
{
SLNoLevel = strlen (NoLevel); /* Just to speed things up a little ... */
if (!strncmp (ConInfo->Info, NoLevel, SLNoLevel))
{
if (!strcmp (ConInfo->Info + SLNoLevel, IdColors[MAXCOLORS]))
strcpy (ConInfo->Info, IdColors[MAXCOLORS + 1]);
else
if (!strcmp (ConInfo->Info + SLNoLevel, IdDemos[MAXDEMOS]))
strcpy (ConInfo->Info, IdDemos[MAXDEMOS + 1]);
else
if (!strcmp (ConInfo->Info + SLNoLevel, IdSounds[MAXSOUNDS]))
strcpy (ConInfo->Info, IdSounds[MAXSOUNDS + 1]);
else
if (!strcmp (ConInfo->Info + SLNoLevel, IdMusic[MAXMUSIC]))
strcpy (ConInfo->Info, IdMusic[MAXMUSIC + 1]);
else
if (!strcmp (ConInfo->Info + SLNoLevel, IdSprites[MAXSPRITES]))
strcpy (ConInfo->Info, IdSprites[MAXSPRITES + 1]);
else
if (!strcmp (ConInfo->Info + SLNoLevel, IdGraphics[MAXGRAPHS]))
strcpy (ConInfo->Info, IdGraphics[MAXGRAPHS + 1]);
}
}
for (Index = strlen (ConInfo->Info) ; Index < MAXINFOLEN ; Index ++) /* Fill info field to maximum */
ConInfo->Info[Index] = ' ';
ConInfo->Info[Index] = '\0';
}
void HandleFileSort (boolean Toggle)
/**********************************************************************************************************************************/
/* Pre : 'Toggle' is TRUE if the sort criterium should be toggled (when called from ToggleFileSort), FALSE if not (when called */
/* from RescanFiles). A requester border should have been previously drawn, together with the top text line. */
/* Post : The question is finished in the requester. The user must confirm the question. If confirmed, then the files are sorted */
/* according to 'Toggle'. If this was TRUE, then the criterium is toggled from "NAME" to "INFO" first. Afterward the */
/* requester has been removed and the files reprinted (if the sort was done, then page 1 is automatically selected). */
/* Import: WaitForConfirmation, PrintWadFiles, ShowMouse, SortFiles, PrText, PrintPagers. */
/**********************************************************************************************************************************/
{
PrText (-1, 20, 32, LRED, "RESORT THE FILES ?");
PrText (-1, 22, 31, DRED, "PRESS <Y> TO CONFIRM");
if (!WaitForConfirmation ()) /* Acknowledged ? */
{ /* Step out if not */
for (M = 16 ; M < 25 ; M ++) /* Erase requester */
PrText (-1, M, 26, DBLACK, " ");
PrintWadFiles ();
ShowMouse ();
return;
}
if (Toggle)
{
SortWadFiles = TRUE;
SortByName = !SortByName; /* Toggle between "NAME" and "INFO" */
}
PrText (-1, 18, 29, DRED, " ");
PrText (-1, 20, 32, LRED, " Sorting ... ");
PrText (-1, 22, 31, DRED, " ");
SortFiles ();
for (M = 16 ; M < 25 ; M ++) /* Erase requester */
PrText (-1, M, 26, DBLACK, " ");
CurrentPage = 0;
CurrentSelected = 0;
PrintPagers (0);
PrintWadFiles ();
ShowMouse ();
}
void ToggleFileSort (void)
/**********************************************************************************************************************************/
/* Pre : The user pressed [F8]. */
/* Post : A requester has been drawn to confirm the action. If this was acknowledged, then the file sort criterium has been */
/* toggled, the files have been resorted and reprinted. */
/* Import: Requester, PrText, HandleFileSort. */
/**********************************************************************************************************************************/
{
Requester (15, 25, 11, 32);
PrText (-1, 18, 29, DRED, "ARE YOU SURE YOU WANT TO");
HandleFileSort (TRUE);
}
void RescanFiles (void)
/**********************************************************************************************************************************/
/* Pre : The user pressed [F5]. */
/* Post : A requester has been drawn to confirm the action. If this was acknowledged, then all files that are currently in */
/* memory have been rescanned, and the result has been written to the WADINFOFILE. After this, the user has been asked if */
/* the files should be resorted. At the end, all files are reprinted on screen. */
/* Import: Requester, PrText, HandleFileSort, GetWadInfo, WriteWadInfo, WaitForConfirmation, ShowMouse, ConvertFullName. */
/**********************************************************************************************************************************/
{
int CountWadFiles;
Requester (15, 25, 11, 32);
PrText (-1, 18, 29, DRED, "ARE YOU SURE YOU WANT TO");
PrText (-1, 20, 32, LRED, "RESCAN THE FILES ?");
PrText (-1, 22, 31, DRED, "PRESS <Y> TO CONFIRM");
if (!WaitForConfirmation ()) /* Acknowledged ? */
{ /* Step out if not */
for (M = 16 ; M < 25 ; M ++) /* Erase requester */
PrText (-1, M, 26, DBLACK, " ");
PrintWadFiles ();
ShowMouse ();
return;
}
PrText (-1, 18, 29, DRED, " ");
PrText (-1, 20, 32, LRED, " Searching ... ");
PrText (-1, 22, 31, DRED, " ");
for (CountWadFiles = 0 ; CountWadFiles < TotalWads ; CountWadFiles ++)
GetWadInfo (CountWadFiles, TRUE); /* Collect information on each WAD file */
PrText (-1, 20, 29, LRED, "Writing WADINFOFILE ... ");
WriteWadInfo (InfoFile); /* Write the result */
for (CountWadFiles = 0 ; CountWadFiles < TotalWads ; CountWadFiles ++)
ConvertFullName (WadInfo[CountWadFiles]); /* Convert full names to short names if wanted */
PrText (-1, 20, 29, LRED, " ");
PrText (-1, 18, 34, DRED, "DO YOU WANT TO");
HandleFileSort (FALSE); /* Handle sorting of the result */
}
void ToggleFullName (void)
/**********************************************************************************************************************************/
/* Pre : The user pressed [F7]. */
/* Post : A requester has been drawn to confirm the action. If this was acknowledged, then the full name criterium has been */
/* toggled, the files have been resorted and reprinted. */
/* Import: Requester, PrText, HandleFileSort. */
/**********************************************************************************************************************************/
{
int CountWadFiles;
Requester (15, 25, 11, 32);
PrText (-1, 18, 29, DRED, "ARE YOU SURE YOU WANT TO");
PrText (-1, 20, 31, LRED, "CONVERT FULL NAMES ?");
PrText (-1, 22, 31, DRED, "PRESS <Y> TO CONFIRM");
if (!WaitForConfirmation ()) /* Acknowledged ? */
{ /* Step out if not */
for (M = 16 ; M < 25 ; M ++) /* Erase requester */
PrText (-1, M, 26, DBLACK, " ");
PrintWadFiles ();
ShowMouse ();
return;
}
PrText (-1, 18, 29, DRED, " ");
PrText (-1, 20, 31, LRED, " Converting ... ");
PrText (-1, 22, 31, DRED, " ");
NoFullName = !NoFullName; /* Toggle NoFullName flag */
for (CountWadFiles = 0 ; CountWadFiles < TotalWads ; CountWadFiles ++)
ConvertFullName (WadInfo[CountWadFiles]);
PrText (-1, 20, 31, DRED, " ");
PrText (-1, 18, 34, DRED, "DO YOU WANT TO");
HandleFileSort (FALSE); /* Handle sorting of the result */
}
void DeleteWadFile (void)
/**********************************************************************************************************************************/
/* Pre : None. */
/* Post : The user has been asked permission to delete the hi-lighted file. If he/she comfirmed, then the file has been deleted */
/* from disk and memory. If the file is protected on disk, then nothing is done. */
/* Import: Requester, PrintWadFiles, ShowMouse, UnselectPreviousWad, WaitForConfirmation. */
/**********************************************************************************************************************************/
{
int DeleteWadNumber;
if (CurrentField != FILEFIELD) /* Return immediately if no file appointed */
return;
DeleteWadNumber = CurrentPage * PAGE + CurrentSelected - 1; /* Determine the WAD number */
Requester (15, 25, 11, 32);
PrText (-1, 18, 29, DRED, "ARE YOU SURE YOU WANT TO");
sprintf (S, "DELETE %s", WadInfo[DeleteWadNumber]->Name);
for (M = strlen (S) - 1 ; S[M] == ' ' ; M --)
S[M] = '\0';
strcat (S, " ?");
PrText (-1, 20, 40 - (strlen (S) / 2), LRED, S);
PrText (-1, 22, 31, DRED, "PRESS <Y> TO CONFIRM");
if (!WaitForConfirmation ()) /* Acknowledged ? */
{ /* Step out if not */
for (M = 16 ; M < 25 ; M ++) /* Erase requester */
PrText (-1, M, 26, DBLACK, " ");
PrintWadFiles ();
ShowMouse ();
return;
}
for (M = 16 ; M < 25 ; M ++) /* Erase requester */
PrText (-1, M, 26, DBLACK, " ");
if (WadInfo[DeleteWadNumber]->Drive) /* Build complete path to the file */
sprintf (S, "%c:", ToName (WadInfo[DeleteWadNumber]->Drive));
else
sprintf (S, "%c:", ToName (CurDrive));
if (!strcmp (WadInfo[DeleteWadNumber]->Path, DEFAULTWADDIR))
strcat (S, CurPath + 2);
else
strcat (S, WadInfo[DeleteWadNumber]->Path);
strcat (S, "\\");
strcat (S, WadInfo[DeleteWadNumber]->OrigName);
if (_dos_setfileattr (S, _A_NORMAL)) /* Clear any preventing file attributes */
{ /* Step out if protected from a higher level */
PrintWadFiles ();
ShowMouse ();
return;
}
if (remove (S) == -1) /* Now remove the file from disk */
{ /* Step out if protected from a higher level */
PrintWadFiles ();
ShowMouse ();
return;
}
_ffree (WadInfo[DeleteWadNumber]); /* Remove the file from memory */
for (M = DeleteWadNumber ; M < TotalWads ; M ++) /* Move all files thereafter one back */
WadInfo[M] = WadInfo[M + 1];
TotalWads --;
PrintWadFiles (); /* Print result ... */
ShowMouse ();
}
void HandleFile (unsigned int Key)
/**********************************************************************************************************************************/
/* Pre : 'Key' holds the preesed (raw) key code that caused calling this routine; if (global) 'UseMouse' was FALSE. */
/* Considered keys are the cursor keys and space. If 'UseMouse' was TRUE, than 'Key' is always 0x0000 (dummy). */
/* Post : The mouse pointer was at the bottom of the screen. The pointed filename has been highlighted. If the right mousebutton */
/* was pressed, then the file is selected, which is shown by a different color. If the file was already selected, then it */
/* is now deselected. Selection can only be done once on a button press. To invert the selection, the mouse button must */
/* first be released, and then pressed again. */
/* Import: HideMouse, ShowMouse, UnselectPreviousField. */
/**********************************************************************************************************************************/
{
int PositionX;
int PositionY;
int OldWadNumber;
int NewWadNumber;
UnselectPreviousField (FILEFIELD);
PositionY = 13 + ((PreviousWad - 1) % WADHEIGHT); /* Location of previously selected WAD */
PositionX = ((PreviousWad - 1) / WADHEIGHT) * WADWIDTH + 1;
OldWadNumber = CurrentPage * PAGE + PreviousWad - 1; /* Number of that WAD */
CurrentSelected = 0; /* Signal: no file pointed to */
if (UseMouse)
{
if (Mouse.Xx <= 7) /* Determine the file column */
CurrentSelected = Mouse.Yy - 11;
else
if (Mouse.Xx >= 27 && Mouse.Xx <= 34)
CurrentSelected = Mouse.Yy - 11 + WADHEIGHT;
else
if (Mouse.Xx >= 54 && Mouse.Xx <= 61)
CurrentSelected = Mouse.Yy - 11 + (2 * WADHEIGHT);
if (CurrentPage * PAGE + CurrentSelected > TotalWads) /* Empty screen part */
CurrentSelected = -1;
MouseHidden = FALSE;
if (CurrentField == FILEFIELD && Mouse.CoChange) /* Only unhighlite the previous one if the mouse moved */
{
HideMouse ();
MouseHidden = TRUE; /* Signal: mouse pointer hidden */
if (WadInfo[OldWadNumber]->Selected)
PrText (-1, PositionY, PositionX, DGREEN, WadInfo[OldWadNumber]->Name);
else
PrText (-1, PositionY, PositionX, DWHITE, WadInfo[OldWadNumber]->Name);
}
}
else
{
switch (Key)
{
case KEY_CURSLEFT : if (PreviousWad > WADHEIGHT) /* Possible to go left ? */
CurrentSelected = PreviousWad - WADHEIGHT;
else /* Determine the far right and go there */
if ((CurrentPage * PAGE + PreviousWad + 2 * WADHEIGHT) <= TotalWads)
CurrentSelected = PreviousWad + 2 * WADHEIGHT; /* 3 columns */
else
if ((CurrentPage * PAGE + PreviousWad + WADHEIGHT) <= TotalWads) /* 2 columns */
CurrentSelected = PreviousWad + WADHEIGHT;
else /* Only 1 column; no move possible */
CurrentSelected = PreviousWad;
break;
case KEY_CURSRIGHT : if ((PreviousWad < 2 * WADHEIGHT) && (CurrentPage * PAGE + PreviousWad + WADHEIGHT) <= TotalWads)
CurrentSelected = PreviousWad + WADHEIGHT;
else
CurrentSelected = PreviousWad % WADHEIGHT;
break;
case KEY_CURSUP : if (((PreviousWad - 1) % WADHEIGHT) > 0)
CurrentSelected = PreviousWad - 1;
else
if ((CurrentPage * PAGE + PreviousWad + WADHEIGHT) <= TotalWads)
CurrentSelected = PreviousWad - 1 + WADHEIGHT;
else
CurrentSelected = TotalWads % PAGE;
break;
case KEY_CURSDOWN : if (((PreviousWad - 1) % WADHEIGHT) < (WADHEIGHT - 1))
if ((CurrentPage * PAGE + PreviousWad + 1) <= TotalWads)
CurrentSelected = PreviousWad + 1;
else
CurrentSelected = (TotalWads % PAGE) - (TotalWads % WADHEIGHT) + 1;
else
CurrentSelected = PreviousWad + 1 - WADHEIGHT;
break;
case KEY_SELECTFILE : CurrentSelected = PreviousWad;
}
if (Key != KEY_SELECTFILE) /* Unhighlite the previous one */
if (WadInfo[OldWadNumber]->Selected)
PrText (-1, PositionY, PositionX, DGREEN, WadInfo[OldWadNumber]->Name);
else
PrText (-1, PositionY, PositionX, DWHITE, WadInfo[OldWadNumber]->Name);
}
NewWadNumber = CurrentPage * PAGE + CurrentSelected - 1;
if ((UseMouse && (Mouse.Left && !Mouse.LeftStillPressed && CurrentSelected > 0)) /* Mouse button pressed ? */
|| (Key == KEY_SELECTFILE))
{
WadInfo[NewWadNumber]->Selected = !WadInfo[NewWadNumber]->Selected; /* Invert selection */
SelectionChange = TRUE; /* Signal: screenchange */
}
else
SelectionChange = FALSE;
if (CurrentSelected > 0) /* A (valid) new file is pointed to */
{
if (Mouse.CoChange || SelectionChange || !UseMouse) /* Color change needed ? */
{
PositionY = 13 + ((CurrentSelected - 1) % WADHEIGHT);
PositionX = ((CurrentSelected - 1) / WADHEIGHT) * WADWIDTH + 1;
if (!MouseHidden) /* Hide the mouse if not hidden already */
HideMouse ();
MouseHidden = TRUE;
if (WadInfo[NewWadNumber]->Selected) /* 'Draw' highlite bar */
PrText (-1, PositionY, PositionX, LGREEN, WadInfo[NewWadNumber]->Name);
else
PrText (-1, PositionY, PositionX, LRED, WadInfo[NewWadNumber]->Name);
}
CurrentField = FILEFIELD;
PreviousWad = CurrentSelected;
}
else
CurrentField = NOFIELD;
if (MouseHidden) /* Reprint the mouse pointer if needed */
ShowMouse ();
}
void HandleEpisode (boolean KeyInput)
/**********************************************************************************************************************************/
/* Pre : 'KeyInput' is TRUE if this routine was called because of a keypress. */
/* Post : The mouse pointer was at the episode block. The pointed episode has been highlited. If the mouse button was pressed, */
/* then this episode is selected (and the previous automatically de-selected). The new result is reprinted. */
/* Import: HideMouse, ShowMouse, PrintEpisodes, UnselectPreviousField. */
/**********************************************************************************************************************************/
{
HideMouse ();
if (!KeyInput)
UnselectPreviousField (EPISODEFIELD);
if (Mouse.Left && !Mouse.LeftStillPressed) /* Mouse button pressed ? */
EpisodeActive = Mouse.Yy - 1; /* Make the highlited episode active */
else
if (KeyInput) /* Key pressed */
if (++ EpisodeActive > NUMEPISODE) /* Increase episode number */
EpisodeActive = 1;
if (KeyInput)
if (CurrentField == EPISODEFIELD)
PrintEpisodes (Mouse.Yy - 1);
else
PrintEpisodes (0);
else
{
PrintEpisodes (Mouse.Yy - 1);
CurrentField = EPISODEFIELD;
}
ShowMouse ();
}
void HandleDifficulty (boolean KeyInput)
/**********************************************************************************************************************************/
/* Pre : 'KeyInput' is TRUE if this routine was called because of a keypress. */
/* Post : The mouse pointer was at the difficulty block. The pointed difficulty has been highlited. If the mouse button was */
/* pressed then this difficulty is selected (and the previous automatically de-selected). The new result is reprinted. */
/* Import: HideMouse, ShowMouse, PrintDifficulties, UnselectPreviousField. */
/**********************************************************************************************************************************/
{
int MaxDiff;
MaxDiff = (DoomVersion >= 2) ? NUMDIFFICULTY : NUMDIFFICULTY - 1; /* NIGHTMARE only available from v1.2 */
HideMouse ();
if (!KeyInput)
UnselectPreviousField (DIFFICULTYFIELD);
if (Mouse.Left && !Mouse.LeftStillPressed)
DifficultyActive = Mouse.Yy - 1;
else
if (KeyInput)
if (++ DifficultyActive > MaxDiff)
DifficultyActive = 1;
if (KeyInput)
if (CurrentField == DIFFICULTYFIELD)
PrintDifficulties (Mouse.Yy - 1);
else
PrintDifficulties (0);
else
{
PrintDifficulties (Mouse.Yy - 1);
CurrentField = DIFFICULTYFIELD;
}
ShowMouse ();
}
void HandlePlayType (boolean KeyInput, char Key)
/**********************************************************************************************************************************/
/* Pre : 'KeyInput' is TRUE if this routine was called because of a keypress. */
/* If it was TRUE, then 'Key' holds the (ASCII) keyvalue, otherwise 'Key' holds 0x00 (dummy). */
/* Post : The mouse pointer was at the playtype block. The pointed playtype has been highlited. If the mouse button was pressed */
/* then this playtype is selected (and the previous automatically de-selected). The new result is reprinted. */
/* If the mouse pointer was at the fourth line, than the PlayType parameter of the current PlayType is handled. */
/* Import: HideMouse, ShowMouse, PrintPlayTypes, UnselectPreviousField. */
/**********************************************************************************************************************************/
{
int Mpt;
if (DoomVersion == 0) /* DOOM v1.0 could only be played alone */
return;
HideMouse ();
if (DoomVersion == 1 && Mouse.Yy == 4)
{
UnselectPreviousField (NOFIELD);
CurrentField = NOFIELD;
PrintPlayTypes (0);
ShowMouse ();
return;
}
Mpt = ((DoomVersion >= 2) ? NUMPLAYTYPE : NUMPLAYTYPE - 1); /* v1.1 also had IPX, v1.2 also had modem */
if (!KeyInput)
UnselectPreviousField (PLAYTYPEFIELD);
if (KeyInput)
{
switch (Key)
{
case KEY_PLAYTYPE : if (++ PlayTypeActive > Mpt)
PlayTypeActive = 1;
break;
case KEY_NODES : if (PlayTypeActive == 2 && !OtherIpxDriver) /* IPX compatible */
if (++ NumNodesActive == 5) /* Increase number of players */
NumNodesActive = 2; /* Must be between 2 and 4 */
break;
case KEY_COMPORT : if (PlayTypeActive == 3 && !OtherSerDriver) /* Null-modem link */
if (++ CommPortActive == 5) /* Increase COM port number */
CommPortActive = 1; /* Must be between 1 and 4 */
}
if (CurrentField == PLAYTYPEFIELD)
PrintPlayTypes (Mouse.Yy - 1);
else
PrintPlayTypes (0);
}
else /* Mouse input */
{
if (Mouse.Left && !Mouse.LeftStillPressed)
if (Mouse.Yy <= Mpt + 1) /* Change PlayType ? */
PlayTypeActive = Mouse.Yy - 1;
else
if (PlayTypeActive == 2 && !OtherIpxDriver) /* IPX compatible */
{
if (++ NumNodesActive == 5) /* Increase number of players */
NumNodesActive = 2; /* Must be between 2 and 4 */
}
else
if (PlayTypeActive == 3 && !OtherSerDriver) /* Null-modem link */
{
if (++ CommPortActive == 5) /* Increase COM port number */
CommPortActive = 1; /* Must be between 1 and 4 */
}
PrintPlayTypes (Mouse.Yy - 1);
CurrentField = PLAYTYPEFIELD;
}
ShowMouse ();
}
void HandleRespawnMonsters (boolean KeyInput)
/**********************************************************************************************************************************/
/* Pre : 'KeyInput' is TRUE if this routine was called because of a keypress. */
/* Post : The mouse pointer was at the respawn item. This item has been highlited. If the mouse button was pressed, then the */
/* active value is inverted. The new result is reprinted. */
/* If (global) 'DoomVersion' is less than 1.2, then nothing has been done here. */
/* Import: HideMouse, ShowMouse, PrintRespawnMonsters, PrintNoMonsters, UnselectPreviousField. */
/**********************************************************************************************************************************/
{
HideMouse ();
if (!KeyInput)
UnselectPreviousField (RESPAWNFIELD);
if (DoomVersion >= 2) /* Respawn only available from v1.2 */
{
if ((Mouse.Left && !Mouse.LeftStillPressed) || KeyInput)
if (RespMonstersOn = !RespMonstersOn) /* Toggle the RESPAWN item */
NoMonstersOn = FALSE;
if (KeyInput)
{
PrintRespawnMonsters (CurrentField == RESPAWNFIELD);
PrintNoMonsters (CurrentField == NOMONSTERSFIELD);
}
else
{
PrintRespawnMonsters (TRUE);
PrintNoMonsters (FALSE);
CurrentField = RESPAWNFIELD;
}
}
ShowMouse ();
}
void HandleNoMonsters (boolean KeyInput)
/**********************************************************************************************************************************/
/* Pre : 'KeyInput' is TRUE if this routine was called because of a keypress. */
/* Post : The mouse pointer was at the nomonsters item. This item has been highlited. If the mouse button was pressed, then the */
/* active value is inverted. The new result is reprinted. */
/* If (global) 'DoomVersion' is less than 1.2, then nothing has been done here. */
/* Import: HideMouse, ShowMouse, PrintNoMonsters, PrintRespawnMonsters, PrintFastMonsters, UnselectPreviousField. */
/**********************************************************************************************************************************/
{
HideMouse ();
if (!KeyInput)
UnselectPreviousField (NOMONSTERSFIELD);
if (DoomVersion >= 2) /* NoMonsters only available from v1.2 */
{
if ((Mouse.Left && !Mouse.LeftStillPressed) || KeyInput)
if (NoMonstersOn = !NoMonstersOn) /* Toggle the NOMONSTERS item */
{
RespMonstersOn = FALSE; /* These are contradictionary */
FastMonstersOn = FALSE;
}
if (KeyInput)
{
PrintNoMonsters (CurrentField == NOMONSTERSFIELD);
PrintRespawnMonsters (CurrentField == RESPAWNFIELD);
PrintFastMonsters (CurrentField == FASTMONSTERSFIELD);
}
else
{
PrintNoMonsters (TRUE);
PrintRespawnMonsters (FALSE);
PrintFastMonsters (FALSE);
CurrentField = NOMONSTERSFIELD;
}
}
ShowMouse ();
}
void HandleFastMonsters (boolean KeyInput)
/**********************************************************************************************************************************/
/* Pre : 'KeyInput' is TRUE if this routine was called because of a keypress. */
/* Post : The mouse pointer was at the fastmonsters item. This item has been highlited. If the mouse button was pressed, then */
/* the active value is inverted. The new result is reprinted. */
/* If (global) 'DoomVersion' is less than 1.5, then nothing has been done here. */
/* Import: HideMouse, ShowMouse, PrintFastMonsters, PrintNoMonsters, UnselectPreviousField. */
/**********************************************************************************************************************************/
{
HideMouse ();
if (!KeyInput)
UnselectPreviousField (FASTMONSTERSFIELD);
if (DoomVersion >= 5) /* FastMonsters only available from v1.5 */
{
if ((Mouse.Left && !Mouse.LeftStillPressed) || KeyInput)
if (FastMonstersOn = !FastMonstersOn) /* Toggle the FASTMONSTERS item */
NoMonstersOn = FALSE; /* These are contradictionary */
if (KeyInput)
{
PrintFastMonsters (CurrentField == FASTMONSTERSFIELD);
PrintNoMonsters (CurrentField == NOMONSTERSFIELD);
}
else
{
PrintFastMonsters (TRUE);
PrintNoMonsters (FALSE);
CurrentField = FASTMONSTERSFIELD;
}
}
ShowMouse ();
}
void HandleDeathmatch (boolean KeyInput)
/**********************************************************************************************************************************/
/* Pre : 'KeyInput' is TRUE if this routine was called because of a keypress. */
/* Post : The mouse pointer was at the deathmatch item. This item has been highlited. If the mouse button was pressed, then the */
/* active value is inverted. The new result is reprinted. */
/* If (global) 'DoomVersion' is less than 1.2, then nothing has been done here. */
/* Import: HideMouse, ShowMouse, PrintDeathmatch, UnselectPreviousField, PrintV2Deathmatch. */
/**********************************************************************************************************************************/
{
HideMouse ();
if (!KeyInput)
UnselectPreviousField (DEATHMATCHFIELD);
if (DoomVersion >= 2) /* Deathmatch only available from v1.2 */
{
if ((Mouse.Left && !Mouse.LeftStillPressed) || KeyInput)
if (DeathmatchOn = !DeathmatchOn) /* Toggle the DEATHMATCH item */
DeathmatchV2On = FALSE;
if (KeyInput)
{
PrintDeathmatch (CurrentField == DEATHMATCHFIELD);
PrintV2Deathmatch (CurrentField == DEATHMATCHV2FIELD);
}
else
{
PrintDeathmatch (TRUE);
PrintV2Deathmatch (FALSE);
CurrentField = DEATHMATCHFIELD;
}
}
ShowMouse ();
}
void HandleV2Deathmatch (boolean KeyInput)
/**********************************************************************************************************************************/
/* Pre : 'KeyInput' is TRUE if this routine was called because of a keypress. */
/* Post : The mouse pointer was at the deathmatch item. This item has been highlited. If the mouse button was pressed, then the */
/* active value is inverted. The new result is reprinted. */
/* If (global) 'DoomVersion' is less than 1.5, then nothing has been done here. */
/* Import: HideMouse, ShowMouse, PrintDeathmatch, UnselectPreviousField, PrintV2Deathmatch. */
/**********************************************************************************************************************************/
{
HideMouse ();
if (!KeyInput)
UnselectPreviousField (DEATHMATCHV2FIELD);
if (DoomVersion >= 5) /* Deathmatch v2.0 only available from v1.5 */
{
if ((Mouse.Left && !Mouse.LeftStillPressed) || KeyInput)
if (DeathmatchV2On = !DeathmatchV2On)
DeathmatchOn = FALSE;
if (KeyInput)
{
PrintV2Deathmatch (CurrentField == DEATHMATCHV2FIELD);
PrintDeathmatch (CurrentField == DEATHMATCHFIELD);
}
else
{
PrintV2Deathmatch (TRUE);
PrintDeathmatch (FALSE);
CurrentField = DEATHMATCHV2FIELD;
}
}
ShowMouse ();
}
void HandleLevel (boolean KeyInput)
/**********************************************************************************************************************************/
/* Pre : 'KeyInput' is TRUE if this routine was called because of a keypress. */
/* Post : The mouse pointer was at the level item. This level has been highlited. If the mouse button was pressed, then the */
/* active level is increased. If it exceeded 9, then it is wrapped back to 1. The new result is reprinted. */
/* Import: HideMouse, ShowMouse, PrintLevel, UnselectPreviousField. */
/**********************************************************************************************************************************/
{
HideMouse ();
if (!KeyInput)
UnselectPreviousField (LEVELFIELD);
if ((Mouse.Left && !Mouse.LeftStillPressed) || KeyInput)
if (++ CurrentLevel > NUMLEVEL) /* Increase current level */
CurrentLevel = 1; /* After level 9 comes level 1 again */
if (KeyInput)
PrintLevel (CurrentField == LEVELFIELD);
else
{
CurrentField = LEVELFIELD;
PrintLevel (TRUE);
}
ShowMouse ();
}
void HandlePreviousPage (boolean KeyInput)
/**********************************************************************************************************************************/
/* Pre : 'KeyInput' is TRUE if this routine is entered because the [PAGE UP] key was pressed. */
/* Post : The mouse pointer was at the previouspage item. This item has been highlited. If the mouse button was pressed, then */
/* a test is made if there are previous pages. If not, then the keyboard bell is sound, otherwise the previous page has */
/* been made the current. This new page has been printed. */
/* Import: HideMouse, ShowMouse, PrintWadFiles, PrintPagers, UnselectPreviousField. */
/**********************************************************************************************************************************/
{
if (CurrentPage == 0) /* Step out if there is no previous page */
return;
HideMouse ();
if (!KeyInput)
UnselectPreviousField (PAGERFIELD);
if ((Mouse.Left && !Mouse.LeftStillPressed) || KeyInput)
{
CurrentPage --; /* Go back a page */
PrText (-1, 11, 69, LWHITE, "%2d", CurrentPage + 1);
PrintWadFiles (); /* Print this new page */
if (!UseMouse)
PrText (-1, 13 + ((PreviousWad - 1) % WADHEIGHT),
((PreviousWad - 1) / WADHEIGHT) * WADWIDTH + 1,
LRED, WadInfo[CurrentPage * PAGE + PreviousWad - 1]->Name); /* Hi-light 'new current' WAD file */
}
if (!KeyInput)
{
PrintPagers (1);
CurrentField = PAGERFIELD;
}
else
PrintPagers (CurrentField == PAGERFIELD ? 1 : 0);
ShowMouse ();
}
void HandleNextPage (boolean KeyInput)
/**********************************************************************************************************************************/
/* Pre : 'KeyInput' is TRUE if this routine was called because the user pressed the [PAGE DOWN] key. */
/* Post : The mouse pointer was at the nextpage item. This item has been highlited. If the mouse button was pressed, then a test */
/* is made if there are next pages. If not, then the keyboard bell is sound, otherwise the next page has been made the */
/* current. This new page has been printed. */
/* Import: HideMouse, ShowMouse, PrintWadFiles, PrintPagers, UnselectPreviousField. */
/**********************************************************************************************************************************/
{
if (CurrentPage == LastPage) /* Step out if there is no next page */
return;
HideMouse ();
if (!KeyInput)
UnselectPreviousField (PAGERFIELD);
if ((Mouse.Left && !Mouse.LeftStillPressed) || KeyInput)
{
CurrentPage ++;
PrText (-1, 11, 69, LWHITE, "%2d", CurrentPage + 1);
PrintWadFiles ();
if (!UseMouse)
{
if ((CurrentPage * PAGE + PreviousWad - 1) >= TotalWads) /* If not a full page, then test that the new pointed */
PreviousWad = TotalWads % PAGE; /* WAD file is valid, otherwise set it to the last one */
PrText (-1, 13 + ((PreviousWad - 1) % WADHEIGHT),
((PreviousWad - 1) / WADHEIGHT) * WADWIDTH + 1,
LRED, WadInfo[CurrentPage * PAGE + PreviousWad - 1]->Name); /* Hi-light 'new current' WAD file */
}
}
if (!KeyInput)
{
PrintPagers (2);
CurrentField = PAGERFIELD;
}
else
PrintPagers (CurrentField == PAGERFIELD ? 2 : 0);
ShowMouse ();
}
void HandleReadPrev (boolean KeyInput)
/**********************************************************************************************************************************/
/* Pre : 'KeyInput' is TRUE if this routine was called because of a keypress. */
/* Post : The mouse pointer was at the read previous item. This item has been highlited. If the mouse button was pressed, then */
/* the file 'START.BAT' is read. Each item is set to the read value, all read WAD files are selected. */
/* Import: HideMouse, ShowMouse, PrintRdPrev, PrintEpisodes, PrintDifficulties, PrintPlayTypes, PrintDeathmatch, PrintLevel, */
/* PrintWadFiles, UnselectPreviousField. */
/**********************************************************************************************************************************/
{
FILE *Fp;
char FileName[_MAX_FNAME];
char Directory[_MAX_DIR];
char Tmp[_MAX_DIR];
char DriveNum;
boolean Handled;
boolean Stop;
HideMouse ();
if (!KeyInput)
UnselectPreviousField (RDPREVFIELD);
if (!KeyInput)
{
PrintRdPrev (TRUE);
CurrentField = RDPREVFIELD;
}
if ((Mouse.Left && !Mouse.LeftStillPressed) || KeyInput)
{
Stop = FALSE;
if (!(Fp = fopen (BATFILE, "r"))) /* Open "START.BAT" */
Stop = TRUE;
else
{
EpisodeActive = DEFAULTEPISODE; /* Set all items to their defaults */
DifficultyActive = DEFAULTDIFFICULTY;
PlayTypeActive = DEFAULTPLAYTYPE;
CurrentLevel = DEFAULTLEVEL;
DeathmatchOn = DEFAULTDMATCH;
DeathmatchV2On = DEFAULTDMATCHV2;
RespMonstersOn = DEFAULTRESPAWN;
NoMonstersOn = DEFAULTNOMONSTERS;
FastMonstersOn = DEFAULTFASTMONST;
CommPortActive = DEFAULTCOMPORT;
NumNodesActive = DEFAULTNODES;
for (M = 0 ; M < TotalWads ; M ++) /* Unselect all WAD files */
WadInfo[M]->Selected = FALSE;
fscanf (Fp, "%s", S); /* First read the command */
while (!feof (Fp)
&& stricmp (S, STARTALONE)
&& stricmp (S, STARTIPX) && stricmp (S, IpxDriver)
&& stricmp (S, STARTLINK) && stricmp (S, SerDriver))
fscanf (Fp, "%s", S);
if (!stricmp (S, STARTALONE))
PlayTypeActive = 1;
else
if (!stricmp (S, STARTIPX) || !stricmp (S, IpxDriver))
PlayTypeActive = 2;
else
if (!stricmp (S, STARTLINK) || !stricmp (S, SerDriver))
PlayTypeActive = 3;
else
Stop = TRUE; /* Not a DOOM start command */
if (!Stop)
{
fscanf (Fp, "%s", S);
while (!feof (Fp) && !Stop) /* Handle each parameter */
{
Handled = FALSE;
if (S[0] == '@') /* 'Response' file following */
{
fclose (Fp); /* Close "START.BAT" */
if (!(Fp = fopen (S + 1, "r"))) /* Open the 'Response' file */
Stop = TRUE; /* Stop if the file does not exist */
else
fscanf (Fp, "%s", S); /* Else: read the first string */
}
if (!feof (Fp) && !stricmp (S, NWSOCKET) && !Stop) /* Found '-SOCKET' */
{
fscanf (Fp, "%s", S); /* '-SOCKET' takes a parameter: 0-255 */
if (feof (Fp))
Stop = TRUE;
for (N = 0 ; N < strlen (S) && !Stop ; N ++)
Stop = !isdigit (S[N]);
if (!Stop)
{
NetworkSocket = atoi (S);
Handled = TRUE;
fscanf (Fp, "%s", S);
}
}
if (!feof (Fp) && !stricmp (S, SKILL) && !Stop) /* Found '-SKILL' */
{
fscanf (Fp, "%s", S); /* '-SKILL' takes a parameter: 1-5 */
if (feof (Fp) || strlen (S) != 1 || S[0] < '1' || S[0] > '5')
Stop = TRUE;
else
{
DifficultyActive = S[0] - '0';
Handled = TRUE;
fscanf (Fp, "%s", S);
}
}
if (!feof (Fp) && !stricmp (S, DMATCH) && !Stop) /* Found '-DEATHMATCH' */
{
DeathmatchOn = TRUE;
Handled = TRUE;
fscanf (Fp, "%s", S);
}
if (!feof (Fp) && !stricmp (S, DMATCHV2) && !Stop) /* Found '-ALTDEATH' */
{
DeathmatchV2On = TRUE;
Handled = TRUE;
fscanf (Fp, "%s", S);
}
if (!feof (Fp) && !stricmp (S, NOMONSTERS) && !Stop) /* Found '-NOMONSTERS' */
{
NoMonstersOn = TRUE;
Handled = TRUE;
fscanf (Fp, "%s", S);
}
if (!feof (Fp) && !stricmp (S, RESPAWNMONSTERS) && !Stop) /* Found '-RESPAWN' */
{
RespMonstersOn = TRUE;
Handled = TRUE;
fscanf (Fp, "%s", S);
}
if (!feof (Fp) && !stricmp (S, FASTMONSTERS) && !Stop) /* Found '-FAST' */
{
FastMonstersOn = TRUE;
Handled = TRUE;
fscanf (Fp, "%s", S);
}
if (!feof (Fp) && !stricmp (S, DEVPARM) && !Stop) /* Found '-DEVPARM' */
{
Handled = TRUE; /* (Ignore the keyword) */
fscanf (Fp, "%s", S);
}
if (!feof (Fp) && !stricmp (S, GOTOANYTHING) && !Stop) /* Found '-WARP' */
{
fscanf (Fp, "%s", S); /* '-WARP' takes two parameters: episode (1-3) and level (1-9) */
if (feof (Fp) || strlen (S) != 1 || S[0] < '1' || S[0] > '3')
Stop = TRUE;
else
{
EpisodeActive = S[0] - '0';
fscanf (Fp, "%s", S);
if (feof (Fp) || strlen (S) != 1 || S[0] < '1' || S[0] > '9')
Stop = TRUE;
else
{
CurrentLevel = S[0] - '0';
Handled = TRUE;
fscanf (Fp, "%s", S);
}
}
}
if (!feof (Fp) && !strnicmp (S, COMPORT, 4) && !Stop) /* Found '-COM#' */
{
if (strlen (S) != 5 || S[4] < '1' || S[0] > '4') /* COM port number is last char in this string */
Stop = TRUE; /* Port number must be between 1-4 */
else
{
CommPortActive = S[4] - '0';
Handled = TRUE;
fscanf (Fp, "%s", S);
}
}
if (!feof (Fp) && !stricmp (S, NUMPLAYERS) && !Stop) /* Found '-NODES' */
{
fscanf (Fp, "%s", S); /* '-NODES' takes a parameter: 2-4 */
if (feof (Fp) || strlen (S) != 1 || S[0] < '2' || S[0] > '4')
Stop = TRUE;
else
{
NumNodesActive = S[0] - '0';
Handled = TRUE;
fscanf (Fp, "%s", S);
}
}
if (!feof (Fp) && !stricmp (S, GOTOEPISODE) && !Stop) /* Found '-EPISODE' */
{
fscanf (Fp, "%s", S); /* '-EPISODE' takes a parameter: 1-3 */
if (feof (Fp) || strlen (S) != 1 || S[0] < '1' || S[0] > '3')
Stop = TRUE;
else
{
EpisodeActive = S[0] - '0';
Handled = TRUE;
fscanf (Fp, "%s", S);
}
}
if (!feof (Fp) && !stricmp (S, INCFILE) && !Stop) /* Found '-FILE' */
{
fscanf (Fp, "%s", S); /* Read-ahead first filename (at least 1 needed) */
do /* Each following word is a filename, until the */
{ /* next keyword is found or EOF is encountered */
if (!feof (Fp) && !Stop)
{
DriveNum = DoomDrive; /* Assume: not preceded by a drive: */
if (S[1] == ':') /* Preceded by drive: */
if (toupper (S[0]) < 'A' || toupper (S[0]) > 'Z')
Stop = TRUE;
else
{
DriveNum = ToNumber (S[0]);
for (M = 2 ; M <= strlen (S) ; M ++) /* Cut drive */
S[M - 2] = S[M];
}
if (!Stop)
if (stricmp (S + strlen (S) - 4, ".WAD")) /* Filename MUST end with '.WAD' */
Stop = TRUE;
if (!Stop)
{
S[strlen (S) - 4] = '\0'; /* Cut the '.WAD' from the filename */
M = strlen (S);
if (!M || S[M - 1] == '\\') /* Ended with a '\' or no filename at all */
Stop = TRUE;
else
{
while (S[-- M] != '\\' && M >= 0)
;
if (M >= 0) /* Preceded by path */
{
if (M == 0)
strcpy (Directory, "\\"); /* Handle root differently */
else
{
strncpy (Directory, strupr (S), M);
Directory[M] = '\0';
if (DriveNum == DoomDrive && Directory[0] != '\\')
{
sprintf (Tmp, "%s\\%s", DoomDirectory, Directory);
strcpy (Directory, Tmp);
}
}
strcpy (FileName, strupr (S) + M + 1);
}
else /* No path */
{
strcpy (FileName, strupr (S));
if (DriveNum == DoomDrive)
strcpy (Directory, DoomDirectory);
else
strcpy (Directory, DEFAULTWADDIR);
}
if (strlen (FileName) > 8) /* Filename contains more than 8 characters */
Stop = TRUE;
else
{
for (M = strlen (FileName) ; M < 8 ; M ++) /* Fill out filename to 8 characters */
FileName[M] = ' ';
FileName[M] = '\0';
Handled = FALSE;
for (M = 0 ; M < TotalWads && !Handled; M ++) /* Match against all WAD filenames in memory */
if (WadInfo[M]->Drive == DriveNum)
if (!strcmp (WadInfo[M]->Path, Directory))
if (!strcmp (WadInfo[M]->Name, FileName))
{
Handled = TRUE;
WadInfo[M]->Selected = TRUE; /* If it matches, than auto-select the file */
}
fscanf (Fp, "%s", S); /* Read next */
}
}
}
}
}
while (!feof (Fp) && S[0] != '-' && !Stop);
Handled = TRUE;
}
if (!Handled && !feof (Fp) && !Stop)
fscanf (Fp, "%s", S); /* Other switch: skip */
}
}
fclose (Fp);
if (DoomVersion < 5) /* Reset all functions that have been read, but are for a higher version */
{
FastMonstersOn = FALSE;
DeathmatchV2On = FALSE;
}
if (DoomVersion < 2)
{
DeathmatchOn = FALSE;
RespMonstersOn = FALSE;
NoMonstersOn = FALSE;
CommPortActive = DEFAULTCOMPORT;
if (DifficultyActive == 5)
DifficultyActive = DEFAULTDIFFICULTY;
if (PlayTypeActive == 3 && DoomVersion < 2)
PlayTypeActive = DEFAULTPLAYTYPE;
if (PlayTypeActive == 2 && DoomVersion < 1)
PlayTypeActive = DEFAULTPLAYTYPE;
}
if (DeathmatchOn && DeathmatchV2On) /* -DEATHMATCH -ALTDEATH means deathmatch v2.0 */
DeathmatchOn = FALSE;
if (NoMonstersOn) /* Handle contradictionaries */
{
RespMonstersOn = FALSE;
FastMonstersOn = FALSE;
}
PrintEpisodes (0); /* Redraw the screen with the read items */
PrintLevel (FALSE);
PrintDifficulties (0);
PrintPlayTypes (0);
PrintDeathmatch (FALSE);
PrintV2Deathmatch (FALSE);
PrintNoMonsters (FALSE);
PrintRespawnMonsters (FALSE);
PrintFastMonsters (FALSE);
PrintWadFiles ();
}
}
ShowMouse ();
}
void HandleAutomatic (boolean KeyInput)
/**********************************************************************************************************************************/
/* Pre : 'KeyInput' is TRUE if this routine was called because of a keypress. */
/* Post : The mouse pointer was at the automatic item. This item has been highlited. If the mouse button was pressed, then this */
/* routine reads all selected WAD files and initializes the current episode and level to the lowest ones found. */
/* Import: HideMouse, ShowMouse, PrintAutomatic, PrintEpisodes, PrintLevel, UnselectPreviousField. */
/**********************************************************************************************************************************/
{
long Startpoint;
long LevelMask;
HideMouse ();
if (!KeyInput)
UnselectPreviousField (AUTOMATICFIELD);
if (!KeyInput)
{
PrintAutomatic (TRUE);
CurrentField = AUTOMATICFIELD;
}
ShowMouse ();
if ((Mouse.Left && !Mouse.LeftStillPressed) || KeyInput)
{
Startpoint = 0x00000000;
for (M = 0 ; M < TotalWads ; M ++)
if (WadInfo[M]->Selected) /* Now merge all level information of all selcted WAD files */
{
GetWadInfo (M, TRUE);
Startpoint |= WadInfo[M]->NewLevels;
}
if (Startpoint != 0x00000000) /* Selected files contain new levels ? */
{
CurrentLevel = 0;
EpisodeActive = 1;
LevelMask = 0x00000001;
while ((Startpoint & LevelMask) != LevelMask) /* Search for the lowest episode and level */
{
LevelMask *= 2; /* Shift left */
if (++ CurrentLevel == NUMLEVEL)
{
CurrentLevel = 0;
EpisodeActive ++;
}
}
if (++ CurrentLevel == NUMLEVEL) /* First level is 1, not 0 */
{
CurrentLevel = 1;
EpisodeActive ++;
}
}
else /* No levels in the files */
{
CurrentLevel = 1;
EpisodeActive = 1;
}
PrintEpisodes (0); /* Redraw the screen with the new results */
PrintLevel (0);
}
}
boolean HandleStartGame (boolean KeyInput)
/**********************************************************************************************************************************/
/* Pre : 'KeyInput' is TRUE if this routine was called because of a keypress. */
/* Post : The mouse pointer was at the startgame item. This item has been highlited. If the mouse button was pressed, then this */
/* routine returns FALSE (which effectively means: start the game), otherwise TRUE. */
/* Import: HideMouse, ShowMouse, PrintStart, UnselectPreviousField. */
/**********************************************************************************************************************************/
{
HideMouse ();
UnselectPreviousField (STARTFIELD);
PrintStart (TRUE);
CurrentField = STARTFIELD;
ShowMouse ();
return ((!Mouse.Left || Mouse.LeftStillPressed) && !KeyInput);
}
int main (int argc, char *argv[])
/**********************************************************************************************************************************/
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> MAIN ROUTINE <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
/* Import: ResetMouse, ReadConfig, PrintEpisodes, PrintDifficulties, PrintPlayTypes, PrintDeathmatch, PrintLevel, PrintWadFiles, */
/* PrintPagers, ShowMouse, MouseStatus, HandleEpisode, HandleDifficulty, HandleDeathmatch, HandleLevel, HandleNextPage, */
/* HandlePreviousPage, HideMouse, DeAllocateAll, PrintStart, PrintRdPrev, HandleStartGame, HandleReadPrev, GetWadInfo, */
/* WriteWadInfo, PrintAutomatic, HandleAutomatic, HandlePlayType, UnselectPreviousField, InitVideo, PrintV2Deathmatch, */
/* PrintRespawnMonsters, PrintNoMonsters, PrintFastMonsters, HandleV2Deathmatch, HandleRespawnMonsters, HandleNoMonsters, */
/* HandleFastMonsters, SortFiles, RescanFiles, ToggleFileSort, Bye, PrText. */
/**********************************************************************************************************************************/
{
FILE *Fp;
struct find_t FileBlock;
struct WadInfo_s ReadInfo; /* Entry as read from the WADINFOFILE */
char DrivePath[_MAX_DIR]; /* Current directory of a drive */
char NextArgument; /* Argument number on the command line */
char Ch;
char SepChar; /* Seperation char in START.*; '\n' or ' ' */
boolean SepCharNeeded;
boolean More;
boolean FirstWad; /* First WAD file to include in START.BAT ? */
boolean AutoFound; /* Files given as AUTOINCLUDE paremeters ? */
boolean DriveChanged; /* Handling other drive than the 'home' drive ? */
boolean CLineError = FALSE; /* Nonsense on the command line ? */
boolean DevparmDone = FALSE; /* TRUE if DEVPARM has been included in START.BAT */
unsigned int Key;
free (getcwd (CurPath, _MAX_DIR - 1)); /* Collect current directory */
CurDrive = ToNumber (CurPath[0]); /* Derive current drive */
UseMouse = ResetMouse (); /* Force mouse to re-initialize */
strcpy (ConfigFile, DEFAULTCONFIGFILE);
NextArgument = 0; /* Handle command line arguments */
if (argc > 3) /* (Max number of arguments is 2) */
CLineError = TRUE;
while (++ NextArgument < argc)
if (!stricmp (argv[NextArgument], RESCAN1) || !stricmp (argv[NextArgument], RESCAN2)) /* Handle any -r parameter */
Rescan = TRUE;
else
if (argv[NextArgument][0] == OTHERCONFIGFILE) /* Handle any +file parameter */
{
strcpy (ConfigFile, argv[NextArgument] + 1);
ConfigChange = TRUE;
}
else
CLineError = TRUE;
if (CLineError)
Bye (RETURNERROR, "Usage: EASYWAD [%s] [%cconfig]\n", RESCAN1, OTHERCONFIGFILE);
ReadConfig (); /* Find CONFIGFILE and handle it */
if (!(Fp = fopen (InfoFile, "r"))) /* Test if the InfoFile exists */
Rescan = TRUE; /* No, it should be created */
else
fclose (Fp);
TotalWads = 0;
if (Rescan)
DoNotSearch = FALSE; /* Override if there is no infofile or if '-R' was given */
_dos_setdrive (CurDrive, &Dummy); /* Start from 'home' location (for partial paths) */
chdir (CurPath);
if (!DoNotSearch) /* Search all WADDIR directories ? */
{
printf ("Searching for WAD files ... ");
for (N = 0 ; N < TotalWadDirs ; N ++) /* Handle all given directories */
{
DriveChanged = FALSE;
if (WadDir[N]->Drive) /* Change drive if one was given */
{
_dos_setdrive (WadDir[N]->Drive, &Dummy);
_dos_getdrive (&Dummy);
if (Dummy != WadDir[N]->Drive) /* Check that the change has been made and report any error */
Bye (RETURNERROR, "ERROR - Drive of WADDIR does not exist\n");
DriveChanged = TRUE;
}
free (getcwd (DrivePath, _MAX_DIR - 1)); /* Collect current directory of this drive */
if (strcmp (WadDir[N]->Name, DEFAULTWADDIR)) /* Change directory if the entry was not "." */
if (chdir (WadDir[N]->Name)) /* Report the error if the directory does not exist */
Bye (RETURNERROR, "ERROR - Directory of WADDIR does not exist\n");
More = !_dos_findfirst (WADFILE, ANYATTR, &FileBlock); /* Look-ahead for a WAD file */
while (TotalWads < MAXWADS && More) /* Handle all WAD files in this directory */
{
if ((strcmp (WadDir[N]->Name, DEFAULTWADDIR)
|| (strcmp (FileBlock.name, MAINWAD1) && strcmp (FileBlock.name, MAINWAD2)))
&& FileBlock.size >= sizeof (struct WadHeader_s)) /* Exclude the main DOOM WAD and too small files */
{
if ((WadInfo[TotalWads] = ((struct WadInfo_s far *)_fmalloc ((size_t)sizeof (struct WadInfo_s)))) == NOMEM)
Bye (RETURNERROR, "FATAL ERROR - Out of memory\n");
strcpy (WadInfo[TotalWads]->OrigName, FileBlock.name); /* Copy filename */
strncpy (WadInfo[TotalWads]->Name, FileBlock.name, strlen (FileBlock.name) - 4); /* Copy name, without extension */
for (M = strlen (FileBlock.name) - 4 ; M < 8 ; M ++) /* Fill out to 8 characters */
WadInfo[TotalWads]->Name[M] = ' ';
WadInfo[TotalWads]->Name[M] = '\0'; /* Make it a valid string */
WadInfo[TotalWads]->Drive = WadDir[N]->Drive;
strcpy (WadInfo[TotalWads]->Path, WadDir[N]->Name);
for (M = 0 ; M < MAXINFOLEN ; M ++)
WadInfo[TotalWads]->Info[M] = ' '; /* Initialize the other fields */
WadInfo[TotalWads]->Info[M] = '\0';
WadInfo[TotalWads]->Selected = FALSE;
if (Rescan)
GetWadInfo (TotalWads, FALSE); /* Read out the WAD directory */
TotalWads ++;
}
More = !_dos_findnext (&FileBlock);
}
if (WadDir[N]->DoSubDirs)
{
More = !_dos_findfirst ("*.*", SUBATTR, &FileBlock); /* Look for subdirectories */
while (More)
{
while ((!(FileBlock.attrib & _A_SUBDIR) || (FileBlock.name[0] == '.')) && More) /* Not '.' or '..' */
More = !_dos_findnext (&FileBlock);
if (More)
{
if (TotalWadDirs == MAXWADDIRS)
Bye (RETURNERROR, "ERROR - Too many WADDIR entries, max is %d\n", MAXWADDIRS);
if ((WadDir[TotalWadDirs] = ((struct WadDir_s far *)_fmalloc ((size_t)sizeof (struct WadDir_s)))) == NOMEM)
Bye (RETURNERROR, "FATAL ERROR - Out of memory\n");
WadDir[TotalWadDirs]->Drive = WadDir[N]->Drive; /* Add this directory to the WADDIR list */
sprintf (WadDir[TotalWadDirs]->Name, "%s\\%s", WadDir[N]->Name, FileBlock.name);
WadDir[TotalWadDirs ++]->DoSubDirs = TRUE; /* Signal: recurse */
More = !_dos_findnext (&FileBlock);
}
}
}
chdir (DrivePath); /* Return to the current directory of this drive */
if (DriveChanged)
_dos_setdrive (CurDrive, &Dummy); /* Return to home drive */
}
}
_dos_setdrive (CurDrive, &Dummy); /* Return to home location */
chdir (CurPath);
if (Rescan)
{
printf ("Writing WADINFOFILE ... ");
WriteWadInfo (InfoFile);
}
if (!(Fp = fopen (InfoFile, "r"))) /* Now handle the InfoFile, which should be found */
Bye (RETURNERROR, "ERROR - Drive read error\n");
fscanf (Fp, "%s", S); /* Read-ahead: first part is the drive number */
while (!feof (Fp))
{
ReadInfo.Drive = atoi (S); /* Convert to number */
fscanf (Fp, "%s", ReadInfo.Path); /* Second part is the directory */
fscanf (Fp, "%s ", ReadInfo.OrigName); /* Third part is the filename */
More = TRUE;
for (M = 0 ; M < MAXINFOLEN && More ; M ++) /* Last part is the info. It may contain spaces */
{
fscanf (Fp, "%c", &ReadInfo.Info[M]);
if (ReadInfo.Info[M] == '\n') /* String shorter than maximum ? */
More = FALSE;
}
while (More) /* End of line not yet found */
{
fscanf (Fp, "%c", &Ch);
if (Ch == '\n') /* Read rest of the line out */
More = FALSE;
}
ReadInfo.Info[M] = '\0';
ConvertFullName (&ReadInfo); /* Convert full to short name if wanted */
if (DoNotSearch)
{
if ((WadInfo[TotalWads] = ((struct WadInfo_s far *)_fmalloc ((size_t)sizeof (struct WadInfo_s)))) == NOMEM)
Bye (RETURNERROR, "FATAL ERROR - Out of memory\n");
strcpy (WadInfo[TotalWads]->OrigName, ReadInfo.OrigName); /* Copy filename */
strncpy (WadInfo[TotalWads]->Name, ReadInfo.OrigName, strlen (ReadInfo.OrigName) - 4); /* Copy name, without extension */
for (M = strlen (ReadInfo.OrigName) - 4 ; M < 8 ; M ++) /* Fill out to 8 characters */
WadInfo[TotalWads]->Name[M] = ' ';
WadInfo[TotalWads]->Name[M] = '\0';
WadInfo[TotalWads]->Drive = ReadInfo.Drive;
strcpy (WadInfo[TotalWads]->Path, ReadInfo.Path);
strcpy (WadInfo[TotalWads]->Info, ReadInfo.Info);
WadInfo[TotalWads]->Selected = FALSE;
TotalWads ++;
}
else
{
More = TRUE;
for (M = 0 ; M < TotalWads && More; M ++) /* Match against all read WAD file names */
if (WadInfo[M]->Drive == ReadInfo.Drive)
if (!stricmp (WadInfo[M]->Path, ReadInfo.Path))
if (!stricmp (WadInfo[M]->OrigName, ReadInfo.OrigName))
{
More = FALSE;
strcpy (WadInfo[M]->Info, ReadInfo.Info); /* Copy info field to correct WAD file */
}
}
fscanf (Fp, "%s", S);
}
fclose (Fp);
if (TotalWads == 0) /* Abort the program if no WAD files were found (other than the main DOOM WAD) */
{
remove (InfoFile);
Bye (RETURNERROR, "No WAD files found!\n");
}
SortFiles (); /* Sort the WAD files if that was requested */
N = -1;
while (++ N < TotalAutoInc) /* Handle all AUTOINCLUDE entries */
{
AutoFound = FALSE;
for (M = 0 ; M < TotalWads && !AutoFound ; M ++) /* AUTOINCLUDE file ? Then select it */
if ((WadInfo[M]->Drive == AutoInc[N]->Drive)
&& (!strcmp (WadInfo[M]->Path, AutoInc[N]->Path))
&& (!strcmp (WadInfo[M]->OrigName, AutoInc[N]->OrigName)))
{
WadInfo[M]->Selected = TRUE;
AutoFound = TRUE;
}
}
CurrentPage = 0;
LastPage = TotalWads / PAGE;
InitVideo (); /* Open a VGA screen of 640x480x16 (80x30 characters in text mode) */
ScreenOpen = TRUE; /* Signal: in graphics mode */
PrText (-1, 1, 1, LWHITE, "DOOM EasyWAD v1.11 - (C) 1994 ThunderWare Research Center"); /* Draw the screen */
PrText (-1, 1, 72, DWHITE, "F1 = HELP");
PrText (-1, 11, 64, LWHITE, "PAGE 1 OF %2d", LastPage + 1);
PrintEpisodes (0);
PrintDifficulties (0);
PrintPlayTypes (0);
PrintLevel (FALSE);
PrintDeathmatch (FALSE);
PrintV2Deathmatch (FALSE);
PrintRespawnMonsters (FALSE);
PrintNoMonsters (FALSE);
PrintFastMonsters (FALSE);
PrintWadFiles ();
PrintPagers (0);
PrintRdPrev (FALSE);
PrintAutomatic (FALSE);
PrintStart (FALSE);
if (UseMouse)
{
ShowMouse (); /* Show the mouse pointer */
MouseStatus (); /* Get current mouse status */
Mouse.OldXx = Mouse.Xx; /* Initialize all non-hardware fields */
Mouse.OldYy = Mouse.Yy;
Mouse.CoChange = TRUE;
Mouse.LeftStillPressed = FALSE;
CurrentField = NOFIELD; /* Signal: check FIELD type directly */
}
else
{
CurrentField = FILEFIELD; /* Hi-lighting is only done in the FILEFIELD */
PreviousWad = 1;
PrText (-1, 13, 1, LRED, WadInfo[0]->Name); /* Hi-light the first WAD file */
}
More = TRUE;
while (More) /* Or: while not [START] pressed ... */
{
if (_bios_keybrd (_KEYBRD_READY)) /* Key pressed ? */
{
Key = _bios_keybrd (_KEYBRD_READ); /* Read the key */
if ((Key & 0xFF00) == KEY_PAGEDOWN)
HandlePreviousPage (TRUE);
else
if ((Key & 0xFF00) == KEY_PAGEUP)
HandleNextPage (TRUE);
else
if (!UseMouse /* Only available if no mouse found */
&& ((Key & 0xFF00) == KEY_CURSLEFT
|| (Key & 0xFF00) == KEY_CURSRIGHT
|| (Key & 0xFF00) == KEY_CURSUP
|| (Key & 0xFF00) == KEY_CURSDOWN
|| (Key & 0xFF00) == KEY_SELECTFILE))
HandleFile (Key & 0xFF00);
else
if ((Key & 0xFF00) == KEY_DELETEWAD)
DeleteWadFile ();
else
if ((Key & 0xFF00) == KEY_TOGGLESORT)
ToggleFileSort ();
else
if ((Key & 0xFF00) == KEY_RESCAN)
RescanFiles ();
else
if ((Key & 0xFF00) == KEY_HELP)
GiveHelp ();
else
if ((Key & 0xFF00) == KEY_TOGGLEFULL)
ToggleFullName ();
else
switch (toupper ((char)(Key & 0x00FF)))
{
case KEY_ABORT : Bye (RETURNABORT, "Program aborted - Thank you for using DOOM EasyWAD\n");
case KEY_STARTGAME : More = HandleStartGame (TRUE);
break;
case KEY_EPISODE : HandleEpisode (TRUE);
break;
case KEY_DIFFICULTY : HandleDifficulty (TRUE);
break;
case KEY_LEVEL : HandleLevel (TRUE);
break;
case KEY_DEATHMATCH : HandleDeathmatch (TRUE);
break;
case KEY_DEATHMATCHV2 : HandleV2Deathmatch (TRUE);
break;
case KEY_NOMONSTERS : HandleNoMonsters (TRUE);
break;
case KEY_RESPAWNMONST : HandleRespawnMonsters (TRUE);
break;
case KEY_FASTMONSTERS : HandleFastMonsters (TRUE);
break;
case KEY_NODES :
case KEY_COMPORT :
case KEY_PLAYTYPE : HandlePlayType (TRUE, toupper ((char)(Key & 0x00FF)));
break;
case KEY_AUTO : HandleAutomatic (TRUE);
break;
case KEY_READPREVIOUS : HandleReadPrev (TRUE);
}
}
if (UseMouse && (Mouse.CoChange || Mouse.Left)) /* Mouse moved or left buttonpressed ? */
{
if (Mouse.Yy > 11) /* Find out which FIELD is pointed to and handle that field */
HandleFile (0x0000); /* Signal: no key */
else
if (Mouse.Yy > 1 && Mouse.Yy < 5 && Mouse.Xx < 25)
HandleEpisode (FALSE);
else
if (Mouse.Yy > 1 && Mouse.Yy < ((DoomVersion >= 2) ? 7 : 6) && Mouse.Xx > 26 && Mouse.Xx < 51)
HandleDifficulty (FALSE);
else
if (Mouse.Yy > 1 && Mouse.Yy < 6 && Mouse.Xx > 53)
HandlePlayType (FALSE, 0x00);
else
if (Mouse.Yy == 7 && Mouse.Xx > 53)
HandleDeathmatch (FALSE);
else
if (Mouse.Yy == 8 && Mouse.Xx > 53)
HandleV2Deathmatch (FALSE);
else
if (Mouse.Yy == 8 && Mouse.Xx > 26 && Mouse.Xx < 51)
HandleNoMonsters (FALSE);
else
if (Mouse.Yy == 9 && Mouse.Xx > 26 && Mouse.Xx < 51)
HandleRespawnMonsters (FALSE);
else
if (Mouse.Yy == 10 && Mouse.Xx > 26 && Mouse.Xx < 51)
HandleFastMonsters (FALSE);
else
if (Mouse.Yy == 6 && Mouse.Xx < 25)
HandleLevel (FALSE);
else
if (Mouse.Yy == 10 && Mouse.Xx > 76)
HandleNextPage (FALSE);
else
if (Mouse.Yy == 10 && Mouse.Xx > 58 && Mouse.Xx < 62)
HandlePreviousPage (FALSE);
else
if (Mouse.Yy == 8 && Mouse.Xx < 15)
More = HandleStartGame (FALSE);
else
if (Mouse.Yy == 9 && Mouse.Xx < 15)
HandleAutomatic (FALSE);
else
if (Mouse.Yy == 10 && Mouse.Xx < 15)
HandleReadPrev (FALSE);
else
if (CurrentField != NOFIELD) /* No FIELD was pointed to */
{ /* If previously a FIELD WAS pointed to, then un-highlite that field */
HideMouse ();
UnselectPreviousField (NOFIELD);
ShowMouse ();
CurrentField = NOFIELD;
}
Mouse.OldXx = Mouse.Xx;
Mouse.OldYy = Mouse.Yy;
}
if (UseMouse)
{
MouseStatus ();
if (Mouse.Right)
{
HideMouse ();
Bye (RETURNABORT, "Program aborted - Thank you for using DOOM EasyWAD\n");
}
}
}
HideMouse ();
_setvideomode (_DEFAULTMODE); /* Close the screen */
ScreenOpen = FALSE; /* Signal: in normal mode */
if (!(Fp = fopen (BATFILE, "w"))) /* Open "START.BAT" */
Bye (RETURNERROR, "ERROR - Cannot create file, disk full ?\n");
fprintf (Fp, "@ECHO OFF\n");
if (DoomDrive)
fprintf (Fp, "%c:\n", ToName (DoomDrive));
if (strcmp (DoomDirectory, DEFAULTWADDIR))
fprintf (Fp, "CD %s\n", DoomDirectory);
if (!NoAutoReturn)
fprintf (Fp, "ECHO.| ");
switch (PlayTypeActive) /* Print the correct command to the file */
{
case 1 : fprintf (Fp, "%s", STARTALONE);
break;
case 2 : fprintf (Fp, "%s", IpxDriver);
break;
case 3 : fprintf (Fp, "%s", SerDriver);
}
if (DoomVersion >= 5)
{
fprintf (Fp, " @%s\\%s\n", CurPath, RESPONSEFILE); /* CurPath also contains the drive: part */
if (DoomDrive)
fprintf (Fp, "%c:\n", ToName (CurDrive));
if (strcmp (DoomDirectory, DEFAULTWADDIR))
fprintf (Fp, "CD %s\n", CurPath + 2);
fclose (Fp);
if (!(Fp = fopen (RESPONSEFILE, "w"))) /* Open "START.OPT" */
Bye (RETURNERROR, "ERROR - Cannot create file, disk full ?\n");
SepChar = '\n';
}
else
{
SepChar = ' ';
if (PlayTypeActive != 1)
fprintf (Fp, " ");
}
SepCharNeeded = TRUE;
switch (PlayTypeActive)
{
case 1 : if (DoomVersion >= 5)
SepCharNeeded = FALSE;
break;
case 2 : if (!OtherIpxDriver)
fprintf (Fp, "%s%c%d%c%d", NUMPLAYERS, SepChar, NumNodesActive, SepChar, NetworkSocket);
break;
case 3 : if (!OtherSerDriver)
fprintf (Fp, "%s%d", COMPORT, CommPortActive);
}
if (DifficultyActive != DEFAULTDIFFICULTY) /* Different difficulty ? */
{
if (SepCharNeeded)
fprintf (Fp, "%c", SepChar);
SepCharNeeded = TRUE;
fprintf (Fp, "%s%c%d", SKILL, SepChar, DifficultyActive); /* Then add it */
}
if (DeathmatchOn != DEFAULTDMATCH) /* DEATHMATCH wanted (and implemented) ? */
{
if (SepCharNeeded)
fprintf (Fp, "%c", SepChar);
SepCharNeeded = TRUE;
fprintf (Fp, "%s", DMATCH);
}
if (DeathmatchV2On != DEFAULTDMATCHV2) /* DEATHMATCH v2.0 wanted ? */
{
if (SepCharNeeded)
fprintf (Fp, "%c", SepChar);
SepCharNeeded = TRUE;
fprintf (Fp, "%s%c%s", DMATCH, SepChar, DMATCHV2);
}
if (NoMonstersOn != DEFAULTNOMONSTERS) /* NOMONSTERS wanted ? */
{
if (SepCharNeeded)
fprintf (Fp, "%c", SepChar);
if (!DevparmDone)
{
fprintf (Fp, "%s%c", DEVPARM, SepChar);
DevparmDone = TRUE;
}
SepCharNeeded = TRUE;
fprintf (Fp, "%s", NOMONSTERS);
}
if (RespMonstersOn != DEFAULTRESPAWN) /* RESPAWN wanted ? */
{
if (SepCharNeeded)
fprintf (Fp, "%c", SepChar);
if (!DevparmDone)
{
fprintf (Fp, "%s%c", DEVPARM, SepChar);
DevparmDone = TRUE;
}
SepCharNeeded = TRUE;
fprintf (Fp, "%s", RESPAWNMONSTERS);
}
if (FastMonstersOn != DEFAULTFASTMONST) /* FASTMONSTERS wanted ? */
{
if (SepCharNeeded)
fprintf (Fp, "%c", SepChar);
if (!DevparmDone)
{
fprintf (Fp, "%s%c", DEVPARM, SepChar);
DevparmDone = TRUE;
}
SepCharNeeded = TRUE;
fprintf (Fp, "%s", FASTMONSTERS);
}
if (CurrentLevel != DEFAULTLEVEL) /* Different starting level ? */
{
if (SepCharNeeded)
fprintf (Fp, "%c", SepChar);
if (!DevparmDone)
{
fprintf (Fp, "%s%c", DEVPARM, SepChar);
DevparmDone = TRUE;
}
SepCharNeeded = TRUE;
fprintf (Fp, "%s%c%d%c%d", GOTOANYTHING, SepChar, EpisodeActive, SepChar, CurrentLevel);
}
if (CurrentLevel == DEFAULTLEVEL && EpisodeActive != DEFAULTEPISODE) /* Other episode, but no other level ? */
{
if (SepCharNeeded)
fprintf (Fp, "%c", SepChar);
SepCharNeeded = TRUE;
fprintf (Fp, "%s%c%d", GOTOEPISODE, SepChar, EpisodeActive); /* "-DEVPARM" not needed */
}
for (M = 0 ; M < MAXADDSWITCHES ; M ++) /* Now add the direct switches */
if (ExtCom[M].InUse)
{
if (SepCharNeeded)
fprintf (Fp, "%c", SepChar);
SepCharNeeded = TRUE;
fprintf (Fp, ExtCom[M].Command);
}
FirstWad = TRUE;
strcat (DoomDirectory, "\\");
for (M = 0 ; M < TotalWads ; M ++) /* Add each selected WAD file */
if (WadInfo[M]->Selected)
{
if (FirstWad) /* Before adding the first, add "-FILE" */
{
FirstWad = FALSE;
if (SepCharNeeded)
fprintf (Fp, "%c", SepChar);
fprintf (Fp, "%s", INCFILE);
}
if (WadInfo[M]->Drive && WadInfo[M]->Drive != DoomDrive)
fprintf (Fp, "%c%c:", SepChar, ToName (WadInfo[M]->Drive)); /* Add the drive if found */
else
fprintf (Fp, "%c", SepChar);
if (strcmp (WadInfo[M]->Path, DEFAULTWADDIR))
if (strncmp (WadInfo[M]->Path, DoomDirectory, strlen (DoomDirectory))) /* Subdir of the DOOM directory ? */
fprintf (Fp, "%s\\", WadInfo[M]->Path); /* Add the path if not */
else
if (WadInfo[M]->Drive == DoomDrive) /* Drive matches too ? */
fprintf (Fp, "%s\\", WadInfo[M]->Path + strlen (DoomDirectory)); /* Cut DOOM directory part */
else
fprintf (Fp, "%s\\", WadInfo[M]->Path); /* Add the path if not */
fprintf (Fp, "%s", WadInfo[M]->OrigName); /* Add the filename */
}
fprintf (Fp, "\n"); /* Add the newline */
if (DoomVersion < 5)
{
if (DoomDrive)
fprintf (Fp, "%c:\n", ToName (CurDrive));
if (strcmp (DoomDirectory, DEFAULTWADDIR))
fprintf (Fp, "CD %s\n", CurPath + 2);
}
fclose (Fp); /* Done; free all memory and shut down the program */
DeAllocateAll ();
exit (RETURNSTART);
}