ref: 1c9458bd4fb64dcc74c08041c59a5088ccee9dd8
dir: /m_misc.c/
//**************************************************************************
//**
//** m_misc.c : Heretic 2 : Raven Software, Corp.
//**
//** $Revision: 560 $
//** $Date: 2010-10-20 15:15:39 +0300 (Wed, 20 Oct 2010) $
//**
//**************************************************************************
// HEADER FILES ------------------------------------------------------------
#include "h2stdinc.h"
#include <ctype.h>
#include "h2def.h"
#include "p_local.h"
#include "i_cdmus.h"
#include "soundst.h"
#ifdef __WATCOMC__
#include "i_sound.h"
#endif
#ifdef RENDER3D
#include "ogl_def.h"
#endif
// MACROS ------------------------------------------------------------------
#define MALLOC_CLIB 1
#define MALLOC_ZONE 2
// TYPES -------------------------------------------------------------------
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static int __ReadFile(char const *name, void **buffer, int mallocType);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PUBLIC DATA DEFINITIONS -------------------------------------------------
int myargc;
const char **myargv;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
// CODE --------------------------------------------------------------------
//==========================================================================
//
// 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(const char *check)
{
int i;
for (i = 1; i < myargc; i++)
{
if (!strcmp(check, myargv[i]))
{
return i;
}
}
return 0;
}
//==========================================================================
//
// M_ParmExists
//
// Returns true if the given parameter exists in the program's command
// line arguments, false if not.
//
//==========================================================================
boolean M_ParmExists(const char *check)
{
return M_CheckParm(check) != 0 ? true : false;
}
//==========================================================================
//
// M_ExtractFileBase
//
//==========================================================================
void M_ExtractFileBase(const char *path, char *dest)
{
const char *src;
int length;
src = path + strlen(path) - 1;
if (src <= path)
{
*dest = '\0';
return;
}
// Back up until a \ or the start
while (src != path && src[-1] != '/' && src[-1] != '\\')
src--;
// Copy up to eight characters
memset(dest, 0, 8);
length = 0;
while (*src && *src != '.')
{
if (++length == 9)
{
I_Error("Filename base of %s > 8 chars", path);
}
*dest++ = toupper((int)*src++);
}
}
/*
===============
=
= M_Random
=
= Returns a 0-255 number
=
===============
*/
// This is the new flat distribution table
unsigned char rndtable[256] =
{
201, 1,243, 19, 18, 42,183,203,101,123,154,137, 34,118, 10,216,
135,246, 0,107,133,229, 35,113,177,211,110, 17,139, 84,251,235,
182,166,161,230,143, 91, 24, 81, 22, 94, 7, 51,232,104,122,248,
175,138,127,171,222,213, 44, 16, 9, 33, 88,102,170,150,136,114,
62, 3,142,237, 6,252,249, 56, 74, 30, 13, 21,180,199, 32,132,
187,234, 78,210, 46,131,197, 8,206,244, 73, 4,236,178,195, 70,
121, 97,167,217,103, 40,247,186,105, 39, 95,163, 99,149,253, 29,
119, 83,254, 26,202, 65,130,155, 60, 64,184,106,221, 93,164,196,
112,108,179,141, 54,109, 11,126, 75,165,191,227, 87,225,156, 15,
98,162,116, 79,169,140,190,205,168,194, 41,250, 27, 20, 14,241,
50,214, 72,192,220,233, 67,148, 96,185,176,181,215,207,172, 85,
89, 90,209,128,124, 2, 55,173, 66,152, 47,129, 59, 43,159,240,
239, 12,189,212,144, 28,200, 77,219,198,134,228, 45, 92,125,151,
5, 53,255, 52, 68,245,160,158, 61, 86, 58, 82,117, 37,242,145,
69,188,115, 76, 63,100, 49,111,153, 80, 38, 57,174,224, 71,231,
23, 25, 48,218,120,147,208, 36,226,223,193,238,157,204,146, 31
};
int rndindex = 0;
int prndindex = 0;
unsigned char 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] = H2MININT;
box[BOXBOTTOM] = box[BOXLEFT] = H2MAXINT;
}
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
=
==================
*/
boolean M_WriteFile (char const *name, const void *source, int length)
{
int handle, count;
handle = create (name, OWRITE, 0666);
if (handle < 0)
return false;
count = write (handle, source, length);
close (handle);
if (count < length)
return false;
return true;
}
//==========================================================================
//
// M_ReadFile
//
// Read a file into a buffer allocated using Z_Malloc().
//
//==========================================================================
int M_ReadFile(char const *name, void **buffer)
{
return __ReadFile(name, buffer, MALLOC_ZONE);
}
//==========================================================================
//
// M_ReadFileCLib
//
// Read a file into a buffer allocated using malloc().
//
//==========================================================================
int M_ReadFileCLib(char const *name, void **buffer)
{
return __ReadFile(name, buffer, MALLOC_CLIB);
}
//==========================================================================
//
// ReadFile
//
//==========================================================================
static int __ReadFile(char const *name, void **buffer, int mallocType)
{
int handle, count, length;
void *buf;
Dir *d;
handle = open(name, OREAD);
if (handle == -1)
{
I_Error("Couldn't read file %s", name);
}
d = dirfstat(handle);
if (d == nil)
{
I_Error("Couldn't read file %s", name);
}
length = d->length;
free(d);
if (mallocType == MALLOC_ZONE)
{ // Use zone memory allocation
buf = Z_Malloc(length, PU_STATIC, NULL);
}
else
{ // Use c library memory allocation
buf = malloc(length);
if (buf == NULL)
{
I_Error("Couldn't malloc buffer %d for file %s.",
length, name);
}
}
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, k, idx;
int indexinfile;
char *infile;
char *file;
const char *moreargs[20];
const char *firstargv;
// READ THE RESPONSE FILE INTO MEMORY
handle = fopen(&myargv[i][1], "rb");
if (!handle)
{
printf("\nNo such response file!");
exits("No such response file!");
}
ST_Message("Found response file %s!\n",&myargv[i][1]);
fseek (handle, 0, SEEK_END);
size = ftell(handle);
fseek (handle, 0, SEEK_SET);
file = (char *) malloc (size);
fread (file, size, 1, handle);
fclose (handle);
// KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG
for (idx = 0, k = i + 1; k < myargc; k++)
moreargs[idx++] = myargv[k];
firstargv = myargv[0];
myargv = (const char **) calloc(1, 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 < idx; k++)
myargv[indexinfile++] = moreargs[k];
myargc = indexinfile;
// DISPLAY ARGS
if (M_CheckParm("-debug"))
{
ST_Message("%d command-line args:\n", myargc);
for (k = 1; k < myargc; k++)
{
ST_Message("%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;
int mouseSensitivity;
extern int mouselook;
extern int alwaysrun;
extern int key_right, key_left, key_up, key_down;
extern int key_strafeleft, key_straferight, key_jump;
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 mousebjump;
extern int joybfire;
extern int joybstrafe;
extern int joybuse;
extern int joybspeed;
extern int joybjump;
extern int messageson;
extern int viewwidth, viewheight;
extern int screenblocks;
extern int snd_Channels;
#ifdef __WATCOMC__
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 /* DOS vars */
default_t defaults[] =
{
/* change of order here affects mn_menu.c :
* see, for example, Options3Items there...
*/
{ "mouse_sensitivity", &mouseSensitivity, 5, 0, 50 },
{ "sfx_volume", &snd_MaxVolume, 10, 0, 15 },
{ "music_volume", &snd_MusicVolume, 10, 0, 15 },
{ "key_right", &key_right, KEY_RIGHTARROW, 0, 254 },
{ "key_left", &key_left, KEY_LEFTARROW, 0, 254 },
{ "key_up", &key_up, KEY_UPARROW, 0, 254 },
{ "key_down", &key_down, KEY_DOWNARROW, 0, 254 },
{ "key_strafeleft", &key_strafeleft, ',', 0, 254 },
{ "key_straferight", &key_straferight, '.', 0, 254 },
{ "key_flyup", &key_flyup, KEY_PGUP, 0, 254 },
{ "key_flydown", &key_flydown, KEY_INS, 0, 254 },
{ "key_flycenter", &key_flycenter, KEY_HOME, 0, 254 },
{ "key_lookup", &key_lookup, KEY_PGDN, 0, 254 },
{ "key_lookdown", &key_lookdown, KEY_DEL, 0, 254 },
{ "key_lookcenter", &key_lookcenter, KEY_END, 0, 254 },
{ "key_invleft", &key_invleft, '[', 0, 254 },
{ "key_invright", &key_invright, ']', 0, 254 },
{ "key_useartifact", &key_useartifact, KEY_ENTER, 0, 254 },
{ "key_fire", &key_fire, KEY_RCTRL, 0, 254 },
{ "key_use", &key_use, ' ', 0, 254 },
{ "key_strafe", &key_strafe, KEY_RALT, 0, 254 },
{ "key_speed", &key_speed, KEY_RSHIFT, 0, 254 },
{ "key_jump", &key_jump, '/', 0, 254 },
{ "use_mouse", &usemouse, 1, 0, 1 },
{ "mouseb_fire", &mousebfire, 0, -1, 2 },
{ "mouseb_strafe", &mousebstrafe, 1, -1, 2 },
{ "mouseb_forward", &mousebforward, 2, -1, 2 },
{ "mouseb_jump", &mousebjump, -1, -1, 2 },
{ "use_joystick", &usejoystick, 0, 0, 1 },
{ "joyb_fire", &joybfire, 0, -1, 3 },
{ "joyb_strafe", &joybstrafe, 1, -1, 3 },
{ "joyb_use", &joybuse, 3, -1, 3 },
{ "joyb_speed", &joybspeed, 2, -1, 3 },
{ "joyb_jump", &joybjump, -1, -1, 3 },
{ "screenblocks", &screenblocks, 10, 3, 11 },
{ "usegamma", &usegamma, 0, 0, 4 },
{ "messageson", &messageson, 1, 0, 1 },
{ "mouselook", &mouselook, 1, 0, 2 },
{ "cdaudio", &cdaudio, 0, 0, 1 },
{ "alwaysrun", &alwaysrun, 0, 0, 1 },
{ "snd_channels", &snd_Channels, 3, 3, MAX_CHANNELS },
#ifdef __WATCOMC__
/* the min/max values I added here are pretty much meaningless.
the values used to be set by the DOS version's setup program. */
{ "snd_musicdevice", &snd_DesiredMusicDevice,0, 0, NUM_SCARDS-1 },
{ "snd_sfxdevice", &snd_DesiredSfxDevice, 0, 0, NUM_SCARDS-1 },
{ "snd_sbport", &snd_SBport, 544, 0, 544 },
{ "snd_sbirq", &snd_SBirq, -1, -1, 7 },
{ "snd_sbdma", &snd_SBdma, -1, -1, 7 },
{ "snd_mport", &snd_Mport, -1, -1, 360 }
#endif /* DOS vars */
};
default_str_t default_strings[] =
{
{ "chatmacro0", chat_macros[0] },
{ "chatmacro1", chat_macros[1] },
{ "chatmacro2", chat_macros[2] },
{ "chatmacro3", chat_macros[3] },
{ "chatmacro4", chat_macros[4] },
{ "chatmacro5", chat_macros[5] },
{ "chatmacro6", chat_macros[6] },
{ "chatmacro7", chat_macros[7] },
{ "chatmacro8", chat_macros[8] },
{ "chatmacro9", chat_macros[9] }
};
static int numdefaults, numstrings;
static char defaultfile[MAX_OSPATH];
/*
==============
=
= 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++)
{
v = *defaults[i].location;
fprintf (f, "%s\t\t%i\n", defaults[i].name, v);
}
for (i = 0; i < numstrings; i++)
{
fprintf (f, "%s\t\t\"%s\"\n", default_strings[i].name,
default_strings[i].location);
}
fclose (f);
}
//==========================================================================
//
// M_LoadDefaults
//
//==========================================================================
void M_LoadDefaults(const char *fileName)
{
int i;
int len;
FILE *f;
char def[80];
char strparm[100];
int parm;
numdefaults = sizeof(defaults) / sizeof(defaults[0]);
numstrings = sizeof(default_strings) / sizeof(default_strings[0]);
ST_Message("Loading default settings\n");
// Set everything to base values
for (i = 0; i < numdefaults; i++)
{
*defaults[i].location = defaults[i].defaultvalue;
}
// Make a backup of all default strings
for (i = 0; i < numstrings; i++)
{
default_strings[i].defaultvalue = (char *) calloc(1, 80);
strcpy (default_strings[i].defaultvalue, default_strings[i].location);
}
// Check for a custom config file
i = M_CheckParm("-config");
if (i && i < myargc-1)
{
snprintf(defaultfile, sizeof(defaultfile), "%s%s", basePath, myargv[i + 1]);
ST_Message("config file: %s\n", defaultfile);
}
else
{
snprintf(defaultfile, sizeof(defaultfile), "%s%s", basePath, fileName);
}
// Scan the config file
f = fopen(defaultfile, "r");
if (f)
{
while (!feof(f))
{
if (fscanf(f, "%79s %[^\n]\n", def, strparm) == 2)
{
if (strparm[0] == '"') /* string values */
{
for (i = 0; i < numstrings; i++)
{
if (!strcmp(def, default_strings[i].name))
{
len = (int)strlen(strparm) - 2;
if (len <= 0)
{
default_strings[i].location[0] = '\0';
break;
}
if (len > 79)
{
len = 79;
}
strncpy(default_strings[i].location, strparm + 1, len);
default_strings[i].location[len] = '\0';
break;
}
}
continue;
}
/* numeric values */
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 (parm >= defaults[i].minvalue && parm <= defaults[i].maxvalue)
*defaults[i].location = parm;
break;
}
}
}
}
fclose (f);
}
}
/*
==============================================================================
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 (const char *filename, byte *data, int width, int height, byte *palette)
{
int i, length;
pcx_t *pcx;
byte *pack;
pcx = (pcx_t *) 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
=
==================
*/
#ifdef RENDER3D
void M_ScreenShot (void)
{
OGL_GrabScreen();
}
#else
void M_ScreenShot (void)
{
int i;
byte *linear;
char lbmname[MAX_OSPATH], *p;
byte *pal;
//
// munge planar buffer to linear
//
linear = screens;
//
// find a file name to save it to
//
snprintf (lbmname, sizeof(lbmname), "%shexen00.pcx", basePath);
p = lbmname + strlen(basePath);
for (i = 0; i <= 99; i++)
{
p[5] = i/10 + '0';
p[6] = i%10 + '0';
if (access(lbmname, AEXIST) == -1)
break; // file doesn't exist
}
if (i == 100)
{
P_SetMessage(&players[consoleplayer], "SCREEN SHOT FAILED", false);
return;
}
//
// save the pcx file
//
pal = (byte *)W_CacheLumpName("PLAYPAL", PU_CACHE);
WritePCXfile (lbmname, linear, SCREENWIDTH, SCREENHEIGHT, pal);
P_SetMessage(&players[consoleplayer], "SCREEN SHOT", false);
}
#endif