- merged menu branch back into trunk.

SVN r2768 (trunk)
This commit is contained in:
Christoph Oelckers 2010-09-14 17:28:18 +00:00
parent ec0b07b5e2
commit 579502ab74
86 changed files with 13680 additions and 9299 deletions

View File

@ -649,13 +649,13 @@ add_executable( zdoom WIN32
hu_scores.cpp
i_net.cpp
info.cpp
keysections.cpp
lumpconfigfile.cpp
m_alloc.cpp
m_argv.cpp
m_bbox.cpp
m_cheat.cpp
m_joy.cpp
m_menu.cpp
m_misc.cpp
m_options.cpp
m_png.cpp
@ -788,6 +788,19 @@ add_executable( zdoom WIN32
g_shared/sbar_mugshot.cpp
g_shared/shared_hud.cpp
g_shared/shared_sbar.cpp
menu/colorpickermenu.cpp
menu/joystickmenu.cpp
menu/listmenu.cpp
menu/loadsavemenu.cpp
menu/menu.cpp
menu/menudef.cpp
menu/menuinput.cpp
menu/messagebox.cpp
menu/optionmenu.cpp
menu/playerdisplay.cpp
menu/playermenu.cpp
menu/readthis.cpp
menu/videomenu.cpp
oplsynth/fmopl.cpp
oplsynth/mlopl.cpp
oplsynth/mlopl_io.cpp

View File

@ -583,7 +583,7 @@ void FKeyBindings::ArchiveBindings(FConfigFile *f, const char *matchcmd)
//
//=============================================================================
int FKeyBindings::GetKeysForCommand (char *cmd, int *first, int *second)
int FKeyBindings::GetKeysForCommand (const char *cmd, int *first, int *second)
{
int c, i;
@ -609,7 +609,7 @@ int FKeyBindings::GetKeysForCommand (char *cmd, int *first, int *second)
//
//=============================================================================
void FKeyBindings::UnbindACommand (char *str)
void FKeyBindings::UnbindACommand (const char *str)
{
int i;

View File

@ -57,8 +57,8 @@ public:
void SetBinds(const FBinding *binds);
bool DoKey(event_t *ev);
void ArchiveBindings(FConfigFile *F, const char *matchcmd = NULL);
int GetKeysForCommand (char *cmd, int *first, int *second);
void UnbindACommand (char *str);
int GetKeysForCommand (const char *cmd, int *first, int *second);
void UnbindACommand (const char *str);
void UnbindAll ();
void UnbindKey(const char *key);
void DoBind (const char *key, const char *bind);
@ -85,6 +85,7 @@ public:
extern FKeyBindings Bindings;
extern FKeyBindings DoubleBindings;
extern FKeyBindings AutomapBindings;
extern FKeyBindings MenuBindings;
bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds);
@ -95,4 +96,18 @@ void C_UnbindAll ();
extern const char *KeyNames[];
struct FKeyAction
{
FString mTitle;
FString mAction;
};
struct FKeySection
{
FString mTitle;
FString mSection;
TArray<FKeyAction> mActions;
};
extern TArray<FKeySection> KeySections;
#endif //__C_BINDINGS_H__

View File

@ -936,3 +936,4 @@ CCMD(currentpos)
FIXED2FLOAT(mo->x), FIXED2FLOAT(mo->y), FIXED2FLOAT(mo->z), mo->angle/float(ANGLE_1), FIXED2FLOAT(mo->floorz), mo->Sector->sectornum, mo->Sector->lightlevel);
}

View File

@ -1119,7 +1119,7 @@ void FFlagCVar::DoSet (UCVarValue value, ECVarType type)
// exec scripts because all flags will base their changes off of the value of
// the "master" cvar at the time the script was run, overriding any changes
// another flag might have made to the same cvar earlier in the script.
if ((ValueVar.Flags & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback)
if ((ValueVar.GetFlags() & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback)
{
if (netgame && !players[consoleplayer].settings_controller)
{
@ -1139,6 +1139,114 @@ void FFlagCVar::DoSet (UCVarValue value, ECVarType type)
}
}
//
// Mask cvar implementation
//
// Similar to FFlagCVar but can have multiple bits
//
FMaskCVar::FMaskCVar (const char *name, FIntCVar &realvar, DWORD bitval)
: FBaseCVar (name, 0, NULL),
ValueVar (realvar),
BitVal (bitval)
{
int bit;
Flags &= ~CVAR_ISDEFAULT;
assert (bitval != 0);
bit = 0;
while ((bitval & 1) == 0)
{
++bit;
bitval >>= 1;
}
BitNum = bit;
}
ECVarType FMaskCVar::GetRealType () const
{
return CVAR_Dummy;
}
UCVarValue FMaskCVar::GetGenericRep (ECVarType type) const
{
return FromInt ((ValueVar & BitVal) >> BitNum, type);
}
UCVarValue FMaskCVar::GetFavoriteRep (ECVarType *type) const
{
UCVarValue ret;
*type = CVAR_Int;
ret.Int = (ValueVar & BitVal) >> BitNum;
return ret;
}
UCVarValue FMaskCVar::GetGenericRepDefault (ECVarType type) const
{
ECVarType dummy;
UCVarValue def;
def = ValueVar.GetFavoriteRepDefault (&dummy);
return FromInt ((def.Int & BitVal) >> BitNum, type);
}
UCVarValue FMaskCVar::GetFavoriteRepDefault (ECVarType *type) const
{
ECVarType dummy;
UCVarValue def;
def = ValueVar.GetFavoriteRepDefault (&dummy);
def.Int = (def.Int & BitVal) >> BitNum;
*type = CVAR_Int;
return def;
}
void FMaskCVar::SetGenericRepDefault (UCVarValue value, ECVarType type)
{
int val = ToInt(value, type) << BitNum;
ECVarType dummy;
UCVarValue def;
def = ValueVar.GetFavoriteRepDefault (&dummy);
def.Int &= ~BitVal;
def.Int |= val;
ValueVar.SetGenericRepDefault (def, CVAR_Int);
}
void FMaskCVar::DoSet (UCVarValue value, ECVarType type)
{
int val = ToInt(value, type) << BitNum;
// Server cvars that get changed by this need to use a special message, because
// changes are not processed until the next net update. This is a problem with
// exec scripts because all flags will base their changes off of the value of
// the "master" cvar at the time the script was run, overriding any changes
// another flag might have made to the same cvar earlier in the script.
if ((ValueVar.GetFlags() & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback)
{
if (netgame && !players[consoleplayer].settings_controller)
{
Printf ("Only setting controllers can change %s\n", Name);
return;
}
// Ugh...
for(int i = 0; i < 32; i++)
{
if (BitVal & (1<<i))
{
D_SendServerFlagChange (&ValueVar, i, !!(val & (1<<i)));
}
}
}
else
{
int vval = *ValueVar;
vval &= ~BitVal;
vval |= val;
ValueVar = vval;
}
}
////////////////////////////////////////////////////////////////////////
static int STACK_ARGS sortcvars (const void *a, const void *b)
{

View File

@ -344,6 +344,30 @@ protected:
int BitNum;
};
class FMaskCVar : public FBaseCVar
{
public:
FMaskCVar (const char *name, FIntCVar &realvar, uint32 bitval);
virtual ECVarType GetRealType () const;
virtual UCVarValue GetGenericRep (ECVarType type) const;
virtual UCVarValue GetFavoriteRep (ECVarType *type) const;
virtual UCVarValue GetGenericRepDefault (ECVarType type) const;
virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const;
virtual void SetGenericRepDefault (UCVarValue value, ECVarType type);
inline operator int () const { return (ValueVar & BitVal) >> BitNum; }
inline int operator *() const { return (ValueVar & BitVal) >> BitNum; }
protected:
virtual void DoSet (UCVarValue value, ECVarType type);
FIntCVar &ValueVar;
uint32 BitVal;
int BitNum;
};
class FGUIDCVar : public FBaseCVar
{
public:

View File

@ -43,27 +43,34 @@ enum EGUIEvent
EV_GUI_KeyRepeat, // same
EV_GUI_KeyUp, // same
EV_GUI_Char, // data1: translated character (for user text input), data2: alt down?
EV_GUI_MouseMove,
EV_GUI_LButtonDown,
EV_GUI_LButtonUp,
EV_GUI_LButtonDblClick,
EV_GUI_MButtonDown,
EV_GUI_MButtonUp,
EV_GUI_MButtonDblClick,
EV_GUI_RButtonDown,
EV_GUI_RButtonUp,
EV_GUI_RButtonDblClick,
EV_GUI_WheelUp, // data3: shift/ctrl/alt
EV_GUI_WheelDown, // "
EV_GUI_WheelRight, // "
EV_GUI_WheelLeft, // "
EV_GUI_FirstMouseEvent,
EV_GUI_MouseMove,
EV_GUI_LButtonDown,
EV_GUI_LButtonUp,
EV_GUI_LButtonDblClick,
EV_GUI_MButtonDown,
EV_GUI_MButtonUp,
EV_GUI_MButtonDblClick,
EV_GUI_RButtonDown,
EV_GUI_RButtonUp,
EV_GUI_RButtonDblClick,
EV_GUI_WheelUp, // data3: shift/ctrl/alt
EV_GUI_WheelDown, // "
EV_GUI_WheelRight, // "
EV_GUI_WheelLeft, // "
EV_GUI_BackButtonDown,
EV_GUI_BackButtonUp,
EV_GUI_FwdButtonDown,
EV_GUI_FwdButtonUp,
EV_GUI_LastMouseEvent,
};
enum GUIKeyModifiers
{
GKM_SHIFT = 1,
GKM_CTRL = 2,
GKM_ALT = 4
GKM_ALT = 4,
GKM_LBUTTON = 8
};
// Special codes for some GUI keys, including a few real ASCII codes.
@ -100,7 +107,7 @@ enum ESpecialGUIKeys
GK_ESCAPE = 27, // ASCII
GK_FREE1 = 28,
GK_FREE2 = 29,
GK_FREE3 = 30,
GK_BACK = 30, // browser back key
GK_CESCAPE = 31 // color escape
};

View File

@ -79,7 +79,7 @@ const IWADInfo IWADInfos[NUM_IWAD_TYPES] =
{ "FreeDM", "FreeDM", MAKERGB(50,84,67), MAKERGB(198,220,209), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx },
{ "Blasphemer", "Blasphemer",MAKERGB(115,0,0), MAKERGB(0,0,0), GAME_Heretic, "mapinfo/heretic.txt" },
{ "Chex(R) Quest", "Chex1", MAKERGB(255,255,0), MAKERGB(0,192,0), GAME_Chex, "mapinfo/chex.txt" },
{ "Chex(R) Quest 3", "Chex3", MAKERGB(255,255,0), MAKERGB(0,192,0), GAME_Chex, "mapinfo/chex3.txt" },
{ "Chex(R) Quest 3", "Chex3", MAKERGB(255,255,0), MAKERGB(0,192,0), GAME_Chex, "mapinfo/chex3.txt", GI_NOTEXTCOLOR },
{ "Action Doom 2: Urban Brawl", "UrbanBrawl",MAKERGB(168,168,0), MAKERGB(168,0,0), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx },
{ "Harmony", "Harmony", MAKERGB(110,180,230), MAKERGB(69,79,126), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx },
//{ "ZDoom Engine", NULL, MAKERGB(168,0,0), MAKERGB(168,168,168) },

View File

@ -61,7 +61,7 @@
#include "f_wipe.h"
#include "m_argv.h"
#include "m_misc.h"
#include "m_menu.h"
#include "menu/menu.h"
#include "c_console.h"
#include "c_dispatch.h"
#include "i_system.h"
@ -392,6 +392,18 @@ CVAR (Flag, sv_nofov, dmflags, DF_NO_FOV);
CVAR (Flag, sv_noweaponspawn, dmflags, DF_NO_COOP_WEAPON_SPAWN);
CVAR (Flag, sv_nocrouch, dmflags, DF_NO_CROUCH);
CVAR (Flag, sv_allowcrouch, dmflags, DF_YES_CROUCH);
CVAR (Flag, sv_cooploseinventory, dmflags, DF_COOP_LOSE_INVENTORY);
CVAR (Flag, sv_cooplosekeys, dmflags, DF_COOP_LOSE_KEYS);
CVAR (Flag, sv_cooploseweapons, dmflags, DF_COOP_LOSE_WEAPONS);
CVAR (Flag, sv_cooplosearmor, dmflags, DF_COOP_LOSE_ARMOR);
CVAR (Flag, sv_cooplosepowerups, dmflags, DF_COOP_LOSE_POWERUPS);
CVAR (Flag, sv_cooploseammo, dmflags, DF_COOP_LOSE_AMMO);
CVAR (Flag, sv_coophalveammo, dmflags, DF_COOP_HALVE_AMMO);
// Some (hopefully cleaner) interface to these settings.
CVAR (Mask, sv_crouch, dmflags, DF_NO_CROUCH|DF_YES_CROUCH);
CVAR (Mask, sv_jump, dmflags, DF_NO_JUMP|DF_YES_JUMP);
CVAR (Mask, sv_fallingdamage, dmflags, DF_FORCE_FALLINGHX|DF_FORCE_FALLINGZD);
//==========================================================================
//
@ -462,7 +474,6 @@ CVAR (Flag, sv_disallowsuicide, dmflags2, DF2_NOSUICIDE);
CVAR (Flag, sv_noautoaim, dmflags2, DF2_NOAUTOAIM);
CVAR (Flag, sv_dontcheckammo, dmflags2, DF2_DONTCHECKAMMO);
CVAR (Flag, sv_killbossmonst, dmflags2, DF2_KILLBOSSMONST);
//==========================================================================
//
// CVAR compatflags
@ -888,6 +899,8 @@ void D_DoomLoop ()
// Clamp the timer to TICRATE until the playloop has been entered.
r_NoInterpolate = true;
I_SetCursor(TexMan["cursor"]);
for (;;)
{
try
@ -2077,6 +2090,7 @@ void D_DoomMain (void)
// [GRB] Initialize player class list
SetupPlayerClasses ();
// [RH] Load custom key and weapon settings from WADs
D_LoadWadSettings ();
@ -2146,7 +2160,7 @@ void D_DoomMain (void)
bglobal.spawn_tries = 0;
bglobal.wanted_botnum = bglobal.getspawned.Size();
Printf ("M_Init: Init miscellaneous info.\n");
Printf ("M_Init: Init menus.\n");
M_Init ();
Printf ("P_Init: Init Playloop state.\n");

View File

@ -25,7 +25,7 @@
#include <stddef.h>
#include "version.h"
#include "m_menu.h"
#include "menu/menu.h"
#include "m_random.h"
#include "i_system.h"
#include "i_video.h"

View File

@ -54,6 +54,7 @@ enum
APMETA_ColorRange, // skin color range
APMETA_InvulMode,
APMETA_HealingRadius,
APMETA_Portrait,
APMETA_Hexenarmor0,
APMETA_Hexenarmor1,
APMETA_Hexenarmor2,

View File

@ -72,6 +72,7 @@
#include "doomstat.h"
#include "m_argv.h"
#include "po_man.h"
#include "menu/menu.h"
// MACROS ------------------------------------------------------------------
@ -298,6 +299,7 @@ static void MarkRoot()
Mark(Args);
Mark(screen);
Mark(StatusBar);
Mark(DMenu::CurrentMenu);
DThinker::MarkRoots();
FCanvasTextureInfo::Mark();
Mark(DACSThinker::ActiveThinker);

View File

@ -40,7 +40,7 @@
#include "f_finale.h"
#include "m_argv.h"
#include "m_misc.h"
#include "m_menu.h"
#include "menu/menu.h"
#include "m_random.h"
#include "m_crc32.h"
#include "i_system.h"
@ -128,6 +128,8 @@ CUSTOM_CVAR (Int, displaynametags, 0, CVAR_ARCHIVE)
}
}
CVAR(Int, nametagcolor, CR_GOLD, CVAR_ARCHIVE)
gameaction_t gameaction;
gamestate_t gamestate = GS_STARTUP;
@ -326,7 +328,7 @@ CCMD (weapnext)
if ((displaynametags & 2) && StatusBar && SmallFont && SendItemUse)
{
StatusBar->AttachMessage(new DHUDMessageFadeOut(SmallFont, SendItemUse->GetTag(),
1.5f, 0.90f, 0, 0, CR_GOLD, 2.f, 0.35f), MAKE_ID( 'W', 'E', 'P', 'N' ));
1.5f, 0.90f, 0, 0, (EColorRange)*nametagcolor, 2.f, 0.35f), MAKE_ID( 'W', 'E', 'P', 'N' ));
}
}
@ -337,7 +339,7 @@ CCMD (weapprev)
if ((displaynametags & 2) && StatusBar && SmallFont && SendItemUse)
{
StatusBar->AttachMessage(new DHUDMessageFadeOut(SmallFont, SendItemUse->GetTag(),
1.5f, 0.90f, 0, 0, CR_GOLD, 2.f, 0.35f), MAKE_ID( 'W', 'E', 'P', 'N' ));
1.5f, 0.90f, 0, 0, (EColorRange)*nametagcolor, 2.f, 0.35f), MAKE_ID( 'W', 'E', 'P', 'N' ));
}
}
@ -368,7 +370,7 @@ CCMD (invnext)
}
if ((displaynametags & 1) && StatusBar && SmallFont && who->InvSel)
StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, who->InvSel->GetTag(),
1.5f, 0.80f, 0, 0, CR_GOLD, 2.f, 0.35f), MAKE_ID('S','I','N','V'));
1.5f, 0.80f, 0, 0, (EColorRange)*nametagcolor, 2.f, 0.35f), MAKE_ID('S','I','N','V'));
}
who->player->inventorytics = 5*TICRATE;
}
@ -398,7 +400,7 @@ CCMD (invprev)
}
if ((displaynametags & 1) && StatusBar && SmallFont && who->InvSel)
StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, who->InvSel->GetTag(),
1.5f, 0.80f, 0, 0, CR_GOLD, 2.f, 0.35f), MAKE_ID('S','I','N','V'));
1.5f, 0.80f, 0, 0, (EColorRange)*nametagcolor, 2.f, 0.35f), MAKE_ID('S','I','N','V'));
}
who->player->inventorytics = 5*TICRATE;
}
@ -897,7 +899,8 @@ bool G_Responder (event_t *ev)
stricmp (cmd, "bumpgamma") &&
stricmp (cmd, "screenshot")))
{
M_StartControlPanel (true, true);
M_StartControlPanel(true);
M_SetMenu(NAME_Mainmenu, -1);
return true;
}
else

View File

@ -68,7 +68,6 @@
#include "m_png.h"
#include "m_random.h"
#include "version.h"
#include "m_menu.h"
#include "statnums.h"
#include "sbarinfo.h"
#include "r_translate.h"
@ -78,6 +77,7 @@
#include "d_net.h"
#include "d_netinf.h"
#include "v_palette.h"
#include "menu/menu.h"
#include "gi.h"
@ -99,6 +99,7 @@ void STAT_WRITE(FILE *f);
EXTERN_CVAR (Float, sv_gravity)
EXTERN_CVAR (Float, sv_aircontrol)
EXTERN_CVAR (Int, disableautosave)
EXTERN_CVAR (String, playerclass)
#define SNAP_ID MAKE_ID('s','n','A','p')
#define DSNP_ID MAKE_ID('d','s','N','p')
@ -230,6 +231,15 @@ void G_DeferedInitNew (const char *mapname, int newskill)
gameaction = ga_newgame2;
}
void G_DeferedInitNew (FGameStartup *gs)
{
playerclass = gs->PlayerClass;
d_mapname = AllEpisodes[gs->Episode].mEpisodeMap;
d_skill = gs->Skill;
CheckWarpTransMap (d_mapname, true);
gameaction = ga_newgame2;
}
//==========================================================================
//
//

View File

@ -486,6 +486,8 @@ void G_InitNew (const char *mapname, bool bTitleLevel);
// A normal game starts at map 1,
// but a warp test can start elsewhere
void G_DeferedInitNew (const char *mapname, int skill = -1);
struct FGameStartup;
void G_DeferedInitNew (FGameStartup *gs);
void G_ExitLevel (int position, bool keepFacing);
void G_SecretExitLevel (int position);
@ -603,6 +605,16 @@ struct FSkillInfo
extern TArray<FSkillInfo> AllSkills;
extern int DefaultSkill;
struct FEpisode
{
FString mEpisodeName;
FString mEpisodeMap;
FString mPicName;
char mShortcut;
bool mNoSkill;
};
extern TArray<FEpisode> AllEpisodes;
#endif //__G_LEVEL_H__

View File

@ -38,7 +38,6 @@
#include "g_level.h"
#include "sc_man.h"
#include "w_wad.h"
#include "m_menu.h"
#include "cmdlib.h"
#include "v_video.h"
#include "p_lnspec.h"
@ -63,6 +62,8 @@ TArray<level_info_t> wadlevelinfos;
level_info_t TheDefaultLevelInfo;
static cluster_info_t TheDefaultClusterInfo;
TArray<FEpisode> AllEpisodes;
//==========================================================================
//
//
@ -1655,10 +1656,10 @@ level_info_t *FMapInfoParser::ParseMapHeader(level_info_t &defaultinfo)
void FMapInfoParser::ParseEpisodeInfo ()
{
int i;
unsigned int i;
char map[9];
char *pic = NULL;
bool picisgfx = false; // Shut up, GCC!!!!
FString pic;
FString name;
bool remove = false;
char key = 0;
bool noskill = false;
@ -1697,15 +1698,13 @@ void FMapInfoParser::ParseEpisodeInfo ()
{
ParseAssign();
sc.MustGetString ();
ReplaceString (&pic, sc.String);
picisgfx = false;
name = sc.String;
}
else if (sc.Compare ("picname"))
{
ParseAssign();
sc.MustGetString ();
ReplaceString (&pic, sc.String);
picisgfx = true;
pic = sc.String;
}
else if (sc.Compare ("remove"))
{
@ -1751,9 +1750,9 @@ void FMapInfoParser::ParseEpisodeInfo ()
}
for (i = 0; i < EpiDef.numitems; ++i)
for (i = 0; i < AllEpisodes.Size(); i++)
{
if (strncmp (EpisodeMaps[i], map, 8) == 0)
if (AllEpisodes[i].mEpisodeMap.CompareNoCase(map) == 0)
{
break;
}
@ -1762,50 +1761,17 @@ void FMapInfoParser::ParseEpisodeInfo ()
if (remove)
{
// If the remove property is given for an episode, remove it.
if (i < EpiDef.numitems)
{
if (i+1 < EpiDef.numitems)
{
memmove (&EpisodeMaps[i], &EpisodeMaps[i+1],
sizeof(EpisodeMaps[0])*(EpiDef.numitems - i - 1));
memmove (&EpisodeMenu[i], &EpisodeMenu[i+1],
sizeof(EpisodeMenu[0])*(EpiDef.numitems - i - 1));
memmove (&EpisodeNoSkill[i], &EpisodeNoSkill[i+1],
sizeof(EpisodeNoSkill[0])*(EpiDef.numitems - i - 1));
}
EpiDef.numitems--;
}
AllEpisodes.Delete(i);
}
else
{
if (pic == NULL)
{
pic = copystring (map);
picisgfx = false;
}
FEpisode *epi = &AllEpisodes[AllEpisodes.Reserve(1)];
if (i == EpiDef.numitems)
{
if (EpiDef.numitems == MAX_EPISODES)
{
i = EpiDef.numitems - 1;
}
else
{
i = EpiDef.numitems++;
}
}
else
{
delete[] const_cast<char *>(EpisodeMenu[i].name);
}
EpisodeMenu[i].name = pic;
EpisodeMenu[i].alphaKey = tolower(key);
EpisodeMenu[i].fulltext = !picisgfx;
EpisodeNoSkill[i] = noskill;
strncpy (EpisodeMaps[i], map, 8);
EpisodeMaps[i][8] = 0;
epi->mEpisodeMap = map;
epi->mEpisodeName = name;
epi->mPicName = pic;
epi->mShortcut = tolower(key);
epi->mNoSkill = noskill;
}
}
@ -1818,12 +1784,7 @@ void FMapInfoParser::ParseEpisodeInfo ()
void ClearEpisodes()
{
for (int i = 0; i < EpiDef.numitems; ++i)
{
delete[] const_cast<char *>(EpisodeMenu[i].name);
EpisodeMenu[i].name = NULL;
}
EpiDef.numitems = 0;
AllEpisodes.Clear();
}
//==========================================================================
@ -2004,7 +1965,7 @@ void G_ParseMapInfo (const char *basemapinfo)
}
EndSequences.ShrinkToFit ();
if (EpiDef.numitems == 0)
if (AllEpisodes.Size() == 0)
{
I_FatalError ("You cannot use clearepisodes in a MAPINFO if you do not define any new episodes after it.");
}

View File

@ -103,12 +103,11 @@ const char* GameInfoBoarders[] =
do \
{ \
sc.MustGetToken(TK_StringConst); \
if(strlen(sc.String) > length) \
if(length > 0 && strlen(sc.String) > length) \
{ \
sc.ScriptError("Value for '%s' can not be longer than %d characters.", #key, length); \
} \
FName val = sc.String; \
gameinfo.key.Push(val); \
gameinfo.key[gameinfo.key.Reserve(1)] = sc.String; \
} \
while (sc.CheckToken(',')); \
}
@ -283,6 +282,16 @@ void FMapInfoParser::ParseGameInfo()
GAMEINFOKEY_INT(defaultdropstyle, "defaultdropstyle")
GAMEINFOKEY_CSTRING(Endoom, "endoom", 8)
GAMEINFOKEY_INT(player5start, "player5start")
GAMEINFOKEY_STRINGARRAY(quitmessages, "quitmessages", 0)
GAMEINFOKEY_STRING(mTitleColor, "menufontcolor_title")
GAMEINFOKEY_STRING(mFontColor, "menufontcolor_label")
GAMEINFOKEY_STRING(mFontColorValue, "menufontcolor_value")
GAMEINFOKEY_STRING(mFontColorMore, "menufontcolor_action")
GAMEINFOKEY_STRING(mFontColorHeader, "menufontcolor_header")
GAMEINFOKEY_STRING(mFontColorHighlight, "menufontcolor_highlight")
GAMEINFOKEY_STRING(mFontColorSelection, "menufontcolor_selection")
GAMEINFOKEY_CSTRING(mBackButton, "menubackbutton", 8)
else
{
// ignore unkown keys.

View File

@ -46,6 +46,7 @@
#define GI_COMPATSTAIRS 0x00000020 // same for stairbuilding
#define GI_COMPATPOLY1 0x00000040 // Hexen's MAP36 needs old polyobject drawing
#define GI_COMPATPOLY2 0x00000080 // so does HEXDD's MAP47
#define GI_NOTEXTCOLOR 0x00000100
#include "gametype.h"
@ -109,6 +110,15 @@ struct gameinfo_t
int defaultdropstyle;
int player5start;
DWORD pickupcolor;
TArray<FString> quitmessages;
FName mTitleColor;
FName mFontColor;
FName mFontColorValue;
FName mFontColorMore;
FName mFontColorHeader;
FName mFontColorHighlight;
FName mFontColorSelection;
char mBackButton[9];
const char *GetFinalePage(unsigned int num) const;
};

146
src/keysections.cpp Normal file
View File

@ -0,0 +1,146 @@
/*
** keysections.cpp
** Custom key bindings
**
**---------------------------------------------------------------------------
** Copyright 1998-2009 Randy Heit
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "menu/menu.h"
#include "g_level.h"
#include "d_player.h"
#include "gi.h"
#include "c_bind.h"
#include "c_dispatch.h"
#include "gameconfigfile.h"
TArray<FKeySection> KeySections;
static void LoadKeys (const char *modname, bool dbl)
{
char section[64];
if (GameNames[gameinfo.gametype] == NULL)
return;
mysnprintf (section, countof(section), "%s.%s%sBindings", GameNames[gameinfo.gametype], modname,
dbl ? ".Double" : ".");
FKeyBindings *bindings = dbl? &DoubleBindings : &Bindings;
if (GameConfig->SetSection (section))
{
const char *key, *value;
while (GameConfig->NextInSection (key, value))
{
bindings->DoBind (key, value);
}
}
}
static void DoSaveKeys (FConfigFile *config, const char *section, FKeySection *keysection, bool dbl)
{
config->SetSection (section, true);
config->ClearCurrentSection ();
FKeyBindings *bindings = dbl? &DoubleBindings : &Bindings;
for (unsigned i = 0; i < keysection->mActions.Size(); ++i)
{
bindings->ArchiveBindings (config, keysection->mActions[i].mAction);
}
}
void M_SaveCustomKeys (FConfigFile *config, char *section, char *subsection, size_t sublen)
{
for (unsigned i=0; i<KeySections.Size(); i++)
{
mysnprintf (subsection, sublen, "%s.Bindings", KeySections[i].mSection);
DoSaveKeys (config, section, &KeySections[i], false);
mysnprintf (subsection, sublen, "%s.DoubleBindings", KeySections[i].mSection);
DoSaveKeys (config, section, &KeySections[i], true);
}
}
static int CurrentKeySection = -1;
CCMD (addkeysection)
{
if (ParsingKeyConf)
{
if (argv.argc() != 3)
{
Printf ("Usage: addkeysection <menu section name> <ini name>\n");
return;
}
// Limit the ini name to 32 chars
if (strlen (argv[2]) > 32)
argv[2][32] = 0;
for (unsigned i = 0; i < KeySections.Size(); i++)
{
if (KeySections[i].mTitle.CompareNoCase(argv[2] == 0))
{
CurrentKeySection = i;
return;
}
}
CurrentKeySection = KeySections.Reserve(1);
KeySections[CurrentKeySection].mTitle = argv[1];
KeySections[CurrentKeySection].mSection = argv[2];
// Load bindings for this section from the ini
LoadKeys (argv[2], 0);
LoadKeys (argv[2], 1);
}
}
CCMD (addmenukey)
{
if (ParsingKeyConf)
{
if (argv.argc() != 3)
{
Printf ("Usage: addmenukey <description> <command>\n");
return;
}
if (CurrentKeySection == -1 || CurrentKeySection >= (int)KeySections.Size())
{
Printf ("You must use addkeysection first.\n");
return;
}
FKeySection *sect = &KeySections[CurrentKeySection];
FKeyAction *act = &sect->mActions[sect->mActions.Reserve(1)];
act->mTitle = argv[1];
act->mAction = argv[2];
}
}

View File

@ -60,5 +60,6 @@ double Joy_RemoveDeadZone(double axisval, double deadzone, BYTE *buttons);
void I_GetAxes(float axes[NUM_JOYAXIS]);
void I_GetJoysticks(TArray<IJoystickConfig *> &sticks);
IJoystickConfig *I_UpdateDeviceList();
extern void UpdateJoystickMenu(IJoystickConfig *);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,280 +0,0 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Menu widget stuff, episode selection and such.
//
//-----------------------------------------------------------------------------
#ifndef __M_MENU_H__
#define __M_MENU_H__
#include "c_cvars.h"
struct event_t;
struct menu_t;
//
// MENUS
//
// Called by main loop,
// saves config file and calls I_Quit when user exits.
// Even when the menu is not displayed,
// this can resize the view and change game parameters.
// Does all the real work of the menu interaction.
bool M_Responder (event_t *ev);
// Called by main loop,
// only used for menu (skull cursor) animation.
void M_Ticker (void);
// Called by main loop,
// draws the menus directly into the screen buffer.
void M_Drawer (void);
// Called by D_DoomMain, loads the config file.
void M_Init (void);
void M_Deinit ();
// Called by intro code to force menu up upon a keypress,
// does nothing if menu is already up.
void M_StartControlPanel (bool makeSound, bool wantTop=false);
// Turns off the menu
void M_ClearMenus ();
// [RH] Setup options menu
bool M_StartOptionsMenu (void);
// [RH] Handle keys for options menu
void M_OptResponder (event_t *ev);
// [RH] Draw options menu
void M_OptDrawer (void);
// [RH] Initialize options menu
void M_OptInit (void);
// [RH] Initialize the video modes menu
void M_InitVideoModesMenu (void);
void M_SwitchMenu (struct menu_t *menu);
void M_PopMenuStack (void);
// [RH] Called whenever the display mode changes
void M_RefreshModesList ();
void M_ActivateMenuInput ();
void M_DeactivateMenuInput ();
void M_NotifyNewSave (const char *file, const char *title, bool okForQuicksave);
//
// MENU TYPEDEFS
//
typedef enum {
whitetext,
redtext,
more,
rightmore,
safemore,
rsafemore,
joymore,
slider,
absslider,
inverter,
discrete,
discretes,
cdiscrete,
ediscrete,
control,
screenres,
bitflag,
bitmask,
listelement,
nochoice,
numberedmore,
colorpicker,
intslider,
palettegrid,
joy_sens,
joy_slider,
joy_map,
joy_inverter,
mapcontrol,
} itemtype;
struct IJoystickConfig;
void UpdateJoystickMenu(IJoystickConfig *selected);
// Yeargh! It's a monster!
struct menuitem_t
{
itemtype type;
const char *label;
union {
FBaseCVar *cvar;
FIntCVar *intcvar;
FGUIDCVar *guidcvar;
FColorCVar *colorcvar;
int selmode;
float fval;
int joyselection;
} a;
union {
float min; /* aka numvalues aka invflag */
float numvalues;
float invflag;
int key1;
char *res1;
int position;
} b;
union {
float max;
int key2;
char *res2;
void *extra;
float discretecenter; // 1 to center or 2 to disable repeat (do I even use centered discretes?)
} c;
union {
float step;
char *res3;
FBoolCVar *graycheck; // for drawing discrete items
} d;
union {
struct value_t *values;
struct valuestring_t *valuestrings;
struct valueenum_t *enumvalues;
char *command;
void (*cfunc)(FBaseCVar *cvar, float newval);
void (*mfunc)(void);
void (*lfunc)(int);
int highlight;
int flagmask;
int joyslidernum;
} e;
};
struct menu_t {
const char *texttitle;
int lastOn;
int numitems;
int indent;
menuitem_t *items;
int scrolltop;
int scrollpos;
int y;
bool (*PreDraw)(void);
bool DontDim;
void (*EscapeHandler)(void);
};
struct value_t {
float value;
const char *name;
};
struct valuestring_t {
float value;
FString name;
};
struct valueenum_t {
const char *value; // Value of cvar
const char *name; // Name on menu
};
struct oldmenuitem_t
{
// -1 = no cursor here, 1 = ok, 2 = arrows ok
SBYTE status;
BYTE fulltext; // [RH] Menu name is text, not a graphic
// hotkey in menu
char alphaKey;
const char *name;
// choice = menu item #.
// if status = 2,
// choice=0:leftarrow,1:rightarrow
void (*routine)(int choice);
int textcolor;
};
struct oldmenu_t
{
short numitems; // # of menu items
oldmenuitem_t *menuitems; // menu items
void (*routine)(void); // draw routine
short x;
short y; // x,y of menu
short lastOn; // last item user was on in menu
};
struct menustack_t
{
union {
menu_t *newmenu;
oldmenu_t *old;
} menu;
bool isNewStyle;
bool drawSkull;
};
enum EMenuKey
{
MKEY_Up,
MKEY_Down,
MKEY_Left,
MKEY_Right,
MKEY_PageUp,
MKEY_PageDown,
//----------------- Keys past here do not repeat.
MKEY_Enter,
MKEY_Back, // Back to previous menu
MKEY_Clear, // Clear keybinding/flip player sprite preview
NUM_MKEYS
};
void M_ButtonHandler(EMenuKey key, bool repeat);
void M_OptButtonHandler(EMenuKey key, bool repeat);
void M_DrawConText (int color, int x, int y, const char *str);
extern value_t YesNo[2];
extern value_t NoYes[2];
extern value_t OnOff[2];
extern menustack_t MenuStack[16];
extern int MenuStackDepth;
extern bool OptionsActive;
extern int skullAnimCounter;
extern menu_t *CurrentMenu;
extern int CurrentItem;
#define MAX_EPISODES 8
extern oldmenuitem_t EpisodeMenu[MAX_EPISODES];
extern bool EpisodeNoSkill[MAX_EPISODES];
extern char EpisodeMaps[MAX_EPISODES][9];
extern oldmenu_t EpiDef;
#endif

