dvr/app/jni/prboom/m_menu.c

5555 lines
148 KiB
C
Raw Normal View History

2016-03-03 22:28:59 +00:00
/* Emacs style mode select -*- C++ -*-
*-----------------------------------------------------------------------------
*
*
* PrBoom: a Doom port merged with LxDoom and LSDLDoom
* based on BOOM, a modified and improved DOOM engine
* Copyright (C) 1999 by
* id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
* Copyright (C) 1999-2000 by
* Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
* Copyright 2005, 2006 by
* Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
*
* 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.
*
* DESCRIPTION:
* DOOM selection menu, options, episode etc. (aka Big Font menus)
* Sliders and icons. Kinda widget stuff.
* Setup Menus.
* Extended HELP screens.
* Dynamic HELP screen.
*
*-----------------------------------------------------------------------------*/
#include <stdio.h>
#include <fcntl.h>
#include "doomdef.h"
#include "doomstat.h"
#include "dstrings.h"
#include "d_main.h"
#include "v_video.h"
#include "w_wad.h"
#include "r_main.h"
#include "hu_stuff.h"
#include "g_game.h"
#include "s_sound.h"
#include "sounds.h"
#include "m_menu.h"
#include "d_deh.h"
#include "m_misc.h"
#include "lprintf.h"
#include "am_map.h"
#include "i_main.h"
#include "i_system.h"
#include "i_video.h"
#include "i_sound.h"
#include "r_demo.h"
#include "r_fps.h"
extern patchnum_t hu_font[HU_FONTSIZE];
extern boolean message_dontfuckwithme;
extern boolean chat_on; // in heads-up code
//
// defaulted values
//
int mouseSensitivity_horiz; // has default // killough
int mouseSensitivity_vert; // has default
int showMessages; // Show messages has default, 0 = off, 1 = on
int hide_setup=1; // killough 5/15/98
// Blocky mode, has default, 0 = high, 1 = normal
//int detailLevel; obsolete -- killough
int screenblocks; // has default
int screenSize; // temp for screenblocks (0-9)
int quickSaveSlot; // -1 = no quicksave slot picked!
int messageToPrint; // 1 = message to be printed
// CPhipps - static const
static const char* messageString; // ...and here is the message string!
// message x & y
int messx;
int messy;
int messageLastMenuActive;
boolean messageNeedsInput; // timed message = no input from user
void (*messageRoutine)(int response);
#define SAVESTRINGSIZE 24
/* killough 8/15/98: when changes are allowed to sync-critical variables */
static int allow_changes(void)
{
return !(demoplayback || demorecording || netgame);
}
static void M_UpdateCurrent(default_t* def)
{
/* cph - requires rewrite of m_misc.c */
if (def->current) {
if (allow_changes()) /* killough 8/15/98 */
*def->current = *def->location.pi;
else if (*def->current != *def->location.pi)
warn_about_changes(S_LEVWARN); /* killough 8/15/98 */
}
}
int warning_about_changes, print_warning_about_changes;
/* cphipps - M_DrawBackground renamed and moved to v_video.c */
#define M_DrawBackground V_DrawBackground
// we are going to be entering a savegame string
int saveStringEnter;
int saveSlot; // which slot to save in
int saveCharIndex; // which char we're editing
// old save description before edit
char saveOldString[SAVESTRINGSIZE];
boolean inhelpscreens; // indicates we are in or just left a help screen
boolean menuactive; // The menus are up
#define SKULLXOFF -32
#define LINEHEIGHT 16
char savegamestrings[10][SAVESTRINGSIZE];
//
// MENU TYPEDEFS
//
typedef struct
{
short status; // 0 = no cursor here, 1 = ok, 2 = arrows ok
char name[10];
// choice = menu item #.
// if status = 2,
// choice=0:leftarrow,1:rightarrow
void (*routine)(int choice);
char alphaKey; // hotkey in menu
} menuitem_t;
typedef struct menu_s
{
short numitems; // # of menu items
struct menu_s* prevMenu; // previous menu
menuitem_t* menuitems; // menu items
void (*routine)(); // draw routine
short x;
short y; // x,y of menu
short lastOn; // last item user was on in menu
} menu_t;
short itemOn; // menu item skull is on (for Big Font menus)
short skullAnimCounter; // skull animation counter
short whichSkull; // which skull to draw (he blinks)
// graphic name of skulls
const char skullName[2][/*8*/9] = {"M_SKULL1","M_SKULL2"};
menu_t* currentMenu; // current menudef
// phares 3/30/98
// externs added for setup menus
extern int mousebfire;
extern int mousebstrafe;
extern int mousebforward;
// proff 08/17/98: Added backward to mousebuttons
extern int mousebbackward;
extern int joybfire;
extern int joybstrafe;
extern int joybuse;
extern int joybspeed;
int mapcolor_me; // cph
extern int map_point_coordinates; // killough 10/98
extern char* chat_macros[]; // chat macros
extern const char* shiftxform;
extern default_t defaults[];
extern int numdefaults;
// end of externs added for setup menus
//
// PROTOTYPES
//
void M_NewGame(int choice);
void M_Episode(int choice);
void M_ChooseSkill(int choice);
void M_LoadGame(int choice);
void M_SaveGame(int choice);
void M_Options(int choice);
void M_EndGame(int choice);
void M_ReadThis(int choice);
void M_ReadThis2(int choice);
void M_QuitDOOM(int choice);
void M_ChangeMessages(int choice);
void M_ChangeSensitivity(int choice);
void M_SfxVol(int choice);
void M_MusicVol(int choice);
/* void M_ChangeDetail(int choice); unused -- killough */
void M_SizeDisplay(int choice);
void M_StartGame(int choice);
void M_Sound(int choice);
void M_Mouse(int choice, int *sens); /* killough */
void M_MouseVert(int choice);
void M_MouseHoriz(int choice);
void M_DrawMouse(void);
void M_FinishReadThis(int choice);
void M_FinishHelp(int choice); // killough 10/98
void M_LoadSelect(int choice);
void M_SaveSelect(int choice);
void M_ReadSaveStrings(void);
void M_QuickSave(void);
void M_QuickLoad(void);
void M_DrawMainMenu(void);
void M_DrawReadThis1(void);
void M_DrawReadThis2(void);
void M_DrawNewGame(void);
void M_DrawEpisode(void);
void M_DrawOptions(void);
void M_DrawSound(void);
void M_DrawLoad(void);
void M_DrawSave(void);
void M_DrawSetup(void); // phares 3/21/98
void M_DrawHelp (void); // phares 5/04/98
void M_DrawSaveLoadBorder(int x,int y);
void M_SetupNextMenu(menu_t *menudef);
void M_DrawThermo(int x,int y,int thermWidth,int thermDot);
void M_DrawEmptyCell(menu_t *menu,int item);
void M_DrawSelCell(menu_t *menu,int item);
void M_WriteText(int x, int y, const char *string);
int M_StringWidth(const char *string);
int M_StringHeight(const char *string);
void M_StartMessage(const char *string,void *routine,boolean input);
void M_StopMessage(void);
void M_ClearMenus (void);
// phares 3/30/98
// prototypes added to support Setup Menus and Extended HELP screens
int M_GetKeyString(int,int);
void M_Setup(int choice);
void M_KeyBindings(int choice);
void M_Weapons(int);
void M_StatusBar(int);
void M_Automap(int);
void M_Enemy(int);
void M_Messages(int);
void M_ChatStrings(int);
void M_InitExtendedHelp(void);
void M_ExtHelpNextScreen(int);
void M_ExtHelp(int);
static int M_GetPixelWidth(const char*);
void M_DrawKeybnd(void);
void M_DrawWeapons(void);
static void M_DrawMenuString(int,int,int);
static void M_DrawStringCentered(int,int,int,const char*);
void M_DrawStatusHUD(void);
void M_DrawExtHelp(void);
void M_DrawAutoMap(void);
void M_DrawEnemy(void);
void M_DrawMessages(void);
void M_DrawChatStrings(void);
void M_Compat(int); // killough 10/98
void M_ChangeDemoSmoothTurns(void);
void M_General(int); // killough 10/98
void M_DrawCompat(void); // killough 10/98
void M_DrawGeneral(void); // killough 10/98
void M_FullScreen(void); // nathanh 01/01
menu_t NewDef; // phares 5/04/98
// end of prototypes added to support Setup Menus and Extended HELP screens
/////////////////////////////////////////////////////////////////////////////
//
// DOOM MENUS
//
/////////////////////////////
//
// MAIN MENU
//
// main_e provides numerical values for which Big Font screen you're on
enum
{
newgame = 0,
loadgame,
savegame,
options,
readthis,
quitdoom,
main_end
} main_e;
//
// MainMenu is the definition of what the main menu Screen should look
// like. Each entry shows that the cursor can land on each item (1), the
// built-in graphic lump (i.e. "M_NGAME") that should be displayed,
// the program which takes over when an item is selected, and the hotkey
// associated with the item.
//
menuitem_t MainMenu[]=
{
{1,"M_NGAME", M_NewGame, 'n'},
{1,"M_OPTION",M_Options, 'o'},
{1,"M_LOADG", M_LoadGame,'l'},
{1,"M_SAVEG", M_SaveGame,'s'},
// Another hickup with Special edition.
{1,"M_RDTHIS",M_ReadThis,'r'},
{1,"M_QUITG", M_QuitDOOM,'q'}
};
menu_t MainDef =
{
main_end, // number of menu items
NULL, // previous menu screen
MainMenu, // table that defines menu items
M_DrawMainMenu, // drawing routine
97,64, // initial cursor position
0 // last menu item the user was on
};
//
// M_DrawMainMenu
//
void M_DrawMainMenu(void)
{
// CPhipps - patch drawing updated
V_DrawNamePatch(94, 2, 0, "M_DOOM", CR_DEFAULT, VPT_STRETCH);
}
/////////////////////////////
//
// Read This! MENU 1 & 2
//
// There are no menu items on the Read This! screens, so read_e just
// provides a placeholder to maintain structure.
enum
{
rdthsempty1,
read1_end
} read_e;
enum
{
rdthsempty2,
read2_end
} read_e2;
enum // killough 10/98
{
helpempty,
help_end
} help_e;
// The definitions of the Read This! screens
menuitem_t ReadMenu1[] =
{
{1,"",M_ReadThis2,0}
};
menuitem_t ReadMenu2[]=
{
{1,"",M_FinishReadThis,0}
};
menuitem_t HelpMenu[]= // killough 10/98
{
{1,"",M_FinishHelp,0}
};
menu_t ReadDef1 =
{
read1_end,
&MainDef,
ReadMenu1,
M_DrawReadThis1,
330,175,
//280,185, // killough 2/21/98: fix help screens
0
};
menu_t ReadDef2 =
{
read2_end,
&ReadDef1,
ReadMenu2,
M_DrawReadThis2,
330,175,
0
};
menu_t HelpDef = // killough 10/98
{
help_end,
&HelpDef,
HelpMenu,
M_DrawHelp,
330,175,
0
};
//
// M_ReadThis
//
void M_ReadThis(int choice)
{
M_SetupNextMenu(&ReadDef1);
}
void M_ReadThis2(int choice)
{
M_SetupNextMenu(&ReadDef2);
}
void M_FinishReadThis(int choice)
{
M_SetupNextMenu(&MainDef);
}
void M_FinishHelp(int choice) // killough 10/98
{
M_SetupNextMenu(&MainDef);
}
//
// Read This Menus
// Had a "quick hack to fix romero bug"
//
// killough 10/98: updated with new screens
void M_DrawReadThis1(void)
{
inhelpscreens = true;
if (gamemode == shareware)
V_DrawNamePatch(0, 0, 0, "HELP2", CR_DEFAULT, VPT_STRETCH);
else
M_DrawCredits();
}
//
// Read This Menus - optional second page.
//
// killough 10/98: updated with new screens
void M_DrawReadThis2(void)
{
inhelpscreens = true;
if (gamemode == shareware)
M_DrawCredits();
else
V_DrawNamePatch(0, 0, 0, "CREDIT", CR_DEFAULT, VPT_STRETCH);
}
/////////////////////////////
//
// EPISODE SELECT
//
//
// episodes_e provides numbers for the episode menu items. The default is
// 4, to accomodate Ultimate Doom. If the user is running anything else,
// this is accounted for in the code.
//
enum
{
ep1,
ep2,
ep3,
ep4,
ep_end
} episodes_e;
// The definitions of the Episodes menu
menuitem_t EpisodeMenu[]=
{
{1,"M_EPI1", M_Episode,'k'},
{1,"M_EPI2", M_Episode,'t'},
{1,"M_EPI3", M_Episode,'i'},
{1,"M_EPI4", M_Episode,'t'}
};
menu_t EpiDef =
{
ep_end, // # of menu items
&MainDef, // previous menu
EpisodeMenu, // menuitem_t ->
M_DrawEpisode, // drawing routine ->
48,63, // x,y
ep1 // lastOn
};
//
// M_Episode
//
int epi;
void M_DrawEpisode(void)
{
// CPhipps - patch drawing updated
V_DrawNamePatch(54, 38, 0, "M_EPISOD", CR_DEFAULT, VPT_STRETCH);
}
void M_Episode(int choice)
{
if ( (gamemode == shareware) && choice) {
M_StartMessage(s_SWSTRING,NULL,false); // Ty 03/27/98 - externalized
M_SetupNextMenu(&ReadDef1);
return;
}
// Yet another hack...
if ( (gamemode == registered) && (choice > 2))
{
lprintf( LO_WARN,
"M_Episode: 4th episode requires UltimateDOOM\n");
choice = 0;
}
epi = choice;
M_SetupNextMenu(&NewDef);
}
/////////////////////////////
//
// NEW GAME
//
// numerical values for the New Game menu items
enum
{
killthings,
toorough,
hurtme,
violence,
nightmare,
newg_end
} newgame_e;
// The definitions of the New Game menu
menuitem_t NewGameMenu[]=
{
{1,"M_JKILL", M_ChooseSkill, 'i'},
{1,"M_ROUGH", M_ChooseSkill, 'h'},
{1,"M_HURT", M_ChooseSkill, 'h'},
{1,"M_ULTRA", M_ChooseSkill, 'u'},
{1,"M_NMARE", M_ChooseSkill, 'n'}
};
menu_t NewDef =
{
newg_end, // # of menu items
&EpiDef, // previous menu
NewGameMenu, // menuitem_t ->
M_DrawNewGame, // drawing routine ->
48,63, // x,y
hurtme // lastOn
};
//
// M_NewGame
//
void M_DrawNewGame(void)
{
// CPhipps - patch drawing updated
V_DrawNamePatch(96, 14, 0, "M_NEWG", CR_DEFAULT, VPT_STRETCH);
V_DrawNamePatch(54, 38, 0, "M_SKILL",CR_DEFAULT, VPT_STRETCH);
}
/* cph - make `New Game' restart the level in a netgame */
static void M_RestartLevelResponse(int ch)
{
if (ch != 'y')
return;
if (demorecording)
exit(0);
currentMenu->lastOn = itemOn;
M_ClearMenus ();
G_RestartLevel ();
}
void M_NewGame(int choice)
{
if (netgame && !demoplayback) {
if (compatibility_level < lxdoom_1_compatibility)
M_StartMessage(s_NEWGAME,NULL,false); // Ty 03/27/98 - externalized
else // CPhipps - query restarting the level
M_StartMessage(s_RESTARTLEVEL,M_RestartLevelResponse,true);
return;
}
if (demorecording) { /* killough 5/26/98: exclude during demo recordings */
M_StartMessage("you can't start a new game\n"
"while recording a demo!\n\n"PRESSKEY,
NULL, false); // killough 5/26/98: not externalized
return;
}
if ( gamemode == commercial )
M_SetupNextMenu(&NewDef);
else
M_SetupNextMenu(&EpiDef);
}
// CPhipps - static
static void M_VerifyNightmare(int ch)
{
if (ch != 'y')
return;
G_DeferedInitNew(nightmare,epi+1,1);
M_ClearMenus ();
}
void M_ChooseSkill(int choice)
{
if (choice == nightmare)
{ // Ty 03/27/98 - externalized
M_StartMessage(s_NIGHTMARE,M_VerifyNightmare,true);
return;
}
G_DeferedInitNew(choice,epi+1,1);
M_ClearMenus ();
}
/////////////////////////////
//
// LOAD GAME MENU
//
// numerical values for the Load Game slots
enum
{
load1,
load2,
load3,
load4,
load5,
load6,
load7, //jff 3/15/98 extend number of slots
load8,
load_end
} load_e;
// The definitions of the Load Game screen
menuitem_t LoadMenue[]=
{
{1,"", M_LoadSelect,'1'},
{1,"", M_LoadSelect,'2'},
{1,"", M_LoadSelect,'3'},
{1,"", M_LoadSelect,'4'},
{1,"", M_LoadSelect,'5'},
{1,"", M_LoadSelect,'6'},
{1,"", M_LoadSelect,'7'}, //jff 3/15/98 extend number of slots
{1,"", M_LoadSelect,'8'},
};
menu_t LoadDef =
{
load_end,
&MainDef,
LoadMenue,
M_DrawLoad,
80,34, //jff 3/15/98 move menu up
0
};
#define LOADGRAPHIC_Y 8
//
// M_LoadGame & Cie.
//
void M_DrawLoad(void)
{
int i;
//jff 3/15/98 use symbolic load position
// CPhipps - patch drawing updated
V_DrawNamePatch(72 ,LOADGRAPHIC_Y, 0, "M_LOADG", CR_DEFAULT, VPT_STRETCH);
for (i = 0 ; i < load_end ; i++) {
M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
}
}
//
// Draw border for the savegame description
//
void M_DrawSaveLoadBorder(int x,int y)
{
int i;
V_DrawNamePatch(x-8, y+7, 0, "M_LSLEFT", CR_DEFAULT, VPT_STRETCH);
for (i = 0 ; i < 24 ; i++)
{
V_DrawNamePatch(x, y+7, 0, "M_LSCNTR", CR_DEFAULT, VPT_STRETCH);
x += 8;
}
V_DrawNamePatch(x, y+7, 0, "M_LSRGHT", CR_DEFAULT, VPT_STRETCH);
}
//
// User wants to load this game
//
void M_LoadSelect(int choice)
{
// CPhipps - Modified so savegame filename is worked out only internal
// to g_game.c, this only passes the slot.
G_LoadGame(choice, false); // killough 3/16/98, 5/15/98: add slot, cmd
M_ClearMenus ();
}
//
// killough 5/15/98: add forced loadgames
//
static void M_VerifyForcedLoadGame(int ch)
{
if (ch=='y')
G_ForcedLoadGame();
free((char*)messageString); // free the message strdup()'ed below
M_ClearMenus();
}
void M_ForcedLoadGame(const char *msg)
{
M_StartMessage(strdup(msg), M_VerifyForcedLoadGame, true); // free()'d above
}
//
// Selected from DOOM menu
//
void M_LoadGame (int choice)
{
/* killough 5/26/98: exclude during demo recordings
* cph - unless a new demo */
if (demorecording && (compatibility_level < prboom_2_compatibility))
{
M_StartMessage("you can't load a game\n"
"while recording an old demo!\n\n"PRESSKEY,
NULL, false); // killough 5/26/98: not externalized
return;
}
M_SetupNextMenu(&LoadDef);
M_ReadSaveStrings();
}
/////////////////////////////
//
// SAVE GAME MENU
//
// The definitions of the Save Game screen
menuitem_t SaveMenu[]=
{
{1,"", M_SaveSelect,'1'},
{1,"", M_SaveSelect,'2'},
{1,"", M_SaveSelect,'3'},
{1,"", M_SaveSelect,'4'},
{1,"", M_SaveSelect,'5'},
{1,"", M_SaveSelect,'6'},
{1,"", M_SaveSelect,'7'}, //jff 3/15/98 extend number of slots
{1,"", M_SaveSelect,'8'},
};
menu_t SaveDef =
{
load_end, // same number of slots as the Load Game screen
&MainDef,
SaveMenu,
M_DrawSave,
80,34, //jff 3/15/98 move menu up
0
};
//
// M_ReadSaveStrings
// read the strings from the savegame files
//
void M_ReadSaveStrings(void)
{
int i;
for (i = 0 ; i < load_end ; i++) {
char name[PATH_MAX+1]; // killough 3/22/98
FILE *fp; // killough 11/98: change to use stdio
/* killough 3/22/98
* cph - add not-demoplayback parameter */
G_SaveGameName(name,sizeof(name),i,false);
fp = fopen(name,"rb");
if (!fp) { // Ty 03/27/98 - externalized:
strcpy(&savegamestrings[i][0],s_EMPTYSTRING);
LoadMenue[i].status = 0;
continue;
}
fread(&savegamestrings[i], SAVESTRINGSIZE, 1, fp);
fclose(fp);
LoadMenue[i].status = 1;
}
}
//
// M_SaveGame & Cie.
//
void M_DrawSave(void)
{
int i;
//jff 3/15/98 use symbolic load position
// CPhipps - patch drawing updated
V_DrawNamePatch(72, LOADGRAPHIC_Y, 0, "M_SAVEG", CR_DEFAULT, VPT_STRETCH);
for (i = 0 ; i < load_end ; i++)
{
M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
}
if (saveStringEnter)
{
i = M_StringWidth(savegamestrings[saveSlot]);
M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*saveSlot,"_");
}
}
//
// M_Responder calls this when user is finished
//
static void M_DoSave(int slot)
{
G_SaveGame (slot,savegamestrings[slot]);
M_ClearMenus ();
// PICK QUICKSAVE SLOT YET?
if (quickSaveSlot == -2)
quickSaveSlot = slot;
}
//
// User wants to save. Start string input for M_Responder
//
void M_SaveSelect(int choice)
{
// we are going to be intercepting all chars
saveStringEnter = 1;
saveSlot = choice;
strcpy(saveOldString,savegamestrings[choice]);
if (!strcmp(savegamestrings[choice],s_EMPTYSTRING)) // Ty 03/27/98 - externalized
savegamestrings[choice][0] = 0;
saveCharIndex = strlen(savegamestrings[choice]);
}
//
// Selected from DOOM menu
//
void M_SaveGame (int choice)
{
// killough 10/6/98: allow savegames during single-player demo playback
if (!usergame && (!demoplayback || netgame))
{
M_StartMessage(s_SAVEDEAD,NULL,false); // Ty 03/27/98 - externalized
return;
}
if (gamestate != GS_LEVEL)
return;
M_SetupNextMenu(&SaveDef);
M_ReadSaveStrings();
}
/////////////////////////////
//
// OPTIONS MENU
//
// numerical values for the Options menu items
enum
{
general, // killough 10/98
// killough 4/6/98: move setup to be a sub-menu of OPTIONs
setup, // phares 3/21/98
endgame,
messages,
/* detail, obsolete -- killough */
scrnsize,
option_empty1,
mousesens,
/* option_empty2, submenu now -- killough */
soundvol,
opt_end
} options_e;
// The definitions of the Options menu
menuitem_t OptionsMenu[]=
{
// killough 4/6/98: move setup to be a sub-menu of OPTIONs
{1,"M_GENERL", M_General, 'g'}, // killough 10/98
{1,"M_SETUP", M_Setup, 's'}, // phares 3/21/98
{1,"M_ENDGAM", M_EndGame,'e'},
{1,"M_MESSG", M_ChangeMessages,'m'},
/* {1,"M_DETAIL", M_ChangeDetail,'g'}, unused -- killough */
{2,"M_SCRNSZ", M_SizeDisplay,'s'},
{-1,"",0},
{1,"M_MSENS", M_ChangeSensitivity,'m'},
/* {-1,"",0}, replaced with submenu -- killough */
{1,"M_SVOL", M_Sound,'s'}
};
menu_t OptionsDef =
{
opt_end,
&MainDef,
OptionsMenu,
M_DrawOptions,
60,37,
0
};
//
// M_Options
//
char detailNames[2][9] = {"M_GDHIGH","M_GDLOW"};
char msgNames[2][9] = {"M_MSGOFF","M_MSGON"};
void M_DrawOptions(void)
{
// CPhipps - patch drawing updated
// proff/nicolas 09/20/98 -- changed for hi-res
V_DrawNamePatch(108, 15, 0, "M_OPTTTL", CR_DEFAULT, VPT_STRETCH);
V_DrawNamePatch(OptionsDef.x + 120, OptionsDef.y+LINEHEIGHT*messages, 0,
msgNames[showMessages], CR_DEFAULT, VPT_STRETCH);
M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1),
9,screenSize);
}
void M_Options(int choice)
{
M_SetupNextMenu(&OptionsDef);
}
/////////////////////////////
//
// M_QuitDOOM
//
int quitsounds[8] =
{
sfx_pldeth,
sfx_dmpain,
sfx_popain,
sfx_slop,
sfx_telept,
sfx_posit1,
sfx_posit3,
sfx_sgtatk
};
int quitsounds2[8] =
{
sfx_vilact,
sfx_getpow,
sfx_boscub,
sfx_slop,
sfx_skeswg,
sfx_kntdth,
sfx_bspact,
sfx_sgtatk
};
static void M_QuitResponse(int ch)
{
if (ch != 'y')
return;
if ((!netgame || demoplayback) // killough 12/98
&& !nosfxparm && snd_card) // avoid delay if no sound card
{
int i;
if (gamemode == commercial)
S_StartSound(NULL,quitsounds2[(gametic>>2)&7]);
else
S_StartSound(NULL,quitsounds[(gametic>>2)&7]);
// wait till all sounds stopped or 3 seconds are over
i = 30;
while (i>0) {
I_uSleep(100000); // CPhipps - don't thrash cpu in this loop
if (!I_AnySoundStillPlaying())
break;
i--;
}
}
exit(0); // killough
}
void M_QuitDOOM(int choice)
{
static char endstring[160];
// We pick index 0 which is language sensitive,
// or one at random, between 1 and maximum number.
// Ty 03/27/98 - externalized DOSY as a string s_DOSY that's in the sprintf
if (language != english)
sprintf(endstring,"%s\n\n%s",s_DOSY, endmsg[0] );
else // killough 1/18/98: fix endgame message calculation:
sprintf(endstring,"%s\n\n%s", endmsg[gametic%(NUM_QUITMESSAGES-1)+1], s_DOSY);
M_StartMessage(endstring,M_QuitResponse,true);
}
/////////////////////////////
//
// SOUND VOLUME MENU
//
// numerical values for the Sound Volume menu items
// The 'empty' slots are where the sliding scales appear.
enum
{
sfx_vol,
sfx_empty1,
music_vol,
sfx_empty2,
sound_end
} sound_e;
// The definitions of the Sound Volume menu
menuitem_t SoundMenu[]=
{
{2,"M_SFXVOL",M_SfxVol,'s'},
{-1,"",0},
{2,"M_MUSVOL",M_MusicVol,'m'},
{-1,"",0}
};
menu_t SoundDef =
{
sound_end,
&OptionsDef,
SoundMenu,
M_DrawSound,
80,64,
0
};
//
// Change Sfx & Music volumes
//
void M_DrawSound(void)
{
// CPhipps - patch drawing updated
V_DrawNamePatch(60, 38, 0, "M_SVOL", CR_DEFAULT, VPT_STRETCH);
M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1),16,snd_SfxVolume);
M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1),16,snd_MusicVolume);
}
void M_Sound(int choice)
{
M_SetupNextMenu(&SoundDef);
}
void M_SfxVol(int choice)
{
switch(choice)
{
case 0:
if (snd_SfxVolume)
snd_SfxVolume--;
break;
case 1:
if (snd_SfxVolume < 15)
snd_SfxVolume++;
break;
}
S_SetSfxVolume(snd_SfxVolume /* *8 */);
}
void M_MusicVol(int choice)
{
switch(choice)
{
case 0:
if (snd_MusicVolume)
snd_MusicVolume--;
break;
case 1:
if (snd_MusicVolume < 15)
snd_MusicVolume++;
break;
}
S_SetMusicVolume(snd_MusicVolume /* *8 */);
}
/////////////////////////////
//
// MOUSE SENSITIVITY MENU -- killough
//
// numerical values for the Mouse Sensitivity menu items
// The 'empty' slots are where the sliding scales appear.
enum
{
mouse_horiz,
mouse_empty1,
mouse_vert,
mouse_empty2,
mouse_end
} mouse_e;
// The definitions of the Mouse Sensitivity menu
menuitem_t MouseMenu[]=
{
{2,"M_HORSEN",M_MouseHoriz,'h'},
{-1,"",0},
{2,"M_VERSEN",M_MouseVert,'v'},
{-1,"",0}
};
menu_t MouseDef =
{
mouse_end,
&OptionsDef,
MouseMenu,
M_DrawMouse,
60,64,
0
};
// I'm using a scale of 100 since I don't know what's normal -- killough.
#define MOUSE_SENS_MAX 100
//
// Change Mouse Sensitivities -- killough
//
void M_DrawMouse(void)
{
int mhmx,mvmx; /* jff 4/3/98 clamp drawn position 99max mead */
// CPhipps - patch drawing updated
V_DrawNamePatch(60, 38, 0, "M_MSENS", CR_DEFAULT, VPT_STRETCH);
//jff 4/3/98 clamp horizontal sensitivity display
mhmx = mouseSensitivity_horiz>99? 99 : mouseSensitivity_horiz; /*mead*/
M_DrawThermo(MouseDef.x,MouseDef.y+LINEHEIGHT*(mouse_horiz+1),100,mhmx);
//jff 4/3/98 clamp vertical sensitivity display
mvmx = mouseSensitivity_vert>99? 99 : mouseSensitivity_vert; /*mead*/
M_DrawThermo(MouseDef.x,MouseDef.y+LINEHEIGHT*(mouse_vert+1),100,mvmx);
}
void M_ChangeSensitivity(int choice)
{
M_SetupNextMenu(&MouseDef); // killough
// switch(choice)
// {
// case 0:
// if (mouseSensitivity)
// mouseSensitivity--;
// break;
// case 1:
// if (mouseSensitivity < 9)
// mouseSensitivity++;
// break;
// }
}
void M_MouseHoriz(int choice)
{
M_Mouse(choice, &mouseSensitivity_horiz);
}
void M_MouseVert(int choice)
{
M_Mouse(choice, &mouseSensitivity_vert);
}
void M_Mouse(int choice, int *sens)
{
switch(choice)
{
case 0:
if (*sens)
--*sens;
break;
case 1:
if (*sens < 99)
++*sens; /*mead*/
break;
}
}
/////////////////////////////
//
// M_QuickSave
//
char tempstring[80];
static void M_QuickSaveResponse(int ch)
{
if (ch == 'y') {
M_DoSave(quickSaveSlot);
S_StartSound(NULL,sfx_swtchx);
}
}
void M_QuickSave(void)
{
if (!usergame && (!demoplayback || netgame)) { /* killough 10/98 */
S_StartSound(NULL,sfx_oof);
return;
}
if (gamestate != GS_LEVEL)
return;
if (quickSaveSlot < 0) {
M_StartControlPanel();
M_ReadSaveStrings();
M_SetupNextMenu(&SaveDef);
quickSaveSlot = -2; // means to pick a slot now
return;
}
sprintf(tempstring,s_QSPROMPT,savegamestrings[quickSaveSlot]); // Ty 03/27/98 - externalized
M_StartMessage(tempstring,M_QuickSaveResponse,true);
}
/////////////////////////////
//
// M_QuickLoad
//
static void M_QuickLoadResponse(int ch)
{
if (ch == 'y') {
M_LoadSelect(quickSaveSlot);
S_StartSound(NULL,sfx_swtchx);
}
}
void M_QuickLoad(void)
{
// cph - removed restriction against quickload in a netgame
if (demorecording) { // killough 5/26/98: exclude during demo recordings
M_StartMessage("you can't quickload\n"
"while recording a demo!\n\n"PRESSKEY,
NULL, false); // killough 5/26/98: not externalized
return;
}
if (quickSaveSlot < 0) {
M_StartMessage(s_QSAVESPOT,NULL,false); // Ty 03/27/98 - externalized
return;
}
sprintf(tempstring,s_QLPROMPT,savegamestrings[quickSaveSlot]); // Ty 03/27/98 - externalized
M_StartMessage(tempstring,M_QuickLoadResponse,true);
}
/////////////////////////////
//
// M_EndGame
//
static void M_EndGameResponse(int ch)
{
if (ch != 'y')
return;
// killough 5/26/98: make endgame quit if recording or playing back demo
if (demorecording || singledemo)
G_CheckDemoStatus();
currentMenu->lastOn = itemOn;
M_ClearMenus ();
D_StartTitle ();
}
void M_EndGame(int choice)
{
if (netgame)
{
M_StartMessage(s_NETEND,NULL,false); // Ty 03/27/98 - externalized
return;
}
M_StartMessage(s_ENDGAME,M_EndGameResponse,true); // Ty 03/27/98 - externalized
}
/////////////////////////////
//
// Toggle messages on/off
//
void M_ChangeMessages(int choice)
{
// warning: unused parameter `int choice'
choice = 0;
showMessages = 1 - showMessages;
if (!showMessages)
players[consoleplayer].message = s_MSGOFF; // Ty 03/27/98 - externalized
else
players[consoleplayer].message = s_MSGON ; // Ty 03/27/98 - externalized
message_dontfuckwithme = true;
}
/////////////////////////////
//
// CHANGE DISPLAY SIZE
//
// jff 2/23/98 restored to pre-HUD state
// hud_active controlled soley by F5=key_detail (key_hud)
// hud_displayed is toggled by + or = in fullscreen
// hud_displayed is cleared by -
void M_SizeDisplay(int choice)
{
switch(choice) {
case 0:
if (screenSize > 0) {
screenblocks--;
screenSize--;
hud_displayed = 0;
}
break;
case 1:
if (screenSize < 8) {
screenblocks++;
screenSize++;
}
else
hud_displayed = !hud_displayed;
break;
}
R_SetViewSize (screenblocks /*, detailLevel obsolete -- killough */);
}
//
// End of Original Menus
//
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// SETUP MENU (phares)
//
// We've added a set of Setup Screens from which you can configure a number
// of variables w/o having to restart the game. There are 7 screens:
//
// Key Bindings
// Weapons
// Status Bar / HUD
// Automap
// Enemies
// Messages
// Chat Strings
//
// killough 10/98: added Compatibility and General menus
//
/////////////////////////////
//
// booleans for setup screens
// these tell you what state the setup screens are in, and whether any of
// the overlay screens (automap colors, reset button message) should be
// displayed
boolean setup_active = false; // in one of the setup screens
boolean set_keybnd_active = false; // in key binding setup screens
boolean set_weapon_active = false; // in weapons setup screen
boolean set_status_active = false; // in status bar/hud setup screen
boolean set_auto_active = false; // in automap setup screen
boolean set_enemy_active = false; // in enemies setup screen
boolean set_mess_active = false; // in messages setup screen
boolean set_chat_active = false; // in chat string setup screen
boolean setup_select = false; // changing an item
boolean setup_gather = false; // gathering keys for value
boolean colorbox_active = false; // color palette being shown
boolean default_verify = false; // verify reset defaults decision
boolean set_general_active = false;
boolean set_compat_active = false;
/////////////////////////////
//
// set_menu_itemon is an index that starts at zero, and tells you which
// item on the current screen the cursor is sitting on.
//
// current_setup_menu is a pointer to the current setup menu table.
static int set_menu_itemon; // which setup item is selected? // phares 3/98
setup_menu_t* current_setup_menu; // points to current setup menu table
/////////////////////////////
//
// The menu_buffer is used to construct strings for display on the screen.
static char menu_buffer[64];
/////////////////////////////
//
// The setup_e enum is used to provide a unique number for each group of Setup
// Screens.
enum
{
set_compat,
set_key_bindings,
set_weapons,
set_statbar,
set_automap,
set_enemy,
set_messages,
set_chatstrings,
set_setup_end
} setup_e;
int setup_screen; // the current setup screen. takes values from setup_e
/////////////////////////////
//
// SetupMenu is the definition of what the main Setup Screen should look
// like. Each entry shows that the cursor can land on each item (1), the
// built-in graphic lump (i.e. "M_KEYBND") that should be displayed,
// the program which takes over when an item is selected, and the hotkey
// associated with the item.
menuitem_t SetupMenu[]=
{
{1,"M_COMPAT",M_Compat, 'p'},
{1,"M_KEYBND",M_KeyBindings,'k'},
{1,"M_WEAP" ,M_Weapons, 'w'},
{1,"M_STAT" ,M_StatusBar, 's'},
{1,"M_AUTO" ,M_Automap, 'a'},
{1,"M_ENEM" ,M_Enemy, 'e'},
{1,"M_MESS" ,M_Messages, 'm'},
{1,"M_CHAT" ,M_ChatStrings,'c'},
};
/////////////////////////////
//
// M_DoNothing does just that: nothing. Just a placeholder.
static void M_DoNothing(int choice)
{
}
/////////////////////////////
//
// Items needed to satisfy the 'Big Font' menu structures:
//
// the generic_setup_e enum mimics the 'Big Font' menu structures, but
// means nothing to the Setup Menus.
enum
{
generic_setupempty1,
generic_setup_end
} generic_setup_e;
// Generic_Setup is a do-nothing definition that the mainstream Menu code
// can understand, while the Setup Menu code is working. Another placeholder.
menuitem_t Generic_Setup[] =
{
{1,"",M_DoNothing,0}
};
/////////////////////////////
//
// SetupDef is the menu definition that the mainstream Menu code understands.
// This is used by M_Setup (below) to define what is drawn and what is done
// with the main Setup screen.
menu_t SetupDef =
{
set_setup_end, // number of Setup Menu items (Key Bindings, etc.)
&OptionsDef, // menu to return to when BACKSPACE is hit on this menu
SetupMenu, // definition of items to show on the Setup Screen
M_DrawSetup, // program that draws the Setup Screen
59,37, // x,y position of the skull (modified when the skull is
// drawn). The skull is parked on the upper-left corner
// of the Setup screens, since it isn't needed as a cursor
0 // last item the user was on for this menu
};
/////////////////////////////
//
// Here are the definitions of the individual Setup Menu screens. They
// follow the format of the 'Big Font' menu structures. See the comments
// for SetupDef (above) to help understand what each of these says.
menu_t KeybndDef =
{
generic_setup_end,
&SetupDef,
Generic_Setup,
M_DrawKeybnd,
34,5, // skull drawn here
0
};
menu_t WeaponDef =
{
generic_setup_end,
&SetupDef,
Generic_Setup,
M_DrawWeapons,
34,5, // skull drawn here
0
};
menu_t StatusHUDDef =
{
generic_setup_end,
&SetupDef,
Generic_Setup,
M_DrawStatusHUD,
34,5, // skull drawn here
0
};
menu_t AutoMapDef =
{
generic_setup_end,
&SetupDef,
Generic_Setup,
M_DrawAutoMap,
34,5, // skull drawn here
0
};
menu_t EnemyDef = // phares 4/08/98
{
generic_setup_end,
&SetupDef,
Generic_Setup,
M_DrawEnemy,
34,5, // skull drawn here
0
};
menu_t MessageDef = // phares 4/08/98
{
generic_setup_end,
&SetupDef,
Generic_Setup,
M_DrawMessages,
34,5, // skull drawn here
0
};
menu_t ChatStrDef = // phares 4/10/98
{
generic_setup_end,
&SetupDef,
Generic_Setup,
M_DrawChatStrings,
34,5, // skull drawn here
0
};
menu_t GeneralDef = // killough 10/98
{
generic_setup_end,
&OptionsDef,
Generic_Setup,
M_DrawGeneral,
34,5, // skull drawn here
0
};
menu_t CompatDef = // killough 10/98
{
generic_setup_end,
&SetupDef,
Generic_Setup,
M_DrawCompat,
34,5, // skull drawn here
0
};
/////////////////////////////
//
// Draws the Title for the main Setup screen
void M_DrawSetup(void)
{
// CPhipps - patch drawing updated
V_DrawNamePatch(124, 15, 0, "M_SETUP", CR_DEFAULT, VPT_STRETCH);
}
/////////////////////////////
//
// Uses the SetupDef structure to draw the menu items for the main
// Setup screen
void M_Setup(int choice)
{
M_SetupNextMenu(&SetupDef);
}
/////////////////////////////
//
// Data that's used by the Setup screen code
//
// Establish the message colors to be used
#define CR_TITLE CR_GOLD
#define CR_SET CR_GREEN
#define CR_ITEM CR_RED
#define CR_HILITE CR_ORANGE
#define CR_SELECT CR_GRAY
// Data used by the Automap color selection code
#define CHIP_SIZE 7 // size of color block for colored items
#define COLORPALXORIG ((320 - 16*(CHIP_SIZE+1))/2)
#define COLORPALYORIG ((200 - 16*(CHIP_SIZE+1))/2)
#define PAL_BLACK 0
#define PAL_WHITE 4
// Data used by the Chat String editing code
#define CHAT_STRING_BFR_SIZE 128
// chat strings must fit in this screen space
// killough 10/98: reduced, for more general uses
#define MAXCHATWIDTH 272
int chat_index;
char* chat_string_buffer; // points to new chat strings while editing
/////////////////////////////
//
// phares 4/17/98:
// Added 'Reset to Defaults' Button to Setup Menu screens
// This is a small button that sits in the upper-right-hand corner of
// the first screen for each group. It blinks when selected, thus the
// two patches, which it toggles back and forth.
char ResetButtonName[2][8] = {"M_BUTT1","M_BUTT2"};
/////////////////////////////
//
// phares 4/18/98:
// Consolidate Item drawing code
//
// M_DrawItem draws the description of the provided item (the left-hand
// part). A different color is used for the text depending on whether the
// item is selected or not, or whether it's about to change.
// CPhipps - static, hanging else removed, const parameter
static void M_DrawItem(const setup_menu_t* s)
{
int x = s->m_x;
int y = s->m_y;
int flags = s->m_flags;
if (flags & S_RESET)
// This item is the reset button
// Draw the 'off' version if this isn't the current menu item
// Draw the blinking version in tune with the blinking skull otherwise
// proff/nicolas 09/20/98 -- changed for hi-res
// CPhipps - Patch drawing updated, reformatted
V_DrawNamePatch(x, y, 0, ResetButtonName[(flags & (S_HILITE|S_SELECT)) ? whichSkull : 0],
CR_DEFAULT, VPT_STRETCH);
else { // Draw the item string
char *p, *t;
int w = 0;
int color =
flags & S_SELECT ? CR_SELECT :
flags & S_HILITE ? CR_HILITE :
flags & (S_TITLE|S_NEXT|S_PREV) ? CR_TITLE : CR_ITEM; // killough 10/98
/* killough 10/98:
* Enhance to support multiline text separated by newlines.
* This supports multiline items on horizontally-crowded menus.
*/
for (p = t = strdup(s->m_text); (p = strtok(p,"\n")); y += 8, p = NULL)
{ /* killough 10/98: support left-justification: */
strcpy(menu_buffer,p);
if (!(flags & S_LEFTJUST))
w = M_GetPixelWidth(menu_buffer) + 4;
M_DrawMenuString(x - w, y ,color);
}
free(t);
}
}
// If a number item is being changed, allow up to N keystrokes to 'gather'
// the value. Gather_count tells you how many you have so far. The legality
// of what is gathered is determined by the low/high settings for the item.
#define MAXGATHER 5
int gather_count;
char gather_buffer[MAXGATHER+1]; // killough 10/98: make input character-based
/////////////////////////////
//
// phares 4/18/98:
// Consolidate Item Setting drawing code
//
// M_DrawSetting draws the setting of the provided item (the right-hand
// part. It determines the text color based on whether the item is
// selected or being changed. Then, depending on the type of item, it
// displays the appropriate setting value: yes/no, a key binding, a number,
// a paint chip, etc.
static void M_DrawSetting(const setup_menu_t* s)
{
int x = s->m_x, y = s->m_y, flags = s->m_flags, color;
// Determine color of the text. This may or may not be used later,
// depending on whether the item is a text string or not.
color = flags & S_SELECT ? CR_SELECT : flags & S_HILITE ? CR_HILITE : CR_SET;
// Is the item a YES/NO item?
if (flags & S_YESNO) {
strcpy(menu_buffer,*s->var.def->location.pi ? "YES" : "NO");
M_DrawMenuString(x,y,color);
return;
}
// Is the item a simple number?
if (flags & S_NUM) {
// killough 10/98: We must draw differently for items being gathered.
if (flags & (S_HILITE|S_SELECT) && setup_gather) {
gather_buffer[gather_count] = 0;
strcpy(menu_buffer, gather_buffer);
}
else
sprintf(menu_buffer,"%d",*s->var.def->location.pi);
M_DrawMenuString(x,y,color);
return;
}
// Is the item a key binding?
if (flags & S_KEY) { // Key Binding
int *key = s->var.m_key;
// Draw the key bound to the action
if (key) {
M_GetKeyString(*key,0); // string to display
if (key == &key_use) {
// For the 'use' key, you have to build the string
if (s->m_mouse)
sprintf(menu_buffer+strlen(menu_buffer), "/DBL-CLK MB%d",*s->m_mouse+1);
if (s->m_joy)
sprintf(menu_buffer+strlen(menu_buffer), "/JSB%d",*s->m_joy+1);
}
else if (key == &key_up || key == &key_speed ||
key == &key_fire || key == &key_strafe)
{
if (s->m_mouse)
sprintf(menu_buffer+strlen(menu_buffer), "/MB%d",
*s->m_mouse+1);
if (s->m_joy)
sprintf(menu_buffer+strlen(menu_buffer), "/JSB%d",
*s->m_joy+1);
}
M_DrawMenuString(x,y,color);
}
return;
}
// Is the item a weapon number?
// OR, Is the item a colored text string from the Automap?
//
// killough 10/98: removed special code, since the rest of the engine
// already takes care of it, and this code prevented the user from setting
// their overall weapons preferences while playing Doom 1.
//
// killough 11/98: consolidated weapons code with color range code
if (flags & (S_WEAP|S_CRITEM)) // weapon number or color range
{
sprintf(menu_buffer,"%d", *s->var.def->location.pi);
M_DrawMenuString(x,y, flags & S_CRITEM ? *s->var.def->location.pi : color);
return;
}
// Is the item a paint chip?
if (flags & S_COLOR) // Automap paint chip
{
int ch;
ch = *s->var.def->location.pi;
// proff 12/6/98: Drawing of colorchips completly changed for hi-res, it now uses a patch
// draw the paint chip
V_FillRect(0, x*SCREENWIDTH/320, (y-1)*SCREENHEIGHT/200,
8*SCREENWIDTH/320, 8*SCREENHEIGHT/200,
PAL_BLACK);
V_FillRect(0, (x+1)*SCREENWIDTH/320, y*SCREENHEIGHT/200,
6*SCREENWIDTH/320, 6*SCREENHEIGHT/200,
(byte)ch);
if (!ch) // don't show this item in automap mode
V_DrawNamePatch(x+1,y,0,"M_PALNO", CR_DEFAULT, VPT_STRETCH);
return;
}
// Is the item a chat string?
// killough 10/98: or a filename?
if (flags & S_STRING) {
/* cph - cast to char* as it's really a Z_Strdup'd string (see m_misc.h) */
char *text = (char*)*s->var.def->location.ppsz;
// Are we editing this string? If so, display a cursor under
// the correct character.
if (setup_select && (s->m_flags & (S_HILITE|S_SELECT))) {
int cursor_start, char_width;
char c[2];
// If the string is too wide for the screen, trim it back,
// one char at a time until it fits. This should only occur
// while you're editing the string.
while (M_GetPixelWidth(text) >= MAXCHATWIDTH) {
int len = strlen(text);
text[--len] = 0;
if (chat_index > len)
chat_index--;
}
// Find the distance from the beginning of the string to
// where the cursor should be drawn, plus the width of
// the char the cursor is under..
*c = text[chat_index]; // hold temporarily
c[1] = 0;
char_width = M_GetPixelWidth(c);
if (char_width == 1)
char_width = 7; // default for end of line
text[chat_index] = 0; // NULL to get cursor position
cursor_start = M_GetPixelWidth(text);
text[chat_index] = *c; // replace stored char
// Now draw the cursor
// proff 12/6/98: Drawing of cursor changed for hi-res
V_FillRect(0, ((x+cursor_start-1)*SCREENWIDTH)/320, (y*SCREENHEIGHT)/200,
(char_width*SCREENWIDTH)/320, 9*SCREENHEIGHT/200, PAL_WHITE);
}
// Draw the setting for the item
strcpy(menu_buffer,text);
M_DrawMenuString(x,y,color);
return;
}
// Is the item a selection of choices?
if (flags & S_CHOICE) {
if (s->var.def->type == def_int) {
if (s->selectstrings == NULL) {
sprintf(menu_buffer,"%d",*s->var.def->location.pi);
} else {
strcpy(menu_buffer,s->selectstrings[*s->var.def->location.pi]);
}
}
if (s->var.def->type == def_str) {
sprintf(menu_buffer,"%s", *s->var.def->location.ppsz);
}
M_DrawMenuString(x,y,color);
return;
}
}
/////////////////////////////
//
// M_DrawScreenItems takes the data for each menu item and gives it to
// the drawing routines above.
// CPhipps - static, const parameter, formatting
static void M_DrawScreenItems(const setup_menu_t* src)
{
if (print_warning_about_changes > 0) { /* killough 8/15/98: print warning */
if (warning_about_changes & S_BADVAL) {
strcpy(menu_buffer, "Value out of Range");
M_DrawMenuString(100,176,CR_RED);
} else if (warning_about_changes & S_PRGWARN) {
strcpy(menu_buffer, "Warning: Program must be restarted to see changes");
M_DrawMenuString(3, 176, CR_RED);
} else if (warning_about_changes & S_BADVID) {
strcpy(menu_buffer, "Video mode not supported");
M_DrawMenuString(80,176,CR_RED);
} else {
strcpy(menu_buffer, "Warning: Changes are pending until next game");
M_DrawMenuString(18,184,CR_RED);
}
}
while (!(src->m_flags & S_END)) {
// See if we're to draw the item description (left-hand part)
if (src->m_flags & S_SHOWDESC)
M_DrawItem(src);
// See if we're to draw the setting (right-hand part)
if (src->m_flags & S_SHOWSET)
M_DrawSetting(src);
src++;
}
}
/////////////////////////////
//
// Data used to draw the "are you sure?" dialogue box when resetting
// to defaults.
#define VERIFYBOXXORG 66
#define VERIFYBOXYORG 88
#define PAL_GRAY1 91
#define PAL_GRAY2 98
#define PAL_GRAY3 105
// And the routine to draw it.
static void M_DrawDefVerify(void)
{
// proff 12/6/98: Drawing of verify box changed for hi-res, it now uses a patch
V_DrawNamePatch(VERIFYBOXXORG,VERIFYBOXYORG,0,"M_VBOX",CR_DEFAULT,VPT_STRETCH);
// The blinking messages is keyed off of the blinking of the
// cursor skull.
if (whichSkull) { // blink the text
strcpy(menu_buffer,"Reset to defaults? (Y or N)");
M_DrawMenuString(VERIFYBOXXORG+8,VERIFYBOXYORG+8,CR_RED);
}
}
/////////////////////////////
//
// phares 4/18/98:
// M_DrawInstructions writes the instruction text just below the screen title
//
// cph 2006/08/06 - go back to the Boom version, and then clean up by using
// M_DrawStringCentered (much better than all those magic 'x' valies!)
static void M_DrawInstructions(void)
{
int flags = current_setup_menu[set_menu_itemon].m_flags;
// There are different instruction messages depending on whether you
// are changing an item or just sitting on it.
if (setup_select) {
switch (flags & (S_KEY | S_YESNO | S_WEAP | S_NUM | S_COLOR | S_CRITEM | S_CHAT | S_RESET | S_FILE | S_CHOICE)) {
case S_KEY:
// See if a joystick or mouse button setting is allowed for
// this item.
if (current_setup_menu[set_menu_itemon].m_mouse || current_setup_menu[set_menu_itemon].m_joy)
M_DrawStringCentered(160, 20, CR_SELECT, "Press key or button for this action");
else
M_DrawStringCentered(160, 20, CR_SELECT, "Press key for this action");
break;
case S_YESNO:
M_DrawStringCentered(160, 20, CR_SELECT, "Press ENTER key to toggle");
break;
case S_WEAP:
M_DrawStringCentered(160, 20, CR_SELECT, "Enter weapon number");
break;
case S_NUM:
M_DrawStringCentered(160, 20, CR_SELECT, "Enter value. Press ENTER when finished.");
break;
case S_COLOR:
M_DrawStringCentered(160, 20, CR_SELECT, "Select color and press enter");
break;
case S_CRITEM:
M_DrawStringCentered(160, 20, CR_SELECT, "Enter value");
break;
case S_CHAT:
M_DrawStringCentered(160, 20, CR_SELECT, "Type/edit chat string and Press ENTER");
break;
case S_FILE:
M_DrawStringCentered(160, 20, CR_SELECT, "Type/edit filename and Press ENTER");
break;
case S_CHOICE:
M_DrawStringCentered(160, 20, CR_SELECT, "Press left or right to choose");
break;
case S_RESET:
break;
#ifdef SIMPLECHECKS
default:
lprintf(LO_WARN,"Unrecognised menu item type %d", flags);
#endif
}
} else {
if (flags & S_RESET)
M_DrawStringCentered(160, 20, CR_HILITE, "Press ENTER key to reset to defaults");
else
M_DrawStringCentered(160, 20, CR_HILITE, "Press Enter to Change");
}
}
/////////////////////////////
//
// The Key Binding Screen tables.
#define KB_X 160
#define KB_PREV 57
#define KB_NEXT 310
#define KB_Y 31
// phares 4/16/98:
// X,Y position of reset button. This is the same for every screen, and is
// only defined once here.
#define X_BUTTON 301
#define Y_BUTTON 3
// Definitions of the (in this case) four key binding screens.
setup_menu_t keys_settings1[];
setup_menu_t keys_settings2[];
setup_menu_t keys_settings3[];
setup_menu_t keys_settings4[];
// The table which gets you from one screen table to the next.
setup_menu_t* keys_settings[] =
{
keys_settings1,
keys_settings2,
keys_settings3,
keys_settings4,
NULL
};
int mult_screens_index; // the index of the current screen in a set
// Here's an example from this first screen, with explanations.
//
// {
// "STRAFE", // The description of the item ('strafe' key)
// S_KEY, // This is a key binding item
// m_scrn, // It belongs to the m_scrn group. Its key cannot be
// // bound to two items in this group.
// KB_X, // The X offset of the start of the right-hand side
// KB_Y+ 8*8, // The Y offset of the start of the right-hand side.
// // Always given in multiples off a baseline.
// &key_strafe, // The variable that holds the key value bound to this
// OR a string that holds the config variable name.
// OR a pointer to another setup_menu
// &mousebstrafe, // The variable that holds the mouse button bound to
// this. If zero, no mouse button can be bound here.
// &joybstrafe, // The variable that holds the joystick button bound to
// this. If zero, no mouse button can be bound here.
// }
// The first Key Binding screen table.
// Note that the Y values are ascending. If you need to add something to
// this table, (well, this one's not a good example, because it's full)
// you need to make sure the Y values still make sense so everything gets
// displayed.
//
// Note also that the first screen of each set has a line for the reset
// button. If there is more than one screen in a set, the others don't get
// the reset button.
//
// Note also that this screen has a "NEXT ->" line. This acts like an
// item, in that 'activating' it moves you along to the next screen. If
// there's a "<- PREV" item on a screen, it behaves similarly, moving you
// to the previous screen. If you leave these off, you can't move from
// screen to screen.
setup_menu_t keys_settings1[] = // Key Binding screen strings
{
{"MOVEMENT" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y},
{"FORWARD" ,S_KEY ,m_scrn,KB_X,KB_Y+1*8,{&key_up},&mousebforward},
{"BACKWARD" ,S_KEY ,m_scrn,KB_X,KB_Y+2*8,{&key_down}},
{"TURN LEFT" ,S_KEY ,m_scrn,KB_X,KB_Y+3*8,{&key_left}},
{"TURN RIGHT" ,S_KEY ,m_scrn,KB_X,KB_Y+4*8,{&key_right}},
{"RUN" ,S_KEY ,m_scrn,KB_X,KB_Y+5*8,{&key_speed},0,&joybspeed},
{"STRAFE LEFT" ,S_KEY ,m_scrn,KB_X,KB_Y+6*8,{&key_strafeleft}},
{"STRAFE RIGHT",S_KEY ,m_scrn,KB_X,KB_Y+7*8,{&key_straferight}},
{"STRAFE" ,S_KEY ,m_scrn,KB_X,KB_Y+8*8,{&key_strafe},&mousebstrafe,&joybstrafe},
{"AUTORUN" ,S_KEY ,m_scrn,KB_X,KB_Y+9*8,{&key_autorun}},
{"180 TURN" ,S_KEY ,m_scrn,KB_X,KB_Y+10*8,{&key_reverse}},
{"USE" ,S_KEY ,m_scrn,KB_X,KB_Y+11*8,{&key_use},&mousebforward,&joybuse},
{"MENUS" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y+12*8},
{"NEXT ITEM" ,S_KEY ,m_menu,KB_X,KB_Y+13*8,{&key_menu_down}},
{"PREV ITEM" ,S_KEY ,m_menu,KB_X,KB_Y+14*8,{&key_menu_up}},
{"LEFT" ,S_KEY ,m_menu,KB_X,KB_Y+15*8,{&key_menu_left}},
{"RIGHT" ,S_KEY ,m_menu,KB_X,KB_Y+16*8,{&key_menu_right}},
{"BACKSPACE" ,S_KEY ,m_menu,KB_X,KB_Y+17*8,{&key_menu_backspace}},
{"SELECT ITEM" ,S_KEY ,m_menu,KB_X,KB_Y+18*8,{&key_menu_enter}},
{"EXIT" ,S_KEY ,m_menu,KB_X,KB_Y+19*8,{&key_menu_escape}},
// Button for resetting to defaults
{0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
{"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {keys_settings2}},
// Final entry
{0,S_SKIP|S_END,m_null}
};
setup_menu_t keys_settings2[] = // Key Binding screen strings
{
{"SCREEN" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y},
// phares 4/13/98:
// key_help and key_escape can no longer be rebound. This keeps the
// player from getting themselves in a bind where they can't remember how
// to get to the menus, and can't remember how to get to the help screen
// to give them a clue as to how to get to the menus. :)
// Also, the keys assigned to these functions cannot be bound to other
// functions. Introduce an S_KEEP flag to show that you cannot swap this
// key with other keys in the same 'group'. (m_scrn, etc.)
{"HELP" ,S_SKIP|S_KEEP ,m_scrn,0 ,0 ,{&key_help}},
{"MENU" ,S_SKIP|S_KEEP ,m_scrn,0 ,0 ,{&key_escape}},
// killough 10/98: hotkey for entering setup menu:
{"SETUP" ,S_KEY ,m_scrn,KB_X,KB_Y+ 1*8,{&key_setup}},
{"PAUSE" ,S_KEY ,m_scrn,KB_X,KB_Y+ 2*8,{&key_pause}},
{"AUTOMAP" ,S_KEY ,m_scrn,KB_X,KB_Y+ 3*8,{&key_map}},
{"VOLUME" ,S_KEY ,m_scrn,KB_X,KB_Y+ 4*8,{&key_soundvolume}},
{"HUD" ,S_KEY ,m_scrn,KB_X,KB_Y+ 5*8,{&key_hud}},
{"MESSAGES" ,S_KEY ,m_scrn,KB_X,KB_Y+ 6*8,{&key_messages}},
{"GAMMA FIX" ,S_KEY ,m_scrn,KB_X,KB_Y+ 7*8,{&key_gamma}},
{"SPY" ,S_KEY ,m_scrn,KB_X,KB_Y+ 8*8,{&key_spy}},
{"LARGER VIEW" ,S_KEY ,m_scrn,KB_X,KB_Y+ 9*8,{&key_zoomin}},
{"SMALLER VIEW",S_KEY ,m_scrn,KB_X,KB_Y+10*8,{&key_zoomout}},
{"SCREENSHOT" ,S_KEY ,m_scrn,KB_X,KB_Y+11*8,{&key_screenshot}},
{"GAME" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y+12*8},
{"SAVE" ,S_KEY ,m_scrn,KB_X,KB_Y+13*8,{&key_savegame}},
{"LOAD" ,S_KEY ,m_scrn,KB_X,KB_Y+14*8,{&key_loadgame}},
{"QUICKSAVE" ,S_KEY ,m_scrn,KB_X,KB_Y+15*8,{&key_quicksave}},
{"QUICKLOAD" ,S_KEY ,m_scrn,KB_X,KB_Y+16*8,{&key_quickload}},
{"END GAME" ,S_KEY ,m_scrn,KB_X,KB_Y+17*8,{&key_endgame}},
{"QUIT" ,S_KEY ,m_scrn,KB_X,KB_Y+18*8,{&key_quit}},
{"<- PREV", S_SKIP|S_PREV,m_null,KB_PREV,KB_Y+20*8, {keys_settings1}},
{"NEXT ->", S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {keys_settings3}},
// Final entry
{0,S_SKIP|S_END,m_null}
};
setup_menu_t keys_settings3[] = // Key Binding screen strings
{
{"WEAPONS" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y},
{"FIST" ,S_KEY ,m_scrn,KB_X,KB_Y+ 1*8,{&key_weapon1}},
{"PISTOL" ,S_KEY ,m_scrn,KB_X,KB_Y+ 2*8,{&key_weapon2}},
{"SHOTGUN" ,S_KEY ,m_scrn,KB_X,KB_Y+ 3*8,{&key_weapon3}},
{"CHAINGUN",S_KEY ,m_scrn,KB_X,KB_Y+ 4*8,{&key_weapon4}},
{"ROCKET" ,S_KEY ,m_scrn,KB_X,KB_Y+ 5*8,{&key_weapon5}},
{"PLASMA" ,S_KEY ,m_scrn,KB_X,KB_Y+ 6*8,{&key_weapon6}},
{"BFG", S_KEY ,m_scrn,KB_X,KB_Y+ 7*8,{&key_weapon7}},
{"CHAINSAW",S_KEY ,m_scrn,KB_X,KB_Y+ 8*8,{&key_weapon8}},
{"SSG" ,S_KEY ,m_scrn,KB_X,KB_Y+ 9*8,{&key_weapon9}},
{"BEST" ,S_KEY ,m_scrn,KB_X,KB_Y+10*8,{&key_weapontoggle}},
{"FIRE" ,S_KEY ,m_scrn,KB_X,KB_Y+11*8,{&key_fire},&mousebfire,&joybfire},
{"<- PREV",S_SKIP|S_PREV,m_null,KB_PREV,KB_Y+20*8, {keys_settings2}},
{"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {keys_settings4}},
// Final entry
{0,S_SKIP|S_END,m_null}
};
setup_menu_t keys_settings4[] = // Key Binding screen strings
{
{"AUTOMAP" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y},
{"FOLLOW" ,S_KEY ,m_map ,KB_X,KB_Y+ 1*8,{&key_map_follow}},
{"ZOOM IN" ,S_KEY ,m_map ,KB_X,KB_Y+ 2*8,{&key_map_zoomin}},
{"ZOOM OUT" ,S_KEY ,m_map ,KB_X,KB_Y+ 3*8,{&key_map_zoomout}},
{"SHIFT UP" ,S_KEY ,m_map ,KB_X,KB_Y+ 4*8,{&key_map_up}},
{"SHIFT DOWN" ,S_KEY ,m_map ,KB_X,KB_Y+ 5*8,{&key_map_down}},
{"SHIFT LEFT" ,S_KEY ,m_map ,KB_X,KB_Y+ 6*8,{&key_map_left}},
{"SHIFT RIGHT",S_KEY ,m_map ,KB_X,KB_Y+ 7*8,{&key_map_right}},
{"MARK PLACE" ,S_KEY ,m_map ,KB_X,KB_Y+ 8*8,{&key_map_mark}},
{"CLEAR MARKS",S_KEY ,m_map ,KB_X,KB_Y+ 9*8,{&key_map_clear}},
{"FULL/ZOOM" ,S_KEY ,m_map ,KB_X,KB_Y+10*8,{&key_map_gobig}},
{"GRID" ,S_KEY ,m_map ,KB_X,KB_Y+11*8,{&key_map_grid}},
{"CHATTING" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y+12*8},
{"BEGIN CHAT" ,S_KEY ,m_scrn,KB_X,KB_Y+13*8,{&key_chat}},
{"PLAYER 1" ,S_KEY ,m_scrn,KB_X,KB_Y+14*8,{&destination_keys[0]}},
{"PLAYER 2" ,S_KEY ,m_scrn,KB_X,KB_Y+15*8,{&destination_keys[1]}},
{"PLAYER 3" ,S_KEY ,m_scrn,KB_X,KB_Y+16*8,{&destination_keys[2]}},
{"PLAYER 4" ,S_KEY ,m_scrn,KB_X,KB_Y+17*8,{&destination_keys[3]}},
{"BACKSPACE" ,S_KEY ,m_scrn,KB_X,KB_Y+18*8,{&key_backspace}},
{"ENTER" ,S_KEY ,m_scrn,KB_X,KB_Y+19*8,{&key_enter}},
{"<- PREV" ,S_SKIP|S_PREV,m_null,KB_PREV,KB_Y+20*8, {keys_settings3}},
// Final entry
{0,S_SKIP|S_END,m_null}
};
// Setting up for the Key Binding screen. Turn on flags, set pointers,
// locate the first item on the screen where the cursor is allowed to
// land.
void M_KeyBindings(int choice)
{
M_SetupNextMenu(&KeybndDef);
setup_active = true;
setup_screen = ss_keys;
set_keybnd_active = true;
setup_select = false;
default_verify = false;
setup_gather = false;
mult_screens_index = 0;
current_setup_menu = keys_settings[0];
set_menu_itemon = 0;
while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
}
// The drawing part of the Key Bindings Setup initialization. Draw the
// background, title, instruction line, and items.
void M_DrawKeybnd(void)
{
inhelpscreens = true; // killough 4/6/98: Force status bar redraw
// Set up the Key Binding screen
M_DrawBackground("FLOOR4_6", 0); // Draw background
// proff/nicolas 09/20/98 -- changed for hi-res
V_DrawNamePatch(84, 2, 0, "M_KEYBND", CR_DEFAULT, VPT_STRETCH);
M_DrawInstructions();
M_DrawScreenItems(current_setup_menu);
// If the Reset Button has been selected, an "Are you sure?" message
// is overlayed across everything else.
if (default_verify)
M_DrawDefVerify();
}
/////////////////////////////
//
// The Weapon Screen tables.
#define WP_X 203
#define WP_Y 33
// There's only one weapon settings screen (for now). But since we're
// trying to fit a common description for screens, it gets a setup_menu_t,
// which only has one screen definition in it.
//
// Note that this screen has no PREV or NEXT items, since there are no
// neighboring screens.
enum { // killough 10/98: enum for y-offset info
weap_recoil,
weap_bobbing,
weap_bfg,
weap_stub1,
weap_pref1,
weap_pref2,
weap_pref3,
weap_pref4,
weap_pref5,
weap_pref6,
weap_pref7,
weap_pref8,
weap_pref9,
weap_stub2,
weap_toggle,
weap_toggle2,
};
setup_menu_t weap_settings1[];
setup_menu_t* weap_settings[] =
{
weap_settings1,
NULL
};
setup_menu_t weap_settings1[] = // Weapons Settings screen
{
{"ENABLE RECOIL", S_YESNO,m_null,WP_X, WP_Y+ weap_recoil*8, {"weapon_recoil"}},
{"ENABLE BOBBING",S_YESNO,m_null,WP_X, WP_Y+weap_bobbing*8, {"player_bobbing"}},
{"1ST CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref1*8, {"weapon_choice_1"}},
{"2nd CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref2*8, {"weapon_choice_2"}},
{"3rd CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref3*8, {"weapon_choice_3"}},
{"4th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref4*8, {"weapon_choice_4"}},
{"5th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref5*8, {"weapon_choice_5"}},
{"6th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref6*8, {"weapon_choice_6"}},
{"7th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref7*8, {"weapon_choice_7"}},
{"8th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref8*8, {"weapon_choice_8"}},
{"9th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref9*8, {"weapon_choice_9"}},
{"Enable Fist/Chainsaw\n& SG/SSG toggle", S_YESNO, m_null, WP_X,
WP_Y+ weap_toggle*8, {"doom_weapon_toggles"}},
// Button for resetting to defaults
{0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
// Final entry
{0,S_SKIP|S_END,m_null}
};
// Setting up for the Weapons screen. Turn on flags, set pointers,
// locate the first item on the screen where the cursor is allowed to
// land.
void M_Weapons(int choice)
{
M_SetupNextMenu(&WeaponDef);
setup_active = true;
setup_screen = ss_weap;
set_weapon_active = true;
setup_select = false;
default_verify = false;
setup_gather = false;
mult_screens_index = 0;
current_setup_menu = weap_settings[0];
set_menu_itemon = 0;
while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
}
// The drawing part of the Weapons Setup initialization. Draw the
// background, title, instruction line, and items.
void M_DrawWeapons(void)
{
inhelpscreens = true; // killough 4/6/98: Force status bar redraw
M_DrawBackground("FLOOR4_6", 0); // Draw background
// proff/nicolas 09/20/98 -- changed for hi-res
V_DrawNamePatch(109, 2, 0, "M_WEAP", CR_DEFAULT, VPT_STRETCH);
M_DrawInstructions();
M_DrawScreenItems(current_setup_menu);
// If the Reset Button has been selected, an "Are you sure?" message
// is overlayed across everything else.
if (default_verify)
M_DrawDefVerify();
}
/////////////////////////////
//
// The Status Bar / HUD tables.
#define ST_X 203
#define ST_Y 31
// Screen table definitions
setup_menu_t stat_settings1[];
setup_menu_t* stat_settings[] =
{
stat_settings1,
NULL
};
setup_menu_t stat_settings1[] = // Status Bar and HUD Settings screen
{
{"STATUS BAR" ,S_SKIP|S_TITLE,m_null,ST_X,ST_Y+ 1*8 },
{"USE RED NUMBERS" ,S_YESNO, m_null,ST_X,ST_Y+ 2*8, {"sts_always_red"}},
{"GRAY %" ,S_YESNO, m_null,ST_X,ST_Y+ 3*8, {"sts_pct_always_gray"}},
{"SINGLE KEY DISPLAY",S_YESNO, m_null,ST_X,ST_Y+ 4*8, {"sts_traditional_keys"}},
{"HEADS-UP DISPLAY" ,S_SKIP|S_TITLE,m_null,ST_X,ST_Y+ 6*8},
{"HIDE SECRETS" ,S_YESNO ,m_null,ST_X,ST_Y+ 7*8, {"hud_nosecrets"}},
{"HEALTH LOW/OK" ,S_NUM ,m_null,ST_X,ST_Y+ 8*8, {"health_red"}},
{"HEALTH OK/GOOD" ,S_NUM ,m_null,ST_X,ST_Y+ 9*8, {"health_yellow"}},
{"HEALTH GOOD/EXTRA" ,S_NUM ,m_null,ST_X,ST_Y+10*8, {"health_green"}},
{"ARMOR LOW/OK" ,S_NUM ,m_null,ST_X,ST_Y+11*8, {"armor_red"}},
{"ARMOR OK/GOOD" ,S_NUM ,m_null,ST_X,ST_Y+12*8, {"armor_yellow"}},
{"ARMOR GOOD/EXTRA" ,S_NUM ,m_null,ST_X,ST_Y+13*8, {"armor_green"}},
{"AMMO LOW/OK" ,S_NUM ,m_null,ST_X,ST_Y+14*8, {"ammo_red"}},
{"AMMO OK/GOOD" ,S_NUM ,m_null,ST_X,ST_Y+15*8, {"ammo_yellow"}},
// Button for resetting to defaults
{0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
// Final entry
{0,S_SKIP|S_END,m_null}
};
// Setting up for the Status Bar / HUD screen. Turn on flags, set pointers,
// locate the first item on the screen where the cursor is allowed to
// land.
void M_StatusBar(int choice)
{
M_SetupNextMenu(&StatusHUDDef);
setup_active = true;
setup_screen = ss_stat;
set_status_active = true;
setup_select = false;
default_verify = false;
setup_gather = false;
mult_screens_index = 0;
current_setup_menu = stat_settings[0];
set_menu_itemon = 0;
while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
}
// The drawing part of the Status Bar / HUD Setup initialization. Draw the
// background, title, instruction line, and items.
void M_DrawStatusHUD(void)
{
inhelpscreens = true; // killough 4/6/98: Force status bar redraw
M_DrawBackground("FLOOR4_6", 0); // Draw background
// proff/nicolas 09/20/98 -- changed for hi-res
V_DrawNamePatch(59, 2, 0, "M_STAT", CR_DEFAULT, VPT_STRETCH);
M_DrawInstructions();
M_DrawScreenItems(current_setup_menu);
// If the Reset Button has been selected, an "Are you sure?" message
// is overlayed across everything else.
if (default_verify)
M_DrawDefVerify();
}
/////////////////////////////
//
// The Automap tables.
#define AU_X 250
#define AU_Y 31
#define AU_PREV KB_PREV
#define AU_NEXT KB_NEXT
setup_menu_t auto_settings1[];
setup_menu_t auto_settings2[];
setup_menu_t* auto_settings[] =
{
auto_settings1,
auto_settings2,
NULL
};
setup_menu_t auto_settings1[] = // 1st AutoMap Settings screen
{
{"background", S_COLOR, m_null, AU_X, AU_Y, {"mapcolor_back"}},
{"grid lines", S_COLOR, m_null, AU_X, AU_Y + 1*8, {"mapcolor_grid"}},
{"normal 1s wall", S_COLOR, m_null,AU_X,AU_Y+ 2*8, {"mapcolor_wall"}},
{"line at floor height change", S_COLOR, m_null, AU_X, AU_Y+ 3*8, {"mapcolor_fchg"}},
{"line at ceiling height change" ,S_COLOR,m_null,AU_X,AU_Y+ 4*8, {"mapcolor_cchg"}},
{"line at sector with floor = ceiling",S_COLOR,m_null,AU_X,AU_Y+ 5*8, {"mapcolor_clsd"}},
{"red key" ,S_COLOR,m_null,AU_X,AU_Y+ 6*8, {"mapcolor_rkey"}},
{"blue key" ,S_COLOR,m_null,AU_X,AU_Y+ 7*8, {"mapcolor_bkey"}},
{"yellow key" ,S_COLOR,m_null,AU_X,AU_Y+ 8*8, {"mapcolor_ykey"}},
{"red door" ,S_COLOR,m_null,AU_X,AU_Y+ 9*8, {"mapcolor_rdor"}},
{"blue door" ,S_COLOR,m_null,AU_X,AU_Y+10*8, {"mapcolor_bdor"}},
{"yellow door" ,S_COLOR,m_null,AU_X,AU_Y+11*8, {"mapcolor_ydor"}},
{"AUTOMAP LEVEL TITLE COLOR" ,S_CRITEM,m_null,AU_X,AU_Y+13*8, {"hudcolor_titl"}},
{"AUTOMAP COORDINATES COLOR" ,S_CRITEM,m_null,AU_X,AU_Y+14*8, {"hudcolor_xyco"}},
{"Show Secrets only after entering",S_YESNO,m_null,AU_X,AU_Y+15*8, {"map_secret_after"}},
{"Show coordinates of automap pointer",S_YESNO,m_null,AU_X,AU_Y+16*8, {"map_point_coord"}}, // killough 10/98
// Button for resetting to defaults
{0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
{"NEXT ->",S_SKIP|S_NEXT,m_null,AU_NEXT,AU_Y+20*8, {auto_settings2}},
// Final entry
{0,S_SKIP|S_END,m_null}
};
setup_menu_t auto_settings2[] = // 2nd AutoMap Settings screen
{
{"teleporter line" ,S_COLOR ,m_null,AU_X,AU_Y, {"mapcolor_tele"}},
{"secret sector boundary" ,S_COLOR ,m_null,AU_X,AU_Y+ 1*8, {"mapcolor_secr"}},
//jff 4/23/98 add exit line to automap
{"exit line" ,S_COLOR ,m_null,AU_X,AU_Y+ 2*8, {"mapcolor_exit"}},
{"computer map unseen line" ,S_COLOR ,m_null,AU_X,AU_Y+ 3*8, {"mapcolor_unsn"}},
{"line w/no floor/ceiling changes",S_COLOR ,m_null,AU_X,AU_Y+ 4*8, {"mapcolor_flat"}},
{"general sprite" ,S_COLOR ,m_null,AU_X,AU_Y+ 5*8, {"mapcolor_sprt"}},
{"countable enemy sprite" ,S_COLOR ,m_null,AU_X,AU_Y+ 6*8, {"mapcolor_enemy"}}, // cph 2006/06/30
{"countable item sprite" ,S_COLOR ,m_null,AU_X,AU_Y+ 7*8, {"mapcolor_item"}}, // mead 3/4/2003
{"crosshair" ,S_COLOR ,m_null,AU_X,AU_Y+ 8*8, {"mapcolor_hair"}},
{"single player arrow" ,S_COLOR ,m_null,AU_X,AU_Y+ 9*8, {"mapcolor_sngl"}},
{"your colour in multiplayer" ,S_COLOR ,m_null,AU_X,AU_Y+10*8, {"mapcolor_me"}},
{"friends" ,S_COLOR ,m_null,AU_X,AU_Y+12*8, {"mapcolor_frnd"}}, // killough 8/8/98
{"<- PREV",S_SKIP|S_PREV,m_null,AU_PREV,AU_Y+20*8, {auto_settings1}},
// Final entry
{0,S_SKIP|S_END,m_null}
};
// Setting up for the Automap screen. Turn on flags, set pointers,
// locate the first item on the screen where the cursor is allowed to
// land.
void M_Automap(int choice)
{
M_SetupNextMenu(&AutoMapDef);
setup_active = true;
setup_screen = ss_auto;
set_auto_active = true;
setup_select = false;
colorbox_active = false;
default_verify = false;
setup_gather = false;
set_menu_itemon = 0;
mult_screens_index = 0;
current_setup_menu = auto_settings[0];
while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
}
// Data used by the color palette that is displayed for the player to
// select colors.
int color_palette_x; // X position of the cursor on the color palette
int color_palette_y; // Y position of the cursor on the color palette
byte palette_background[16*(CHIP_SIZE+1)+8];
// M_DrawColPal() draws the color palette when the user needs to select a
// color.
// phares 4/1/98: now uses a single lump for the palette instead of
// building the image out of individual paint chips.
static void M_DrawColPal(void)
{
int cpx, cpy;
// Draw a background, border, and paint chips
// proff/nicolas 09/20/98 -- changed for hi-res
// CPhipps - patch drawing updated
V_DrawNamePatch(COLORPALXORIG-5, COLORPALYORIG-5, 0, "M_COLORS", CR_DEFAULT, VPT_STRETCH);
// Draw the cursor around the paint chip
// (cpx,cpy) is the upper left-hand corner of the paint chip
cpx = COLORPALXORIG+color_palette_x*(CHIP_SIZE+1)-1;
cpy = COLORPALYORIG+color_palette_y*(CHIP_SIZE+1)-1;
// proff 12/6/98: Drawing of colorchips completly changed for hi-res, it now uses a patch
V_DrawNamePatch(cpx,cpy,0,"M_PALSEL",CR_DEFAULT,VPT_STRETCH); // PROFF_GL_FIX
}
// The drawing part of the Automap Setup initialization. Draw the
// background, title, instruction line, and items.
void M_DrawAutoMap(void)
{
inhelpscreens = true; // killough 4/6/98: Force status bar redraw
M_DrawBackground("FLOOR4_6", 0); // Draw background
// CPhipps - patch drawing updated
V_DrawNamePatch(109, 2, 0, "M_AUTO", CR_DEFAULT, VPT_STRETCH);
M_DrawInstructions();
M_DrawScreenItems(current_setup_menu);
// If a color is being selected, need to show color paint chips
if (colorbox_active)
M_DrawColPal();
// If the Reset Button has been selected, an "Are you sure?" message
// is overlayed across everything else.
else if (default_verify)
M_DrawDefVerify();
}
/////////////////////////////
//
// The Enemies table.
#define E_X 250
#define E_Y 31
setup_menu_t enem_settings1[];
setup_menu_t* enem_settings[] =
{
enem_settings1,
NULL
};
enum {
enem_infighting,
enem_remember = 1,
enem_backing,
enem_monkeys,
enem_avoid_hazards,
enem_friction,
enem_help_friends,
#ifdef DOGS
enem_helpers,
#endif
enem_distfriend,
#ifdef DOGS
enem_dog_jumping,
#endif
enem_end
};
setup_menu_t enem_settings1[] = // Enemy Settings screen
{
// killough 7/19/98
{"Monster Infighting When Provoked",S_YESNO,m_null,E_X,E_Y+ enem_infighting*8, {"monster_infighting"}},
{"Remember Previous Enemy",S_YESNO,m_null,E_X,E_Y+ enem_remember*8, {"monsters_remember"}},
// killough 9/8/98
{"Monster Backing Out",S_YESNO,m_null,E_X,E_Y+ enem_backing*8, {"monster_backing"}},
{"Climb Steep Stairs", S_YESNO,m_null,E_X,E_Y+enem_monkeys*8, {"monkeys"}},
// killough 9/9/98
{"Intelligently Avoid Hazards",S_YESNO,m_null,E_X,E_Y+ enem_avoid_hazards*8, {"monster_avoid_hazards"}},
// killough 10/98
{"Affected by Friction",S_YESNO,m_null,E_X,E_Y+ enem_friction*8, {"monster_friction"}},
{"Rescue Dying Friends",S_YESNO,m_null,E_X,E_Y+ enem_help_friends*8, {"help_friends"}},
#ifdef DOGS
// killough 7/19/98
{"Number Of Single-Player Helper Dogs",S_NUM|S_LEVWARN,m_null,E_X,E_Y+ enem_helpers*8, {"player_helpers"}},
// killough 8/8/98
{"Distance Friends Stay Away",S_NUM,m_null,E_X,E_Y+ enem_distfriend*8, {"friend_distance"}},
{"Allow dogs to jump down",S_YESNO,m_null,E_X,E_Y+ enem_dog_jumping*8, {"dog_jumping"}},
#endif
// Button for resetting to defaults
{0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
// Final entry
{0,S_SKIP|S_END,m_null}
};
/////////////////////////////
// Setting up for the Enemies screen. Turn on flags, set pointers,
// locate the first item on the screen where the cursor is allowed to
// land.
void M_Enemy(int choice)
{
M_SetupNextMenu(&EnemyDef);
setup_active = true;
setup_screen = ss_enem;
set_enemy_active = true;
setup_select = false;
default_verify = false;
setup_gather = false;
mult_screens_index = 0;
current_setup_menu = enem_settings[0];
set_menu_itemon = 0;
while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
}
// The drawing part of the Enemies Setup initialization. Draw the
// background, title, instruction line, and items.
void M_DrawEnemy(void)
{
inhelpscreens = true;
M_DrawBackground("FLOOR4_6", 0); // Draw background
// proff/nicolas 09/20/98 -- changed for hi-res
V_DrawNamePatch(114, 2, 0, "M_ENEM", CR_DEFAULT, VPT_STRETCH);
M_DrawInstructions();
M_DrawScreenItems(current_setup_menu);
// If the Reset Button has been selected, an "Are you sure?" message
// is overlayed across everything else.
if (default_verify)
M_DrawDefVerify();
}
/////////////////////////////
//
// The General table.
// killough 10/10/98
extern int usejoystick, usemouse, default_mus_card, default_snd_card;
extern int detect_voices, realtic_clock_rate, tran_filter_pct;
setup_menu_t gen_settings1[], gen_settings2[], gen_settings3[];
setup_menu_t* gen_settings[] =
{
gen_settings1,
gen_settings2,
gen_settings3,
NULL
};
enum {
general_trans,
general_transpct,
general_fullscreen,
general_videomode,
// general_pcx,
// general_diskicon,
general_uncapped,
};
enum {
general_gl_texfilter,
general_gl_texformat,
general_flooroffset,
};
enum {
// general_sndcard,
// general_muscard,
// general_detvoices,
general_sndchan,
general_pitch
};
#define G_X 250
#define G_YA 44
#define G_YA2 (G_YA+9*8)
#define G_YA3 (G_YA2+5*8)
#define GF_X 76
static const char *videomodes[] = {"8bit","15bit","16bit",
"32bit","OpenGL", NULL};
static const char *gltexfilters[] = {"GL_NEAREST","GL_LINEAR",
"GL_LINEAR_MIPMAP_LINEAR",
NULL};
static const char *gltexformats[] = {"GL_RGBA","GL_RGB5_A1",
"GL_RGBA4", NULL};
setup_menu_t gen_settings1[] = { // General Settings screen1
{"Video" ,S_SKIP|S_TITLE, m_null, G_X, G_YA - 12},
{"Enable Translucency", S_YESNO, m_null, G_X,
G_YA + general_trans*8, {"translucency"}, 0, 0, M_Trans},
{"Translucency filter percentage", S_NUM, m_null, G_X,
G_YA + general_transpct*8, {"tran_filter_pct"}, 0, 0, M_Trans},
{"Fullscreen Video mode", S_YESNO|S_PRGWARN, m_null, G_X,
G_YA + general_fullscreen*8, {"use_fullscreen"}, 0, 0, NULL},
{"Video mode", S_CHOICE|S_PRGWARN, m_null, G_X,
G_YA + general_videomode*8, {"videomode"}, 0, 0, NULL, videomodes},
{"Uncapped Framerate", S_YESNO, m_null, G_X,
G_YA + general_uncapped*8, {"uncapped_framerate"}},
#ifdef GL_DOOM
{"OpenGL", S_SKIP|S_TITLE, m_null, G_X, G_YA2 - 12},
{"Texture filter", S_CHOICE|S_PRGWARN, m_null, G_X,
G_YA2 + general_gl_texfilter*8, {"gl_tex_filter_string"}, 0, 0, NULL, gltexfilters},
{"Texture format", S_CHOICE|S_PRGWARN, m_null, G_X,
G_YA2 + general_gl_texformat*8, {"gl_tex_format_string"}, 0, 0, NULL, gltexformats},
{"Item out of Floor offset", S_NUM, m_null, G_X,
G_YA2 + general_flooroffset*8, {"gl_sprite_offset"}},
#endif
#if 0
{"PCX instead of BMP for screenshots", S_YESNO, m_null, G_X,
G_YA + general_pcx*8, {"screenshot_pcx"}},
#endif
#if 0 // MBF
{"Flash Icon During Disk IO", S_YESNO, m_null, G_X,
G_YA + general_diskicon*8, {"disk_icon"}},
#endif
{"Sound & Music", S_SKIP|S_TITLE, m_null, G_X, G_YA3 - 12},
#if 0 // MBF
{"Sound Card", S_NUM|S_PRGWARN, m_null, G_X,
G_YA2 + general_sndcard*8, {"sound_card"}},
{"Music Card", S_NUM|S_PRGWARN, m_null, G_X,
G_YA2 + general_muscard*8, {"music_card"}},
{"Autodetect Number of Voices", S_YESNO|S_PRGWARN, m_null, G_X,
G_YA2 + general_detvoices*8, {"detect_voices"}},
#endif
{"Number of Sound Channels", S_NUM|S_PRGWARN, m_null, G_X,
G_YA3 + general_sndchan*8, {"snd_channels"}},
{"Enable v1.1 Pitch Effects", S_YESNO, m_null, G_X,
G_YA3 + general_pitch*8, {"pitched_sounds"}},
// Button for resetting to defaults
{0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
{"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {gen_settings2}},
// Final entry
{0,S_SKIP|S_END,m_null}
};
enum {
general_mouse,
general_joy,
general_leds
};
enum {
general_wad1,
general_wad2,
general_deh1,
general_deh2
};
enum {
general_corpse,
general_realtic,
general_smooth,
general_smoothfactor,
general_defskill,
};
#define G_YB 44
#define G_YB1 (G_YB+44)
#define G_YB2 (G_YB1+52)
static const char *gen_skillstrings[] = {
// Dummy first option because defaultskill is 1-based
"", "ITYTD", "HNTR", "HMP", "UV", "NM", NULL
};
setup_menu_t gen_settings2[] = { // General Settings screen2
{"Input Devices" ,S_SKIP|S_TITLE, m_null, G_X, G_YB - 12},
{"Enable Mouse", S_YESNO, m_null, G_X,
G_YB + general_mouse*8, {"use_mouse"}},
{"Enable Joystick", S_YESNO, m_null, G_X,
G_YB + general_joy*8, {"use_joystick"}},
{"Files Preloaded at Game Startup",S_SKIP|S_TITLE, m_null, G_X,
G_YB1 - 12},
{"WAD # 1", S_FILE, m_null, GF_X, G_YB1 + general_wad1*8, {"wadfile_1"}},
{"WAD #2", S_FILE, m_null, GF_X, G_YB1 + general_wad2*8, {"wadfile_2"}},
{"DEH/BEX # 1", S_FILE, m_null, GF_X, G_YB1 + general_deh1*8, {"dehfile_1"}},
{"DEH/BEX #2", S_FILE, m_null, GF_X, G_YB1 + general_deh2*8, {"dehfile_2"}},
{"Miscellaneous" ,S_SKIP|S_TITLE, m_null, G_X, G_YB2 - 12},
{"Maximum number of player corpses", S_NUM|S_PRGWARN, m_null, G_X,
G_YB2 + general_corpse*8, {"max_player_corpse"}},
{"Game speed, percentage of normal", S_NUM|S_PRGWARN, m_null, G_X,
G_YB2 + general_realtic*8, {"realtic_clock_rate"}},
{"Smooth Demo Playback", S_YESNO, m_null, G_X,
G_YB2 + general_smooth*8, {"demo_smoothturns"}, 0, 0, M_ChangeDemoSmoothTurns},
{"Smooth Demo Playback Factor", S_NUM, m_null, G_X,
G_YB2 + general_smoothfactor*8, {"demo_smoothturnsfactor"}, 0, 0, M_ChangeDemoSmoothTurns},
{"Default skill level", S_CHOICE, m_null, G_X,
G_YB2 + general_defskill*8, {"default_skill"}, 0, 0, NULL, gen_skillstrings},
{"<- PREV",S_SKIP|S_PREV, m_null, KB_PREV, KB_Y+20*8, {gen_settings1}},
{"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {gen_settings3}},
// Final entry
{0,S_SKIP|S_END,m_null}
};
enum {
general_filterwall,
general_filterfloor,
general_filtersprite,
general_filterpatch,
general_filterz,
general_filter_threshold,
general_spriteedges,
general_patchedges,
general_hom,
};
#define G_YC 44
static const char *renderfilters[] = {"none", "point", "linear", "rounded"};
static const char *edgetypes[] = {"jagged", "sloped"};
setup_menu_t gen_settings3[] = { // General Settings screen2
{"Renderer settings" ,S_SKIP|S_TITLE, m_null, G_X, G_YB - 12},
{"Filter for walls", S_CHOICE, m_null, G_X,
G_YC + general_filterwall*8, {"filter_wall"}, 0, 0, NULL, renderfilters},
{"Filter for floors/ceilings", S_CHOICE, m_null, G_X,
G_YC + general_filterfloor*8, {"filter_floor"}, 0, 0, NULL, renderfilters},
{"Filter for sprites", S_CHOICE, m_null, G_X,
G_YC + general_filtersprite*8, {"filter_sprite"}, 0, 0, NULL, renderfilters},
{"Filter for patches", S_CHOICE, m_null, G_X,
G_YC + general_filterpatch*8, {"filter_patch"}, 0, 0, NULL, renderfilters},
{"Filter for lighting", S_CHOICE, m_null, G_X,
G_YC + general_filterz*8, {"filter_z"}, 0, 0, NULL, renderfilters},
{"Drawing of sprite edges", S_CHOICE, m_null, G_X,
G_YC + general_spriteedges*8, {"sprite_edges"}, 0, 0, NULL, edgetypes},
{"Drawing of patch edges", S_CHOICE, m_null, G_X,
G_YC + general_patchedges*8, {"patch_edges"}, 0, 0, NULL, edgetypes},
{"Flashing HOM indicator", S_YESNO, m_null, G_X,
G_YC + general_hom*8, {"flashing_hom"}},
{"<- PREV",S_SKIP|S_PREV, m_null, KB_PREV, KB_Y+20*8, {gen_settings2}},
// Final entry
{0,S_SKIP|S_END,m_null}
};
void M_Trans(void) // To reset translucency after setting it in menu
{
general_translucency = default_translucency; //e6y: Fix for "translucency won't change until you restart the engine"
if (general_translucency)
R_InitTranMap(0);
}
void M_FullScreen(void) // To (un)set fullscreen video after menu changes
{
I_UpdateVideoMode();
V_SetPalette(0);
}
void M_ChangeDemoSmoothTurns(void)
{
if (demo_smoothturns)
gen_settings2[12].m_flags &= ~(S_SKIP|S_SELECT);
else
gen_settings2[12].m_flags |= (S_SKIP|S_SELECT);
R_SmoothPlaying_Reset(NULL);
}
// Setting up for the General screen. Turn on flags, set pointers,
// locate the first item on the screen where the cursor is allowed to
// land.
void M_General(int choice)
{
M_SetupNextMenu(&GeneralDef);
setup_active = true;
setup_screen = ss_gen;
set_general_active = true;
setup_select = false;
default_verify = false;
setup_gather = false;
mult_screens_index = 0;
current_setup_menu = gen_settings[0];
set_menu_itemon = 0;
while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
}
// The drawing part of the General Setup initialization. Draw the
// background, title, instruction line, and items.
void M_DrawGeneral(void)
{
inhelpscreens = true;
M_DrawBackground("FLOOR4_6", 0); // Draw background
// proff/nicolas 09/20/98 -- changed for hi-res
V_DrawNamePatch(114, 2, 0, "M_GENERL", CR_DEFAULT, VPT_STRETCH);
M_DrawInstructions();
M_DrawScreenItems(current_setup_menu);
// If the Reset Button has been selected, an "Are you sure?" message
// is overlayed across everything else.
if (default_verify)
M_DrawDefVerify();
}
/////////////////////////////
//
// The Compatibility table.
// killough 10/10/98
#define C_X 284
#define C_Y 32
#define COMP_SPC 12
#define C_NEXTPREV 131
setup_menu_t comp_settings1[], comp_settings2[], comp_settings3[];
setup_menu_t* comp_settings[] =
{
comp_settings1,
comp_settings2,
comp_settings3,
NULL
};
enum
{
compat_telefrag,
compat_dropoff,
compat_falloff,
compat_staylift,
compat_doorstuck,
compat_pursuit,
compat_vile,
compat_pain,
compat_skull,
compat_blazing,
compat_doorlight = 0,
compat_god,
compat_infcheat,
compat_zombie,
compat_skymap,
compat_stairs,
compat_floors,
compat_moveblock,
compat_model,
compat_zerotags,
compat_666 = 0,
compat_soul,
compat_maskedanim,
};
setup_menu_t comp_settings1[] = // Compatibility Settings screen #1
{
{"Any monster can telefrag on MAP30", S_YESNO, m_null, C_X,
C_Y + compat_telefrag * COMP_SPC, {"comp_telefrag"}},
{"Some objects never hang over tall ledges", S_YESNO, m_null, C_X,
C_Y + compat_dropoff * COMP_SPC, {"comp_dropoff"}},
{"Objects don't fall under their own weight", S_YESNO, m_null, C_X,
C_Y + compat_falloff * COMP_SPC, {"comp_falloff"}},
{"Monsters randomly walk off of moving lifts", S_YESNO, m_null, C_X,
C_Y + compat_staylift * COMP_SPC, {"comp_staylift"}},
{"Monsters get stuck on doortracks", S_YESNO, m_null, C_X,
C_Y + compat_doorstuck * COMP_SPC, {"comp_doorstuck"}},
{"Monsters don't give up pursuit of targets", S_YESNO, m_null, C_X,
C_Y + compat_pursuit * COMP_SPC, {"comp_pursuit"}},
{"Arch-Vile resurrects invincible ghosts", S_YESNO, m_null, C_X,
C_Y + compat_vile * COMP_SPC, {"comp_vile"}},
{"Pain Elementals limited to 21 lost souls", S_YESNO, m_null, C_X,
C_Y + compat_pain * COMP_SPC, {"comp_pain"}},
{"Lost souls get stuck behind walls", S_YESNO, m_null, C_X,
C_Y + compat_skull * COMP_SPC, {"comp_skull"}},
{"Blazing doors make double closing sounds", S_YESNO, m_null, C_X,
C_Y + compat_blazing * COMP_SPC, {"comp_blazing"}},
// Button for resetting to defaults
{0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
{"NEXT ->",S_SKIP|S_NEXT, m_null, KB_NEXT, C_Y+C_NEXTPREV, {comp_settings2}},
// Final entry
{0,S_SKIP|S_END,m_null}
};
setup_menu_t comp_settings2[] = // Compatibility Settings screen #2
{
{"Tagged doors don't trigger special lighting", S_YESNO, m_null, C_X,
C_Y + compat_doorlight * COMP_SPC, {"comp_doorlight"}},
{"God mode isn't absolute", S_YESNO, m_null, C_X,
C_Y + compat_god * COMP_SPC, {"comp_god"}},
{"Powerup cheats are not infinite duration", S_YESNO, m_null, C_X,
C_Y + compat_infcheat * COMP_SPC, {"comp_infcheat"}},
{"Zombie players can exit levels", S_YESNO, m_null, C_X,
C_Y + compat_zombie * COMP_SPC, {"comp_zombie"}},
{"Sky is unaffected by invulnerability", S_YESNO, m_null, C_X,
C_Y + compat_skymap * COMP_SPC, {"comp_skymap"}},
{"Use exactly Doom's stairbuilding method", S_YESNO, m_null, C_X,
C_Y + compat_stairs * COMP_SPC, {"comp_stairs"}},
{"Use exactly Doom's floor motion behavior", S_YESNO, m_null, C_X,
C_Y + compat_floors * COMP_SPC, {"comp_floors"}},
{"Use exactly Doom's movement clipping code", S_YESNO, m_null, C_X,
C_Y + compat_moveblock * COMP_SPC, {"comp_moveblock"}},
{"Use exactly Doom's linedef trigger model", S_YESNO, m_null, C_X,
C_Y + compat_model * COMP_SPC, {"comp_model"}},
{"Linedef effects work with sector tag = 0", S_YESNO, m_null, C_X,
C_Y + compat_zerotags * COMP_SPC, {"comp_zerotags"}},
{"<- PREV", S_SKIP|S_PREV, m_null, KB_PREV, C_Y+C_NEXTPREV,{comp_settings1}},
{"NEXT ->",S_SKIP|S_NEXT, m_null, KB_NEXT, C_Y+C_NEXTPREV, {comp_settings3}},
// Final entry
{0,S_SKIP|S_END,m_null}
};
setup_menu_t comp_settings3[] = // Compatibility Settings screen #2
{
{"All boss types can trigger tag 666 at ExM8", S_YESNO, m_null, C_X,
C_Y + compat_666 * COMP_SPC, {"comp_666"}},
{"Lost souls don't bounce off flat surfaces", S_YESNO, m_null, C_X,
C_Y + compat_soul * COMP_SPC, {"comp_soul"}},
{"2S middle textures do not animate", S_YESNO, m_null, C_X,
C_Y + compat_maskedanim * COMP_SPC, {"comp_maskedanim"}},
{"<- PREV", S_SKIP|S_PREV, m_null, KB_PREV, C_Y+C_NEXTPREV,{comp_settings2}},
// Final entry
{0,S_SKIP|S_END,m_null}
};
// Setting up for the Compatibility screen. Turn on flags, set pointers,
// locate the first item on the screen where the cursor is allowed to
// land.
void M_Compat(int choice)
{
M_SetupNextMenu(&CompatDef);
setup_active = true;
setup_screen = ss_comp;
set_general_active = true;
setup_select = false;
default_verify = false;
setup_gather = false;
mult_screens_index = 0;
current_setup_menu = comp_settings[0];
set_menu_itemon = 0;
while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
}
// The drawing part of the Compatibility Setup initialization. Draw the
// background, title, instruction line, and items.
void M_DrawCompat(void)
{
inhelpscreens = true;
M_DrawBackground("FLOOR4_6", 0); // Draw background
V_DrawNamePatch(52,2,0,"M_COMPAT", CR_DEFAULT, VPT_STRETCH);
M_DrawInstructions();
M_DrawScreenItems(current_setup_menu);
// If the Reset Button has been selected, an "Are you sure?" message
// is overlayed across everything else.
if (default_verify)
M_DrawDefVerify();
}
/////////////////////////////
//
// The Messages table.
#define M_X 230
#define M_Y 39
// killough 11/98: enumerated
enum {
mess_color_play,
mess_timer,
mess_color_chat,
mess_chat_timer,
mess_color_review,
mess_timed,
mess_hud_timer,
mess_lines,
mess_scrollup,
mess_background,
};
setup_menu_t mess_settings1[];
setup_menu_t* mess_settings[] =
{
mess_settings1,
NULL
};
setup_menu_t mess_settings1[] = // Messages screen
{
{"Message Color During Play", S_CRITEM, m_null, M_X,
M_Y + mess_color_play*8, {"hudcolor_mesg"}},
#if 0
{"Message Duration During Play (ms)", S_NUM, m_null, M_X,
M_Y + mess_timer*8, {"message_timer"}},
#endif
{"Chat Message Color", S_CRITEM, m_null, M_X,
M_Y + mess_color_chat*8, {"hudcolor_chat"}},
#if 0
{"Chat Message Duration (ms)", S_NUM, m_null, M_X,
M_Y + mess_chat_timer*8, {"chat_msg_timer"}},
#endif
{"Message Review Color", S_CRITEM, m_null, M_X,
M_Y + mess_color_review*8, {"hudcolor_list"}},
#if 0
{"Message Listing Review is Temporary", S_YESNO, m_null, M_X,
M_Y + mess_timed*8, {"hud_msg_timed"}},
{"Message Review Duration (ms)", S_NUM, m_null, M_X,
M_Y + mess_hud_timer*8, {"hud_msg_timer"}},
#endif
{"Number of Review Message Lines", S_NUM, m_null, M_X,
M_Y + mess_lines*8, {"hud_msg_lines"}},
#if 0
{"Message Listing Scrolls Upwards", S_YESNO, m_null, M_X,
M_Y + mess_scrollup*8, {"hud_msg_scrollup"}},
#endif
{"Message Background", S_YESNO, m_null, M_X,
M_Y + mess_background*8, {"hud_list_bgon"}},
// Button for resetting to defaults
{0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
// Final entry
{0,S_SKIP|S_END,m_null}
};
// Setting up for the Messages screen. Turn on flags, set pointers,
// locate the first item on the screen where the cursor is allowed to
// land.
void M_Messages(int choice)
{
M_SetupNextMenu(&MessageDef);
setup_active = true;
setup_screen = ss_mess;
set_mess_active = true;
setup_select = false;
default_verify = false;
setup_gather = false;
mult_screens_index = 0;
current_setup_menu = mess_settings[0];
set_menu_itemon = 0;
while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
}
// The drawing part of the Messages Setup initialization. Draw the
// background, title, instruction line, and items.
void M_DrawMessages(void)
{
inhelpscreens = true;
M_DrawBackground("FLOOR4_6", 0); // Draw background
// CPhipps - patch drawing updated
V_DrawNamePatch(103, 2, 0, "M_MESS", CR_DEFAULT, VPT_STRETCH);
M_DrawInstructions();
M_DrawScreenItems(current_setup_menu);
if (default_verify)
M_DrawDefVerify();
}
/////////////////////////////
//
// The Chat Strings table.
#define CS_X 20
#define CS_Y (31+8)
setup_menu_t chat_settings1[];
setup_menu_t* chat_settings[] =
{
chat_settings1,
NULL
};
setup_menu_t chat_settings1[] = // Chat Strings screen
{
{"1",S_CHAT,m_null,CS_X,CS_Y+ 1*8, {"chatmacro1"}},
{"2",S_CHAT,m_null,CS_X,CS_Y+ 2*8, {"chatmacro2"}},
{"3",S_CHAT,m_null,CS_X,CS_Y+ 3*8, {"chatmacro3"}},
{"4",S_CHAT,m_null,CS_X,CS_Y+ 4*8, {"chatmacro4"}},
{"5",S_CHAT,m_null,CS_X,CS_Y+ 5*8, {"chatmacro5"}},
{"6",S_CHAT,m_null,CS_X,CS_Y+ 6*8, {"chatmacro6"}},
{"7",S_CHAT,m_null,CS_X,CS_Y+ 7*8, {"chatmacro7"}},
{"8",S_CHAT,m_null,CS_X,CS_Y+ 8*8, {"chatmacro8"}},
{"9",S_CHAT,m_null,CS_X,CS_Y+ 9*8, {"chatmacro9"}},
{"0",S_CHAT,m_null,CS_X,CS_Y+10*8, {"chatmacro0"}},
// Button for resetting to defaults
{0,S_RESET,m_null,X_BUTTON,Y_BUTTON},
// Final entry
{0,S_SKIP|S_END,m_null}
};
// Setting up for the Chat Strings screen. Turn on flags, set pointers,
// locate the first item on the screen where the cursor is allowed to
// land.
void M_ChatStrings(int choice)
{
M_SetupNextMenu(&ChatStrDef);
setup_active = true;
setup_screen = ss_chat;
set_chat_active = true;
setup_select = false;
default_verify = false;
setup_gather = false;
mult_screens_index = 0;
current_setup_menu = chat_settings[0];
set_menu_itemon = 0;
while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP);
current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
}
// The drawing part of the Chat Strings Setup initialization. Draw the
// background, title, instruction line, and items.
void M_DrawChatStrings(void)
{
inhelpscreens = true;
M_DrawBackground("FLOOR4_6", 0); // Draw background
// CPhipps - patch drawing updated
V_DrawNamePatch(83, 2, 0, "M_CHAT", CR_DEFAULT, VPT_STRETCH);
M_DrawInstructions();
M_DrawScreenItems(current_setup_menu);
// If the Reset Button has been selected, an "Are you sure?" message
// is overlayed across everything else.
if (default_verify)
M_DrawDefVerify();
}
/////////////////////////////
//
// General routines used by the Setup screens.
//
static boolean shiftdown = false; // phares 4/10/98: SHIFT key down or not
// phares 4/17/98:
// M_SelectDone() gets called when you have finished entering your
// Setup Menu item change.
static void M_SelectDone(setup_menu_t* ptr)
{
ptr->m_flags &= ~S_SELECT;
ptr->m_flags |= S_HILITE;
S_StartSound(NULL,sfx_itemup);
setup_select = false;
colorbox_active = false;
if (print_warning_about_changes) // killough 8/15/98
print_warning_about_changes--;
}
// phares 4/21/98:
// Array of setup screens used by M_ResetDefaults()
static setup_menu_t **setup_screens[] =
{
keys_settings,
weap_settings,
stat_settings,
auto_settings,
enem_settings,
mess_settings,
chat_settings,
gen_settings, // killough 10/98
comp_settings,
};
// phares 4/19/98:
// M_ResetDefaults() resets all values for a setup screen to default values
//
// killough 10/98: rewritten to fix bugs and warn about pending changes
static void M_ResetDefaults(void)
{
int i; //e6y
default_t *dp;
int warn = 0;
// Look through the defaults table and reset every variable that
// belongs to the group we're interested in.
//
// killough: However, only reset variables whose field in the
// current setup screen is the same as in the defaults table.
// i.e. only reset variables really in the current setup screen.
// e6y
// Fixed crash while trying to read data past array end
// All previous versions of prboom worked only by a lucky accident
// old code: for (dp = defaults; dp->name; dp++)
for (i = 0; i < numdefaults ; i++)
{
dp = &defaults[i];
if (dp->setupscreen == setup_screen)
{
setup_menu_t **l, *p;
for (l = setup_screens[setup_screen-1]; *l; l++)
for (p = *l; !(p->m_flags & S_END); p++)
if (p->m_flags & S_HASDEFPTR ? p->var.def == dp :
p->var.m_key == dp->location.pi ||
p->m_mouse == dp->location.pi ||
p->m_joy == dp->location.pi)
{
if (IS_STRING(*dp))
free((char*)*dp->location.ppsz),
*dp->location.ppsz = strdup(dp->defaultvalue.psz);
else
*dp->location.pi = dp->defaultvalue.i;
#if 0
if (p->m_flags & (S_LEVWARN | S_PRGWARN))
warn |= p->m_flags & (S_LEVWARN | S_PRGWARN);
else
if (dp->current)
if (allow_changes())
*dp->current = *dp->location.pi;
else
warn |= S_LEVWARN;
#endif
if (p->action)
p->action();
goto end;
}
end:;
}
}
if (warn)
warn_about_changes(warn);
}
//
// M_InitDefaults()
//
// killough 11/98:
//
// This function converts all setup menu entries consisting of cfg
// variable names, into pointers to the corresponding default[]
// array entry. var.name becomes converted to var.def.
//
static void M_InitDefaults(void)
{
setup_menu_t *const *p, *t;
default_t *dp;
int i;
for (i = 0; i < ss_max-1; i++)
for (p = setup_screens[i]; *p; p++)
for (t = *p; !(t->m_flags & S_END); t++)
if (t->m_flags & S_HASDEFPTR) {
if (!(dp = M_LookupDefault(t->var.name)))
I_Error("M_InitDefaults: Couldn't find config variable %s", t->var.name);
else
(t->var.def = dp)->setup_menu = t;
}
}
//
// End of Setup Screens.
//
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// Start of Extended HELP screens // phares 3/30/98
//
// The wad designer can define a set of extended HELP screens for their own
// information display. These screens should be 320x200 graphic lumps
// defined in a separate wad. They should be named "HELP01" through "HELP99".
// "HELP01" is shown after the regular BOOM Dynamic HELP screen, and ENTER
// and BACKSPACE keys move the player through the HELP set.
//
// Rather than define a set of menu definitions for each of the possible
// HELP screens, one definition is used, and is altered on the fly
// depending on what HELPnn lumps the game finds.
// phares 3/30/98:
// Extended Help Screen variables
int extended_help_count; // number of user-defined help screens found
int extended_help_index; // index of current extended help screen
menuitem_t ExtHelpMenu[] =
{
{1,"",M_ExtHelpNextScreen,0}
};
menu_t ExtHelpDef =
{
1, // # of menu items
&ReadDef1, // previous menu
ExtHelpMenu, // menuitem_t ->
M_DrawExtHelp, // drawing routine ->
330,181, // x,y
0 // lastOn
};
// M_ExtHelpNextScreen establishes the number of the next HELP screen in
// the series.
void M_ExtHelpNextScreen(int choice)
{
choice = 0;
if (++extended_help_index > extended_help_count)
{
// when finished with extended help screens, return to Main Menu
extended_help_index = 1;
M_SetupNextMenu(&MainDef);
}
}
// phares 3/30/98:
// Routine to look for HELPnn screens and create a menu
// definition structure that defines extended help screens.
void M_InitExtendedHelp(void)
{
int index,i;
char namebfr[] = { "HELPnn"} ;
extended_help_count = 0;
for (index = 1 ; index < 100 ; index++) {
namebfr[4] = index/10 + 0x30;
namebfr[5] = index%10 + 0x30;
i = W_CheckNumForName(namebfr);
if (i == -1) {
if (extended_help_count) {
if (gamemode == commercial) {
ExtHelpDef.prevMenu = &ReadDef1; /* previous menu */
ReadMenu1[0].routine = M_ExtHelp;
} else {
ExtHelpDef.prevMenu = &ReadDef2; /* previous menu */
ReadMenu2[0].routine = M_ExtHelp;
}
}
return;
}
extended_help_count++;
}
}
// Initialization for the extended HELP screens.
void M_ExtHelp(int choice)
{
choice = 0;
extended_help_index = 1; // Start with first extended help screen
M_SetupNextMenu(&ExtHelpDef);
}
// Initialize the drawing part of the extended HELP screens.
void M_DrawExtHelp(void)
{
char namebfr[10] = { "HELPnn" }; // CPhipps - make it local & writable
inhelpscreens = true; // killough 5/1/98
namebfr[4] = extended_help_index/10 + 0x30;
namebfr[5] = extended_help_index%10 + 0x30;
// CPhipps - patch drawing updated
V_DrawNamePatch(0, 0, 0, namebfr, CR_DEFAULT, VPT_STRETCH);
}
//
// End of Extended HELP screens // phares 3/30/98
//
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//
// Dynamic HELP screen // phares 3/2/98
//
// Rather than providing the static HELP screens from DOOM and its versions,
// BOOM provides the player with a dynamic HELP screen that displays the
// current settings of major key bindings.
//
// The Dynamic HELP screen is defined in a manner similar to that used for
// the Setup Screens above.
//
// M_GetKeyString finds the correct string to represent the key binding
// for the current item being drawn.
int M_GetKeyString(int c,int offset)
{
const char* s;
if (c >= 33 && c <= 126) {
// The '=', ',', and '.' keys originally meant the shifted
// versions of those keys, but w/o having to shift them in
// the game. Any actions that are mapped to these keys will
// still mean their shifted versions. Could be changed later
// if someone can come up with a better way to deal with them.
if (c == '=') // probably means the '+' key?
c = '+';
else if (c == ',') // probably means the '<' key?
c = '<';
else if (c == '.') // probably means the '>' key?
c = '>';
menu_buffer[offset++] = c; // Just insert the ascii key
menu_buffer[offset] = 0;
} else {
// Retrieve 4-letter (max) string representing the key
// cph - Keypad keys, general code reorganisation to
// make this smaller and neater.
if ((0x100 <= c) && (c < 0x200)) {
if (c == KEYD_KEYPADENTER)
s = "PADE";
else {
strcpy(&menu_buffer[offset], "PAD");
offset+=4;
menu_buffer[offset-1] = c & 0xff;
menu_buffer[offset] = 0;
}
} else if ((KEYD_F1 <= c) && (c < KEYD_F10)) {
menu_buffer[offset++] = 'F';
menu_buffer[offset++] = '1' + c - KEYD_F1;
menu_buffer[offset] = 0;
} else {
switch(c) {
case KEYD_TAB: s = "TAB"; break;
case KEYD_ENTER: s = "ENTR"; break;
case KEYD_ESCAPE: s = "ESC"; break;
case KEYD_SPACEBAR: s = "SPAC"; break;
case KEYD_BACKSPACE: s = "BACK"; break;
case KEYD_RCTRL: s = "CTRL"; break;
case KEYD_LEFTARROW: s = "LARR"; break;
case KEYD_UPARROW: s = "UARR"; break;
case KEYD_RIGHTARROW: s = "RARR"; break;
case KEYD_DOWNARROW: s = "DARR"; break;
case KEYD_RSHIFT: s = "SHFT"; break;
case KEYD_RALT: s = "ALT"; break;
case KEYD_CAPSLOCK: s = "CAPS"; break;
case KEYD_SCROLLLOCK: s = "SCRL"; break;
case KEYD_HOME: s = "HOME"; break;
case KEYD_PAGEUP: s = "PGUP"; break;
case KEYD_END: s = "END"; break;
case KEYD_PAGEDOWN: s = "PGDN"; break;
case KEYD_INSERT: s = "INST"; break;
case KEYD_DEL: s = "DEL"; break;
case KEYD_F10: s = "F10"; break;
case KEYD_F11: s = "F11"; break;
case KEYD_F12: s = "F12"; break;
case KEYD_PAUSE: s = "PAUS"; break;
default: s = "JUNK"; break;
}
if (s) { // cph - Slight code change
strcpy(&menu_buffer[offset],s); // string to display
offset += strlen(s);
}
}
}
return offset;
}
//
// The Dynamic HELP screen table.
#define KT_X1 283
#define KT_X2 172
#define KT_X3 87
#define KT_Y1 2
#define KT_Y2 118
#define KT_Y3 102
setup_menu_t helpstrings[] = // HELP screen strings
{
{"SCREEN" ,S_SKIP|S_TITLE,m_null,KT_X1,KT_Y1},
{"HELP" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 1*8,{&key_help}},
{"MENU" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 2*8,{&key_escape}},
{"SETUP" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 3*8,{&key_setup}},
{"PAUSE" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 4*8,{&key_pause}},
{"AUTOMAP" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 5*8,{&key_map}},
{"SOUND VOLUME",S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 6*8,{&key_soundvolume}},
{"HUD" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 7*8,{&key_hud}},
{"MESSAGES" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 8*8,{&key_messages}},
{"GAMMA FIX" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 9*8,{&key_gamma}},
{"SPY" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+10*8,{&key_spy}},
{"LARGER VIEW" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+11*8,{&key_zoomin}},
{"SMALLER VIEW",S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+12*8,{&key_zoomout}},
{"SCREENSHOT" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+13*8,{&key_screenshot}},
{"AUTOMAP" ,S_SKIP|S_TITLE,m_null,KT_X1,KT_Y2},
{"FOLLOW MODE" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 1*8,{&key_map_follow}},
{"ZOOM IN" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 2*8,{&key_map_zoomin}},
{"ZOOM OUT" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 3*8,{&key_map_zoomout}},
{"MARK PLACE" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 4*8,{&key_map_mark}},
{"CLEAR MARKS" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 5*8,{&key_map_clear}},
{"FULL/ZOOM" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 6*8,{&key_map_gobig}},
{"GRID" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 7*8,{&key_map_grid}},
{"WEAPONS" ,S_SKIP|S_TITLE,m_null,KT_X3,KT_Y1},
{"FIST" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 1*8,{&key_weapon1}},
{"PISTOL" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 2*8,{&key_weapon2}},
{"SHOTGUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 3*8,{&key_weapon3}},
{"CHAINGUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 4*8,{&key_weapon4}},
{"ROCKET" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 5*8,{&key_weapon5}},
{"PLASMA" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 6*8,{&key_weapon6}},
{"BFG 9000" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 7*8,{&key_weapon7}},
{"CHAINSAW" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 8*8,{&key_weapon8}},
{"SSG" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 9*8,{&key_weapon9}},
{"BEST" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+10*8,{&key_weapontoggle}},
{"FIRE" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+11*8,{&key_fire},&mousebfire,&joybfire},
{"MOVEMENT" ,S_SKIP|S_TITLE,m_null,KT_X3,KT_Y3},
{"FORWARD" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 1*8,{&key_up},&mousebforward},
{"BACKWARD" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 2*8,{&key_down}},
{"TURN LEFT" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 3*8,{&key_left}},
{"TURN RIGHT" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 4*8,{&key_right}},
{"RUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 5*8,{&key_speed},0,&joybspeed},
{"STRAFE LEFT" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 6*8,{&key_strafeleft}},
{"STRAFE RIGHT",S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 7*8,{&key_straferight}},
{"STRAFE" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 8*8,{&key_strafe},&mousebstrafe,&joybstrafe},
{"AUTORUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 9*8,{&key_autorun}},
{"180 TURN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+10*8,{&key_reverse}},
{"USE" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+11*8,{&key_use},&mousebforward,&joybuse},
{"GAME" ,S_SKIP|S_TITLE,m_null,KT_X2,KT_Y1},
{"SAVE" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 1*8,{&key_savegame}},
{"LOAD" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 2*8,{&key_loadgame}},
{"QUICKSAVE" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 3*8,{&key_quicksave}},
{"END GAME" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 4*8,{&key_endgame}},
{"QUICKLOAD" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 5*8,{&key_quickload}},
{"QUIT" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 6*8,{&key_quit}},
// Final entry
{0,S_SKIP|S_END,m_null}
};
#define SPACEWIDTH 4
/* cph 2006/08/06
* M_DrawString() is the old M_DrawMenuString, except that it is not tied to
* menu_buffer - no reason to force all the callers to write into one array! */
static void M_DrawString(int cx, int cy, int color, const char* ch)
{
int w;
int c;
while (*ch) {
c = *ch++; // get next char
c = toupper(c) - HU_FONTSTART;
if (c < 0 || c> HU_FONTSIZE)
{
cx += SPACEWIDTH; // space
continue;
}
w = hu_font[c].width;
if (cx + w > 320)
break;
// V_DrawpatchTranslated() will draw the string in the
// desired color, colrngs[color]
// CPhipps - patch drawing updated
V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, color, VPT_STRETCH | VPT_TRANS);
// The screen is cramped, so trim one unit from each
// character so they butt up against each other.
cx += w - 1;
}
}
// M_DrawMenuString() draws the string in menu_buffer[]
static void M_DrawMenuString(int cx, int cy, int color)
{
M_DrawString(cx, cy, color, menu_buffer);
}
// M_GetPixelWidth() returns the number of pixels in the width of
// the string, NOT the number of chars in the string.
static int M_GetPixelWidth(const char* ch)
{
int len = 0;
int c;
while (*ch) {
c = *ch++; // pick up next char
c = toupper(c) - HU_FONTSTART;
if (c < 0 || c > HU_FONTSIZE)
{
len += SPACEWIDTH; // space
continue;
}
len += hu_font[c].width;
len--; // adjust so everything fits
}
len++; // replace what you took away on the last char only
return len;
}
static void M_DrawStringCentered(int cx, int cy, int color, const char* ch)
{
M_DrawString(cx - M_GetPixelWidth(ch)/2, cy, color, ch);
}
//
// M_DrawHelp
//
// This displays the help screen
void M_DrawHelp (void)
{
inhelpscreens = true; // killough 10/98
M_DrawBackground("FLOOR4_6", 0);
M_DrawScreenItems(helpstrings);
}
//
// End of Dynamic HELP screen // phares 3/2/98
//
////////////////////////////////////////////////////////////////////////////
enum {
prog,
prog_stub,
prog_stub1,
prog_stub2,
adcr
};
enum {
cr_prog=0,
cr_adcr=2,
};
#define CR_S 9
#define CR_X 20
#define CR_X2 50
#define CR_Y 32
#define CR_SH 9
setup_menu_t cred_settings[]={
{"DVR Programmer",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X, CR_Y + CR_S*prog + CR_SH*cr_prog},
{"Simon 'DrBeef' Brown",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+1) + CR_SH*cr_prog},
{"Additional Credit for PrBoom To:",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X, CR_Y + CR_S*adcr + CR_SH*cr_adcr},
{"Florian 'Proff' Schulze",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+1) + CR_SH*cr_adcr},
{"Colin Phipps",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+2) + CR_SH*cr_adcr},
{"Neil Stevens",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+3) + CR_SH*cr_adcr},
{"Andrey Budko",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+4) + CR_SH*cr_adcr},
{"id Software for DOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+5)+CR_SH*cr_adcr},
{"TeamTNT for BOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+6)+CR_SH*cr_adcr},
{"Lee Killough for MBF",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+7)+CR_SH*cr_adcr},
{0,S_SKIP|S_END,m_null}
};
void M_DrawCredits(void) // killough 10/98: credit screen
{
inhelpscreens = true;
M_DrawBackground(gamemode==shareware ? "CEIL5_1" : "MFLR8_4", 0);
//V_DrawNamePatch(115,9,0, "DVR",CR_GOLD, VPT_TRANS | VPT_STRETCH);
M_DrawScreenItems(cred_settings);
}
static int M_IndexInChoices(const char *str, const char **choices) {
int i = 0;
while (*choices != NULL) {
if (!strcmp(str, *choices))
return i;
i++;
choices++;
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////
//
// M_Responder
//
// Examines incoming keystrokes and button pushes and determines some
// action based on the state of the system.
//
boolean M_Responder (event_t* ev) {
int ch;
int i;
static int joywait = 0;
static int mousewait = 0;
static int mousey = 0;
static int lasty = 0;
static int mousex = 0;
static int lastx = 0;
ch = -1; // will be changed to a legit char if we're going to use it here
// Process joystick input
if (ev->type == ev_joystick && joywait < I_GetTime()) {
if (ev->data3 == -1)
{
ch = key_menu_up; // phares 3/7/98
joywait = I_GetTime() + 5;
}
else if (ev->data3 == 1)
{
ch = key_menu_down; // phares 3/7/98
joywait = I_GetTime() + 5;
}
if (ev->data2 == -1)
{
ch = key_menu_left; // phares 3/7/98
joywait = I_GetTime() + 2;
}
else if (ev->data2 == 1)
{
ch = key_menu_right; // phares 3/7/98
joywait = I_GetTime() + 2;
}
if (ev->data1&1)
{
ch = key_menu_enter; // phares 3/7/98
joywait = I_GetTime() + 5;
}
if (ev->data1&2)
{
ch = key_menu_backspace; // phares 3/7/98
joywait = I_GetTime() + 5;
}
// phares 4/4/98:
// Handle joystick buttons 3 and 4, and allow them to pass down
// to where key binding can eat them.
if (setup_active && set_keybnd_active) {
if (ev->data1&4) {
ch = 0; // meaningless, just to get you past the check for -1
joywait = I_GetTime() + 5;
}
if (ev->data1&8) {
ch = 0; // meaningless, just to get you past the check for -1
joywait = I_GetTime() + 5;
}
}
} else {
// Mouse input processing removed
// Process keyboard input
if (ev->type == ev_keydown)
{
ch = ev->data1; // phares 4/11/98:
if (ch == KEYD_RSHIFT) // For chat string processing, need
shiftdown = true; // to know when shift key is up or
} // down so you can get at the !,#,
else if (ev->type == ev_keyup) // etc. keys. Keydowns are allowed
if (ev->data1 == KEYD_RSHIFT) // past this point, but keyups aren't
shiftdown = false; // so we need to note the difference
} // here using the 'shiftdown' boolean.
if (ch == -1)
return false; // we can't use the event here
// Save Game string input
if (saveStringEnter) {
if (ch == key_menu_backspace) // phares 3/7/98
{
if (saveCharIndex > 0)
{
saveCharIndex--;
savegamestrings[saveSlot][saveCharIndex] = 0;
}
}
else if (ch == key_menu_escape) // phares 3/7/98
{
saveStringEnter = 0;
strcpy(&savegamestrings[saveSlot][0],saveOldString);
}
else if (ch == key_menu_enter) // phares 3/7/98
{
saveStringEnter = 0;
if (savegamestrings[saveSlot][0])
M_DoSave(saveSlot);
}
else
{
ch = toupper(ch);
if (ch >= 32 && ch <= 127 &&
saveCharIndex < SAVESTRINGSIZE-1 &&
M_StringWidth(savegamestrings[saveSlot]) < (SAVESTRINGSIZE-2)*8)
{
savegamestrings[saveSlot][saveCharIndex++] = ch;
savegamestrings[saveSlot][saveCharIndex] = 0;
}
}
return true;
}
// Take care of any messages that need input
if (messageToPrint) {
if (messageNeedsInput == true &&
!(ch == ' ' || ch == 'n' || ch == 'y' || ch == key_escape)) // phares
return false;
menuactive = messageLastMenuActive;
messageToPrint = 0;
if (messageRoutine)
messageRoutine(ch);
menuactive = false;
//S_StartSound(NULL,sfx_swtchx);
return true;
}
/* killough 2/22/98: add support for screenshot key:
* cph 2001/02/04: no need for this to be a gameaction, just do it
*/
if (ch == key_screenshot)
{
M_ScreenShot ();
// Don't eat the keypress in this case. See sf bug #1843280.
}
// If there is no active menu displayed...
if (!menuactive) { // phares
if (ch == key_autorun) // Autorun // V
{
autorun = !autorun;
return true;
}
if (ch == key_help) // Help key
{
M_StartControlPanel ();
currentMenu = &HelpDef; // killough 10/98: new help screen
itemOn = 0;
S_StartSound(NULL,sfx_swtchn);
return true;
}
if (ch == key_savegame) // Save Game
{
M_StartControlPanel();
S_StartSound(NULL,sfx_swtchn);
M_SaveGame(0);
return true;
}
if (ch == key_loadgame) // Load Game
{
M_StartControlPanel();
S_StartSound(NULL,sfx_swtchn);
M_LoadGame(0);
return true;
}
if (ch == key_soundvolume) // Sound Volume
{
M_StartControlPanel ();
currentMenu = &SoundDef;
itemOn = sfx_vol;
S_StartSound(NULL,sfx_swtchn);
return true;
}
if (ch == key_quicksave) // Quicksave
{
S_StartSound(NULL,sfx_swtchn);
M_QuickSave();
return true;
}
if (ch == key_endgame) // End game
{
S_StartSound(NULL,sfx_swtchn);
M_EndGame(0);
return true;
}
if (ch == key_messages) // Toggle messages
{
M_ChangeMessages(0);
S_StartSound(NULL,sfx_swtchn);
return true;
}
if (ch == key_quickload) // Quickload
{
S_StartSound(NULL,sfx_swtchn);
M_QuickLoad();
return true;
}
if (ch == key_quit) // Quit DOOM
{
S_StartSound(NULL,sfx_swtchn);
M_QuitDOOM(0);
return true;
}
if (ch == key_gamma) // gamma toggle
{
usegamma++;
if (usegamma > 4)
usegamma = 0;
players[consoleplayer].message =
usegamma == 0 ? s_GAMMALVL0 :
usegamma == 1 ? s_GAMMALVL1 :
usegamma == 2 ? s_GAMMALVL2 :
usegamma == 3 ? s_GAMMALVL3 :
s_GAMMALVL4;
V_SetPalette(0);
return true;
}
if (ch == key_zoomout) // zoom out
{
if ((automapmode & am_active) || chat_on)
return false;
M_SizeDisplay(0);
S_StartSound(NULL,sfx_stnmov);
return true;
}
if (ch == key_zoomin) // zoom in
{ // jff 2/23/98
if ((automapmode & am_active) || chat_on) // allow
return false; // key_hud==key_zoomin
M_SizeDisplay(1); // ^
S_StartSound(NULL,sfx_stnmov); // |
return true; // phares
}
if (ch == key_hud) // heads-up mode
{
if ((automapmode & am_active) || chat_on) // jff 2/22/98
return false; // HUD mode control
if (screenSize<8) // function on default F5
while (screenSize<8 || !hud_displayed) // make hud visible
M_SizeDisplay(1); // when configuring it
else
{
hud_displayed = 1; //jff 3/3/98 turn hud on
hud_active = (hud_active+1)%3; // cycle hud_active
if (!hud_active) //jff 3/4/98 add distributed
{
hud_distributed = !hud_distributed; // to cycle
HU_MoveHud(); //jff 3/9/98 move it now to avoid glitch
}
}
return true;
}
/* killough 10/98: allow key shortcut into Setup menu */
if (ch == key_setup) {
M_StartControlPanel();
S_StartSound(NULL,sfx_swtchn);
M_SetupNextMenu(&SetupDef);
return true;
}
}
// Pop-up Main menu?
if (!menuactive)
{
if (ch == key_escape) // phares
{
M_StartControlPanel ();
S_StartSound(NULL,sfx_swtchn);
return true;
}
return false;
}
// phares 3/26/98 - 4/11/98:
// Setup screen key processing
if (setup_active) {
setup_menu_t* ptr1= current_setup_menu + set_menu_itemon;
setup_menu_t* ptr2 = NULL;
// phares 4/19/98:
// Catch the response to the 'reset to default?' verification
// screen
if (default_verify)
{
if (toupper(ch) == 'Y') {
M_ResetDefaults();
default_verify = false;
M_SelectDone(ptr1);
}
else if (toupper(ch) == 'N') {
default_verify = false;
M_SelectDone(ptr1);
}
return true;
}
// Common processing for some items
if (setup_select) { // changing an entry
if (ch == key_menu_escape) // Exit key = no change
{
M_SelectDone(ptr1); // phares 4/17/98
setup_gather = false; // finished gathering keys, if any
return true;
}
if (ptr1->m_flags & S_YESNO) // yes or no setting?
{
if (ch == key_menu_enter) {
*ptr1->var.def->location.pi = !*ptr1->var.def->location.pi; // killough 8/15/98
// phares 4/14/98:
// If not in demoplayback, demorecording, or netgame,
// and there's a second variable in var2, set that
// as well
// killough 8/15/98: add warning messages
if (ptr1->m_flags & (S_LEVWARN | S_PRGWARN))
warn_about_changes(ptr1->m_flags & // killough 10/98
(S_LEVWARN | S_PRGWARN));
else
M_UpdateCurrent(ptr1->var.def);
if (ptr1->action) // killough 10/98
ptr1->action();
}
M_SelectDone(ptr1); // phares 4/17/98
return true;
}
if (ptr1->m_flags & S_CRITEM)
{
if (ch != key_menu_enter)
{
ch -= 0x30; // out of ascii
if (ch < 0 || ch > 9)
return true; // ignore
*ptr1->var.def->location.pi = ch;
}
if (ptr1->action) // killough 10/98
ptr1->action();
M_SelectDone(ptr1); // phares 4/17/98
return true;
}
if (ptr1->m_flags & S_NUM) // number?
{
if (setup_gather) { // gathering keys for a value?
/* killough 10/98: Allow negatives, and use a more
* friendly input method (e.g. don't clear value early,
* allow backspace, and return to original value if bad
* value is entered).
*/
if (ch == key_menu_enter) {
if (gather_count) { // Any input?
int value;
gather_buffer[gather_count] = 0;
value = atoi(gather_buffer); // Integer value
if ((ptr1->var.def->minvalue != UL &&
value < ptr1->var.def->minvalue) ||
(ptr1->var.def->maxvalue != UL &&
value > ptr1->var.def->maxvalue))
warn_about_changes(S_BADVAL);
else {
*ptr1->var.def->location.pi = value;
/* killough 8/9/98: fix numeric vars
* killough 8/15/98: add warning message
*/
if (ptr1->m_flags & (S_LEVWARN | S_PRGWARN))
warn_about_changes(ptr1->m_flags &
(S_LEVWARN | S_PRGWARN));
else
M_UpdateCurrent(ptr1->var.def);
if (ptr1->action) // killough 10/98
ptr1->action();
}
}
M_SelectDone(ptr1); // phares 4/17/98
setup_gather = false; // finished gathering keys
return true;
}
if (ch == key_menu_backspace && gather_count) {
gather_count--;
return true;
}
if (gather_count >= MAXGATHER)
return true;
if (!isdigit(ch) && ch != '-')
return true; // ignore
/* killough 10/98: character-based numerical input */
gather_buffer[gather_count++] = ch;
}
return true;
}
if (ptr1->m_flags & S_CHOICE) // selection of choices?
{
if (ch == key_menu_left) {
if (ptr1->var.def->type == def_int) {
int value = *ptr1->var.def->location.pi;
value = value - 1;
if ((ptr1->var.def->minvalue != UL &&
value < ptr1->var.def->minvalue))
value = ptr1->var.def->minvalue;
if ((ptr1->var.def->maxvalue != UL &&
value > ptr1->var.def->maxvalue))
value = ptr1->var.def->maxvalue;
if (*ptr1->var.def->location.pi != value)
S_StartSound(NULL,sfx_pstop);
*ptr1->var.def->location.pi = value;
}
if (ptr1->var.def->type == def_str) {
int old_value, value;
old_value = M_IndexInChoices(*ptr1->var.def->location.ppsz,
ptr1->selectstrings);
value = old_value - 1;
if (value < 0)
value = 0;
if (old_value != value)
S_StartSound(NULL,sfx_pstop);
*ptr1->var.def->location.ppsz = ptr1->selectstrings[value];
}
}
if (ch == key_menu_right) {
if (ptr1->var.def->type == def_int) {
int value = *ptr1->var.def->location.pi;
value = value + 1;
if ((ptr1->var.def->minvalue != UL &&
value < ptr1->var.def->minvalue))
value = ptr1->var.def->minvalue;
if ((ptr1->var.def->maxvalue != UL &&
value > ptr1->var.def->maxvalue))
value = ptr1->var.def->maxvalue;
if (*ptr1->var.def->location.pi != value)
S_StartSound(NULL,sfx_pstop);
*ptr1->var.def->location.pi = value;
}
if (ptr1->var.def->type == def_str) {
int old_value, value;
old_value = M_IndexInChoices(*ptr1->var.def->location.ppsz,
ptr1->selectstrings);
value = old_value + 1;
if (ptr1->selectstrings[value] == NULL)
value = old_value;
if (old_value != value)
S_StartSound(NULL,sfx_pstop);
*ptr1->var.def->location.ppsz = ptr1->selectstrings[value];
}
}
if (ch == key_menu_enter) {
// phares 4/14/98:
// If not in demoplayback, demorecording, or netgame,
// and there's a second variable in var2, set that
// as well
// killough 8/15/98: add warning messages
if (ptr1->m_flags & (S_LEVWARN | S_PRGWARN))
warn_about_changes(ptr1->m_flags & // killough 10/98
(S_LEVWARN | S_PRGWARN));
else
M_UpdateCurrent(ptr1->var.def);
if (ptr1->action) // killough 10/98
ptr1->action();
M_SelectDone(ptr1); // phares 4/17/98
}
return true;
}
}
// Key Bindings
if (set_keybnd_active) // on a key binding setup screen
if (setup_select) // incoming key or button gets bound
{
if (ev->type == ev_joystick)
{
int oldbutton,group;
boolean search = true;
if (!ptr1->m_joy)
return true; // not a legal action here (yet)
// see if the button is already bound elsewhere. if so, you
// have to swap bindings so the action where it's currently
// bound doesn't go dead. Since there is more than one
// keybinding screen, you have to search all of them for
// any duplicates. You're only interested in the items
// that belong to the same group as the one you're changing.
oldbutton = *ptr1->m_joy;
group = ptr1->m_group;
if (ev->data1 & 1)
ch = 0;
else if (ev->data1 & 2)
ch = 1;
else if (ev->data1 & 4)
ch = 2;
else if (ev->data1 & 8)
ch = 3;
else
return true;
for (i = 0 ; keys_settings[i] && search ; i++)
for (ptr2 = keys_settings[i] ; !(ptr2->m_flags & S_END) ; ptr2++)
if (ptr2->m_group == group && ptr1 != ptr2)
if (ptr2->m_flags & S_KEY && ptr2->m_joy)
if (*ptr2->m_joy == ch)
{
*ptr2->m_joy = oldbutton;
search = false;
break;
}
*ptr1->m_joy = ch;
}
else if (ev->type == ev_mouse)
{
int i,oldbutton,group;
boolean search = true;
if (!ptr1->m_mouse)
return true; // not a legal action here (yet)
// see if the button is already bound elsewhere. if so, you
// have to swap bindings so the action where it's currently
// bound doesn't go dead. Since there is more than one
// keybinding screen, you have to search all of them for
// any duplicates. You're only interested in the items
// that belong to the same group as the one you're changing.
oldbutton = *ptr1->m_mouse;
group = ptr1->m_group;
if (ev->data1 & 1)
ch = 0;
else if (ev->data1 & 2)
ch = 1;
else if (ev->data1 & 4)
ch = 2;
else
return true;
for (i = 0 ; keys_settings[i] && search ; i++)
for (ptr2 = keys_settings[i] ; !(ptr2->m_flags & S_END) ; ptr2++)
if (ptr2->m_group == group && ptr1 != ptr2)
if (ptr2->m_flags & S_KEY && ptr2->m_mouse)
if (*ptr2->m_mouse == ch)
{
*ptr2->m_mouse = oldbutton;
search = false;
break;
}
*ptr1->m_mouse = ch;
}
else // keyboard key
{
int i,oldkey,group;
boolean search = true;
// see if 'ch' is already bound elsewhere. if so, you have
// to swap bindings so the action where it's currently
// bound doesn't go dead. Since there is more than one
// keybinding screen, you have to search all of them for
// any duplicates. You're only interested in the items
// that belong to the same group as the one you're changing.
// if you find that you're trying to swap with an action
// that has S_KEEP set, you can't bind ch; it's already
// bound to that S_KEEP action, and that action has to
// keep that key.
oldkey = *ptr1->var.m_key;
group = ptr1->m_group;
for (i = 0 ; keys_settings[i] && search ; i++)
for (ptr2 = keys_settings[i] ; !(ptr2->m_flags & S_END) ; ptr2++)
if (ptr2->m_flags & (S_KEY|S_KEEP) &&
ptr2->m_group == group &&
ptr1 != ptr2)
if (*ptr2->var.m_key == ch)
{
if (ptr2->m_flags & S_KEEP)
return true; // can't have it!
*ptr2->var.m_key = oldkey;
search = false;
break;
}
*ptr1->var.m_key = ch;
}
M_SelectDone(ptr1); // phares 4/17/98
return true;
}
// Weapons
if (set_weapon_active) // on the weapons setup screen
if (setup_select) // changing an entry
{
if (ch != key_menu_enter)
{
ch -= '0'; // out of ascii
if (ch < 1 || ch > 9)
return true; // ignore
// Plasma and BFG don't exist in shareware
// killough 10/98: allow it anyway, since this
// isn't the game itself, just setting preferences
// see if 'ch' is already assigned elsewhere. if so,
// you have to swap assignments.
// killough 11/98: simplified
for (i = 0; (ptr2 = weap_settings[i]); i++)
for (; !(ptr2->m_flags & S_END); ptr2++)
if (ptr2->m_flags & S_WEAP &&
*ptr2->var.def->location.pi == ch && ptr1 != ptr2)
{
*ptr2->var.def->location.pi = *ptr1->var.def->location.pi;
goto end;
}
end:
*ptr1->var.def->location.pi = ch;
}
M_SelectDone(ptr1); // phares 4/17/98
return true;
}
// Automap
if (set_auto_active) // on the automap setup screen
if (setup_select) // incoming key
{
if (ch == key_menu_down)
{
if (++color_palette_y == 16)
color_palette_y = 0;
S_StartSound(NULL,sfx_itemup);
return true;
}
if (ch == key_menu_up)
{
if (--color_palette_y < 0)
color_palette_y = 15;
S_StartSound(NULL,sfx_itemup);
return true;
}
if (ch == key_menu_left)
{
if (--color_palette_x < 0)
color_palette_x = 15;
S_StartSound(NULL,sfx_itemup);
return true;
}
if (ch == key_menu_right)
{
if (++color_palette_x == 16)
color_palette_x = 0;
S_StartSound(NULL,sfx_itemup);
return true;
}
if (ch == key_menu_enter)
{
*ptr1->var.def->location.pi = color_palette_x + 16*color_palette_y;
M_SelectDone(ptr1); // phares 4/17/98
colorbox_active = false;
return true;
}
}
// killough 10/98: consolidate handling into one place:
if (setup_select &&
set_enemy_active | set_general_active | set_chat_active |
set_mess_active | set_status_active | set_compat_active)
{
if (ptr1->m_flags & S_STRING) // creating/editing a string?
{
if (ch == key_menu_backspace) // backspace and DEL
{
if (chat_string_buffer[chat_index] == 0)
{
if (chat_index > 0)
chat_string_buffer[--chat_index] = 0;
}
// shift the remainder of the text one char left
else
strcpy(&chat_string_buffer[chat_index],
&chat_string_buffer[chat_index+1]);
}
else if (ch == key_menu_left) // move cursor left
{
if (chat_index > 0)
chat_index--;
}
else if (ch == key_menu_right) // move cursor right
{
if (chat_string_buffer[chat_index] != 0)
chat_index++;
}
else if ((ch == key_menu_enter) ||
(ch == key_menu_escape))
{
*ptr1->var.def->location.ppsz = chat_string_buffer;
M_SelectDone(ptr1); // phares 4/17/98
}
// Adding a char to the text. Has to be a printable
// char, and you can't overrun the buffer. If the
// chat string gets larger than what the screen can hold,
// it is dealt with when the string is drawn (above).
else if ((ch >= 32) && (ch <= 126))
if ((chat_index+1) < CHAT_STRING_BFR_SIZE)
{
if (shiftdown)
ch = shiftxform[ch];
if (chat_string_buffer[chat_index] == 0)
{
chat_string_buffer[chat_index++] = ch;
chat_string_buffer[chat_index] = 0;
}
else
chat_string_buffer[chat_index++] = ch;
}
return true;
}
M_SelectDone(ptr1); // phares 4/17/98
return true;
}
// Not changing any items on the Setup screens. See if we're
// navigating the Setup menus or selecting an item to change.
if (ch == key_menu_down)
{
ptr1->m_flags &= ~S_HILITE; // phares 4/17/98
do
if (ptr1->m_flags & S_END)
{
set_menu_itemon = 0;
ptr1 = current_setup_menu;
}
else
{
set_menu_itemon++;
ptr1++;
}
while (ptr1->m_flags & S_SKIP);
M_SelectDone(ptr1); // phares 4/17/98
return true;
}
if (ch == key_menu_up)
{
ptr1->m_flags &= ~S_HILITE; // phares 4/17/98
do
{
if (set_menu_itemon == 0)
do
set_menu_itemon++;
while(!((current_setup_menu + set_menu_itemon)->m_flags & S_END));
set_menu_itemon--;
}
while((current_setup_menu + set_menu_itemon)->m_flags & S_SKIP);
M_SelectDone(current_setup_menu + set_menu_itemon); // phares 4/17/98
return true;
}
if (ch == key_menu_enter)
{
int flags = ptr1->m_flags;
// You've selected an item to change. Highlight it, post a new
// message about what to do, and get ready to process the
// change.
//
// killough 10/98: use friendlier char-based input buffer
if (flags & S_NUM)
{
setup_gather = true;
print_warning_about_changes = false;
gather_count = 0;
}
else if (flags & S_COLOR)
{
int color = *ptr1->var.def->location.pi;
if (color < 0 || color > 255) // range check the value
color = 0; // 'no show' if invalid
color_palette_x = *ptr1->var.def->location.pi & 15;
color_palette_y = *ptr1->var.def->location.pi >> 4;
colorbox_active = true;
}
else if (flags & S_STRING)
{
// copy chat string into working buffer; trim if needed.
// free the old chat string memory and replace it with
// the (possibly larger) new memory for editing purposes
//
// killough 10/98: fix bugs, simplify
chat_string_buffer = malloc(CHAT_STRING_BFR_SIZE);
strncpy(chat_string_buffer,
*ptr1->var.def->location.ppsz, CHAT_STRING_BFR_SIZE);
// guarantee null delimiter
chat_string_buffer[CHAT_STRING_BFR_SIZE-1] = 0;
// set chat table pointer to working buffer
// and free old string's memory.
free((char*)*ptr1->var.def->location.ppsz);
*ptr1->var.def->location.ppsz = chat_string_buffer;
chat_index = 0; // current cursor position in chat_string_buffer
}
else if (flags & S_RESET)
default_verify = true;
ptr1->m_flags |= S_SELECT;
setup_select = true;
S_StartSound(NULL,sfx_itemup);
return true;
}
if ((ch == key_menu_escape) || (ch == key_menu_backspace))
{
if (ch == key_menu_escape) // Clear all menus
M_ClearMenus();
else // key_menu_backspace = return to Setup Menu
if (currentMenu->prevMenu)
{
currentMenu = currentMenu->prevMenu;
itemOn = currentMenu->lastOn;
S_StartSound(NULL,sfx_swtchn);
}
ptr1->m_flags &= ~(S_HILITE|S_SELECT);// phares 4/19/98
setup_active = false;
set_keybnd_active = false;
set_weapon_active = false;
set_status_active = false;
set_auto_active = false;
set_enemy_active = false;
set_mess_active = false;
set_chat_active = false;
colorbox_active = false;
default_verify = false; // phares 4/19/98
set_general_active = false; // killough 10/98
set_compat_active = false; // killough 10/98
HU_Start(); // catch any message changes // phares 4/19/98
S_StartSound(NULL,sfx_swtchx);
return true;
}
// Some setup screens may have multiple screens.
// When there are multiple screens, m_prev and m_next items need to
// be placed on the appropriate screen tables so the user can
// move among the screens using the left and right arrow keys.
// The m_var1 field contains a pointer to the appropriate screen
// to move to.
if (ch == key_menu_left)
{
ptr2 = ptr1;
do
{
ptr2++;
if (ptr2->m_flags & S_PREV)
{
ptr1->m_flags &= ~S_HILITE;
mult_screens_index--;
current_setup_menu = ptr2->var.menu;
set_menu_itemon = 0;
print_warning_about_changes = false; // killough 10/98
while (current_setup_menu[set_menu_itemon++].m_flags&S_SKIP);
current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
S_StartSound(NULL,sfx_pstop); // killough 10/98
return true;
}
}
while (!(ptr2->m_flags & S_END));
}
if (ch == key_menu_right)
{
ptr2 = ptr1;
do
{
ptr2++;
if (ptr2->m_flags & S_NEXT)
{
ptr1->m_flags &= ~S_HILITE;
mult_screens_index++;
current_setup_menu = ptr2->var.menu;
set_menu_itemon = 0;
print_warning_about_changes = false; // killough 10/98
while (current_setup_menu[set_menu_itemon++].m_flags&S_SKIP);
current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE;
S_StartSound(NULL,sfx_pstop); // killough 10/98
return true;
}
}
while (!(ptr2->m_flags & S_END));
}
} // End of Setup Screen processing
// From here on, these navigation keys are used on the BIG FONT menus
// like the Main Menu.
if (ch == key_menu_down) // phares 3/7/98
{
do
{
if (itemOn+1 > currentMenu->numitems-1)
itemOn = 0;
else
itemOn++;
S_StartSound(NULL,sfx_pstop);
}
while(currentMenu->menuitems[itemOn].status==-1);
return true;
}
if (ch == key_menu_up) // phares 3/7/98
{
do
{
if (!itemOn)
itemOn = currentMenu->numitems-1;
else
itemOn--;
S_StartSound(NULL,sfx_pstop);
}
while(currentMenu->menuitems[itemOn].status==-1);
return true;
}
if (ch == key_menu_left) // phares 3/7/98
{
if (currentMenu->menuitems[itemOn].routine &&
currentMenu->menuitems[itemOn].status == 2)
{
S_StartSound(NULL,sfx_stnmov);
currentMenu->menuitems[itemOn].routine(0);
}
return true;
}
if (ch == key_menu_right) // phares 3/7/98
{
if (currentMenu->menuitems[itemOn].routine &&
currentMenu->menuitems[itemOn].status == 2)
{
S_StartSound(NULL,sfx_stnmov);
currentMenu->menuitems[itemOn].routine(1);
}
return true;
}
if (ch == key_menu_enter) // phares 3/7/98
{
if (currentMenu->menuitems[itemOn].routine &&
currentMenu->menuitems[itemOn].status)
{
currentMenu->lastOn = itemOn;
if (currentMenu->menuitems[itemOn].status == 2)
{
currentMenu->menuitems[itemOn].routine(1); // right arrow
S_StartSound(NULL,sfx_stnmov);
}
else
{
currentMenu->menuitems[itemOn].routine(itemOn);
S_StartSound(NULL,sfx_pistol);
}
}
//jff 3/24/98 remember last skill selected
// killough 10/98 moved to skill-specific functions
return true;
}
if (ch == key_menu_escape) // phares 3/7/98
{
currentMenu->lastOn = itemOn;
M_ClearMenus ();
S_StartSound(NULL,sfx_swtchx);
return true;
}
if (ch == key_menu_backspace) // phares 3/7/98
{
currentMenu->lastOn = itemOn;
// phares 3/30/98:
// add checks to see if you're in the extended help screens
// if so, stay with the same menu definition, but bump the
// index back one. if the index bumps back far enough ( == 0)
// then you can return to the Read_Thisn menu definitions
if (currentMenu->prevMenu)
{
if (currentMenu == &ExtHelpDef)
{
if (--extended_help_index == 0)
{
currentMenu = currentMenu->prevMenu;
extended_help_index = 1; // reset
}
}
else
currentMenu = currentMenu->prevMenu;
itemOn = currentMenu->lastOn;
S_StartSound(NULL,sfx_swtchn);
}
return true;
}
else
{
for (i = itemOn+1;i < currentMenu->numitems;i++)
if (currentMenu->menuitems[i].alphaKey == ch)
{
itemOn = i;
S_StartSound(NULL,sfx_pstop);
return true;
}
for (i = 0;i <= itemOn;i++)
if (currentMenu->menuitems[i].alphaKey == ch)
{
itemOn = i;
S_StartSound(NULL,sfx_pstop);
return true;
}
}
return false;
}
//
// End of M_Responder
//
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// General Routines
//
// This displays the Main menu and gets the menu screens rolling.
// Plus a variety of routines that control the Big Font menu display.
// Plus some initialization for game-dependant situations.
void M_StartControlPanel (void)
{
// intro might call this repeatedly
if (menuactive)
return;
//jff 3/24/98 make default skill menu choice follow -skill or defaultskill
//from command line or config file
//
// killough 10/98:
// Fix to make "always floating" with menu selections, and to always follow
// defaultskill, instead of -skill.
NewDef.lastOn = defaultskill - 1;
default_verify = 0; // killough 10/98
menuactive = 1;
currentMenu = &MainDef; // JDC
itemOn = currentMenu->lastOn; // JDC
print_warning_about_changes = false; // killough 11/98
}
//
// M_Drawer
// Called after the view has been rendered,
// but before it has been blitted.
//
// killough 9/29/98: Significantly reformatted source
//
void M_Drawer (void)
{
inhelpscreens = false;
// Horiz. & Vertically center string and print it.
// killough 9/29/98: simplified code, removed 40-character width limit
if (messageToPrint)
{
/* cph - strdup string to writable memory */
char *ms = strdup(messageString);
char *p = ms;
int y = 100 - M_StringHeight(messageString)/2;
while (*p)
{
char *string = p, c;
while ((c = *p) && *p != '\n')
p++;
*p = 0;
M_WriteText(160 - M_StringWidth(string)/2, y, string);
y += hu_font[0].height;
if ((*p = c))
p++;
}
free(ms);
}
else
if (menuactive)
{
int x,y,max,i;
if (currentMenu->routine)
currentMenu->routine(); // call Draw routine
// DRAW MENU
x = currentMenu->x;
y = currentMenu->y;
max = currentMenu->numitems;
for (i=0;i<max;i++)
{
if (currentMenu->menuitems[i].name[0])
V_DrawNamePatch(x,y,0,currentMenu->menuitems[i].name,
CR_DEFAULT, VPT_STRETCH);
y += LINEHEIGHT;
}
// DRAW SKULL
// CPhipps - patch drawing updated
V_DrawNamePatch(x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT,0,
skullName[whichSkull], CR_DEFAULT, VPT_STRETCH);
}
}
//
// M_ClearMenus
//
// Called when leaving the menu screens for the real world
void M_ClearMenus (void)
{
menuactive = 0;
print_warning_about_changes = 0; // killough 8/15/98
default_verify = 0; // killough 10/98
// if (!netgame && usergame && paused)
// sendpause = true;
}
//
// M_SetupNextMenu
//
void M_SetupNextMenu(menu_t *menudef)
{
currentMenu = menudef;
itemOn = currentMenu->lastOn;
}
/////////////////////////////
//
// M_Ticker
//
void M_Ticker (void)
{
if (--skullAnimCounter <= 0)
{
whichSkull ^= 1;
skullAnimCounter = 8;
}
}
/////////////////////////////
//
// Message Routines
//
void M_StartMessage (const char* string,void* routine,boolean input)
{
messageLastMenuActive = menuactive;
messageToPrint = 1;
messageString = string;
messageRoutine = routine;
messageNeedsInput = input;
menuactive = true;
return;
}
void M_StopMessage(void)
{
menuactive = messageLastMenuActive;
messageToPrint = 0;
}
/////////////////////////////
//
// Thermometer Routines
//
//
// M_DrawThermo draws the thermometer graphic for Mouse Sensitivity,
// Sound Volume, etc.
//
// proff/nicolas 09/20/98 -- changed for hi-res
// CPhipps - patch drawing updated
//
void M_DrawThermo(int x,int y,int thermWidth,int thermDot )
{
int xx;
int i;
/*
* Modification By Barry Mead to allow the Thermometer to have vastly
* larger ranges. (the thermWidth parameter can now have a value as
* large as 200. Modified 1-9-2000 Originally I used it to make
* the sensitivity range for the mouse better. It could however also
* be used to improve the dynamic range of music and sound affect
* volume controls for example.
*/
int horizScaler; //Used to allow more thermo range for mouse sensitivity.
thermWidth = (thermWidth > 200) ? 200 : thermWidth; //Clamp to 200 max
horizScaler = (thermWidth > 23) ? (200 / thermWidth) : 8; //Dynamic range
xx = x;
V_DrawNamePatch(xx, y, 0, "M_THERML", CR_DEFAULT, VPT_STRETCH);
xx += 8;
for (i=0;i<thermWidth;i++)
{
V_DrawNamePatch(xx, y, 0, "M_THERMM", CR_DEFAULT, VPT_STRETCH);
xx += horizScaler;
}
xx += (8 - horizScaler); /* make the right end look even */
V_DrawNamePatch(xx, y, 0, "M_THERMR", CR_DEFAULT, VPT_STRETCH);
V_DrawNamePatch((x+8)+thermDot*horizScaler,y,0,"M_THERMO",CR_DEFAULT,VPT_STRETCH);
}
//
// Draw an empty cell in the thermometer
//
void M_DrawEmptyCell (menu_t* menu,int item)
{
// CPhipps - patch drawing updated
V_DrawNamePatch(menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0,
"M_CELL1", CR_DEFAULT, VPT_STRETCH);
}
//
// Draw a full cell in the thermometer
//
void M_DrawSelCell (menu_t* menu,int item)
{
// CPhipps - patch drawing updated
V_DrawNamePatch(menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0,
"M_CELL2", CR_DEFAULT, VPT_STRETCH);
}
/////////////////////////////
//
// String-drawing Routines
//
//
// Find string width from hu_font chars
//
int M_StringWidth(const char* string)
{
int i, c, w = 0;
for (i = 0;(size_t)i < strlen(string);i++)
w += (c = toupper(string[i]) - HU_FONTSTART) < 0 || c >= HU_FONTSIZE ?
4 : hu_font[c].width;
return w;
}
//
// Find string height from hu_font chars
//
int M_StringHeight(const char* string)
{
int i, h, height = h = hu_font[0].height;
for (i = 0;string[i];i++) // killough 1/31/98
if (string[i] == '\n')
h += height;
return h;
}
//
// Write a string using the hu_font
//
void M_WriteText (int x,int y,const char* string)
{
int w;
const char* ch;
int c;
int cx;
int cy;
ch = string;
cx = x;
cy = y;
while(1) {
c = *ch++;
if (!c)
break;
if (c == '\n') {
cx = x;
cy += 12;
continue;
}
c = toupper(c) - HU_FONTSTART;
if (c < 0 || c>= HU_FONTSIZE) {
cx += 4;
continue;
}
w = hu_font[c].width;
if (cx+w > SCREENWIDTH)
break;
// proff/nicolas 09/20/98 -- changed for hi-res
// CPhipps - patch drawing updated
V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH);
cx+=w;
}
}
/////////////////////////////
//
// Initialization Routines to take care of one-time setup
//
// phares 4/08/98:
// M_InitHelpScreen() clears the weapons from the HELP
// screen that don't exist in this version of the game.
void M_InitHelpScreen(void)
{
setup_menu_t* src;
src = helpstrings;
while (!(src->m_flags & S_END)) {
if ((strncmp(src->m_text,"PLASMA",6) == 0) && (gamemode == shareware))
src->m_flags = S_SKIP; // Don't show setting or item
if ((strncmp(src->m_text,"BFG",3) == 0) && (gamemode == shareware))
src->m_flags = S_SKIP; // Don't show setting or item
if ((strncmp(src->m_text,"SSG",3) == 0) && (gamemode != commercial))
src->m_flags = S_SKIP; // Don't show setting or item
src++;
}
}
//
// M_Init
//
void M_Init(void)
{
M_InitDefaults(); // killough 11/98
currentMenu = &MainDef;
menuactive = 0;
itemOn = currentMenu->lastOn;
whichSkull = 0;
skullAnimCounter = 10;
screenSize = screenblocks - 3;
messageToPrint = 0;
messageString = NULL;
messageLastMenuActive = menuactive;
quickSaveSlot = -1;
// Here we could catch other version dependencies,
// like HELP1/2, and four episodes.
switch(gamemode)
{
case commercial:
// This is used because DOOM 2 had only one HELP
// page. I use CREDIT as second page now, but
// kept this hack for educational purposes.
MainMenu[readthis] = MainMenu[quitdoom];
MainDef.numitems--;
MainDef.y += 8;
NewDef.prevMenu = &MainDef;
ReadDef1.routine = M_DrawReadThis1;
ReadDef1.x = 330;
ReadDef1.y = 165;
ReadMenu1[0].routine = M_FinishReadThis;
break;
case registered:
// Episode 2 and 3 are handled,
// branching to an ad screen.
// killough 2/21/98: Fix registered Doom help screen
// killough 10/98: moved to second screen, moved up to the top
ReadDef2.y = 15;
case shareware:
// We need to remove the fourth episode.
EpiDef.numitems--;
break;
case retail:
// We are fine.
default:
break;
}
M_InitHelpScreen(); // init the help screen // phares 4/08/98
M_InitExtendedHelp(); // init extended help screens // phares 3/30/98
M_ChangeDemoSmoothTurns();
}
//
// End of General Routines
//
/////////////////////////////////////////////////////////////////////////////