ref: 15f26fadf4315e0336fd0e2c68e7162c29bbffcb
dir: /src/heretic/m_misc.c/
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 1993-2008 Raven Software
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//-----------------------------------------------------------------------------
// M_misc.c
#ifdef __NeXT__
#include <libc.h>
#else
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#endif
#include <ctype.h>
#include "doomdef.h"
#include "soundst.h"
int myargc;
char **myargv;
//---------------------------------------------------------------------------
//
// FUNC M_ValidEpisodeMap
//
//---------------------------------------------------------------------------
boolean M_ValidEpisodeMap(int episode, int map)
{
if (episode < 1 || map < 1 || map > 9)
{
return false;
}
if (shareware)
{ // Shareware version checks
if (episode != 1)
{
return false;
}
}
else if (ExtendedWAD)
{ // Extended version checks
if (episode == 6)
{
if (map > 3)
{
return false;
}
}
else if (episode > 5)
{
return false;
}
}
else
{ // Registered version checks
if (episode == 4)
{
if (map != 1)
{
return false;
}
}
else if (episode > 3)
{
return false;
}
}
return true;
}
/*
=================
=
= M_CheckParm
=
= Checks for the given parameter in the program's command line arguments
=
= Returns the argument number (1 to argc-1) or 0 if not present
=
=================
*/
int M_CheckParm(char *check)
{
int i;
for (i = 1; i < myargc; i++)
{
if (!strcasecmp(check, myargv[i]))
return i;
}
return 0;
}
/*
===============
=
= M_Random
=
= Returns a 0-255 number
=
===============
*/
unsigned char rndtable[256] = {
0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66,
74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36,
95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188,
52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224,
149, 104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242,
145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0,
175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235,
25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113,
94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75,
136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196,
135, 106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113,
80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241,
24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224,
145, 224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95,
28, 139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226,
71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36,
17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106,
197, 242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136,
120, 163, 236, 249
};
int rndindex = 0;
int prndindex = 0;
int P_Random(void)
{
prndindex = (prndindex + 1) & 0xff;
return rndtable[prndindex];
}
int M_Random(void)
{
rndindex = (rndindex + 1) & 0xff;
return rndtable[rndindex];
}
void M_ClearRandom(void)
{
rndindex = prndindex = 0;
}
void M_ClearBox(fixed_t * box)
{
box[BOXTOP] = box[BOXRIGHT] = MININT;
box[BOXBOTTOM] = box[BOXLEFT] = MAXINT;
}
void M_AddToBox(fixed_t * box, fixed_t x, fixed_t y)
{
if (x < box[BOXLEFT])
box[BOXLEFT] = x;
else if (x > box[BOXRIGHT])
box[BOXRIGHT] = x;
if (y < box[BOXBOTTOM])
box[BOXBOTTOM] = y;
else if (y > box[BOXTOP])
box[BOXTOP] = y;
}
/*
==================
=
= M_WriteFile
=
==================
*/
#ifndef O_BINARY
#define O_BINARY 0
#endif
boolean M_WriteFile(char const *name, void *source, int length)
{
int handle, count;
handle = open(name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
if (handle == -1)
return false;
count = write(handle, source, length);
close(handle);
if (count < length)
return false;
return true;
}
/*
==================
=
= M_ReadFile
=
==================
*/
int M_ReadFile(char const *name, byte ** buffer)
{
int handle, count, length;
struct stat fileinfo;
byte *buf;
handle = open(name, O_RDONLY | O_BINARY, 0666);
if (handle == -1)
I_Error("Couldn't read file %s", name);
if (fstat(handle, &fileinfo) == -1)
I_Error("Couldn't read file %s", name);
length = fileinfo.st_size;
buf = Z_Malloc(length, PU_STATIC, NULL);
count = read(handle, buf, length);
close(handle);
if (count < length)
I_Error("Couldn't read file %s", name);
*buffer = buf;
return length;
}
//---------------------------------------------------------------------------
//
// PROC M_FindResponseFile
//
//---------------------------------------------------------------------------
#define MAXARGVS 100
void M_FindResponseFile(void)
{
int i;
for (i = 1; i < myargc; i++)
{
if (myargv[i][0] == '@')
{
FILE *handle;
int size;
int k;
int index;
int indexinfile;
char *infile;
char *file;
char *moreargs[20];
char *firstargv;
// READ THE RESPONSE FILE INTO MEMORY
handle = fopen(&myargv[i][1], "rb");
if (!handle)
{
printf("\nNo such response file!");
exit(1);
}
printf("Found response file %s!\n", &myargv[i][1]);
fseek(handle, 0, SEEK_END);
size = ftell(handle);
fseek(handle, 0, SEEK_SET);
file = malloc(size);
fread(file, size, 1, handle);
fclose(handle);
// KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG
for (index = 0, k = i + 1; k < myargc; k++)
moreargs[index++] = myargv[k];
firstargv = myargv[0];
myargv = malloc(sizeof(char *) * MAXARGVS);
memset(myargv, 0, sizeof(char *) * MAXARGVS);
myargv[0] = firstargv;
infile = file;
indexinfile = k = 0;
indexinfile++; // SKIP PAST ARGV[0] (KEEP IT)
do
{
myargv[indexinfile++] = infile + k;
while (k < size &&
((*(infile + k) >= ' ' + 1) && (*(infile + k) <= 'z')))
k++;
*(infile + k) = 0;
while (k < size &&
((*(infile + k) <= ' ') || (*(infile + k) > 'z')))
k++;
}
while (k < size);
for (k = 0; k < index; k++)
myargv[indexinfile++] = moreargs[k];
myargc = indexinfile;
// DISPLAY ARGS
if (M_CheckParm("-debug"))
{
printf("%d command-line args:\n", myargc);
for (k = 1; k < myargc; k++)
{
printf("%s\n", myargv[k]);
}
}
break;
}
}
}
//---------------------------------------------------------------------------
//
// PROC M_ForceUppercase
//
// Change string to uppercase.
//
//---------------------------------------------------------------------------
void M_ForceUppercase(char *text)
{
char c;
while ((c = *text) != 0)
{
if (c >= 'a' && c <= 'z')
{
*text++ = c - ('a' - 'A');
}
else
{
text++;
}
}
}
/*
==============================================================================
DEFAULTS
==============================================================================
*/
int usemouse;
int usejoystick;
extern int key_right, key_left, key_up, key_down;
extern int key_strafeleft, key_straferight;
extern int key_fire, key_use, key_strafe, key_speed;
extern int key_flyup, key_flydown, key_flycenter;
extern int key_lookup, key_lookdown, key_lookcenter;
extern int key_invleft, key_invright, key_useartifact;
extern int mousebfire;
extern int mousebstrafe;
extern int mousebforward;
extern int joybfire;
extern int joybstrafe;
extern int joybuse;
extern int joybspeed;
extern int viewwidth, viewheight;
int mouseSensitivity;
extern int screenblocks;
extern char *chat_macros[10];
typedef struct
{
char *name;
int *location;
int defaultvalue;
int scantranslate; // PC scan code hack
int untranslated; // lousy hack
} default_t;
#ifndef __NeXT__
extern int snd_Channels;
extern int snd_DesiredMusicDevice, snd_DesiredSfxDevice;
extern int snd_MusicDevice, // current music card # (index to dmxCodes)
snd_SfxDevice; // current sfx card # (index to dmxCodes)
extern int snd_SBport, snd_SBirq, snd_SBdma; // sound blaster variables
extern int snd_Mport; // midi variables
#endif
default_t defaults[] = {
{"mouse_sensitivity", &mouseSensitivity, 5},
#ifndef __NeXT__
{"sfx_volume", &snd_MaxVolume, 10},
{"music_volume", &snd_MusicVolume, 10},
#endif
#ifdef __WATCOMC__
#define SC_UPARROW 0x48
#define SC_DOWNARROW 0x50
#define SC_LEFTARROW 0x4b
#define SC_RIGHTARROW 0x4d
#define SC_RCTRL 0x1d
#define SC_RALT 0x38
#define SC_RSHIFT 0x36
#define SC_SPACE 0x39
#define SC_COMMA 0x33
#define SC_PERIOD 0x34
#define SC_PAGEUP 0x49
#define SC_INSERT 0x52
#define SC_HOME 0x47
#define SC_PAGEDOWN 0x51
#define SC_DELETE 0x53
#define SC_END 0x4f
#define SC_ENTER 0x1c
{"key_right", &key_right, SC_RIGHTARROW, 1},
{"key_left", &key_left, SC_LEFTARROW, 1},
{"key_up", &key_up, SC_UPARROW, 1},
{"key_down", &key_down, SC_DOWNARROW, 1},
{"key_strafeleft", &key_strafeleft, SC_COMMA, 1},
{"key_straferight", &key_straferight, SC_PERIOD, 1},
{"key_flyup", &key_flyup, SC_PAGEUP, 1},
{"key_flydown", &key_flydown, SC_INSERT, 1},
{"key_flycenter", &key_flycenter, SC_HOME, 1},
{"key_lookup", &key_lookup, SC_PAGEDOWN, 1},
{"key_lookdown", &key_lookdown, SC_DELETE, 1},
{"key_lookcenter", &key_lookcenter, SC_END, 1},
{"key_invleft", &key_invleft, 0x1a, 1},
{"key_invright", &key_invright, 0x1b, 1},
{"key_useartifact", &key_useartifact, SC_ENTER, 1},
{"key_fire", &key_fire, SC_RCTRL, 1},
{"key_use", &key_use, SC_SPACE, 1},
{"key_strafe", &key_strafe, SC_RALT, 1},
{"key_speed", &key_speed, SC_RSHIFT, 1},
#endif
#ifdef __NeXT__
{"key_right", &key_right, KEY_RIGHTARROW},
{"key_left", &key_left, KEY_LEFTARROW},
{"key_up", &key_up, KEY_UPARROW},
{"key_down", &key_down, KEY_DOWNARROW},
{"key_strafeleft", &key_strafeleft, ','},
{"key_straferight", &key_straferight, '.'},
{"key_flyup", &key_flyup, 'u'},
{"key_flydown", &key_flydown, 'j'},
{"key_flycenter", &key_flycenter, 'k'},
{"key_lookup", &key_lookup, 'm'},
{"key_lookdown", &key_lookdown, 'b'},
{"key_lookcenter", &key_lookcenter, 'n'},
{"key_invleft", &key_invleft, '['},
{"key_invright", &key_invright, ']'},
{"key_useartifact", &key_useartifact, 13},
{"key_fire", &key_fire, ' ', 1},
{"key_use", &key_use, 'x', 1},
{"key_strafe", &key_strafe, 'c', 1},
{"key_speed", &key_speed, 'z', 1},
#endif
{"use_mouse", &usemouse, 1},
{"mouseb_fire", &mousebfire, 0},
{"mouseb_strafe", &mousebstrafe, 1},
{"mouseb_forward", &mousebforward, 2},
{"use_joystick", &usejoystick, 0},
{"joyb_fire", &joybfire, 0},
{"joyb_strafe", &joybstrafe, 1},
{"joyb_use", &joybuse, 3},
{"joyb_speed", &joybspeed, 2},
{"screenblocks", &screenblocks, 10},
#ifndef __NeXT__
{"snd_channels", &snd_Channels, 3},
{"snd_musicdevice", &snd_DesiredMusicDevice, 0},
{"snd_sfxdevice", &snd_DesiredSfxDevice, 0},
{"snd_sbport", &snd_SBport, 544},
{"snd_sbirq", &snd_SBirq, -1},
{"snd_sbdma", &snd_SBdma, -1},
{"snd_mport", &snd_Mport, -1},
#endif
{"usegamma", &usegamma, 0},
{"chatmacro0", (int *) &chat_macros[0], (int) HUSTR_CHATMACRO0},
{"chatmacro1", (int *) &chat_macros[1], (int) HUSTR_CHATMACRO1},
{"chatmacro2", (int *) &chat_macros[2], (int) HUSTR_CHATMACRO2},
{"chatmacro3", (int *) &chat_macros[3], (int) HUSTR_CHATMACRO3},
{"chatmacro4", (int *) &chat_macros[4], (int) HUSTR_CHATMACRO4},
{"chatmacro5", (int *) &chat_macros[5], (int) HUSTR_CHATMACRO5},
{"chatmacro6", (int *) &chat_macros[6], (int) HUSTR_CHATMACRO6},
{"chatmacro7", (int *) &chat_macros[7], (int) HUSTR_CHATMACRO7},
{"chatmacro8", (int *) &chat_macros[8], (int) HUSTR_CHATMACRO8},
{"chatmacro9", (int *) &chat_macros[9], (int) HUSTR_CHATMACRO9}
};
int numdefaults;
char *defaultfile;
/*
==============
=
= M_SaveDefaults
=
==============
*/
void M_SaveDefaults(void)
{
int i, v;
FILE *f;
f = fopen(defaultfile, "w");
if (!f)
return; // can't write the file, but don't complain
for (i = 0; i < numdefaults; i++)
{
#ifdef __WATCOMC__
if (defaults[i].scantranslate)
defaults[i].location = &defaults[i].untranslated;
#endif
if (defaults[i].defaultvalue > -0xfff
&& defaults[i].defaultvalue < 0xfff)
{
v = *defaults[i].location;
fprintf(f, "%s\t\t%i\n", defaults[i].name, v);
}
else
{
fprintf(f, "%s\t\t\"%s\"\n", defaults[i].name,
*(char **) (defaults[i].location));
}
}
fclose(f);
}
/*
==============
=
= M_LoadDefaults
=
==============
*/
extern byte scantokey[128];
extern char *basedefault;
void M_LoadDefaults(void)
{
int i, len;
FILE *f;
char def[80];
char strparm[100];
char *newstring;
int parm;
boolean isstring;
//
// set everything to base values
//
numdefaults = sizeof(defaults) / sizeof(defaults[0]);
for (i = 0; i < numdefaults; i++)
*defaults[i].location = defaults[i].defaultvalue;
//
// check for a custom default file
//
i = M_CheckParm("-config");
if (i && i < myargc - 1)
{
defaultfile = myargv[i + 1];
printf("default file: %s\n", defaultfile);
}
else if (cdrom)
{
defaultfile = "c:\\heretic.cd\\heretic.cfg";
}
else
{
defaultfile = basedefault;
}
//
// read the file in, overriding any set defaults
//
f = fopen(defaultfile, "r");
if (f)
{
while (!feof(f))
{
isstring = false;
if (fscanf(f, "%79s %[^\n]\n", def, strparm) == 2)
{
if (strparm[0] == '"')
{
// get a string default
isstring = true;
len = strlen(strparm);
newstring = (char *) malloc(len);
strparm[len - 1] = 0;
strcpy(newstring, strparm + 1);
}
else if (strparm[0] == '0' && strparm[1] == 'x')
sscanf(strparm + 2, "%x", &parm);
else
sscanf(strparm, "%i", &parm);
for (i = 0; i < numdefaults; i++)
if (!strcmp(def, defaults[i].name))
{
if (!isstring)
*defaults[i].location = parm;
else
*defaults[i].location = (int) newstring;
break;
}
}
}
fclose(f);
}
#ifdef __WATCOMC__
for (i = 0; i < numdefaults; i++)
{
if (defaults[i].scantranslate)
{
parm = *defaults[i].location;
defaults[i].untranslated = parm;
*defaults[i].location = scantokey[parm];
}
}
#endif
}
/*
==============================================================================
SCREEN SHOTS
==============================================================================
*/
typedef struct
{
char manufacturer;
char version;
char encoding;
char bits_per_pixel;
unsigned short xmin, ymin, xmax, ymax;
unsigned short hres, vres;
unsigned char palette[48];
char reserved;
char color_planes;
unsigned short bytes_per_line;
unsigned short palette_type;
char filler[58];
unsigned char data; // unbounded
} pcx_t;
/*
==============
=
= WritePCXfile
=
==============
*/
void WritePCXfile(char *filename, byte * data, int width, int height,
byte * palette)
{
int i, length;
pcx_t *pcx;
byte *pack;
pcx = Z_Malloc(width * height * 2 + 1000, PU_STATIC, NULL);
pcx->manufacturer = 0x0a; // PCX id
pcx->version = 5; // 256 color
pcx->encoding = 1; // uncompressed
pcx->bits_per_pixel = 8; // 256 color
pcx->xmin = 0;
pcx->ymin = 0;
pcx->xmax = SHORT(width - 1);
pcx->ymax = SHORT(height - 1);
pcx->hres = SHORT(width);
pcx->vres = SHORT(height);
memset(pcx->palette, 0, sizeof(pcx->palette));
pcx->color_planes = 1; // chunky image
pcx->bytes_per_line = SHORT(width);
pcx->palette_type = SHORT(2); // not a grey scale
memset(pcx->filler, 0, sizeof(pcx->filler));
//
// pack the image
//
pack = &pcx->data;
for (i = 0; i < width * height; i++)
if ((*data & 0xc0) != 0xc0)
*pack++ = *data++;
else
{
*pack++ = 0xc1;
*pack++ = *data++;
}
//
// write the palette
//
*pack++ = 0x0c; // palette ID byte
for (i = 0; i < 768; i++)
*pack++ = *palette++;
//
// write output file
//
length = pack - (byte *) pcx;
M_WriteFile(filename, pcx, length);
Z_Free(pcx);
}
//==============================================================================
/*
==================
=
= M_ScreenShot
=
==================
*/
void M_ScreenShot(void)
{
int i;
byte *linear;
char lbmname[12];
byte *pal;
#ifdef _WATCOMC_
extern byte *pcscreen;
#endif
//
// munge planar buffer to linear
//
#ifdef _WATCOMC_
linear = pcscreen;
#else
linear = screen;
#endif
//
// find a file name to save it to
//
strcpy(lbmname, "HRTIC00.pcx");
for (i = 0; i <= 99; i++)
{
lbmname[5] = i / 10 + '0';
lbmname[6] = i % 10 + '0';
if (access(lbmname, 0) == -1)
break; // file doesn't exist
}
if (i == 100)
I_Error("M_ScreenShot: Couldn't create a PCX");
//
// save the pcx file
//
#ifdef __WATCOMC__
pal = (byte *) Z_Malloc(768, PU_STATIC, NULL);
outp(0x3c7, 0);
for (i = 0; i < 768; i++)
{
*(pal + i) = inp(0x3c9) << 2;
}
#else
pal = (byte *) W_CacheLumpName("PLAYPAL", PU_CACHE);
#endif
WritePCXfile(lbmname, linear, SCREENWIDTH, SCREENHEIGHT, pal);
players[consoleplayer].message = "SCREEN SHOT";
#ifdef __WATCOMC__
Z_Free(pal);
#endif
}