View File

@ -85,8 +85,6 @@ CVAR(String, screenshot_type, "png", CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CVAR(String, screenshot_dir, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
EXTERN_CVAR(Bool, longsavemessages);
extern void FreeKeySections();
static long ParseCommandLine (const char *args, int *argc, char **argv);
//
@ -420,7 +418,6 @@ void M_LoadDefaults ()
{
GameConfig = new FGameConfigFile;
GameConfig->DoGlobalSetup ();
atterm (FreeKeySections);
atterm (M_SaveDefaultsFinal);
}

View File

@ -43,6 +43,7 @@ void M_LoadDefaults ();
bool M_SaveDefaults (const char *filename);
void M_SaveCustomKeys (FConfigFile *config, char *section, char *subsection, size_t sublen);
// Prepends ~/.zdoom to path
FString GetUserFile (const char *path);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,357 @@
/*
** colorpickermenu.cpp
** The color picker menu
**
**---------------------------------------------------------------------------
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include <float.h>
#include "menu/menu.h"
#include "c_dispatch.h"
#include "w_wad.h"
#include "sc_man.h"
#include "v_font.h"
#include "g_level.h"
#include "d_player.h"
#include "v_video.h"
#include "gi.h"
#include "i_system.h"
#include "c_bind.h"
#include "v_palette.h"
#include "d_event.h"
#include "d_gui.h"
#define NO_IMP
#include "menu/optionmenuitems.h"
class DColorPickerMenu : public DOptionMenu
{
DECLARE_CLASS(DColorPickerMenu, DOptionMenu)
float mRed;
float mGreen;
float mBlue;
int mGridPosX;
int mGridPosY;
int mStartItem;
FColorCVar *mCVar;
public:
DColorPickerMenu(DMenu *parent, const char *name, FOptionMenuDescriptor *desc, FColorCVar *cvar)
{
mStartItem = desc->mItems.Size();
mRed = (float)RPART(DWORD(*cvar));
mGreen = (float)GPART(DWORD(*cvar));
mBlue = (float)BPART(DWORD(*cvar));
mGridPosX = 0;
mGridPosY = 0;
mCVar = cvar;
// This menu uses some featurs that are hard to implement in an external control lump
// so it creates its own list of menu items.
desc->mItems.Resize(mStartItem+8);
desc->mItems[mStartItem+0] = new FOptionMenuItemStaticText(name, false);
desc->mItems[mStartItem+1] = new FOptionMenuItemStaticText(" ", false);
desc->mItems[mStartItem+2] = new FOptionMenuSliderVar("Red", &mRed, 0, 255, 15, 0);
desc->mItems[mStartItem+3] = new FOptionMenuSliderVar("Green", &mGreen, 0, 255, 15, 0);
desc->mItems[mStartItem+4] = new FOptionMenuSliderVar("Blue", &mBlue, 0, 255, 15, 0);
desc->mItems[mStartItem+5] = new FOptionMenuItemStaticText(" ", false);
desc->mItems[mStartItem+6] = new FOptionMenuItemCommand("Undo changes", "undocolorpic");
desc->mItems[mStartItem+7] = new FOptionMenuItemStaticText(" ", false);
desc->mSelectedItem = mStartItem + 2;
Init(parent, desc);
desc->mIndent = 0;
desc->CalcIndent();
}
void Destroy()
{
if (mStartItem >= 0)
{
for(unsigned i=0;i<8;i++)
{
delete mDesc->mItems[mStartItem+i];
mDesc->mItems.Resize(mStartItem);
}
UCVarValue val;
val.Int = MAKERGB(int(mRed), int(mGreen), int(mBlue));
if (mCVar != NULL) mCVar->SetGenericRep (val, CVAR_Int);
mStartItem = -1;
}
}
void Reset()
{
mRed = (float)RPART(DWORD(*mCVar));
mGreen = (float)GPART(DWORD(*mCVar));
mBlue = (float)BPART(DWORD(*mCVar));
}
//=============================================================================
//
//
//
//=============================================================================
bool MenuEvent (int mkey, bool fromcontroller)
{
int &mSelectedItem = mDesc->mSelectedItem;
switch (mkey)
{
case MKEY_Down:
if (mSelectedItem == mStartItem+6) // last valid item
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
mGridPosY = 0;
// let it point to the last static item so that the super class code still has a valid item
mSelectedItem = mStartItem+7;
return true;
}
else if (mSelectedItem == mStartItem+7)
{
if (mGridPosY < 15)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
mGridPosY++;
}
return true;
}
break;
case MKEY_Up:
if (mSelectedItem == mStartItem+7)
{
if (mGridPosY > 0)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
mGridPosY--;
}
else
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
mSelectedItem = mStartItem+6;
}
return true;
}
break;
case MKEY_Left:
if (mSelectedItem == mStartItem+7)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
if (--mGridPosX < 0) mGridPosX = 15;
return true;
}
break;
case MKEY_Right:
if (mSelectedItem == mStartItem+7)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
if (++mGridPosX > 15) mGridPosX = 0;
return true;
}
break;
case MKEY_Enter:
if (mSelectedItem == mStartItem+7)
{
// Choose selected palette entry
int index = mGridPosX + mGridPosY * 16;
mRed = GPalette.BaseColors[index].r;
mGreen = GPalette.BaseColors[index].g;
mBlue = GPalette.BaseColors[index].b;
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
return true;
}
break;
}
if (mSelectedItem >= 0 && mSelectedItem < mStartItem+7)
{
if (mDesc->mItems[mDesc->mSelectedItem]->MenuEvent(mkey, fromcontroller)) return true;
}
return Super::MenuEvent(mkey, fromcontroller);
}
//=============================================================================
//
//
//
//=============================================================================
bool MouseEvent(int type, int mx, int my)
{
int olditem = mDesc->mSelectedItem;
bool res = Super::MouseEvent(type, mx, my);
if (mDesc->mSelectedItem == -1 || mDesc->mSelectedItem == mStartItem+7)
{
int y = (-mDesc->mPosition + BigFont->GetHeight() + mDesc->mItems.Size() * OptionSettings.mLinespacing) * CleanYfac_1;
int h = (screen->GetHeight() - y) / 16;
int fh = OptionSettings.mLinespacing * CleanYfac_1;
int w = fh;
int yy = y + 2 * CleanYfac_1;
int indent = (screen->GetWidth() / 2);
if (h > fh) h = fh;
else if (h < 4) return res; // no space to draw it.
int box_y = y - 2 * CleanYfac_1;
int box_x = indent - 16*w;
if (mx >= box_x && mx < box_x + 16*w && my >= box_y && my < box_y + 16*h)
{
int cell_x = (mx - box_x) / w;
int cell_y = (my - box_y) / h;
if (olditem != mStartItem+7 || cell_x != mGridPosX || cell_y != mGridPosY)
{
mGridPosX = cell_x;
mGridPosY = cell_y;
//S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
}
mDesc->mSelectedItem = mStartItem+7;
if (type == MOUSE_Release)
{
MenuEvent(MKEY_Enter, true);
if (m_use_mouse == 2) mDesc->mSelectedItem = -1;
}
res = true;
}
}
return res;
}
//=============================================================================
//
//
//
//=============================================================================
void Drawer()
{
Super::Drawer();
if (mCVar == NULL) return;
int y = (-mDesc->mPosition + BigFont->GetHeight() + mDesc->mItems.Size() * OptionSettings.mLinespacing) * CleanYfac_1;
int h = (screen->GetHeight() - y) / 16;
int fh = OptionSettings.mLinespacing * CleanYfac_1;
int w = fh;
int yy = y;
if (h > fh) h = fh;
else if (h < 4) return; // no space to draw it.
int indent = (screen->GetWidth() / 2);
int p = 0;
for(int i = 0; i < 16; i++, y += h)
{
int box_x, box_y;
int x1;
box_y = y - 2 * CleanYfac_1;
box_x = indent - 16*w;
for (x1 = 0; x1 < 16; ++x1, p++)
{
screen->Clear (box_x, box_y, box_x + w, box_y + h, p, 0);
if ((mDesc->mSelectedItem == mStartItem+7) &&
(/*p == CurrColorIndex ||*/ (i == mGridPosY && x1 == mGridPosX)))
{
int r, g, b;
DWORD col;
double blinky;
if (i == mGridPosY && x1 == mGridPosX)
{
r = 255, g = 128, b = 0;
}
else
{
r = 200, g = 200, b = 255;
}
// Make sure the cursors stand out against similar colors
// by pulsing them.
blinky = fabs(sin(I_MSTime()/1000.0)) * 0.5 + 0.5;
col = MAKEARGB(255,int(r*blinky),int(g*blinky),int(b*blinky));
screen->Clear (box_x, box_y, box_x + w, box_y + 1, -1, col);
screen->Clear (box_x, box_y + h-1, box_x + w, box_y + h, -1, col);
screen->Clear (box_x, box_y, box_x + 1, box_y + h, -1, col);
screen->Clear (box_x + w - 1, box_y, box_x + w, box_y + h, -1, col);
}
box_x += w;
}
}
y = yy;
DWORD newColor = MAKEARGB(255, int(mRed), int(mGreen), int(mBlue));
DWORD oldColor = DWORD(*mCVar) | 0xFF000000;
int x = screen->GetWidth()*2/3;
screen->Clear (x, y, x + 48*CleanXfac_1, y + 48*CleanYfac_1, -1, oldColor);
screen->Clear (x + 48*CleanXfac_1, y, x + 48*2*CleanXfac_1, y + 48*CleanYfac_1, -1, newColor);
y += 49*CleanYfac_1;
screen->DrawText (SmallFont, CR_GRAY, x+(24-SmallFont->StringWidth("Old")/2)*CleanXfac_1, y,
"Old", DTA_CleanNoMove_1, true, TAG_DONE);
screen->DrawText (SmallFont, CR_WHITE, x+(48+24-SmallFont->StringWidth("New")/2)*CleanXfac_1, y,
"New", DTA_CleanNoMove_1, true, TAG_DONE);
}
};
IMPLEMENT_ABSTRACT_CLASS(DColorPickerMenu)
CCMD(undocolorpic)
{
if (DMenu::CurrentMenu != NULL && DMenu::CurrentMenu->IsKindOf(RUNTIME_CLASS(DColorPickerMenu)))
{
static_cast<DColorPickerMenu*>(DMenu::CurrentMenu)->Reset();
}
}
DMenu *StartPickerMenu(DMenu *parent, const char *name, FColorCVar *cvar)
{
FMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_Colorpickermenu);
if (desc != NULL && (*desc)->mType == MDESC_OptionsMenu)
{
return new DColorPickerMenu(parent, name, (FOptionMenuDescriptor*)(*desc), cvar);
}
else
{
return NULL;
}
}

420
src/menu/joystickmenu.cpp Normal file
View File

@ -0,0 +1,420 @@
/*
** joystickmenu.cpp
** The joystick configuration menus
**
**---------------------------------------------------------------------------
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include <float.h>
#include "menu/menu.h"
#include "c_dispatch.h"
#include "w_wad.h"
#include "sc_man.h"
#include "v_font.h"
#include "g_level.h"
#include "d_player.h"
#include "v_video.h"
#include "gi.h"
#include "i_system.h"
#include "c_bind.h"
#include "v_palette.h"
#include "d_event.h"
#include "d_gui.h"
#include "i_music.h"
#include "m_joy.h"
#define NO_IMP
#include "optionmenuitems.h"
static TArray<IJoystickConfig *> Joysticks;
IJoystickConfig *SELECTED_JOYSTICK;
FOptionMenuDescriptor *UpdateJoystickConfigMenu(IJoystickConfig *joy);
//=============================================================================
//
//
//
//=============================================================================
class FOptionMenuSliderJoySensitivity : public FOptionMenuSliderBase
{
public:
FOptionMenuSliderJoySensitivity(const char *label, double min, double max, double step, int showval)
: FOptionMenuSliderBase(label, min, max, step, showval)
{
}
double GetValue()
{
return SELECTED_JOYSTICK->GetSensitivity();
}
void SetValue(double val)
{
SELECTED_JOYSTICK->SetSensitivity(float(val));
}
};
//=============================================================================
//
//
//
//=============================================================================
class FOptionMenuSliderJoyScale : public FOptionMenuSliderBase
{
int mAxis;
int mNeg;
public:
FOptionMenuSliderJoyScale(const char *label, int axis, double min, double max, double step, int showval)
: FOptionMenuSliderBase(label, min, max, step, showval)
{
mAxis = axis;
mNeg = 1;
}
double GetValue()
{
double d = SELECTED_JOYSTICK->GetAxisScale(mAxis);
mNeg = d < 0? -1:1;
return d;
}
void SetValue(double val)
{
SELECTED_JOYSTICK->SetAxisScale(mAxis, float(val * mNeg));
}
};
//=============================================================================
//
//
//
//=============================================================================
class FOptionMenuSliderJoyDeadZone : public FOptionMenuSliderBase
{
int mAxis;
int mNeg;
public:
FOptionMenuSliderJoyDeadZone(const char *label, int axis, double min, double max, double step, int showval)
: FOptionMenuSliderBase(label, min, max, step, showval)
{
mAxis = axis;
mNeg = 1;
}
double GetValue()
{
double d = SELECTED_JOYSTICK->GetAxisDeadZone(mAxis);
mNeg = d < 0? -1:1;
return d;
}
void SetValue(double val)
{
SELECTED_JOYSTICK->SetAxisDeadZone(mAxis, float(val * mNeg));
}
};
//=============================================================================
//
//
//
//=============================================================================
class FOptionMenuItemJoyMap : public FOptionMenuItemOptionBase
{
int mAxis;
public:
FOptionMenuItemJoyMap(const char *label, int axis, const char *values, int center)
: FOptionMenuItemOptionBase(label, "none", values, NULL, center)
{
mAxis = axis;
}
int GetSelection()
{
float f = (float)(int)SELECTED_JOYSTICK->GetAxisMap(mAxis);
for(unsigned i=0;i<mValues->mValues.Size(); i++)
{
if (fabs(f - mValues->mValues[i].Value) < FLT_EPSILON)
{
return i;
}
}
return -1;
}
void SetSelection(int Selection)
{
SELECTED_JOYSTICK->SetAxisMap(mAxis, (EJoyAxis)Selection);
}
};
//=============================================================================
//
//
//
//=============================================================================
class FOptionMenuItemInverter : public FOptionMenuItemOptionBase
{
int mAxis;
public:
FOptionMenuItemInverter(const char *label, int axis, int center)
: FOptionMenuItemOptionBase(label, "none", "YesNo", NULL, center)
{
mAxis = axis;
}
int GetSelection()
{
float f = SELECTED_JOYSTICK->GetAxisScale(mAxis);
return f > 0? 0:1;
}
void SetSelection(int Selection)
{
float f = fabs(SELECTED_JOYSTICK->GetAxisScale(mAxis));
if (Selection) f*=-1;
SELECTED_JOYSTICK->SetAxisScale(mAxis, f);
}
};
class DJoystickConfigMenu : public DOptionMenu
{
DECLARE_CLASS(DJoystickConfigMenu, DOptionMenu)
};
IMPLEMENT_CLASS(DJoystickConfigMenu)
//=============================================================================
//
// Executes a CCMD, action is a CCMD name
//
//=============================================================================
class FOptionMenuItemJoyConfigMenu : public FOptionMenuItemSubmenu
{
IJoystickConfig *mJoy;
public:
FOptionMenuItemJoyConfigMenu(const char *label, IJoystickConfig *joy)
: FOptionMenuItemSubmenu(label, "JoystickConfigMenu")
{
mJoy = joy;
}
bool Activate()
{
UpdateJoystickConfigMenu(mJoy);
return FOptionMenuItemSubmenu::Activate();
}
};
/*=======================================
*
* Joystick Menu
*
*=======================================*/
FOptionMenuDescriptor *UpdateJoystickConfigMenu(IJoystickConfig *joy)
{
FMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_JoystickConfigMenu);
if (desc != NULL && (*desc)->mType == MDESC_OptionsMenu)
{
FOptionMenuDescriptor *opt = (FOptionMenuDescriptor *)*desc;
FOptionMenuItem *it;
for(unsigned i=0;i<opt->mItems.Size();i++)
{
delete opt->mItems[i];
opt->mItems.Clear();
}
opt->mTitle.Format("Configure %s", joy->GetName().GetChars());
if (joy == NULL)
{
it = new FOptionMenuItemStaticText("Invalid controller specified for menu", false);
opt->mItems.Push(it);
}
else
{
SELECTED_JOYSTICK = joy;
it = new FOptionMenuSliderJoySensitivity("Overall sensitivity", 0, 2, 0.1, 3);
opt->mItems.Push(it);
it = new FOptionMenuItemStaticText(" ", false);
opt->mItems.Push(it);
if (joy->GetNumAxes() > 0)
{
it = new FOptionMenuItemStaticText("Axis Configuration", true);
opt->mItems.Push(it);
for (int i = 0; i < joy->GetNumAxes(); ++i)
{
it = new FOptionMenuItemStaticText(" ", false);
opt->mItems.Push(it);
it = new FOptionMenuItemJoyMap(joy->GetAxisName(i), i, "JoyAxisMapNames", false);
opt->mItems.Push(it);
it = new FOptionMenuSliderJoyScale("Overall sensitivity", i, 0, 4, 0.1, 3);
opt->mItems.Push(it);
it = new FOptionMenuItemInverter("Invert", i, false);
opt->mItems.Push(it);
it = new FOptionMenuSliderJoyDeadZone("Dead Zone", i, 0, 0.9, 0.05, 3);
opt->mItems.Push(it);
}
}
else
{
it = new FOptionMenuItemStaticText("No configurable axes", false);
opt->mItems.Push(it);
}
}
opt->mScrollPos = 0;
opt->mSelectedItem = -1;
opt->mIndent = 0;
opt->mPosition = -25;
opt->CalcIndent();
return opt;
}
return NULL;
}
void UpdateJoystickMenu(IJoystickConfig *selected)
{
FMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_JoystickOptions);
if (desc != NULL && (*desc)->mType == MDESC_OptionsMenu)
{
FOptionMenuDescriptor *opt = (FOptionMenuDescriptor *)*desc;
FOptionMenuItem *it;
for(unsigned i=0;i<opt->mItems.Size();i++)
{
delete opt->mItems[i];
opt->mItems.Clear();
}
int i;
int itemnum = -1;
I_GetJoysticks(Joysticks);
if ((unsigned)itemnum >= Joysticks.Size())
{
itemnum = Joysticks.Size() - 1;
}
if (selected != NULL)
{
for (i = 0; (unsigned)i < Joysticks.Size(); ++i)
{
if (Joysticks[i] == selected)
{
itemnum = i;
break;
}
}
}
// Todo: Block joystick for changing this one.
it = new FOptionMenuItemOption("Enable controller support", "use_joystick", "YesNo", NULL, false);
opt->mItems.Push(it);
#ifdef _WIN32
it = new FOptionMenuItemOption("Enable DirectInput controllers", "joy_dinput", "YesNo", NULL, false);
opt->mItems.Push(it);
it = new FOptionMenuItemOption("Enable XInput controllers", "joy_xinput", "YesNo", NULL, false);
opt->mItems.Push(it);
it = new FOptionMenuItemOption("Enable raw PlayStation 2 adapters", "joy_ps2raw", "YesNo", NULL, false);
opt->mItems.Push(it);
#endif
it = new FOptionMenuItemStaticText(" ", false);
opt->mItems.Push(it);
if (Joysticks.Size() == 0)
{
it = new FOptionMenuItemStaticText("No controllers detected", false);
opt->mItems.Push(it);
if (!use_joystick)
{
it = new FOptionMenuItemStaticText("Controller support must be", false);
opt->mItems.Push(it);
it = new FOptionMenuItemStaticText("enabled to detect any", false);
opt->mItems.Push(it);
}
}
else
{
it = new FOptionMenuItemStaticText("Configure controllers:", false);
opt->mItems.Push(it);
for (int i = 0; i < (int)Joysticks.Size(); ++i)
{
it = new FOptionMenuItemJoyConfigMenu(Joysticks[i]->GetName(), Joysticks[i]);
opt->mItems.Push(it);
if (i == itemnum) opt->mSelectedItem = opt->mItems.Size();
}
}
if (opt->mSelectedItem >= (int)opt->mItems.Size())
{
opt->mSelectedItem = opt->mItems.Size() - 1;
}
opt->CalcIndent();
// If the joystick config menu is open, close it if the device it's
// open for is gone.
for (i = 0; (unsigned)i < Joysticks.Size(); ++i)
{
if (Joysticks[i] == SELECTED_JOYSTICK)
{
break;
}
}
if (i == (int)Joysticks.Size())
{
SELECTED_JOYSTICK = NULL;
if (DMenu::CurrentMenu != NULL && DMenu::CurrentMenu->IsKindOf(RUNTIME_CLASS(DJoystickConfigMenu)))
{
DMenu::CurrentMenu->Close();
}
}
}
}

511
src/menu/listmenu.cpp Normal file
View File

