git-subtree-dir: src/dp_doom git-subtree-split: 190992421c7c643afc99d7f7c511c162f65bea85
665 lines
14 KiB
C
665 lines
14 KiB
C
// Emacs style mode select -*- C++ -*-
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Id:$
|
|
//
|
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
|
//
|
|
// 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.
|
|
//
|
|
//
|
|
// $Log:$
|
|
//
|
|
// DESCRIPTION:
|
|
// Main loop menu stuff.
|
|
// Default Config File.
|
|
// PCX Screenshots.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
#include "doomdef.h"
|
|
|
|
#include "z_zone.h"
|
|
|
|
#include "m_swap.h"
|
|
#include "m_argv.h"
|
|
|
|
#include "w_wad.h"
|
|
|
|
#include "i_system.h"
|
|
#include "i_video.h"
|
|
#include "v_video.h"
|
|
|
|
#include "hu_stuff.h"
|
|
|
|
// State.
|
|
#include "doomstat.h"
|
|
|
|
// Data.
|
|
#include "dstrings.h"
|
|
|
|
#include "m_misc.h"
|
|
|
|
//
|
|
// M_DrawText
|
|
// Returns the final X coordinate
|
|
// HU_Init must have been called to init the font
|
|
//
|
|
extern patch_t* hu_font[HU_FONTSIZE];
|
|
|
|
int
|
|
M_DrawText
|
|
( int x,
|
|
int y,
|
|
boolean direct,
|
|
char* string )
|
|
{
|
|
int c;
|
|
int w;
|
|
|
|
while (*string)
|
|
{
|
|
c = toupper(*string) - HU_FONTSTART;
|
|
string++;
|
|
if (c < 0 || c> HU_FONTSIZE)
|
|
{
|
|
x += 4;
|
|
continue;
|
|
}
|
|
|
|
w = SHORT (hu_font[c]->width);
|
|
if (x+w > SCREENWIDTH)
|
|
break;
|
|
if (direct)
|
|
V_DrawPatchDirect(x, y, 0, hu_font[c]);
|
|
else
|
|
V_DrawPatch(x, y, 0, hu_font[c]);
|
|
x+=w;
|
|
}
|
|
|
|
return x;
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// M_WriteFile
|
|
//
|
|
boolean
|
|
M_WriteFile
|
|
( char const* name,
|
|
void* source,
|
|
int length )
|
|
{
|
|
FILE* handle;
|
|
int count;
|
|
|
|
handle = fopen ( name, "wb");
|
|
|
|
if (handle == NULL)
|
|
return false;
|
|
|
|
count = fwrite (source, 1, length, handle);
|
|
fclose (handle);
|
|
|
|
if (count < length)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//
|
|
// M_ReadFile
|
|
//
|
|
int
|
|
M_ReadFile
|
|
( char const* name,
|
|
byte** buffer )
|
|
{
|
|
FILE* handle;
|
|
long count, length;
|
|
byte *buf;
|
|
|
|
handle = fopen (name, "rb");
|
|
if (handle != NULL)
|
|
{
|
|
fseek(handle, 0, SEEK_END);
|
|
length = ftell(handle);
|
|
if (length != -1)
|
|
{
|
|
buf = Z_Malloc (length, PU_STATIC, NULL);
|
|
rewind(handle);
|
|
count = fread (buf, 1, length, handle);
|
|
fclose (handle);
|
|
|
|
if (count == length)
|
|
{
|
|
*buffer = buf;
|
|
return length;
|
|
}
|
|
}
|
|
}
|
|
|
|
I_Error ("Couldn't read file %s", name);
|
|
return -1;
|
|
}
|
|
|
|
|
|
//
|
|
// DEFAULTS
|
|
//
|
|
int usemouse;
|
|
int usejoystick;
|
|
int bmp_screenshots;
|
|
|
|
extern int key_right;
|
|
extern int key_left;
|
|
extern int key_up;
|
|
extern int key_down;
|
|
|
|
extern int key_strafeleft;
|
|
extern int key_straferight;
|
|
|
|
extern int key_fire;
|
|
extern int key_use;
|
|
extern int key_strafe;
|
|
extern int key_speed;
|
|
|
|
extern int mousebfire;
|
|
extern int mousebstrafe;
|
|
extern int mousebforward;
|
|
|
|
extern int joybfire;
|
|
extern int joybstrafe;
|
|
extern int joybuse;
|
|
extern int joybspeed;
|
|
|
|
extern int viewwidth;
|
|
extern int viewheight;
|
|
|
|
extern int mouseSensitivity;
|
|
extern int showMessages;
|
|
|
|
extern int novert;
|
|
extern int always_run;
|
|
|
|
extern int detailLevel;
|
|
|
|
extern int screenblocks;
|
|
|
|
extern int aspect_ratio_correction;
|
|
|
|
extern int showMessages;
|
|
|
|
// machine-independent sound params
|
|
extern int numChannels;
|
|
|
|
extern const char* wildmidi_config_path;
|
|
|
|
extern const char* chat_macros[];
|
|
|
|
|
|
|
|
typedef struct
|
|
{
|
|
const char* name;
|
|
int* location;
|
|
size_t defaultvalue;
|
|
boolean is_string;
|
|
// int scantranslate; // PC scan code hack
|
|
// int untranslated; // lousy hack
|
|
} default_t;
|
|
|
|
default_t defaults[] =
|
|
{
|
|
/* General */
|
|
{"show_messages",&showMessages, 1, false},
|
|
{"novert",&novert, 1, false},
|
|
{"always_run",&always_run, 1, false},
|
|
{"bmp_screenshots",&bmp_screenshots, 1, false},
|
|
|
|
/* Keyboard */
|
|
/* Movement */
|
|
{"key_right",&key_right, ',', false},
|
|
{"key_left",&key_left, '.', false},
|
|
{"key_up",&key_up, 'w', false},
|
|
{"key_down",&key_down, 's', false},
|
|
{"key_strafeleft",&key_strafeleft, 'a', false},
|
|
{"key_straferight",&key_straferight, 'd', false},
|
|
/* Actions */
|
|
{"key_fire",&key_fire, KEY_RCTRL, false},
|
|
{"key_use",&key_use, ' ', false},
|
|
{"key_strafe",&key_strafe, KEY_RALT, false},
|
|
{"key_speed",&key_speed, KEY_RSHIFT, false},
|
|
|
|
/* Mouse */
|
|
{"use_mouse",&usemouse, 1, false},
|
|
{"mouseb_fire",&mousebfire,0, false},
|
|
{"mouseb_strafe",&mousebstrafe,1, false},
|
|
{"mouseb_forward",&mousebforward,2, false},
|
|
{"mouse_sensitivity",&mouseSensitivity, 5, false},
|
|
|
|
/* Joystick */
|
|
{"use_joystick",&usejoystick, 0, false},
|
|
{"joyb_fire",&joybfire,0, false},
|
|
{"joyb_strafe",&joybstrafe,1, false},
|
|
{"joyb_use",&joybuse,3, false},
|
|
{"joyb_speed",&joybspeed,2, false},
|
|
|
|
/* Video */
|
|
{"screenblocks",&screenblocks, 10, false},
|
|
{"detaillevel",&detailLevel, 0, false},
|
|
{"usegamma",&usegamma, 0, false},
|
|
{"aspect_ratio_correction",&aspect_ratio_correction, 1, false},
|
|
|
|
/* Audio */
|
|
{"music_volume",&musicVolume, 8, false},
|
|
{"sfx_volume",&sfxVolume, 8, false},
|
|
{"snd_channels",&numChannels, 8, false},
|
|
{"wildmidi_config_path", (int*)&wildmidi_config_path, (size_t)"wildmidi.cfg", true },
|
|
|
|
/* Chat macros */
|
|
{"chatmacro0", (int *) &chat_macros[0], (size_t) HUSTR_CHATMACRO0, true },
|
|
{"chatmacro1", (int *) &chat_macros[1], (size_t) HUSTR_CHATMACRO1, true },
|
|
{"chatmacro2", (int *) &chat_macros[2], (size_t) HUSTR_CHATMACRO2, true },
|
|
{"chatmacro3", (int *) &chat_macros[3], (size_t) HUSTR_CHATMACRO3, true },
|
|
{"chatmacro4", (int *) &chat_macros[4], (size_t) HUSTR_CHATMACRO4, true },
|
|
{"chatmacro5", (int *) &chat_macros[5], (size_t) HUSTR_CHATMACRO5, true },
|
|
{"chatmacro6", (int *) &chat_macros[6], (size_t) HUSTR_CHATMACRO6, true },
|
|
{"chatmacro7", (int *) &chat_macros[7], (size_t) HUSTR_CHATMACRO7, true },
|
|
{"chatmacro8", (int *) &chat_macros[8], (size_t) HUSTR_CHATMACRO8, true },
|
|
{"chatmacro9", (int *) &chat_macros[9], (size_t) HUSTR_CHATMACRO9, true }
|
|
};
|
|
|
|
int numdefaults;
|
|
char* defaultfile;
|
|
|
|
|
|
//
|
|
// M_SaveDefaults
|
|
//
|
|
void M_SaveDefaults (void)
|
|
{
|
|
int i;
|
|
int 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++)
|
|
{
|
|
if (!defaults[i].is_string)
|
|
{
|
|
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,
|
|
* (const char **) (defaults[i].location));
|
|
}
|
|
}
|
|
|
|
fclose (f);
|
|
}
|
|
|
|
|
|
//
|
|
// M_LoadDefaults
|
|
//
|
|
extern byte scantokey[128];
|
|
|
|
void M_LoadDefaults (void)
|
|
{
|
|
int i;
|
|
int 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++)
|
|
{
|
|
if (defaults[i].is_string)
|
|
*(const char**)defaults[i].location = (const char*)defaults[i].defaultvalue;
|
|
else
|
|
*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
|
|
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
|
|
sscanf(strparm, "%i", &parm);
|
|
for (i=0 ; i<numdefaults ; i++)
|
|
if (!strcmp(def, defaults[i].name))
|
|
{
|
|
if (!isstring)
|
|
*defaults[i].location = parm;
|
|
else
|
|
*(const char**)defaults[i].location =
|
|
newstring;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose (f);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// SCREEN SHOTS
|
|
//
|
|
|
|
|
|
static void WriteLE(unsigned char *pointer, unsigned long value, unsigned int total_bytes)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < total_bytes; ++i)
|
|
*pointer++ = (value >> (8 * i)) & 0xFF;
|
|
}
|
|
|
|
#define WriteU16LE(pointer, value) WriteLE(pointer, value, 2)
|
|
#define WriteU32LE(pointer, value) WriteLE(pointer, value, 4)
|
|
|
|
|
|
//
|
|
// WritePCXfile
|
|
//
|
|
void
|
|
WritePCXfile
|
|
( char* filename,
|
|
byte* data,
|
|
unsigned int width,
|
|
unsigned int height,
|
|
byte* palette )
|
|
{
|
|
size_t bytes_remaining;
|
|
size_t length;
|
|
byte* pcx;
|
|
byte* pack;
|
|
|
|
length = 0x80 + 1 + (1 << 8) * 3;
|
|
|
|
pcx = Z_Malloc(length + width * height * 2, PU_STATIC, NULL);
|
|
|
|
/* Manufacturer */
|
|
pcx[0] = 0x0A; /* PCX ID */
|
|
/* Version */
|
|
pcx[1] = 5; /* 256 colors */
|
|
/* Encoding */
|
|
pcx[2] = 1; /* RLE */
|
|
/* Bits per pixel */
|
|
pcx[3] = 8; /* 256 colors */
|
|
/* X minimum */
|
|
WriteU16LE(&pcx[4], 0);
|
|
/* Y minimum */
|
|
WriteU16LE(&pcx[6], 0);
|
|
/* X maximum */
|
|
WriteU16LE(&pcx[8], width-1);
|
|
/* Y maximum */
|
|
WriteU16LE(&pcx[0xA], height-1);
|
|
/* Horizontal resolution */
|
|
WriteU16LE(&pcx[0xC], width);
|
|
/* Vertical resolution */
|
|
WriteU16LE(&pcx[0xE], height);
|
|
/* Palette */
|
|
memset(&pcx[0x10], 0, 0x30);
|
|
/* Reserved */
|
|
pcx[0x40] = 0;
|
|
/* Color planes */
|
|
pcx[0x41] = 1; /* Chunky image */
|
|
/* Bytes per line */
|
|
WriteU16LE(&pcx[0x42], width);
|
|
/* Palette type */
|
|
WriteU16LE(&pcx[0x44], 2); /* Not a grey scale */
|
|
/* Filler */
|
|
memset(&pcx[0x46], 0, 0x3A);
|
|
|
|
/* Pack the image */
|
|
pack = &pcx[0x80];
|
|
|
|
bytes_remaining = width * height;
|
|
|
|
while (bytes_remaining != 0)
|
|
{
|
|
size_t run_length;
|
|
|
|
const size_t run_length_limit = bytes_remaining < 0x3F ? bytes_remaining : 0x3F;
|
|
const byte run_length_value = *data++;
|
|
|
|
run_length = 1;
|
|
|
|
while (*data == run_length_value && run_length < run_length_limit)
|
|
{
|
|
++data;
|
|
++run_length;
|
|
}
|
|
|
|
if (run_length != 1 || (run_length_value & 0xC0) == 0xC0)
|
|
{
|
|
*pack++ = 0xC0 | run_length;
|
|
++length;
|
|
}
|
|
|
|
*pack++ = run_length_value;
|
|
++length;
|
|
|
|
bytes_remaining -= run_length;
|
|
}
|
|
|
|
/* Write the palette */
|
|
*pack++ = 0x0C; /* Palette ID byte */
|
|
memcpy(pack, palette, (1 << 8) * 3);
|
|
|
|
/* Write output file */
|
|
M_WriteFile(filename, pcx, length);
|
|
|
|
Z_Free(pcx);
|
|
}
|
|
|
|
|
|
//
|
|
// WriteBMPfile
|
|
//
|
|
void
|
|
WriteBMPfile
|
|
( char* filename,
|
|
byte* data,
|
|
unsigned int width,
|
|
unsigned int height,
|
|
byte* palette )
|
|
{
|
|
unsigned int i;
|
|
byte *bmp, *bmp_pointer;
|
|
|
|
const unsigned long rounded_width = (width + (4 - 1)) / 4 * 4; /* Pad width to a multiple of 4, as required by the BMP file format. */
|
|
const unsigned long bitmap_offset = 0x1A + 0x100 * 3;
|
|
const unsigned long length = bitmap_offset + rounded_width * height;
|
|
|
|
bmp = Z_Malloc(length, PU_STATIC, NULL);
|
|
|
|
/* BMP file header */
|
|
|
|
/* Identifier */
|
|
bmp[0] = 'B';
|
|
bmp[1] = 'M';
|
|
|
|
/* Size of file in bytes */
|
|
WriteU32LE(&bmp[2], length);
|
|
|
|
/* Reserved */
|
|
WriteU16LE(&bmp[6], 0);
|
|
|
|
/* Reserved */
|
|
WriteU16LE(&bmp[8], 0);
|
|
|
|
/* Offset of pixel array */
|
|
WriteU32LE(&bmp[0xA], bitmap_offset);
|
|
|
|
/* BITMAPCOREHEADER */
|
|
|
|
/* Size of 'BITMAPCOREHEADER' */
|
|
WriteU32LE(&bmp[0xE], 0x1A - 0xE);
|
|
|
|
/* Width of bitmap in pixels */
|
|
WriteU16LE(&bmp[0x12], width);
|
|
|
|
/* Height of bitmap in pixels */
|
|
WriteU16LE(&bmp[0x14], height);
|
|
|
|
/* Number of color planes */
|
|
WriteU16LE(&bmp[0x16], 1);
|
|
|
|
/* Bits per pixel */
|
|
WriteU16LE(&bmp[0x18], 8);
|
|
|
|
/* Color table */
|
|
|
|
bmp_pointer = &bmp[0x1A];
|
|
|
|
for (i = 0; i < 1 << 8; ++i)
|
|
{
|
|
const byte blue = *palette++;
|
|
const byte green = *palette++;
|
|
const byte red = *palette++;
|
|
|
|
*bmp_pointer++ = red;
|
|
*bmp_pointer++ = green;
|
|
*bmp_pointer++ = blue;
|
|
}
|
|
|
|
/* Pixel array */
|
|
|
|
for (i = 0; i < height; ++i)
|
|
{
|
|
unsigned int j;
|
|
|
|
bmp_pointer = &bmp[bitmap_offset + rounded_width * (height - i - 1)];
|
|
|
|
memcpy(bmp_pointer, data, width);
|
|
memset(bmp_pointer + width, 0, rounded_width - width);
|
|
}
|
|
|
|
/* Write output file */
|
|
M_WriteFile(filename, bmp, length);
|
|
|
|
Z_Free(bmp);
|
|
}
|
|
|
|
|
|
//
|
|
// M_ScreenShot
|
|
//
|
|
void M_ScreenShot (void)
|
|
{
|
|
int i;
|
|
byte* linear;
|
|
char lbmname[12];
|
|
|
|
// munge planar buffer to linear
|
|
linear = screens[2];
|
|
I_ReadScreen (linear);
|
|
|
|
// find a file name to save it to
|
|
strcpy(lbmname,"DOOM00.pcx");
|
|
if (bmp_screenshots)
|
|
strcpy(&lbmname[7],"bmp");
|
|
|
|
for (i=0 ; i<=99 ; i++)
|
|
{
|
|
lbmname[4] = i/10 + '0';
|
|
lbmname[5] = i%10 + '0';
|
|
if (!M_FileExists(lbmname))
|
|
break; // file doesn't exist
|
|
}
|
|
if (i==100)
|
|
I_Error ("M_ScreenShot: Couldn't create a screenshot");
|
|
|
|
// save the screenshot file
|
|
(bmp_screenshots ? WriteBMPfile : WritePCXfile) (lbmname, linear,
|
|
SCREENWIDTH, SCREENHEIGHT,
|
|
W_CacheLumpName ("PLAYPAL",PU_CACHE));
|
|
|
|
players[consoleplayer].message = "screen shot";
|
|
}
|
|
|
|
int M_strncasecmp(const char *s1, const char *s2, size_t n)
|
|
{
|
|
int delta = 0;
|
|
|
|
while (n-- != 0)
|
|
{
|
|
const int c1 = *s1++;
|
|
const int c2 = *s2++;
|
|
|
|
delta = toupper(c1) - toupper(c2);
|
|
|
|
if (delta != 0 || c1 == '\0')
|
|
break;
|
|
}
|
|
|
|
return delta;
|
|
}
|
|
|
|
boolean M_FileExists(const char* const filename)
|
|
{
|
|
FILE* const file = fopen(filename, "rb");
|
|
|
|
if (file != NULL)
|
|
{
|
|
fclose(file);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|