@ -0,0 +1,511 @@
/*
** listmenu.cpp
** A simple menu consisting of a list of items
**
**---------------------------------------------------------------------------
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "v_video.h"
#include "v_font.h"
#include "cmdlib.h"
#include "gstrings.h"
#include "g_level.h"
#include "gi.h"
#include "d_gui.h"
#include "d_event.h"
#include "menu/menu.h"
IMPLEMENT_CLASS(DListMenu)
//=============================================================================
//
//
//
//=============================================================================
DListMenu::DListMenu(DMenu *parent, FListMenuDescriptor *desc)
: DMenu(parent)
{
mDesc = desc;
mFocusControl = NULL;
}
//=============================================================================
//
//
//
//=============================================================================
void DListMenu::Init(DMenu *parent, FListMenuDescriptor *desc)
{
mParentMenu = parent;
GC::WriteBarrier(this, parent);
mDesc = desc;
}
//=============================================================================
//
//
//
//=============================================================================
FListMenuItem *DListMenu::GetItem(FName name)
{
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
{
FName nm = mDesc->mItems[i]->GetAction(NULL);
if (nm == name) return mDesc->mItems[i];
}
return NULL;
}
//=============================================================================
//
//
//
//=============================================================================
bool DListMenu::Responder (event_t *ev)
{
if (ev->type == EV_GUI_Event)
{
if (ev->subtype == EV_GUI_KeyDown)
{
int ch = tolower (ev->data1);
for(unsigned i = mDesc->mSelectedItem + 1; i < mDesc->mItems.Size(); i++)
{
if (mDesc->mItems[i]->CheckHotkey(ch))
{
mDesc->mSelectedItem = i;
S_Sound(CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
return true;
}
}
for(int i = 0; i < mDesc->mSelectedItem; i++)
{
if (mDesc->mItems[i]->CheckHotkey(ch))
{
mDesc->mSelectedItem = i;
S_Sound(CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
return true;
}
}
}
}
return Super::Responder(ev);
}
//=============================================================================
//
//
//
//=============================================================================
bool DListMenu::MenuEvent (int mkey, bool fromcontroller)
{
int startedAt = mDesc->mSelectedItem;
switch (mkey)
{
case MKEY_Up:
do
{
if (--mDesc->mSelectedItem < 0) mDesc->mSelectedItem = mDesc->mItems.Size()-1;
}
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt);
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
return true;
case MKEY_Down:
do
{
if (++mDesc->mSelectedItem >= (int)mDesc->mItems.Size()) mDesc->mSelectedItem = 0;
}
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt);
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
return true;
case MKEY_Enter:
if (mDesc->mSelectedItem >= 0 && mDesc->mItems[mDesc->mSelectedItem]->Activate())
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
}
return true;
default:
return Super::MenuEvent(mkey, fromcontroller);
}
}
//=============================================================================
//
//
//
//=============================================================================
bool DListMenu::MouseEvent(int type, int x, int y)
{
int sel = -1;
// convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture
x = ((x - (screen->GetWidth() / 2)) / CleanXfac) + 160;
y = ((y - (screen->GetHeight() / 2)) / CleanYfac) + 100;
if (mFocusControl != NULL)
{
mFocusControl->MouseEvent(type, x, y);
return true;
}
else
{
if ((mDesc->mWLeft <= 0 || x > mDesc->mWLeft) &&
(mDesc->mWRight <= 0 || x < mDesc->mWRight))
{
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
{
if (mDesc->mItems[i]->CheckCoordinate(x, y))
{
if (i != mDesc->mSelectedItem)
{
//S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
}
mDesc->mSelectedItem = i;
mDesc->mItems[i]->MouseEvent(type, x, y);
return true;
}
}
}
}
mDesc->mSelectedItem = -1;
return Super::MouseEvent(type, x, y);
}
//=============================================================================
//
//
//
//=============================================================================
void DListMenu::Ticker ()
{
Super::Ticker();
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
{
mDesc->mItems[i]->Ticker();
}
}
//=============================================================================
//
//
//
//=============================================================================
void DListMenu::Drawer ()
{
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
{
if (mDesc->mItems[i]->mEnabled) mDesc->mItems[i]->Drawer(mDesc->mSelectedItem == i);
}
if (mDesc->mSelectedItem >= 0 && mDesc->mSelectedItem < (int)mDesc->mItems.Size())
mDesc->mItems[mDesc->mSelectedItem]->DrawSelector(mDesc->mSelectOfsX, mDesc->mSelectOfsY, mDesc->mSelector);
Super::Drawer();
}
//=============================================================================
//
// base class for menu items
//
//=============================================================================
FListMenuItem::~FListMenuItem()
{
}
bool FListMenuItem::CheckCoordinate(int x, int y)
{
return false;
}
void FListMenuItem::Ticker()
{
}
void FListMenuItem::Drawer(bool selected)
{
}
bool FListMenuItem::Selectable()
{
return false;
}
void FListMenuItem::DrawSelector(int xofs, int yofs, FTextureID tex)
{
if (tex.isNull())
{
if ((DMenu::MenuTime%8) < 6)
{
screen->DrawText(ConFont, OptionSettings.mFontColorSelection,
mXpos + xofs, mYpos + yofs, "\xd", DTA_Clean, true, TAG_DONE);
}
}
else
{
screen->DrawTexture (TexMan(tex), mXpos + xofs, mYpos + yofs, DTA_Clean, true, TAG_DONE);
}
}
bool FListMenuItem::Activate()
{
return false; // cannot be activated
}
FName FListMenuItem::GetAction(int *pparam)
{
return mAction;
}
bool FListMenuItem::SetString(int i, const char *s)
{
return false;
}
bool FListMenuItem::GetString(int i, char *s, int len)
{
return false;
}
bool FListMenuItem::SetValue(int i, int value)
{
return false;
}
bool FListMenuItem::GetValue(int i, int *pvalue)
{
return false;
}
void FListMenuItem::Enable(bool on)
{
mEnabled = on;
}
bool FListMenuItem::MenuEvent(int mkey, bool fromcontroller)
{
return false;
}
bool FListMenuItem::MouseEvent(int type, int x, int y)
{
return false;
}
bool FListMenuItem::CheckHotkey(int c)
{
return false;
}
//=============================================================================
//
// static patch
//
//=============================================================================
FListMenuItemStaticPatch::FListMenuItemStaticPatch(int x, int y, FTextureID patch, bool centered)
: FListMenuItem(x, y)
{
mTexture = patch;
mCentered = centered;
}
void FListMenuItemStaticPatch::Drawer(bool selected)
{
int x = mXpos;
FTexture *tex = TexMan(mTexture);
if (mYpos >= 0)
{
if (mCentered) x -= tex->GetScaledWidth()/2;
screen->DrawTexture (tex, x, mYpos, DTA_Clean, true, TAG_DONE);
}
else
{
int x = (mXpos - 160) * CleanXfac + (SCREENWIDTH>>1);
if (mCentered) x -= (tex->GetScaledWidth()*CleanXfac)/2;
screen->DrawTexture (tex, x, -mYpos*CleanYfac, DTA_CleanNoMove, true, TAG_DONE);
}
}
//=============================================================================
//
// static text
//
//=============================================================================
FListMenuItemStaticText::FListMenuItemStaticText(int x, int y, const char *text, FFont *font, EColorRange color, bool centered)
: FListMenuItem(x, y)
{
mText = ncopystring(text);
mFont = font;
mColor = color;
mCentered = centered;
}
void FListMenuItemStaticText::Drawer(bool selected)
{
const char *text = mText;
if (text != NULL)
{
if (*text == '$') text = GStrings(text+1);
if (mYpos >= 0)
{
int x = mXpos;
if (mCentered) x -= mFont->StringWidth(text)/2;
screen->DrawText(mFont, mColor, x, mYpos, text, DTA_Clean, true, TAG_DONE);
}
else
{
int x = (mXpos - 160) * CleanXfac + (SCREENWIDTH>>1);
if (mCentered) x -= (mFont->StringWidth(text)*CleanXfac)/2;
screen->DrawText (mFont, mColor, x, -mYpos*CleanYfac, text, DTA_CleanNoMove, true, TAG_DONE);
}
}
}
FListMenuItemStaticText::~FListMenuItemStaticText()
{
if (mText != NULL) delete [] mText;
}
//=============================================================================
//
// base class for selectable items
//
//=============================================================================
FListMenuItemSelectable::FListMenuItemSelectable(int x, int y, int height, FName action, int param)
: FListMenuItem(x, y, action)
{
mHeight = height;
mParam = param;
mHotkey = 0;
}
bool FListMenuItemSelectable::CheckCoordinate(int x, int y)
{
return mEnabled && y >= mYpos && y < mYpos + mHeight; // no x check here
}
bool FListMenuItemSelectable::Selectable()
{
return mEnabled;
}
bool FListMenuItemSelectable::Activate()
{
M_SetMenu(mAction, mParam);
return true;
}
FName FListMenuItemSelectable::GetAction(int *pparam)
{
if (pparam != NULL) *pparam = mParam;
return mAction;
}
bool FListMenuItemSelectable::CheckHotkey(int c)
{
return c == tolower(mHotkey);
}
bool FListMenuItemSelectable::MouseEvent(int type, int x, int y)
{
if (type == DMenu::MOUSE_Release)
{
if (DMenu::CurrentMenu->MenuEvent(MKEY_Enter, true))
{
return true;
}
}
return false;
}
//=============================================================================
//
// text item
//
//=============================================================================
FListMenuItemText::FListMenuItemText(int x, int y, int height, int hotkey, const char *text, FFont *font, EColorRange color, FName child, int param)
: FListMenuItemSelectable(x, y, height, child, param)
{
mText = ncopystring(text);
mFont = font;
mColor = color;
mHotkey = hotkey;
}
FListMenuItemText::~FListMenuItemText()
{
if (mText != NULL)
{
delete [] mText;
}
}
void FListMenuItemText::Drawer(bool selected)
{
const char *text = mText;
if (text != NULL)
{
if (*text == '$') text = GStrings(text+1);
screen->DrawText(mFont, mColor, mXpos, mYpos, text, DTA_Clean, true, TAG_DONE);
}
}
//=============================================================================
//
// patch item
//
//=============================================================================
FListMenuItemPatch::FListMenuItemPatch(int x, int y, int height, int hotkey, FTextureID patch, FName child, int param)
: FListMenuItemSelectable(x, y, height, child, param)
{
mHotkey = hotkey;
mTexture = patch;
}
void FListMenuItemPatch::Drawer(bool selected)
{
screen->DrawTexture (TexMan(mTexture), mXpos, mYpos, DTA_Clean, true, TAG_DONE);
}

1165
src/menu/loadsavemenu.cpp Normal file

File diff suppressed because it is too large Load Diff

949
src/menu/menu.cpp Normal file
View File

@ -0,0 +1,949 @@
/*
** menu.cpp
** Menu base class and global interface
**
**---------------------------------------------------------------------------
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "doomdef.h"
#include "doomstat.h"
#include "c_dispatch.h"
#include "d_gui.h"
#include "d_player.h"
#include "g_level.h"
#include "c_console.h"
#include "c_bind.h"
#include "s_sound.h"
#include "p_tick.h"
#include "g_game.h"
#include "c_cvars.h"
#include "d_event.h"
#include "v_video.h"
#include "hu_stuff.h"
#include "gi.h"
#include "i_input.h"
#include "gameconfigfile.h"
#include "gstrings.h"
#include "r_main.h"
#include "menu/menu.h"
#include "textures/textures.h"
//
// Todo: Move these elsewhere
//
CVAR (Float, mouse_sensitivity, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, show_messages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, show_obituaries, true, CVAR_ARCHIVE)
CVAR (Float, snd_menuvolume, 0.6f, CVAR_ARCHIVE)
CVAR(Int, m_use_mouse, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR(Int, m_show_backbutton, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
DMenu *DMenu::CurrentMenu;
int DMenu::MenuTime;
FListMenuDescriptor *MainMenu;
FGameStartup GameStartupInfo;
EMenuState menuactive;
bool M_DemoNoPlay;
FButtonStatus MenuButtons[NUM_MKEYS];
int MenuButtonTickers[NUM_MKEYS];
bool MenuButtonOrigin[NUM_MKEYS];
int BackbuttonTime;
fixed_t BackbuttonAlpha;
#define KEY_REPEAT_DELAY (TICRATE*5/12)
#define KEY_REPEAT_RATE (3)
//============================================================================
//
// DMenu base class
//
//============================================================================
IMPLEMENT_POINTY_CLASS (DMenu)
DECLARE_POINTER(mParentMenu)
END_POINTERS
DMenu::DMenu(DMenu *parent)
{
mParentMenu = parent;
mMouseCapture = false;
mBackbuttonSelected = false;
GC::WriteBarrier(this, parent);
}
bool DMenu::Responder (event_t *ev)
{
if (ev->type == EV_GUI_Event)
{
if (ev->subtype == EV_GUI_LButtonDown)
{
MouseEventBack(MOUSE_Click, ev->data1, ev->data2);
if (MouseEvent(MOUSE_Click, ev->data1, ev->data2))
{
SetCapture();
}
}
else if (ev->subtype == EV_GUI_MouseMove)
{
BackbuttonTime = BACKBUTTON_TIME;
if (mMouseCapture || m_use_mouse == 1)
{
MouseEventBack(MOUSE_Move, ev->data1, ev->data2);
return MouseEvent(MOUSE_Move, ev->data1, ev->data2);
}
}
else if (ev->subtype == EV_GUI_LButtonUp)
{
if (mMouseCapture)
{
ReleaseCapture();
MouseEventBack(MOUSE_Release, ev->data1, ev->data2);
return MouseEvent(MOUSE_Release, ev->data1, ev->data2);
}
}
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
bool DMenu::MenuEvent (int mkey, bool fromcontroller)
{
switch (mkey)
{
case MKEY_Back:
{
Close();
S_Sound (CHAN_VOICE | CHAN_UI,
DMenu::CurrentMenu != NULL? "menu/backup" : "menu/clear", snd_menuvolume, ATTN_NONE);
return true;
}
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
void DMenu::Close ()
{
assert(DMenu::CurrentMenu == this);
DMenu::CurrentMenu = mParentMenu;
Destroy();
if (DMenu::CurrentMenu != NULL)
{
GC::WriteBarrier(DMenu::CurrentMenu);
}
else
{
M_ClearMenus ();
}
}
//=============================================================================
//
//
//
//=============================================================================
bool DMenu::MouseEvent(int type, int x, int y)
{
return true;
}
//=============================================================================
//
//
//
//=============================================================================
bool DMenu::MouseEventBack(int type, int x, int y)
{
if (m_show_backbutton >= 0)
{
FTexture *tex = TexMan[gameinfo.mBackButton];
if (tex != NULL)
{
if (m_show_backbutton&1) x -= screen->GetWidth() - tex->GetScaledWidth() * CleanXfac;
if (m_show_backbutton&2) y -= screen->GetHeight() - tex->GetScaledHeight() * CleanYfac;
mBackbuttonSelected = (x >= 0 && x < tex->GetScaledWidth() * CleanXfac && y < tex->GetScaledHeight() * CleanYfac);
if (mBackbuttonSelected && type == MOUSE_Release)
{
if (m_use_mouse == 2) mBackbuttonSelected = false;
MenuEvent(MKEY_Back, true);
}
return true;
}
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
void DMenu::SetCapture()
{
if (!mMouseCapture)
{
mMouseCapture = true;
I_SetMouseCapture();
}
}
void DMenu::ReleaseCapture()
{
if (mMouseCapture)
{
mMouseCapture = false;
I_ReleaseMouseCapture();
}
}
//=============================================================================
//
//
//
//=============================================================================
void DMenu::Ticker ()
{
}
void DMenu::Drawer ()
{
if (this == DMenu::CurrentMenu && BackbuttonAlpha > 0 && m_show_backbutton >= 0 && m_use_mouse)
{
FTexture *tex = TexMan[gameinfo.mBackButton];
int w = tex->GetScaledWidth() * CleanXfac;
int h = tex->GetScaledHeight() * CleanYfac;
int x = (!(m_show_backbutton&1))? 0:screen->GetWidth() - w;
int y = (!(m_show_backbutton&2))? 0:screen->GetHeight() - h;
if (mBackbuttonSelected && (mMouseCapture || m_use_mouse == 1))
{
screen->DrawTexture(tex, x, y, DTA_CleanNoMove, true, DTA_ColorOverlay, MAKEARGB(40, 255,255,255), TAG_DONE);
}
else
{
screen->DrawTexture(tex, x, y, DTA_CleanNoMove, true, DTA_Alpha, BackbuttonAlpha, TAG_DONE);
}
}
}
bool DMenu::DimAllowed()
{
return true;
}
bool DMenu::TranslateKeyboardEvents()
{
return true;
}
//=============================================================================
//
//
//
//=============================================================================
void M_StartControlPanel (bool makeSound)
{
// intro might call this repeatedly
if (DMenu::CurrentMenu != NULL)
return;
ResetButtonStates ();
for (int i = 0; i < NUM_MKEYS; ++i)
{
MenuButtons[i].ReleaseKey(0);
}
C_HideConsole (); // [RH] Make sure console goes bye bye.
menuactive = MENU_On;
// Pause sound effects before we play the menu switch sound.
// That way, it won't be paused.
P_CheckTickerPaused ();
if (makeSound)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE);
}
BackbuttonTime = 0;
BackbuttonAlpha = 0;
}
//=============================================================================
//
//
//
//=============================================================================
void M_ActivateMenu(DMenu *menu)
{
if (menuactive == MENU_Off) menuactive = MENU_On;
if (DMenu::CurrentMenu != NULL) DMenu::CurrentMenu->ReleaseCapture();
DMenu::CurrentMenu = menu;
GC::WriteBarrier(DMenu::CurrentMenu);
}
//=============================================================================
//
//
//
//=============================================================================
void M_SetMenu(FName menu, int param)
{
// some menus need some special treatment
switch (menu)
{
case NAME_Episodemenu:
// sent from the player class menu
GameStartupInfo.Skill = -1;
GameStartupInfo.Episode = -1;
GameStartupInfo.PlayerClass =
param == -1? "Random" : PlayerClasses[param].Type->Meta.GetMetaString (APMETA_DisplayName);
break;
case NAME_Skillmenu:
// sent from the episode menu
if ((gameinfo.flags & GI_SHAREWARE) && param > 0)
{
// Only Doom and Heretic have multi-episode shareware versions.
if (gameinfo.gametype == GAME_Doom)
{
M_StartMessage(GStrings("SWSTRING"), 1);
}
else
{
M_StartMessage(GStrings("MNU_ONLYREGISTERED"), 1);
}
return;
}
GameStartupInfo.Episode = param;
M_StartupSkillMenu(&GameStartupInfo); // needs player class name from class menu (later)
break;
case NAME_StartgameConfirm:
{
// sent from the skill menu for a skill that needs to be confirmed
GameStartupInfo.Skill = param;
const char *msg = AllSkills[param].MustConfirmText;
if (*msg==0) msg = GStrings("NIGHTMARE");
M_StartMessage (msg, 0, NAME_Startgame);
return;
}
case NAME_Startgame:
// sent either from skill menu or confirmation screen. Skill gets only set if sent from skill menu
// Now we can finally start the game. Ugh...
if (GameStartupInfo.Skill == -1) GameStartupInfo.Skill = param;
G_DeferedInitNew (&GameStartupInfo);
if (gamestate == GS_FULLCONSOLE)
{
gamestate = GS_HIDECONSOLE;
gameaction = ga_newgame;
}
M_ClearMenus ();
return;
case NAME_Savegamemenu:
if (!usergame || (players[consoleplayer].health <= 0 && !multiplayer))
{
// cannot save outside the game.
M_StartMessage (GStrings("SAVEDEAD"), 1);
return;
}
}
// End of special checks
FMenuDescriptor **desc = MenuDescriptors.CheckKey(menu);
if (desc != NULL)
{
if ((*desc)->mNetgameMessage.IsNotEmpty() && netgame)
{
M_StartMessage((*desc)->mNetgameMessage, 1);
return;
}
if ((*desc)->mType == MDESC_ListMenu)
{
FListMenuDescriptor *ld = static_cast<FListMenuDescriptor*>(*desc);
if (ld->mAutoselect >= 0 && ld->mAutoselect < (int)ld->mItems.Size())
{
// recursively activate the autoselected item without ever creating this menu.
ld->mItems[ld->mAutoselect]->Activate();
}
else
{
const PClass *cls = ld->mClass == NULL? RUNTIME_CLASS(DListMenu) : ld->mClass;
DListMenu *newmenu = (DListMenu *)cls->CreateNew();
newmenu->Init(DMenu::CurrentMenu, ld);
M_ActivateMenu(newmenu);
}
}
else if ((*desc)->mType == MDESC_OptionsMenu)
{
FOptionMenuDescriptor *ld = static_cast<FOptionMenuDescriptor*>(*desc);
const PClass *cls = ld->mClass == NULL? RUNTIME_CLASS(DOptionMenu) : ld->mClass;
DOptionMenu *newmenu = (DOptionMenu *)cls->CreateNew();
newmenu->Init(DMenu::CurrentMenu, ld);
M_ActivateMenu(newmenu);
}
return;
}
else
{
const PClass *menuclass = PClass::FindClass(menu);
if (menuclass != NULL)
{
if (menuclass->IsDescendantOf(RUNTIME_CLASS(DMenu)))
{
DMenu *newmenu = (DMenu*)menuclass->CreateNew();
newmenu->mParentMenu = DMenu::CurrentMenu;
M_ActivateMenu(newmenu);
return;
}
}
}
Printf("Attempting to open menu of unknown type '%s'\n", menu.GetChars());
}
//=============================================================================
//
//
//
//=============================================================================
bool M_Responder (event_t *ev)
{
int ch = 0;
bool keyup = false;
int mkey = NUM_MKEYS;
bool fromcontroller = true;
if (chatmodeon)
{
return false;
}
if (DMenu::CurrentMenu != NULL && menuactive != MENU_Off)
{
// There are a few input sources we are interested in:
//
// EV_KeyDown / EV_KeyUp : joysticks/gamepads/controllers
// EV_GUI_KeyDown / EV_GUI_KeyUp : the keyboard
// EV_GUI_Char : printable characters, which we want in string input mode
//
// This code previously listened for EV_GUI_KeyRepeat to handle repeating
// in the menus, but that doesn't work with gamepads, so now we combine
// the multiple inputs into buttons and handle the repetition manually.
if (ev->type == EV_GUI_Event)
{
fromcontroller = false;
if (ev->subtype == EV_GUI_KeyRepeat)
{
// We do our own key repeat handling but still want to eat the
// OS's repeated keys.
return true;
}
else if (ev->subtype == EV_GUI_BackButtonDown || ev->subtype == EV_GUI_BackButtonUp)
{
mkey = MKEY_Back;
keyup = ev->subtype == EV_GUI_BackButtonUp;
}
else if (ev->subtype != EV_GUI_KeyDown && ev->subtype != EV_GUI_KeyUp)
{
// do we want mouse input?
if (ev->subtype >= EV_GUI_FirstMouseEvent && ev->subtype <= EV_GUI_LastMouseEvent)
{
// FIXME: Mouse events in SDL code are mostly useless so mouse is
// disabled until that code is fixed
#ifdef _WIN32
if (!m_use_mouse)
#endif
return true;
}
// pass everything else on to the current menu
return DMenu::CurrentMenu->Responder(ev);
}
else if (DMenu::CurrentMenu->TranslateKeyboardEvents())
{
ch = ev->data1;
keyup = ev->subtype == EV_GUI_KeyUp;
switch (ch)
{
case GK_BACK: mkey = MKEY_Back; break;
case GK_ESCAPE: mkey = MKEY_Back; break;
case GK_RETURN: mkey = MKEY_Enter; break;
case GK_UP: mkey = MKEY_Up; break;
case GK_DOWN: mkey = MKEY_Down; break;
case GK_LEFT: mkey = MKEY_Left; break;
case GK_RIGHT: mkey = MKEY_Right; break;
case GK_BACKSPACE: mkey = MKEY_Clear; break;
case GK_PGUP: mkey = MKEY_PageUp; break;
case GK_PGDN: mkey = MKEY_PageDown; break;
default:
if (!keyup)
{
return DMenu::CurrentMenu->Responder(ev);
}
break;
}
}
}
else if (ev->type == EV_KeyDown || ev->type == EV_KeyUp)
{
keyup = ev->type == EV_KeyUp;
ch = ev->data1;
switch (ch)
{
case KEY_JOY1:
case KEY_PAD_A:
mkey = MKEY_Enter;
break;
case KEY_JOY2:
case KEY_PAD_B:
mkey = MKEY_Back;
break;
case KEY_JOY3:
case KEY_PAD_X:
mkey = MKEY_Clear;
break;
case KEY_JOY5:
case KEY_PAD_LSHOULDER:
mkey = MKEY_PageUp;
break;
case KEY_JOY6:
case KEY_PAD_RSHOULDER:
mkey = MKEY_PageDown;
break;
case KEY_PAD_DPAD_UP:
case KEY_PAD_LTHUMB_UP:
case KEY_JOYAXIS1MINUS:
case KEY_JOYPOV1_UP:
mkey = MKEY_Up;
break;
case KEY_PAD_DPAD_DOWN:
case KEY_PAD_LTHUMB_DOWN:
case KEY_JOYAXIS1PLUS:
case KEY_JOYPOV1_DOWN:
mkey = MKEY_Down;
break;
case KEY_PAD_DPAD_LEFT:
case KEY_PAD_LTHUMB_LEFT:
case KEY_JOYAXIS2MINUS:
case KEY_JOYPOV1_LEFT:
mkey = MKEY_Left;
break;
case KEY_PAD_DPAD_RIGHT:
case KEY_PAD_LTHUMB_RIGHT:
case KEY_JOYAXIS2PLUS:
case KEY_JOYPOV1_RIGHT:
mkey = MKEY_Right;
break;
}
}
if (mkey != NUM_MKEYS)
{
if (keyup)
{
MenuButtons[mkey].ReleaseKey(ch);
return false;
}
else
{
MenuButtons[mkey].PressKey(ch);
MenuButtonOrigin[mkey] = fromcontroller;
if (mkey <= MKEY_PageDown)
{
MenuButtonTickers[mkey] = KEY_REPEAT_DELAY;
}
DMenu::CurrentMenu->MenuEvent(mkey, fromcontroller);
return true;
}
}
return DMenu::CurrentMenu->Responder(ev) || !keyup;
}
else
{
if (ev->type == EV_KeyDown)
{
// Pop-up menu?
if (ev->data1 == KEY_ESCAPE)
{
M_StartControlPanel(true);
M_SetMenu(NAME_Mainmenu, -1);
return true;
}
// If devparm is set, pressing F1 always takes a screenshot no matter
// what it's bound to. (for those who don't bother to read the docs)
if (devparm && ev->data1 == KEY_F1)
{
G_ScreenShot(NULL);
return true;
}
return false;
}
else if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_LButtonDown &&
ConsoleState != c_down && m_use_mouse)
{
M_StartControlPanel(true);
M_SetMenu(NAME_Mainmenu, -1);
return true;
}
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
void M_Ticker (void)
{
DMenu::MenuTime++;
if (DMenu::CurrentMenu != NULL && menuactive != MENU_Off)
DMenu::CurrentMenu->Ticker();
for (int i = 0; i < NUM_MKEYS; ++i)
{
if (MenuButtons[i].bDown)
{
if (MenuButtonTickers[i] > 0 && --MenuButtonTickers[i] <= 0)
{
MenuButtonTickers[i] = KEY_REPEAT_RATE;
DMenu::CurrentMenu->MenuEvent(i, MenuButtonOrigin[i]);
}
}
}
if (BackbuttonTime > 0)
{
if (BackbuttonAlpha < FRACUNIT) BackbuttonAlpha += FRACUNIT/10;
BackbuttonTime--;
}
else
{
if (BackbuttonAlpha > 0) BackbuttonAlpha -= FRACUNIT/10;
if (BackbuttonAlpha < 0) BackbuttonAlpha = 0;
}
}
//=============================================================================
//
//
//
//=============================================================================
void M_Drawer (void)
{
player_t *player = &players[consoleplayer];
AActor *camera = player->camera;
PalEntry fade = 0;
if (!screen->Accel2D && camera != NULL && (gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL))
{
if (camera->player != NULL)
{
player = camera->player;
}
fade = PalEntry (BYTE(player->BlendA*255), BYTE(player->BlendR*255), BYTE(player->BlendG*255), BYTE(player->BlendB*255));
}
if (DMenu::CurrentMenu != NULL && menuactive != MENU_Off)
{
if (DMenu::CurrentMenu->DimAllowed()) screen->Dim(fade);
DMenu::CurrentMenu->Drawer();
}
}
//=============================================================================
//
//
//
//=============================================================================
void M_ClearMenus ()
{
M_DemoNoPlay = false;
if (DMenu::CurrentMenu != NULL)
{
DMenu::CurrentMenu->Destroy();
DMenu::CurrentMenu = NULL;
}
BorderNeedRefresh = screen->GetPageCount ();
menuactive = MENU_Off;
}
//=============================================================================
//
//
//
//=============================================================================
void M_Init (void)
{
M_ParseMenuDefs();
M_CreateMenus();
}
//=============================================================================
//
// [RH] Most menus can now be accessed directly
// through console commands.
//
//=============================================================================
CCMD (menu_main)
{
M_StartControlPanel(true);
M_SetMenu(NAME_Mainmenu, -1);
}
CCMD (menu_load)
{ // F3
M_StartControlPanel (true);
M_SetMenu(NAME_Loadgamemenu, -1);
}
CCMD (menu_save)
{ // F2
M_StartControlPanel (true);
M_SetMenu(NAME_Savegamemenu, -1);
}
CCMD (menu_help)
{ // F1
M_StartControlPanel (true);
M_SetMenu(NAME_Readthismenu, -1);
}
CCMD (menu_game)
{
M_StartControlPanel (true);
M_SetMenu(NAME_Playerclassmenu, -1); // The playerclass menu is the first in the 'start game' chain
}
CCMD (menu_options)
{
M_StartControlPanel (true);
M_SetMenu(NAME_Optionsmenu, -1);
}
CCMD (menu_player)
{
M_StartControlPanel (true);
M_SetMenu(NAME_Playermenu, -1);
}
CCMD (menu_messages)
{
M_StartControlPanel (true);
M_SetMenu(NAME_MessageOptions, -1);
}
CCMD (menu_automap)
{
M_StartControlPanel (true);
M_SetMenu(NAME_AutomapOptions, -1);
}
CCMD (menu_scoreboard)
{
M_StartControlPanel (true);
M_SetMenu(NAME_ScoreboardOptions, -1);
}
CCMD (menu_mapcolors)
{
M_StartControlPanel (true);
M_SetMenu(NAME_MapColorMenu, -1);
}
CCMD (menu_keys)
{
M_StartControlPanel (true);
M_SetMenu(NAME_CustomizeControls, -1);
}
CCMD (menu_gameplay)
{
M_StartControlPanel (true);
M_SetMenu(NAME_GameplayOptions, -1);
}
CCMD (menu_compatibility)
{
M_StartControlPanel (true);
M_SetMenu(NAME_CompatibilityOptions, -1);
}
CCMD (menu_mouse)
{
M_StartControlPanel (true);
M_SetMenu(NAME_MouseOptions, -1);
}
CCMD (menu_joystick)
{
M_StartControlPanel (true);
M_SetMenu(NAME_JoystickOptions, -1);
}
CCMD (menu_sound)
{
M_StartControlPanel (true);
M_SetMenu(NAME_SoundOptions, -1);
}
CCMD (menu_advsound)
{
M_StartControlPanel (true);
M_SetMenu(NAME_AdvSoundOptions, -1);
}
CCMD (menu_modreplayer)
{
M_StartControlPanel(true);
M_SetMenu(NAME_ModReplayerOptions, -1);
}
CCMD (menu_display)
{
M_StartControlPanel (true);
M_SetMenu(NAME_VideoOptions, -1);
}
CCMD (menu_video)
{
M_StartControlPanel (true);
M_SetMenu(NAME_VideoModeMenu, -1);
}
CCMD (openmenu)
{
if (argv.argc() < 2)
{
Printf("Usage: openmenu \"menu_name\"");
return;
}
M_StartControlPanel (true);
M_SetMenu(argv[1], -1);
}
//
// Toggle messages on/off
//
CCMD (togglemessages)
{
if (show_messages)
{
Printf (128, "%s\n", GStrings("MSGOFF"));
show_messages = false;
}
else
{
Printf (128, "%s\n", GStrings("MSGON"));
show_messages = true;
}
}
EXTERN_CVAR (Int, screenblocks)
CCMD (sizedown)
{
screenblocks = screenblocks - 1;
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
}
CCMD (sizeup)
{
screenblocks = screenblocks + 1;
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
}
CCMD(menuconsole)
{
M_ClearMenus();
C_ToggleConsole();
}
CCMD(reset2defaults)
{
C_SetDefaultBindings ();
C_SetCVarsToDefaults ();
R_SetViewSize (screenblocks);
}
CCMD(reset2saved)
{
GameConfig->DoGlobalSetup ();
GameConfig->DoGameSetup (GameNames[gameinfo.gametype]);
R_SetViewSize (screenblocks);
}

652
src/menu/menu.h Normal file
View File

@ -0,0 +1,652 @@
#ifndef __M_MENU_MENU_H__
#define __M_MENU_MENU_H__
#include "dobject.h"
#include "lists.h"
#include "d_player.h"
#include "r_translate.h"
#include "c_cvars.h"
#include "v_font.h"
#include "version.h"
#include "textures/textures.h"
EXTERN_CVAR(Float, snd_menuvolume)
EXTERN_CVAR(Int, m_use_mouse);
struct event_t;
class FTexture;
class FFont;
enum EColorRange;
class FPlayerClass;
class FKeyBindings;
enum EMenuKey
{
MKEY_Up,
MKEY_Down,
MKEY_Left,
MKEY_Right,
MKEY_PageUp,
MKEY_PageDown,
//----------------- Keys past here do not repeat.
MKEY_Enter,
MKEY_Back, // Back to previous menu
MKEY_Clear, // Clear keybinding/flip player sprite preview
NUM_MKEYS,
// These are not buttons but events sent from other menus
MKEY_Input, // Sent when input is confirmed
MKEY_Abort, // Input aborted
MKEY_MBYes,
MKEY_MBNo,
};
struct FGameStartup
{
const char *PlayerClass;
int Episode;
int Skill;
};
extern FGameStartup GameStartupInfo;
struct FSaveGameNode : public Node
{
char Title[SAVESTRINGSIZE];
FString Filename;
bool bOldVersion;
bool bMissingWads;
bool bNoDelete;
FSaveGameNode() { bNoDelete = false; }
};
//=============================================================================
//
// menu descriptor. This is created from the menu definition lump
// Items must be inserted in the order they are cycled through with the cursor
//
//=============================================================================
enum EMenuDescriptorType
{
MDESC_ListMenu,
MDESC_OptionsMenu,
};
struct FMenuDescriptor
{
FName mMenuName;
FString mNetgameMessage;
int mType;
virtual ~FMenuDescriptor() {}
};
class FListMenuItem;
class FOptionMenuItem;
struct FListMenuDescriptor : public FMenuDescriptor
{
TDeletingArray<FListMenuItem *> mItems;
int mSelectedItem;
int mSelectOfsX;
int mSelectOfsY;
FTextureID mSelector;
int mDisplayTop;
int mXpos, mYpos;
int mWLeft, mWRight;
int mLinespacing; // needs to be stored for dynamically created menus
int mAutoselect; // this can only be set by internal menu creation functions
FFont *mFont;
EColorRange mFontColor;
EColorRange mFontColor2;
const PClass *mClass;
FMenuDescriptor *mRedirect; // used to redirect overlong skill and episode menus to option menu based alternatives
};
struct FOptionMenuSettings
{
EColorRange mTitleColor;
EColorRange mFontColor;
EColorRange mFontColorValue;
EColorRange mFontColorMore;
EColorRange mFontColorHeader;
EColorRange mFontColorHighlight;
EColorRange mFontColorSelection;
int mLinespacing;
int mLabelOffset;
};
struct FOptionMenuDescriptor : public FMenuDescriptor
{
TDeletingArray<FOptionMenuItem *> mItems;
FString mTitle;
int mSelectedItem;
int mDrawTop;
int mScrollTop;
int mScrollPos;
int mIndent;
int mPosition;
bool mDontDim;
const PClass *mClass;
void CalcIndent();
FOptionMenuItem *GetItem(FName name);
};
typedef TMap<FName, FMenuDescriptor *> MenuDescriptorList;
extern FOptionMenuSettings OptionSettings;
extern MenuDescriptorList MenuDescriptors;
#define CURSORSPACE (14 * CleanXfac_1)
//=============================================================================
//
//
//
//=============================================================================
struct FMenuRect
{
int x, y;
int width, height;
void set(int _x, int _y, int _w, int _h)
{
x = _x;
y = _y;
width = _w;
height = _h;
}
bool inside(int _x, int _y)
{
return _x >= x && _x < x+width && _y >= y && _y < y+height;
}
};
class DMenu : public DObject
{
DECLARE_CLASS (DMenu, DObject)
HAS_OBJECT_POINTERS
protected:
bool mMouseCapture;
bool mBackbuttonSelected;
public:
enum
{
MOUSE_Click,
MOUSE_Move,
MOUSE_Release
};
enum
{
BACKBUTTON_TIME = 4*TICRATE
};
static DMenu *CurrentMenu;
static int MenuTime;
TObjPtr<DMenu> mParentMenu;
DMenu(DMenu *parent = NULL);
virtual bool Responder (event_t *ev);
virtual bool MenuEvent (int mkey, bool fromcontroller);
virtual void Ticker ();
virtual void Drawer ();
virtual bool DimAllowed ();
virtual bool TranslateKeyboardEvents();
virtual void Close();
virtual bool MouseEvent(int type, int x, int y);
bool MouseEventBack(int type, int x, int y);
void SetCapture();
void ReleaseCapture();
bool HasCapture()
{
return mMouseCapture;
}
};
//=============================================================================
//
// base class for menu items
//
//=============================================================================
class FListMenuItem
{
protected:
int mXpos, mYpos;
FName mAction;
public:
bool mEnabled;
FListMenuItem(int xpos = 0, int ypos = 0, FName action = NAME_None)
{
mXpos = xpos;
mYpos = ypos;
mAction = action;
mEnabled = true;
}
virtual ~FListMenuItem();
virtual bool CheckCoordinate(int x, int y);
virtual void Ticker();
virtual void Drawer(bool selected);
virtual bool Selectable();
virtual bool Activate();
virtual FName GetAction(int *pparam);
virtual bool SetString(int i, const char *s);
virtual bool GetString(int i, char *s, int len);
virtual bool SetValue(int i, int value);
virtual bool GetValue(int i, int *pvalue);
virtual void Enable(bool on);
virtual bool MenuEvent (int mkey, bool fromcontroller);
virtual bool MouseEvent(int type, int x, int y);
virtual bool CheckHotkey(int c);
void DrawSelector(int xofs, int yofs, FTextureID tex);
void OffsetPositionY(int ydelta) { mYpos += ydelta; }
int GetY() { return mYpos; }
};
class FListMenuItemStaticPatch : public FListMenuItem
{
protected:
FTextureID mTexture;
bool mCentered;
public:
FListMenuItemStaticPatch(int x, int y, FTextureID patch, bool centered);
void Drawer(bool selected);
};
class FListMenuItemStaticText : public FListMenuItem
{
protected:
const char *mText;
FFont *mFont;
EColorRange mColor;
bool mCentered;
public:
FListMenuItemStaticText(int x, int y, const char *text, FFont *font, EColorRange color, bool centered);
~FListMenuItemStaticText();
void Drawer(bool selected);
};
//=============================================================================
//
// the player sprite window
//
//=============================================================================
class FListMenuItemPlayerDisplay : public FListMenuItem
{
FListMenuDescriptor *mOwner;
FTexture *mBackdrop;
FRemapTable mRemap;
FPlayerClass *mPlayerClass;
FState *mPlayerState;
int mPlayerTics;
bool mNoportrait;
BYTE mRotation;
BYTE mMode; // 0: automatic (used by class selection), 1: manual (used by player setup)
BYTE mTranslate;
int mSkin;
int mRandomClass;
int mRandomTimer;
int mClassNum;
void SetPlayerClass(int classnum, bool force = false);
bool UpdatePlayerClass();
void UpdateRandomClass();
public:
enum
{
PDF_ROTATION = 0x10001,
PDF_SKIN = 0x10002,
PDF_CLASS = 0x10003,
PDF_MODE = 0x10004,
PDF_TRANSLATE = 0x10005,
};
FListMenuItemPlayerDisplay(FListMenuDescriptor *menu, int x, int y, PalEntry c1, PalEntry c2, bool np, FName action);
~FListMenuItemPlayerDisplay();
virtual void Ticker();
virtual void Drawer(bool selected);
bool SetValue(int i, int value);
};
//=============================================================================
//
// selectable items
//
//=============================================================================
class FListMenuItemSelectable : public FListMenuItem
{
protected:
int mHotkey;
int mHeight;
int mParam;
public:
FListMenuItemSelectable(int x, int y, int height, FName childmenu, int mParam = -1);
bool CheckCoordinate(int x, int y);
bool Selectable();
bool CheckHotkey(int c);
bool Activate();
bool MouseEvent(int type, int x, int y);
FName GetAction(int *pparam);
};
class FListMenuItemText : public FListMenuItemSelectable
{
const char *mText;
FFont *mFont;
EColorRange mColor;
public:
FListMenuItemText(int x, int y, int height, int hotkey, const char *text, FFont *font, EColorRange color, FName child, int param = 0);
~FListMenuItemText();
void Drawer(bool selected);
};
class FListMenuItemPatch : public FListMenuItemSelectable
{
FTextureID mTexture;
public:
FListMenuItemPatch(int x, int y, int height, int hotkey, FTextureID patch, FName child, int param = 0);
void Drawer(bool selected);
};
//=============================================================================
//
// items for the player menu
//
//=============================================================================
class FPlayerNameBox : public FListMenuItemSelectable
{
const char *mText;
FFont *mFont;
EColorRange mFontColor;
int mFrameSize;
char mPlayerName[MAXPLAYERNAME+1];
char mEditName[MAXPLAYERNAME+2];
bool mEntering;
void DrawBorder (int x, int y, int len);
public:
FPlayerNameBox(int x, int y, int height, int frameofs, const char *text, FFont *font, EColorRange color, FName action);
~FPlayerNameBox();
bool SetString(int i, const char *s);
bool GetString(int i, char *s, int len);
void Drawer(bool selected);
bool MenuEvent (int mkey, bool fromcontroller);
};
//=============================================================================
//
// items for the player menu
//
//=============================================================================
class FValueTextItem : public FListMenuItemSelectable
{
TArray<FString> mSelections;
const char *mText;
int mSelection;
FFont *mFont;
EColorRange mFontColor;
EColorRange mFontColor2;
public:
FValueTextItem(int x, int y, int height, const char *text, FFont *font, EColorRange color, EColorRange valuecolor, FName action, FName values);
~FValueTextItem();
bool SetString(int i, const char *s);
bool SetValue(int i, int value);
bool GetValue(int i, int *pvalue);
bool MenuEvent (int mkey, bool fromcontroller);
void Drawer(bool selected);
};
//=============================================================================
//
// items for the player menu
//
//=============================================================================
class FSliderItem : public FListMenuItemSelectable
{
const char *mText;
FFont *mFont;
EColorRange mFontColor;
int mMinrange, mMaxrange;
int mStep;
int mSelection;
void DrawSlider (int x, int y);
public:
FSliderItem(int x, int y, int height, const char *text, FFont *font, EColorRange color, FName action, int min, int max, int step);
~FSliderItem();
bool SetValue(int i, int value);
bool GetValue(int i, int *pvalue);
bool MenuEvent (int mkey, bool fromcontroller);
void Drawer(bool selected);
bool MouseEvent(int type, int x, int y);
};
//=============================================================================
//
// list menu class runs a menu described by a FListMenuDescriptor
//
//=============================================================================
class DListMenu : public DMenu
{
DECLARE_CLASS(DListMenu, DMenu)
protected:
FListMenuDescriptor *mDesc;
FListMenuItem *mFocusControl;
public:
DListMenu(DMenu *parent = NULL, FListMenuDescriptor *desc = NULL);
virtual void Init(DMenu *parent = NULL, FListMenuDescriptor *desc = NULL);
FListMenuItem *GetItem(FName name);
bool Responder (event_t *ev);
bool MenuEvent (int mkey, bool fromcontroller);
bool MouseEvent(int type, int x, int y);
void Ticker ();
void Drawer ();
void SetFocus(FListMenuItem *fc)
{
mFocusControl = fc;
}
bool CheckFocus(FListMenuItem *fc)
{
return mFocusControl == fc;
}
void ReleaseFocus()
{
mFocusControl = NULL;
}
};
//=============================================================================
//
// base class for menu items
//
//=============================================================================
class FOptionMenuItem : public FListMenuItem
{
protected:
char *mLabel;
bool mCentered;
void drawLabel(int indent, int y, EColorRange color, bool grayed = false);
public:
FOptionMenuItem(const char *text, FName action = NAME_None, bool center = false)
: FListMenuItem(0, 0, action)
{
mLabel = copystring(text);
mCentered = center;
}
~FOptionMenuItem();
virtual bool CheckCoordinate(FOptionMenuDescriptor *desc, int x, int y);
virtual int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected);
virtual bool Selectable();
virtual int GetIndent();
virtual bool MouseEvent(int type, int x, int y);
};
//=============================================================================
//
//
//
//=============================================================================
struct FOptionValues
{
struct Pair
{
double Value;
FString TextValue;
FString Text;
};
TArray<Pair> mValues;
};
typedef TMap< FName, FOptionValues* > FOptionMap;
extern FOptionMap OptionValues;
//=============================================================================
//
// Option menu class runs a menu described by a FOptionMenuDescriptor
//
//=============================================================================
class DOptionMenu : public DMenu
{
DECLARE_CLASS(DOptionMenu, DMenu)
bool CanScrollUp;
bool CanScrollDown;
int VisBottom;
FOptionMenuItem *mFocusControl;
protected:
FOptionMenuDescriptor *mDesc;
public:
FOptionMenuItem *GetItem(FName name);
DOptionMenu(DMenu *parent = NULL, FOptionMenuDescriptor *desc = NULL);
virtual void Init(DMenu *parent = NULL, FOptionMenuDescriptor *desc = NULL);
bool Responder (event_t *ev);
bool MenuEvent (int mkey, bool fromcontroller);
bool MouseEvent(int type, int x, int y);
void Ticker ();
void Drawer ();
const FOptionMenuDescriptor *GetDescriptor() const { return mDesc; }
void SetFocus(FOptionMenuItem *fc)
{
mFocusControl = fc;
}
bool CheckFocus(FOptionMenuItem *fc)
{
return mFocusControl == fc;
}
void ReleaseFocus()
{
mFocusControl = NULL;
}
};
//=============================================================================
//
// Input some text
//
//=============================================================================
class DTextEnterMenu : public DMenu
{
DECLARE_ABSTRACT_CLASS(DTextEnterMenu, DMenu)
char *mEnterString;
unsigned int mEnterSize;
unsigned int mEnterPos;
int mSizeMode; // 1: size is length in chars. 2: also check string width
bool mInputGridOkay;
int InputGridX;
int InputGridY;
public:
DTextEnterMenu(DMenu *parent, char *textbuffer, int maxlen, int sizemode, bool showgrid);
void Drawer ();
bool MenuEvent (int mkey, bool fromcontroller);
bool Responder(event_t *ev);
bool TranslateKeyboardEvents();
bool MouseEvent(int type, int x, int y);
};
struct event_t;
bool M_Responder (event_t *ev);
void M_Ticker (void);
void M_Drawer (void);
void M_Init (void);
void M_CreateMenus();
void M_ActivateMenu(DMenu *menu);
void M_ClearMenus ();
void M_ParseMenuDefs();
void M_StartupSkillMenu(FGameStartup *gs);
void M_StartControlPanel (bool makeSound);
void M_SetMenu(FName menu, int param = -1);
void M_NotifyNewSave (const char *file, const char *title, bool okForQuicksave);
void M_StartMessage(const char *message, int messagemode, FName action = NAME_None);
DMenu *StartPickerMenu(DMenu *parent, const char *name, FColorCVar *cvar);
void M_RefreshModesList ();
void M_InitVideoModesMenu ();
#endif

1389
src/menu/menudef.cpp Normal file

File diff suppressed because it is too large Load Diff

366
src/menu/menuinput.cpp Normal file
View File

@ -0,0 +1,366 @@
/*
** menuinput.cpp
** The string input code
**
**---------------------------------------------------------------------------
** Copyright 2001-2010 Randy Heit
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "menu/menu.h"
#include "v_video.h"
#include "c_cvars.h"
#include "d_event.h"
#include "d_gui.h"
#include "v_font.h"
#include "v_palette.h"
IMPLEMENT_ABSTRACT_CLASS(DTextEnterMenu)
#define INPUTGRID_WIDTH 13
#define INPUTGRID_HEIGHT 5
// Heretic and Hexen do not, by default, come with glyphs for all of these
// characters. Oh well. Doom and Strife do.
static const char InputGridChars[INPUTGRID_WIDTH * INPUTGRID_HEIGHT] =
"ABCDEFGHIJKLM"
"NOPQRSTUVWXYZ"
"0123456789+-="
".,!?@'\":;[]()"
"<>^#$%&*/_ \b";
CVAR(Bool, m_showinputgrid, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
//=============================================================================
//
//
//
//=============================================================================
DTextEnterMenu::DTextEnterMenu(DMenu *parent, char *textbuffer, int maxlen, int sizemode, bool showgrid)
: DMenu(parent)
{
mEnterString = textbuffer;
mEnterSize = maxlen;
mEnterPos = (unsigned)strlen(textbuffer);
mSizeMode = sizemode;
mInputGridOkay = showgrid || m_showinputgrid;
if (mEnterPos > 0)
{
InputGridX = INPUTGRID_WIDTH - 1;
InputGridY = INPUTGRID_HEIGHT - 1;
}
else
{
// If we are naming a new save, don't start the cursor on "end".
InputGridX = 0;
InputGridY = 0;
}
}
//=============================================================================
//
//
//
//=============================================================================
bool DTextEnterMenu::TranslateKeyboardEvents()
{
return mInputGridOkay;
}
//=============================================================================
//
//
//
//=============================================================================
bool DTextEnterMenu::Responder(event_t *ev)
{
if (ev->type == EV_GUI_Event)
{
// Save game and player name string input
if (ev->subtype == EV_GUI_Char)
{
mInputGridOkay = false;
if (mEnterPos < mEnterSize &&
(mSizeMode == 2/*entering player name*/ || (size_t)SmallFont->StringWidth(mEnterString) < (mEnterSize-1)*8))
{
mEnterString[mEnterPos] = (char)ev->data1;
mEnterString[++mEnterPos] = 0;
}
return true;
}
char ch = (char)ev->data1;
if ((ev->subtype == EV_GUI_KeyDown || ev->subtype == EV_GUI_KeyRepeat) && ch == '\b')
{
if (mEnterPos > 0)
{
mEnterPos--;
mEnterString[mEnterPos] = 0;
}
}
else if (ev->subtype == EV_GUI_KeyDown)
{
if (ch == GK_ESCAPE)
{
DMenu *parent = mParentMenu;
Close();
parent->MenuEvent(MKEY_Abort, false);
return true;
}
else if (ch == '\r')
{
if (mEnterString[0])
{
DMenu *parent = mParentMenu;
Close();
parent->MenuEvent(MKEY_Input, false);
return true;
}
}
}
if (ev->subtype == EV_GUI_KeyDown || ev->subtype == EV_GUI_KeyRepeat)
{
return true;
}
}
return Super::Responder(ev);
}
//=============================================================================
//
//
//
//=============================================================================
bool DTextEnterMenu::MouseEvent(int type, int x, int y)
{
const int cell_width = 18 * CleanXfac;
const int cell_height = 12 * CleanYfac;
const int screen_y = screen->GetHeight() - INPUTGRID_HEIGHT * cell_height;
const int screen_x = (screen->GetWidth() - INPUTGRID_WIDTH * cell_width) / 2;
if (x >= screen_x && x < screen_x + INPUTGRID_WIDTH * cell_width && y >= screen_y)
{
InputGridX = (x - screen_x) / cell_width;
InputGridY = (y - screen_y) / cell_height;
if (type == DMenu::MOUSE_Release)
{
if (MenuEvent(MKEY_Enter, true))
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
if (m_use_mouse == 2) InputGridX = InputGridY = -1;
return true;
}
}
}
else
{
InputGridX = InputGridY = -1;
}
return Super::MouseEvent(type, x, y);
}
//=============================================================================
//
//
//
//=============================================================================
bool DTextEnterMenu::MenuEvent (int key, bool fromcontroller)
{
if (key == MKEY_Back)
{
mParentMenu->MenuEvent(MKEY_Abort, false);
return Super::MenuEvent(key, fromcontroller);
}
if (fromcontroller)
{
mInputGridOkay = true;
}
if (mInputGridOkay)
{
int ch;
if (InputGridX == -1 || InputGridY == -1)
{
InputGridX = InputGridY = 0;
}
switch (key)
{
case MKEY_Down:
InputGridY = (InputGridY + 1) % INPUTGRID_HEIGHT;
return true;
case MKEY_Up:
InputGridY = (InputGridY + INPUTGRID_HEIGHT - 1) % INPUTGRID_HEIGHT;
return true;
case MKEY_Right:
InputGridX = (InputGridX + 1) % INPUTGRID_WIDTH;
return true;
case MKEY_Left:
InputGridX = (InputGridX + INPUTGRID_WIDTH - 1) % INPUTGRID_WIDTH;
return true;
case MKEY_Clear:
if (mEnterPos > 0)
{
mEnterString[--mEnterPos] = 0;
}
return true;
case MKEY_Enter:
assert(unsigned(InputGridX) < INPUTGRID_WIDTH && unsigned(InputGridY) < INPUTGRID_HEIGHT);
if (mInputGridOkay)
{
ch = InputGridChars[InputGridX + InputGridY * INPUTGRID_WIDTH];
if (ch == 0) // end
{
if (mEnterString[0] != '\0')
{
DMenu *parent = mParentMenu;
Close();
parent->MenuEvent(MKEY_Input, false);
return true;
}
}
else if (ch == '\b') // bs
{
if (mEnterPos > 0)
{
mEnterString[--mEnterPos] = 0;
}
}
else if (mEnterPos < mEnterSize &&
(mSizeMode == 2/*entering player name*/ || (size_t)SmallFont->StringWidth(mEnterString) < (mEnterSize-1)*8))
{
mEnterString[mEnterPos] = ch;
mEnterString[++mEnterPos] = 0;
}
}
return true;
default:
break; // Keep GCC quiet
}
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
void DTextEnterMenu::Drawer ()
{
mParentMenu->Drawer();
if (mInputGridOkay)
{
const int cell_width = 18 * CleanXfac;
const int cell_height = 12 * CleanYfac;
const int top_padding = cell_height / 2 - SmallFont->GetHeight() * CleanYfac / 2;
// Darken the background behind the character grid.
// Unless we frame it with a border, I think it looks better to extend the
// background across the full width of the screen.
screen->Dim(0, 0.8f,
0 /*screen->GetWidth()/2 - 13 * cell_width / 2*/,
screen->GetHeight() - INPUTGRID_HEIGHT * cell_height,
screen->GetWidth() /*13 * cell_width*/,
INPUTGRID_HEIGHT * cell_height);
if (InputGridX >= 0 && InputGridY >= 0)
{
// Highlight the background behind the selected character.
screen->Dim(MAKERGB(255,248,220), 0.6f,
InputGridX * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen->GetWidth() / 2,
InputGridY * cell_height - INPUTGRID_HEIGHT * cell_height + screen->GetHeight(),
cell_width, cell_height);
}
for (int y = 0; y < INPUTGRID_HEIGHT; ++y)
{
const int yy = y * cell_height - INPUTGRID_HEIGHT * cell_height + screen->GetHeight();
for (int x = 0; x < INPUTGRID_WIDTH; ++x)
{
int width;
const int xx = x * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen->GetWidth() / 2;
const int ch = InputGridChars[y * INPUTGRID_WIDTH + x];
FTexture *pic = SmallFont->GetChar(ch, &width);
EColorRange color;
FRemapTable *remap;
// The highlighted character is yellow; the rest are dark gray.
color = (x == InputGridX && y == InputGridY) ? CR_YELLOW : CR_DARKGRAY;
remap = SmallFont->GetColorTranslation(color);
if (pic != NULL)
{
// Draw a normal character.
screen->DrawTexture(pic, xx + cell_width/2 - width*CleanXfac/2, yy + top_padding,
DTA_Translation, remap,
DTA_CleanNoMove, true,
TAG_DONE);
}
else if (ch == ' ')
{
// Draw the space as a box outline. We also draw it 50% wider than it really is.
const int x1 = xx + cell_width/2 - width * CleanXfac * 3 / 4;
const int x2 = x1 + width * 3 * CleanXfac / 2;
const int y1 = yy + top_padding;
const int y2 = y1 + SmallFont->GetHeight() * CleanYfac;
const int palentry = remap->Remap[remap->NumEntries*2/3];
const uint32 palcolor = remap->Palette[remap->NumEntries*2/3];
screen->Clear(x1, y1, x2, y1+CleanYfac, palentry, palcolor); // top
screen->Clear(x1, y2, x2, y2+CleanYfac, palentry, palcolor); // bottom
screen->Clear(x1, y1+CleanYfac, x1+CleanXfac, y2, palentry, palcolor); // left
screen->Clear(x2-CleanXfac, y1+CleanYfac, x2, y2, palentry, palcolor); // right
}
else if (ch == '\b' || ch == 0)
{
// Draw the backspace and end "characters".
const char *const str = ch == '\b' ? "BS" : "ED";
screen->DrawText(SmallFont, color,
xx + cell_width/2 - SmallFont->StringWidth(str)*CleanXfac/2,
yy + top_padding, str, DTA_CleanNoMove, true, TAG_DONE);
}
}
}
}
Super::Drawer();
}

733
src/menu/messagebox.cpp Normal file
View File

@ -0,0 +1,733 @@
/*
** messagebox.cpp
** Confirmation, notification screns
**
**---------------------------------------------------------------------------
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "menu/menu.h"
#include "d_event.h"
#include "d_gui.h"
#include "v_video.h"
#include "v_text.h"
#include "d_main.h"
#include "gstrings.h"
#include "gi.h"
#include "i_video.h"
#include "st_start.h"
#include "c_dispatch.h"
#include "g_game.h"
extern FSaveGameNode *quickSaveSlot;
class DMessageBoxMenu : public DMenu
{
DECLARE_CLASS(DMessageBoxMenu, DMenu)
FBrokenLines *mMessage;
int mMessageMode;
int messageSelection;
int mMouseLeft, mMouseRight, mMouseY;
FName mAction;
public:
DMessageBoxMenu(DMenu *parent = NULL, const char *message = NULL, int messagemode = 0, bool playsound = false, FName action = NAME_None);
void Destroy();
void Init(DMenu *parent, const char *message, int messagemode, bool playsound = false);
void Drawer();
bool Responder(event_t *ev);
bool MenuEvent(int mkey, bool fromcontroller);
bool MouseEvent(int type, int x, int y);
void CloseSound();
virtual void HandleResult(bool res);
};
IMPLEMENT_CLASS(DMessageBoxMenu)
//=============================================================================
//
//
//
//=============================================================================
DMessageBoxMenu::DMessageBoxMenu(DMenu *parent, const char *message, int messagemode, bool playsound, FName action)
: DMenu(parent)
{
mAction = action;
messageSelection = 0;
mMouseLeft = 140;
mMouseY = INT_MIN;
int mr1 = 170 + SmallFont->StringWidth(GStrings["TXT_YES"]);
int mr2 = 170 + SmallFont->StringWidth(GStrings["TXT_NO"]);
mMouseRight = MAX(mr1, mr2);
Init(parent, message, messagemode, playsound);
}
//=============================================================================
//
//
//
//=============================================================================
void DMessageBoxMenu::Init(DMenu *parent, const char *message, int messagemode, bool playsound)
{
mParentMenu = parent;
if (message != NULL)
{
if (*message == '$') message = GStrings(message+1);
mMessage = V_BreakLines(SmallFont, 300, message);
}
else mMessage = NULL;
mMessageMode = messagemode;
if (playsound)
{
S_StopSound (CHAN_VOICE);
S_Sound (CHAN_VOICE | CHAN_UI, "menu/prompt", snd_menuvolume, ATTN_NONE);
}
}
//=============================================================================
//
//
//
//=============================================================================
void DMessageBoxMenu::Destroy()
{
if (mMessage != NULL) V_FreeBrokenLines(mMessage);
mMessage = NULL;
}
//=============================================================================
//
//
//
//=============================================================================
void DMessageBoxMenu::CloseSound()
{
S_Sound (CHAN_VOICE | CHAN_UI,
DMenu::CurrentMenu != NULL? "menu/backup" : "menu/dismiss", snd_menuvolume, ATTN_NONE);
}
//=============================================================================
//
//
//
//=============================================================================
void DMessageBoxMenu::HandleResult(bool res)
{
if (mParentMenu != NULL)
{
if (mMessageMode == 0)
{
if (mAction == NAME_None)
{
mParentMenu->MenuEvent(res? MKEY_MBYes : MKEY_MBNo, false);
Close();
}
else
{
Close();
if (res) M_SetMenu(mAction, -1);
}
CloseSound();
}
}
}
//=============================================================================
//
//
//
//=============================================================================
void DMessageBoxMenu::Drawer ()
{
int i, y;
PalEntry fade = 0;
int fontheight = SmallFont->GetHeight();
//BorderNeedRefresh = screen->GetPageCount ();
//SB_state = screen->GetPageCount ();
y = 100;
if (mMessage != NULL)
{
for (i = 0; mMessage[i].Width >= 0; i++)
y -= SmallFont->GetHeight () / 2;
for (i = 0; mMessage[i].Width >= 0; i++)
{
screen->DrawText (SmallFont, CR_UNTRANSLATED, 160 - mMessage[i].Width/2, y, mMessage[i].Text,
DTA_Clean, true, TAG_DONE);
y += fontheight;
}
}
if (mMessageMode == 0)
{
y += fontheight;
mMouseY = y;
screen->DrawText(SmallFont,
messageSelection == 0? OptionSettings.mFontColorSelection : OptionSettings.mFontColor,
160, y, GStrings["TXT_YES"], DTA_Clean, true, TAG_DONE);
screen->DrawText(SmallFont,
messageSelection == 1? OptionSettings.mFontColorSelection : OptionSettings.mFontColor,
160, y + fontheight + 1, GStrings["TXT_NO"], DTA_Clean, true, TAG_DONE);
if (messageSelection >= 0)
{
if ((DMenu::MenuTime%8) < 6)
{
screen->DrawText(ConFont, OptionSettings.mFontColorSelection,
(150 - 160) * CleanXfac + screen->GetWidth() / 2,
(y + (fontheight + 1) * messageSelection - 100) * CleanYfac + screen->GetHeight() / 2,
"\xd",
DTA_CellX, 8 * CleanXfac,
DTA_CellY, 8 * CleanYfac,
TAG_DONE);
}
}
}
}
//=============================================================================
//
//
//
//=============================================================================
bool DMessageBoxMenu::Responder(event_t *ev)
{
if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_KeyDown)
{
if (mMessageMode == 0)
{
int ch = tolower(ev->data1);
if (ch == 'n' || ch == ' ')
{
HandleResult(false);
return true;
}
else if (ch == 'y')
{
HandleResult(true);
return true;
}
}
else
{
Close();
return true;
}
return false;
}
else if (ev->type == EV_KeyDown)
{
Close();
return true;
}
return Super::Responder(ev);
}
//=============================================================================
//
//
//
//=============================================================================
bool DMessageBoxMenu::MenuEvent(int mkey, bool fromcontroller)
{
if (mMessageMode == 0)
{
if (mkey == MKEY_Up || mkey == MKEY_Down)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
messageSelection = !messageSelection;
return true;
}
else if (mkey == MKEY_Enter)
{
// 0 is yes, 1 is no
HandleResult(!messageSelection);
return true;
}
else if (mkey == MKEY_Back)
{
HandleResult(false);
return true;
}
return false;
}
else
{
Close();
CloseSound();
return true;
}
}
//=============================================================================
//
//
//
//=============================================================================
bool DMessageBoxMenu::MouseEvent(int type, int x, int y)
{
if (mMessageMode == 1)
{
if (type == MOUSE_Click)
{
return MenuEvent(MKEY_Enter, true);
}
return false;
}
else
{
int sel = -1;
int fh = SmallFont->GetHeight() + 1;
// convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture
x = ((x - (screen->GetWidth() / 2)) / CleanXfac) + 160;
y = ((y - (screen->GetHeight() / 2)) / CleanYfac) + 100;
if (x >= mMouseLeft && x <= mMouseRight && y >= mMouseY && y < mMouseY + 2 * fh)
{
sel = y >= mMouseY + fh;
}
if (sel != -1 && sel != messageSelection)
{
//S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
}
messageSelection = sel;
if (type == MOUSE_Release)
{
return MenuEvent(MKEY_Enter, true);
}
return true;
}
}
//=============================================================================
//
//
//
//=============================================================================
//=============================================================================
//
//
//
//=============================================================================
class DQuitMenu : public DMessageBoxMenu
{
DECLARE_CLASS(DQuitMenu, DMessageBoxMenu)
public:
DQuitMenu(bool playsound = false);
virtual void HandleResult(bool res);
};
IMPLEMENT_CLASS(DQuitMenu)
//=============================================================================
//
//
//
//=============================================================================
DQuitMenu::DQuitMenu(bool playsound)
{
int messageindex = gametic % gameinfo.quitmessages.Size();
FString EndString;
const char *msg = gameinfo.quitmessages[messageindex];
if (msg[0] == '$')
{
if (msg[1] == '*')
{
EndString = GStrings(msg+2);
}
else
{
EndString.Format("%s\n\n%s", GStrings(msg+1), GStrings("DOSY"));
}
}
else EndString = gameinfo.quitmessages[messageindex];
Init(NULL, EndString, 0, playsound);
}
//=============================================================================
//
//
//
//=============================================================================
void DQuitMenu::HandleResult(bool res)
{
if (res)
{
if (!netgame)
{
if (gameinfo.quitSound.IsNotEmpty())
{
S_Sound (CHAN_VOICE | CHAN_UI, gameinfo.quitSound, snd_menuvolume, ATTN_NONE);
I_WaitVBL (105);
}
}
ST_Endoom();
}
else
{
Close();
CloseSound();
}
}
//=============================================================================
//
//
//
//=============================================================================
CCMD (menu_quit)
{ // F10
M_StartControlPanel (true);
DMenu *newmenu = new DQuitMenu(false);
newmenu->mParentMenu = DMenu::CurrentMenu;
M_ActivateMenu(newmenu);
}
//=============================================================================
//
//
//
//=============================================================================
//=============================================================================
//
//
//
//=============================================================================
class DEndGameMenu : public DMessageBoxMenu
{
DECLARE_CLASS(DEndGameMenu, DMessageBoxMenu)
public:
DEndGameMenu(bool playsound = false);
virtual void HandleResult(bool res);
};
IMPLEMENT_CLASS(DEndGameMenu)
//=============================================================================
//
//
//
//=============================================================================
DEndGameMenu::DEndGameMenu(bool playsound)
{
int messageindex = gametic % gameinfo.quitmessages.Size();
FString EndString = gameinfo.quitmessages[messageindex];
if (netgame)
{
if(gameinfo.gametype == GAME_Chex)
EndString = GStrings("CNETEND");
else
EndString = GStrings("NETEND");
return;
}
if(gameinfo.gametype == GAME_Chex)
EndString = GStrings("CENDGAME");
else
EndString = GStrings("ENDGAME");
Init(NULL, EndString, 0, playsound);
}
//=============================================================================
//
//
//
//=============================================================================
void DEndGameMenu::HandleResult(bool res)
{
if (res)
{
M_ClearMenus ();
D_StartTitle ();
}
else
{
Close();
CloseSound();
}
}
//=============================================================================
//
//
//
//=============================================================================
CCMD (menu_endgame)
{ // F7
if (!usergame)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/invalid", snd_menuvolume, ATTN_NONE);
return;
}
//M_StartControlPanel (true);
S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE);
DMenu *newmenu = new DEndGameMenu(false);
newmenu->mParentMenu = DMenu::CurrentMenu;
M_ActivateMenu(newmenu);
}
//=============================================================================
//
//
//
//=============================================================================
//=============================================================================
//
//
//
//=============================================================================
class DQuickSaveMenu : public DMessageBoxMenu
{
DECLARE_CLASS(DQuickSaveMenu, DMessageBoxMenu)
public:
DQuickSaveMenu(bool playsound = false);
virtual void HandleResult(bool res);
};
IMPLEMENT_CLASS(DQuickSaveMenu)
//=============================================================================
//
//
//
//=============================================================================
DQuickSaveMenu::DQuickSaveMenu(bool playsound)
{
FString tempstring;
if(gameinfo.gametype == GAME_Chex)
tempstring.Format(GStrings("CQSPROMPT"), quickSaveSlot->Title);
else
tempstring.Format(GStrings("QSPROMPT"), quickSaveSlot->Title);
Init(NULL, tempstring, 0, playsound);
}
//=============================================================================
//
//
//
//=============================================================================
void DQuickSaveMenu::HandleResult(bool res)
{
if (res)
{
G_SaveGame (quickSaveSlot->Filename.GetChars(), quickSaveSlot->Title);
S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE);
M_ClearMenus();
}
else
{
Close();
CloseSound();
}
}
//=============================================================================
//
//
//
//=============================================================================
CCMD (quicksave)
{ // F6
if (!usergame || (players[consoleplayer].health <= 0 && !multiplayer))
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/invalid", snd_menuvolume, ATTN_NONE);
return;
}
if (gamestate != GS_LEVEL)
return;
S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE);
if (quickSaveSlot == NULL)
{
M_StartControlPanel(false);
M_SetMenu(NAME_Savegamemenu);
return;
}
DMenu *newmenu = new DQuickSaveMenu(false);
newmenu->mParentMenu = DMenu::CurrentMenu;
M_ActivateMenu(newmenu);
}
//=============================================================================
//
//
//
//=============================================================================
//=============================================================================
//
//
//
//=============================================================================
class DQuickLoadMenu : public DMessageBoxMenu
{
DECLARE_CLASS(DQuickLoadMenu, DMessageBoxMenu)
public:
DQuickLoadMenu(bool playsound = false);
virtual void HandleResult(bool res);
};
IMPLEMENT_CLASS(DQuickLoadMenu)
//=============================================================================
//
//
//
//=============================================================================
DQuickLoadMenu::DQuickLoadMenu(bool playsound)
{
FString tempstring;
if(gameinfo.gametype == GAME_Chex)
tempstring.Format(GStrings("CQLPROMPT"), quickSaveSlot->Title);
else
tempstring.Format(GStrings("QLPROMPT"), quickSaveSlot->Title);
Init(NULL, tempstring, 0, playsound);
}
//=============================================================================
//
//
//
//=============================================================================
void DQuickLoadMenu::HandleResult(bool res)
{
if (res)
{
G_LoadGame (quickSaveSlot->Filename.GetChars());
S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE);
M_ClearMenus();
}
else
{
Close();
CloseSound();
}
}
//=============================================================================
//
//
//
//=============================================================================
CCMD (quickload)
{ // F9
M_StartControlPanel (true);
if (netgame)
{
if(gameinfo.gametype == GAME_Chex)
M_StartMessage (GStrings("CQLOADNET"), NULL);
else
M_StartMessage (GStrings("QLOADNET"), NULL);
return;
}
if (quickSaveSlot == NULL)
{
M_StartControlPanel(false);
// signal that whatever gets loaded should be the new quicksave
quickSaveSlot = (FSaveGameNode *)1;
M_SetMenu(NAME_Loadgamemenu);
return;
}
DMenu *newmenu = new DQuickLoadMenu(false);
newmenu->mParentMenu = DMenu::CurrentMenu;
M_ActivateMenu(newmenu);
}
//=============================================================================
//
//
//
//=============================================================================
void M_StartMessage(const char *message, int messagemode, FName action)
{
if (DMenu::CurrentMenu == NULL)
{
// only play a sound if no menu was active before
M_StartControlPanel(menuactive == MENU_Off);
}
DMenu *newmenu = new DMessageBoxMenu(DMenu::CurrentMenu, message, messagemode, false, action);
newmenu->mParentMenu = DMenu::CurrentMenu;
M_ActivateMenu(newmenu);
}

591
src/menu/optionmenu.cpp Normal file
View File

@ -0,0 +1,591 @@
/*
** optionmenu.cpp
** Handler class for the option menus and associated items
**
**---------------------------------------------------------------------------
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "v_video.h"
#include "v_font.h"
#include "cmdlib.h"
#include "gstrings.h"
#include "g_level.h"
#include "gi.h"
#include "v_palette.h"
#include "d_gui.h"
#include "d_event.h"
#include "c_dispatch.h"
#include "c_console.h"
#include "c_cvars.h"
#include "c_bind.h"
#include "gameconfigfile.h"
#include "menu/menu.h"
//=============================================================================
//
// Draws a string in the console font, scaled to the 8x8 cells
// used by the default console font.
//
//=============================================================================
void M_DrawConText (int color, int x, int y, const char *str)
{
int len = (int)strlen(str);
screen->DrawText (ConFont, color, x, y, str,
DTA_CellX, 8 * CleanXfac_1,
DTA_CellY, 8 * CleanYfac_1,
TAG_DONE);
}
//=============================================================================
//
// Draw a slider. Set fracdigits negative to not display the current value numerically.
//
//=============================================================================
void M_DrawSlider (int x, int y, double min, double max, double cur,int fracdigits)
{
double range;
range = max - min;
double ccur = clamp(cur, min, max) - min;
if (CleanXfac > CleanXfac_1)
{
M_DrawConText(CR_WHITE, x, y, "\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12");
M_DrawConText(CR_ORANGE, x + int((5 + ((ccur * 78) / range)) * CleanXfac_1), y, "\x13");
if (fracdigits >= 0)
{
char textbuf[16];
mysnprintf(textbuf, countof(textbuf), "%.*f", fracdigits, cur);
screen->DrawText(SmallFont, CR_DARKGRAY, x + (12*8 + 4) * CleanXfac_1, y, textbuf, DTA_CleanNoMove_1, true, TAG_DONE);
}
}
else
{
// On 320x200 we need a shorter slider
M_DrawConText(CR_WHITE, x, y, "\x10\x11\x11\x11\x11\x11\x12");
M_DrawConText(CR_ORANGE, x + int((5 + ((ccur * 38) / range)) * CleanXfac_1), y, "\x13");
if (fracdigits >= 0)
{
char textbuf[16];
mysnprintf(textbuf, countof(textbuf), "%.*f", fracdigits, cur);
screen->DrawText(SmallFont, CR_DARKGRAY, x + (7*8 + 4) * CleanXfac_1, y, textbuf, DTA_CleanNoMove_1, true, TAG_DONE);
}
}
}
IMPLEMENT_CLASS(DOptionMenu)
//=============================================================================
//
//
//
//=============================================================================
DOptionMenu::DOptionMenu(DMenu *parent, FOptionMenuDescriptor *desc)
: DMenu(parent)
{
CanScrollUp = false;
CanScrollDown = false;
VisBottom = 0;
mFocusControl = NULL;
Init(parent, desc);
}
//=============================================================================
//
//
//
//=============================================================================
void DOptionMenu::Init(DMenu *parent, FOptionMenuDescriptor *desc)
{
mParentMenu = parent;
GC::WriteBarrier(this, parent);
mDesc = desc;
if (mDesc != NULL && mDesc->mSelectedItem < 0)
{
// Go down to the first selectable item
int i = -1;
mDesc->mSelectedItem = -1;
do
{
i++;
}
while (!mDesc->mItems[i]->Selectable() && i < (int)mDesc->mItems.Size());
if (i>=0) mDesc->mSelectedItem = i;
}
}
//=============================================================================
//
//
//
//=============================================================================
FOptionMenuItem *DOptionMenu::GetItem(FName name)
{
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
{
FName nm = mDesc->mItems[i]->GetAction(NULL);
if (nm == name) return mDesc->mItems[i];
}
return NULL;
}
//=============================================================================
//
//
//
//=============================================================================
bool DOptionMenu::Responder (event_t *ev)
{
if (ev->type == EV_GUI_Event)
{
if (ev->subtype == EV_GUI_WheelUp)
{
if (mDesc->mScrollPos > 0)
{
mDesc->mScrollPos--;
}
return true;
}
else if (ev->subtype == EV_GUI_WheelDown)
{
if (CanScrollDown)
{
mDesc->mScrollPos++;
VisBottom++;
}
return true;
}
}
return Super::Responder(ev);
}
//=============================================================================
//
//
//
//=============================================================================
bool DOptionMenu::MenuEvent (int mkey, bool fromcontroller)
{
int startedAt = mDesc->mSelectedItem;
switch (mkey)
{
case MKEY_Up:
do
{
--mDesc->mSelectedItem;
if (mDesc->mScrollPos > 0 &&
mDesc->mSelectedItem == mDesc->mScrollTop + mDesc->mScrollPos)
{
mDesc->mScrollPos--;
}
if (mDesc->mSelectedItem < 0)
{
// Figure out how many lines of text fit on the menu
int y = mDesc->mPosition;
if (y <= 0)
{
if (BigFont && mDesc->mTitle.IsNotEmpty())
{
y = -y + BigFont->GetHeight();
}
else
{
y = -y;
}
}
y *= CleanYfac_1;
int rowheight = OptionSettings.mLinespacing * CleanYfac_1;
int maxitems = (screen->GetHeight() - rowheight - y) / rowheight + 1;
mDesc->mScrollPos = MAX (0, (int)mDesc->mItems.Size() - maxitems + mDesc->mScrollTop);
mDesc->mSelectedItem = mDesc->mItems.Size()-1;
}
}
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt);
break;
case MKEY_Down:
do
{
++mDesc->mSelectedItem;
if (CanScrollDown && mDesc->mSelectedItem == VisBottom)
{
mDesc->mScrollPos++;
VisBottom++;
}
if (mDesc->mSelectedItem >= (int)mDesc->mItems.Size())
{
mDesc->mSelectedItem = 0;
mDesc->mScrollPos = 0;
}
}
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt);
break;
case MKEY_PageUp:
if (mDesc->mScrollPos > 0)
{
mDesc->mScrollPos -= VisBottom - mDesc->mScrollPos - mDesc->mScrollTop;
if (mDesc->mScrollPos < 0)
{
mDesc->mScrollPos = 0;
}
mDesc->mSelectedItem = mDesc->mScrollTop + mDesc->mScrollPos + 1;
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable())
{
++mDesc->mSelectedItem;
}
}
break;
case MKEY_PageDown:
if (CanScrollDown)
{
int pagesize = VisBottom - mDesc->mScrollPos - mDesc->mScrollTop;
mDesc->mScrollPos += pagesize;
if (mDesc->mScrollPos + mDesc->mScrollTop + pagesize > (int)mDesc->mItems.Size())
{
mDesc->mScrollPos = mDesc->mItems.Size() - mDesc->mScrollTop - pagesize;
}
mDesc->mSelectedItem = mDesc->mScrollTop + mDesc->mScrollPos;
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable())
{
++mDesc->mSelectedItem;
}
}
break;
case MKEY_Enter:
if (mDesc->mSelectedItem >= 0 && mDesc->mItems[mDesc->mSelectedItem]->Activate())
{
return true;
}
// fall through to default
default:
if (mDesc->mSelectedItem >= 0 &&
mDesc->mItems[mDesc->mSelectedItem]->MenuEvent(mkey, fromcontroller)) return true;
return Super::MenuEvent(mkey, fromcontroller);
}
if (mDesc->mSelectedItem != startedAt)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
}
return true;
}
//=============================================================================
//
//
//
//=============================================================================
bool DOptionMenu::MouseEvent(int type, int x, int y)
{
y = (y / CleanYfac_1) - mDesc->mDrawTop;
if (mFocusControl)
{
mFocusControl->MouseEvent(type, x, y);
return true;
}
else
{
int yline = (y / OptionSettings.mLinespacing);
if (yline >= mDesc->mScrollTop)
{
yline += mDesc->mScrollPos;
}
if ((unsigned)yline < mDesc->mItems.Size() && mDesc->mItems[yline]->Selectable())
{
if (yline != mDesc->mSelectedItem)
{
mDesc->mSelectedItem = yline;
//S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
}
mDesc->mItems[yline]->MouseEvent(type, x, y);
return true;
}
}
mDesc->mSelectedItem = -1;
return Super::MouseEvent(type, x, y);
}
//=============================================================================
//
//
//
//=============================================================================
void DOptionMenu::Ticker ()
{
Super::Ticker();
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
{
mDesc->mItems[i]->Ticker();
}
}
//=============================================================================
//
//
//
//=============================================================================
void DOptionMenu::Drawer ()
{
int y = mDesc->mPosition;
if (y <= 0)
{
if (BigFont && mDesc->mTitle.IsNotEmpty())
{
const char *tt = mDesc->mTitle;
if (*tt == '$') tt = GStrings(tt+1);
screen->DrawText (BigFont, OptionSettings.mTitleColor,
(screen->GetWidth() - BigFont->StringWidth(tt) * CleanXfac_1) / 2, 10*CleanYfac_1,
tt, DTA_CleanNoMove_1, true, TAG_DONE);
y = -y + BigFont->GetHeight();
}
else
{
y = -y;
}
}
mDesc->mDrawTop = y;
//int labelofs = OptionSettings.mLabelOffset * CleanXfac_1;
//int cursorspace = 14 * CleanXfac_1;
int fontheight = OptionSettings.mLinespacing * CleanYfac_1;
y *= CleanYfac_1;
int indent = mDesc->mIndent;
if (indent > 280)
{ // kludge for the compatibility options with their extremely long labels
if (indent + 40 <= CleanWidth_1)
{
indent = (screen->GetWidth() - ((indent + 40) * CleanXfac_1)) / 2 + indent * CleanXfac_1;
}
else
{
indent = screen->GetWidth() - 40 * CleanXfac_1;
}
}
else
{
indent = (indent - 160) * CleanXfac_1 + screen->GetWidth() / 2;
}
int ytop = y + mDesc->mScrollTop * 8 * CleanYfac_1;
int lastrow = screen->GetHeight() - SmallFont->GetHeight() * CleanYfac_1;
unsigned i;
for (i = 0; i < mDesc->mItems.Size() && y <= lastrow; i++, y += fontheight)
{
// Don't scroll the uppermost items
if (i == mDesc->mScrollTop)
{
i += mDesc->mScrollPos;
if (i >= mDesc->mItems.Size()) break; // skipped beyond end of menu
}
int cur_indent = mDesc->mItems[i]->Draw(mDesc, y, indent, mDesc->mSelectedItem == i);
if (cur_indent >= 0 && mDesc->mSelectedItem == i && mDesc->mItems[i]->Selectable())
{
if (((DMenu::MenuTime%8) < 6) || DMenu::CurrentMenu != this)
{
M_DrawConText(OptionSettings.mFontColorSelection, cur_indent + 3 * CleanXfac_1, y-CleanYfac_1+OptionSettings.mLabelOffset, "\xd");
}
}
}
CanScrollUp = (mDesc->mScrollPos > 0);
CanScrollDown = (i < mDesc->mItems.Size());
VisBottom = i - 1;
if (CanScrollUp)
{
M_DrawConText(CR_ORANGE, 3 * CleanXfac_1, ytop + OptionSettings.mLabelOffset, "\x1a");
}
if (CanScrollDown)
{
M_DrawConText(CR_ORANGE, 3 * CleanXfac_1, y - 8*CleanYfac_1 + OptionSettings.mLabelOffset, "\x1b");
}
Super::Drawer();
}
//=============================================================================
//
// base class for menu items
//
//=============================================================================
FOptionMenuItem::~FOptionMenuItem()
{
if (mLabel != NULL) delete [] mLabel;
}
bool FOptionMenuItem::CheckCoordinate(FOptionMenuDescriptor *desc, int x, int y)
{
return false;
}
int FOptionMenuItem::Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
{
return indent;
}
bool FOptionMenuItem::Selectable()
{
return true;
}
bool FOptionMenuItem::MouseEvent(int type, int x, int y)
{
if (Selectable() && type == DMenu::MOUSE_Release)
{
return DMenu::CurrentMenu->MenuEvent(MKEY_Enter, true);
}
return false;
}
int FOptionMenuItem::GetIndent()
{
return mCentered? 0 : SmallFont->StringWidth(mLabel);
}
void FOptionMenuItem::drawLabel(int indent, int y, EColorRange color, bool grayed)
{
const char *label = mLabel;
if (*label == '$') label = GStrings(label+1);
int overlay = grayed? MAKEARGB(96,48,0,0) : 0;
int x;
int w = SmallFont->StringWidth(label) * CleanXfac_1;
if (!mCentered) x = indent - w;
else x = (screen->GetWidth() - w) / 2;
screen->DrawText (SmallFont, color, x, y, label, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay, TAG_DONE);
}
void FOptionMenuDescriptor::CalcIndent()
{
// calculate the menu indent
int widest = 0, thiswidth;
for (unsigned i = 0; i < mItems.Size(); i++)
{
thiswidth = mItems[i]->GetIndent();
if (thiswidth > widest) widest = thiswidth;
}
mIndent = widest + 4;
}
//=============================================================================
//
//
//
//=============================================================================
FOptionMenuItem *FOptionMenuDescriptor::GetItem(FName name)
{
for(unsigned i=0;i<mItems.Size(); i++)
{
FName nm = mItems[i]->GetAction(NULL);
if (nm == name) return mItems[i];
}
return NULL;
}
class DGameplayMenu : public DOptionMenu
{
DECLARE_CLASS(DGameplayMenu, DOptionMenu)
public:
DGameplayMenu()
{}
void Drawer ()
{
Super::Drawer();
char text[64];
mysnprintf(text, 64, "dmflags = %d dmflags2 = %d", *dmflags, *dmflags2);
screen->DrawText (SmallFont, OptionSettings.mFontColorValue,
(screen->GetWidth() - SmallFont->StringWidth (text) * CleanXfac_1) / 2, 0, text,
DTA_CleanNoMove_1, true, TAG_DONE);
}
};
IMPLEMENT_CLASS(DGameplayMenu)
class DCompatibilityMenu : public DOptionMenu
{
DECLARE_CLASS(DCompatibilityMenu, DOptionMenu)
public:
DCompatibilityMenu()
{}
void Drawer ()
{
Super::Drawer();
char text[64];
mysnprintf(text, 64, "compatflags = %d", *compatflags);
screen->DrawText (SmallFont, OptionSettings.mFontColorValue,
(screen->GetWidth() - SmallFont->StringWidth (text) * CleanXfac_1) / 2, 0, text,
DTA_CleanNoMove_1, true, TAG_DONE);
}
};
IMPLEMENT_CLASS(DCompatibilityMenu)

916
src/menu/optionmenuitems.h Normal file
View File

@ -0,0 +1,916 @@
/*
** optionmenuitems.h
** Control items for option menus
**
**---------------------------------------------------------------------------
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
void M_DrawConText (int color, int x, int y, const char *str);
void M_DrawSlider (int x, int y, double min, double max, double cur,int fracdigits);
void M_SetVideoMode();
//=============================================================================
//
// opens a submenu, action is a submenu name
//
//=============================================================================
class FOptionMenuItemSubmenu : public FOptionMenuItem
{
int mParam;
public:
FOptionMenuItemSubmenu(const char *label, const char *menu, int param = 0)
: FOptionMenuItem(label, menu)
{
mParam = param;
}
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
{
drawLabel(indent, y, selected? OptionSettings.mFontColorSelection : OptionSettings.mFontColorMore);
return indent;
}
bool Activate()
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
M_SetMenu(mAction, mParam);
return true;
}
};
//=============================================================================
//
// Executes a CCMD, action is a CCMD name
//
//=============================================================================
class FOptionMenuItemCommand : public FOptionMenuItemSubmenu
{
public:
FOptionMenuItemCommand(const char *label, const char *menu)
: FOptionMenuItemSubmenu(label, menu)
{
}
bool Activate()
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
C_DoCommand(mAction);
return true;
}
};
//=============================================================================
//
// Executes a CCMD after confirmation, action is a CCMD name
//
//=============================================================================
class FOptionMenuItemSafeCommand : public FOptionMenuItemCommand
{
// action is a CCMD
public:
FOptionMenuItemSafeCommand(const char *label, const char *menu)
: FOptionMenuItemCommand(label, menu)
{
}
bool MenuEvent (int mkey, bool fromcontroller)
{
if (mkey == MKEY_MBYes)
{
C_DoCommand(mAction);
return true;
}
return FOptionMenuItemCommand::MenuEvent(mkey, fromcontroller);
}
bool Activate()
{
M_StartMessage("Do you really want to do this?", 0);
return true;
}
};
//=============================================================================
//
// Base class for option lists
//
//=============================================================================
class FOptionMenuItemOptionBase : public FOptionMenuItem
{
protected:
// action is a CVAR
FOptionValues *mValues;
FBaseCVar *mGrayCheck;
int mCenter;
public:
enum
{
OP_VALUES = 0x11001
};
FOptionMenuItemOptionBase(const char *label, const char *menu, const char *values, const char *graycheck, int center)
: FOptionMenuItem(label, menu)
{
FOptionValues **opt = OptionValues.CheckKey(values);
if (opt != NULL)
{
mValues = *opt;
}
else
{
mValues = NULL;
}
mGrayCheck = (FBoolCVar*)FindCVar(graycheck, NULL);
mCenter = center;
}
bool SetString(int i, const char *newtext)
{
if (i == OP_VALUES)
{
FOptionValues **opt = OptionValues.CheckKey(newtext);
if (opt != NULL)
{
mValues = *opt;
int s = GetSelection();
if (s >= (int)mValues->mValues.Size()) s = 0;
SetSelection(s); // readjust the CVAR if its value is outside the range now
return true;
}
}
return false;
}
//=============================================================================
virtual int GetSelection() = 0;
virtual void SetSelection(int Selection) = 0;
//=============================================================================
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
{
bool grayed = mGrayCheck != NULL && !(mGrayCheck->GetGenericRep(CVAR_Bool).Bool);
if (mCenter)
{
indent = (screen->GetWidth() / 2);
}
drawLabel(indent, y, selected? OptionSettings.mFontColorSelection : OptionSettings.mFontColor, grayed);
int overlay = grayed? MAKEARGB(96,48,0,0) : 0;
const char *text;
int Selection = GetSelection();
if (Selection < 0)
{
text = "Unknown";
}
else
{
text = mValues->mValues[Selection].Text;
}
screen->DrawText (SmallFont, OptionSettings.mFontColorValue, indent + CURSORSPACE, y,
text, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay, TAG_DONE);
return indent;
}
//=============================================================================
bool MenuEvent (int mkey, bool fromcontroller)
{
if (mValues->mValues.Size() > 0)
{
int Selection = GetSelection();
if (mkey == MKEY_Left)
{
if (Selection == -1) Selection = 0;
else if (--Selection < 0) Selection = mValues->mValues.Size()-1;
}
else if (mkey == MKEY_Right || mkey == MKEY_Enter)
{
if (++Selection >= (int)mValues->mValues.Size()) Selection = 0;
}
else
{
return FOptionMenuItem::MenuEvent(mkey, fromcontroller);
}
SetSelection(Selection);
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
}
return true;
}
bool Selectable()
{
return !(mGrayCheck != NULL && !(mGrayCheck->GetGenericRep(CVAR_Bool).Bool));
}
};
//=============================================================================
//
// Change a CVAR, action is the CVAR name
//
//=============================================================================
class FOptionMenuItemOption : public FOptionMenuItemOptionBase
{
// action is a CVAR
FBaseCVar *mCVar;
public:
FOptionMenuItemOption(const char *label, const char *menu, const char *values, const char *graycheck, int center)
: FOptionMenuItemOptionBase(label, menu, values, graycheck, center)
{
mCVar = FindCVar(mAction, NULL);
}
//=============================================================================
int GetSelection()
{
int Selection = -1;
if (mValues != NULL && mCVar != NULL && mValues->mValues.Size() > 0)
{
if (mValues->mValues[0].TextValue.IsEmpty())
{
UCVarValue cv = mCVar->GetGenericRep(CVAR_Float);
for(unsigned i=0;i<mValues->mValues.Size(); i++)
{
if (fabs(cv.Float - mValues->mValues[i].Value) < FLT_EPSILON)
{
Selection = i;
break;
}
}
}
else
{
UCVarValue cv = mCVar->GetGenericRep(CVAR_String);
for(unsigned i=0;i<mValues->mValues.Size(); i++)
{
if (mValues->mValues[i].TextValue.CompareNoCase(cv.String) == 0)
{
Selection = i;
break;
}
}
}
}
return Selection;
}
void SetSelection(int Selection)
{
UCVarValue value;
if (mValues != NULL && mCVar != NULL && mValues->mValues.Size() > 0)
{
if (mValues->mValues[0].TextValue.IsEmpty())
{
value.Float = (float)mValues->mValues[Selection].Value;
mCVar->SetGenericRep (value, CVAR_Float);
}
else
{
value.String = mValues->mValues[Selection].TextValue.LockBuffer();
mCVar->SetGenericRep (value, CVAR_String);
mValues->mValues[Selection].TextValue.UnlockBuffer();
}
}
}
};
//=============================================================================
//
// This class is used to capture the key to be used as the new key binding
// for a control item
//
//=============================================================================
class DEnterKey : public DMenu
{
DECLARE_CLASS(DEnterKey, DMenu)
int *pKey;
public:
DEnterKey(DMenu *parent, int *keyptr)
: DMenu(parent)
{
pKey = keyptr;
SetMenuMessage(1);
menuactive = MENU_WaitKey; // There should be a better way to disable GUI capture...
}
bool TranslateKeyboardEvents()
{
return false;
}
void SetMenuMessage(int which)
{
if (mParentMenu->IsKindOf(RUNTIME_CLASS(DOptionMenu)))
{
DOptionMenu *m = barrier_cast<DOptionMenu*>(mParentMenu);
FListMenuItem *it = m->GetItem(NAME_Controlmessage);
if (it != NULL)
{
it->SetValue(0, which);
}
}
}
bool Responder(event_t *ev)
{
if (ev->type == EV_KeyDown)
{
*pKey = ev->data1;
menuactive = MENU_On;
SetMenuMessage(0);
Close();
mParentMenu->MenuEvent((ev->data1 == KEY_ESCAPE)? MKEY_Abort : MKEY_Input, 0);
return true;
}
return false;
}
void Drawer()
{
mParentMenu->Drawer();
}
};
#ifndef NO_IMP
IMPLEMENT_ABSTRACT_CLASS(DEnterKey)
#endif
//=============================================================================
//
// // Edit a key binding, Action is the CCMD to bind
//
//=============================================================================
class FOptionMenuItemControl : public FOptionMenuItem
{
FKeyBindings *mBindings;
int mInput;
bool mWaiting;
public:
FOptionMenuItemControl(const char *label, const char *menu, FKeyBindings *bindings)
: FOptionMenuItem(label, menu)
{
mBindings = bindings;
mWaiting = false;
}
//=============================================================================
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
{
drawLabel(indent, y, mWaiting? OptionSettings.mFontColorHighlight:
(selected? OptionSettings.mFontColorSelection : OptionSettings.mFontColor));
char description[64];
int Key1, Key2;
mBindings->GetKeysForCommand(mAction, &Key1, &Key2);
C_NameKeys (description, Key1, Key2);
if (description[0])
{
M_DrawConText(CR_WHITE, indent + CURSORSPACE, y-1+OptionSettings.mLabelOffset, description);
}
else
{
screen->DrawText(SmallFont, CR_BLACK, indent + CURSORSPACE, y + OptionSettings.mLabelOffset, "---",
DTA_CleanNoMove_1, true, TAG_DONE);
}
return indent;
}
//=============================================================================
bool MenuEvent(int mkey, bool fromcontroller)
{
if (mkey == MKEY_Input)
{
mWaiting = false;
mBindings->SetBind(mInput, mAction);
return true;
}
else if (mkey == MKEY_Clear)
{
mBindings->UnbindACommand(mAction);
return true;
}
else if (mkey == MKEY_Abort)
{
mWaiting = false;
return true;
}
return false;
}
bool Activate()
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
mWaiting = true;
DMenu *input = new DEnterKey(DMenu::CurrentMenu, &mInput);
M_ActivateMenu(input);
return true;
}
};
//=============================================================================
//
//
//
//=============================================================================
class FOptionMenuItemStaticText : public FOptionMenuItem
{
EColorRange mColor;
public:
FOptionMenuItemStaticText(const char *label, bool header)
: FOptionMenuItem(label, NAME_None, true)
{
mColor = header? OptionSettings.mFontColorHeader : OptionSettings.mFontColor;
}
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
{
drawLabel(indent, y, mColor);
return -1;
}
bool Selectable()
{
return false;
}
};
//=============================================================================
//
//
//
//=============================================================================
class FOptionMenuItemStaticTextSwitchable : public FOptionMenuItem
{
EColorRange mColor;
FString mAltText;
int mCurrent;
public:
FOptionMenuItemStaticTextSwitchable(const char *label, const char *label2, FName action, bool header)
: FOptionMenuItem(label, action, true)
{
mColor = header? OptionSettings.mFontColorHeader : OptionSettings.mFontColor;
mAltText = label2;
mCurrent = 0;
}
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
{
const char *txt = mCurrent? (const char*)mAltText : mLabel;
int w = SmallFont->StringWidth(txt) * CleanXfac_1;
int x = (screen->GetWidth() - w) / 2;
screen->DrawText (SmallFont, mColor, x, y, txt, DTA_CleanNoMove_1, true, TAG_DONE);
return -1;
}
bool SetValue(int i, int val)
{
if (i == 0)
{
mCurrent = val;
return true;
}
return false;
}
bool SetString(int i, const char *newtext)
{
if (i == 0)
{
mAltText = newtext;
return true;
}
return false;
}
bool Selectable()
{
return false;
}
};
//=============================================================================
//
//
//
//=============================================================================
class FOptionMenuSliderBase : public FOptionMenuItem
{
// action is a CVAR
double mMin, mMax, mStep;
int mShowValue;
int mDrawX;
public:
FOptionMenuSliderBase(const char *label, double min, double max, double step, int showval)
: FOptionMenuItem(label, NAME_None)
{
mMin = min;
mMax = max;
mStep = step;
mShowValue = showval;
mDrawX = 0;
}
virtual double GetValue() = 0;
virtual void SetValue(double val) = 0;
//=============================================================================
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
{
drawLabel(indent, y, selected? OptionSettings.mFontColorSelection : OptionSettings.mFontColor);
mDrawX = indent + CURSORSPACE;
M_DrawSlider (mDrawX, y + OptionSettings.mLabelOffset, mMin, mMax, GetValue(), mShowValue);
return indent;
}
//=============================================================================
bool MenuEvent (int mkey, bool fromcontroller)
{
double value = GetValue();
if (mkey == MKEY_Left)
{
value -= mStep;
}
else if (mkey == MKEY_Right)
{
value += mStep;
}
else
{
return FOptionMenuItem::MenuEvent(mkey, fromcontroller);
}
SetValue(clamp(value, mMin, mMax));
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
return true;
}
bool MouseEvent(int type, int x, int y)
{
DOptionMenu *lm = static_cast<DOptionMenu*>(DMenu::CurrentMenu);
if (type != DMenu::MOUSE_Click)
{
if (!lm->CheckFocus(this)) return false;
}
if (type == DMenu::MOUSE_Release)
{
lm->ReleaseFocus();
}
int slide_left = mDrawX+8*CleanXfac_1;
int slide_right = slide_left + 10*8*CleanXfac_1; // 12 char cells with 8 pixels each.
if (type == DMenu::MOUSE_Click)
{
if (x < slide_left || x >= slide_right) return true;
}
x = clamp(x, slide_left, slide_right);
double v = mMin + ((x - slide_left) * (mMax - mMin)) / (slide_right - slide_left);
if (v != GetValue())
{
SetValue(v);
//S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
}
if (type == DMenu::MOUSE_Click)
{
lm->SetFocus(this);
}
return true;
}
};
//=============================================================================
//
//
//
//=============================================================================
class FOptionMenuSliderCVar : public FOptionMenuSliderBase
{
FBaseCVar *mCVar;
public:
FOptionMenuSliderCVar(const char *label, const char *menu, double min, double max, double step, int showval)
: FOptionMenuSliderBase(label, min, max, step, showval)
{
mCVar = FindCVar(menu, NULL);
}
double GetValue()
{
if (mCVar != NULL)
{
return mCVar->GetGenericRep(CVAR_Float).Float;
}
else
{
return 0;
}
}
void SetValue(double val)
{
if (mCVar != NULL)
{
UCVarValue value;
value.Float = (float)val;
mCVar->SetGenericRep(value, CVAR_Float);
}
}
};
//=============================================================================
//
//
//
//=============================================================================
class FOptionMenuSliderVar : public FOptionMenuSliderBase
{
float *mPVal;
public:
FOptionMenuSliderVar(const char *label, float *pVal, double min, double max, double step, int showval)
: FOptionMenuSliderBase(label, min, max, step, showval)
{
mPVal = pVal;
}
double GetValue()
{
return *mPVal;
}
void SetValue(double val)
{
*mPVal = (float)val;
}
};
//=============================================================================
//
// // Edit a key binding, Action is the CCMD to bind
//
//=============================================================================
class FOptionMenuItemColorPicker : public FOptionMenuItem
{
FColorCVar *mCVar;
public:
enum
{
CPF_RESET = 0x20001,
};
FOptionMenuItemColorPicker(const char *label, const char *menu)
: FOptionMenuItem(label, menu)
{
FBaseCVar *cv = FindCVar(menu, NULL);
if (cv->GetRealType() == CVAR_Color)
{
mCVar = (FColorCVar*)cv;
}
else mCVar = NULL;
}
//=============================================================================
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
{
drawLabel(indent, y, selected? OptionSettings.mFontColorSelection : OptionSettings.mFontColor);
if (mCVar != NULL)
{
int box_x = indent + CURSORSPACE;
int box_y = y + OptionSettings.mLabelOffset * CleanYfac_1 / 2;
screen->Clear (box_x, box_y, box_x + 32*CleanXfac_1, box_y + (SmallFont->GetHeight() - 1) * CleanYfac_1,
-1, (uint32)*mCVar | 0xff000000);
}
return indent;
}
bool SetValue(int i, int v)
{
if (i == CPF_RESET && mCVar != NULL)
{
mCVar->ResetToDefault();
return true;
}
return false;
}
bool Activate()
{
if (mCVar != NULL)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
DMenu *picker = StartPickerMenu(DMenu::CurrentMenu, mLabel, mCVar);
if (picker != NULL)
{
M_ActivateMenu(picker);
return true;
}
}
return false;
}
};
class FOptionMenuScreenResolutionLine : public FOptionMenuItem
{
FString mResTexts[3];
int mSelection;
int mHighlight;
int mMaxValid;
public:
enum
{
SRL_INDEX = 0x30000,
SRL_SELECTION = 0x30003,
SRL_HIGHLIGHT = 0x30004,
};
FOptionMenuScreenResolutionLine(const char *action)
: FOptionMenuItem("", action)
{
mSelection = 0;
mHighlight = -1;
}
bool SetValue(int i, int v)
{
if (i == SRL_SELECTION)
{
mSelection = v;
return true;
}
else if (i == SRL_HIGHLIGHT)
{
mHighlight = v;
return true;
}
return false;
}
bool GetValue(int i, int *v)
{
if (i == SRL_SELECTION)
{
*v = mSelection;
return true;
}
return false;
}
bool SetString(int i, const char *newtext)
{
if (i >= SRL_INDEX && i <= SRL_INDEX+2)
{
mResTexts[i-SRL_INDEX] = newtext;
if (mResTexts[0].IsEmpty()) mMaxValid = -1;
else if (mResTexts[1].IsEmpty()) mMaxValid = 0;
else if (mResTexts[2].IsEmpty()) mMaxValid = 1;
else mMaxValid = 2;
return true;
}
return false;
}
bool GetString(int i, char *s, int len)
{
if (i >= SRL_INDEX && i <= SRL_INDEX+2)
{
strncpy(s, mResTexts[i-SRL_INDEX], len-1);
s[len-1] = 0;
return true;
}
return false;
}
bool MenuEvent (int mkey, bool fromcontroller)
{
if (mkey == MKEY_Left)
{
if (--mSelection < 0) mSelection = mMaxValid;
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
return true;
}
else if (mkey == MKEY_Right)
{
if (++mSelection > mMaxValid) mSelection = 0;
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
return true;
}
else
{
return FOptionMenuItem::MenuEvent(mkey, fromcontroller);
}
return false;
}
bool MouseEvent(int type, int x, int y)
{
int colwidth = screen->GetWidth() / 3;
mSelection = x / colwidth;
return FOptionMenuItem::MouseEvent(type, x, y);
}
bool Activate()
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
M_SetVideoMode();
return true;
}
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
{
int colwidth = screen->GetWidth() / 3;
EColorRange color;
for (int x = 0; x < 3; x++)
{
if (selected && mSelection == x)
color = OptionSettings.mFontColorSelection;
else if (x == mHighlight)
color = OptionSettings.mFontColorHighlight;
else
color = OptionSettings.mFontColorValue;
screen->DrawText (SmallFont, color, colwidth * x + 20 * CleanXfac_1, y, mResTexts[x], DTA_CleanNoMove_1, true, TAG_DONE);
}
return colwidth * mSelection + 20 * CleanXfac_1 - CURSORSPACE;
}
bool Selectable()
{
return mMaxValid >= 0;
}
};
#ifndef NO_IMP
CCMD(am_restorecolors)
{
if (DMenu::CurrentMenu != NULL && DMenu::CurrentMenu->IsKindOf(RUNTIME_CLASS(DOptionMenu)))
{
DOptionMenu *m = (DOptionMenu*)DMenu::CurrentMenu;
const FOptionMenuDescriptor *desc = m->GetDescriptor();
// Find the color cvars by scanning the MapColors menu.
for (unsigned i = 0; i < desc->mItems.Size(); ++i)
{
desc->mItems[i]->SetValue(FOptionMenuItemColorPicker::CPF_RESET, 0);
}
}
}
#endif

561
src/menu/playerdisplay.cpp Normal file
View File

@ -0,0 +1,561 @@
/*
** playerdisplay.cpp
** The player display for the player setup and class selection screen
**
**---------------------------------------------------------------------------
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "doomtype.h"
#include "doomstat.h"
#include "d_player.h"
#include "tables.h"
#include "m_fixed.h"
#include "templates.h"
#include "menu/menu.h"
#include "colormatcher.h"
#include "textures/textures.h"
#include "w_wad.h"
#include "v_font.h"
#include "v_video.h"
#include "g_level.h"
#include "gi.h"
#include "r_defs.h"
#include "r_state.h"
//=============================================================================
//
// Used by the player display
//
//=============================================================================
struct FBackdropTexture : public FTexture
{
public:
FBackdropTexture();
const BYTE *GetColumn(unsigned int column, const Span **spans_out);
const BYTE *GetPixels();
void Unload();
bool CheckModified();
protected:
BYTE Pixels[144*160];
static const Span DummySpan[2];
int LastRenderTic;
angle_t time1, time2, time3, time4;
angle_t t1ang, t2ang, z1ang, z2ang;
void Render();
};
// A 32x32 cloud rendered with Photoshop, plus some other filters
static BYTE pattern1[1024] =
{
5, 9, 7,10, 9,15, 9, 7, 8,10, 5, 3, 5, 7, 9, 8,14, 8, 4, 7, 8, 9, 5, 7,14, 7, 0, 7,13,13, 9, 6,
2, 7, 9, 7, 7,10, 8, 8,11,10, 6, 7,10, 7, 5, 6, 6, 4, 7,13,15,16,11,15,11, 8, 0, 4,13,22,17,11,
5, 9, 9, 7, 9,10, 4, 3, 6, 7, 8, 6, 5, 4, 2, 2, 1, 4, 6,11,15,15,14,13,17, 9, 5, 9,11,12,17,20,
9,16, 9, 8,12,13, 7, 3, 7, 9, 5, 4, 2, 5, 5, 5, 7,11, 6, 7, 6,13,17,10,10, 9,12,17,14,12,16,15,
15,13, 5, 3, 9,10, 4,10,12,12, 7, 9, 8, 8, 8,10, 7, 6, 5, 5, 5, 6,11, 9, 3,13,16,18,21,16,23,18,
23,13, 0, 0, 0, 0, 0,12,18,14,15,16,13, 7, 7, 5, 9, 6, 6, 8, 4, 0, 0, 0, 0,14,19,17,14,20,21,25,
19,20,14,13, 7, 5,13,19,14,13,17,15,14, 7, 3, 5, 6,11, 7, 7, 8, 8,10, 9, 9,18,17,15,14,15,18,16,
16,29,24,23,18, 9,17,20,11, 5,12,15,15,12, 6, 3, 4, 6, 7,10,13,18,18,19,16,12,17,19,23,16,14,14,
9,18,20,26,19, 5,18,18,10, 5,12,15,14,17,11, 6,11, 9,10,13,10,20,24,20,21,20,14,18,15,22,20,19,
0, 6,16,18, 8, 7,15,18,10,13,17,17,13,11,15,11,19,12,13,10, 4,15,19,21,21,24,14, 9,17,20,24,17,
18,17, 7, 7,16,21,22,15, 5,14,20,14,13,21,13, 8,12,14, 7, 8,11,15,13,11,16,17, 7, 5,12,17,19,14,
25,23,17,16,23,18,15, 7, 0, 6,11, 6,11,15,11, 7,12, 7, 4,10,16,13, 7, 7,15,13, 9,15,21,14, 5, 0,
18,22,21,21,21,22,12, 6,14,20,15, 6,10,19,13, 8, 7, 3, 7,12,14,16, 9,12,22,15,12,18,24,19,17, 9,
0,15,18,21,17,25,14,13,19,21,21,11, 6,13,16,16,12,10,12,11,13,20,14,13,18,13, 9,15,16,25,31,20,
5,20,24,16, 7,14,14,11,18,19,19, 6, 0, 5,11,14,17,16,19,14,15,21,19,15,14,14, 8, 0, 7,24,18,16,
9,17,15, 7, 6,14,12, 7,14,16,11, 4, 7, 6,13,16,15,13,12,20,21,20,21,17,18,26,14, 0,13,23,21,11,
9,12,18,11,15,21,13, 8,13,13,10, 7,13, 8, 8,19,13, 7, 4,15,19,18,14,12,14,15, 8, 6,16,22,22,15,
9,17,14,19,15,14,15, 9,11, 9, 6, 8,14,13,13,12, 5, 0, 0, 6,12,13, 7, 7, 9, 7, 0,12,21,16,15,18,
15,16,18,11, 6, 8,15, 9, 2, 0, 5,10,10,16, 9, 0, 4,12,15, 9,12, 9, 7, 7,12, 7, 0, 6,12, 6, 9,13,
12,19,15,14,11, 7, 8, 9,12,10, 5, 5, 7,12,12,10,14,16,16,11, 8,12,10,12,10, 8,10,10,14,12,16,16,
16,17,20,22,12,15,12,14,19,11, 6, 5,10,13,17,17,21,19,15, 9, 6, 9,15,18,10,10,18,14,20,15,16,17,
11,19,19,18,19,14,17,13,12,12, 7,11,18,17,16,15,19,19,10, 2, 0, 8,15,12, 8,11,12,10,19,20,19,19,
6,14,18,13,13,16,16,12, 5, 8,10,12,10,13,18,12, 9,10, 7, 6, 5,11, 8, 6, 7,13,16,13,10,15,20,14,
0, 5,12,12, 4, 0, 9,16, 9,10,12, 8, 0, 9,13, 9, 0, 2, 4, 7,10, 6, 7, 3, 4,11,16,18,10,11,21,21,
16,13,11,15, 8, 0, 5, 9, 8, 7, 6, 3, 0, 9,17, 9, 0, 0, 0, 3, 5, 4, 3, 5, 7,15,16,16,17,14,22,22,
24,14,15,12, 9, 0, 5,10, 8, 4, 7,12,10,11,12, 7, 6, 8, 6, 5, 7, 8, 8,11,13,10,15,14,12,18,20,16,
16,17,17,18,12, 9,12,16,10, 5, 6,20,13,15, 8, 4, 8, 9, 8, 7, 9,11,12,17,16,16,11,10, 9,10, 5, 0,
0,14,18,18,15,16,14, 9,10, 9, 9,15,14,10, 4, 6,10, 8, 8, 7,10, 9,10,16,18,10, 0, 0, 7,12,10, 8,
0,14,19,14, 9,11,11, 8, 8,10,15, 9,10, 7, 4,10,13, 9, 7, 5, 5, 7, 7, 7,13,13, 5, 5,14,22,18,16,
0,10,14,10, 3, 6, 5, 6, 8, 9, 8, 9, 5, 9, 8, 9, 6, 8, 8, 8, 1, 0, 0, 0, 9,17,12,12,17,19,20,13,
6,11,17,11, 5, 5, 8,10, 6, 5, 6, 6, 3, 7, 9, 7, 6, 8,12,10, 4, 8, 6, 6,11,16,16,15,16,17,17,16,
11, 9,10,10, 5, 6,12,10, 5, 1, 6,10, 5, 3, 3, 5, 4, 7,15,10, 7,13, 7, 8,15,11,15,15,15, 8,11,15,
};
// Just a 32x32 cloud rendered with the standard Photoshop filter
static BYTE pattern2[1024] =
{
9, 9, 8, 8, 8, 8, 6, 6,13,13,11,21,19,21,23,18,23,24,19,19,24,17,18,12, 9,14, 8,12,12, 5, 8, 6,
11,10, 6, 7, 8, 8, 9,13,10,11,17,15,23,22,23,22,20,26,27,26,17,21,20,14,12, 8,11, 8,11, 7, 8, 7,
6, 9,13,13,10, 9,13, 7,12,13,16,19,16,20,22,25,22,25,27,22,21,23,15,10,14,14,15,13,12, 8,12, 6,
6, 7,12,12,12,16, 9,12,12,15,16,11,21,24,19,24,23,26,28,27,26,21,14,15, 7, 7,10,15,12,11,10, 9,
7,14,11,16,12,18,16,14,16,14,11,14,15,21,23,17,20,18,26,24,27,18,20,11,11,14,10,17,17,10, 6,10,
13, 9,14,10,13,11,14,15,18,15,15,12,19,19,20,18,22,20,19,22,19,19,19,20,17,15,15,11,16,14,10, 8,
13,16,12,16,17,19,17,18,15,19,14,18,15,14,15,17,21,19,23,18,23,22,18,18,17,15,15,16,12,12,15,10,
10,12,14,10,16,11,18,15,21,20,20,17,18,19,16,19,14,20,19,14,19,25,22,21,22,24,18,12, 9, 9, 8, 6,
10,10,13, 9,15,13,20,19,22,18,18,17,17,21,21,13,13,12,19,18,16,17,27,26,22,23,20,17,12,11, 8, 9,
7,13,14,15,11,13,18,22,19,23,23,20,22,24,21,14,12,16,17,19,18,18,22,18,24,23,19,17,16,14, 8, 7,
12,12, 8, 8,16,20,26,25,28,28,22,29,23,22,21,18,13,16,15,15,20,17,25,24,19,17,17,17,15,10, 8, 9,
7,12,15,11,17,20,25,25,25,29,30,31,28,26,18,16,17,18,20,21,22,20,23,19,18,19,10,16,16,11,11, 8,
5, 6, 8,14,14,17,17,21,27,23,27,31,27,22,23,21,19,19,21,19,20,19,17,22,13,17,12,15,10,10,12, 6,
8, 9, 8,14,15,16,15,18,27,26,23,25,23,22,18,21,20,17,19,20,20,16,20,14,15,13,12, 8, 8, 7,11,13,
7, 6,11,11,11,13,15,22,25,24,26,22,24,26,23,18,24,24,20,18,20,16,17,12,12,12,10, 8,11, 9, 6, 8,
9,10, 9, 6, 5,14,16,19,17,21,26,20,23,19,19,17,20,21,26,25,23,21,17,13,12, 5,13,11, 7,12,10,12,
6, 5, 4,10,11, 9,10,13,17,20,20,18,23,26,27,20,21,24,20,19,24,20,18,10,11, 3, 6,13, 9, 6, 8, 8,
1, 2, 2,11,13,13,11,16,16,16,19,21,20,23,22,28,21,20,19,18,23,16,18, 7, 5, 9, 7, 6, 5,10, 8, 8,
0, 0, 6, 9,11,15,12,12,19,18,19,26,22,24,26,30,23,22,22,16,20,19,12,12, 3, 4, 6, 5, 4, 7, 2, 4,
2, 0, 0, 7,11, 8,14,13,15,21,26,28,25,24,27,26,23,24,22,22,15,17,12, 8,10, 7, 7, 4, 0, 5, 0, 1,
1, 2, 0, 1, 9,14,13,10,19,24,22,29,30,28,30,30,31,23,24,19,17,14,13, 8, 8, 8, 1, 4, 0, 0, 0, 3,
5, 2, 4, 2, 9, 8, 8, 8,18,23,20,27,30,27,31,25,28,30,28,24,24,15,11,14,10, 3, 4, 3, 0, 0, 1, 3,
9, 3, 4, 3, 5, 6, 8,13,14,23,21,27,28,27,28,27,27,29,30,24,22,23,13,15, 8, 6, 2, 0, 4, 3, 4, 1,
6, 5, 5, 3, 9, 3, 6,14,13,16,23,26,28,23,30,31,28,29,26,27,21,20,15,15,13, 9, 1, 0, 2, 0, 5, 8,
8, 4, 3, 7, 2, 0,10, 7,10,14,21,21,29,28,25,27,30,28,25,24,27,22,19,13,10, 5, 0, 0, 0, 0, 0, 7,
7, 6, 7, 0, 2, 2, 5, 6,15,11,19,24,22,29,27,31,30,30,31,28,23,18,14,14, 7, 5, 0, 0, 1, 0, 1, 0,
5, 5, 5, 0, 0, 4, 5,11, 7,10,13,20,21,21,28,31,28,30,26,28,25,21, 9,12, 3, 3, 0, 2, 2, 2, 0, 1,
3, 3, 0, 2, 0, 3, 5, 3,11,11,16,19,19,27,26,26,30,27,28,26,23,22,16, 6, 2, 2, 3, 2, 0, 2, 4, 0,
0, 0, 0, 3, 3, 1, 0, 4, 5, 9,11,16,24,20,28,26,28,24,28,25,22,21,16, 5, 7, 5, 7, 3, 2, 3, 3, 6,
0, 0, 2, 0, 2, 0, 4, 3, 8,12, 9,17,16,23,23,27,27,22,26,22,21,21,13,14, 5, 3, 7, 3, 2, 4, 6, 1,
2, 5, 6, 4, 0, 1, 5, 8, 7, 6,15,17,22,20,24,28,23,25,20,21,18,16,13,15,13,10, 8, 5, 5, 9, 3, 7,
7, 7, 0, 5, 1, 6, 7, 9,12, 9,12,21,22,25,24,22,23,25,24,18,24,22,17,13,10, 9,10, 9, 6,11, 6, 5,
};
const FTexture::Span FBackdropTexture::DummySpan[2] = { { 0, 160 }, { 0, 0 } };
//=============================================================================
//
//
//
//=============================================================================
FBackdropTexture::FBackdropTexture()
{
Width = 144;
Height = 160;
WidthBits = 8;
HeightBits = 8;
WidthMask = 255;
LastRenderTic = 0;
time1 = ANGLE_1*180;
time2 = ANGLE_1*56;
time3 = ANGLE_1*99;
time4 = ANGLE_1*1;
t1ang = ANGLE_90;
t2ang = 0;
z1ang = 0;
z2ang = ANGLE_90/2;
}
//=============================================================================
//
//
//
//=============================================================================
bool FBackdropTexture::CheckModified()
{
return LastRenderTic != gametic;
}
void FBackdropTexture::Unload()
{
}
//=============================================================================
//
//
//
//=============================================================================
const BYTE *FBackdropTexture::GetColumn(unsigned int column, const Span **spans_out)
{
if (LastRenderTic != gametic)
{
Render();
}
column = clamp(column, 0u, 143u);
if (spans_out != NULL)
{
*spans_out = DummySpan;
}
return Pixels + column*160;
}
//=============================================================================
//
//
//
//=============================================================================
const BYTE *FBackdropTexture::GetPixels()
{
if (LastRenderTic != gametic)
{
Render();
}
return Pixels;
}
//=============================================================================
//
// This is one plasma and two rotozoomers. I think it turned out quite awesome.
//
//=============================================================================
void FBackdropTexture::Render()
{
BYTE *from;
int width, height, pitch;
width = 160;
height = 144;
pitch = width;
int x, y;
const angle_t a1add = ANGLE_1/2;
const angle_t a2add = ANGLE_MAX-ANGLE_1;
const angle_t a3add = ANGLE_1*5/7;
const angle_t a4add = ANGLE_MAX-ANGLE_1*4/3;
const angle_t t1add = ANGLE_MAX-ANGLE_1*2;
const angle_t t2add = ANGLE_MAX-ANGLE_1*3+ANGLE_1/6;
const angle_t t3add = ANGLE_1*16/7;
const angle_t t4add = ANGLE_MAX-ANGLE_1*2/3;
const angle_t x1add = 5<<ANGLETOFINESHIFT;
const angle_t x2add = ANGLE_MAX-(13<<ANGLETOFINESHIFT);
const angle_t z1add = 3<<ANGLETOFINESHIFT;
const angle_t z2add = 4<<ANGLETOFINESHIFT;
angle_t a1, a2, a3, a4;
fixed_t c1, c2, c3, c4;
DWORD tx, ty, tc, ts;
DWORD ux, uy, uc, us;
DWORD ltx, lty, lux, luy;
from = Pixels;
a3 = time3;
a4 = time4;
fixed_t z1 = (finecosine[z2ang>>ANGLETOFINESHIFT]>>2)+FRACUNIT/2;
fixed_t z2 = (finecosine[z1ang>>ANGLETOFINESHIFT]>>2)+FRACUNIT*3/4;
tc = MulScale5 (finecosine[t1ang>>ANGLETOFINESHIFT], z1);
ts = MulScale5 (finesine[t1ang>>ANGLETOFINESHIFT], z1);
uc = MulScale5 (finecosine[t2ang>>ANGLETOFINESHIFT], z2);
us = MulScale5 (finesine[t2ang>>ANGLETOFINESHIFT], z2);
ltx = -width/2*tc;
lty = -width/2*ts;
lux = -width/2*uc;
luy = -width/2*us;
for (y = 0; y < height; ++y)
{
a1 = time1;
a2 = time2;
c3 = finecosine[a3>>ANGLETOFINESHIFT];
c4 = finecosine[a4>>ANGLETOFINESHIFT];
tx = ltx - (y-height/2)*ts;
ty = lty + (y-height/2)*tc;
ux = lux - (y-height/2)*us;
uy = luy + (y-height/2)*uc;
for (x = 0; x < width; ++x)
{
c1 = finecosine[a1>>ANGLETOFINESHIFT];
c2 = finecosine[a2>>ANGLETOFINESHIFT];
from[x] = ((c1 + c2 + c3 + c4) >> (FRACBITS+3-7)) + 128 // plasma
+ pattern1[(tx>>27)+((ty>>22)&992)] // rotozoomer 1
+ pattern2[(ux>>27)+((uy>>22)&992)]; // rotozoomer 2
tx += tc;
ty += ts;
ux += uc;
uy += us;
a1 += a1add;
a2 += a2add;
}
a3 += a3add;
a4 += a4add;
from += pitch;
}
time1 += t1add;
time2 += t2add;
time3 += t3add;
time4 += t4add;
t1ang += x1add;
t2ang += x2add;
z1ang += z1add;
z2ang += z2add;
LastRenderTic = gametic;
}
//=============================================================================
//
//
//
//=============================================================================
FListMenuItemPlayerDisplay::FListMenuItemPlayerDisplay(FListMenuDescriptor *menu, int x, int y, PalEntry c1, PalEntry c2, bool np, FName action)
: FListMenuItem(x, y, action)
{
mOwner = menu;
for (int i = 0; i < 256; i++)
{
int r = c1.r + c2.r * i / 255;
int g = c1.g + c2.g * i / 255;
int b = c1.b + c2.b * i / 255;
mRemap.Remap[i] = ColorMatcher.Pick (r, g, b);
mRemap.Palette[i] = PalEntry(255, r, g, b);
}
mBackdrop = new FBackdropTexture;
mPlayerClass = NULL;
mPlayerState = NULL;
mNoportrait = np;
mMode = 0;
mRotation = 0;
mTranslate = false;
mSkin = 0;
mRandomClass = 0;
mRandomTimer = 0;
mClassNum = -1;
}
//=============================================================================
//
//
//
//=============================================================================
FListMenuItemPlayerDisplay::~FListMenuItemPlayerDisplay()
{
delete mBackdrop;
}
//=============================================================================
//
//
//
//=============================================================================
void FListMenuItemPlayerDisplay::UpdateRandomClass()
{
if (--mRandomTimer < 0)
{
if (++mRandomClass >= (int)PlayerClasses.Size ()) mRandomClass = 0;
mPlayerClass = &PlayerClasses[mRandomClass];
mPlayerState = GetDefaultByType (mPlayerClass->Type)->SeeState;
mPlayerTics = mPlayerState->GetTics();
mRandomTimer = 6;
}
}
//=============================================================================
//
//
//
//=============================================================================
void FListMenuItemPlayerDisplay::SetPlayerClass(int classnum, bool force)
{
if (classnum < 0 || classnum >= (int)PlayerClasses.Size ())
{
if (mClassNum != -1)
{
mClassNum = -1;
mRandomTimer = 0;
UpdateRandomClass();
}
}
else if (mPlayerClass != &PlayerClasses[classnum] || force)
{
mPlayerClass = &PlayerClasses[classnum];
mPlayerState = GetDefaultByType (mPlayerClass->Type)->SeeState;
mPlayerTics = mPlayerState->GetTics();
mClassNum = classnum;
}
}
//=============================================================================
//
//
//
//=============================================================================
bool FListMenuItemPlayerDisplay::UpdatePlayerClass()
{
int classnum;
FName seltype = mOwner->mItems[mOwner->mSelectedItem]->GetAction(&classnum);
if (seltype != NAME_Episodemenu) return false;
if (PlayerClasses.Size() == 0) return false;
SetPlayerClass(classnum);
return true;
}
//=============================================================================
//
//
//
//=============================================================================
bool FListMenuItemPlayerDisplay::SetValue(int i, int value)
{
switch (i)
{
case PDF_MODE:
mMode = value;
return true;
case PDF_ROTATION:
mRotation = value;
return true;
case PDF_TRANSLATE:
mTranslate = value;
case PDF_CLASS:
SetPlayerClass(value, true);
break;
case PDF_SKIN:
mSkin = value;
break;
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
void FListMenuItemPlayerDisplay::Ticker()
{
if (mClassNum < 0) UpdateRandomClass();
if (mPlayerState != NULL && mPlayerState->GetTics () != -1 && mPlayerState->GetNextState () != NULL)
{
if (--mPlayerTics <= 0)
{
mPlayerState = mPlayerState->GetNextState();
mPlayerTics = mPlayerState->GetTics();
}
}
}
//=============================================================================
//
//
//
//=============================================================================
void FListMenuItemPlayerDisplay::Drawer(bool selected)
{
if (mMode == 0 && !UpdatePlayerClass())
{
return;
}
const char *portrait = mPlayerClass->Type->Meta.GetMetaString(APMETA_Portrait);
if (portrait != NULL && !mNoportrait)
{
FTextureID texid = TexMan.CheckForTexture(portrait, FTexture::TEX_MiscPatch);
if (texid.isValid())
{
FTexture *tex = TexMan(texid);
if (tex != NULL)
{
screen->DrawTexture (tex, mXpos, mYpos, DTA_Clean, true, TAG_DONE);
return;
}
}
}
int x = (mXpos - 160) * CleanXfac + (SCREENWIDTH>>1);
int y = (mYpos - 100) * CleanYfac + (SCREENHEIGHT>>1);
screen->DrawTexture (mBackdrop, x, y - 1,
DTA_DestWidth, 72 * CleanXfac,
DTA_DestHeight, 80 * CleanYfac,
DTA_Translation, &mRemap,
DTA_Masked, true,
TAG_DONE);
V_DrawFrame (x, y, 72*CleanXfac, 80*CleanYfac-1);
spriteframe_t *sprframe;
fixed_t scaleX, scaleY;
if (mSkin == 0)
{
sprframe = &SpriteFrames[sprites[mPlayerState->sprite].spriteframes + mPlayerState->GetFrame()];
scaleX = GetDefaultByType(mPlayerClass->Type)->scaleX;
scaleY = GetDefaultByType(mPlayerClass->Type)->scaleY;
}
else
{
sprframe = &SpriteFrames[sprites[skins[mSkin].sprite].spriteframes + mPlayerState->GetFrame()];
scaleX = skins[mSkin].ScaleX;
scaleY = skins[mSkin].ScaleY;
}
if (sprframe != NULL)
{
FTexture *tex = TexMan(sprframe->Texture[mRotation]);
if (tex != NULL && tex->UseType != FTexture::TEX_Null)
{
FRemapTable *trans = NULL;
if (mTranslate) trans = translationtables[TRANSLATION_Players](MAXPLAYERS);
screen->DrawTexture (tex,
x + 36*CleanXfac, y + 71*CleanYfac,
DTA_DestWidth, MulScale16 (tex->GetWidth() * CleanXfac, scaleX),
DTA_DestHeight, MulScale16 (tex->GetHeight() * CleanYfac, scaleY),
DTA_Translation, trans,
TAG_DONE);
}
}
}

1142
src/menu/playermenu.cpp Normal file

File diff suppressed because it is too large Load Diff

154
src/menu/readthis.cpp Normal file
View File

@ -0,0 +1,154 @@
/*
** readthis.cpp
** Help screens
**
**---------------------------------------------------------------------------
** Copyright 2001-2010 Randy Heit
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "menu/menu.h"
#include "v_video.h"
#include "g_level.h"
#include "gi.h"
#include "textures/textures.h"
class DReadThisMenu : public DMenu
{
DECLARE_CLASS(DReadThisMenu, DMenu)
int mScreen;
int mInfoTic;
public:
DReadThisMenu(DMenu *parent = NULL);
void Drawer();
bool MenuEvent(int mkey, bool fromcontroller);
bool DimAllowed () { return false; }
bool MouseEvent(int type, int x, int y);
};
IMPLEMENT_CLASS(DReadThisMenu)
//=============================================================================
//
// Read This Menus
//
//=============================================================================
DReadThisMenu::DReadThisMenu(DMenu *parent)
: DMenu(parent)
{
mScreen = 1;
mInfoTic = gametic;
}
//=============================================================================
//
//
//
//=============================================================================
void DReadThisMenu::Drawer()
{
FTexture *tex = NULL, *prevpic = NULL;
fixed_t alpha;
// Did the mapper choose a custom help page via MAPINFO?
if ((level.info != NULL) && level.info->f1[0] != 0)
{
tex = TexMan.FindTexture(level.info->f1);
mScreen = 1;
}
if (tex == NULL)
{
tex = TexMan[gameinfo.infoPages[mScreen-1].GetChars()];
}
if (mScreen > 1)
{
prevpic = TexMan[gameinfo.infoPages[mScreen-2].GetChars()];
}
alpha = MIN<fixed_t> (Scale (gametic - mInfoTic, OPAQUE, TICRATE/3), OPAQUE);
if (alpha < OPAQUE && prevpic != NULL)
{
screen->DrawTexture (prevpic, 0, 0,
DTA_DestWidth, screen->GetWidth(),
DTA_DestHeight, screen->GetHeight(),
TAG_DONE);
}
screen->DrawTexture (tex, 0, 0,
DTA_DestWidth, screen->GetWidth(),
DTA_DestHeight, screen->GetHeight(),
DTA_Alpha, alpha,
TAG_DONE);
}
//=============================================================================
//
//
//
//=============================================================================
bool DReadThisMenu::MenuEvent(int mkey, bool fromcontroller)
{
if (mkey == MKEY_Enter)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
mScreen++;
mInfoTic = gametic;
if ((level.info != NULL && level.info->f1[0] != 0) || mScreen > int(gameinfo.infoPages.Size()))
{
Close();
}
return true;
}
else return Super::MenuEvent(mkey, fromcontroller);
}
//=============================================================================
//
//
//
//=============================================================================
bool DReadThisMenu::MouseEvent(int type, int x, int y)
{
if (type == MOUSE_Click)
{
return MenuEvent(MKEY_Enter, true);
}
return false;
}

442
src/menu/videomenu.cpp Normal file
View File

@ -0,0 +1,442 @@
/*
** videomenu.cpp
** The video modes menu
**
**---------------------------------------------------------------------------
** Copyright 2001-2010 Randy Heit
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include <float.h>
#include "menu/menu.h"
#include "c_dispatch.h"
#include "w_wad.h"
#include "sc_man.h"
#include "v_font.h"
#include "g_level.h"
#include "d_player.h"
#include "v_video.h"
#include "gi.h"
#include "i_system.h"
#include "c_bind.h"
#include "v_palette.h"
#include "d_event.h"
#include "d_gui.h"
#include "i_music.h"
#include "m_joy.h"
#include "sbar.h"
#include "hardware.h"
#define NO_IMP
#include "optionmenuitems.h"
/*=======================================
*
* Video Modes Menu
*
*=======================================*/
static void BuildModesList (int hiwidth, int hiheight, int hi_id);
static bool GetSelectedSize (int *width, int *height);
static void SetModesMenu (int w, int h, int bits);
FOptionMenuDescriptor *GetVideoModeMenu();
extern bool setmodeneeded;
extern int NewWidth, NewHeight, NewBits;
extern int DisplayBits;
EXTERN_CVAR (Int, vid_defwidth)
EXTERN_CVAR (Int, vid_defheight)
EXTERN_CVAR (Int, vid_defbits)
EXTERN_CVAR (Bool, fullscreen)
EXTERN_CVAR (Bool, vid_tft) // Defined below
int testingmode; // Holds time to revert to old mode
int OldWidth, OldHeight, OldBits;
static FIntCVar DummyDepthCvar (NULL, 0, 0);
static BYTE BitTranslate[32];
CUSTOM_CVAR (Int, menu_screenratios, 0, CVAR_ARCHIVE)
{
if (self < 0 || self > 4)
{
self = 3;
}
else if (self == 4 && !vid_tft)
{
self = 3;
}
else
{
BuildModesList (SCREENWIDTH, SCREENHEIGHT, DisplayBits);
}
}
CUSTOM_CVAR (Bool, vid_tft, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
FOptionMenuDescriptor *opt = GetVideoModeMenu();
if (opt != NULL)
{
FOptionMenuItem *it = opt->GetItem("menu_screenratios");
if (it != NULL)
{
if (self)
{
it->SetString(FOptionMenuItemOptionBase::OP_VALUES, "RatiosTFT");
}
else
{
it->SetString(FOptionMenuItemOptionBase::OP_VALUES, "Ratios");
}
}
}
setsizeneeded = true;
if (StatusBar != NULL)
{
StatusBar->ScreenSizeChanged();
}
}
//=============================================================================
//
//
//
//=============================================================================
class DVideoModeMenu : public DOptionMenu
{
DECLARE_CLASS(DVideoModeMenu, DOptionMenu)
public:
DVideoModeMenu()
{
SetModesMenu (SCREENWIDTH, SCREENHEIGHT, DisplayBits);
}
bool MenuEvent(int mkey, bool fromcontroller)
{
if ((mkey == MKEY_Up || mkey == MKEY_Down) && mDesc->mSelectedItem >= 0 &&
mDesc->mSelectedItem < (int)mDesc->mItems.Size())
{
int sel;
bool selected = mDesc->mItems[mDesc->mSelectedItem]->GetValue(FOptionMenuScreenResolutionLine::SRL_SELECTION, &sel);
bool res = Super::MenuEvent(mkey, fromcontroller);
if (selected) mDesc->mItems[mDesc->mSelectedItem]->SetValue(FOptionMenuScreenResolutionLine::SRL_SELECTION, sel);
return res;
}
return Super::MenuEvent(mkey, fromcontroller);
}
bool Responder(event_t *ev)
{
if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_KeyDown &&
(ev->data1 == 't' || ev->data1 == 'T'))
{
if (!GetSelectedSize (&NewWidth, &NewHeight))
{
NewWidth = SCREENWIDTH;
NewHeight = SCREENHEIGHT;
}
OldWidth = SCREENWIDTH;
OldHeight = SCREENHEIGHT;
OldBits = DisplayBits;
NewBits = BitTranslate[DummyDepthCvar];
setmodeneeded = true;
testingmode = I_GetTime(false) + 5 * TICRATE;
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
SetModesMenu (NewWidth, NewHeight, NewBits);
return true;
}
return Super::Responder(ev);
}
};
IMPLEMENT_CLASS(DVideoModeMenu)
//=============================================================================
//
//
//
//=============================================================================
FOptionMenuDescriptor *GetVideoModeMenu()
{
FMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_VideoModeMenu);
if (desc != NULL && (*desc)->mType == MDESC_OptionsMenu)
{
return (FOptionMenuDescriptor *)*desc;
}
return NULL;
}
//=============================================================================
//
// Set some stuff up for the video modes menu
//
//=============================================================================
static void BuildModesList (int hiwidth, int hiheight, int hi_bits)
{
char strtemp[32];
int i, c;
int width, height, showbits;
bool letterbox=false;
int ratiomatch;
if (menu_screenratios >= 0 && menu_screenratios <= 4 && menu_screenratios != 3)
{
ratiomatch = menu_screenratios;
}
else
{
ratiomatch = -1;
}
showbits = BitTranslate[DummyDepthCvar];
if (Video != NULL)
{
Video->StartModeIterator (showbits, screen->IsFullscreen());
}
FOptionMenuDescriptor *opt = GetVideoModeMenu();
if (opt != NULL)
{
for (i = NAME_res_0; i<= NAME_res_9; i++)
{
FOptionMenuItem *it = opt->GetItem((ENamedName)i);
if (it != NULL)
{
it->SetValue(FOptionMenuScreenResolutionLine::SRL_HIGHLIGHT, -1);
for (c = 0; c < 3; c++)
{
bool haveMode = false;
if (Video != NULL)
{
while ((haveMode = Video->NextMode (&width, &height, &letterbox)) &&
(ratiomatch >= 0 && CheckRatio (width, height) != ratiomatch))
{
}
}
if (haveMode)
{
if (width == hiwidth && height == hiheight)
{
it->SetValue(FOptionMenuScreenResolutionLine::SRL_SELECTION, c);
it->SetValue(FOptionMenuScreenResolutionLine::SRL_HIGHLIGHT, c);
}
mysnprintf (strtemp, countof(strtemp), "%dx%d%s", width, height, letterbox?TEXTCOLOR_BROWN" LB":"");
it->SetString(FOptionMenuScreenResolutionLine::SRL_INDEX+c, strtemp);
}
else
{
it->SetString(FOptionMenuScreenResolutionLine::SRL_INDEX+c, "");
}
}
}
}
}
}
//=============================================================================
//
//
//
//=============================================================================
void M_RestoreMode ()
{
NewWidth = OldWidth;
NewHeight = OldHeight;
NewBits = OldBits;
setmodeneeded = true;
testingmode = 0;
SetModesMenu (OldWidth, OldHeight, OldBits);
}
void M_SetDefaultMode ()
{
// Make current resolution the default
vid_defwidth = SCREENWIDTH;
vid_defheight = SCREENHEIGHT;
vid_defbits = DisplayBits;
testingmode = 0;
SetModesMenu (SCREENWIDTH, SCREENHEIGHT, DisplayBits);
}
//=============================================================================
//
//
//
//=============================================================================
void M_RefreshModesList ()
{
BuildModesList (SCREENWIDTH, SCREENHEIGHT, DisplayBits);
}
void M_InitVideoModesMenu ()
{
int dummy1, dummy2;
size_t currval = 0;
M_RefreshModesList();
for (unsigned int i = 1; i <= 32 && currval < countof(BitTranslate); i++)
{
Video->StartModeIterator (i, screen->IsFullscreen());
if (Video->NextMode (&dummy1, &dummy2, NULL))
{
BitTranslate[currval++] = i;
}
}
/* It doesn't look like this can be anything but DISPLAY_Both, regardless of any other settings.
switch (Video->GetDisplayType ())
{
case DISPLAY_FullscreenOnly:
case DISPLAY_WindowOnly:
// todo: gray out fullscreen option
default:
break;
}
*/
}
//=============================================================================
//
//
//
//=============================================================================
static bool GetSelectedSize (int *width, int *height)
{
FOptionMenuDescriptor *opt = GetVideoModeMenu();
if (opt != NULL)
{
int line = opt->mSelectedItem;
int hsel;
FOptionMenuItem *it = opt->mItems[line];
if (it->GetValue(FOptionMenuScreenResolutionLine::SRL_SELECTION, &hsel))
{
char buffer[32];
char *breakpt;
if (it->GetString(FOptionMenuScreenResolutionLine::SRL_INDEX+hsel, buffer, sizeof(buffer)))
{
*width = strtol (buffer, &breakpt, 10);
*height = strtol (breakpt+1, NULL, 10);
return true;
}
}
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
void M_SetVideoMode()
{
if (!GetSelectedSize (&NewWidth, &NewHeight))
{
NewWidth = SCREENWIDTH;
NewHeight = SCREENHEIGHT;
}
else
{
testingmode = 1;
setmodeneeded = true;
NewBits = BitTranslate[DummyDepthCvar];
}
SetModesMenu (NewWidth, NewHeight, NewBits);
}
//=============================================================================
//
//
//
//=============================================================================
static int FindBits (int bits)
{
int i;
for (i = 0; i < 22; i++)
{
if (BitTranslate[i] == bits)
return i;
}
return 0;
}
static void SetModesMenu (int w, int h, int bits)
{
DummyDepthCvar = FindBits (bits);
FOptionMenuDescriptor *opt = GetVideoModeMenu();
if (opt != NULL)
{
FOptionMenuItem *it;
if (testingmode <= 1)
{
it = opt->GetItem(NAME_VMEnterText);
if (it != NULL) it->SetValue(0, 0);
it = opt->GetItem(NAME_VMTestText);
if (it != NULL) it->SetValue(0, 0);
}
else
{
it = opt->GetItem(NAME_VMTestText);
if (it != NULL) it->SetValue(0, 1);
it = opt->GetItem(NAME_VMEnterText);
if (it != NULL)
{
char strtemp[64];
mysnprintf (strtemp, countof(strtemp), "TESTING %dx%dx%d", w, h, bits);
it->SetValue(0, 1);
it->SetString(0, strtemp);
}
}
}
BuildModesList (w, h, bits);
}

View File

@ -465,3 +465,64 @@ xx(Dialog)
xx(Ifitem)
xx(Choice)
xx(Link)
// Special menus
xx(Mainmenu)
xx(Episodemenu)
xx(Playerclassmenu)
xx(HexenDefaultPlayerclassmenu)
xx(Skillmenu)
xx(Startgame)
xx(StartgameConfirm)
xx(Loadgamemenu)
xx(Savegamemenu)
xx(Readthismenu)
xx(Optionsmenu)
xx(Quitmenu)
xx(Savemenu)
xx(Playermenu)
xx(Playerbox)
xx(Team)
xx(Color)
xx(Red)
xx(Green)
xx(Blue)
xx(Class)
xx(Skin)
xx(Gender)
xx(Autoaim)
xx(Switch)
xx(Playerdisplay)
xx(Controlmessage)
xx(Crosshairs)
xx(Colorpickermenu)
xx(Mididevices)
xx(CustomizeControls)
xx(MessageOptions)
xx(AutomapOptions)
xx(ScoreboardOptions)
xx(MapColorMenu)
xx(GameplayOptions)
xx(CompatibilityOptions)
xx(MouseOptions)
xx(JoystickOptions)
xx(SoundOptions)
xx(AdvSoundOptions)
xx(ModReplayerOptions)
xx(VideoOptions)
xx(JoystickConfigMenu)
xx(VMEnterText)
xx(VMTestText)
xx(VideoModeMenu)
xx(res_0)
xx(res_1)
xx(res_2)
xx(res_3)
xx(res_4)
xx(res_5)
xx(res_6)
xx(res_7)
xx(res_8)
xx(res_9)
xx(AlwaysRun)

View File

@ -41,7 +41,6 @@
#include "w_wad.h"
#include "cmdlib.h"
#include "s_sound.h"
#include "m_menu.h"
#include "v_text.h"
#include "v_video.h"
#include "m_random.h"
@ -56,11 +55,13 @@
#include "d_net.h"
#include "g_level.h"
#include "d_event.h"
#include "d_gui.h"
#include "doomstat.h"
#include "c_console.h"
#include "sbar.h"
#include "farchive.h"
#include "p_lnspec.h"
#include "menu/menu.h"
// The conversations as they exist inside a SCRIPTxx lump.
struct Response
@ -112,9 +113,8 @@ typedef TMap<FName, int> FDialogueMap; // maps actor class names to dialogue
static FStrifeTypeMap StrifeTypes;
static FDialogueIDMap DialogueRoots;
static FDialogueMap ClassRoots;
static int ConversationMenuY;
static menu_t ConversationMenu;
static TArray<menuitem_t> ConversationItems;
static int ConversationPauseTic;
static bool ShowGold;
@ -123,13 +123,11 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker
static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeakerType);
static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses);
static bool DrawConversationMenu ();
static void PickConversationReply ();
static void PickConversationReply (int replyindex);
static void CleanupConversationMenu ();
static void ConversationMenuEscaped ();
static void TerminalResponse (const char *str);
static FStrifeDialogueNode *CurNode, *PrevNode;
static FBrokenLines *DialogueLines;
static FStrifeDialogueNode *PrevNode;
#define NUM_RANDOM_LINES 10
#define NUM_RANDOM_GOODBYES 3
@ -233,7 +231,6 @@ void P_FreeStrifeConversations ()
DialogueRoots.Clear();
ClassRoots.Clear();
CurNode = NULL;
PrevNode = NULL;
}
@ -541,10 +538,6 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses)
reply->ItemCheck[k].Amount = rsp->Count[k];
}
// ReplyLines is calculated when the menu is shown. It is just Reply
// with word wrap turned on.
reply->ReplyLines = NULL;
// If the first item check has a positive amount required, then
// add that to the reply string. Otherwise, use the reply as-is.
if (rsp->Count[0] > 0)
@ -615,7 +608,6 @@ FStrifeDialogueReply::~FStrifeDialogueReply ()
if (Reply != NULL) delete[] Reply;
if (QuickYes != NULL) delete[] QuickYes;
if (QuickNo != NULL) delete[] QuickNo;
if (ReplyLines != NULL) V_FreeBrokenLines (ReplyLines);
}
//============================================================================
@ -703,6 +695,372 @@ CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE)
else if (self > 1.f) self = 1.f;
}
//============================================================================
//
// The conversation menu
//
//============================================================================
class DConversationMenu : public DMenu
{
DECLARE_CLASS(DConversationMenu, DMenu)
FString mSpeaker;
FBrokenLines *mDialogueLines;
TArray<FString> mResponseLines;
TArray<unsigned int> mResponses;
bool mShowGold;
FStrifeDialogueNode *mCurNode;
int mYpos;
public:
static int mSelection;
//=============================================================================
//
//
//
//=============================================================================
DConversationMenu(FStrifeDialogueNode *CurNode)
{
menuactive = MENU_OnNoPause;
mCurNode = CurNode;
mDialogueLines = NULL;
mShowGold = false;
// Format the speaker's message.
const char * toSay = CurNode->Dialogue;
if (strncmp (toSay, "RANDOM_", 7) == 0)
{
FString dlgtext;
dlgtext.Format("TXT_%s_%02d", toSay, 1+(pr_randomspeech() % NUM_RANDOM_LINES));
toSay = GStrings[dlgtext];
if (toSay == NULL)
{
toSay = "Go away!"; // Ok, it's lame - but it doesn't look like an error to the player. ;)
}
}
else
{
// handle string table replacement
if (toSay[0] == '$')
{
toSay = GStrings(toSay + 1);
}
}
if (toSay == NULL)
{
toSay = ".";
}
mDialogueLines = V_BreakLines (SmallFont, screen->GetWidth()/CleanXfac - 24*2, toSay);
FStrifeDialogueReply *reply;
int i,j;
for (reply = CurNode->Children, i = 1; reply != NULL; reply = reply->Next)
{
if (reply->Reply == NULL)
{
continue;
}
mShowGold |= reply->NeedsGold;
const char *ReplyText = reply->Reply;
if (ReplyText[0] == '$')
{
ReplyText = GStrings(ReplyText + 1);
}
FBrokenLines *ReplyLines = V_BreakLines (SmallFont, 320-50-10, ReplyText);
mResponses.Push(mResponseLines.Size());
for (j = 0; ReplyLines[j].Width >= 0; ++j)
{
mResponseLines.Push(ReplyLines[j].Text);
}
++i;
V_FreeBrokenLines (ReplyLines);
}
char goodbye[25];
mysnprintf(goodbye, countof(goodbye), "TXT_RANDOMGOODBYE_%d", 1+(pr_randomspeech() % NUM_RANDOM_GOODBYES));
const char *goodbyestr = GStrings[goodbye];
if (goodbyestr == NULL) goodbyestr = "Bye.";
mResponses.Push(mResponseLines.Size());
mResponseLines.Push(FString(goodbyestr));
// Determine where the top of the reply list should be positioned.
i = OptionSettings.mLinespacing;
mYpos = MIN<int> (140, 192 - mResponseLines.Size() * i);
for (i = 0; mDialogueLines[i].Width >= 0; ++i)
{ }
i = 44 + i * 10;
if (mYpos - 100 < i - screen->GetHeight() / CleanYfac / 2)
{
mYpos = i - screen->GetHeight() / CleanYfac / 2 + 100;
}
ConversationMenuY = mYpos;
//ConversationMenu.indent = 50;
}
//=============================================================================
//
//
//
//=============================================================================
void Destroy()
{
V_FreeBrokenLines(mDialogueLines);
mDialogueLines = NULL;
I_SetMusicVolume (1.f);
}
bool DimAllowed()
{
return false;
}
//=============================================================================
//
//
//
//=============================================================================
bool MenuEvent(int mkey, bool fromcontroller)
{
if (mkey == MKEY_Up)
{
if (--mSelection < 0) mSelection = mResponses.Size() - 1;
return true;
}
else if (mkey == MKEY_Down)
{
if (++mSelection >= (int)mResponses.Size()) mSelection = 0;
return true;
}
else if (mkey == MKEY_Back)
{
Close();
return true;
}
else if (mkey == MKEY_Enter)
{
if ((unsigned)mSelection >= mResponses.Size())
{
Net_WriteByte(DEM_CONVCLOSE);
}
else
{
// Send dialogue and reply numbers across the wire.
assert((unsigned)mCurNode->ThisNodeNum < StrifeDialogues.Size());
assert(StrifeDialogues[mCurNode->ThisNodeNum] == mCurNode);
Net_WriteByte(DEM_CONVREPLY);
Net_WriteWord(mCurNode->ThisNodeNum);
Net_WriteByte(mSelection);
}
Close();
return true;
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
bool MouseEvent(int type, int x, int y)
{
int sel = -1;
int fh = SmallFont->GetHeight();
// convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture
x = ((x - (screen->GetWidth() / 2)) / CleanXfac) + 160;
y = ((y - (screen->GetHeight() / 2)) / CleanYfac) + 100;
if (x >= 24 && x <= 320-24 && y >= mYpos && y < mYpos + fh * (int)mResponseLines.Size())
{
sel = (y - mYpos) / fh;
for(unsigned i=0;i<mResponses.Size(); i++)
{
if ((int)mResponses[i] > sel)
{
sel = i-1;
break;
}
}
}
if (sel != -1 && sel != mSelection)
{
//S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
}
mSelection = sel;
if (type == MOUSE_Release)
{
return MenuEvent(MKEY_Enter, true);
}
return true;
}
//=============================================================================
//
//
//
//=============================================================================
bool Responder(event_t *ev)
{
if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_Char && ev->data1 >= '0' && ev->data1 <= '9')
{ // Activate an item of type numberedmore (dialogue only)
mSelection = ev->data1 == '0' ? 10 : ev->data1 - '0';
return MenuEvent(MKEY_Enter, false);
}
return Super::Responder(ev);
}
//============================================================================
//
// DrawConversationMenu
//
//============================================================================
void Drawer()
{
const char *speakerName;
int i, x, y, linesize;
int width, fontheight;
int labelofs;
player_t *cp = &players[consoleplayer];
assert (mDialogueLines != NULL);
assert (mCurNode != NULL);
FStrifeDialogueNode *CurNode = mCurNode;
if (CurNode == NULL)
{
Close ();
return;
}
// [CW] Freeze the game depending on MAPINFO options.
if (ConversationPauseTic < gametic && !multiplayer && !(level.flags2 & LEVEL2_CONV_SINGLE_UNFREEZE))
{
menuactive = MENU_On;
}
if (CurNode->Backdrop.isValid())
{
screen->DrawTexture (TexMan(CurNode->Backdrop), 0, 0, DTA_320x200, true, TAG_DONE);
}
x = 16 * screen->GetWidth() / 320;
y = 16 * screen->GetHeight() / 200;
linesize = 10 * CleanYfac;
// Who is talking to you?
if (CurNode->SpeakerName != NULL)
{
speakerName = CurNode->SpeakerName;
}
else
{
speakerName = cp->ConversationNPC->GetTag("Person");
}
// Dim the screen behind the dialogue (but only if there is no backdrop).
if (!CurNode->Backdrop.isValid())
{
for (i = 0; mDialogueLines[i].Width >= 0; ++i)
{ }
screen->Dim (0, 0.45f, 14 * screen->GetWidth() / 320, 13 * screen->GetHeight() / 200,
308 * screen->GetWidth() / 320 - 14 * screen->GetWidth () / 320,
speakerName == NULL ? linesize * i + 6 * CleanYfac
: linesize * i + 6 * CleanYfac + linesize * 3/2);
}
// Dim the screen behind the PC's choices.
screen->Dim (0, 0.45f, (24-160) * CleanXfac + screen->GetWidth()/2,
(mYpos - 2 - 100) * CleanYfac + screen->GetHeight()/2,
272 * CleanXfac,
MIN<int>(mResponseLines.Size() * OptionSettings.mLinespacing + 4, 200 - mYpos) * CleanYfac);
if (speakerName != NULL)
{
screen->DrawText (SmallFont, CR_WHITE, x, y, speakerName,
DTA_CleanNoMove, true, TAG_DONE);
y += linesize * 3 / 2;
}
x = 24 * screen->GetWidth() / 320;
for (i = 0; mDialogueLines[i].Width >= 0; ++i)
{
screen->DrawText (SmallFont, CR_UNTRANSLATED, x, y, mDialogueLines[i].Text,
DTA_CleanNoMove, true, TAG_DONE);
y += linesize;
}
if (ShowGold)
{
AInventory *coin = cp->ConversationPC->FindInventory (RUNTIME_CLASS(ACoin));
char goldstr[32];
mysnprintf (goldstr, countof(goldstr), "%d", coin != NULL ? coin->Amount : 0);
screen->DrawText (SmallFont, CR_GRAY, 21, 191, goldstr, DTA_320x200, true,
DTA_FillColor, 0, DTA_Alpha, HR_SHADOW, TAG_DONE);
screen->DrawTexture (TexMan(((AInventory *)GetDefaultByType (RUNTIME_CLASS(ACoin)))->Icon),
3, 190, DTA_320x200, true,
DTA_FillColor, 0, DTA_Alpha, HR_SHADOW, TAG_DONE);
screen->DrawText (SmallFont, CR_GRAY, 20, 190, goldstr, DTA_320x200, true, TAG_DONE);
screen->DrawTexture (TexMan(((AInventory *)GetDefaultByType (RUNTIME_CLASS(ACoin)))->Icon),
2, 189, DTA_320x200, true, TAG_DONE);
}
y = mYpos;
labelofs = OptionSettings.mLabelOffset;
y -= labelofs;
fontheight = OptionSettings.mLinespacing;
int response = 0;
for (i = 0; i < (int)mResponseLines.Size(); i++, y += fontheight)
{
width = SmallFont->StringWidth(mResponseLines[i]);
x = 64;
screen->DrawText (SmallFont, CR_GREEN, x, y, mResponseLines[i], DTA_Clean, true, TAG_DONE);
if (i == mResponses[response])
{
char tbuf[16];
response++;
mysnprintf (tbuf, countof(tbuf), "%d.", response);
x = 50 - SmallFont->StringWidth (tbuf);
screen->DrawText (SmallFont, CR_GREY, x, y, tbuf, DTA_Clean, true, TAG_DONE);
if (response == mSelection+1)
{
int color = ((DMenu::MenuTime%8) < 4) || DMenu::CurrentMenu != this ? CR_RED:CR_GREY;
x = (50 + 3 - 160) * CleanXfac + screen->GetWidth() / 2;
int yy = (y-1+labelofs - 100) * CleanYfac + screen->GetHeight() / 2;
screen->DrawText (ConFont, color, x, yy, "\xd",
DTA_CellX, 8 * CleanXfac,
DTA_CellY, 8 * CleanYfac,
TAG_DONE);
}
}
}
}
};
IMPLEMENT_ABSTRACT_CLASS(DConversationMenu)
int DConversationMenu::mSelection; // needs to be preserved if the same dialogue is restarted
//============================================================================
//
// P_StartConversation
@ -714,10 +1072,7 @@ CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE)
void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveangle)
{
AActor *oldtarget;
FStrifeDialogueReply *reply;
menuitem_t item;
const char *toSay;
int i, j;
int i;
// Make sure this is actually a player.
if (pc->player == NULL) return;
@ -798,102 +1153,19 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
S_Sound (npc, CHAN_VOICE|CHAN_NOPAUSE, CurNode->SpeakerVoice, 1, ATTN_NORM);
}
// Set up the menu
::CurNode = CurNode; // only set the global variable for the consoleplayer
ConversationMenu.PreDraw = DrawConversationMenu;
ConversationMenu.EscapeHandler = ConversationMenuEscaped;
DConversationMenu *cmenu = new DConversationMenu(CurNode);
// Format the speaker's message.
toSay = CurNode->Dialogue;
if (strncmp (toSay, "RANDOM_", 7) == 0)
{
FString dlgtext;
dlgtext.Format("TXT_%s_%02d", toSay, 1+(pr_randomspeech() % NUM_RANDOM_LINES));
toSay = GStrings[dlgtext];
if (toSay == NULL)
{
toSay = "Go away!"; // Ok, it's lame - but it doesn't look like an error to the player. ;)
}
}
else
{
// handle string table replacement
if (toSay[0] == '$')
{
toSay = GStrings(toSay + 1);
}
}
if (toSay == NULL)
{
toSay = ".";
}
DialogueLines = V_BreakLines (SmallFont, screen->GetWidth()/CleanXfac - 24*2, toSay);
// Fill out the possible choices
ShowGold = false;
item.type = numberedmore;
item.e.mfunc = PickConversationReply;
for (reply = CurNode->Children, i = 1; reply != NULL; reply = reply->Next)
{
if (reply->Reply == NULL)
{
continue;
}
ShowGold |= reply->NeedsGold;
reply->ReplyLines = V_BreakLines (SmallFont, 320-50-10, reply->Reply);
for (j = 0; reply->ReplyLines[j].Width >= 0; ++j)
{
item.label = reply->ReplyLines[j].Text.LockBuffer();
// handle string table replacement
if (item.label[0] == '$')
{
item.label = GStrings(item.label + 1);
}
item.b.position = j == 0 ? i : 0;
item.c.extra = reply;
ConversationItems.Push (item);
}
++i;
}
char goodbye[25];
mysnprintf(goodbye, countof(goodbye), "TXT_RANDOMGOODBYE_%d", 1+(pr_randomspeech() % NUM_RANDOM_GOODBYES));
item.label = (char*)GStrings[goodbye];
if (item.label == NULL) item.label = "Bye.";
item.b.position = i;
item.c.extra = NULL;
ConversationItems.Push (item);
// Determine where the top of the reply list should be positioned.
i = (gameinfo.gametype & GAME_Raven) ? 9 : 8;
ConversationMenu.y = MIN<int> (140, 192 - ConversationItems.Size() * i);
for (i = 0; DialogueLines[i].Width >= 0; ++i)
{ }
i = 44 + i * 10;
if (ConversationMenu.y - 100 < i - screen->GetHeight() / CleanYfac / 2)
{
ConversationMenu.y = i - screen->GetHeight() / CleanYfac / 2 + 100;
}
ConversationMenu.indent = 50;
// Finish setting up the menu
ConversationMenu.items = &ConversationItems[0];
ConversationMenu.numitems = ConversationItems.Size();
if (CurNode != PrevNode)
{ // Only reset the selection if showing a different menu.
ConversationMenu.lastOn = 0;
DConversationMenu::mSelection = 0;
PrevNode = CurNode;
}
ConversationMenu.DontDim = true;
// And open the menu
M_StartControlPanel (false);
OptionsActive = true;
menuactive = MENU_OnNoPause;
M_ActivateMenu(cmenu);
ConversationPauseTic = gametic + 20;
M_SwitchMenu (&ConversationMenu);
}
}
@ -921,193 +1193,6 @@ void P_ResumeConversation ()
}
}
//============================================================================
//
// DrawConversationMenu
//
//============================================================================
static bool DrawConversationMenu ()
{
const char *speakerName;
int i, x, y, linesize;
int width, fontheight;
menuitem_t *item;
int labelofs;
player_t *cp = &players[consoleplayer];
assert (DialogueLines != NULL);
assert (CurNode != NULL);
if (CurNode == NULL)
{
M_ClearMenus ();
return true;
}
// [CW] Freeze the game depending on MAPINFO options.
if (ConversationPauseTic < gametic && !multiplayer && !(level.flags2 & LEVEL2_CONV_SINGLE_UNFREEZE))
{
menuactive = MENU_On;
}
if (CurNode->Backdrop.isValid())
{
screen->DrawTexture (TexMan(CurNode->Backdrop), 0, 0, DTA_320x200, true, TAG_DONE);
}
x = 16 * screen->GetWidth() / 320;
y = 16 * screen->GetHeight() / 200;
linesize = 10 * CleanYfac;
// Who is talking to you?
if (CurNode->SpeakerName != NULL)
{
speakerName = CurNode->SpeakerName;
}
else
{
speakerName = cp->ConversationNPC->GetTag("Person");
}
// Dim the screen behind the dialogue (but only if there is no backdrop).
if (!CurNode->Backdrop.isValid())
{
for (i = 0; DialogueLines[i].Width >= 0; ++i)
{ }
screen->Dim (0, 0.45f, 14 * screen->GetWidth() / 320, 13 * screen->GetHeight() / 200,
308 * screen->GetWidth() / 320 - 14 * screen->GetWidth () / 320,
speakerName == NULL ? linesize * i + 6 * CleanYfac
: linesize * i + 6 * CleanYfac + linesize * 3/2);
}
// Dim the screen behind the PC's choices.
screen->Dim (0, 0.45f, (24-160) * CleanXfac + screen->GetWidth()/2,
(ConversationMenu.y - 2 - 100) * CleanYfac + screen->GetHeight()/2,
272 * CleanXfac,
MIN(ConversationMenu.numitems * (gameinfo.gametype & GAME_Raven ? 9 : 8) + 4,
200 - ConversationMenu.y) * CleanYfac);
if (speakerName != NULL)
{
screen->DrawText (SmallFont, CR_WHITE, x, y, speakerName,
DTA_CleanNoMove, true, TAG_DONE);
y += linesize * 3 / 2;
}
x = 24 * screen->GetWidth() / 320;
for (i = 0; DialogueLines[i].Width >= 0; ++i)
{
screen->DrawText (SmallFont, CR_UNTRANSLATED, x, y, DialogueLines[i].Text,
DTA_CleanNoMove, true, TAG_DONE);
y += linesize;
}
if (ShowGold)
{
AInventory *coin = cp->ConversationPC->FindInventory (RUNTIME_CLASS(ACoin));
char goldstr[32];
mysnprintf (goldstr, countof(goldstr), "%d", coin != NULL ? coin->Amount : 0);
screen->DrawText (SmallFont, CR_GRAY, 21, 191, goldstr, DTA_320x200, true,
DTA_FillColor, 0, DTA_Alpha, HR_SHADOW, TAG_DONE);
screen->DrawTexture (TexMan(((AInventory *)GetDefaultByType (RUNTIME_CLASS(ACoin)))->Icon),
3, 190, DTA_320x200, true,
DTA_FillColor, 0, DTA_Alpha, HR_SHADOW, TAG_DONE);
screen->DrawText (SmallFont, CR_GRAY, 20, 190, goldstr, DTA_320x200, true, TAG_DONE);
screen->DrawTexture (TexMan(((AInventory *)GetDefaultByType (RUNTIME_CLASS(ACoin)))->Icon),
2, 189, DTA_320x200, true, TAG_DONE);
}
y = CurrentMenu->y;
if (gameinfo.gametype & GAME_Raven)
{
labelofs = 2;
y -= 2;
fontheight = 9;
}
else
{
labelofs = 0;
fontheight = 8;
}
for (i = 0; i < CurrentMenu->numitems; i++, y += fontheight)
{
item = CurrentMenu->items + i;
width = SmallFont->StringWidth(item->label);
x = CurrentMenu->indent + 14;
screen->DrawText (SmallFont, CR_GREEN, x, y, item->label, DTA_Clean, true, TAG_DONE);
if (item->b.position != 0)
{
char tbuf[16];
mysnprintf (tbuf, countof(tbuf), "%d.", item->b.position);
x = CurrentMenu->indent - SmallFont->StringWidth (tbuf);
screen->DrawText (SmallFont, CR_GREY, x, y, tbuf, DTA_Clean, true, TAG_DONE);
}
if (i == CurrentItem &&
(skullAnimCounter < 6 || menuactive == MENU_WaitKey))
{
int x = (CurrentMenu->indent + 3 - 160) * CleanXfac + screen->GetWidth() / 2;
int yy = (y-1+labelofs - 100) * CleanYfac + screen->GetHeight() / 2;
screen->DrawText (ConFont, CR_RED, x, yy, "\xd",
DTA_CellX, 8 * CleanXfac,
DTA_CellY, 8 * CleanYfac,
TAG_DONE);
}
}
return true;
}
//============================================================================
//
// PickConversationReply
//
// Run only on the local machine with the conversation menu up.
//
//============================================================================
static void PickConversationReply ()
{
FStrifeDialogueReply *reply = (FStrifeDialogueReply *)ConversationItems[ConversationMenu.lastOn].c.extra;
FStrifeDialogueReply *replyscan;
int replynum = 0;
assert(CurNode->ThisNodeNum >= 0 && CurNode->ThisNodeNum < 65536);
assert(StrifeDialogues[CurNode->ThisNodeNum] == CurNode);
// Determine reply number for netcode.
if (reply == NULL)
{
replyscan = NULL;
}
else
{
for (replyscan = CurNode->Children; replyscan != NULL && replyscan != reply; ++replynum, replyscan = replyscan->Next)
{ }
}
M_ClearMenus ();
if (replyscan == NULL)
{
Net_WriteByte(DEM_CONVCLOSE);
}
else
{
// Send dialogue and reply numbers across the wire.
assert(replynum < 256);
Net_WriteByte(DEM_CONVREPLY);
Net_WriteWord(CurNode->ThisNodeNum);
Net_WriteByte(replynum);
}
CleanupConversationMenu ();
}
//============================================================================
//
// HandleReply
@ -1307,27 +1392,6 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply
void CleanupConversationMenu ()
{
FStrifeDialogueReply *reply;
if (CurNode != NULL)
{
for (reply = CurNode->Children; reply != NULL; reply = reply->Next)
{
if (reply->ReplyLines != NULL)
{
V_FreeBrokenLines (reply->ReplyLines);
reply->ReplyLines = NULL;
}
}
CurNode = NULL;
}
if (DialogueLines != NULL)
{
V_FreeBrokenLines (DialogueLines);
DialogueLines = NULL;
}
ConversationItems.Clear ();
I_SetMusicVolume (1.f);
}
//============================================================================
@ -1408,7 +1472,7 @@ static void TerminalResponse (const char *str)
// their dialogue screen. I think most other conversations use this
// only as a response for terminating the dialogue.
StatusBar->AttachMessage(new DHUDMessageFadeOut(SmallFont, str,
float(CleanWidth/2) + 0.4f, float(ConversationMenu.y - 110 + CleanHeight/2), CleanWidth, -CleanHeight,
float(CleanWidth/2) + 0.4f, float(ConversationMenuY - 110 + CleanHeight/2), CleanWidth, -CleanHeight,
CR_UNTRANSLATED, 3, 1), MAKE_ID('T','A','L','K'));
}
else

View File

@ -48,8 +48,6 @@ struct FStrifeDialogueReply
char *LogString;
char *QuickNo;
bool NeedsGold;
FBrokenLines *ReplyLines;
};
extern TArray<FStrifeDialogueNode *> StrifeDialogues;

View File

@ -1961,7 +1961,7 @@ void R_DrawBorder (int x1, int y1, int x2, int y2)
int BorderNeedRefresh;
void V_MarkRect (int x, int y, int width, int height);
void M_DrawFrame (int x, int y, int width, int height);
void V_DrawFrame (int x, int y, int width, int height);
void R_DrawViewBorder (void)
{
@ -1982,7 +1982,7 @@ void R_DrawViewBorder (void)
R_DrawBorder (viewwindowx + viewwidth, viewwindowy, SCREENWIDTH, viewheight + viewwindowy);
R_DrawBorder (0, viewwindowy + viewheight, SCREENWIDTH, ST_Y);
M_DrawFrame (viewwindowx, viewwindowy, viewwidth, viewheight);
V_DrawFrame (viewwindowx, viewwindowy, viewwidth, viewheight);
V_MarkRect (0, 0, SCREENWIDTH, ST_Y);
}

View File

@ -147,6 +147,14 @@ static void I_CheckGUICapture ()
}
}
void I_SetMouseCapture()
{
}
void I_ReleaseMouseCapture()
{
}
static void CenterMouse ()
{
SDL_WarpMouse (screen->GetWidth()/2, screen->GetHeight()/2);

View File

@ -3,6 +3,8 @@
void I_PutInClipboard (const char *str);
FString I_GetFromClipboard (bool use_primary_selection);
void I_SetMouseCapture();
void I_ReleaseMouseCapture();
#endif

View File

@ -778,3 +778,8 @@ unsigned int I_MakeRNGSeed()
}
return seed;
}
bool I_SetCursor(FTexture *cursorpic)
{
return false;
}

View File

@ -128,6 +128,8 @@ bool I_WriteIniFailed ();
unsigned int I_MSTime (void);
unsigned int I_FPSTime();
class FTexture;
bool I_SetCursor(FTexture *);
// Directory searching routines

View File

@ -37,13 +37,14 @@
#include "doomdef.h"
class FileReader;
struct FOptionValues;
//
// MUSIC I/O
//
void I_InitMusic ();
void I_ShutdownMusic ();
void I_BuildMIDIMenuList (struct value_t **values, float *numValues);
void I_BuildMIDIMenuList (FOptionValues *);
void I_UpdateMusic ();
// Volume.

View File

@ -5,7 +5,7 @@
#include "templates.h"
#include "v_text.h"
#include "m_menu.h"
#include "menu/menu.h"
static DWORD nummididevices;
static bool nummididevicesset;
@ -71,50 +71,43 @@ void I_ShutdownMusicWin32 ()
}
}
void I_BuildMIDIMenuList (struct value_t **outValues, float *numValues)
{
if (*outValues == NULL)
{
int count = 4 + nummididevices;
value_t *values;
UINT id;
int p = 0;
*outValues = values = new value_t[count];
#ifdef HAVE_FLUIDSYNTH
values[p].name = "FluidSynth";
values[p].value = -5.0;
++p;
#define NUM_DEF_DEVICES 4
#else
#define NUM_DEF_DEVICES 3
#endif
values[p].name = "OPL Synth Emulation";
values[p].value = -3.0;
++p;
values[p].name = "TiMidity++";
values[p].value = -2.0;
++p;
values[p].name = "FMOD";
values[p].value = -1.0;
++p;
for (id = 0; id < nummididevices; ++id)
void I_BuildMIDIMenuList (FOptionValues *opt)
{
int p;
FOptionValues::Pair *pair = &opt->mValues[opt->mValues.Reserve(NUM_DEF_DEVICES)];
#ifdef HAVE_FLUIDSYNTH
pair[0].Text = "FluidSynth";
pair[0].Value = -5.0;
p = 1;
#else
p = 0;
#endif
pair[p].Text = "OPL Synth Emulation";
pair[p].Value = -3.0;
pair[p+1].Text = "TiMidity++";
pair[p+1].Value = -2.0;
pair[p+2].Text = "FMOD";
pair[p+2].Value = -1.0;
for (DWORD id = 0; id < nummididevices; ++id)
{
MIDIOUTCAPS caps;
MMRESULT res;
res = midiOutGetDevCaps (id, &caps, sizeof(caps));
assert(res == MMSYSERR_NOERROR);
if (res == MMSYSERR_NOERROR)
{
MIDIOUTCAPS caps;
MMRESULT res;
res = midiOutGetDevCaps (id, &caps, sizeof(caps));
assert(res == MMSYSERR_NOERROR);
if (res == MMSYSERR_NOERROR)
{
size_t len = strlen (caps.szPname) + 1;
char *name = new char[len];
memcpy (name, caps.szPname, len);
values[p].name = name;
values[p].value = (float)id;
++p;
}
pair = &opt->mValues[opt->mValues.Reserve(1)];
pair->Text = caps.szPname;
pair->Value = (float)id;
}
*numValues = float(p);
}
}
@ -195,31 +188,28 @@ CUSTOM_CVAR(Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
self = -1;
}
void I_BuildMIDIMenuList (struct value_t **outValues, float *numValues)
{
if (*outValues == NULL)
{
value_t *values;
int p = 0;
*outValues = values = new value_t[4];
#ifdef HAVE_FLUIDSYNTH
values[p].name = "FluidSynth";
values[p].value = -5.0;
++p;
#define NUM_DEF_DEVICES 4
#else
#define NUM_DEF_DEVICES 3
#endif
values[p].name = "OPL Synth Emulation";
values[p].value = -3.0;
++p;
values[p].name = "TiMidity++";
values[p].value = -2.0;
++p;
values[p].name = "FMOD";
values[p].value = -1.0;
++p;
*numValues = float(p);
}
void I_BuildMIDIMenuList (FOptionValues *opt)
{
int p;
FOptionValues::Pair *pair = &opt->mValues[opt->mValues.Reserve(NUM_DEF_DEVICES)];
#ifdef HAVE_FLUIDSYNTH
pair[0].Text = "FluidSynth";
pair[0].Value = -5.0;
p = 1;
#else
p = 0;
#endif
pair[p].Text = "OPL Synth Emulation";
pair[p].Value = -3.0;
pair[p+1].Text = "TiMidity++";
pair[p+1].Value = -2.0;
pair[p+2].Text = "FMOD";
pair[p+2].Value = -1.0;
}
CCMD (snd_listmididevices)

View File

@ -100,6 +100,7 @@ public:
Width = w;
Height = h;
data = new BYTE[4*w*h];
memset(data, 0, 4*w*h);
FreeBuffer = true;
ClipRect.x = ClipRect.y = 0;
ClipRect.width = w;

View File

@ -189,7 +189,7 @@ protected:
private:
void CheckForHacks ();
void ParsePatch(FScanner &sc, TexPart & part);
void ParsePatch(FScanner &sc, TexPart & part, bool silent);
};
//==========================================================================
@ -970,7 +970,7 @@ void FTextureManager::AddTexturesLumps (int lump1, int lump2, int patcheslump)
//
//==========================================================================
void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part)
void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, bool silent)
{
FString patchname;
sc.MustGetString();
@ -1011,7 +1011,7 @@ void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part)
}
if (part.Texture == NULL)
{
Printf("Unknown patch '%s' in texture '%s'\n", sc.String, Name);
if (!silent) Printf("Unknown patch '%s' in texture '%s'\n", sc.String, Name);
}
sc.MustGetStringName(",");
sc.MustGetNumber();
@ -1164,6 +1164,14 @@ void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part)
bComplex |= (part.op != OP_COPY);
bTranslucentPatches = bComplex;
}
else if (sc.Compare("useoffsets"))
{
if (part.Texture != NULL)
{
part.OriginX -= part.Texture->LeftOffset;
part.OriginY -= part.Texture->TopOffset;
}
}
}
}
if (Mirror & 2)
@ -1187,10 +1195,23 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype)
: Pixels (0), Spans(0), Parts(0), bRedirect(false), bTranslucentPatches(false)
{
TArray<TexPart> parts;
bool bSilent = false;
bMultiPatch = true;
sc.SetCMode(true);
sc.MustGetString();
if (sc.Compare("optional"))
{
bSilent = true;
sc.MustGetString();
if (sc.Compare(","))
{
// this is not right. Apparently a texture named 'optional' is being defined right now...
sc.UnGet();
sc.String = "optional";
bSilent = false;
}
}
uppercopy(Name, sc.String);
Name[8] = 0;
sc.MustGetStringName(",");
@ -1231,7 +1252,7 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype)
else if (sc.Compare("Patch"))
{
TexPart part;
ParsePatch(sc, part);
ParsePatch(sc, part, bSilent);
if (part.Texture != NULL) parts.Push(part);
part.Texture = NULL;
part.Translation = NULL;

View File

@ -2182,6 +2182,15 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn)
}
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player, portrait, S, PlayerPawn)
{
PROP_STRING_PARM(val, 0);
info->Class->Meta.SetMetaString (APMETA_Portrait, val);
}
//==========================================================================
//
//==========================================================================

View File

@ -45,6 +45,7 @@
#include "r_translate.h"
#include "doomstat.h"
#include "v_palette.h"
#include "gi.h"
#include "i_system.h"
#include "i_video.h"
@ -1351,3 +1352,35 @@ bool DCanvas::ClipBox (int &x, int &y, int &w, int &h, const BYTE *&src, const i
}
return false;
}
// Draw a frame around the specified area using the view border
// frame graphics. The border is drawn outside the area, not in it.
void V_DrawFrame (int left, int top, int width, int height)
{
FTexture *p;
const gameborder_t *border = gameinfo.border;
// Sanity check for incomplete gameinfo
if (border == NULL)
return;
int offset = border->offset;
int right = left + width;
int bottom = top + height;
// Draw top and bottom sides.
p = TexMan[border->t];
screen->FlatFill(left, top - p->GetHeight(), right, top, p, true);
p = TexMan[border->b];
screen->FlatFill(left, bottom, right, bottom + p->GetHeight(), p, true);
// Draw left and right sides.
p = TexMan[border->l];
screen->FlatFill(left - p->GetWidth(), top, left, bottom, p, true);
p = TexMan[border->r];
screen->FlatFill(right, top, right + p->GetWidth(), bottom, p, true);
// Draw beveled corners.
screen->DrawTexture (TexMan[border->tl], left-offset, top-offset, TAG_DONE);
screen->DrawTexture (TexMan[border->tr], left+width, top-offset, TAG_DONE);
screen->DrawTexture (TexMan[border->bl], left-offset, top+height, TAG_DONE);
screen->DrawTexture (TexMan[border->br], left+width, top+height, TAG_DONE);
}

View File

@ -2043,6 +2043,15 @@ void V_InitFontColors ()
while ((lump = Wads.FindLump ("TEXTCOLO", &lastlump)) != -1)
{
if (gameinfo.flags & GI_NOTEXTCOLOR)
{
// Chex3 contains a bad TEXTCOLO lump, probably to force all text to be green.
// This renders the Gray, Gold, Red and Yellow color range inoperable, some of
// which are used by the menu. So we have no choice but to skip this lump so that
// all colors work properly.
// The text colors should be the end user's choice anyway.
if (Wads.GetLumpFile(lump) == 1) continue;
}
FScanner sc(lump);
while (sc.GetString())
{

View File

@ -118,6 +118,21 @@ CUSTOM_CVAR (Float, Gamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
}
}
CCMD (bumpgamma)
{
// [RH] Gamma correction tables are now generated
// on the fly for *any* gamma level.
// Q: What are reasonable limits to use here?
float newgamma = Gamma + 0.1f;
if (newgamma > 3.0)
newgamma = 1.0;
Gamma = newgamma;
Printf ("Gamma correction level %g\n", *Gamma);
}
/****************************/
/* Palette management stuff */

View File

@ -42,7 +42,6 @@
#include "m_argv.h"
#include "m_bbox.h"
#include "m_swap.h"
#include "m_menu.h"
#include "i_video.h"
#include "v_video.h"
@ -63,6 +62,7 @@
#include "colormatcher.h"
#include "v_palette.h"
#include "r_sky.h"
#include "menu/menu.h"
IMPLEMENT_ABSTRACT_CLASS (DCanvas)

View File

@ -412,6 +412,7 @@ public:
virtual void WipeEndScreen();
virtual bool WipeDo(int ticks);
virtual void WipeCleanup();
virtual int GetPixelDoubling() const { return 1; }
uint32 GetLastFPS() const { return LastCount; }
@ -489,6 +490,7 @@ FString V_GetColorStringByName (const char *name);
// Tries to get color by name, then by string
int V_GetColor (const DWORD *palette, const char *str);
void V_DrawFrame (int left, int top, int width, int height);
#if defined(X86_ASM) || defined(X64_ASM)
extern "C" void ASM_PatchPitch (void);

View File

@ -21,7 +21,6 @@
#include "doomdef.h"
#include "doomstat.h"
#include "win32iface.h"
#include "m_menu.h"
#include "templates.h"
#include "gameconfigfile.h"
#include "cmdlib.h"
@ -236,8 +235,6 @@ protected:
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
extern void UpdateJoystickMenu();
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
@ -246,7 +243,6 @@ static void MapAxis(FIntCVar &var, int num);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern menu_t JoystickMenu;
extern LPDIRECTINPUT8 g_pdi;
extern HWND Window;

View File

@ -86,7 +86,6 @@
#include "i_input.h"
#include "v_video.h"
#include "i_sound.h"
#include "m_menu.h"
#include "g_game.h"
#include "d_main.h"
#include "d_gui.h"
@ -145,6 +144,7 @@ extern HWND EAXEditWindow;
EXTERN_CVAR (String, language)
EXTERN_CVAR (Bool, lookstrafe)
EXTERN_CVAR (Bool, use_joystick)
EXTERN_CVAR (Bool, use_mouse)
static int WheelDelta;
extern bool CursorState;
@ -191,6 +191,16 @@ static void I_CheckGUICapture ()
}
}
void I_SetMouseCapture()
{
SetCapture(Window);
}
void I_ReleaseMouseCapture()
{
ReleaseCapture();
}
bool GUIWndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result)
{
event_t ev = { EV_GUI_Event };
@ -228,28 +238,29 @@ bool GUIWndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESU
{
switch (wParam)
{
case VK_PRIOR: ev.data1 = GK_PGUP; break;
case VK_NEXT: ev.data1 = GK_PGDN; break;
case VK_END: ev.data1 = GK_END; break;
case VK_HOME: ev.data1 = GK_HOME; break;
case VK_LEFT: ev.data1 = GK_LEFT; break;
case VK_RIGHT: ev.data1 = GK_RIGHT; break;
case VK_UP: ev.data1 = GK_UP; break;
case VK_DOWN: ev.data1 = GK_DOWN; break;
case VK_DELETE: ev.data1 = GK_DEL; break;
case VK_ESCAPE: ev.data1 = GK_ESCAPE; break;
case VK_F1: ev.data1 = GK_F1; break;
case VK_F2: ev.data1 = GK_F2; break;
case VK_F3: ev.data1 = GK_F3; break;
case VK_F4: ev.data1 = GK_F4; break;
case VK_F5: ev.data1 = GK_F5; break;
case VK_F6: ev.data1 = GK_F6; break;
case VK_F7: ev.data1 = GK_F7; break;
case VK_F8: ev.data1 = GK_F8; break;
case VK_F9: ev.data1 = GK_F9; break;
case VK_F10: ev.data1 = GK_F10; break;
case VK_F11: ev.data1 = GK_F11; break;
case VK_F12: ev.data1 = GK_F12; break;
case VK_PRIOR: ev.data1 = GK_PGUP; break;
case VK_NEXT: ev.data1 = GK_PGDN; break;
case VK_END: ev.data1 = GK_END; break;
case VK_HOME: ev.data1 = GK_HOME; break;
case VK_LEFT: ev.data1 = GK_LEFT; break;
case VK_RIGHT: ev.data1 = GK_RIGHT; break;
case VK_UP: ev.data1 = GK_UP; break;
case VK_DOWN: ev.data1 = GK_DOWN; break;
case VK_DELETE: ev.data1 = GK_DEL; break;
case VK_ESCAPE: ev.data1 = GK_ESCAPE; break;
case VK_F1: ev.data1 = GK_F1; break;
case VK_F2: ev.data1 = GK_F2; break;
case VK_F3: ev.data1 = GK_F3; break;
case VK_F4: ev.data1 = GK_F4; break;
case VK_F5: ev.data1 = GK_F5; break;
case VK_F6: ev.data1 = GK_F6; break;
case VK_F7: ev.data1 = GK_F7; break;
case VK_F8: ev.data1 = GK_F8; break;
case VK_F9: ev.data1 = GK_F9; break;
case VK_F10: ev.data1 = GK_F10; break;
case VK_F11: ev.data1 = GK_F11; break;
case VK_F12: ev.data1 = GK_F12; break;
case VK_BROWSER_BACK: ev.data1 = GK_BACK; break;
}
if (ev.data1 != 0)
{
@ -278,6 +289,9 @@ bool GUIWndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESU
case WM_RBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_XBUTTONDOWN:
case WM_XBUTTONUP:
case WM_MOUSEMOVE:
if (message >= WM_LBUTTONDOWN && message <= WM_LBUTTONDBLCLK)
{
ev.subtype = message - WM_LBUTTONDOWN + EV_GUI_LButtonDown;
@ -290,11 +304,35 @@ bool GUIWndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESU
{
ev.subtype = message - WM_MBUTTONDOWN + EV_GUI_MButtonDown;
}
D_PostEvent(&ev);
else if (message >= WM_XBUTTONDOWN && message <= WM_XBUTTONUP)
{
ev.subtype = message - WM_XBUTTONDOWN + EV_GUI_BackButtonDown;
if (GET_XBUTTON_WPARAM(wParam) == 2)
{
ev.subtype += EV_GUI_FwdButtonDown - EV_GUI_BackButtonDown;
}
else if (GET_XBUTTON_WPARAM(wParam) != 1)
{
break;
}
}
else if (message == WM_MOUSEMOVE)
{
ev.subtype = EV_GUI_MouseMove;
}
ev.data1 = LOWORD(lParam) >> screen->GetPixelDoubling();
ev.data2 = HIWORD(lParam) >> screen->GetPixelDoubling();
if (wParam & MK_SHIFT) ev.data3 |= GKM_SHIFT;
if (wParam & MK_CONTROL) ev.data3 |= GKM_CTRL;
if (GetKeyState(VK_MENU) & 0x8000) ev.data3 |= GKM_ALT;
if (use_mouse) D_PostEvent(&ev);
return true;
// Note: If the mouse is grabbed, it sends the mouse wheel events itself.
case WM_MOUSEWHEEL:
if (!use_mouse) return false;
if (wParam & MK_SHIFT) ev.data3 |= GKM_SHIFT;
if (wParam & MK_CONTROL) ev.data3 |= GKM_CTRL;
if (GetKeyState(VK_MENU) & 0x8000) ev.data3 |= GKM_ALT;
@ -385,6 +423,15 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
return result;
}
if ((gamestate == GS_DEMOSCREEN || gamestate == GS_TITLELEVEL) && message == WM_LBUTTONDOWN)
{
if (GUIWndProcHook(hWnd, message, wParam, lParam, &result))
{
return result;
}
}
switch (message)
{
case WM_DESTROY:
@ -425,6 +472,10 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
SetCursor(NULL); // turn off window cursor
return TRUE; // Prevent Windows from setting cursor to window class cursor
}
else
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_SIZE:

View File

@ -37,6 +37,9 @@
#include "doomtype.h"
#include "doomdef.h"
void I_SetMouseCapture();
void I_ReleaseMouseCapture();
bool I_InitInput (void *hwnd);
void I_ShutdownInput ();
void I_PutInClipboard (const char *str);

View File

@ -1,8 +1,3 @@
#ifdef _MSC_VER
// Turn off "conversion from 'LONG_PTR' to 'LONG', possible loss of data"
// generated by SetClassLongPtr().
#pragma warning(disable:4244)
#endif
// HEADER FILES ------------------------------------------------------------
@ -22,6 +17,7 @@
#include "doomstat.h"
#include "win32iface.h"
#include "rawinput.h"
#include "menu/menu.h"
// MACROS ------------------------------------------------------------------
@ -265,18 +261,17 @@ void I_CheckNativeMouse(bool preferNative)
if (!windowed)
{
want_native = false;
// ungrab mouse when in the menu with mouse control on.
want_native = m_use_mouse && (menuactive == MENU_On || menuactive == MENU_OnNoPause);
}
else
{
want_native =
(GetForegroundWindow() != Window) ||
!CaptureMode_InGame() ||
GUICapture ||
paused ||
preferNative ||
!use_mouse ||
demoplayback;
((!m_use_mouse || menuactive != MENU_WaitKey) &&
(!CaptureMode_InGame() || GUICapture || paused || demoplayback));
}
//Printf ("%d %d %d\n", wantNative, preferNative, NativeMouse);
@ -592,7 +587,7 @@ void FRawMouse::Ungrab()
bool FRawMouse::ProcessRawInput(RAWINPUT *raw, int code)
{
if (!Grabbed || raw->header.dwType != RIM_TYPEMOUSE)
if (!Grabbed || raw->header.dwType != RIM_TYPEMOUSE || !use_mouse)
{
return false;
}
@ -806,7 +801,7 @@ void FDInputMouse::ProcessInput()
dx = 0;
dy = 0;
if (!Grabbed)
if (!Grabbed || !use_mouse)
return;
event_t ev = { 0 };
@ -948,7 +943,7 @@ void FWin32Mouse::ProcessInput()
POINT pt;
int x, y;
if (!Grabbed || !GetCursorPos(&pt))
if (!Grabbed || !use_mouse || !GetCursorPos(&pt))
{
return;
}
@ -1006,6 +1001,11 @@ bool FWin32Mouse::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPa
return true;
}
}
else if (!use_mouse)
{
// all following messages should only be processed if the mouse is in use
return false;
}
else if (message == WM_MOUSEWHEEL)
{
WheelMoved(0, (SHORT)HIWORD(wParam));

View File

@ -16,7 +16,6 @@
#include "doomdef.h"
#include "doomstat.h"
#include "win32iface.h"
#include "m_menu.h"
#include "templates.h"
#include "gameconfigfile.h"
#include "cmdlib.h"

View File

@ -83,9 +83,17 @@
#include "doomstat.h"
#include "v_palette.h"
#include "stats.h"
#include "r_data.h"
#include "textures/bitmap.h"
// MACROS ------------------------------------------------------------------
#ifdef _MSC_VER
// Turn off "conversion from 'LONG_PTR' to 'LONG', possible loss of data"
// generated by SetClassLongPtr().
#pragma warning(disable:4244)
#endif
// TYPES -------------------------------------------------------------------
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
@ -108,6 +116,11 @@ static int I_WaitForTicEvent(int prevtic);
static void I_FreezeTimeEventDriven(bool frozen);
static void CALLBACK TimerTicked(UINT id, UINT msg, DWORD_PTR user, DWORD_PTR dw1, DWORD_PTR dw2);
static HCURSOR CreateCompatibleCursor(FTexture *cursorpic);
static HCURSOR CreateAlphaCursor(FTexture *cursorpic);
static HCURSOR CreateBitmapCursor(int xhot, int yhot, HBITMAP and_mask, HBITMAP color_mask);
static void DestroyCustomCursor();
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
EXTERN_CVAR(String, language);
@ -158,6 +171,8 @@ static WadStuff *WadList;
static int NumWads;
static int DefaultWad;
static HCURSOR CustomCursor;
// CODE --------------------------------------------------------------------
//==========================================================================
@ -1175,6 +1190,208 @@ int I_PickIWad(WadStuff *wads, int numwads, bool showwin, int defaultiwad)
return defaultiwad;
}
//==========================================================================
//
// I_SetCursor
//
// Returns true if the cursor was successfully changed.
//
//==========================================================================
bool I_SetCursor(FTexture *cursorpic)
{
HCURSOR cursor;
// Must be no larger than 32x32.
if (cursorpic->GetWidth() > 32 || cursorpic->GetHeight() > 32)
{
return false;
}
cursor = CreateAlphaCursor(cursorpic);
if (cursor == NULL)
{
cursor = CreateCompatibleCursor(cursorpic);
}
if (cursor == NULL)
{
return false;
}
// Replace the existing cursor with the new one.
if (CustomCursor != NULL)
{
DestroyCursor(CustomCursor);
}
CustomCursor = cursor;
atterm(DestroyCustomCursor);
SetClassLongPtr(Window, GCLP_HCURSOR, (LONG_PTR)cursor);
return true;
}
//==========================================================================
//
// CreateCompatibleCursor
//
// Creates a cursor with a 1-bit alpha channel.
//
//==========================================================================
static HCURSOR CreateCompatibleCursor(FTexture *cursorpic)
{
int picwidth = cursorpic->GetWidth();
int picheight = cursorpic->GetHeight();
// Create bitmap masks for the cursor from the texture.
HDC dc = GetDC(NULL);
if (dc == NULL)
{
return false;
}
HDC and_mask_dc = CreateCompatibleDC(dc);
HDC xor_mask_dc = CreateCompatibleDC(dc);
HBITMAP and_mask = CreateCompatibleBitmap(dc, 32, 32);
HBITMAP xor_mask = CreateCompatibleBitmap(dc, 32, 32);
ReleaseDC(NULL, dc);
SelectObject(and_mask_dc, and_mask);
SelectObject(xor_mask_dc, xor_mask);
// Initialize with an invisible cursor.
SelectObject(and_mask_dc, GetStockObject(WHITE_PEN));
SelectObject(and_mask_dc, GetStockObject(WHITE_BRUSH));
Rectangle(and_mask_dc, 0, 0, 32, 32);
SelectObject(xor_mask_dc, GetStockObject(BLACK_PEN));
SelectObject(xor_mask_dc, GetStockObject(BLACK_BRUSH));
Rectangle(xor_mask_dc, 0, 0, 32, 32);
FBitmap bmp;
const BYTE *pixels;
bmp.Create(picwidth, picheight);
cursorpic->CopyTrueColorPixels(&bmp, 0, 0);
pixels = bmp.GetPixels();
// Copy color data from the source texture to the cursor bitmaps.
for (int y = 0; y < picheight; ++y)
{
for (int x = 0; x < picwidth; ++x)
{
const BYTE *bgra = &pixels[x*4 + y*bmp.GetPitch()];
if (bgra[3] != 0)
{
SetPixelV(and_mask_dc, x, y, RGB(0,0,0));
SetPixelV(xor_mask_dc, x, y, RGB(bgra[2], bgra[1], bgra[0]));
}
}
}
DeleteDC(and_mask_dc);
DeleteDC(xor_mask_dc);
// Create the cursor from the bitmaps.
return CreateBitmapCursor(cursorpic->LeftOffset, cursorpic->TopOffset, and_mask, xor_mask);
}
//==========================================================================
//
// CreateAlphaCursor
//
// Creates a cursor with a full alpha channel.
//
//==========================================================================
static HCURSOR CreateAlphaCursor(FTexture *cursorpic)
{
HDC dc;
BITMAPV5HEADER bi;
HBITMAP color, mono;
void *bits;
memset(&bi, 0, sizeof(bi));
bi.bV5Size = sizeof(bi);
bi.bV5Width = 32;
bi.bV5Height = 32;
bi.bV5Planes = 1;
bi.bV5BitCount = 32;
bi.bV5Compression = BI_BITFIELDS;
bi.bV5RedMask = 0x00FF0000;
bi.bV5GreenMask = 0x0000FF00;
bi.bV5BlueMask = 0x000000FF;
bi.bV5AlphaMask = 0xFF000000;
dc = GetDC(NULL);
if (dc == NULL)
{
return NULL;
}
// Create the DIB section with an alpha channel.
color = CreateDIBSection(dc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, &bits, NULL, 0);
ReleaseDC(NULL, dc);
if (color == NULL)
{
return NULL;
}
// Create an empty mask bitmap, since CreateIconIndirect requires this.
mono = CreateBitmap(32, 32, 1, 1, NULL);
if (mono == NULL)
{
DeleteObject(color);
return NULL;
}
// Copy cursor to the color bitmap. Note that GDI bitmaps are upside down compared
// to normal conventions, so we create the FBitmap pointing at the last row and use
// a negative pitch so that CopyTrueColorPixels will use GDI's orientation.
FBitmap bmp((BYTE *)bits + 31*32*4, -32*4, 32, 32);
cursorpic->CopyTrueColorPixels(&bmp, 0, 0);
return CreateBitmapCursor(cursorpic->LeftOffset, cursorpic->TopOffset, mono, color);
}
//==========================================================================
//
// CreateBitmapCursor
//
// Create the cursor from the bitmaps. Deletes the bitmaps before returning.
//
//==========================================================================
static HCURSOR CreateBitmapCursor(int xhot, int yhot, HBITMAP and_mask, HBITMAP color_mask)
{
ICONINFO iconinfo =
{
FALSE, // fIcon
xhot, // xHotspot
yhot, // yHotspot
and_mask, // hbmMask
color_mask // hbmColor
};
HCURSOR cursor = CreateIconIndirect(&iconinfo);
// Delete the bitmaps.
DeleteObject(and_mask);
DeleteObject(color_mask);
return cursor;
}
//==========================================================================
//
// DestroyCustomCursor
//
//==========================================================================
static void DestroyCustomCursor()
{
if (CustomCursor != NULL)
{
DestroyCursor(CustomCursor);
CustomCursor = NULL;
}
}
//==========================================================================
//
// I_WriteIniFailed

View File

@ -114,6 +114,10 @@ void STACK_ARGS I_FatalError (const char *error, ...) GCCPRINTF(1,2);
void atterm (void (*func)(void));
void popterm ();
// Set the mouse cursor. The texture must be 32x32.
class FTexture;
bool I_SetCursor(FTexture *cursor);
// Repaint the pre-game console
void I_PaintConsole (void);

View File

@ -19,7 +19,6 @@
#include "doomdef.h"
#include "doomstat.h"
#include "win32iface.h"
#include "m_menu.h"
#include "templates.h"
#include "gameconfigfile.h"
#include "cmdlib.h"

View File

@ -372,6 +372,7 @@ private:
void EndLineBatch();
void EndBatch();
void CopyNextFrontBuffer();
int GetPixelDoubling() const { return PixelDoubling; }
D3DCAPS9 DeviceCaps;

View File

@ -23,6 +23,7 @@ ACTOR ClericPlayer : PlayerPawn
Player.HealRadiusType "Health"
Player.Hexenarmor 10, 10, 25, 5, 20
Player.StartItem "CWeapMace"
Player.Portrait "P_CWALK1"
Player.WeaponSlot 1, CWeapMace
Player.WeaponSlot 2, CWeapStaff
Player.WeaponSlot 3, CWeapFlame

View File

@ -23,6 +23,7 @@ ACTOR FighterPlayer : PlayerPawn
Player.StartItem "FWeapFist"
Player.ForwardMove 1.08, 1.2
Player.SideMove 1.125, 1.475
Player.Portrait "P_FWALK1"
Player.WeaponSlot 1, FWeapFist
Player.WeaponSlot 2, FWeapAxe
Player.WeaponSlot 3, FWeapHammer

View File

@ -25,6 +25,7 @@ ACTOR MagePlayer : PlayerPawn
Player.StartItem "MWeapWand"
Player.ForwardMove 0.88, 0.92
Player.SideMove 0.875, 0.925
Player.Portrait "P_MWALK1"
Player.WeaponSlot 1, MWeapWand
Player.WeaponSlot 2, MWeapFrost
Player.WeaponSlot 3, MWeapLightning

View File

@ -101,6 +101,85 @@ pic PTN1A0 tics 3
pic PTN1B0 tics 3
pic PTN1C0 tics 3
// Hexen's player portraits
texture optional P_FWALK1
pic P_FWALK1 tics 8
pic P_FWALK2 tics 8
pic P_FWALK3 tics 8
pic P_FWALK4 tics 8
texture optional P_CWALK1
pic P_CWALK1 tics 8
pic P_CWALK2 tics 8
pic P_CWALK3 tics 8
pic P_CWALK4 tics 8
texture optional P_MWALK1
pic P_MWALK1 tics 8
pic P_MWALK2 tics 8
pic P_MWALK3 tics 8
pic P_MWALK4 tics 8
// Heretic's menu skulls
texture optional M_SKL00
pic M_SKL00 tics 3
pic M_SKL01 tics 3
pic M_SKL02 tics 3
pic M_SKL03 tics 3
pic M_SKL04 tics 3
pic M_SKL05 tics 3
pic M_SKL06 tics 3
pic M_SKL07 tics 3
pic M_SKL08 tics 3
pic M_SKL09 tics 3
pic M_SKL10 tics 3
pic M_SKL11 tics 3
pic M_SKL12 tics 3
pic M_SKL13 tics 3
pic M_SKL14 tics 3
pic M_SKL15 tics 3
pic M_SKL16 tics 3
pic M_SKL17 tics 3
texture optional M_SKL01
pic M_SKL17 tics 3
pic M_SKL16 tics 3
pic M_SKL15 tics 3
pic M_SKL14 tics 3
pic M_SKL13 tics 3
pic M_SKL12 tics 3
pic M_SKL11 tics 3
pic M_SKL10 tics 3
pic M_SKL09 tics 3
pic M_SKL08 tics 3
pic M_SKL07 tics 3
pic M_SKL06 tics 3
pic M_SKL05 tics 3
pic M_SKL04 tics 3
pic M_SKL03 tics 3
pic M_SKL02 tics 3
pic M_SKL01 tics 3
pic M_SKL00 tics 3
// Hexen's Fire Bulls
texture optional FBULA0
pic FBULA0 tics 5
pic FBULB0 tics 5
pic FBULC0 tics 5
pic FBULD0 tics 5
pic FBULE0 tics 5
pic FBULF0 tics 5
pic FBULG0 tics 5
texture optional FBULB0
pic FBULC0 tics 5
pic FBULD0 tics 5
pic FBULE0 tics 5
pic FBULF0 tics 5
pic FBULG0 tics 5
pic FBULA0 tics 5
pic FBULB0 tics 5
// The Wings of Wrath are not included, because they stop spinning when
// you stop flying, so they can't be a simple animation.

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

View File

@ -1559,6 +1559,8 @@ MNU_DELETESG = "Do you really want to delete the savegame\n";
MNU_ONLYREGISTERED = "ONLY AVAILABLE IN THE REGISTERED VERSION";
MNU_EPISODE = "Select Episode";
// Bloodbath announcer
BBA_BONED = "%k boned %o like a fish";

View File

@ -43,6 +43,15 @@ gameinfo
player5start = 4001
drawreadthis = true
pickupcolor = "d6 ba 45"
quitmessages = "$QUITMSG", "$QUITMSG23", "$QUITMSG24", "$QUITMSG25", "$QUITMSG26", "$QUITMSG27", "$QUITMSG28", "$QUITMSG29"
menufontcolor_title = "GREEN"
menufontcolor_label = "UNTRANSLATED"
menufontcolor_value = "GRAY"
menufontcolor_action = "GRAY"
menufontcolor_header = "YELLOW"
menufontcolor_highlight = "BLUE"
menufontcolor_selection = "GOLD"
menubackbutton = "M_BACK_H"
}
skill baby

View File

@ -14,6 +14,7 @@ gameinfo
borderflat = "FLOOR7_2"
drawreadthis = true
intermissionmusic = "$MUSIC_INTER"
quitmessages = "$QUITMSG", "$QUITMSG1", "$QUITMSG2", "$QUITMSG3", "$QUITMSG4", "$QUITMSG5", "$QUITMSG6", "$QUITMSG7"
}
clearepisodes

View File

@ -41,6 +41,17 @@ gameinfo
endoom = "ENDOOM"
player5start = 4001
pickupcolor = "d6 ba 45"
quitmessages = "$QUITMSG", "$QUITMSG1", "$QUITMSG2", "$QUITMSG3", "$QUITMSG4", "$QUITMSG5", "$QUITMSG6", "$QUITMSG7",
"$QUITMSG8", "$QUITMSG9", "$QUITMSG10", "$QUITMSG11", "$QUITMSG12", "$QUITMSG13", "$QUITMSG14"
menufontcolor_title = "RED"
menufontcolor_label = "UNTRANSLATED"
menufontcolor_value = "GRAY"
menufontcolor_action = "GRAY"
menufontcolor_header = "GOLD"
menufontcolor_highlight = "YELLOW"
menufontcolor_selection = "BRICK"
menubackbutton = "M_BACK_D"
}
skill baby

View File

@ -42,6 +42,15 @@ gameinfo
endoom = "ENDTEXT"
player5start = 4001
pickupcolor = "d6 ba 45"
quitmessages = "$*RAVENQUITMSG"
menufontcolor_title = "UNTRANSLATED"
menufontcolor_label = "GREEN"
menufontcolor_value = "UNTRANSLATED"
menufontcolor_action = "UNTRANSLATED"
menufontcolor_header = "GOLD"
menufontcolor_highlight = "YELLOW"
menufontcolor_selection = "DARKGREEN"
menubackbutton = "M_BACK_H"
}
skill baby

View File

@ -40,6 +40,15 @@ gameinfo
defaultdropstyle = 1
player5start = 9100
pickupcolor = "d6 ba 45"
quitmessages = "$*RAVENQUITMSG"
menufontcolor_title = "UNTRANSLATED"
menufontcolor_label = "RED"
menufontcolor_value = "UNTRANSLATED"
menufontcolor_action = "UNTRANSLATED"
menufontcolor_header = "GOLD"
menufontcolor_highlight = "YELLOW"
menufontcolor_selection = "BRICK"
menubackbutton = "M_BACK_X"
}
skill baby

View File

@ -43,6 +43,15 @@ gameinfo
endoom = "ENDSTRF"
player5start = 5
pickupcolor = "d6 ba 45"
quitmessages = "$QUITMSG", "$QUITMSG15", "$QUITMSG16", "$QUITMSG17", "$QUITMSG18", "$QUITMSG19", "$QUITMSG20", "$QUITMSG21", "$QUITMSG22"
menufontcolor_title = "UNTRANSLATED"
menufontcolor_label = "UNTRANSLATED"
menufontcolor_value = "GRAY"
menufontcolor_action = "GRAY"
menufontcolor_header = "RED"
menufontcolor_highlight = "GREEN"
menufontcolor_selection = "GOLD"
menubackbutton = "M_BACK_S"
}
skill baby

1333
wadsrc/static/menudef.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,72 @@
Graphic optional P_FWALK1, 112, 136
{
Patch "M_FBOX", 0, 0
Patch "M_FWALK1", 24, 12 { useoffsets }
}
Graphic optional P_FWALK2, 112, 136
{
Patch "M_FBOX", 0, 0
Patch "M_FWALK2", 24, 12 { useoffsets }
}
Graphic optional P_FWALK3, 112, 136
{
Patch "M_FBOX", 0, 0
Patch "M_FWALK3", 24, 12 { useoffsets }
}
Graphic optional P_FWALK4, 112, 136
{
Patch "M_FBOX", 0, 0
Patch "M_FWALK4", 24, 12 { useoffsets }
}
Graphic optional P_CWALK1, 112, 136
{
Patch "M_CBOX", 0, 0
Patch "M_CWALK1", 24, 12 { useoffsets }
}
Graphic optional P_CWALK2, 112, 136
{
Patch "M_CBOX", 0, 0
Patch "M_CWALK2", 24, 12 { useoffsets }
}
Graphic optional P_CWALK3, 112, 136
{
Patch "M_CBOX", 0, 0
Patch "M_CWALK3", 24, 12 { useoffsets }
}
Graphic optional P_CWALK4, 112, 136
{
Patch "M_CBOX", 0, 0
Patch "M_CWALK4", 24, 12 { useoffsets }
}
Graphic optional P_MWALK1, 112, 136
{
Patch "M_MBOX", 0, 0
Patch "M_MWALK1", 24, 12 { useoffsets }
}
Graphic optional P_MWALK2, 112, 136
{
Patch "M_MBOX", 0, 0
Patch "M_MWALK2", 24, 12 { useoffsets }
}
Graphic optional P_MWALK3, 112, 136
{
Patch "M_MBOX", 0, 0
Patch "M_MWALK3", 24, 12 { useoffsets }
}
Graphic optional P_MWALK4, 112, 136
{
Patch "M_MBOX", 0, 0
Patch "M_MWALK4", 24, 12 { useoffsets }
}

File diff suppressed because it is too large Load Diff