mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-27 20:20:40 +00:00
Merge branch 'menu2'
# Conflicts: # source/exhumed/src/sound.cpp
This commit is contained in:
commit
b06a847d9a
161 changed files with 17715 additions and 13910 deletions
|
@ -802,6 +802,7 @@ set (PCH_SOURCES
|
||||||
core/palette.cpp
|
core/palette.cpp
|
||||||
core/zcompile.cpp
|
core/zcompile.cpp
|
||||||
core/statusbar.cpp
|
core/statusbar.cpp
|
||||||
|
core/gi.cpp
|
||||||
|
|
||||||
core/console/c_console.cpp
|
core/console/c_console.cpp
|
||||||
core/console/d_event.cpp
|
core/console/d_event.cpp
|
||||||
|
@ -810,7 +811,7 @@ set (PCH_SOURCES
|
||||||
common/audio/sound/oalsound.cpp
|
common/audio/sound/oalsound.cpp
|
||||||
common/audio/sound/s_environment.cpp
|
common/audio/sound/s_environment.cpp
|
||||||
common/audio/sound/s_sound.cpp
|
common/audio/sound/s_sound.cpp
|
||||||
#common/audio/sound/s_reverbedit.cpp
|
common/audio/sound/s_reverbedit.cpp
|
||||||
common/audio/music/music_midi_base.cpp
|
common/audio/music/music_midi_base.cpp
|
||||||
common/audio/music/music.cpp
|
common/audio/music/music.cpp
|
||||||
common/audio/music/i_music.cpp
|
common/audio/music/i_music.cpp
|
||||||
|
@ -910,6 +911,7 @@ set (PCH_SOURCES
|
||||||
common/filesystem/resourcefile.cpp
|
common/filesystem/resourcefile.cpp
|
||||||
common/engine/cycler.cpp
|
common/engine/cycler.cpp
|
||||||
common/engine/d_event.cpp
|
common/engine/d_event.cpp
|
||||||
|
common/engine/date.cpp
|
||||||
common/engine/stats.cpp
|
common/engine/stats.cpp
|
||||||
common/engine/sc_man.cpp
|
common/engine/sc_man.cpp
|
||||||
common/engine/palettecontainer.cpp
|
common/engine/palettecontainer.cpp
|
||||||
|
@ -924,6 +926,13 @@ set (PCH_SOURCES
|
||||||
common/objects/dobject.cpp
|
common/objects/dobject.cpp
|
||||||
common/objects/dobjgc.cpp
|
common/objects/dobjgc.cpp
|
||||||
common/objects/dobjtype.cpp
|
common/objects/dobjtype.cpp
|
||||||
|
common/menu/joystickmenu.cpp
|
||||||
|
common/menu/menu.cpp
|
||||||
|
common/menu/messagebox.cpp
|
||||||
|
common/menu/optionmenu.cpp
|
||||||
|
common/menu/resolutionmenu.cpp
|
||||||
|
common/menu/menudef.cpp
|
||||||
|
common/menu/savegamemanager.cpp
|
||||||
|
|
||||||
common/rendering/v_framebuffer.cpp
|
common/rendering/v_framebuffer.cpp
|
||||||
common/rendering/v_video.cpp
|
common/rendering/v_video.cpp
|
||||||
|
@ -975,22 +984,12 @@ set (PCH_SOURCES
|
||||||
common/scripting/backend/codegen.cpp
|
common/scripting/backend/codegen.cpp
|
||||||
|
|
||||||
|
|
||||||
core/textures/buildtiles.cpp
|
|
||||||
#core/textures/texture.cpp
|
|
||||||
|
|
||||||
|
core/textures/buildtiles.cpp
|
||||||
core/music/s_advsound.cpp
|
core/music/s_advsound.cpp
|
||||||
|
|
||||||
core/menu/imagescroller.cpp
|
|
||||||
core/menu/joystickmenu.cpp
|
|
||||||
core/menu/listmenu.cpp
|
|
||||||
core/menu/savegamemanager.cpp
|
|
||||||
core/menu/loadsavemenu.cpp
|
core/menu/loadsavemenu.cpp
|
||||||
core/menu/menu.cpp
|
core/menu/razemenu.cpp
|
||||||
core/menu/menudef.cpp
|
|
||||||
core/menu/menuinput.cpp
|
|
||||||
core/menu/messagebox.cpp
|
|
||||||
core/menu/optionmenu.cpp
|
|
||||||
core/menu/resolutionmenu.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if( ${HAVE_VM_JIT} )
|
if( ${HAVE_VM_JIT} )
|
||||||
|
|
|
@ -39,7 +39,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "view.h"
|
#include "view.h"
|
||||||
#include "nnexts.h"
|
#include "nnexts.h"
|
||||||
#include "zstring.h"
|
#include "zstring.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "gstrings.h"
|
#include "gstrings.h"
|
||||||
#include "v_2ddrawer.h"
|
#include "v_2ddrawer.h"
|
||||||
#include "v_video.h"
|
#include "v_video.h"
|
||||||
|
|
|
@ -51,7 +51,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "gamecontrol.h"
|
#include "gamecontrol.h"
|
||||||
#include "m_argv.h"
|
#include "m_argv.h"
|
||||||
#include "statistics.h"
|
#include "statistics.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "raze_sound.h"
|
#include "raze_sound.h"
|
||||||
#include "nnexts.h"
|
#include "nnexts.h"
|
||||||
#include "secrets.h"
|
#include "secrets.h"
|
||||||
|
@ -61,6 +61,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "choke.h"
|
#include "choke.h"
|
||||||
#include "d_net.h"
|
#include "d_net.h"
|
||||||
#include "v_video.h"
|
#include "v_video.h"
|
||||||
|
#include "v_draw.h"
|
||||||
|
#include "texturemanager.h"
|
||||||
#include "statusbar.h"
|
#include "statusbar.h"
|
||||||
|
|
||||||
BEGIN_BLD_NS
|
BEGIN_BLD_NS
|
||||||
|
@ -394,6 +396,16 @@ void GameInterface::DrawBackground()
|
||||||
DrawTexture(twod, tileGetTexture(2518, true), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE);
|
DrawTexture(twod, tileGetTexture(2518, true), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define x(a, b) registerName(#a, b);
|
||||||
|
static void SetTileNames()
|
||||||
|
{
|
||||||
|
auto registerName = [](const char* name, int index)
|
||||||
|
{
|
||||||
|
TexMan.AddAlias(name, tileGetTexture(index));
|
||||||
|
};
|
||||||
|
#include "namelist.h"
|
||||||
|
}
|
||||||
|
#undef x
|
||||||
|
|
||||||
|
|
||||||
void ReadAllRFS();
|
void ReadAllRFS();
|
||||||
|
@ -416,6 +428,7 @@ void GameInterface::app_init()
|
||||||
|
|
||||||
levelLoadDefaults();
|
levelLoadDefaults();
|
||||||
LoadDefinitions();
|
LoadDefinitions();
|
||||||
|
SetTileNames();
|
||||||
|
|
||||||
TileFiles.SetBackup();
|
TileFiles.SetBackup();
|
||||||
powerupInit();
|
powerupInit();
|
||||||
|
|
|
@ -80,11 +80,8 @@ struct GameInterface : ::GameInterface
|
||||||
void MenuClosed() override;
|
void MenuClosed() override;
|
||||||
bool CanSave() override;
|
bool CanSave() override;
|
||||||
bool StartGame(FNewGameStartup& gs) override;
|
bool StartGame(FNewGameStartup& gs) override;
|
||||||
void DrawNativeMenuText(int fontnum, int state, double xpos, double ypos, float fontscale, const char* text, int flags) override;
|
bool SaveGame() override;
|
||||||
void DrawMenuCaption(const DVector2& origin, const char* text) override;
|
bool LoadGame() override;
|
||||||
bool SaveGame(FSaveGameNode*) override;
|
|
||||||
bool LoadGame(FSaveGameNode*) override;
|
|
||||||
void DrawCenteredTextScreen(const DVector2& origin, const char* text, int position, bool bg) override;
|
|
||||||
void QuitToTitle() override;
|
void QuitToTitle() override;
|
||||||
FString GetCoordString() override;
|
FString GetCoordString() override;
|
||||||
ReservedSpace GetReservedScreenSpace(int viewsize) override;
|
ReservedSpace GetReservedScreenSpace(int viewsize) override;
|
||||||
|
|
|
@ -42,59 +42,57 @@ void _consoleSysMsg(const char* pMessage, ...);
|
||||||
|
|
||||||
#define ThrowError(...) \
|
#define ThrowError(...) \
|
||||||
{ \
|
{ \
|
||||||
_SetErrorLoc(__FILE__,__LINE__); \
|
|
||||||
I_Error(__VA_ARGS__); \
|
I_Error(__VA_ARGS__); \
|
||||||
}
|
}
|
||||||
|
|
||||||
// print error to console only
|
// print error to console only
|
||||||
#define consoleSysMsg(...) \
|
#define consoleSysMsg(...) \
|
||||||
{ \
|
{ \
|
||||||
_SetErrorLoc(__FILE__,__LINE__); \
|
|
||||||
_consoleSysMsg(__VA_ARGS__); \
|
_consoleSysMsg(__VA_ARGS__); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define dassert(x) assert(x)
|
#define dassert(x) assert(x)
|
||||||
|
|
||||||
|
|
||||||
#define kMaxSectors MAXSECTORS
|
|
||||||
#define kMaxWalls MAXWALLS
|
|
||||||
#define kMaxSprites MAXSPRITES
|
|
||||||
|
|
||||||
#define kMaxTiles MAXTILES
|
|
||||||
#define kMaxStatus MAXSTATUS
|
|
||||||
#define kMaxPlayers 8
|
|
||||||
#define kMaxViewSprites maxspritesonscreen
|
#define kMaxViewSprites maxspritesonscreen
|
||||||
|
|
||||||
#define kMaxVoxels MAXVOXELS
|
enum
|
||||||
|
{
|
||||||
|
kMaxSectors = MAXSECTORS,
|
||||||
|
kMaxWalls = MAXWALLS,
|
||||||
|
kMaxSprites = MAXSPRITES,
|
||||||
|
|
||||||
#define kTicRate 120
|
kMaxTiles = MAXTILES,
|
||||||
#define kTicsPerFrame 4
|
kMaxStatus = MAXSTATUS,
|
||||||
#define kTicsPerSec (kTicRate/kTicsPerFrame)
|
kMaxPlayers = 8,
|
||||||
|
kMaxVoxels = MAXVOXELS,
|
||||||
|
|
||||||
#define TILTBUFFER 4078
|
kTicRate = 120,
|
||||||
|
kTicsPerFrame = 4,
|
||||||
|
kTicsPerSec = (kTicRate / kTicsPerFrame),
|
||||||
|
|
||||||
#define kExplodeMax 8
|
kExplodeMax = 8,
|
||||||
|
|
||||||
#define kLensSize 80
|
kLensSize = 80,
|
||||||
#define kViewEffectMax 19
|
kViewEffectMax = 19,
|
||||||
|
|
||||||
#define kNoTile -1
|
kNoTile = -1,
|
||||||
|
|
||||||
|
|
||||||
// defined by NoOne:
|
//= = = = // = defined = by = NoOne:
|
||||||
// -------------------------------
|
//= = = = // = -------------------------------
|
||||||
|
|
||||||
#define kMaxPAL 5
|
kMaxPAL = 5,
|
||||||
#define kUserPLUStart 15
|
kUserPLUStart = 15,
|
||||||
|
|
||||||
#define kDmgFall 0
|
kDmgFall = 0,
|
||||||
#define kDmgBurn 1
|
kDmgBurn = 1,
|
||||||
#define kDmgBullet 2
|
kDmgBullet = 2,
|
||||||
#define kDmgExplode 3
|
kDmgExplode = 3,
|
||||||
#define kDmgChoke 4
|
kDmgChoke = 4,
|
||||||
#define kDmgSpirit 5
|
kDmgSpirit = 5,
|
||||||
#define kDmgElectric 6
|
kDmgElectric = 6,
|
||||||
#define kDmgMax 7
|
kDmgMax = 7,
|
||||||
|
};
|
||||||
|
|
||||||
// MEDIUM /////////////////////////////////////////////////////
|
// MEDIUM /////////////////////////////////////////////////////
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -26,7 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "mmulti.h"
|
#include "mmulti.h"
|
||||||
#include "view.h"
|
#include "view.h"
|
||||||
#include "gamestate.h"
|
#include "gamestate.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
|
|
||||||
BEGIN_BLD_NS
|
BEGIN_BLD_NS
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "screenjob.h"
|
#include "screenjob.h"
|
||||||
#include "gamestate.h"
|
#include "gamestate.h"
|
||||||
#include "seq.h"
|
#include "seq.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
|
|
||||||
BEGIN_BLD_NS
|
BEGIN_BLD_NS
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
||||||
Copyright (C) 2019 Nuke.YKT
|
Copyright (C) 2019 Nuke.YKT
|
||||||
|
Copyright (C) 2020 Christoph Oelckers
|
||||||
|
|
||||||
This file is part of NBlood.
|
This file is part of Raze.
|
||||||
|
|
||||||
NBlood is free software; you can redistribute it and/or
|
NBlood is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU General Public License version 2
|
modify it under the terms of the GNU General Public License version 2
|
||||||
|
@ -27,7 +28,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "mmulti.h"
|
#include "mmulti.h"
|
||||||
#include "c_bind.h"
|
#include "c_bind.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "gamestate.h"
|
#include "gamestate.h"
|
||||||
|
|
||||||
#include "blood.h"
|
#include "blood.h"
|
||||||
|
@ -36,6 +37,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "view.h"
|
#include "view.h"
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "v_video.h"
|
#include "v_video.h"
|
||||||
|
#include "v_draw.h"
|
||||||
|
#include "vm.h"
|
||||||
|
|
||||||
bool ShowOptionMenu();
|
bool ShowOptionMenu();
|
||||||
|
|
||||||
|
@ -118,112 +121,34 @@ void CGameMenuItemQAV::Draw(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static std::unique_ptr<CGameMenuItemQAV> itemBloodQAV; // This must be global to ensure that the animation remains consistent across menus.
|
static std::unique_ptr<CGameMenuItemQAV> itemBloodQAV; // This must be global to ensure that the animation remains consistent across menus.
|
||||||
|
|
||||||
|
|
||||||
void UpdateNetworkMenus(void)
|
void UpdateNetworkMenus(void)
|
||||||
{
|
{
|
||||||
// For now disable the network menu item as it is not yet functional.
|
// For now disable the network menu item as it is not functional.
|
||||||
for (auto name : { NAME_Mainmenu, NAME_IngameMenu })
|
for (auto name : { NAME_Mainmenu, NAME_IngameMenu })
|
||||||
{
|
{
|
||||||
FMenuDescriptor** desc = MenuDescriptors.CheckKey(name);
|
DMenuDescriptor** desc = MenuDescriptors.CheckKey(name);
|
||||||
if (desc != NULL && (*desc)->mType == MDESC_ListMenu)
|
if (desc != NULL && (*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor)))
|
||||||
{
|
{
|
||||||
FListMenuDescriptor* ld = static_cast<FListMenuDescriptor*>(*desc);
|
DListMenuDescriptor* ld = static_cast<DListMenuDescriptor*>(*desc);
|
||||||
for (auto& li : ld->mItems)
|
for (auto& li : ld->mItems)
|
||||||
{
|
{
|
||||||
if (li->GetAction(nullptr) == NAME_MultiMenu)
|
if (li->mAction == NAME_MultiMenu)
|
||||||
{
|
{
|
||||||
li->mEnabled = false;
|
li->mEnabled = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Implements the native looking menu used for the main menu
|
|
||||||
// and the episode/skill selection screens, i.e. the parts
|
|
||||||
// that need to look authentic
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
class BloodListMenu : public DListMenu
|
|
||||||
{
|
|
||||||
using Super = DListMenu;
|
|
||||||
protected:
|
|
||||||
|
|
||||||
void PostDraw()
|
|
||||||
{
|
|
||||||
// For narrow screens this would be mispositioned so skip drawing it there.
|
|
||||||
double ratio = screen->GetWidth() / double(screen->GetHeight());
|
|
||||||
if (ratio > 1.32) itemBloodQAV->Draw();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
class BloodImageScreen : public ImageScreen
|
|
||||||
{
|
|
||||||
CGameMenuItemQAV anim;
|
|
||||||
public:
|
|
||||||
BloodImageScreen(FImageScrollerDescriptor::ScrollerItem* desc)
|
|
||||||
: ImageScreen(desc), anim(169, 100, mDesc->text.GetChars(), false, true)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Drawer() override
|
|
||||||
{
|
|
||||||
anim.Draw();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class DBloodImageScrollerMenu : public DImageScrollerMenu
|
|
||||||
{
|
|
||||||
ImageScreen* newImageScreen(FImageScrollerDescriptor::ScrollerItem* desc) override
|
|
||||||
{
|
|
||||||
if (desc->type >= 0) return DImageScrollerMenu::newImageScreen(desc);
|
|
||||||
return new BloodImageScreen(desc);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Menu related game interface functions
|
// Menu related game interface functions
|
||||||
//
|
//
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
void GameInterface::DrawNativeMenuText(int fontnum, int state, double xpos, double ypos, float fontscale, const char* text, int flags)
|
|
||||||
{
|
|
||||||
if (!text) return;
|
|
||||||
int shade = (state != NIT_InactiveState) ? 32 : 48;
|
|
||||||
int pal = (state != NIT_InactiveState) ? 5 : 5;
|
|
||||||
if (state == NIT_SelectedState) shade = 32 - (I_GetBuildTime() & 63);
|
|
||||||
auto gamefont = fontnum == NIT_BigFont ? BigFont : SmallFont;
|
|
||||||
|
|
||||||
if (flags & LMF_Centered)
|
|
||||||
{
|
|
||||||
int width = gamefont->StringWidth(text);
|
|
||||||
xpos -= width / 2;
|
|
||||||
}
|
|
||||||
DrawText(twod, gamefont, CR_UNDEFINED, xpos+1, ypos+1, text, DTA_Color, 0xff000000, //DTA_Alpha, 0.5,
|
|
||||||
DTA_FullscreenScale, FSMode_Fit320x200, TAG_DONE);
|
|
||||||
|
|
||||||
DrawText(twod, gamefont, CR_UNDEFINED, xpos, ypos, text, DTA_TranslationIndex, TRANSLATION(Translation_Remap, pal), DTA_Color, shadeToLight(shade),
|
|
||||||
DTA_FullscreenScale, FSMode_Fit320x200, TAG_DONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void GameInterface::MenuOpened()
|
void GameInterface::MenuOpened()
|
||||||
{
|
{
|
||||||
itemBloodQAV.reset(new CGameMenuItemQAV(160, 100, "BDRIP.QAV", true));
|
itemBloodQAV.reset(new CGameMenuItemQAV(160, 100, "BDRIP.QAV", true));
|
||||||
|
@ -245,7 +170,7 @@ bool GameInterface::StartGame(FNewGameStartup& gs)
|
||||||
{
|
{
|
||||||
if (g_gameType & GAMEFLAG_SHAREWARE)
|
if (g_gameType & GAMEFLAG_SHAREWARE)
|
||||||
{
|
{
|
||||||
M_StartMessage(GStrings("BUYBLOOD"), 1, -1); // unreachable because we do not support Blood SW versions yet.
|
M_StartMessage(GStrings("BUYBLOOD"), 1, NAME_None); // unreachable because we do not support Blood SW versions yet.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,41 +186,6 @@ FSavegameInfo GameInterface::GetSaveSig()
|
||||||
return { SAVESIG_BLD, MINSAVEVER_BLD, SAVEVER_BLD };
|
return { SAVESIG_BLD, MINSAVEVER_BLD, SAVEVER_BLD };
|
||||||
}
|
}
|
||||||
|
|
||||||
// This also gets used by the summary and the loading screen
|
|
||||||
void DrawMenuCaption(const char* text)
|
|
||||||
{
|
|
||||||
double scalex = 1.; // Expand the box if the text is longer
|
|
||||||
int width = BigFont->StringWidth(text);
|
|
||||||
int boxwidth = tileWidth(2038);
|
|
||||||
if (boxwidth - 10 < width) scalex = double(width) / (boxwidth - 10);
|
|
||||||
|
|
||||||
DrawTexture(twod, tileGetTexture(2038, true), 160, 20, DTA_FullscreenScale, FSMode_Fit320x200Top, DTA_CenterOffsetRel, true, DTA_ScaleX, scalex, TAG_DONE);
|
|
||||||
DrawText(twod, BigFont, CR_UNDEFINED, 160 - width/2, 20 - tileHeight(4193) / 2, text, DTA_FullscreenScale, FSMode_Fit320x200Top, TAG_DONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameInterface::DrawMenuCaption(const DVector2& origin, const char* text)
|
|
||||||
{
|
|
||||||
Blood::DrawMenuCaption(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameInterface::DrawCenteredTextScreen(const DVector2& origin, const char* text, int position, bool bg)
|
|
||||||
{
|
|
||||||
if (text)
|
|
||||||
{
|
|
||||||
int height = SmallFont->GetHeight();
|
|
||||||
|
|
||||||
auto lines = FString(text).Split("\n");
|
|
||||||
int y = 100 - (height * lines.Size() / 2);
|
|
||||||
for (auto& l : lines)
|
|
||||||
{
|
|
||||||
int width = SmallFont->StringWidth(l);
|
|
||||||
int x = 160 - width / 2;
|
|
||||||
DrawText(twod, SmallFont, CR_UNTRANSLATED, x, y, l, DTA_FullscreenScale, FSMode_Fit320x200, TAG_DONE);
|
|
||||||
y += height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameInterface::QuitToTitle()
|
void GameInterface::QuitToTitle()
|
||||||
{
|
{
|
||||||
Mus_Stop();
|
Mus_Stop();
|
||||||
|
@ -304,20 +194,43 @@ void GameInterface::QuitToTitle()
|
||||||
|
|
||||||
END_BLD_NS
|
END_BLD_NS
|
||||||
|
|
||||||
|
using namespace Blood;
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Class registration
|
//
|
||||||
//
|
//
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(DListMenuItemBloodDripDrawer, Draw)
|
||||||
static TMenuClassDescriptor<Blood::BloodListMenu> _lm("Blood.ListMenu");
|
|
||||||
static TMenuClassDescriptor<Blood::BloodListMenu> _mm("Blood.MainMenu");
|
|
||||||
static TMenuClassDescriptor<Blood::DBloodImageScrollerMenu> _im("Blood.ImageScrollerMenu");
|
|
||||||
|
|
||||||
void RegisterBloodMenus()
|
|
||||||
{
|
{
|
||||||
menuClasses.Push(&_lm);
|
// For narrow screens this would be mispositioned so skip drawing it there.
|
||||||
menuClasses.Push(&_mm);
|
double ratio = screen->GetWidth() / double(screen->GetHeight());
|
||||||
menuClasses.Push(&_im);
|
if (ratio > 1.32) itemBloodQAV->Draw();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(_ImageScrollerPageQavDrawer, LoadQav)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_STRING(str);
|
||||||
|
auto qav = new CGameMenuItemQAV(160, 100, str, false, true);
|
||||||
|
ACTION_RETURN_POINTER(qav);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(_ImageScrollerPageQavDrawer, DestroyQav)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_POINTER(qav, CGameMenuItemQAV);
|
||||||
|
if (qav) delete qav;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(_ImageScrollerPageQavDrawer, DrawQav)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_POINTER(qav, CGameMenuItemQAV);
|
||||||
|
qav->Draw();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,18 @@ static void drawTextScreenBackground(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// One these screens get scriptified this should use the version in BloodMenuDelegate.
|
||||||
|
static void DrawCaption(const char* text)
|
||||||
|
{
|
||||||
|
double scalex = 1.; // Expand the box if the text is longer
|
||||||
|
int width = BigFont->StringWidth(text);
|
||||||
|
int boxwidth = tileWidth(2038);
|
||||||
|
if (boxwidth - 10 < width) scalex = double(width) / (boxwidth - 10);
|
||||||
|
|
||||||
|
DrawTexture(twod, tileGetTexture(2038, true), 160, 20, DTA_FullscreenScale, FSMode_Fit320x200Top, DTA_CenterOffsetRel, true, DTA_ScaleX, scalex, TAG_DONE);
|
||||||
|
DrawText(twod, BigFont, CR_UNDEFINED, 160 - width / 2, 20 - tileHeight(4193) / 2, text, DTA_FullscreenScale, FSMode_Fit320x200Top, TAG_DONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class DBloodSummaryScreen : public DScreenJob
|
class DBloodSummaryScreen : public DScreenJob
|
||||||
{
|
{
|
||||||
|
@ -141,7 +153,7 @@ class DBloodSummaryScreen : public DScreenJob
|
||||||
drawTextScreenBackground();
|
drawTextScreenBackground();
|
||||||
if (gGameOptions.nGameType == 0)
|
if (gGameOptions.nGameType == 0)
|
||||||
{
|
{
|
||||||
DrawMenuCaption(GStrings("TXTB_LEVELSTATS"));
|
DrawCaption(GStrings("TXTB_LEVELSTATS"));
|
||||||
if (bPlayerCheated)
|
if (bPlayerCheated)
|
||||||
{
|
{
|
||||||
auto text = GStrings("TXTB_CHEATED");
|
auto text = GStrings("TXTB_CHEATED");
|
||||||
|
@ -154,7 +166,7 @@ class DBloodSummaryScreen : public DScreenJob
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DrawMenuCaption(GStrings("TXTB_FRAGSTATS"));
|
DrawCaption(GStrings("TXTB_FRAGSTATS"));
|
||||||
DrawKills();
|
DrawKills();
|
||||||
}
|
}
|
||||||
int myclock = int(clock * 120 / 1'000'000'000);
|
int myclock = int(clock * 120 / 1'000'000'000);
|
||||||
|
@ -301,7 +313,7 @@ public:
|
||||||
{
|
{
|
||||||
twod->ClearScreen();
|
twod->ClearScreen();
|
||||||
drawTextScreenBackground();
|
drawTextScreenBackground();
|
||||||
DrawMenuCaption(pzLoadingScreenText1);
|
DrawCaption(pzLoadingScreenText1);
|
||||||
viewDrawText(1, rec->DisplayName(), 160, 50, -128, 0, 1, 1);
|
viewDrawText(1, rec->DisplayName(), 160, 50, -128, 0, 1, 1);
|
||||||
|
|
||||||
auto text = GStrings("TXTB_PLSWAIT");
|
auto text = GStrings("TXTB_PLSWAIT");
|
||||||
|
|
|
@ -58,12 +58,9 @@ void _SetErrorLoc(const char *pzFile, int nLine)
|
||||||
// by NoOne: show warning msgs in game instead of throwing errors (in some cases)
|
// by NoOne: show warning msgs in game instead of throwing errors (in some cases)
|
||||||
void _consoleSysMsg(const char* pzFormat, ...) {
|
void _consoleSysMsg(const char* pzFormat, ...) {
|
||||||
|
|
||||||
char buffer[1024];
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, pzFormat);
|
va_start(args, pzFormat);
|
||||||
vsprintf(buffer, pzFormat, args);
|
VPrintf(PRINT_LOW, TEXTCOLOR_RED "%s\n", args);
|
||||||
|
|
||||||
Printf(TEXTCOLOR_RED "%s(%i): %s\n", _module, _line, buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
END_BLD_NS
|
END_BLD_NS
|
||||||
|
|
|
@ -39,7 +39,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "view.h"
|
#include "view.h"
|
||||||
#include "nnexts.h"
|
#include "nnexts.h"
|
||||||
#include "zstring.h"
|
#include "zstring.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "gstrings.h"
|
#include "gstrings.h"
|
||||||
#include "v_2ddrawer.h"
|
#include "v_2ddrawer.h"
|
||||||
#include "v_video.h"
|
#include "v_video.h"
|
||||||
|
|
|
@ -38,7 +38,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "view.h"
|
#include "view.h"
|
||||||
#include "eventq.h"
|
#include "eventq.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
|
|
||||||
BEGIN_BLD_NS
|
BEGIN_BLD_NS
|
||||||
|
|
||||||
|
|
|
@ -474,7 +474,7 @@ void LoadSave::Write(void *pData, int nSize)
|
||||||
ThrowError("File error #%d writing save file.", errno);
|
ThrowError("File error #%d writing save file.", errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameInterface::LoadGame(FSaveGameNode* node)
|
bool GameInterface::LoadGame()
|
||||||
{
|
{
|
||||||
sndKillAllSounds();
|
sndKillAllSounds();
|
||||||
sfxKillAllSounds();
|
sfxKillAllSounds();
|
||||||
|
@ -534,7 +534,7 @@ bool GameInterface::LoadGame(FSaveGameNode* node)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameInterface::SaveGame(FSaveGameNode* node)
|
bool GameInterface::SaveGame()
|
||||||
{
|
{
|
||||||
LoadSave::hSFile = WriteSavegameChunk("snapshot.bld");
|
LoadSave::hSFile = WriteSavegameChunk("snapshot.bld");
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,6 @@ public:
|
||||||
virtual void Load(void);
|
virtual void Load(void);
|
||||||
void Read(void *, int);
|
void Read(void *, int);
|
||||||
void Write(void *, int);
|
void Write(void *, int);
|
||||||
static void LoadGame(FSavegameNode *);
|
|
||||||
static void SaveGame(FSavegameNode*);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void LoadSaveSetup(void);
|
void LoadSaveSetup(void);
|
||||||
|
|
|
@ -143,6 +143,5 @@ void tilePrecacheTile(int nTile, int nType, HitList& hits);
|
||||||
char tileGetSurfType(int hit);
|
char tileGetSurfType(int hit);
|
||||||
|
|
||||||
void scrLoadPalette(void);
|
void scrLoadPalette(void);
|
||||||
void DrawMenuCaption(const char* text);
|
|
||||||
|
|
||||||
END_BLD_NS
|
END_BLD_NS
|
||||||
|
|
2
source/blood/src/namelist.h
Normal file
2
source/blood/src/namelist.h
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
// names for everything that gets accessed by scripts.
|
||||||
|
x(MENUBAR, 2038)
|
|
@ -39,7 +39,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "view.h"
|
#include "view.h"
|
||||||
#include "nnexts.h"
|
#include "nnexts.h"
|
||||||
#include "zstring.h"
|
#include "zstring.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "gstrings.h"
|
#include "gstrings.h"
|
||||||
#include "v_2ddrawer.h"
|
#include "v_2ddrawer.h"
|
||||||
#include "v_video.h"
|
#include "v_video.h"
|
||||||
|
|
|
@ -39,7 +39,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "view.h"
|
#include "view.h"
|
||||||
#include "nnexts.h"
|
#include "nnexts.h"
|
||||||
#include "zstring.h"
|
#include "zstring.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "gstrings.h"
|
#include "gstrings.h"
|
||||||
#include "v_2ddrawer.h"
|
#include "v_2ddrawer.h"
|
||||||
#include "v_video.h"
|
#include "v_video.h"
|
||||||
|
@ -47,6 +47,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "glbackend/glbackend.h"
|
#include "glbackend/glbackend.h"
|
||||||
#include "statusbar.h"
|
#include "statusbar.h"
|
||||||
#include "automap.h"
|
#include "automap.h"
|
||||||
|
#include "v_draw.h"
|
||||||
|
|
||||||
CVARD(Bool, hud_powerupduration, true, CVAR_ARCHIVE/*|CVAR_FRONTEND_BLOOD*/, "enable/disable displaying the remaining seconds for power-ups")
|
CVARD(Bool, hud_powerupduration, true, CVAR_ARCHIVE/*|CVAR_FRONTEND_BLOOD*/, "enable/disable displaying the remaining seconds for power-ups")
|
||||||
|
|
||||||
|
|
|
@ -39,13 +39,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "view.h"
|
#include "view.h"
|
||||||
#include "nnexts.h"
|
#include "nnexts.h"
|
||||||
#include "zstring.h"
|
#include "zstring.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "gstrings.h"
|
#include "gstrings.h"
|
||||||
#include "v_2ddrawer.h"
|
#include "v_2ddrawer.h"
|
||||||
#include "v_video.h"
|
#include "v_video.h"
|
||||||
#include "v_font.h"
|
#include "v_font.h"
|
||||||
#include "statusbar.h"
|
#include "statusbar.h"
|
||||||
#include "automap.h"
|
#include "automap.h"
|
||||||
|
#include "v_draw.h"
|
||||||
#include "glbackend/glbackend.h"
|
#include "glbackend/glbackend.h"
|
||||||
|
|
||||||
BEGIN_BLD_NS
|
BEGIN_BLD_NS
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "v_2ddrawer.h"
|
#include "v_2ddrawer.h"
|
||||||
#include "v_draw.h"
|
#include "v_draw.h"
|
||||||
#include "stats.h"
|
#include "stats.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "earcut.hpp"
|
#include "earcut.hpp"
|
||||||
#include "gamestate.h"
|
#include "gamestate.h"
|
||||||
|
|
|
@ -35,6 +35,7 @@ bool hw_int_useindexedcolortextures;
|
||||||
CUSTOM_CVARD(Bool, hw_useindexedcolortextures, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enable/disable indexed color texture rendering")
|
CUSTOM_CVARD(Bool, hw_useindexedcolortextures, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enable/disable indexed color texture rendering")
|
||||||
{
|
{
|
||||||
hw_int_useindexedcolortextures = self;
|
hw_int_useindexedcolortextures = self;
|
||||||
|
if (screen) screen->SetTextureFilterMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -439,6 +439,9 @@ void F2DDrawer::AddTexture(FGameTexture* img, DrawParms& parms)
|
||||||
std::swap(v1, v2);
|
std::swap(v1, v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto osave = offset;
|
||||||
|
if (parms.nooffset) offset = { 0,0 };
|
||||||
|
|
||||||
if (parms.rotateangle == 0)
|
if (parms.rotateangle == 0)
|
||||||
{
|
{
|
||||||
double x = parms.x - parms.left * xscale;
|
double x = parms.x - parms.left * xscale;
|
||||||
|
@ -461,10 +464,10 @@ void F2DDrawer::AddTexture(FGameTexture* img, DrawParms& parms)
|
||||||
|
|
||||||
if (x < (double)parms.lclip || y < (double)parms.uclip || x + w >(double)parms.rclip || y + h >(double)parms.dclip)
|
if (x < (double)parms.lclip || y < (double)parms.uclip || x + w >(double)parms.rclip || y + h >(double)parms.dclip)
|
||||||
{
|
{
|
||||||
dg.mScissor[0] = parms.lclip;
|
dg.mScissor[0] = parms.lclip + int(offset.X);
|
||||||
dg.mScissor[1] = parms.uclip;
|
dg.mScissor[1] = parms.uclip + int(offset.Y);
|
||||||
dg.mScissor[2] = parms.rclip;
|
dg.mScissor[2] = parms.rclip + int(offset.X);
|
||||||
dg.mScissor[3] = parms.dclip;
|
dg.mScissor[3] = parms.dclip + int(offset.Y);
|
||||||
dg.mFlags |= DTF_Scissor;
|
dg.mFlags |= DTF_Scissor;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -475,10 +478,10 @@ void F2DDrawer::AddTexture(FGameTexture* img, DrawParms& parms)
|
||||||
dg.mVertCount = 4;
|
dg.mVertCount = 4;
|
||||||
dg.mVertIndex = (int)mVertices.Reserve(4);
|
dg.mVertIndex = (int)mVertices.Reserve(4);
|
||||||
TwoDVertex* ptr = &mVertices[dg.mVertIndex];
|
TwoDVertex* ptr = &mVertices[dg.mVertIndex];
|
||||||
ptr->Set(x, y, 0, u1, v1, vertexcolor); ptr++;
|
Set(ptr, x, y, 0, u1, v1, vertexcolor); ptr++;
|
||||||
ptr->Set(x, y + h, 0, u1, v2, vertexcolor); ptr++;
|
Set(ptr, x, y + h, 0, u1, v2, vertexcolor); ptr++;
|
||||||
ptr->Set(x + w, y, 0, u2, v1, vertexcolor); ptr++;
|
Set(ptr, x + w, y, 0, u2, v1, vertexcolor); ptr++;
|
||||||
ptr->Set(x + w, y + h, 0, u2, v2, vertexcolor); ptr++;
|
Set(ptr, x + w, y + h, 0, u2, v2, vertexcolor); ptr++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -502,25 +505,26 @@ void F2DDrawer::AddTexture(FGameTexture* img, DrawParms& parms)
|
||||||
double x4 = parms.x + xscale * (xd2 * cosang + yd2 * sinang);
|
double x4 = parms.x + xscale * (xd2 * cosang + yd2 * sinang);
|
||||||
double y4 = parms.y - yscale * (xd2 * sinang - yd2 * cosang);
|
double y4 = parms.y - yscale * (xd2 * sinang - yd2 * cosang);
|
||||||
|
|
||||||
dg.mScissor[0] = parms.lclip;
|
dg.mScissor[0] = parms.lclip + int(offset.X);
|
||||||
dg.mScissor[1] = parms.uclip;
|
dg.mScissor[1] = parms.uclip + int(offset.Y);
|
||||||
dg.mScissor[2] = parms.rclip;
|
dg.mScissor[2] = parms.rclip + int(offset.X);
|
||||||
dg.mScissor[3] = parms.dclip;
|
dg.mScissor[3] = parms.dclip + int(offset.Y);
|
||||||
dg.mFlags |= DTF_Scissor;
|
dg.mFlags |= DTF_Scissor;
|
||||||
|
|
||||||
dg.mVertCount = 4;
|
dg.mVertCount = 4;
|
||||||
dg.mVertIndex = (int)mVertices.Reserve(4);
|
dg.mVertIndex = (int)mVertices.Reserve(4);
|
||||||
TwoDVertex* ptr = &mVertices[dg.mVertIndex];
|
TwoDVertex* ptr = &mVertices[dg.mVertIndex];
|
||||||
ptr->Set(x1, y1, 0, u1, v1, vertexcolor); ptr++;
|
Set(ptr, x1, y1, 0, u1, v1, vertexcolor); ptr++;
|
||||||
ptr->Set(x2, y2, 0, u1, v2, vertexcolor); ptr++;
|
Set(ptr, x2, y2, 0, u1, v2, vertexcolor); ptr++;
|
||||||
ptr->Set(x3, y3, 0, u2, v1, vertexcolor); ptr++;
|
Set(ptr, x3, y3, 0, u2, v1, vertexcolor); ptr++;
|
||||||
ptr->Set(x4, y4, 0, u2, v2, vertexcolor); ptr++;
|
Set(ptr, x4, y4, 0, u2, v2, vertexcolor); ptr++;
|
||||||
|
|
||||||
}
|
}
|
||||||
dg.mIndexIndex = mIndices.Size();
|
dg.mIndexIndex = mIndices.Size();
|
||||||
dg.mIndexCount += 6;
|
dg.mIndexCount += 6;
|
||||||
AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2);
|
AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2);
|
||||||
AddCommand(&dg);
|
AddCommand(&dg);
|
||||||
|
offset = osave;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -561,6 +565,9 @@ void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms)
|
||||||
shape->dirty = false;
|
shape->dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto osave = offset;
|
||||||
|
if (parms.nooffset) offset = { 0,0 };
|
||||||
|
|
||||||
double minx = 16383, miny = 16383, maxx = -16384, maxy = -16384;
|
double minx = 16383, miny = 16383, maxx = -16384, maxy = -16384;
|
||||||
for ( int i=0; i<dg.mVertCount; i++ )
|
for ( int i=0; i<dg.mVertCount; i++ )
|
||||||
{
|
{
|
||||||
|
@ -571,10 +578,10 @@ void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms)
|
||||||
}
|
}
|
||||||
if (minx < (double)parms.lclip || miny < (double)parms.uclip || maxx >(double)parms.rclip || maxy >(double)parms.dclip)
|
if (minx < (double)parms.lclip || miny < (double)parms.uclip || maxx >(double)parms.rclip || maxy >(double)parms.dclip)
|
||||||
{
|
{
|
||||||
dg.mScissor[0] = parms.lclip;
|
dg.mScissor[0] = parms.lclip + int(offset.X);
|
||||||
dg.mScissor[1] = parms.uclip;
|
dg.mScissor[1] = parms.uclip + int(offset.Y);
|
||||||
dg.mScissor[2] = parms.rclip;
|
dg.mScissor[2] = parms.rclip + int(offset.X);
|
||||||
dg.mScissor[3] = parms.dclip;
|
dg.mScissor[3] = parms.dclip + int(offset.Y);
|
||||||
dg.mFlags |= DTF_Scissor;
|
dg.mFlags |= DTF_Scissor;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -583,7 +590,7 @@ void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms)
|
||||||
dg.mVertIndex = (int)mVertices.Reserve(dg.mVertCount);
|
dg.mVertIndex = (int)mVertices.Reserve(dg.mVertCount);
|
||||||
TwoDVertex *ptr = &mVertices[dg.mVertIndex];
|
TwoDVertex *ptr = &mVertices[dg.mVertIndex];
|
||||||
for ( int i=0; i<dg.mVertCount; i++ )
|
for ( int i=0; i<dg.mVertCount; i++ )
|
||||||
ptr[i].Set(shape->mTransformedVertices[i].X, shape->mTransformedVertices[i].Y, 0, shape->mCoords[i].X, shape->mCoords[i].Y, vertexcolor);
|
Set(&ptr[i], shape->mTransformedVertices[i].X, shape->mTransformedVertices[i].Y, 0, shape->mCoords[i].X, shape->mCoords[i].Y, vertexcolor);
|
||||||
dg.mIndexIndex = mIndices.Size();
|
dg.mIndexIndex = mIndices.Size();
|
||||||
dg.mIndexCount += shape->mIndices.Size();
|
dg.mIndexCount += shape->mIndices.Size();
|
||||||
for ( int i=0; i<int(shape->mIndices.Size()); i+=3 )
|
for ( int i=0; i<int(shape->mIndices.Size()); i+=3 )
|
||||||
|
@ -599,6 +606,7 @@ void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms)
|
||||||
AddIndices(dg.mVertIndex, 3, shape->mIndices[i], shape->mIndices[i+1], shape->mIndices[i+2]);
|
AddIndices(dg.mVertIndex, 3, shape->mIndices[i], shape->mIndices[i+1], shape->mIndices[i+2]);
|
||||||
}
|
}
|
||||||
AddCommand(&dg);
|
AddCommand(&dg);
|
||||||
|
offset = osave;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -655,7 +663,7 @@ void F2DDrawer::AddPoly(FGameTexture *texture, FVector2 *points, int npoints,
|
||||||
u = t * cosrot - v * sinrot;
|
u = t * cosrot - v * sinrot;
|
||||||
v = v * cosrot + t * sinrot;
|
v = v * cosrot + t * sinrot;
|
||||||
}
|
}
|
||||||
mVertices[poly.mVertIndex+i].Set(points[i].X, points[i].Y, 0, u*uscale, v*vscale, color0);
|
Set(&mVertices[poly.mVertIndex+i], points[i].X, points[i].Y, 0, u*uscale, v*vscale, color0);
|
||||||
}
|
}
|
||||||
poly.mIndexIndex = mIndices.Size();
|
poly.mIndexIndex = mIndices.Size();
|
||||||
|
|
||||||
|
@ -694,10 +702,10 @@ void F2DDrawer::AddPoly(FGameTexture* img, FVector4* vt, size_t vtcount, unsigne
|
||||||
dg.mType = DrawTypeTriangles;
|
dg.mType = DrawTypeTriangles;
|
||||||
if (clipx1 > 0 || clipy1 > 0 || clipx2 < GetWidth() - 1 || clipy2 < GetHeight() - 1)
|
if (clipx1 > 0 || clipy1 > 0 || clipx2 < GetWidth() - 1 || clipy2 < GetHeight() - 1)
|
||||||
{
|
{
|
||||||
dg.mScissor[0] = clipx1;
|
dg.mScissor[0] = clipx1 + int(offset.X);
|
||||||
dg.mScissor[1] = clipy1;
|
dg.mScissor[1] = clipy1 + int(offset.Y);
|
||||||
dg.mScissor[2] = clipx2 + 1;
|
dg.mScissor[2] = clipx2 + 1 + int(offset.X);
|
||||||
dg.mScissor[3] = clipy2 + 1;
|
dg.mScissor[3] = clipy2 + 1 + int(offset.Y);
|
||||||
dg.mFlags |= DTF_Scissor;
|
dg.mFlags |= DTF_Scissor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -712,7 +720,7 @@ void F2DDrawer::AddPoly(FGameTexture* img, FVector4* vt, size_t vtcount, unsigne
|
||||||
|
|
||||||
for (size_t i=0;i<vtcount;i++)
|
for (size_t i=0;i<vtcount;i++)
|
||||||
{
|
{
|
||||||
ptr->Set(vt[i].X, vt[i].Y, 0.f, vt[i].Z, vt[i].W, color);
|
Set(ptr, vt[i].X, vt[i].Y, 0.f, vt[i].Z, vt[i].W, color);
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -841,18 +849,18 @@ void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FGameTextu
|
||||||
dg.mVertIndex = (int)mVertices.Reserve(4);
|
dg.mVertIndex = (int)mVertices.Reserve(4);
|
||||||
auto ptr = &mVertices[dg.mVertIndex];
|
auto ptr = &mVertices[dg.mVertIndex];
|
||||||
|
|
||||||
ptr->Set(left, top, 0, fU1, fV1, color); ptr++;
|
Set(ptr, left, top, 0, fU1, fV1, color); ptr++;
|
||||||
if (local_origin < 4)
|
if (local_origin < 4)
|
||||||
{
|
{
|
||||||
ptr->Set(left, bottom, 0, fU1, fV2, color); ptr++;
|
Set(ptr, left, bottom, 0, fU1, fV2, color); ptr++;
|
||||||
ptr->Set(right, top, 0, fU2, fV1, color); ptr++;
|
Set(ptr, right, top, 0, fU2, fV1, color); ptr++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ptr->Set(left, bottom, 0, fU2, fV1, color); ptr++;
|
Set(ptr, left, bottom, 0, fU2, fV1, color); ptr++;
|
||||||
ptr->Set(right, top, 0, fU1, fV2, color); ptr++;
|
Set(ptr, right, top, 0, fU1, fV2, color); ptr++;
|
||||||
}
|
}
|
||||||
ptr->Set(right, bottom, 0, fU2, fV2, color); ptr++;
|
Set(ptr, right, bottom, 0, fU2, fV2, color); ptr++;
|
||||||
dg.mIndexIndex = mIndices.Size();
|
dg.mIndexIndex = mIndices.Size();
|
||||||
dg.mIndexCount += 6;
|
dg.mIndexCount += 6;
|
||||||
AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2);
|
AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2);
|
||||||
|
@ -875,10 +883,10 @@ void F2DDrawer::AddColorOnlyQuad(int x1, int y1, int w, int h, PalEntry color, F
|
||||||
dg.mVertIndex = (int)mVertices.Reserve(4);
|
dg.mVertIndex = (int)mVertices.Reserve(4);
|
||||||
dg.mRenderStyle = style? *style : LegacyRenderStyles[STYLE_Translucent];
|
dg.mRenderStyle = style? *style : LegacyRenderStyles[STYLE_Translucent];
|
||||||
auto ptr = &mVertices[dg.mVertIndex];
|
auto ptr = &mVertices[dg.mVertIndex];
|
||||||
ptr->Set(x1, y1, 0, 0, 0, color); ptr++;
|
Set(ptr, x1, y1, 0, 0, 0, color); ptr++;
|
||||||
ptr->Set(x1, y1 + h, 0, 0, 0, color); ptr++;
|
Set(ptr, x1, y1 + h, 0, 0, 0, color); ptr++;
|
||||||
ptr->Set(x1 + w, y1, 0, 0, 0, color); ptr++;
|
Set(ptr, x1 + w, y1, 0, 0, 0, color); ptr++;
|
||||||
ptr->Set(x1 + w, y1 + h, 0, 0, 0, color); ptr++;
|
Set(ptr, x1 + w, y1 + h, 0, 0, 0, color); ptr++;
|
||||||
dg.mIndexIndex = mIndices.Size();
|
dg.mIndexIndex = mIndices.Size();
|
||||||
dg.mIndexCount += 6;
|
dg.mIndexCount += 6;
|
||||||
AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2);
|
AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2);
|
||||||
|
@ -911,10 +919,10 @@ void F2DDrawer::AddLine(double x1, double y1, double x2, double y2, int clipx1,
|
||||||
|
|
||||||
if (clipx1 > 0 || clipy1 > 0 || clipx2 < GetWidth()- 1 || clipy2 < GetHeight() - 1)
|
if (clipx1 > 0 || clipy1 > 0 || clipx2 < GetWidth()- 1 || clipy2 < GetHeight() - 1)
|
||||||
{
|
{
|
||||||
dg.mScissor[0] = clipx1;
|
dg.mScissor[0] = clipx1 + int(offset.X);
|
||||||
dg.mScissor[1] = clipy1;
|
dg.mScissor[1] = clipy1 + int(offset.Y);
|
||||||
dg.mScissor[2] = clipx2 + 1;
|
dg.mScissor[2] = clipx2 + 1 + int(offset.X);
|
||||||
dg.mScissor[3] = clipy2 + 1;
|
dg.mScissor[3] = clipy2 + 1 + int(offset.Y);
|
||||||
dg.mFlags |= DTF_Scissor;
|
dg.mFlags |= DTF_Scissor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -922,8 +930,8 @@ void F2DDrawer::AddLine(double x1, double y1, double x2, double y2, int clipx1,
|
||||||
dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent];
|
dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent];
|
||||||
dg.mVertCount = 2;
|
dg.mVertCount = 2;
|
||||||
dg.mVertIndex = (int)mVertices.Reserve(2);
|
dg.mVertIndex = (int)mVertices.Reserve(2);
|
||||||
mVertices[dg.mVertIndex].Set(x1, y1, 0, 0, 0, p);
|
Set(&mVertices[dg.mVertIndex], x1, y1, 0, 0, 0, p);
|
||||||
mVertices[dg.mVertIndex+1].Set(x2, y2, 0, 0, 0, p);
|
Set(&mVertices[dg.mVertIndex+1], x2, y2, 0, 0, 0, p);
|
||||||
AddCommand(&dg);
|
AddCommand(&dg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -958,10 +966,10 @@ void F2DDrawer::AddThickLine(int x1, int y1, int x2, int y2, double thickness, u
|
||||||
dg.mVertIndex = (int)mVertices.Reserve(4);
|
dg.mVertIndex = (int)mVertices.Reserve(4);
|
||||||
dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent];
|
dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent];
|
||||||
auto ptr = &mVertices[dg.mVertIndex];
|
auto ptr = &mVertices[dg.mVertIndex];
|
||||||
ptr->Set(corner0.X, corner0.Y, 0, 0, 0, p); ptr++;
|
Set(ptr, corner0.X, corner0.Y, 0, 0, 0, p); ptr++;
|
||||||
ptr->Set(corner1.X, corner1.Y, 0, 0, 0, p); ptr++;
|
Set(ptr, corner1.X, corner1.Y, 0, 0, 0, p); ptr++;
|
||||||
ptr->Set(corner2.X, corner2.Y, 0, 0, 0, p); ptr++;
|
Set(ptr, corner2.X, corner2.Y, 0, 0, 0, p); ptr++;
|
||||||
ptr->Set(corner3.X, corner3.Y, 0, 0, 0, p); ptr++;
|
Set(ptr, corner3.X, corner3.Y, 0, 0, 0, p); ptr++;
|
||||||
dg.mIndexIndex = mIndices.Size();
|
dg.mIndexIndex = mIndices.Size();
|
||||||
dg.mIndexCount += 6;
|
dg.mIndexCount += 6;
|
||||||
AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2);
|
AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2);
|
||||||
|
@ -985,7 +993,7 @@ void F2DDrawer::AddPixel(int x1, int y1, uint32_t color)
|
||||||
dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent];
|
dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent];
|
||||||
dg.mVertCount = 1;
|
dg.mVertCount = 1;
|
||||||
dg.mVertIndex = (int)mVertices.Reserve(1);
|
dg.mVertIndex = (int)mVertices.Reserve(1);
|
||||||
mVertices[dg.mVertIndex].Set(x1, y1, 0, 0, 0, p);
|
Set(&mVertices[dg.mVertIndex], x1, y1, 0, 0, 0, p);
|
||||||
AddCommand(&dg);
|
AddCommand(&dg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -167,6 +167,7 @@ public:
|
||||||
bool isIn2D;
|
bool isIn2D;
|
||||||
bool locked; // prevents clearing of the data so it can be reused multiple times (useful for screen fades)
|
bool locked; // prevents clearing of the data so it can be reused multiple times (useful for screen fades)
|
||||||
float screenFade = 1.f;
|
float screenFade = 1.f;
|
||||||
|
DVector2 offset;
|
||||||
public:
|
public:
|
||||||
int fullscreenautoaspect = 0;
|
int fullscreenautoaspect = 0;
|
||||||
int cliptop = -1, clipleft = -1, clipwidth = -1, clipheight = -1;
|
int cliptop = -1, clipleft = -1, clipwidth = -1, clipheight = -1;
|
||||||
|
@ -216,6 +217,19 @@ public:
|
||||||
void SetClipRect(int x, int y, int w, int h);
|
void SetClipRect(int x, int y, int w, int h);
|
||||||
void GetClipRect(int* x, int* y, int* w, int* h);
|
void GetClipRect(int* x, int* y, int* w, int* h);
|
||||||
|
|
||||||
|
DVector2 SetOffset(const DVector2& vec)
|
||||||
|
{
|
||||||
|
auto v = offset;
|
||||||
|
offset = vec;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set(TwoDVertex* v, double xx, double yy, double zz, double uu, double vv, PalEntry col)
|
||||||
|
{
|
||||||
|
v->Set(xx + offset.X, yy + offset.Y, zz, uu, vv, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int DrawCount() const
|
int DrawCount() const
|
||||||
{
|
{
|
||||||
return mData.Size();
|
return mData.Size();
|
||||||
|
|
|
@ -417,8 +417,6 @@ DEFINE_ACTION_FUNCTION(_Screen, GetFullscreenRect)
|
||||||
PARAM_FLOAT(virth);
|
PARAM_FLOAT(virth);
|
||||||
PARAM_INT(fsmode);
|
PARAM_INT(fsmode);
|
||||||
|
|
||||||
if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function");
|
|
||||||
|
|
||||||
DrawParms parms;
|
DrawParms parms;
|
||||||
DoubleRect rect;
|
DoubleRect rect;
|
||||||
parms.viewport.width = twod->GetWidth();
|
parms.viewport.width = twod->GetWidth();
|
||||||
|
@ -705,6 +703,7 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double
|
||||||
parms->rotateangle = 0;
|
parms->rotateangle = 0;
|
||||||
parms->flipoffsets = false;
|
parms->flipoffsets = false;
|
||||||
parms->indexed = false;
|
parms->indexed = false;
|
||||||
|
parms->nooffset = false;
|
||||||
|
|
||||||
// Parse the tag list for attributes. (For floating point attributes,
|
// Parse the tag list for attributes. (For floating point attributes,
|
||||||
// consider that the C ABI dictates that all floats be promoted to
|
// consider that the C ABI dictates that all floats be promoted to
|
||||||
|
@ -916,6 +915,10 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double
|
||||||
parms->flipoffsets = ListGetInt(tags);
|
parms->flipoffsets = ListGetInt(tags);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DTA_NoOffset:
|
||||||
|
parms->nooffset = ListGetInt(tags);
|
||||||
|
break;
|
||||||
|
|
||||||
case DTA_SrcX:
|
case DTA_SrcX:
|
||||||
parms->srcx = ListGetDouble(tags) / img->GetDisplayWidth();
|
parms->srcx = ListGetDouble(tags) / img->GetDisplayWidth();
|
||||||
break;
|
break;
|
||||||
|
@ -1531,9 +1534,30 @@ void DrawFrame(F2DDrawer* twod, PalEntry color, int left, int top, int width, in
|
||||||
twod->AddColorOnlyQuad(right, top - offset, offset, height + 2 * offset, color);
|
twod->AddColorOnlyQuad(right, top - offset, offset, height + 2 * offset, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(_Screen, DrawLineFrame)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_COLOR(color);
|
||||||
|
PARAM_INT(left);
|
||||||
|
PARAM_INT(top);
|
||||||
|
PARAM_INT(width);
|
||||||
|
PARAM_INT(height);
|
||||||
|
PARAM_INT(thickness);
|
||||||
|
DrawFrame(twod, color, left, top, width, height, thickness);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void V_CalcCleanFacs(int designwidth, int designheight, int realwidth, int realheight, int* cleanx, int* cleany, int* _cx1, int* _cx2)
|
void V_CalcCleanFacs(int designwidth, int designheight, int realwidth, int realheight, int* cleanx, int* cleany, int* _cx1, int* _cx2)
|
||||||
{
|
{
|
||||||
if (designheight < 240 && realheight >= 480) designheight = 240;
|
if (designheight < 240 && realheight >= 480) designheight = 240;
|
||||||
*cleanx = *cleany = std::min(realwidth / designwidth, realheight / designheight);
|
*cleanx = *cleany = std::min(realwidth / designwidth, realheight / designheight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(_Screen, SetOffset)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_FLOAT(x);
|
||||||
|
PARAM_FLOAT(y);
|
||||||
|
ACTION_RETURN_VEC2(twod->SetOffset(DVector2(x, y)));
|
||||||
|
}
|
|
@ -131,6 +131,7 @@ enum
|
||||||
DTA_FlipOffsets, // Flips offsets when using DTA_FlipX and DTA_FlipY, this cannot be automatic due to unexpected behavior with unoffsetted graphics.
|
DTA_FlipOffsets, // Flips offsets when using DTA_FlipX and DTA_FlipY, this cannot be automatic due to unexpected behavior with unoffsetted graphics.
|
||||||
DTA_Indexed, // Use an indexed texture combined with the given translation.
|
DTA_Indexed, // Use an indexed texture combined with the given translation.
|
||||||
DTA_CleanTop, // Like DTA_Clean but aligns to the top of the screen instead of the center.
|
DTA_CleanTop, // Like DTA_Clean but aligns to the top of the screen instead of the center.
|
||||||
|
DTA_NoOffset, // Ignore 2D drawer's offset.
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -198,6 +199,7 @@ struct DrawParms
|
||||||
bool burn;
|
bool burn;
|
||||||
bool flipoffsets;
|
bool flipoffsets;
|
||||||
bool indexed;
|
bool indexed;
|
||||||
|
bool nooffset;
|
||||||
int8_t fsscalemode;
|
int8_t fsscalemode;
|
||||||
double srcx, srcy;
|
double srcx, srcy;
|
||||||
double srcwidth, srcheight;
|
double srcwidth, srcheight;
|
||||||
|
|
|
@ -99,7 +99,7 @@ SoundStream *S_CreateCustomStream(size_t size, int samplerate, int numchannels,
|
||||||
{
|
{
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
if (numchannels < 2) flags |= SoundStream::Mono;
|
if (numchannels < 2) flags |= SoundStream::Mono;
|
||||||
auto stream = GSnd->CreateStream(cb, size, flags, samplerate, userdata);
|
auto stream = GSnd->CreateStream(cb, int(size), flags, samplerate, userdata);
|
||||||
if (stream) stream->Play(true, 1);
|
if (stream) stream->Play(true, 1);
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,6 @@ enum
|
||||||
};
|
};
|
||||||
static FRandom pr_soundpitch ("SoundPitch");
|
static FRandom pr_soundpitch ("SoundPitch");
|
||||||
SoundEngine* soundEngine;
|
SoundEngine* soundEngine;
|
||||||
int sfx_empty = -1;
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
@ -713,10 +712,9 @@ sfxinfo_t *SoundEngine::LoadSound(sfxinfo_t *sfx)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
// If the sound doesn't exist, replace it with the empty sound.
|
if (sfx->lumpnum == sfx_empty)
|
||||||
if (sfx->lumpnum == -1)
|
|
||||||
{
|
{
|
||||||
sfx->lumpnum = sfx_empty;
|
return sfx;
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if there is another sound already initialized with this lump. If so,
|
// See if there is another sound already initialized with this lump. If so,
|
||||||
|
@ -1532,31 +1530,12 @@ int SoundEngine::AddSoundLump(const char* logicalname, int lump, int CurrentPitc
|
||||||
S_sfx.Reserve(1);
|
S_sfx.Reserve(1);
|
||||||
sfxinfo_t &newsfx = S_sfx.Last();
|
sfxinfo_t &newsfx = S_sfx.Last();
|
||||||
|
|
||||||
newsfx.data.Clear();
|
|
||||||
newsfx.name = logicalname;
|
newsfx.name = logicalname;
|
||||||
newsfx.lumpnum = lump;
|
newsfx.lumpnum = lump;
|
||||||
newsfx.next = 0;
|
newsfx.next = 0;
|
||||||
newsfx.index = 0;
|
|
||||||
newsfx.Volume = 1;
|
|
||||||
newsfx.Attenuation = 1;
|
|
||||||
newsfx.PitchMask = CurrentPitchMask;
|
newsfx.PitchMask = CurrentPitchMask;
|
||||||
newsfx.DefPitch = 0.0;
|
|
||||||
newsfx.DefPitchMax = 0.0;
|
|
||||||
newsfx.NearLimit = nearlimit;
|
newsfx.NearLimit = nearlimit;
|
||||||
newsfx.LimitRange = 256 * 256;
|
|
||||||
newsfx.bRandomHeader = false;
|
|
||||||
newsfx.bLoadRAW = false;
|
|
||||||
newsfx.b16bit = false;
|
|
||||||
newsfx.bUsed = false;
|
|
||||||
newsfx.bSingular = false;
|
|
||||||
newsfx.bTentative = false;
|
|
||||||
newsfx.ResourceId = resid;
|
newsfx.ResourceId = resid;
|
||||||
newsfx.RawRate = 0;
|
|
||||||
newsfx.link = sfxinfo_t::NO_LINK;
|
|
||||||
newsfx.Rolloff.RolloffType = ROLLOFF_Doom;
|
|
||||||
newsfx.Rolloff.MinDistance = 0;
|
|
||||||
newsfx.Rolloff.MaxDistance = 0;
|
|
||||||
newsfx.LoopStart = -1;
|
|
||||||
|
|
||||||
if (resid >= 0) ResIdMap[resid] = S_sfx.Size() - 1;
|
if (resid >= 0) ResIdMap[resid] = S_sfx.Size() - 1;
|
||||||
return (int)S_sfx.Size()-1;
|
return (int)S_sfx.Size()-1;
|
||||||
|
|
|
@ -8,7 +8,12 @@ struct FRandomSoundList
|
||||||
uint32_t Owner = 0;
|
uint32_t Owner = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int sfx_empty;
|
enum
|
||||||
|
{
|
||||||
|
sfx_empty = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// SoundFX struct.
|
// SoundFX struct.
|
||||||
|
@ -17,71 +22,38 @@ struct sfxinfo_t
|
||||||
{
|
{
|
||||||
// Next field is for use by the system sound interface.
|
// Next field is for use by the system sound interface.
|
||||||
// A non-null data means the sound has been loaded.
|
// A non-null data means the sound has been loaded.
|
||||||
SoundHandle data;
|
SoundHandle data{};
|
||||||
|
|
||||||
FString name; // [RH] Sound name defined in SNDINFO
|
FString name; // [RH] Sound name defined in SNDINFO
|
||||||
int lumpnum; // lump number of sfx
|
int lumpnum = sfx_empty; // lump number of sfx
|
||||||
|
|
||||||
unsigned int next, index; // [RH] For hashing
|
unsigned int next = -1, index = 0; // [RH] For hashing
|
||||||
float Volume;
|
float Volume = 1.f;
|
||||||
|
|
||||||
int ResourceId; // Resource ID as implemented by Blood. Not used by Doom but added for completeness.
|
int ResourceId = -1; // Resource ID as implemented by Blood. Not used by Doom but added for completeness.
|
||||||
uint8_t PitchMask;
|
float LimitRange = 256*256; // Range for sound limiting (squared for faster computations)
|
||||||
int16_t NearLimit; // 0 means unlimited
|
float DefPitch = 0.f; // A defined pitch instead of a random one the sound plays at, similar to A_StartSound.
|
||||||
float LimitRange; // Range for sound limiting (squared for faster computations)
|
float DefPitchMax = 0.f; // Randomized range with stronger control over pitch itself.
|
||||||
float DefPitch; // A defined pitch instead of a random one the sound plays at, similar to A_StartSound.
|
|
||||||
float DefPitchMax; // Randomized range with stronger control over pitch itself.
|
|
||||||
|
|
||||||
unsigned bRandomHeader:1;
|
int16_t NearLimit = 4; // 0 means unlimited.
|
||||||
unsigned bLoadRAW:1;
|
uint8_t PitchMask = 0;
|
||||||
unsigned b16bit:1;
|
bool bRandomHeader = false;
|
||||||
unsigned bUsed:1;
|
bool bLoadRAW = false;
|
||||||
unsigned bSingular:1;
|
bool b16bit = false;
|
||||||
|
bool bUsed = false;
|
||||||
|
bool bSingular = false;
|
||||||
|
bool bTentative = true;
|
||||||
|
|
||||||
unsigned bTentative:1;
|
|
||||||
TArray<int> UserData;
|
TArray<int> UserData;
|
||||||
|
|
||||||
int RawRate; // Sample rate to use when bLoadRAW is true
|
int RawRate = 0; // Sample rate to use when bLoadRAW is true
|
||||||
|
int LoopStart = -1; // -1 means no specific loop defined
|
||||||
|
|
||||||
int LoopStart; // -1 means no specific loop defined
|
unsigned int link = NO_LINK;;
|
||||||
|
|
||||||
unsigned int link;
|
|
||||||
enum { NO_LINK = 0xffffffff };
|
enum { NO_LINK = 0xffffffff };
|
||||||
|
|
||||||
FRolloffInfo Rolloff;
|
FRolloffInfo Rolloff{};
|
||||||
float Attenuation; // Multiplies the attenuation passed to S_Sound.
|
float Attenuation = 1.f; // Multiplies the attenuation passed to S_Sound.
|
||||||
|
|
||||||
void MarkUsed(); // Marks this sound as used.
|
|
||||||
|
|
||||||
void Clear()
|
|
||||||
{
|
|
||||||
data.Clear();
|
|
||||||
lumpnum = -1; // lump number of sfx
|
|
||||||
next = -1;
|
|
||||||
index = 0; // [RH] For hashing
|
|
||||||
Volume = 1.f;
|
|
||||||
ResourceId = -1;
|
|
||||||
PitchMask = 0;
|
|
||||||
NearLimit = 4; // 0 means unlimited
|
|
||||||
LimitRange = 256*256;
|
|
||||||
|
|
||||||
bRandomHeader = false;
|
|
||||||
bLoadRAW = false;
|
|
||||||
b16bit= false;
|
|
||||||
bUsed = false;
|
|
||||||
bSingular = false;
|
|
||||||
|
|
||||||
bTentative = true;
|
|
||||||
|
|
||||||
RawRate = 0; // Sample rate to use when bLoadRAW is true
|
|
||||||
|
|
||||||
LoopStart = 0; // -1 means no specific loop defined
|
|
||||||
|
|
||||||
link = NO_LINK;
|
|
||||||
|
|
||||||
Rolloff = {};
|
|
||||||
Attenuation = 1.f;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Rolloff types
|
// Rolloff types
|
||||||
|
|
248
source/common/engine/date.cpp
Normal file
248
source/common/engine/date.cpp
Normal file
|
@ -0,0 +1,248 @@
|
||||||
|
/*
|
||||||
|
** date.cpp
|
||||||
|
**
|
||||||
|
** VM exports for engine backend classes
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
**
|
||||||
|
** 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 <time.h>
|
||||||
|
#include "c_dispatch.h"
|
||||||
|
#include "vm.h"
|
||||||
|
#include "zstring.h"
|
||||||
|
#include "printf.h"
|
||||||
|
|
||||||
|
time_t epochoffset = 0; // epoch start in seconds (0 = January 1st, 1970)
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// CCMD setdate
|
||||||
|
//
|
||||||
|
// Set the time to a specific value
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
UNSAFE_CCMD(setdate)
|
||||||
|
{
|
||||||
|
if (argv.argc() != 3)
|
||||||
|
{
|
||||||
|
Printf("setdate HH:MM:SS DD-MM-YYYY: Set the current date\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t today;
|
||||||
|
time(&today);
|
||||||
|
struct tm* timeinfo = localtime(&today);
|
||||||
|
if (timeinfo != nullptr)
|
||||||
|
{
|
||||||
|
auto clock = FString(argv[1]).Split(":");
|
||||||
|
auto date = FString(argv[2]).Split("-");
|
||||||
|
if(clock.Size() != 3 || date.Size() != 3)
|
||||||
|
{
|
||||||
|
Printf("setdate HH:MM:SS DD-MM-YYYY: Set the current date\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!clock[0].IsInt())
|
||||||
|
{
|
||||||
|
Printf("Invalid hour\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!clock[1].IsInt())
|
||||||
|
{
|
||||||
|
Printf("Invalid minutes\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!clock[2].IsInt())
|
||||||
|
{
|
||||||
|
Printf("Invalid seconds\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!date[0].IsInt())
|
||||||
|
{
|
||||||
|
Printf("Invalid day\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!date[1].IsInt())
|
||||||
|
{
|
||||||
|
Printf("Invalid month\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!date[2].IsInt())
|
||||||
|
{
|
||||||
|
Printf("Invalid year\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set Date
|
||||||
|
timeinfo->tm_hour = int( clock[0].ToLong() );
|
||||||
|
timeinfo->tm_min = int( clock[1].ToLong() );
|
||||||
|
timeinfo->tm_sec = int( clock[2].ToLong() );
|
||||||
|
timeinfo->tm_mday = int( date[0].ToLong() );
|
||||||
|
timeinfo->tm_mon = int( date[1].ToLong() - 1); // Month interally is 0 - 11
|
||||||
|
timeinfo->tm_year = int( date[2].ToLong() - 1900 ); // Year interally is 00 - 138
|
||||||
|
|
||||||
|
time_t newTime = mktime(timeinfo);
|
||||||
|
tm* t_old = localtime(&today);
|
||||||
|
time_t oldTime = mktime(t_old);
|
||||||
|
|
||||||
|
if (newTime == -1 || oldTime == -1)
|
||||||
|
{
|
||||||
|
Printf("Unable to set the date\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
epochoffset = newTime - oldTime;
|
||||||
|
|
||||||
|
// This deals with some inconsistent display behaviour for DST
|
||||||
|
// In this case, we want to emulate GCC's behaviour
|
||||||
|
today += epochoffset;
|
||||||
|
struct tm* t_new = localtime(&today);
|
||||||
|
if (t_new != nullptr)
|
||||||
|
{
|
||||||
|
char timeString[1024];
|
||||||
|
if (strftime(timeString, sizeof(timeString), "%H", t_new))
|
||||||
|
{
|
||||||
|
auto hour = FString(timeString).ToLong();
|
||||||
|
if (hour - clock[0].ToLong() == -1 || hour - clock[0].ToLong() == 23)
|
||||||
|
epochoffset += 3600;
|
||||||
|
else if (hour - clock[0].ToLong() == 1 || hour - clock[0].ToLong() == -23)
|
||||||
|
epochoffset -= 3600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Printf("Unable to set the date\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CCMD(getdate)
|
||||||
|
{
|
||||||
|
time_t now;
|
||||||
|
time(&now);
|
||||||
|
now += epochoffset;
|
||||||
|
struct tm* timeinfo = localtime(&now);
|
||||||
|
if (timeinfo != nullptr)
|
||||||
|
{
|
||||||
|
char timeString[1024];
|
||||||
|
if (strftime(timeString, sizeof(timeString), "%H:%M:%S %d-%m-%Y%n", timeinfo))
|
||||||
|
Printf("%s\n", timeString);
|
||||||
|
else
|
||||||
|
Printf("Error Retrieving Current Date\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Printf("Error Retrieving Current Date\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=====================================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//=====================================================================================
|
||||||
|
|
||||||
|
extern time_t epochoffset;
|
||||||
|
|
||||||
|
static int GetEpochTime()
|
||||||
|
{
|
||||||
|
time_t now;
|
||||||
|
time(&now);
|
||||||
|
return now != (time_t)(-1) ? int(now + epochoffset) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns an empty string if the Strf tokens are valid, otherwise returns the problematic token
|
||||||
|
static FString CheckStrfString(FString timeForm)
|
||||||
|
{
|
||||||
|
// Valid Characters after %
|
||||||
|
const char validSingles[] = { 'a','A','b','B','c','C','d','D','e','F','g','G','h','H','I','j','m','M','n','p','r','R','S','t','T','u','U','V','w','W','x','X','y','Y','z','Z' };
|
||||||
|
|
||||||
|
timeForm.Substitute("%%", "%a"); //Prevent %% from causing tokenizing problems
|
||||||
|
timeForm = "a" + timeForm; //Prevent %* at the beginning from causing a false error from tokenizing
|
||||||
|
|
||||||
|
auto tokens = timeForm.Split("%");
|
||||||
|
for (auto t : tokens)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
// % at end
|
||||||
|
if (t.Len() == 0) return FString("%");
|
||||||
|
|
||||||
|
// Single Character
|
||||||
|
for (size_t i = 0; i < sizeof(validSingles) / sizeof(validSingles[0]); i++)
|
||||||
|
{
|
||||||
|
if (t[0] == validSingles[i])
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) continue;
|
||||||
|
return FString("%") + t[0];
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FormatTime(const FString& timeForm, int timeVal, FString* result)
|
||||||
|
{
|
||||||
|
FString error = CheckStrfString(timeForm);
|
||||||
|
if (!error.IsEmpty())
|
||||||
|
ThrowAbortException(X_FORMAT_ERROR, "'%s' is not a valid format specifier of SystemTime.Format()", error.GetChars());
|
||||||
|
|
||||||
|
time_t val = timeVal;
|
||||||
|
struct tm* timeinfo = localtime(&val);
|
||||||
|
if (timeinfo != nullptr)
|
||||||
|
{
|
||||||
|
char timeString[1024];
|
||||||
|
if (strftime(timeString, sizeof(timeString), timeForm, timeinfo))
|
||||||
|
*result = timeString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION_NATIVE(_SystemTime, Now, GetEpochTime)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
ACTION_RETURN_INT(GetEpochTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION_NATIVE(_SystemTime, Format, FormatTime)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_STRING(timeForm);
|
||||||
|
PARAM_INT(timeVal);
|
||||||
|
FString result;
|
||||||
|
FormatTime(timeForm, timeVal, &result);
|
||||||
|
ACTION_RETURN_STRING(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,10 @@ struct SystemCallbacks
|
||||||
void (*MenuDim)();
|
void (*MenuDim)();
|
||||||
FString(*GetPlayerName)(int i);
|
FString(*GetPlayerName)(int i);
|
||||||
bool (*DispatchEvent)(event_t* ev);
|
bool (*DispatchEvent)(event_t* ev);
|
||||||
|
bool (*CheckGame)(const char* nm);
|
||||||
|
int (*GetGender)();
|
||||||
|
void (*MenuClosed)();
|
||||||
|
bool (*CheckMenudefOption)(const char* opt);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern SystemCallbacks sysCallbacks;
|
extern SystemCallbacks sysCallbacks;
|
||||||
|
@ -36,3 +40,6 @@ struct WadStuff
|
||||||
extern FString endoomName;
|
extern FString endoomName;
|
||||||
extern bool batchrun;
|
extern bool batchrun;
|
||||||
extern float menuBlurAmount;
|
extern float menuBlurAmount;
|
||||||
|
extern bool generic_ui;
|
||||||
|
|
||||||
|
void UpdateGenericUI(bool cvar);
|
||||||
|
|
|
@ -81,5 +81,6 @@ struct doomcom_t
|
||||||
|
|
||||||
extern doomcom_t doomcom;
|
extern doomcom_t doomcom;
|
||||||
extern bool netgame, multiplayer;
|
extern bool netgame, multiplayer;
|
||||||
|
extern int consoleplayer;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -715,8 +715,10 @@ xx(MainmenuTextOnly)
|
||||||
xx(Episodemenu)
|
xx(Episodemenu)
|
||||||
xx(Playerclassmenu)
|
xx(Playerclassmenu)
|
||||||
xx(HexenDefaultPlayerclassmenu)
|
xx(HexenDefaultPlayerclassmenu)
|
||||||
|
xx(ListMenuItemBloodDripDrawer)
|
||||||
xx(Skillmenu)
|
xx(Skillmenu)
|
||||||
xx(Startgame)
|
xx(Startgame)
|
||||||
|
xx(StartgameNoSkill)
|
||||||
xx(StartgameConfirm)
|
xx(StartgameConfirm)
|
||||||
xx(StartgameConfirmed)
|
xx(StartgameConfirmed)
|
||||||
xx(Loadgamemenu)
|
xx(Loadgamemenu)
|
||||||
|
@ -1078,6 +1080,7 @@ xx(PlayerSkin)
|
||||||
xx(NewPlayerMenu)
|
xx(NewPlayerMenu)
|
||||||
xx(AltHud)
|
xx(AltHud)
|
||||||
xx(GameScreen)
|
xx(GameScreen)
|
||||||
|
xx(ListM)
|
||||||
|
|
||||||
// summary
|
// summary
|
||||||
xx(cwidth)
|
xx(cwidth)
|
||||||
|
@ -1086,3 +1089,14 @@ xx(wrapwidth)
|
||||||
xx(scalefactorx)
|
xx(scalefactorx)
|
||||||
xx(scalefactory)
|
xx(scalefactory)
|
||||||
xx(scalemode)
|
xx(scalemode)
|
||||||
|
|
||||||
|
xy(menu_cursor, "menu/cursor")
|
||||||
|
xy(menu_choose, "menu/choose")
|
||||||
|
xy(menu_backup, "menu/backup")
|
||||||
|
xy(menu_clear, "menu/clear")
|
||||||
|
xy(menu_dismiss, "menu/dismiss")
|
||||||
|
xy(menu_change, "menu/change")
|
||||||
|
xy(menu_advance, "menu/advance")
|
||||||
|
|
||||||
|
xx(zoomsize)
|
||||||
|
|
||||||
|
|
|
@ -1044,8 +1044,8 @@ bool FScanner::ScanValue(bool allowfloat, bool evaluate)
|
||||||
auto d = constants.CheckKey(String);
|
auto d = constants.CheckKey(String);
|
||||||
if (!d) return false;
|
if (!d) return false;
|
||||||
if (!allowfloat && int64_t(*d) != *d) return false;
|
if (!allowfloat && int64_t(*d) != *d) return false;
|
||||||
BigNumber = *d;
|
BigNumber = int64_t(*d);
|
||||||
Number = *d;
|
Number = int(*d);
|
||||||
Float = *d;
|
Float = *d;
|
||||||
}
|
}
|
||||||
if (neg)
|
if (neg)
|
||||||
|
@ -1231,8 +1231,8 @@ void FScanner::AddSymbol(const char *name, int64_t value)
|
||||||
{
|
{
|
||||||
Symbol sym;
|
Symbol sym;
|
||||||
sym.tokenType = TK_IntConst;
|
sym.tokenType = TK_IntConst;
|
||||||
sym.Number = value;
|
sym.Number = int(value);
|
||||||
sym.Float = value;
|
sym.Float = double(value);
|
||||||
symbols.Insert(name, sym);
|
symbols.Insert(name, sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
#include "sc_man.h"
|
#include "sc_man.h"
|
||||||
#include "printf.h"
|
#include "printf.h"
|
||||||
|
#include "i_interface.h"
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
@ -237,12 +238,12 @@ bool FStringTable::ParseLanguageCSV(int lumpnum, const TArray<uint8_t> &buffer)
|
||||||
if (filterstr.IsNotEmpty())
|
if (filterstr.IsNotEmpty())
|
||||||
{
|
{
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
if (callbacks && callbacks->ValidFilter)
|
if (sysCallbacks.CheckGame)
|
||||||
{
|
{
|
||||||
auto filter = filterstr.Split(" ", FString::TOK_SKIPEMPTY);
|
auto filter = filterstr.Split(" ", FString::TOK_SKIPEMPTY);
|
||||||
for (auto& entry : filter)
|
for (auto& entry : filter)
|
||||||
{
|
{
|
||||||
if (callbacks->ValidFilter(entry))
|
if (sysCallbacks.CheckGame(entry))
|
||||||
{
|
{
|
||||||
ok = true;
|
ok = true;
|
||||||
break;
|
break;
|
||||||
|
@ -356,7 +357,7 @@ void FStringTable::LoadLanguage (int lumpnum, const TArray<uint8_t> &buffer)
|
||||||
sc.MustGetStringName("ifgame");
|
sc.MustGetStringName("ifgame");
|
||||||
sc.MustGetStringName("(");
|
sc.MustGetStringName("(");
|
||||||
sc.MustGetString();
|
sc.MustGetString();
|
||||||
skip |= (!callbacks || !callbacks->ValidFilter || !callbacks->ValidFilter(sc.String));
|
skip |= (!sysCallbacks.CheckGame || !sysCallbacks.CheckGame(sc.String));
|
||||||
sc.MustGetStringName(")");
|
sc.MustGetStringName(")");
|
||||||
sc.MustGetString();
|
sc.MustGetString();
|
||||||
|
|
||||||
|
@ -564,7 +565,7 @@ const char *FStringTable::GetString(const char *name, uint32_t *langtable, int g
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (gender == -1 && callbacks && callbacks->GetPlayerGender) gender = callbacks->GetPlayerGender();
|
if (gender == -1 && sysCallbacks.GetGender) gender = sysCallbacks.GetGender();
|
||||||
if (gender < 0 || gender > 3) gender = 0;
|
if (gender < 0 || gender > 3) gender = 0;
|
||||||
FName nm(name, true);
|
FName nm(name, true);
|
||||||
if (nm != NAME_None)
|
if (nm != NAME_None)
|
||||||
|
@ -597,7 +598,7 @@ const char *FStringTable::GetLanguageString(const char *name, uint32_t langtable
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (gender == -1 && callbacks && callbacks->GetPlayerGender) gender = callbacks->GetPlayerGender();
|
if (gender == -1 && sysCallbacks.GetGender) gender = sysCallbacks.GetGender();
|
||||||
if (gender < 0 || gender > 3) gender = 0;
|
if (gender < 0 || gender > 3) gender = 0;
|
||||||
FName nm(name, true);
|
FName nm(name, true);
|
||||||
if (nm != NAME_None)
|
if (nm != NAME_None)
|
||||||
|
@ -665,3 +666,5 @@ const char *StringMap::MatchString (const char *string) const
|
||||||
}
|
}
|
||||||
|
|
||||||
FStringTable GStrings;
|
FStringTable GStrings;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -50,13 +50,6 @@
|
||||||
#include "name.h"
|
#include "name.h"
|
||||||
|
|
||||||
|
|
||||||
struct StringtableCallbacks
|
|
||||||
{
|
|
||||||
// These two functions would create a dependency on the game code so they are installed as callbacks.
|
|
||||||
bool (*ValidFilter)(const char* str);
|
|
||||||
int (*GetPlayerGender)();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TableElement
|
struct TableElement
|
||||||
{
|
{
|
||||||
int filenum;
|
int filenum;
|
||||||
|
@ -108,7 +101,6 @@ public:
|
||||||
return GetString(name, nullptr);
|
return GetString(name, nullptr);
|
||||||
}
|
}
|
||||||
bool exists(const char *name);
|
bool exists(const char *name);
|
||||||
void SetCallbacks(StringtableCallbacks* cb) { callbacks = cb; }
|
|
||||||
|
|
||||||
void InsertString(int lumpnum, int langid, FName label, const FString& string);
|
void InsertString(int lumpnum, int langid, FName label, const FString& string);
|
||||||
|
|
||||||
|
@ -118,8 +110,7 @@ private:
|
||||||
StringMacroMap allMacros;
|
StringMacroMap allMacros;
|
||||||
LangMap allStrings;
|
LangMap allStrings;
|
||||||
TArray<std::pair<uint32_t, StringMap*>> currentLanguageSet;
|
TArray<std::pair<uint32_t, StringMap*>> currentLanguageSet;
|
||||||
StringtableCallbacks* callbacks = nullptr;
|
|
||||||
|
|
||||||
void LoadLanguage (int lumpnum, const TArray<uint8_t> &buffer);
|
void LoadLanguage (int lumpnum, const TArray<uint8_t> &buffer);
|
||||||
TArray<TArray<FString>> parseCSV(const TArray<uint8_t> &buffer);
|
TArray<TArray<FString>> parseCSV(const TArray<uint8_t> &buffer);
|
||||||
bool ParseLanguageCSV(int lumpnum, const TArray<uint8_t> &buffer);
|
bool ParseLanguageCSV(int lumpnum, const TArray<uint8_t> &buffer);
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "gstrings.h"
|
#include "gstrings.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
#include "serializer.h"
|
#include "serializer.h"
|
||||||
|
#include "c_cvars.h"
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
@ -240,3 +241,46 @@ DEFINE_ACTION_FUNCTION(FFont, BreakLines)
|
||||||
auto broken = V_BreakLines(self, maxwidth, text, true);
|
auto broken = V_BreakLines(self, maxwidth, text, true);
|
||||||
ACTION_RETURN_OBJECT(Create<DBrokenLines>(broken));
|
ACTION_RETURN_OBJECT(Create<DBrokenLines>(broken));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool generic_ui;
|
||||||
|
EXTERN_CVAR(String, language)
|
||||||
|
|
||||||
|
bool CheckFontComplete(FFont* font)
|
||||||
|
{
|
||||||
|
// Also check if the SmallFont contains all characters this language needs.
|
||||||
|
// If not, switch back to the original one.
|
||||||
|
return font->CanPrint(GStrings["REQUIRED_CHARACTERS"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateGenericUI(bool cvar)
|
||||||
|
{
|
||||||
|
auto switchstr = GStrings["USE_GENERIC_FONT"];
|
||||||
|
generic_ui = (cvar || (switchstr && strtoll(switchstr, nullptr, 0)));
|
||||||
|
if (!generic_ui)
|
||||||
|
{
|
||||||
|
// Use the mod's SmallFont if it is complete.
|
||||||
|
// Otherwise use the stock Smallfont if it is complete.
|
||||||
|
// If none is complete, fall back to the VGA font.
|
||||||
|
// The font being set here will be used in 3 places: Notifications, centered messages and menu confirmations.
|
||||||
|
if (CheckFontComplete(SmallFont))
|
||||||
|
{
|
||||||
|
AlternativeSmallFont = SmallFont;
|
||||||
|
}
|
||||||
|
else if (OriginalSmallFont && CheckFontComplete(OriginalSmallFont))
|
||||||
|
{
|
||||||
|
AlternativeSmallFont = OriginalSmallFont;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AlternativeSmallFont = NewSmallFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Todo: Do the same for the BigFont
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CUSTOM_CVAR(Bool, ui_generic, false, CVAR_NOINITCALL) // This is for allowing to test the generic font system with all languages
|
||||||
|
{
|
||||||
|
UpdateGenericUI(self);
|
||||||
|
}
|
||||||
|
|
198
source/common/menu/joystickmenu.cpp
Normal file
198
source/common/menu/joystickmenu.cpp
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
/*
|
||||||
|
** 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 "menu.h"
|
||||||
|
#include "m_joy.h"
|
||||||
|
#include "vm.h"
|
||||||
|
|
||||||
|
static TArray<IJoystickConfig *> Joysticks;
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetSensitivity)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||||
|
ACTION_RETURN_FLOAT(self->GetSensitivity());
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(IJoystickConfig, SetSensitivity)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||||
|
PARAM_FLOAT(sens);
|
||||||
|
self->SetSensitivity((float)sens);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetAxisScale)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||||
|
PARAM_INT(axis);
|
||||||
|
ACTION_RETURN_FLOAT(self->GetAxisScale(axis));
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(IJoystickConfig, SetAxisScale)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||||
|
PARAM_INT(axis);
|
||||||
|
PARAM_FLOAT(sens);
|
||||||
|
self->SetAxisScale(axis, (float)sens);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetAxisDeadZone)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||||
|
PARAM_INT(axis);
|
||||||
|
ACTION_RETURN_FLOAT(self->GetAxisDeadZone(axis));
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(IJoystickConfig, SetAxisDeadZone)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||||
|
PARAM_INT(axis);
|
||||||
|
PARAM_FLOAT(dz);
|
||||||
|
self->SetAxisDeadZone(axis, (float)dz);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetAxisMap)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||||
|
PARAM_INT(axis);
|
||||||
|
ACTION_RETURN_INT(self->GetAxisMap(axis));
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(IJoystickConfig, SetAxisMap)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||||
|
PARAM_INT(axis);
|
||||||
|
PARAM_INT(map);
|
||||||
|
self->SetAxisMap(axis, (EJoyAxis)map);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetName)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||||
|
ACTION_RETURN_STRING(self->GetName());
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetAxisName)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||||
|
PARAM_INT(axis);
|
||||||
|
ACTION_RETURN_STRING(self->GetAxisName(axis));
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetNumAxes)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||||
|
ACTION_RETURN_INT(self->GetNumAxes());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void UpdateJoystickMenu(IJoystickConfig *selected)
|
||||||
|
{
|
||||||
|
DMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_JoystickOptions);
|
||||||
|
DMenuDescriptor **ddesc = MenuDescriptors.CheckKey("JoystickOptionsDefaults");
|
||||||
|
if (ddesc == nullptr) return; // without any data the menu cannot be set up and must remain empty.
|
||||||
|
if (desc != NULL && (*desc)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor)))
|
||||||
|
{
|
||||||
|
DOptionMenuDescriptor *opt = (DOptionMenuDescriptor *)*desc;
|
||||||
|
DOptionMenuDescriptor *dopt = (DOptionMenuDescriptor *)*ddesc;
|
||||||
|
if (dopt == nullptr) return;
|
||||||
|
DMenuItemBase *it;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opt->mItems = dopt->mItems;
|
||||||
|
|
||||||
|
it = opt->GetItem("ConfigureMessage");
|
||||||
|
if (it != nullptr) it->SetValue(0, !!Joysticks.Size());
|
||||||
|
it = opt->GetItem("ConnectMessage1");
|
||||||
|
if (it != nullptr) it->SetValue(0, !use_joystick);
|
||||||
|
it = opt->GetItem("ConnectMessage2");
|
||||||
|
if (it != nullptr) it->SetValue(0, !use_joystick);
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)Joysticks.Size(); ++i)
|
||||||
|
{
|
||||||
|
it = CreateOptionMenuItemJoyConfigMenu(Joysticks[i]->GetName(), Joysticks[i]);
|
||||||
|
GC::WriteBarrier(opt, it);
|
||||||
|
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.
|
||||||
|
if (CurrentMenu != nullptr && (CurrentMenu->IsKindOf("JoystickConfigMenu")))
|
||||||
|
{
|
||||||
|
auto p = CurrentMenu->PointerVar<IJoystickConfig>("mJoy");
|
||||||
|
if (p != nullptr)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < Joysticks.Size(); ++i)
|
||||||
|
{
|
||||||
|
if (Joysticks[i] == p)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == Joysticks.Size())
|
||||||
|
{
|
||||||
|
CurrentMenu->Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
1235
source/common/menu/menu.cpp
Normal file
1235
source/common/menu/menu.cpp
Normal file
File diff suppressed because it is too large
Load diff
327
source/common/menu/menu.h
Normal file
327
source/common/menu/menu.h
Normal file
|
@ -0,0 +1,327 @@
|
||||||
|
#ifndef __M_MENU_MENU_H__
|
||||||
|
#define __M_MENU_MENU_H__
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "dobject.h"
|
||||||
|
#include "c_cvars.h"
|
||||||
|
#include "v_font.h"
|
||||||
|
#include "textures.h"
|
||||||
|
|
||||||
|
EXTERN_CVAR(Float, snd_menuvolume)
|
||||||
|
EXTERN_CVAR(Int, m_use_mouse);
|
||||||
|
|
||||||
|
|
||||||
|
struct event_t;
|
||||||
|
class FTexture;
|
||||||
|
class FFont;
|
||||||
|
enum EColorRange : int;
|
||||||
|
class FKeyBindings;
|
||||||
|
struct FBrokenLines;
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DMenu;
|
||||||
|
extern DMenu *CurrentMenu;
|
||||||
|
extern int MenuTime;
|
||||||
|
class DMenuItemBase;
|
||||||
|
extern DObject* menuDelegate;
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// menu descriptor. This is created from the menu definition lump
|
||||||
|
// Items must be inserted in the order they are cycled through with the cursor
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
class DMenuDescriptor : public DObject
|
||||||
|
{
|
||||||
|
DECLARE_CLASS(DMenuDescriptor, DObject)
|
||||||
|
public:
|
||||||
|
FName mMenuName = NAME_None;
|
||||||
|
FString mNetgameMessage;
|
||||||
|
PClass *mClass = nullptr;
|
||||||
|
bool mProtected = false;
|
||||||
|
TArray<DMenuItemBase *> mItems;
|
||||||
|
|
||||||
|
size_t PropagateMark() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DListMenuDescriptor : public DMenuDescriptor
|
||||||
|
{
|
||||||
|
DECLARE_CLASS(DListMenuDescriptor, DMenuDescriptor)
|
||||||
|
|
||||||
|
public:
|
||||||
|
int mSelectedItem;
|
||||||
|
double mSelectOfsX;
|
||||||
|
double mSelectOfsY;
|
||||||
|
FTextureID mSelector;
|
||||||
|
int mDisplayTop;
|
||||||
|
double 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;
|
||||||
|
bool mCenter;
|
||||||
|
bool mFromEngine;
|
||||||
|
bool mAnimated;
|
||||||
|
bool mAnimatedTransition;
|
||||||
|
int mVirtWidth;
|
||||||
|
int mVirtHeight;
|
||||||
|
|
||||||
|
void Reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FOptionMenuSettings
|
||||||
|
{
|
||||||
|
EColorRange mTitleColor;
|
||||||
|
EColorRange mFontColor;
|
||||||
|
EColorRange mFontColorValue;
|
||||||
|
EColorRange mFontColorMore;
|
||||||
|
EColorRange mFontColorHeader;
|
||||||
|
EColorRange mFontColorHighlight;
|
||||||
|
EColorRange mFontColorSelection;
|
||||||
|
int mLinespacing;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DOptionMenuDescriptor : public DMenuDescriptor
|
||||||
|
{
|
||||||
|
DECLARE_CLASS(DOptionMenuDescriptor, DMenuDescriptor)
|
||||||
|
|
||||||
|
public:
|
||||||
|
FString mTitle;
|
||||||
|
int mSelectedItem;
|
||||||
|
int mDrawTop;
|
||||||
|
int mScrollTop;
|
||||||
|
int mScrollPos;
|
||||||
|
int mIndent;
|
||||||
|
int mPosition;
|
||||||
|
bool mDontDim;
|
||||||
|
FFont *mFont;
|
||||||
|
|
||||||
|
void CalcIndent();
|
||||||
|
DMenuItemBase *GetItem(FName name);
|
||||||
|
void Reset();
|
||||||
|
~DOptionMenuDescriptor() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DImageScrollerDescriptor : public DMenuDescriptor
|
||||||
|
{
|
||||||
|
DECLARE_CLASS(DOptionMenuDescriptor, DMenuDescriptor)
|
||||||
|
public:
|
||||||
|
FTextureID textBackground;
|
||||||
|
PalEntry textBackgroundBrightness;
|
||||||
|
|
||||||
|
FFont *textFont;
|
||||||
|
double textScale;
|
||||||
|
bool mAnimatedTransition;
|
||||||
|
int virtWidth, virtHeight;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef TMap<FName, DMenuDescriptor *> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum MenuTransitionType
|
||||||
|
{ // Note: This enum is for logical categories, not visual types.
|
||||||
|
MA_None,
|
||||||
|
MA_Return,
|
||||||
|
MA_Advance,
|
||||||
|
};
|
||||||
|
|
||||||
|
class DMenu;
|
||||||
|
|
||||||
|
struct MenuTransition
|
||||||
|
{
|
||||||
|
DMenu* previous;
|
||||||
|
DMenu* current;
|
||||||
|
|
||||||
|
double start;
|
||||||
|
int32_t length;
|
||||||
|
int8_t dir;
|
||||||
|
bool destroyprev;
|
||||||
|
|
||||||
|
bool StartTransition(DMenu* from, DMenu* to, MenuTransitionType animtype);
|
||||||
|
bool Draw();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DMenu : public DObject
|
||||||
|
{
|
||||||
|
DECLARE_CLASS (DMenu, DObject)
|
||||||
|
HAS_OBJECT_POINTERS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MOUSE_Click,
|
||||||
|
MOUSE_Move,
|
||||||
|
MOUSE_Release
|
||||||
|
};
|
||||||
|
|
||||||
|
TObjPtr<DMenu*> mParentMenu;
|
||||||
|
bool mMouseCapture;
|
||||||
|
bool mBackbuttonSelected;
|
||||||
|
bool DontDim;
|
||||||
|
bool DontBlur;
|
||||||
|
bool Animated;
|
||||||
|
bool AnimatedTransition;
|
||||||
|
static int InMenu;
|
||||||
|
|
||||||
|
DMenu(DMenu *parent = NULL);
|
||||||
|
bool TranslateKeyboardEvents();
|
||||||
|
virtual void Close();
|
||||||
|
|
||||||
|
bool CallResponder(event_t *ev);
|
||||||
|
bool CallMenuEvent(int mkey, bool fromcontroller);
|
||||||
|
void CallTicker();
|
||||||
|
void CallDrawer();
|
||||||
|
bool canAnimate() { return AnimatedTransition; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// base class for menu items
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
class DMenuItemBase : public DObject
|
||||||
|
{
|
||||||
|
DECLARE_CLASS(DMenuItemBase, DObject)
|
||||||
|
public:
|
||||||
|
double mXpos, mYpos;
|
||||||
|
FName mAction;
|
||||||
|
int mEnabled;
|
||||||
|
|
||||||
|
bool Activate();
|
||||||
|
bool SetString(int i, const char *s);
|
||||||
|
bool GetString(int i, char *s, int len);
|
||||||
|
bool SetValue(int i, int value);
|
||||||
|
bool GetValue(int i, int *pvalue);
|
||||||
|
void OffsetPositionY(int ydelta) { mYpos += ydelta; }
|
||||||
|
double GetY() { return mYpos; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
struct FOptionValues
|
||||||
|
{
|
||||||
|
struct Pair
|
||||||
|
{
|
||||||
|
double Value;
|
||||||
|
FString TextValue;
|
||||||
|
FString Text;
|
||||||
|
};
|
||||||
|
|
||||||
|
TArray<Pair> mValues;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef TMap< FName, FOptionValues* > FOptionMap;
|
||||||
|
|
||||||
|
extern FOptionMap OptionValues;
|
||||||
|
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
struct event_t;
|
||||||
|
void M_EnableMenu (bool on) ;
|
||||||
|
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_PreviousMenu ();
|
||||||
|
void M_ParseMenuDefs();
|
||||||
|
void M_DoStartControlPanel(bool scaleoverride);
|
||||||
|
void M_SetMenu(FName menu, int param = -1);
|
||||||
|
void M_StartMessage(const char *message, int messagemode, FName action = NAME_None);
|
||||||
|
DMenu *StartPickerMenu(DMenu *parent, const char *name, FColorCVar *cvar);
|
||||||
|
void M_MarkMenus();
|
||||||
|
FTextureID GetMenuTexture(const char* const name);
|
||||||
|
void DeinitMenus();
|
||||||
|
bool M_Active();
|
||||||
|
bool M_IsAnimated();
|
||||||
|
|
||||||
|
|
||||||
|
struct IJoystickConfig;
|
||||||
|
DMenuItemBase * CreateOptionMenuItemStaticText(const char *name, int v = -1);
|
||||||
|
DMenuItemBase * CreateOptionMenuItemSubmenu(const char *label, FName cmd, int center);
|
||||||
|
DMenuItemBase * CreateOptionMenuItemControl(const char *label, FName cmd, FKeyBindings *bindings);
|
||||||
|
DMenuItemBase * CreateOptionMenuItemJoyConfigMenu(const char *label, IJoystickConfig *joy);
|
||||||
|
DMenuItemBase * CreateListMenuItemPatch(double x, double y, int height, int hotkey, FTextureID tex, FName command, int param);
|
||||||
|
DMenuItemBase * CreateListMenuItemText(double x, double y, int height, int hotkey, const char *text, FFont *font, PalEntry color1, PalEntry color2, FName command, int param);
|
||||||
|
DMenuItemBase * CreateOptionMenuItemCommand(const char *label, FName cmd, bool centered = false);
|
||||||
|
DMenuItemBase* CreateListMenuItemStaticText(double x, double y, const char* text, FFont* font, PalEntry color, bool centered = false);
|
||||||
|
|
||||||
|
void UpdateVRModes(bool considerQuadBuffered=true);
|
||||||
|
|
||||||
|
#endif
|
1442
source/common/menu/menudef.cpp
Normal file
1442
source/common/menu/menudef.cpp
Normal file
File diff suppressed because it is too large
Load diff
105
source/common/menu/messagebox.cpp
Normal file
105
source/common/menu/messagebox.cpp
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
** 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 <ctype.h>
|
||||||
|
#include "menu.h"
|
||||||
|
#include "gstrings.h"
|
||||||
|
#include "i_video.h"
|
||||||
|
#include "c_dispatch.h"
|
||||||
|
#include "vm.h"
|
||||||
|
#include "menustate.h"
|
||||||
|
|
||||||
|
void M_StartControlPanel(bool makeSound, bool scaleoverride = false);
|
||||||
|
FName MessageBoxClass = NAME_MessageBoxMenu;
|
||||||
|
|
||||||
|
CVAR(Bool, m_quickexit, false, CVAR_ARCHIVE)
|
||||||
|
|
||||||
|
typedef void(*hfunc)();
|
||||||
|
DEFINE_ACTION_FUNCTION(DMessageBoxMenu, CallHandler)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_POINTERTYPE(Handler, hfunc);
|
||||||
|
Handler();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
DMenu *CreateMessageBoxMenu(DMenu *parent, const char *message, int messagemode, bool playsound, FName action = NAME_None, hfunc handler = nullptr)
|
||||||
|
{
|
||||||
|
auto c = PClass::FindClass(MessageBoxClass);
|
||||||
|
if (!c->IsDescendantOf(NAME_MessageBoxMenu)) c = PClass::FindClass(NAME_MessageBoxMenu);
|
||||||
|
auto p = c->CreateNew();
|
||||||
|
FString namestr = message;
|
||||||
|
|
||||||
|
IFVIRTUALPTRNAME(p, NAME_MessageBoxMenu, Init)
|
||||||
|
{
|
||||||
|
VMValue params[] = { p, parent, &namestr, messagemode, playsound, action.GetIndex(), reinterpret_cast<void*>(handler) };
|
||||||
|
VMCall(func, params, countof(params), nullptr, 0);
|
||||||
|
return (DMenu*)p;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
void M_StartMessage(const char *message, int messagemode, FName action)
|
||||||
|
{
|
||||||
|
if (CurrentMenu == NULL)
|
||||||
|
{
|
||||||
|
// only play a sound if no menu was active before
|
||||||
|
M_StartControlPanel(menuactive == MENU_Off);
|
||||||
|
}
|
||||||
|
DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, message, messagemode, false, action);
|
||||||
|
newmenu->mParentMenu = CurrentMenu;
|
||||||
|
M_ActivateMenu(newmenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(DMenu, StartMessage)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_STRING(msg);
|
||||||
|
PARAM_INT(mode);
|
||||||
|
PARAM_NAME(action);
|
||||||
|
M_StartMessage(msg, mode, action);
|
||||||
|
return 0;
|
||||||
|
}
|
68
source/common/menu/optionmenu.cpp
Normal file
68
source/common/menu/optionmenu.cpp
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
** optionmenu.cpp
|
||||||
|
** Handler class for the option menus and associated items
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
** Copyright 2010-2017 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 "menu.h"
|
||||||
|
#include "vm.h"
|
||||||
|
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
DMenuItemBase *DOptionMenuDescriptor::GetItem(FName name)
|
||||||
|
{
|
||||||
|
for(unsigned i=0;i<mItems.Size(); i++)
|
||||||
|
{
|
||||||
|
FName nm = mItems[i]->mAction;
|
||||||
|
if (nm == name) return mItems[i];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCVarDescription(FBaseCVar* cvar, const FString* label)
|
||||||
|
{
|
||||||
|
cvar->AddDescription(*label);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION_NATIVE(_OptionMenuItemOption, SetCVarDescription, SetCVarDescription)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_POINTER(cv, FBaseCVar);
|
||||||
|
PARAM_STRING(label);
|
||||||
|
SetCVarDescription(cv, &label);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
**
|
**
|
||||||
**---------------------------------------------------------------------------
|
**---------------------------------------------------------------------------
|
||||||
** Copyright 2001-2010 Randy Heit
|
** Copyright 2001-2010 Randy Heit
|
||||||
** Copyright 2010 Christoph Oelckers
|
** Copyright 2010-2020 Christoph Oelckers
|
||||||
** All rights reserved.
|
** All rights reserved.
|
||||||
**
|
**
|
||||||
** Redistribution and use in source and binary forms, with or without
|
** Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -38,68 +38,16 @@
|
||||||
#include "m_png.h"
|
#include "m_png.h"
|
||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
#include "v_text.h"
|
#include "v_text.h"
|
||||||
#include "d_event.h"
|
|
||||||
#include "gstrings.h"
|
#include "gstrings.h"
|
||||||
#include "d_gui.h"
|
|
||||||
#include "v_draw.h"
|
|
||||||
#include "files.h"
|
|
||||||
#include "resourcefile.h"
|
|
||||||
#include "cmdlib.h"
|
|
||||||
#include "files.h"
|
|
||||||
#include "savegamehelp.h"
|
|
||||||
#include "i_specialpaths.h"
|
|
||||||
#include "c_dispatch.h"
|
|
||||||
#include "build.h"
|
|
||||||
#include "serializer.h"
|
#include "serializer.h"
|
||||||
|
#include "vm.h"
|
||||||
|
#include "i_system.h"
|
||||||
|
#include "v_video.h"
|
||||||
#include "findfile.h"
|
#include "findfile.h"
|
||||||
#include "inputstate.h"
|
#include "v_draw.h"
|
||||||
#include "gamestate.h"
|
#include "savegamemanager.h"
|
||||||
|
|
||||||
|
|
||||||
FSavegameManager savegameManager;
|
|
||||||
FString BackupSaveGame;
|
|
||||||
|
|
||||||
void DoLoadGame(const char* name)
|
|
||||||
{
|
|
||||||
if (OpenSaveGameForRead(name))
|
|
||||||
{
|
|
||||||
if (gi->LoadGame(nullptr))
|
|
||||||
{
|
|
||||||
gameaction = ga_level;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
I_Error("%s: Failed to load savegame", name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
I_Error("%s: Failed to open savegame", name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FSavegameManager::LoadGame(FSaveGameNode* node)
|
|
||||||
{
|
|
||||||
inputState.ClearAllInput();
|
|
||||||
gi->FreeLevelData();
|
|
||||||
DoLoadGame(node->Filename);
|
|
||||||
BackupSaveGame = node->Filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FSavegameManager::SaveGame(FSaveGameNode* node, bool ok4q, bool forceq)
|
|
||||||
{
|
|
||||||
if (OpenSaveGameForWrite(node->Filename, node->SaveTitle))
|
|
||||||
{
|
|
||||||
if (gi->SaveGame(node) && FinishSavegameWrite())
|
|
||||||
{
|
|
||||||
FString fn = node->Filename;
|
|
||||||
FString desc = node->SaveTitle;
|
|
||||||
NotifyNewSave(fn, desc, ok4q, forceq);
|
|
||||||
Printf(PRINT_NOTIFY, "%s\n", GStrings("GAME SAVED"));
|
|
||||||
BackupSaveGame = node->Filename;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//
|
//
|
||||||
|
@ -107,7 +55,7 @@ void FSavegameManager::SaveGame(FSaveGameNode* node, bool ok4q, bool forceq)
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
void FSavegameManager::ClearSaveGames()
|
void FSavegameManagerBase::ClearSaveGames()
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i<SaveGames.Size(); i++)
|
for (unsigned i = 0; i<SaveGames.Size(); i++)
|
||||||
{
|
{
|
||||||
|
@ -117,7 +65,7 @@ void FSavegameManager::ClearSaveGames()
|
||||||
SaveGames.Clear();
|
SaveGames.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
FSavegameManager::~FSavegameManager()
|
FSavegameManagerBase::~FSavegameManagerBase()
|
||||||
{
|
{
|
||||||
ClearSaveGames();
|
ClearSaveGames();
|
||||||
}
|
}
|
||||||
|
@ -128,7 +76,7 @@ FSavegameManager::~FSavegameManager()
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
int FSavegameManager::RemoveSaveSlot(int index)
|
int FSavegameManagerBase::RemoveSaveSlot(int index)
|
||||||
{
|
{
|
||||||
int listindex = SaveGames[0]->bNoDelete ? index - 1 : index;
|
int listindex = SaveGames[0]->bNoDelete ? index - 1 : index;
|
||||||
if (listindex < 0) return index;
|
if (listindex < 0) return index;
|
||||||
|
@ -155,13 +103,20 @@ int FSavegameManager::RemoveSaveSlot(int index)
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveSaveSlot)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||||
|
PARAM_INT(sel);
|
||||||
|
ACTION_RETURN_INT(self->RemoveSaveSlot(sel));
|
||||||
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
int FSavegameManager::InsertSaveNode(FSaveGameNode *node)
|
int FSavegameManagerBase::InsertSaveNode(FSaveGameNode *node)
|
||||||
{
|
{
|
||||||
if (SaveGames.Size() == 0)
|
if (SaveGames.Size() == 0)
|
||||||
{
|
{
|
||||||
|
@ -175,7 +130,7 @@ int FSavegameManager::InsertSaveNode(FSaveGameNode *node)
|
||||||
else
|
else
|
||||||
{ // Add node at top of list
|
{ // Add node at top of list
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
if (SaveGames[0] == &NewSaveNode) i++; // To not insert above the "new savegame" dummy entry.
|
//if (SaveGames[0] == &NewSaveNode) i++; // To not insert above the "new savegame" dummy entry.
|
||||||
for (; i < SaveGames.Size(); i++)
|
for (; i < SaveGames.Size(); i++)
|
||||||
{
|
{
|
||||||
if (SaveGames[i]->bOldVersion || node->SaveTitle.CompareNoCase(SaveGames[i]->SaveTitle) <= 0)
|
if (SaveGames[i]->bOldVersion || node->SaveTitle.CompareNoCase(SaveGames[i]->SaveTitle) <= 0)
|
||||||
|
@ -188,72 +143,13 @@ int FSavegameManager::InsertSaveNode(FSaveGameNode *node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// M_ReadSaveStrings
|
|
||||||
//
|
|
||||||
// Find savegames and read their titles
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
void FSavegameManager::ReadSaveStrings()
|
|
||||||
{
|
|
||||||
if (SaveGames.Size() == 0)
|
|
||||||
{
|
|
||||||
void *filefirst;
|
|
||||||
findstate_t c_file;
|
|
||||||
FString filter;
|
|
||||||
|
|
||||||
LastSaved = LastAccessed = -1;
|
|
||||||
quickSaveSlot = nullptr;
|
|
||||||
filter = G_BuildSaveName("*");
|
|
||||||
filefirst = I_FindFirst(filter.GetChars(), &c_file);
|
|
||||||
if (filefirst != ((void *)(-1)))
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// I_FindName only returns the file's name and not its full path
|
|
||||||
FString filepath = G_BuildSaveName(I_FindName(&c_file));
|
|
||||||
|
|
||||||
FResourceFile *savegame = FResourceFile::OpenResourceFile(filepath, true, true);
|
|
||||||
if (savegame != nullptr)
|
|
||||||
{
|
|
||||||
FResourceLump *info = savegame->FindLump("info.json");
|
|
||||||
if (info == nullptr)
|
|
||||||
{
|
|
||||||
// savegame info not found. This is not a savegame so leave it alone.
|
|
||||||
delete savegame;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto fr = info->NewReader();
|
|
||||||
FString title;
|
|
||||||
int check = G_ValidateSavegame(fr, &title, true);
|
|
||||||
fr.Close();
|
|
||||||
delete savegame;
|
|
||||||
if (check != 0)
|
|
||||||
{
|
|
||||||
FSaveGameNode *node = new FSaveGameNode;
|
|
||||||
node->Filename = filepath;
|
|
||||||
node->bOldVersion = check == -1;
|
|
||||||
node->bMissingWads = check == -2;
|
|
||||||
node->SaveTitle = title;
|
|
||||||
InsertSaveNode(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (I_FindNext (filefirst, &c_file) == 0);
|
|
||||||
I_FindClose (filefirst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
void FSavegameManager::NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave, bool forceQuicksave)
|
void FSavegameManagerBase::NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave, bool forceQuicksave)
|
||||||
{
|
{
|
||||||
FSaveGameNode *node;
|
FSaveGameNode *node;
|
||||||
|
|
||||||
|
@ -278,7 +174,7 @@ void FSavegameManager::NotifyNewSave(const FString &file, const FString &title,
|
||||||
if (okForQuicksave)
|
if (okForQuicksave)
|
||||||
{
|
{
|
||||||
if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node;
|
if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node;
|
||||||
LastAccessed = LastSaved = i - 1; // without <new save> item
|
LastAccessed = LastSaved = i;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -294,7 +190,7 @@ void FSavegameManager::NotifyNewSave(const FString &file, const FString &title,
|
||||||
if (okForQuicksave)
|
if (okForQuicksave)
|
||||||
{
|
{
|
||||||
if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node;
|
if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node;
|
||||||
LastAccessed = LastSaved = index - 1; // without <new save> item
|
LastAccessed = LastSaved = index;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -302,27 +198,31 @@ void FSavegameManager::NotifyNewSave(const FString &file, const FString &title,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//
|
//
|
||||||
// Loads the savegame
|
// Loads the savegame
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
void FSavegameManager::LoadSavegame(int Selected)
|
void FSavegameManagerBase::LoadSavegame(int Selected)
|
||||||
{
|
{
|
||||||
auto sel = savegameManager.GetSavegame(Selected);
|
PerformLoadGame(SaveGames[Selected]->Filename.GetChars(), true);
|
||||||
if (sel && !sel->bOldVersion && !sel->bMissingWads)
|
if (quickSaveSlot == (FSaveGameNode*)1)
|
||||||
{
|
{
|
||||||
savegameManager.LoadGame(SaveGames[Selected]);
|
quickSaveSlot = SaveGames[Selected];
|
||||||
if (quickSaveSlot == (FSaveGameNode*)1)
|
|
||||||
{
|
|
||||||
quickSaveSlot = SaveGames[Selected];
|
|
||||||
}
|
|
||||||
M_ClearMenus();
|
|
||||||
LastAccessed = Selected;
|
|
||||||
}
|
}
|
||||||
|
M_ClearMenus();
|
||||||
|
LastAccessed = Selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(FSavegameManager, LoadSavegame)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||||
|
PARAM_INT(sel);
|
||||||
|
self->LoadSavegame(sel);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//
|
//
|
||||||
|
@ -330,13 +230,12 @@ void FSavegameManager::LoadSavegame(int Selected)
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
void FSavegameManager::DoSave(int Selected, const char *savegamestring)
|
void FSavegameManagerBase::DoSave(int Selected, const char *savegamestring)
|
||||||
{
|
{
|
||||||
if (Selected != 0)
|
if (Selected != 0)
|
||||||
{
|
{
|
||||||
auto node = *SaveGames[Selected];
|
auto node = SaveGames[Selected];
|
||||||
node.SaveTitle = savegamestring;
|
PerformSaveGame(node->Filename.GetChars(), savegamestring);
|
||||||
savegameManager.SaveGame(&node, true, false);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -346,18 +245,25 @@ void FSavegameManager::DoSave(int Selected, const char *savegamestring)
|
||||||
|
|
||||||
for (i = 0;; ++i)
|
for (i = 0;; ++i)
|
||||||
{
|
{
|
||||||
filename = G_BuildSaveName(FStringf("save%04d", i));
|
filename = BuildSaveName("save", i);
|
||||||
if (!FileExists(filename))
|
if (!FileExists(filename))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FSaveGameNode sg{ savegamestring, filename };
|
PerformSaveGame(filename, savegamestring);
|
||||||
savegameManager.SaveGame(&sg, true, false);
|
|
||||||
}
|
}
|
||||||
M_ClearMenus();
|
M_ClearMenus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(FSavegameManager, DoSave)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||||
|
PARAM_INT(sel);
|
||||||
|
PARAM_STRING(name);
|
||||||
|
self->DoSave(sel, name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//
|
//
|
||||||
|
@ -365,7 +271,7 @@ void FSavegameManager::DoSave(int Selected, const char *savegamestring)
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
unsigned FSavegameManager::ExtractSaveData(int index)
|
unsigned FSavegameManagerBase::ExtractSaveData(int index)
|
||||||
{
|
{
|
||||||
FResourceFile *resf;
|
FResourceFile *resf;
|
||||||
FSaveGameNode *node;
|
FSaveGameNode *node;
|
||||||
|
@ -406,15 +312,7 @@ unsigned FSavegameManager::ExtractSaveData(int index)
|
||||||
}
|
}
|
||||||
info->Unlock();
|
info->Unlock();
|
||||||
|
|
||||||
FString comment, fcomment, ncomment, mtime;
|
SaveCommentString = ExtractSaveComment(arc);
|
||||||
|
|
||||||
arc("Creation Time", comment)
|
|
||||||
("Map Label", fcomment)
|
|
||||||
("Map Name", ncomment)
|
|
||||||
("Map Time", mtime);
|
|
||||||
|
|
||||||
comment.AppendFormat("\n%s - %s\n%s", fcomment.GetChars(), ncomment.GetChars(), mtime.GetChars());
|
|
||||||
SaveCommentString = comment;
|
|
||||||
|
|
||||||
FResourceLump *pic = resf->FindLump("savepic.png");
|
FResourceLump *pic = resf->FindLump("savepic.png");
|
||||||
if (pic != nullptr)
|
if (pic != nullptr)
|
||||||
|
@ -438,7 +336,6 @@ unsigned FSavegameManager::ExtractSaveData(int index)
|
||||||
{
|
{
|
||||||
delete SavePic;
|
delete SavePic;
|
||||||
SavePic = nullptr;
|
SavePic = nullptr;
|
||||||
SavePicData.Clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -453,7 +350,7 @@ unsigned FSavegameManager::ExtractSaveData(int index)
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
void FSavegameManager::UnloadSaveData()
|
void FSavegameManagerBase::UnloadSaveData()
|
||||||
{
|
{
|
||||||
if (SavePic != nullptr)
|
if (SavePic != nullptr)
|
||||||
{
|
{
|
||||||
|
@ -462,7 +359,13 @@ void FSavegameManager::UnloadSaveData()
|
||||||
|
|
||||||
SaveCommentString = "";
|
SaveCommentString = "";
|
||||||
SavePic = nullptr;
|
SavePic = nullptr;
|
||||||
SavePicData.Clear();
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(FSavegameManager, UnloadSaveData)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||||
|
self->UnloadSaveData();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
@ -471,7 +374,7 @@ void FSavegameManager::UnloadSaveData()
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
void FSavegameManager::ClearSaveStuff()
|
void FSavegameManagerBase::ClearSaveStuff()
|
||||||
{
|
{
|
||||||
UnloadSaveData();
|
UnloadSaveData();
|
||||||
if (quickSaveSlot == (FSaveGameNode*)1)
|
if (quickSaveSlot == (FSaveGameNode*)1)
|
||||||
|
@ -480,6 +383,12 @@ void FSavegameManager::ClearSaveStuff()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(FSavegameManager, ClearSaveStuff)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||||
|
self->ClearSaveStuff();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//
|
//
|
||||||
|
@ -487,13 +396,22 @@ void FSavegameManager::ClearSaveStuff()
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
bool FSavegameManager::DrawSavePic(int x, int y, int w, int h)
|
bool FSavegameManagerBase::DrawSavePic(int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
if (SavePic == nullptr) return false;
|
if (SavePic == nullptr) return false;
|
||||||
DrawTexture(twod, SavePic, x, y, DTA_DestWidth, w, DTA_DestHeight, h, DTA_Masked, false, TAG_DONE);
|
DrawTexture(twod, SavePic, x, y, DTA_DestWidth, w, DTA_DestHeight, h, DTA_Masked, false, TAG_DONE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(FSavegameManager, DrawSavePic)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||||
|
PARAM_INT(x);
|
||||||
|
PARAM_INT(y);
|
||||||
|
PARAM_INT(w);
|
||||||
|
PARAM_INT(h);
|
||||||
|
ACTION_RETURN_BOOL(self->DrawSavePic(x, y, w, h));
|
||||||
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//
|
//
|
||||||
|
@ -501,7 +419,7 @@ bool FSavegameManager::DrawSavePic(int x, int y, int w, int h)
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
void FSavegameManager::SetFileInfo(int Selected)
|
void FSavegameManagerBase::SetFileInfo(int Selected)
|
||||||
{
|
{
|
||||||
if (!SaveGames[Selected]->Filename.IsEmpty())
|
if (!SaveGames[Selected]->Filename.IsEmpty())
|
||||||
{
|
{
|
||||||
|
@ -509,6 +427,14 @@ void FSavegameManager::SetFileInfo(int Selected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(FSavegameManager, SetFileInfo)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||||
|
PARAM_INT(i);
|
||||||
|
self->SetFileInfo(i);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//
|
//
|
||||||
|
@ -516,11 +442,16 @@ void FSavegameManager::SetFileInfo(int Selected)
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
unsigned FSavegameManager::SavegameCount()
|
unsigned FSavegameManagerBase::SavegameCount()
|
||||||
{
|
{
|
||||||
return SaveGames.Size();
|
return SaveGames.Size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(FSavegameManager, SavegameCount)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||||
|
ACTION_RETURN_INT(self->SavegameCount());
|
||||||
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//
|
//
|
||||||
|
@ -528,11 +459,17 @@ unsigned FSavegameManager::SavegameCount()
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
FSaveGameNode *FSavegameManager::GetSavegame(int i)
|
FSaveGameNode *FSavegameManagerBase::GetSavegame(int i)
|
||||||
{
|
{
|
||||||
return SaveGames[i];
|
return SaveGames[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(FSavegameManager, GetSavegame)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||||
|
PARAM_INT(i);
|
||||||
|
ACTION_RETURN_POINTER(self->GetSavegame(i));
|
||||||
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//
|
//
|
||||||
|
@ -540,13 +477,19 @@ FSaveGameNode *FSavegameManager::GetSavegame(int i)
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
void FSavegameManager::InsertNewSaveNode()
|
void FSavegameManagerBase::InsertNewSaveNode()
|
||||||
{
|
{
|
||||||
NewSaveNode.SaveTitle = GStrings("NEWSAVE");
|
NewSaveNode.SaveTitle = GStrings("NEWSAVE");
|
||||||
NewSaveNode.bNoDelete = true;
|
NewSaveNode.bNoDelete = true;
|
||||||
SaveGames.Insert(0, &NewSaveNode);
|
SaveGames.Insert(0, &NewSaveNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(FSavegameManager, InsertNewSaveNode)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||||
|
self->InsertNewSaveNode();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//
|
//
|
||||||
|
@ -554,7 +497,7 @@ void FSavegameManager::InsertNewSaveNode()
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
bool FSavegameManager::RemoveNewSaveNode()
|
bool FSavegameManagerBase::RemoveNewSaveNode()
|
||||||
{
|
{
|
||||||
if (SaveGames[0] == &NewSaveNode)
|
if (SaveGames[0] == &NewSaveNode)
|
||||||
{
|
{
|
||||||
|
@ -564,176 +507,35 @@ bool FSavegameManager::RemoveNewSaveNode()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveNewSaveNode)
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
CVAR(Bool, saveloadconfirmation, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
|
||||||
|
|
||||||
CVAR(Int, autosavenum, 0, CVAR_NOSET | CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
|
||||||
static int nextautosave = -1;
|
|
||||||
CVAR(Int, disableautosave, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
|
||||||
CUSTOM_CVAR(Int, autosavecount, 4, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
|
||||||
{
|
{
|
||||||
if (self < 1)
|
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||||
self = 1;
|
ACTION_RETURN_INT(self->RemoveNewSaveNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
CVAR(Int, quicksavenum, 0, CVAR_NOSET | CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
|
||||||
static int nextquicksave = -1;
|
DEFINE_ACTION_FUNCTION(FSavegameManager, ReadSaveStrings)
|
||||||
CUSTOM_CVAR(Int, quicksavecount, 4, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
|
||||||
{
|
{
|
||||||
if (self < 1)
|
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||||
self = 1;
|
self->ReadSaveStrings();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void M_Autosave()
|
DEFINE_ACTION_FUNCTION(FSavegameManager, ExtractSaveData)
|
||||||
{
|
{
|
||||||
if (disableautosave) return;
|
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||||
if (!gi->CanSave()) return;
|
PARAM_INT(sel);
|
||||||
FString description;
|
ACTION_RETURN_INT(self->ExtractSaveData(sel));
|
||||||
FString file;
|
|
||||||
// Keep a rotating sets of autosaves
|
|
||||||
UCVarValue num;
|
|
||||||
const char* readableTime;
|
|
||||||
int count = autosavecount != 0 ? autosavecount : 1;
|
|
||||||
|
|
||||||
if (nextautosave == -1)
|
|
||||||
{
|
|
||||||
nextautosave = (autosavenum + 1) % count;
|
|
||||||
}
|
|
||||||
|
|
||||||
num.Int = nextautosave;
|
|
||||||
autosavenum.ForceSet(num, CVAR_Int);
|
|
||||||
|
|
||||||
FSaveGameNode sg;
|
|
||||||
sg.Filename = G_BuildSaveName(FStringf("auto%04d", nextautosave));
|
|
||||||
readableTime = myasctime();
|
|
||||||
sg.SaveTitle.Format("Autosave %s", readableTime);
|
|
||||||
nextautosave = (nextautosave + 1) % count;
|
|
||||||
savegameManager.SaveGame(&sg, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
CCMD(autosave)
|
|
||||||
{
|
|
||||||
gameaction = ga_autosave;
|
|
||||||
}
|
|
||||||
|
|
||||||
CCMD(rotatingquicksave)
|
|
||||||
{
|
|
||||||
if (!gi->CanSave()) return;
|
|
||||||
FString description;
|
|
||||||
FString file;
|
|
||||||
// Keep a rotating sets of quicksaves
|
|
||||||
UCVarValue num;
|
|
||||||
const char* readableTime;
|
|
||||||
int count = quicksavecount != 0 ? quicksavecount : 1;
|
|
||||||
|
|
||||||
if (nextquicksave == -1)
|
|
||||||
{
|
|
||||||
nextquicksave = (quicksavenum + 1) % count;
|
|
||||||
}
|
|
||||||
|
|
||||||
num.Int = nextquicksave;
|
|
||||||
quicksavenum.ForceSet(num, CVAR_Int);
|
|
||||||
|
|
||||||
FSaveGameNode sg;
|
|
||||||
sg.Filename = G_BuildSaveName(FStringf("quick%04d", nextquicksave));
|
|
||||||
readableTime = myasctime();
|
|
||||||
sg.SaveTitle.Format("Quicksave %s", readableTime);
|
|
||||||
nextquicksave = (nextquicksave + 1) % count;
|
|
||||||
savegameManager.SaveGame(&sg, false, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
DEFINE_FIELD(FSaveGameNode, SaveTitle);
|
||||||
//
|
DEFINE_FIELD(FSaveGameNode, Filename);
|
||||||
//
|
DEFINE_FIELD(FSaveGameNode, bOldVersion);
|
||||||
//
|
DEFINE_FIELD(FSaveGameNode, bMissingWads);
|
||||||
//=============================================================================
|
DEFINE_FIELD(FSaveGameNode, bNoDelete);
|
||||||
|
|
||||||
CCMD(quicksave)
|
DEFINE_FIELD_X(SavegameManager, FSavegameManagerBase, WindowSize);
|
||||||
{ // F6
|
DEFINE_FIELD_X(SavegameManager, FSavegameManagerBase, quickSaveSlot);
|
||||||
if (!gi->CanSave()) return;
|
DEFINE_FIELD_X(SavegameManager, FSavegameManagerBase, SaveCommentString);
|
||||||
|
|
||||||
if (savegameManager.quickSaveSlot == NULL || savegameManager.quickSaveSlot == (FSaveGameNode*)1)
|
|
||||||
{
|
|
||||||
M_StartControlPanel(true);
|
|
||||||
M_SetMenu(NAME_Savegamemenu);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto slot = savegameManager.quickSaveSlot;
|
|
||||||
|
|
||||||
// [mxd]. Just save the game, no questions asked.
|
|
||||||
if (!saveloadconfirmation)
|
|
||||||
{
|
|
||||||
savegameManager.SaveGame(savegameManager.quickSaveSlot, true, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FString tempstring = GStrings("QSPROMPT");
|
|
||||||
tempstring.Substitute("%s", slot->SaveTitle.GetChars());
|
|
||||||
M_StartControlPanel(true);
|
|
||||||
|
|
||||||
DMenu* newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, INT_MAX, false, NAME_None, [](bool res)
|
|
||||||
{
|
|
||||||
if (res)
|
|
||||||
{
|
|
||||||
savegameManager.SaveGame(savegameManager.quickSaveSlot, true, true);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
M_ActivateMenu(newmenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
CCMD(quickload)
|
|
||||||
{ // F9
|
|
||||||
#if 0
|
|
||||||
if (netgame)
|
|
||||||
{
|
|
||||||
M_StartControlPanel(true);
|
|
||||||
M_StartMessage(GStrings("QLOADNET"), 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (savegameManager.quickSaveSlot == nullptr || savegameManager.quickSaveSlot == (FSaveGameNode*)1)
|
|
||||||
{
|
|
||||||
M_StartControlPanel(true);
|
|
||||||
// signal that whatever gets loaded should be the new quicksave
|
|
||||||
savegameManager.quickSaveSlot = (FSaveGameNode*)1;
|
|
||||||
M_SetMenu(NAME_Loadgamemenu);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// [mxd]. Just load the game, no questions asked.
|
|
||||||
if (!saveloadconfirmation)
|
|
||||||
{
|
|
||||||
savegameManager.LoadGame(savegameManager.quickSaveSlot);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
FString tempstring = GStrings("QLPROMPT");
|
|
||||||
tempstring.Substitute("%s", savegameManager.quickSaveSlot->SaveTitle.GetChars());
|
|
||||||
|
|
||||||
M_StartControlPanel(true);
|
|
||||||
|
|
||||||
DMenu* newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, INT_MAX, false, NAME_None, [](bool res)
|
|
||||||
{
|
|
||||||
if (res)
|
|
||||||
{
|
|
||||||
savegameManager.LoadGame(savegameManager.quickSaveSlot);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
M_ActivateMenu(newmenu);
|
|
||||||
}
|
|
61
source/common/menu/savegamemanager.h
Normal file
61
source/common/menu/savegamemanager.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "zstring.h"
|
||||||
|
#include "tarray.h"
|
||||||
|
|
||||||
|
class FGameTexture;
|
||||||
|
class FSerializer;
|
||||||
|
|
||||||
|
// The savegame manager contains too much code that is game specific. Parts are shareable but need more work first.
|
||||||
|
struct FSaveGameNode
|
||||||
|
{
|
||||||
|
FString SaveTitle;
|
||||||
|
FString Filename;
|
||||||
|
bool bOldVersion = false;
|
||||||
|
bool bMissingWads = false;
|
||||||
|
bool bNoDelete = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FSavegameManagerBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
TArray<FSaveGameNode*> SaveGames;
|
||||||
|
FSaveGameNode NewSaveNode;
|
||||||
|
int LastSaved = -1;
|
||||||
|
int LastAccessed = -1;
|
||||||
|
FGameTexture *SavePic = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
int WindowSize = 0;
|
||||||
|
FString SaveCommentString;
|
||||||
|
FSaveGameNode *quickSaveSlot = nullptr;
|
||||||
|
virtual ~FSavegameManagerBase();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int InsertSaveNode(FSaveGameNode *node);
|
||||||
|
virtual void PerformSaveGame(const char *fn, const char *sgdesc) = 0;
|
||||||
|
virtual void PerformLoadGame(const char *fn, bool) = 0;
|
||||||
|
virtual FString ExtractSaveComment(FSerializer &arc) = 0;
|
||||||
|
virtual FString BuildSaveName(const char* prefix, int slot) = 0;
|
||||||
|
public:
|
||||||
|
void NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave, bool forceQuicksave);
|
||||||
|
void ClearSaveGames();
|
||||||
|
|
||||||
|
virtual void ReadSaveStrings() = 0;
|
||||||
|
void UnloadSaveData();
|
||||||
|
|
||||||
|
int RemoveSaveSlot(int index);
|
||||||
|
void LoadSavegame(int Selected);
|
||||||
|
void DoSave(int Selected, const char *savegamestring);
|
||||||
|
unsigned ExtractSaveData(int index);
|
||||||
|
void ClearSaveStuff();
|
||||||
|
bool DrawSavePic(int x, int y, int w, int h);
|
||||||
|
void DrawSaveComment(FFont *font, int cr, int x, int y, int scalefactor);
|
||||||
|
void SetFileInfo(int Selected);
|
||||||
|
unsigned SavegameCount();
|
||||||
|
FSaveGameNode *GetSavegame(int i);
|
||||||
|
void InsertNewSaveNode();
|
||||||
|
bool RemoveNewSaveNode();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
|
@ -125,7 +125,7 @@ void FSamplerManager::SetTextureFilterMode()
|
||||||
{
|
{
|
||||||
glSamplerParameteri(mSamplers[i], GL_TEXTURE_MIN_FILTER, TexFilter[filter].minfilter);
|
glSamplerParameteri(mSamplers[i], GL_TEXTURE_MIN_FILTER, TexFilter[filter].minfilter);
|
||||||
glSamplerParameteri(mSamplers[i], GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter);
|
glSamplerParameteri(mSamplers[i], GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter);
|
||||||
glSamplerParameterf(mSamplers[i], GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_filter_anisotropic);
|
glSamplerParameterf(mSamplers[i], GL_TEXTURE_MAX_ANISOTROPY_EXT, filter > 0? gl_texture_filter_anisotropic : 1.0);
|
||||||
}
|
}
|
||||||
glSamplerParameteri(mSamplers[CLAMP_XY_NOMIP], GL_TEXTURE_MIN_FILTER, TexFilter[filter].magfilter);
|
glSamplerParameteri(mSamplers[CLAMP_XY_NOMIP], GL_TEXTURE_MIN_FILTER, TexFilter[filter].magfilter);
|
||||||
glSamplerParameteri(mSamplers[CLAMP_XY_NOMIP], GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter);
|
glSamplerParameteri(mSamplers[CLAMP_XY_NOMIP], GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter);
|
||||||
|
|
|
@ -234,6 +234,7 @@ class_head(X) ::= EXTEND CLASS(T) IDENTIFIER(A).
|
||||||
X = head;
|
X = head;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C).
|
class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C).
|
||||||
{
|
{
|
||||||
NEW_AST_NODE(Class,head,T);
|
NEW_AST_NODE(Class,head,T);
|
||||||
|
@ -394,6 +395,17 @@ struct_def(X) ::= STRUCT(T) IDENTIFIER(A) struct_flags(S) LBRACE opt_struct_body
|
||||||
X = def;
|
X = def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct_def(X) ::= EXTEND STRUCT(T) IDENTIFIER(A) LBRACE opt_struct_body(B) RBRACE opt_semicolon.
|
||||||
|
{
|
||||||
|
NEW_AST_NODE(Struct,def,T);
|
||||||
|
def->NodeName = A.Name();
|
||||||
|
def->Body = B;
|
||||||
|
def->Type = nullptr;
|
||||||
|
def->Symbol = nullptr;
|
||||||
|
def->Flags = ZCC_Extension;
|
||||||
|
X = def;
|
||||||
|
}
|
||||||
|
|
||||||
%type struct_flags{ClassFlagsBlock}
|
%type struct_flags{ClassFlagsBlock}
|
||||||
struct_flags(X) ::= . { X.Flags = 0; X.Version = {0, 0}; }
|
struct_flags(X) ::= . { X.Flags = 0; X.Version = {0, 0}; }
|
||||||
struct_flags(X) ::= struct_flags(A) UI. { X.Flags = A.Flags | ZCC_UIFlag; }
|
struct_flags(X) ::= struct_flags(A) UI. { X.Flags = A.Flags | ZCC_UIFlag; }
|
||||||
|
|
|
@ -377,8 +377,30 @@ void ZCCCompiler::ProcessMixin(ZCC_MixinDef *cnode, PSymbolTreeNode *treenode)
|
||||||
|
|
||||||
void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZCC_Class *outer)
|
void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZCC_Class *outer)
|
||||||
{
|
{
|
||||||
Structs.Push(new ZCC_StructWork(static_cast<ZCC_Struct *>(cnode), treenode, outer));
|
ZCC_StructWork* cls = nullptr;
|
||||||
ZCC_StructWork *cls = Structs.Last();
|
|
||||||
|
// If this is a struct extension, put the new node directly into the existing class.
|
||||||
|
if (cnode->Flags == ZCC_Extension)
|
||||||
|
{
|
||||||
|
for (auto strct : Structs)
|
||||||
|
{
|
||||||
|
if (strct->NodeName() == cnode->NodeName)
|
||||||
|
{
|
||||||
|
cls = strct;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cls == nullptr)
|
||||||
|
{
|
||||||
|
Error(cnode, "Struct %s cannot be found in the current translation unit.", FName(cnode->NodeName).GetChars());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Structs.Push(new ZCC_StructWork(static_cast<ZCC_Struct*>(cnode), treenode, outer));
|
||||||
|
cls = Structs.Last();
|
||||||
|
}
|
||||||
|
|
||||||
auto node = cnode->Body;
|
auto node = cnode->Body;
|
||||||
PSymbolTreeNode *childnode;
|
PSymbolTreeNode *childnode;
|
||||||
|
@ -494,7 +516,15 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols,
|
||||||
ProcessClass(static_cast<ZCC_Class *>(node), tnode);
|
ProcessClass(static_cast<ZCC_Class *>(node), tnode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
goto common;
|
||||||
case AST_Struct:
|
case AST_Struct:
|
||||||
|
if (static_cast<ZCC_Class*>(node)->Flags == ZCC_Extension)
|
||||||
|
{
|
||||||
|
ProcessStruct(static_cast<ZCC_Struct*>(node), tnode, nullptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
common:
|
||||||
case AST_ConstantDef:
|
case AST_ConstantDef:
|
||||||
case AST_Enum:
|
case AST_Enum:
|
||||||
if ((tnode = AddTreeNode(static_cast<ZCC_NamedNode *>(node)->NodeName, node, GlobalTreeNodes)))
|
if ((tnode = AddTreeNode(static_cast<ZCC_NamedNode *>(node)->NodeName, node, GlobalTreeNodes)))
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include "gstrings.h"
|
#include "gstrings.h"
|
||||||
#include "printf.h"
|
#include "printf.h"
|
||||||
#include "s_music.h"
|
#include "s_music.h"
|
||||||
|
#include "i_interface.h"
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -354,6 +355,18 @@ DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetCursor, GetCursor)
|
||||||
ACTION_RETURN_STRING(FString(self->GetCursor()));
|
ACTION_RETURN_STRING(FString(self->GetCursor()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int GetGlyphHeight(FFont* fnt, int code)
|
||||||
|
{
|
||||||
|
auto glyph = fnt->GetChar(code, CR_UNTRANSLATED, nullptr);
|
||||||
|
return glyph ? (int)glyph->GetDisplayHeight() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetGlyphHeight, GetGlyphHeight)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(FFont);
|
||||||
|
PARAM_INT(code);
|
||||||
|
ACTION_RETURN_INT(GetGlyphHeight(self, code));
|
||||||
|
}
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// file system
|
// file system
|
||||||
|
@ -541,7 +554,7 @@ DEFINE_ACTION_FUNCTION(_CVar, FindCVar)
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
#if 0
|
|
||||||
DEFINE_ACTION_FUNCTION(FKeyBindings, SetBind)
|
DEFINE_ACTION_FUNCTION(FKeyBindings, SetBind)
|
||||||
{
|
{
|
||||||
PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings);
|
PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings);
|
||||||
|
@ -623,7 +636,7 @@ DEFINE_ACTION_FUNCTION(DOptionMenuItemCommand, DoCommand)
|
||||||
C_DoCommand(cmd);
|
C_DoCommand(cmd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
DEFINE_ACTION_FUNCTION(_Console, MidPrint)
|
DEFINE_ACTION_FUNCTION(_Console, MidPrint)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
|
@ -659,3 +672,5 @@ DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, loop);
|
||||||
|
|
||||||
DEFINE_GLOBAL_NAMED(PClass::AllClasses, AllClasses)
|
DEFINE_GLOBAL_NAMED(PClass::AllClasses, AllClasses)
|
||||||
DEFINE_GLOBAL(Bindings)
|
DEFINE_GLOBAL(Bindings)
|
||||||
|
DEFINE_GLOBAL(AutomapBindings)
|
||||||
|
DEFINE_GLOBAL(generic_ui)
|
||||||
|
|
|
@ -265,6 +265,11 @@ FTextureID FTextureManager::CheckForTexture (const char *name, ETextureType uset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!(flags & TEXMAN_NoAlias))
|
||||||
|
{
|
||||||
|
int* alias = aliases.CheckKey(name);
|
||||||
|
if (alias) return FTextureID(*alias);
|
||||||
|
}
|
||||||
|
|
||||||
return FTextureID(-1);
|
return FTextureID(-1);
|
||||||
}
|
}
|
||||||
|
@ -1539,6 +1544,19 @@ void FTextureManager::SetTranslation(FTextureID fromtexnum, FTextureID totexnum)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Adds an alias name to the texture manager.
|
||||||
|
// Aliases are only checked if no real texture with the given name exists.
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void FTextureManager::AddAlias(const char* name, FGameTexture* tex)
|
||||||
|
{
|
||||||
|
FTextureID id = tex->GetID();
|
||||||
|
if (tex != Textures[id.GetIndex()].Texture || !tex->isValid()) return; // Whatever got passed in here was not valid, so ignore the alias.
|
||||||
|
aliases.Insert(name, id.GetIndex());
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
|
|
@ -89,7 +89,8 @@ public:
|
||||||
TEXMAN_ShortNameOnly = 16,
|
TEXMAN_ShortNameOnly = 16,
|
||||||
TEXMAN_DontCreate = 32,
|
TEXMAN_DontCreate = 32,
|
||||||
TEXMAN_Localize = 64,
|
TEXMAN_Localize = 64,
|
||||||
TEXMAN_ForceLookup = 128
|
TEXMAN_ForceLookup = 128,
|
||||||
|
TEXMAN_NoAlias = 256,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
@ -144,6 +145,8 @@ public:
|
||||||
tmanips.Remove(cname);
|
tmanips.Remove(cname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddAlias(const char* name, FGameTexture* tex);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// texture counting
|
// texture counting
|
||||||
|
@ -190,6 +193,7 @@ private:
|
||||||
TArray<int> Translation;
|
TArray<int> Translation;
|
||||||
|
|
||||||
TMap<FName, TextureManipulation> tmanips;
|
TMap<FName, TextureManipulation> tmanips;
|
||||||
|
TMap<FName, int> aliases;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -73,8 +73,10 @@ bool FName::NameManager::Inited;
|
||||||
static const char *PredefinedNames[] =
|
static const char *PredefinedNames[] =
|
||||||
{
|
{
|
||||||
#define xx(n) #n,
|
#define xx(n) #n,
|
||||||
|
#define xy(n, s) s,
|
||||||
#include "namedef.h"
|
#include "namedef.h"
|
||||||
#undef xx
|
#undef xx
|
||||||
|
#undef xy
|
||||||
};
|
};
|
||||||
|
|
||||||
// CODE --------------------------------------------------------------------
|
// CODE --------------------------------------------------------------------
|
||||||
|
|
|
@ -40,8 +40,10 @@
|
||||||
enum ENamedName
|
enum ENamedName
|
||||||
{
|
{
|
||||||
#define xx(n) NAME_##n,
|
#define xx(n) NAME_##n,
|
||||||
|
#define xy(n, s) NAME_##n,
|
||||||
#include "namedef.h"
|
#include "namedef.h"
|
||||||
#undef xx
|
#undef xx
|
||||||
|
#undef xy
|
||||||
};
|
};
|
||||||
|
|
||||||
class FString;
|
class FString;
|
||||||
|
|
|
@ -252,11 +252,11 @@ void ChangeLevel(MapRecord* map, int skill)
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
void DeferedStartGame(MapRecord* map, int skill)
|
void DeferedStartGame(MapRecord* map, int skill, bool nostopsound)
|
||||||
{
|
{
|
||||||
g_nextmap = map;
|
g_nextmap = map;
|
||||||
g_nextskill = skill;
|
g_nextskill = skill;
|
||||||
gameaction = ga_newgame;
|
gameaction = nostopsound? ga_newgamenostopsound : ga_newgame;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
|
@ -62,9 +62,12 @@
|
||||||
#include "v_video.h"
|
#include "v_video.h"
|
||||||
#include "v_draw.h"
|
#include "v_draw.h"
|
||||||
#include "g_input.h"
|
#include "g_input.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "raze_music.h"
|
#include "raze_music.h"
|
||||||
#include "gstrings.h"
|
#include "gstrings.h"
|
||||||
|
#include "menustate.h"
|
||||||
|
#include "i_interface.h"
|
||||||
|
#include "vm.h"
|
||||||
|
|
||||||
#define LEFTMARGIN 8
|
#define LEFTMARGIN 8
|
||||||
#define RIGHTMARGIN 8
|
#define RIGHTMARGIN 8
|
||||||
|
@ -108,6 +111,8 @@ constate_e ConsoleState = c_up;
|
||||||
|
|
||||||
double NotifyFontScale = 1;
|
double NotifyFontScale = 1;
|
||||||
|
|
||||||
|
DEFINE_GLOBAL(NotifyFontScale)
|
||||||
|
|
||||||
void C_SetNotifyFontScale(double scale)
|
void C_SetNotifyFontScale(double scale)
|
||||||
{
|
{
|
||||||
NotifyFontScale = scale;
|
NotifyFontScale = scale;
|
||||||
|
@ -165,9 +170,6 @@ CVAR(Int, developer, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||||
EXTERN_CVAR(Int, uiscale);
|
EXTERN_CVAR(Int, uiscale);
|
||||||
|
|
||||||
|
|
||||||
CVAR(Bool, generic_ui, false, CVAR_ARCHIVE)
|
|
||||||
|
|
||||||
|
|
||||||
struct History
|
struct History
|
||||||
{
|
{
|
||||||
struct History *Older;
|
struct History *Older;
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
#include "c_console.h"
|
#include "c_console.h"
|
||||||
#include "d_gui.h"
|
#include "d_gui.h"
|
||||||
#include "inputstate.h"
|
#include "inputstate.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "gamestate.h"
|
#include "gamestate.h"
|
||||||
#include "gamecontrol.h"
|
#include "gamecontrol.h"
|
||||||
#include "uiinput.h"
|
#include "uiinput.h"
|
||||||
|
|
|
@ -36,9 +36,10 @@
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
#include "c_buttons.h"
|
#include "c_buttons.h"
|
||||||
#include "v_draw.h"
|
#include "v_draw.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "gamestruct.h"
|
#include "gamestruct.h"
|
||||||
#include "gamecvars.h"
|
#include "gamecvars.h"
|
||||||
|
#include "menustate.h"
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "i_video.h"
|
#include "i_video.h"
|
||||||
#include "c_console.h"
|
#include "c_console.h"
|
||||||
#include "d_net.h"
|
#include "d_net.h"
|
||||||
|
|
|
@ -41,7 +41,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "i_specialpaths.h"
|
#include "i_specialpaths.h"
|
||||||
#include "raze_music.h"
|
#include "raze_music.h"
|
||||||
#include "statistics.h"
|
#include "statistics.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "gstrings.h"
|
#include "gstrings.h"
|
||||||
#include "quotemgr.h"
|
#include "quotemgr.h"
|
||||||
#include "mapinfo.h"
|
#include "mapinfo.h"
|
||||||
|
@ -71,15 +71,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "uiinput.h"
|
#include "uiinput.h"
|
||||||
#include "d_net.h"
|
#include "d_net.h"
|
||||||
#include "automap.h"
|
#include "automap.h"
|
||||||
|
#include "v_draw.h"
|
||||||
|
#include "gi.h"
|
||||||
|
|
||||||
CVAR(Bool, autoloadlights, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR(Bool, autoloadlights, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
CVAR(Bool, autoloadbrightmaps, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
CVAR(Bool, autoloadbrightmaps, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||||
CVARD(Bool, invertmousex, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "invert horizontal mouse movement")
|
CVARD(Bool, invertmousex, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "invert horizontal mouse movement")
|
||||||
CVARD(Bool, invertmouse, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "invert vertical mouse movement")
|
CVARD(Bool, invertmouse, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "invert vertical mouse movement")
|
||||||
|
|
||||||
|
EXTERN_CVAR(Bool, ui_generic)
|
||||||
|
|
||||||
CUSTOM_CVAR(String, language, "auto", CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG)
|
CUSTOM_CVAR(String, language, "auto", CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG)
|
||||||
{
|
{
|
||||||
GStrings.UpdateLanguage(self);
|
GStrings.UpdateLanguage(self);
|
||||||
|
UpdateGenericUI(ui_generic);
|
||||||
}
|
}
|
||||||
|
|
||||||
CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG | CVAR_ARCHIVE)
|
CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG | CVAR_ARCHIVE)
|
||||||
|
@ -132,8 +137,6 @@ bool AppActive = true;
|
||||||
|
|
||||||
FString currentGame;
|
FString currentGame;
|
||||||
FString LumpFilter;
|
FString LumpFilter;
|
||||||
TMap<FName, int32_t> NameToTileIndex; // for assigning names to tiles. The menu accesses this list. By default it gets everything from the dynamic tile map in Duke Nukem and Redneck Rampage.
|
|
||||||
// Todo: Add additional definition file for the other games or textures not in that list so that the menu does not have to rely on indices.
|
|
||||||
|
|
||||||
CVAR(Bool, queryiwad, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
CVAR(Bool, queryiwad, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||||
CVAR(String, defaultiwad, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
CVAR(String, defaultiwad, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||||
|
@ -158,12 +161,6 @@ int StrTable_GetGender()
|
||||||
|
|
||||||
bool validFilter(const char* str);
|
bool validFilter(const char* str);
|
||||||
|
|
||||||
static StringtableCallbacks stblcb =
|
|
||||||
{
|
|
||||||
validFilter,
|
|
||||||
StrTable_GetGender
|
|
||||||
};
|
|
||||||
|
|
||||||
extern int chatmodeon;
|
extern int chatmodeon;
|
||||||
|
|
||||||
bool System_WantGuiCapture()
|
bool System_WantGuiCapture()
|
||||||
|
@ -465,7 +462,7 @@ namespace ShadowWarrior
|
||||||
{
|
{
|
||||||
::GameInterface* CreateInterface();
|
::GameInterface* CreateInterface();
|
||||||
}
|
}
|
||||||
namespace Powerslave
|
namespace Exhumed
|
||||||
{
|
{
|
||||||
::GameInterface* CreateInterface();
|
::GameInterface* CreateInterface();
|
||||||
}
|
}
|
||||||
|
@ -482,7 +479,7 @@ void CheckFrontend(int flags)
|
||||||
}
|
}
|
||||||
else if (flags & GAMEFLAG_PSEXHUMED)
|
else if (flags & GAMEFLAG_PSEXHUMED)
|
||||||
{
|
{
|
||||||
gi = Powerslave::CreateInterface();
|
gi = Exhumed::CreateInterface();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -493,6 +490,8 @@ void CheckFrontend(int flags)
|
||||||
void I_StartupJoysticks();
|
void I_StartupJoysticks();
|
||||||
void I_ShutdownInput();
|
void I_ShutdownInput();
|
||||||
int RunGame();
|
int RunGame();
|
||||||
|
void System_MenuClosed();
|
||||||
|
void System_MenuDim();
|
||||||
|
|
||||||
int GameMain()
|
int GameMain()
|
||||||
{
|
{
|
||||||
|
@ -512,9 +511,13 @@ int GameMain()
|
||||||
nullptr,
|
nullptr,
|
||||||
System_GetSceneRect,
|
System_GetSceneRect,
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
System_MenuDim,
|
||||||
nullptr,
|
nullptr,
|
||||||
System_DispatchEvent,
|
System_DispatchEvent,
|
||||||
|
validFilter,
|
||||||
|
StrTable_GetGender,
|
||||||
|
System_MenuClosed,
|
||||||
|
nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -533,7 +536,7 @@ int GameMain()
|
||||||
r = -1;
|
r = -1;
|
||||||
}
|
}
|
||||||
DeleteScreenJob();
|
DeleteScreenJob();
|
||||||
M_ClearMenus(true);
|
DeinitMenus();
|
||||||
if (gi)
|
if (gi)
|
||||||
{
|
{
|
||||||
gi->FreeGameData(); // Must be done before taking down any subsystems.
|
gi->FreeGameData(); // Must be done before taking down any subsystems.
|
||||||
|
@ -551,7 +554,6 @@ int GameMain()
|
||||||
TileFiles.CloseAll(); // delete the texture data before shutting down graphics.
|
TileFiles.CloseAll(); // delete the texture data before shutting down graphics.
|
||||||
GLInterface.Deinit();
|
GLInterface.Deinit();
|
||||||
I_ShutdownGraphics();
|
I_ShutdownGraphics();
|
||||||
M_DeinitMenus();
|
|
||||||
engineUnInit();
|
engineUnInit();
|
||||||
if (gi)
|
if (gi)
|
||||||
{
|
{
|
||||||
|
@ -745,6 +747,7 @@ static TArray<GrpEntry> SetupGame()
|
||||||
currentGame = LumpFilter;
|
currentGame = LumpFilter;
|
||||||
currentGame.Truncate(currentGame.IndexOf("."));
|
currentGame.Truncate(currentGame.IndexOf("."));
|
||||||
CheckFrontend(g_gameType);
|
CheckFrontend(g_gameType);
|
||||||
|
gameinfo.gametype = g_gameType;
|
||||||
return usedgroups;
|
return usedgroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -851,10 +854,10 @@ int RunGame()
|
||||||
TexMan.Init([]() {}, [](BuildInfo &) {});
|
TexMan.Init([]() {}, [](BuildInfo &) {});
|
||||||
V_InitFonts();
|
V_InitFonts();
|
||||||
TileFiles.Init();
|
TileFiles.Init();
|
||||||
sfx_empty = fileSystem.FindFile("engine/dsempty.lmp"); // this must be done outside the sound code because it's initialized late.
|
|
||||||
I_InitSound();
|
I_InitSound();
|
||||||
Mus_InitMusic();
|
Mus_InitMusic();
|
||||||
S_ParseSndInfo();
|
S_ParseSndInfo();
|
||||||
|
S_ParseReverbDef();
|
||||||
InitStatistics();
|
InitStatistics();
|
||||||
LoadScripts();
|
LoadScripts();
|
||||||
SetDefaultStrings();
|
SetDefaultStrings();
|
||||||
|
@ -870,8 +873,11 @@ int RunGame()
|
||||||
if (exec) exec->ExecCommands();
|
if (exec) exec->ExecCommands();
|
||||||
|
|
||||||
SetupGameButtons();
|
SetupGameButtons();
|
||||||
|
gameinfo.mBackButton = "engine/graphics/m_back.png";
|
||||||
gi->app_init();
|
gi->app_init();
|
||||||
|
SetDefaultMenuColors();
|
||||||
M_Init();
|
M_Init();
|
||||||
|
BuildGameMenus();
|
||||||
if (!(paletteloaded & PALETTE_MAIN))
|
if (!(paletteloaded & PALETTE_MAIN))
|
||||||
I_FatalError("No palette found.");
|
I_FatalError("No palette found.");
|
||||||
|
|
||||||
|
@ -1791,3 +1797,70 @@ void playerProcessHelpers(fixed_t* q16ang, double* angAdjust, fixed_t* angTarget
|
||||||
*q16horiz += FloatToFixed(scaleAdjust * *horizAdjust);
|
*q16horiz += FloatToFixed(scaleAdjust * *horizAdjust);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool M_Active()
|
||||||
|
{
|
||||||
|
return CurrentMenu != nullptr || ConsoleState == c_down || ConsoleState == c_falling;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct gamefilter
|
||||||
|
{
|
||||||
|
const char* gamename;
|
||||||
|
int gameflag;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const gamefilter games[] = {
|
||||||
|
{ "Duke", GAMEFLAG_DUKE},
|
||||||
|
{ "Nam", GAMEFLAG_NAM | GAMEFLAG_NAPALM},
|
||||||
|
{ "NamOnly", GAMEFLAG_NAM}, // for cases where the difference matters.
|
||||||
|
{ "Napalm", GAMEFLAG_NAPALM},
|
||||||
|
{ "WW2GI", GAMEFLAG_WW2GI},
|
||||||
|
{ "Redneck", GAMEFLAG_RR},
|
||||||
|
{ "RedneckRides", GAMEFLAG_RRRA},
|
||||||
|
{ "Deer", GAMEFLAG_DEER},
|
||||||
|
{ "Blood", GAMEFLAG_BLOOD},
|
||||||
|
{ "ShadowWarrior", GAMEFLAG_SW},
|
||||||
|
{ "Exhumed", GAMEFLAG_POWERSLAVE | GAMEFLAG_EXHUMED},
|
||||||
|
{ "Plutopak", GAMEFLAG_PLUTOPAK},
|
||||||
|
{ "Worldtour", GAMEFLAG_WORLDTOUR},
|
||||||
|
{ "Shareware", GAMEFLAG_SHAREWARE},
|
||||||
|
};
|
||||||
|
|
||||||
|
bool validFilter(const char* str)
|
||||||
|
{
|
||||||
|
for (auto& gf : games)
|
||||||
|
{
|
||||||
|
if (g_gameType & gf.gameflag)
|
||||||
|
{
|
||||||
|
if (!stricmp(str, gf.gamename)) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "vm.h"
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(_Screen, GetViewWindow)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
if (numret > 0) ret[0].SetInt(windowxy1.x);
|
||||||
|
if (numret > 1) ret[1].SetInt(windowxy1.y);
|
||||||
|
if (numret > 2) ret[2].SetInt(windowxy2.x - windowxy1.x + 1);
|
||||||
|
if (numret > 3) ret[3].SetInt(windowxy2.y - windowxy1.y + 1);
|
||||||
|
return MIN(numret, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION_NATIVE(_Build, ShadeToLight, shadeToLight)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_INT(shade);
|
||||||
|
ACTION_RETURN_INT(shadeToLight(shade));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern bool demoplayback;
|
||||||
|
DEFINE_GLOBAL(multiplayer)
|
||||||
|
DEFINE_GLOBAL(netgame)
|
||||||
|
DEFINE_GLOBAL(gameaction)
|
||||||
|
DEFINE_GLOBAL(gamestate)
|
||||||
|
DEFINE_GLOBAL(demoplayback)
|
||||||
|
DEFINE_GLOBAL(consoleplayer)
|
||||||
|
|
|
@ -22,15 +22,11 @@ extern cycle_t drawtime, actortime, thinktime, gameupdatetime;
|
||||||
extern bool r_NoInterpolate;
|
extern bool r_NoInterpolate;
|
||||||
|
|
||||||
struct MapRecord;
|
struct MapRecord;
|
||||||
struct FSaveGameNode;
|
|
||||||
extern MapRecord* g_nextmap;
|
extern MapRecord* g_nextmap;
|
||||||
extern int g_nextskill;
|
extern int g_nextskill;
|
||||||
extern FSaveGameNode* g_savenode;
|
|
||||||
|
|
||||||
extern FMemArena dump; // this is for memory blocks than cannot be deallocated without some huge effort. Put them in here so that they do not register on shutdown.
|
extern FMemArena dump; // this is for memory blocks than cannot be deallocated without some huge effort. Put them in here so that they do not register on shutdown.
|
||||||
|
|
||||||
extern TMap<FName, int32_t> NameToTileIndex;
|
|
||||||
|
|
||||||
int CONFIG_Init();
|
int CONFIG_Init();
|
||||||
|
|
||||||
// I am not sure if anything below will survive for long...
|
// I am not sure if anything below will survive for long...
|
||||||
|
@ -60,7 +56,7 @@ int GetAutomapZoom(int gZoom);
|
||||||
|
|
||||||
void DrawCrosshair(int deftile, int health, double xdelta, double ydelta, double scale, PalEntry color = 0xffffffff);
|
void DrawCrosshair(int deftile, int health, double xdelta, double ydelta, double scale, PalEntry color = 0xffffffff);
|
||||||
void updatePauseStatus();
|
void updatePauseStatus();
|
||||||
void DeferedStartGame(MapRecord* map, int skill);
|
void DeferedStartGame(MapRecord* map, int skill, bool nostopsound = false);
|
||||||
void ChangeLevel(MapRecord* map, int skill);
|
void ChangeLevel(MapRecord* map, int skill);
|
||||||
void CompleteLevel(MapRecord* map);
|
void CompleteLevel(MapRecord* map);
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,9 @@ enum gameaction_t : int
|
||||||
ga_savegame, // save the game
|
ga_savegame, // save the game
|
||||||
ga_autosave, // autosave the game (for triggering a save from within the game.)
|
ga_autosave, // autosave the game (for triggering a save from within the game.)
|
||||||
ga_completed, // Level was exited.
|
ga_completed, // Level was exited.
|
||||||
ga_nextlevel // Actually start the next level.
|
ga_nextlevel, // Actually start the next level.
|
||||||
|
ga_loadgamehidecon,
|
||||||
|
ga_newgamenostopsound, // start a new game
|
||||||
};
|
};
|
||||||
extern gamestate_t gamestate;
|
extern gamestate_t gamestate;
|
||||||
extern gameaction_t gameaction;
|
extern gameaction_t gameaction;
|
||||||
|
|
|
@ -33,21 +33,6 @@ struct FSavegameInfo
|
||||||
int currentsavever;
|
int currentsavever;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FSaveGameNode
|
|
||||||
{
|
|
||||||
FString SaveTitle;
|
|
||||||
FString Filename;
|
|
||||||
bool bOldVersion = false;
|
|
||||||
bool bMissingWads = false;
|
|
||||||
bool bNoDelete = false;
|
|
||||||
bool bIsExt = false;
|
|
||||||
|
|
||||||
bool isValid() const
|
|
||||||
{
|
|
||||||
return Filename.IsNotEmpty() && !bOldVersion && !bMissingWads;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ReservedSpace
|
struct ReservedSpace
|
||||||
{
|
{
|
||||||
int top;
|
int top;
|
||||||
|
@ -71,7 +56,6 @@ struct GameInterface
|
||||||
virtual void FreeGameData() {}
|
virtual void FreeGameData() {}
|
||||||
virtual void PlayHudSound() {}
|
virtual void PlayHudSound() {}
|
||||||
virtual GameStats getStats() { return {}; }
|
virtual GameStats getStats() { return {}; }
|
||||||
virtual void DrawNativeMenuText(int fontnum, int state, double xpos, double ypos, float fontscale, const char* text, int flags) {}
|
|
||||||
virtual void MainMenuOpened() {}
|
virtual void MainMenuOpened() {}
|
||||||
virtual void MenuOpened() {}
|
virtual void MenuOpened() {}
|
||||||
virtual void MenuClosed() {}
|
virtual void MenuClosed() {}
|
||||||
|
@ -80,12 +64,9 @@ struct GameInterface
|
||||||
virtual void CustomMenuSelection(int menu, int item) {}
|
virtual void CustomMenuSelection(int menu, int item) {}
|
||||||
virtual bool StartGame(FNewGameStartup& gs) { return false; }
|
virtual bool StartGame(FNewGameStartup& gs) { return false; }
|
||||||
virtual FSavegameInfo GetSaveSig() { return { "", 0, 0}; }
|
virtual FSavegameInfo GetSaveSig() { return { "", 0, 0}; }
|
||||||
virtual bool DrawSpecialScreen(const DVector2 &origin, int tilenum) { return false; }
|
|
||||||
virtual void DrawCenteredTextScreen(const DVector2& origin, const char* text, int position, bool withbg = true);
|
|
||||||
virtual double SmallFontScale() { return 1; }
|
virtual double SmallFontScale() { return 1; }
|
||||||
virtual void DrawMenuCaption(const DVector2& origin, const char* text) {}
|
virtual bool SaveGame() { return true; }
|
||||||
virtual bool SaveGame(FSaveGameNode*) { return true; }
|
virtual bool LoadGame() { return true; }
|
||||||
virtual bool LoadGame(FSaveGameNode*) { return true; }
|
|
||||||
virtual void SerializeGameState(FSerializer& arc) {}
|
virtual void SerializeGameState(FSerializer& arc) {}
|
||||||
virtual void DrawPlayerSprite(const DVector2& origin, bool onteam) {}
|
virtual void DrawPlayerSprite(const DVector2& origin, bool onteam) {}
|
||||||
virtual void QuitToTitle() {}
|
virtual void QuitToTitle() {}
|
||||||
|
|
52
source/core/gi.cpp
Normal file
52
source/core/gi.cpp
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
** gi.cpp
|
||||||
|
** Holds same game-dependant info
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
** Copyright 1998-2006 Randy Heit
|
||||||
|
** 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 <stdlib.h>
|
||||||
|
#include "gi.h"
|
||||||
|
#include "sc_man.h"
|
||||||
|
#include "filesystem.h"
|
||||||
|
#include "v_video.h"
|
||||||
|
#include "vm.h"
|
||||||
|
#include "c_cvars.h"
|
||||||
|
|
||||||
|
gameinfo_t gameinfo;
|
||||||
|
|
||||||
|
EXTERN_CVAR(Float, turbo)
|
||||||
|
|
||||||
|
|
||||||
|
DEFINE_GLOBAL(gameinfo)
|
||||||
|
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, gametype)
|
||||||
|
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mBackButton)
|
||||||
|
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mSliderColor)
|
||||||
|
|
55
source/core/gi.h
Normal file
55
source/core/gi.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
** gi.h
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
** Copyright 1998-2006 Randy Heit
|
||||||
|
** 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.
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GI_H__
|
||||||
|
#define __GI_H__
|
||||||
|
|
||||||
|
#include "basics.h"
|
||||||
|
#include "zstring.h"
|
||||||
|
#include "name.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct gameinfo_t
|
||||||
|
{
|
||||||
|
int gametype;
|
||||||
|
FName mSliderColor;
|
||||||
|
FString mBackButton;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern gameinfo_t gameinfo;
|
||||||
|
|
||||||
|
bool CheckGame(const char *string, bool chexisdoom);
|
||||||
|
|
||||||
|
#endif //__GI_H__
|
|
@ -376,6 +376,9 @@ void InitFileSystem(TArray<GrpEntry>& groups)
|
||||||
LumpFilterInfo lfi;
|
LumpFilterInfo lfi;
|
||||||
|
|
||||||
lfi.dotFilter = LumpFilter;
|
lfi.dotFilter = LumpFilter;
|
||||||
|
|
||||||
|
if (g_gameType & (GAMEFLAG_DUKE | GAMEFLAG_NAM | GAMEFLAG_NAPALM | GAMEFLAG_WW2GI | GAMEFLAG_RRALL)) lfi.gameTypeFilter.Push("DukeEngine");
|
||||||
|
|
||||||
lfi.postprocessFunc = [&]()
|
lfi.postprocessFunc = [&]()
|
||||||
{
|
{
|
||||||
DeleteStuff(fileSystem, todelete, groups.Size());
|
DeleteStuff(fileSystem, todelete, groups.Size());
|
||||||
|
|
|
@ -67,7 +67,7 @@
|
||||||
#include "d_net.h"
|
#include "d_net.h"
|
||||||
#include "gamecontrol.h"
|
#include "gamecontrol.h"
|
||||||
#include "c_console.h"
|
#include "c_console.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "i_system.h"
|
#include "i_system.h"
|
||||||
#include "raze_sound.h"
|
#include "raze_sound.h"
|
||||||
#include "raze_music.h"
|
#include "raze_music.h"
|
||||||
|
@ -76,7 +76,6 @@
|
||||||
#include "screenjob.h"
|
#include "screenjob.h"
|
||||||
#include "mmulti.h"
|
#include "mmulti.h"
|
||||||
#include "c_console.h"
|
#include "c_console.h"
|
||||||
#include "menu.h"
|
|
||||||
#include "uiinput.h"
|
#include "uiinput.h"
|
||||||
#include "v_video.h"
|
#include "v_video.h"
|
||||||
#include "glbackend/glbackend.h"
|
#include "glbackend/glbackend.h"
|
||||||
|
@ -86,6 +85,8 @@
|
||||||
#include "mapinfo.h"
|
#include "mapinfo.h"
|
||||||
#include "automap.h"
|
#include "automap.h"
|
||||||
#include "statusbar.h"
|
#include "statusbar.h"
|
||||||
|
#include "gamestruct.h"
|
||||||
|
#include "savegamehelp.h"
|
||||||
|
|
||||||
CVAR(Bool, vid_activeinbackground, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
CVAR(Bool, vid_activeinbackground, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||||
CVAR(Bool, r_ticstability, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
CVAR(Bool, r_ticstability, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||||
|
@ -103,7 +104,7 @@ int entertic;
|
||||||
int oldentertics;
|
int oldentertics;
|
||||||
int gametic;
|
int gametic;
|
||||||
|
|
||||||
extern FString BackupSaveGame;
|
FString BackupSaveGame;
|
||||||
|
|
||||||
void DoLoadGame(const char* name);
|
void DoLoadGame(const char* name);
|
||||||
|
|
||||||
|
@ -146,7 +147,9 @@ static void GameTicker()
|
||||||
C_ClearMessages();
|
C_ClearMessages();
|
||||||
if (BackupSaveGame.IsNotEmpty() && cl_resumesavegame)
|
if (BackupSaveGame.IsNotEmpty() && cl_resumesavegame)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
DoLoadGame(BackupSaveGame);
|
DoLoadGame(BackupSaveGame);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -184,8 +187,9 @@ static void GameTicker()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ga_newgame:
|
case ga_newgame:
|
||||||
newGameStarted = true;
|
|
||||||
FX_StopAllSounds();
|
FX_StopAllSounds();
|
||||||
|
case ga_newgamenostopsound:
|
||||||
|
newGameStarted = true;
|
||||||
FX_SetReverb(0);
|
FX_SetReverb(0);
|
||||||
gi->FreeLevelData();
|
gi->FreeLevelData();
|
||||||
C_ClearMessages();
|
C_ClearMessages();
|
||||||
|
@ -206,7 +210,7 @@ static void GameTicker()
|
||||||
case ga_mainmenunostopsound:
|
case ga_mainmenunostopsound:
|
||||||
gi->FreeLevelData();
|
gi->FreeLevelData();
|
||||||
gamestate = GS_MENUSCREEN;
|
gamestate = GS_MENUSCREEN;
|
||||||
M_StartControlPanel(false);
|
M_StartControlPanel(ga == ga_mainmenu);
|
||||||
M_SetMenu(NAME_Mainmenu);
|
M_SetMenu(NAME_Mainmenu);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -339,12 +343,14 @@ void Display()
|
||||||
}
|
}
|
||||||
|
|
||||||
screen->FrameTime = I_msTimeFS();
|
screen->FrameTime = I_msTimeFS();
|
||||||
|
tileUpdateAnimations();
|
||||||
screen->BeginFrame();
|
screen->BeginFrame();
|
||||||
twodpsp.Clear();
|
twodpsp.Clear();
|
||||||
twodpsp.SetSize(screen->GetWidth(), screen->GetHeight());
|
twodpsp.SetSize(screen->GetWidth(), screen->GetHeight());
|
||||||
twodpsp.ClearClipRect();
|
twodpsp.ClearClipRect();
|
||||||
twod->Clear();
|
twod->Clear();
|
||||||
twod->SetSize(screen->GetWidth(), screen->GetHeight());
|
//twod->SetSize(screen->GetWidth(), screen->GetHeight());
|
||||||
|
twod->Begin(screen->GetWidth(), screen->GetHeight());
|
||||||
twod->ClearClipRect();
|
twod->ClearClipRect();
|
||||||
switch (gamestate)
|
switch (gamestate)
|
||||||
{
|
{
|
||||||
|
@ -643,6 +649,7 @@ void MainLoop ()
|
||||||
Printf (PRINT_BOLD, "\n%s\n", error.GetMessage());
|
Printf (PRINT_BOLD, "\n%s\n", error.GetMessage());
|
||||||
}
|
}
|
||||||
gi->ErrorCleanup();
|
gi->ErrorCleanup();
|
||||||
|
M_ClearMenus();
|
||||||
C_FullConsole();
|
C_FullConsole();
|
||||||
gameaction = ga_nothing;
|
gameaction = ga_nothing;
|
||||||
}
|
}
|
||||||
|
@ -651,6 +658,8 @@ void MainLoop ()
|
||||||
error.MaybePrintMessage();
|
error.MaybePrintMessage();
|
||||||
Printf("%s", error.stacktrace.GetChars());
|
Printf("%s", error.stacktrace.GetChars());
|
||||||
gi->ErrorCleanup();
|
gi->ErrorCleanup();
|
||||||
|
twod->SetOffset(DVector2(0, 0));
|
||||||
|
M_ClearMenus();
|
||||||
C_FullConsole();
|
C_FullConsole();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,12 @@
|
||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
#include "printf.h"
|
#include "printf.h"
|
||||||
|
|
||||||
|
FString gSkillNames[MAXSKILLS];
|
||||||
|
FString gVolumeNames[MAXVOLUMES];
|
||||||
|
FString gVolumeSubtitles[MAXVOLUMES];
|
||||||
|
int32_t gVolumeFlags[MAXVOLUMES];
|
||||||
|
int gDefaultVolume = 0, gDefaultSkill = 1;
|
||||||
|
|
||||||
MapRecord mapList[512]; // Due to how this gets used it needs to be static. EDuke defines 7 episode plus one spare episode with 64 potential levels each and relies on the static array which is freely accessible by scripts.
|
MapRecord mapList[512]; // Due to how this gets used it needs to be static. EDuke defines 7 episode plus one spare episode with 64 potential levels each and relies on the static array which is freely accessible by scripts.
|
||||||
MapRecord *currentLevel; // level that is currently played. (The real level, not what script hacks modfifying the current level index can pretend.)
|
MapRecord *currentLevel; // level that is currently played. (The real level, not what script hacks modfifying the current level index can pretend.)
|
||||||
MapRecord* lastLevel; // Same here, for the last level.
|
MapRecord* lastLevel; // Same here, for the last level.
|
||||||
|
|
|
@ -7,6 +7,27 @@
|
||||||
#undef GetMessage // Windows strikes...
|
#undef GetMessage // Windows strikes...
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
enum EMax
|
||||||
|
{
|
||||||
|
MAXSKILLS = 7,
|
||||||
|
MAXVOLUMES = 7,
|
||||||
|
MAXMENUGAMEPLAYENTRIES = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EVolFlags
|
||||||
|
{
|
||||||
|
EF_HIDEFROMSP = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
// These get filled in by the map definition parsers of the front ends.
|
||||||
|
extern FString gSkillNames[MAXSKILLS];
|
||||||
|
extern FString gVolumeNames[MAXVOLUMES];
|
||||||
|
extern FString gVolumeSubtitles[MAXVOLUMES];
|
||||||
|
extern int32_t gVolumeFlags[MAXVOLUMES];
|
||||||
|
extern int gDefaultVolume, gDefaultSkill;
|
||||||
|
|
||||||
|
|
||||||
// Localization capable replacement of the game specific solutions.
|
// Localization capable replacement of the game specific solutions.
|
||||||
|
|
||||||
inline void MakeStringLocalizable(FString "e)
|
inline void MakeStringLocalizable(FString "e)
|
||||||
|
|
|
@ -1,182 +0,0 @@
|
||||||
/*
|
|
||||||
** imagescroller.cpp
|
|
||||||
** Scrolls through multiple fullscreen image pages,
|
|
||||||
**
|
|
||||||
**---------------------------------------------------------------------------
|
|
||||||
** Copyright 2019 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_font.h"
|
|
||||||
#include "cmdlib.h"
|
|
||||||
#include "gstrings.h"
|
|
||||||
#include "d_gui.h"
|
|
||||||
#include "d_event.h"
|
|
||||||
#include "menu.h"
|
|
||||||
#include "v_draw.h"
|
|
||||||
#include "gamecontrol.h"
|
|
||||||
#include "build.h"
|
|
||||||
#include "zstring.h"
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// Fullscreen image drawer (move to its own source file!)
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
void ImageScreen::Drawer()
|
|
||||||
{
|
|
||||||
if (mDesc == nullptr)
|
|
||||||
{
|
|
||||||
// don't let bogus definitions crash this.
|
|
||||||
}
|
|
||||||
else if (mDesc->type == 0)
|
|
||||||
{
|
|
||||||
auto tileindexp = NameToTileIndex.CheckKey(FName(mDesc->text, true));
|
|
||||||
int tileindex = 0;
|
|
||||||
if (tileindexp == nullptr)
|
|
||||||
{
|
|
||||||
// If this isn't a name, try a literal tile index;
|
|
||||||
auto c = mDesc->text.GetChars();
|
|
||||||
if (*c == '#') tileindex = (int)strtoll(c + 1, nullptr, 0);
|
|
||||||
// Error out if the screen cannot be found, this is always a definition error that needs to be reported.
|
|
||||||
else I_Error("Invalid menu screen '%s'", mDesc->text.GetChars());
|
|
||||||
}
|
|
||||||
else tileindex = *tileindexp;
|
|
||||||
if (!gi->DrawSpecialScreen(origin, tileindex)) // allows the front end to do custom handling for a given image.
|
|
||||||
{
|
|
||||||
DrawTexture(twod, tileGetTexture(tileindex), origin.X, origin.Y, DTA_FullscreenScale, FSMode_Fit320x200, DTA_TopLeft, true, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (mDesc->type > 0)
|
|
||||||
{
|
|
||||||
gi->DrawCenteredTextScreen(origin, mDesc->text, mDesc->type);
|
|
||||||
}
|
|
||||||
// QAVs are handled in the Blood frontend. Maybe they should be moved out? Stuff for later, but this is a feature where it is feasible.
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageScreen* DImageScrollerMenu::newImageScreen(FImageScrollerDescriptor::ScrollerItem* desc)
|
|
||||||
{
|
|
||||||
return new ImageScreen(desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DImageScrollerMenu::Init(DMenu* parent, FImageScrollerDescriptor* desc)
|
|
||||||
{
|
|
||||||
mParentMenu = parent;
|
|
||||||
index = 0;
|
|
||||||
mDesc = desc;
|
|
||||||
canAnimate = !!(mDesc->mFlags & LMF_Animate);
|
|
||||||
|
|
||||||
mCurrent = newImageScreen(&mDesc->mItems[0]);
|
|
||||||
mCurrent->canAnimate = canAnimate;
|
|
||||||
isAnimated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DImageScrollerMenu::MenuEvent(int mkey, bool fromcontroller)
|
|
||||||
{
|
|
||||||
if (mDesc->mItems.Size() <= 1)
|
|
||||||
{
|
|
||||||
if (mkey == MKEY_Enter) mkey = MKEY_Back;
|
|
||||||
else if (mkey == MKEY_Right || mkey == MKEY_Left) return true;
|
|
||||||
}
|
|
||||||
switch (mkey)
|
|
||||||
{
|
|
||||||
case MKEY_Back:
|
|
||||||
// Before going back the currently running transition must be terminated.
|
|
||||||
pageTransition.previous = nullptr;
|
|
||||||
if (pageTransition.current) pageTransition.current->origin = { 0,0 };
|
|
||||||
return DMenu::MenuEvent(mkey, fromcontroller);
|
|
||||||
|
|
||||||
|
|
||||||
case MKEY_Left:
|
|
||||||
if (pageTransition.previous == nullptr)
|
|
||||||
{
|
|
||||||
if (--index < 0) index = mDesc->mItems.Size() - 1;
|
|
||||||
auto next = newImageScreen(&mDesc->mItems[index]);
|
|
||||||
next->canAnimate = canAnimate;
|
|
||||||
if (!pageTransition.StartTransition(mCurrent, next, MA_Return))
|
|
||||||
{
|
|
||||||
delete mCurrent;
|
|
||||||
}
|
|
||||||
mCurrent = next;
|
|
||||||
gi->MenuSound(ChooseSound);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MKEY_Right:
|
|
||||||
case MKEY_Enter:
|
|
||||||
if (pageTransition.previous == nullptr)
|
|
||||||
{
|
|
||||||
int oldindex = index;
|
|
||||||
if (++index >= (int)mDesc->mItems.Size()) index = 0;
|
|
||||||
|
|
||||||
auto next = newImageScreen(&mDesc->mItems[index]);
|
|
||||||
next->canAnimate = canAnimate;
|
|
||||||
if (!pageTransition.StartTransition(mCurrent, next, MA_Advance))
|
|
||||||
{
|
|
||||||
delete mCurrent;
|
|
||||||
}
|
|
||||||
mCurrent = next;
|
|
||||||
gi->MenuSound(ChooseSound);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return DMenu::MenuEvent(mkey, fromcontroller);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DImageScrollerMenu::MouseEvent(int type, int x, int y)
|
|
||||||
{
|
|
||||||
// Todo: Implement some form of drag event to switch between pages.
|
|
||||||
if (type == MOUSE_Release)
|
|
||||||
{
|
|
||||||
return MenuEvent(MKEY_Enter, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return DMenu::MouseEvent(type, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DImageScrollerMenu::Ticker()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void DImageScrollerMenu::Drawer()
|
|
||||||
{
|
|
||||||
if (pageTransition.previous != nullptr)
|
|
||||||
{
|
|
||||||
auto res = pageTransition.Draw();
|
|
||||||
if (res) return;
|
|
||||||
delete pageTransition.previous;
|
|
||||||
pageTransition.previous = nullptr;
|
|
||||||
}
|
|
||||||
mCurrent->origin = origin;
|
|
||||||
mCurrent->Drawer();
|
|
||||||
mCurrent->origin = {};
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,434 +0,0 @@
|
||||||
/*
|
|
||||||
** 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.h"
|
|
||||||
#include "c_dispatch.h"
|
|
||||||
#include "filesystem.h"
|
|
||||||
#include "sc_man.h"
|
|
||||||
#include "v_font.h"
|
|
||||||
#include "c_bind.h"
|
|
||||||
#include "d_event.h"
|
|
||||||
#include "d_gui.h"
|
|
||||||
#include "m_joy.h"
|
|
||||||
#include "v_video.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 GetSliderValue()
|
|
||||||
{
|
|
||||||
return SELECTED_JOYSTICK->GetSensitivity();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetSliderValue(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 GetSliderValue()
|
|
||||||
{
|
|
||||||
double d = SELECTED_JOYSTICK->GetAxisScale(mAxis);
|
|
||||||
mNeg = d < 0? -1:1;
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetSliderValue(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 GetSliderValue()
|
|
||||||
{
|
|
||||||
double d = SELECTED_JOYSTICK->GetAxisDeadZone(mAxis);
|
|
||||||
mNeg = d < 0? -1:1;
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetSliderValue(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()
|
|
||||||
{
|
|
||||||
double f = SELECTED_JOYSTICK->GetAxisMap(mAxis);
|
|
||||||
FOptionValues **opt = OptionValues.CheckKey(mValues);
|
|
||||||
if (opt != NULL && *opt != NULL)
|
|
||||||
{
|
|
||||||
// Map from joystick axis to menu selection.
|
|
||||||
for(unsigned i = 0; i < (*opt)->mValues.Size(); i++)
|
|
||||||
{
|
|
||||||
if (fabs(f - (*opt)->mValues[i].Value) < FLT_EPSILON)
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetSelection(int selection)
|
|
||||||
{
|
|
||||||
FOptionValues **opt = OptionValues.CheckKey(mValues);
|
|
||||||
// Map from menu selection to joystick axis.
|
|
||||||
if (opt == NULL || *opt == NULL || (unsigned)selection >= (*opt)->mValues.Size())
|
|
||||||
{
|
|
||||||
selection = JOYAXIS_None;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
selection = (int)(*opt)->mValues[selection].Value;
|
|
||||||
}
|
|
||||||
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
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// 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(FName caller) override
|
|
||||||
{
|
|
||||||
UpdateJoystickConfigMenu(mJoy);
|
|
||||||
return FOptionMenuItemSubmenu::Activate(caller);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*=======================================
|
|
||||||
*
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
if (joy == NULL)
|
|
||||||
{
|
|
||||||
opt->mTitle = "$JOYMNU_TITLE";
|
|
||||||
it = new FOptionMenuItemStaticText("$JOYMNU_INVALID");
|
|
||||||
opt->mItems.Push(it);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
opt->mTitle.Format("%s", joy->GetName().GetChars());
|
|
||||||
|
|
||||||
SELECTED_JOYSTICK = joy;
|
|
||||||
|
|
||||||
it = new FOptionMenuSliderJoySensitivity("$JOYMNU_OVRSENS", 0, 2, 0.1, 3);
|
|
||||||
opt->mItems.Push(it);
|
|
||||||
it = new FOptionMenuItemStaticText(" ");
|
|
||||||
opt->mItems.Push(it);
|
|
||||||
|
|
||||||
if (joy->GetNumAxes() > 0)
|
|
||||||
{
|
|
||||||
it = new FOptionMenuItemStaticText("$JOYMNU_AXIS");
|
|
||||||
opt->mItems.Push(it);
|
|
||||||
|
|
||||||
for (int i = 0; i < joy->GetNumAxes(); ++i)
|
|
||||||
{
|
|
||||||
it = new FOptionMenuItemStaticText(" ");
|
|
||||||
opt->mItems.Push(it);
|
|
||||||
|
|
||||||
it = new FOptionMenuItemJoyMap(joy->GetAxisName(i), i, "JoyAxisMapNames", false);
|
|
||||||
opt->mItems.Push(it);
|
|
||||||
it = new FOptionMenuSliderJoyScale("$JOYMNU_OVRSENS", i, 0, 4, 0.1, 3);
|
|
||||||
opt->mItems.Push(it);
|
|
||||||
it = new FOptionMenuItemInverter("$JOYMNU_INVERT", i, false);
|
|
||||||
opt->mItems.Push(it);
|
|
||||||
it = new FOptionMenuSliderJoyDeadZone("$JOYMNU_DEADZONE", i, 0, 0.9, 0.05, 3);
|
|
||||||
opt->mItems.Push(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
it = new FOptionMenuItemStaticText("$JOYMNU_NOAXES");
|
|
||||||
opt->mItems.Push(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
opt->mScrollPos = 0;
|
|
||||||
opt->mSelectedItem = -1;
|
|
||||||
opt->mIndent = 0;
|
|
||||||
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("$JOYMNU_ENABLE", "use_joystick", "YesNo", NULL, false);
|
|
||||||
opt->mItems.Push(it);
|
|
||||||
#if 0//def _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(" ");
|
|
||||||
opt->mItems.Push(it);
|
|
||||||
|
|
||||||
if (Joysticks.Size() == 0)
|
|
||||||
{
|
|
||||||
it = new FOptionMenuItemStaticText("$JOYMNU_NOCON");
|
|
||||||
opt->mItems.Push(it);
|
|
||||||
if (!use_joystick)
|
|
||||||
{
|
|
||||||
it = new FOptionMenuItemStaticText("$JOYMNU_DISABLED1");
|
|
||||||
opt->mItems.Push(it);
|
|
||||||
it = new FOptionMenuItemStaticText("$JOYMNU_DISABLED2");
|
|
||||||
opt->mItems.Push(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
it = new FOptionMenuItemStaticText("$JOYMNU_CONFIG");
|
|
||||||
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 (CurrentMenu != NULL && dynamic_cast<DJoystickConfigMenu*>(CurrentMenu))
|
|
||||||
{
|
|
||||||
CurrentMenu->Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static TMenuClassDescriptor<DJoystickConfigMenu> _im("JoystickConfigMenu");
|
|
||||||
|
|
||||||
void RegisterJoystickMenus()
|
|
||||||
{
|
|
||||||
menuClasses.Push(&_im);
|
|
||||||
}
|
|
|
@ -1,634 +0,0 @@
|
||||||
/*
|
|
||||||
** 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_font.h"
|
|
||||||
#include "cmdlib.h"
|
|
||||||
#include "gstrings.h"
|
|
||||||
#include "d_gui.h"
|
|
||||||
#include "d_event.h"
|
|
||||||
#include "menu.h"
|
|
||||||
#include "v_draw.h"
|
|
||||||
#include "gamecontrol.h"
|
|
||||||
#include "build.h"
|
|
||||||
#include "v_video.h"
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
DListMenu::DListMenu(DMenu *parent, FListMenuDescriptor *desc)
|
|
||||||
: DMenu(parent)
|
|
||||||
{
|
|
||||||
mDesc = NULL;
|
|
||||||
if (desc != NULL) Init(parent, desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
void DListMenu::Init(DMenu *parent, FListMenuDescriptor *desc)
|
|
||||||
{
|
|
||||||
mParentMenu = parent;
|
|
||||||
mDesc = desc;
|
|
||||||
canAnimate = !!(mDesc->mFlags & LMF_Animate);
|
|
||||||
if (mDesc->mScriptId >= 0) scriptID = mDesc->mScriptId;
|
|
||||||
#if 0
|
|
||||||
if (desc->mCenter)
|
|
||||||
{
|
|
||||||
int center = 160;
|
|
||||||
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
|
|
||||||
{
|
|
||||||
int xpos = mDesc->mItems[i]->GetX();
|
|
||||||
int width = mDesc->mItems[i]->GetWidth();
|
|
||||||
int curx = mDesc->mSelectOfsX;
|
|
||||||
|
|
||||||
if (width > 0 && mDesc->mItems[i]->Selectable())
|
|
||||||
{
|
|
||||||
int left = 160 - (width - curx) / 2 - curx;
|
|
||||||
if (left < center) center = left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
|
|
||||||
{
|
|
||||||
int width = mDesc->mItems[i]->GetWidth();
|
|
||||||
|
|
||||||
if (width > 0)
|
|
||||||
{
|
|
||||||
mDesc->mItems[i]->SetX(center);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
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;
|
|
||||||
SelectionChanged();
|
|
||||||
M_MenuSound(CursorSound);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(int i = 0; i < mDesc->mSelectedItem; i++)
|
|
||||||
{
|
|
||||||
if (mDesc->mItems[i]->CheckHotkey(ch))
|
|
||||||
{
|
|
||||||
mDesc->mSelectedItem = i;
|
|
||||||
SelectionChanged();
|
|
||||||
M_MenuSound(CursorSound);
|
|
||||||
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);
|
|
||||||
SelectionChanged();
|
|
||||||
M_MenuSound(CursorSound);
|
|
||||||
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);
|
|
||||||
SelectionChanged();
|
|
||||||
M_MenuSound(CursorSound);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MKEY_Enter:
|
|
||||||
if (mDesc->mSelectedItem >= 0 && mDesc->mItems[mDesc->mSelectedItem]->Activate(mDesc->mMenuName))
|
|
||||||
{
|
|
||||||
M_MenuSound(AdvanceSound);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return Super::MenuEvent(mkey, fromcontroller);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
bool DListMenu::MouseEvent(int type, int xx, int yy)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
int width43 = (screen->GetHeight() * 4 / 3);
|
|
||||||
int x = (xx - (screen->GetWidth() - width43) / 2) * 320 / width43;
|
|
||||||
int y = yy * 200 / screen->GetHeight();
|
|
||||||
|
|
||||||
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 ((int)i != mDesc->mSelectedItem)
|
|
||||||
{
|
|
||||||
// no sound. This is too noisy.
|
|
||||||
}
|
|
||||||
mDesc->mSelectedItem = i;
|
|
||||||
SelectionChanged();
|
|
||||||
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::PreDraw()
|
|
||||||
{
|
|
||||||
if (mDesc->mCaption.IsNotEmpty())
|
|
||||||
{
|
|
||||||
gi->DrawMenuCaption(origin, GStrings.localize(mDesc->mCaption));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DListMenu::Drawer ()
|
|
||||||
{
|
|
||||||
PreDraw();
|
|
||||||
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
|
|
||||||
{
|
|
||||||
mDesc->mItems[i]->Drawer(this, origin, mDesc->mSelectedItem == (int)i);
|
|
||||||
}
|
|
||||||
if (mDesc->mSelectedItem >= 0 && mDesc->mSelectedItem < (int)mDesc->mItems.Size())
|
|
||||||
mDesc->mItems[mDesc->mSelectedItem]->DrawSelector(mDesc->mSelectOfsX, mDesc->mSelectOfsY, mDesc->mSelector);
|
|
||||||
PostDraw();
|
|
||||||
Super::Drawer();
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// base class for menu items
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
FListMenuItem::~FListMenuItem()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FListMenuItem::CheckCoordinate(int x, int y)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FListMenuItem::Ticker()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void FListMenuItem::Drawer(DListMenu* menu, const DVector2& origin, bool selected)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FListMenuItem::Selectable()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FListMenuItem::DrawSelector(int xofs, int yofs, FGameTexture *tex)
|
|
||||||
{
|
|
||||||
if (tex)
|
|
||||||
{
|
|
||||||
DrawTexture (twod, tex, mXpos + xofs, mYpos + yofs, DTA_Clean, true, TAG_DONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FListMenuItem::Activate(FName)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int FListMenuItem::GetWidth()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// static patch
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
FListMenuItemStaticPatch::FListMenuItemStaticPatch(int x, int y, FGameTexture *patch, bool centered)
|
|
||||||
: FListMenuItem(x, y)
|
|
||||||
{
|
|
||||||
mTexture = patch;
|
|
||||||
mCentered = centered;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FListMenuItemStaticPatch::Drawer(DListMenu* menu, const DVector2& origin, bool selected)
|
|
||||||
{
|
|
||||||
if (!mTexture)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int x = mXpos;
|
|
||||||
FGameTexture *tex = mTexture;
|
|
||||||
if (mYpos >= 0)
|
|
||||||
{
|
|
||||||
if (mCentered) x -= tex->GetDisplayWidth()/2;
|
|
||||||
DrawTexture (twod, tex, x, mYpos, DTA_Clean, true, TAG_DONE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int x = (mXpos - 160) * CleanXfac + (screen->GetWidth()>>1);
|
|
||||||
if (mCentered) x -= (tex->GetDisplayWidth()*CleanXfac)/2;
|
|
||||||
DrawTexture (twod, 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 = text;
|
|
||||||
mFont = font;
|
|
||||||
mColor = color;
|
|
||||||
mCentered = centered;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FListMenuItemStaticText::Drawer(DListMenu* menu, const DVector2& origin, bool selected)
|
|
||||||
{
|
|
||||||
const char *text = mText;
|
|
||||||
if (text != NULL)
|
|
||||||
{
|
|
||||||
if (mYpos >= 0)
|
|
||||||
{
|
|
||||||
int x = mXpos;
|
|
||||||
if (mCentered) x -= mFont->StringWidth(text)/2;
|
|
||||||
DrawText(twod, mFont, mColor, x, mYpos, text, DTA_Clean, true, TAG_DONE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int x = (mXpos - 160) * CleanXfac + (screen->GetWidth()>>1);
|
|
||||||
if (mCentered) x -= (mFont->StringWidth(text)*CleanXfac)/2;
|
|
||||||
DrawText (twod, mFont, mColor, x, -mYpos*CleanYfac, text, DTA_CleanNoMove, true, TAG_DONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FListMenuItemStaticText::~FListMenuItemStaticText()
|
|
||||||
{
|
|
||||||
if (mText != NULL) delete [] mText;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// native static text item
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
FListMenuItemNativeStaticText::FListMenuItemNativeStaticText(int x, int y, const FString& text, int fontnum, int palnum, bool centered)
|
|
||||||
: FListMenuItem(x, y)
|
|
||||||
{
|
|
||||||
mText = text;
|
|
||||||
mFontnum = fontnum;
|
|
||||||
mPalnum = palnum;
|
|
||||||
mCentered = centered;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FListMenuItemNativeStaticText::Drawer(DListMenu* menu, const DVector2& origin, bool selected)
|
|
||||||
{
|
|
||||||
const char* text = mText;
|
|
||||||
if (mText.Len() && !mHidden)
|
|
||||||
{
|
|
||||||
gi->DrawNativeMenuText(mFontnum, mPalnum, origin.X + mXpos, origin.Y + mYpos, 1.f, GStrings.localize(text), menu->Descriptor()->mFlags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// 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 && !mHidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FListMenuItemSelectable::Activate(FName caller)
|
|
||||||
{
|
|
||||||
return M_SetMenu(mAction, mParam, caller);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (NULL != CurrentMenu && CurrentMenu->MenuEvent(MKEY_Enter, true))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// text item
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
FListMenuItemText::FListMenuItemText(int x, int y, int height, int hotkey, const FString &text, FFont *font, EColorRange color, EColorRange color2, FName child, int param)
|
|
||||||
: FListMenuItemSelectable(x, y, height, child, param)
|
|
||||||
{
|
|
||||||
mText = text;
|
|
||||||
mFont = font;
|
|
||||||
mColor = color;
|
|
||||||
mColorSelected = color2;
|
|
||||||
mFont = NewSmallFont;
|
|
||||||
mHotkey = hotkey;
|
|
||||||
}
|
|
||||||
|
|
||||||
FListMenuItemText::~FListMenuItemText()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void FListMenuItemText::Drawer(DListMenu* menu, const DVector2& origin, bool selected)
|
|
||||||
{
|
|
||||||
const char *text = GStrings(mText);
|
|
||||||
if (mText.Len())
|
|
||||||
{
|
|
||||||
DrawText(twod, mFont, selected ? mColorSelected : mColor, mXpos - mFont->StringWidth(text)/2, mYpos, text, DTA_Clean, true, TAG_DONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int FListMenuItemText::GetWidth()
|
|
||||||
{
|
|
||||||
const char *text = mText;
|
|
||||||
if (mText.Len())
|
|
||||||
{
|
|
||||||
return mFont->StringWidth(GStrings.localize(text));
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// native text item
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
FListMenuItemNativeText::FListMenuItemNativeText(int x, int y, int height, int hotkey, const FString& text, int fontnum, int palnum, float fontscale, FName child, int param)
|
|
||||||
: FListMenuItemSelectable(x, y, height, child, param)
|
|
||||||
{
|
|
||||||
mText = text;
|
|
||||||
mFontnum = NIT_BigFont;
|
|
||||||
mPalnum = NIT_ActiveColor;
|
|
||||||
mFontscale = fontscale;
|
|
||||||
mHotkey = hotkey;
|
|
||||||
}
|
|
||||||
|
|
||||||
FListMenuItemNativeText::~FListMenuItemNativeText()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void FListMenuItemNativeText::Drawer(DListMenu* menu, const DVector2& origin, bool selected)
|
|
||||||
{
|
|
||||||
const char* text = mText;
|
|
||||||
if (mText.Len() && !mHidden)
|
|
||||||
{
|
|
||||||
auto state = selected ? NIT_SelectedState : mEnabled ? NIT_ActiveState : NIT_InactiveState;
|
|
||||||
gi->DrawNativeMenuText(mFontnum, state, origin.X + mXpos, origin.Y + mYpos, 1.f, GStrings.localize(text), menu->Descriptor()->mFlags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int FListMenuItemNativeText::GetWidth()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// patch item
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
FListMenuItemPatch::FListMenuItemPatch(int x, int y, int height, int hotkey, FGameTexture *patch, FName child, int param)
|
|
||||||
: FListMenuItemSelectable(x, y, height, child, param)
|
|
||||||
{
|
|
||||||
mHotkey = hotkey;
|
|
||||||
mTexture = patch;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FListMenuItemPatch::Drawer(DListMenu* menu, const DVector2& origin, bool selected)
|
|
||||||
{
|
|
||||||
DrawTexture (twod, mTexture, mXpos, mYpos, DTA_Clean, true, TAG_DONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
int FListMenuItemPatch::GetWidth()
|
|
||||||
{
|
|
||||||
return mTexture
|
|
||||||
? mTexture->GetDisplayWidth()
|
|
||||||
: 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
**
|
**
|
||||||
**---------------------------------------------------------------------------
|
**---------------------------------------------------------------------------
|
||||||
** Copyright 2001-2010 Randy Heit
|
** Copyright 2001-2010 Randy Heit
|
||||||
** Copyright 2010 Christoph Oelckers
|
** Copyright 2010-2020 Christoph Oelckers
|
||||||
** All rights reserved.
|
** All rights reserved.
|
||||||
**
|
**
|
||||||
** Redistribution and use in source and binary forms, with or without
|
** Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -33,612 +33,124 @@
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "m_png.h"
|
#include "m_png.h"
|
||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
#include "v_text.h"
|
#include "v_text.h"
|
||||||
#include "d_event.h"
|
|
||||||
#include "gstrings.h"
|
#include "gstrings.h"
|
||||||
#include "d_gui.h"
|
#include "serializer.h"
|
||||||
#include "v_draw.h"
|
#include "vm.h"
|
||||||
#include "files.h"
|
#include "i_system.h"
|
||||||
#include "resourcefile.h"
|
|
||||||
#include "savegamehelp.h"
|
|
||||||
#include "i_specialpaths.h"
|
|
||||||
#include "findfile.h"
|
|
||||||
#include "v_video.h"
|
#include "v_video.h"
|
||||||
|
#include "findfile.h"
|
||||||
|
#include "v_draw.h"
|
||||||
|
#include "savegamehelp.h"
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// M_ReadSaveStrings
|
||||||
|
//
|
||||||
|
// Find savegames and read their titles
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
void FSavegameManager::ReadSaveStrings()
|
||||||
class DLoadSaveMenu : public DListMenu
|
|
||||||
{
|
{
|
||||||
using Super = DListMenu;
|
if (SaveGames.Size() == 0)
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
int Selected = 0;
|
|
||||||
int TopItem = 0;
|
|
||||||
|
|
||||||
|
|
||||||
int savepicLeft;
|
|
||||||
int savepicTop;
|
|
||||||
int savepicWidth;
|
|
||||||
int savepicHeight;
|
|
||||||
|
|
||||||
int rowHeight;
|
|
||||||
int listboxLeft;
|
|
||||||
int listboxTop;
|
|
||||||
int listboxWidth;
|
|
||||||
|
|
||||||
int listboxRows;
|
|
||||||
int listboxHeight;
|
|
||||||
int listboxRight;
|
|
||||||
int listboxBottom;
|
|
||||||
|
|
||||||
int commentLeft;
|
|
||||||
int commentTop;
|
|
||||||
int commentWidth;
|
|
||||||
int commentHeight;
|
|
||||||
int commentRight;
|
|
||||||
int commentBottom;
|
|
||||||
int commentRows;
|
|
||||||
|
|
||||||
double FontScale;
|
|
||||||
DTextEnterMenu *mInput = nullptr;
|
|
||||||
TArray<FBrokenLines> BrokenSaveComment;
|
|
||||||
bool mEntering = false;
|
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// End of static savegame maintenance code
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
DLoadSaveMenu()
|
|
||||||
{
|
{
|
||||||
savegameManager.ReadSaveStrings();
|
void *filefirst;
|
||||||
}
|
findstate_t c_file;
|
||||||
|
FString filter;
|
||||||
|
|
||||||
void Init(DMenu* parent, FListMenuDescriptor* desc) override
|
LastSaved = LastAccessed = -1;
|
||||||
{
|
quickSaveSlot = nullptr;
|
||||||
Super::Init(parent, desc);
|
filter = G_BuildSaveName("*");
|
||||||
int Width43 = screen->GetHeight() * 4 / 3;
|
filefirst = I_FindFirst(filter.GetChars(), &c_file);
|
||||||
int Left43 = (screen->GetWidth() - Width43) / 2;
|
if (filefirst != ((void *)(-1)))
|
||||||
float wScale = Width43 / 640.;
|
|
||||||
savepicLeft = Left43 + int(20 * wScale);
|
|
||||||
savepicTop = mDesc->mYpos * screen->GetHeight() / 200 ;
|
|
||||||
savepicWidth = int(240 * wScale);
|
|
||||||
savepicHeight = int(180 * wScale);
|
|
||||||
|
|
||||||
|
|
||||||
FontScale = std::max(screen->GetHeight() / 480, 1);
|
|
||||||
rowHeight = std::max(int((NewConsoleFont->GetHeight() + 1) * FontScale), 1);
|
|
||||||
listboxLeft = savepicLeft + savepicWidth + int(20 * wScale);
|
|
||||||
listboxTop = savepicTop;
|
|
||||||
listboxWidth = Width43 + Left43 - listboxLeft - int(30 * wScale);
|
|
||||||
int listboxHeight1 = screen->GetHeight() - listboxTop - int(20*wScale);
|
|
||||||
listboxRows = (listboxHeight1 - 1) / rowHeight;
|
|
||||||
listboxHeight = listboxRows * rowHeight + 1;
|
|
||||||
listboxRight = listboxLeft + listboxWidth;
|
|
||||||
listboxBottom = listboxTop + listboxHeight;
|
|
||||||
|
|
||||||
commentLeft = savepicLeft;
|
|
||||||
commentTop = savepicTop + savepicHeight + int(16 * wScale);
|
|
||||||
commentWidth = savepicWidth;
|
|
||||||
commentHeight = listboxHeight - savepicHeight - (16 * wScale);
|
|
||||||
commentRight = commentLeft + commentWidth;
|
|
||||||
commentBottom = commentTop + commentHeight;
|
|
||||||
commentRows = commentHeight / rowHeight;
|
|
||||||
UpdateSaveComment();
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
void Drawer() override
|
|
||||||
{
|
|
||||||
Super::Drawer();
|
|
||||||
|
|
||||||
int i;
|
|
||||||
unsigned j;
|
|
||||||
bool didSeeSelected = false;
|
|
||||||
|
|
||||||
// Draw picture area
|
|
||||||
/*
|
|
||||||
if (gameaction == ga_loadgame || gameaction == ga_loadgamehidecon || gameaction == ga_savegame)
|
|
||||||
{
|
{
|
||||||
return;
|
do
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
PalEntry frameColor(255, 80, 80, 80); // todo: pick a proper color per game.
|
|
||||||
PalEntry fillColor(160, 0, 0, 0);
|
|
||||||
DrawFrame(twod, frameColor, savepicLeft, savepicTop, savepicWidth, savepicHeight, -1);
|
|
||||||
if (!savegameManager.DrawSavePic(savepicLeft, savepicTop, savepicWidth, savepicHeight))
|
|
||||||
{
|
|
||||||
twod->AddColorOnlyQuad(savepicLeft, savepicTop, savepicWidth, savepicHeight, fillColor);
|
|
||||||
|
|
||||||
if (savegameManager.SavegameCount() > 0)
|
|
||||||
{
|
{
|
||||||
if (Selected >= savegameManager.SavegameCount()) Selected = 0;
|
// I_FindName only returns the file's name and not its full path
|
||||||
FString text = (Selected == -1 || !savegameManager.GetSavegame(Selected)->bOldVersion) ? GStrings("MNU_NOPICTURE") : GStrings("MNU_DIFFVERSION");
|
FString filepath = G_BuildSaveName(I_FindName(&c_file));
|
||||||
int textlen = NewSmallFont->StringWidth(text) * CleanXfac;
|
|
||||||
|
|
||||||
DrawText(twod, NewSmallFont, CR_GOLD, savepicLeft + (savepicWidth - textlen) / 2,
|
FResourceFile *savegame = FResourceFile::OpenResourceFile(filepath, true, true);
|
||||||
savepicTop + (savepicHeight - rowHeight) / 2, text, DTA_CleanNoMove, true, TAG_DONE);
|
if (savegame != nullptr)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw comment area
|
|
||||||
DrawFrame(twod, frameColor, commentLeft, commentTop, commentWidth, commentHeight, -1);
|
|
||||||
twod->AddColorOnlyQuad(commentLeft, commentTop, commentWidth, commentHeight, fillColor);
|
|
||||||
|
|
||||||
int numlinestoprint = std::min(commentRows, (int)BrokenSaveComment.Size());
|
|
||||||
for (int i = 0; i < numlinestoprint; i++)
|
|
||||||
{
|
|
||||||
DrawText(twod, NewConsoleFont, CR_ORANGE, commentLeft / FontScale, (commentTop + rowHeight * i) / FontScale, BrokenSaveComment[i].Text,
|
|
||||||
DTA_VirtualWidthF, screen->GetWidth() / FontScale, DTA_VirtualHeightF, screen->GetHeight() / FontScale, DTA_KeepRatio, true, TAG_DONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Draw file area
|
|
||||||
DrawFrame(twod, frameColor, listboxLeft, listboxTop, listboxWidth, listboxHeight, -1);
|
|
||||||
twod->AddColorOnlyQuad(listboxLeft, listboxTop, listboxWidth, listboxHeight, fillColor);
|
|
||||||
|
|
||||||
if (savegameManager.SavegameCount() == 0)
|
|
||||||
{
|
|
||||||
FString text = GStrings("MNU_NOFILES");
|
|
||||||
int textlen = int(NewConsoleFont->StringWidth(text) * FontScale);
|
|
||||||
|
|
||||||
DrawText(twod, NewConsoleFont, CR_GOLD, (listboxLeft + (listboxWidth - textlen) / 2) / FontScale, (listboxTop + (listboxHeight - rowHeight) / 2) / FontScale, text,
|
|
||||||
DTA_VirtualWidthF, screen->GetWidth() / FontScale, DTA_VirtualHeightF, screen->GetHeight() / FontScale, DTA_KeepRatio, true, TAG_DONE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
j = TopItem;
|
|
||||||
for (i = 0; i < listboxRows && j < savegameManager.SavegameCount(); i++)
|
|
||||||
{
|
|
||||||
int colr;
|
|
||||||
auto& node = *savegameManager.GetSavegame(j);
|
|
||||||
if (node.bOldVersion)
|
|
||||||
{
|
|
||||||
colr = CR_RED;
|
|
||||||
}
|
|
||||||
else if (node.bMissingWads)
|
|
||||||
{
|
|
||||||
colr = CR_YELLOW;
|
|
||||||
}
|
|
||||||
else if (j == Selected)
|
|
||||||
{
|
|
||||||
colr = CR_WHITE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
colr = CR_TAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
//screen->SetClipRect(listboxLeft, listboxTop+rowHeight*i, listboxRight, listboxTop+rowHeight*(i+1));
|
|
||||||
|
|
||||||
if ((int)j == Selected)
|
|
||||||
{
|
|
||||||
twod->AddColorOnlyQuad(listboxLeft, listboxTop + rowHeight * i, listboxWidth, rowHeight, mEntering ? PalEntry(255, 255, 0, 0) : PalEntry(255, 0, 0, 255));
|
|
||||||
didSeeSelected = true;
|
|
||||||
if (!mEntering)
|
|
||||||
{
|
{
|
||||||
DrawText(twod, NewConsoleFont, colr, (listboxLeft + 1) / FontScale, (listboxTop + rowHeight * i + FontScale) / FontScale, node.SaveTitle,
|
FResourceLump *info = savegame->FindLump("info.json");
|
||||||
DTA_VirtualWidthF, screen->GetWidth() / FontScale, DTA_VirtualHeightF, screen->GetHeight() / FontScale, DTA_KeepRatio, true, TAG_DONE);
|
if (info == nullptr)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FStringf s("%s%c", mInput->GetText(), NewConsoleFont->GetCursor());
|
|
||||||
int length = int(NewConsoleFont->StringWidth(s) * FontScale);
|
|
||||||
int displacement = std::min(0, listboxWidth - 2 - length);
|
|
||||||
DrawText(twod, NewConsoleFont, CR_WHITE, (listboxLeft + 1 + displacement) / FontScale, (listboxTop + rowHeight * i + FontScale) / FontScale, s,
|
|
||||||
DTA_VirtualWidthF, screen->GetWidth() / FontScale, DTA_VirtualHeightF, screen->GetHeight() / FontScale, DTA_KeepRatio, true, TAG_DONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DrawText(twod, NewConsoleFont, colr, (listboxLeft + 1) / FontScale, (listboxTop + rowHeight * i + FontScale) / FontScale, node.SaveTitle,
|
|
||||||
DTA_VirtualWidthF, screen->GetWidth() / FontScale, DTA_VirtualHeightF, screen->GetHeight() / FontScale, DTA_KeepRatio, true, TAG_DONE);
|
|
||||||
}
|
|
||||||
//screen->ClearClipRect();
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateSaveComment()
|
|
||||||
{
|
|
||||||
BrokenSaveComment = V_BreakLines(NewConsoleFont, int(commentWidth / FontScale), savegameManager.SaveCommentString);
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
bool MenuEvent(int mkey, bool fromcontroller) override
|
|
||||||
{
|
|
||||||
auto& manager = savegameManager;
|
|
||||||
switch (mkey)
|
|
||||||
{
|
|
||||||
case MKEY_Up:
|
|
||||||
if (manager.SavegameCount() > 1)
|
|
||||||
{
|
|
||||||
if (Selected == -1) Selected = TopItem;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (--Selected < 0) Selected = manager.SavegameCount() - 1;
|
|
||||||
if (Selected < TopItem) TopItem = Selected;
|
|
||||||
else if (Selected >= TopItem + listboxRows) TopItem = std::max(0, Selected - listboxRows + 1);
|
|
||||||
}
|
|
||||||
manager.UnloadSaveData();
|
|
||||||
manager.ExtractSaveData(Selected);
|
|
||||||
UpdateSaveComment();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MKEY_Down:
|
|
||||||
if (manager.SavegameCount() > 1)
|
|
||||||
{
|
|
||||||
if (Selected == -1) Selected = TopItem;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (++Selected >= manager.SavegameCount()) Selected = 0;
|
|
||||||
if (Selected < TopItem) TopItem = Selected;
|
|
||||||
else if (Selected >= TopItem + listboxRows) TopItem = std::max(0, Selected - listboxRows + 1);
|
|
||||||
}
|
|
||||||
manager.UnloadSaveData();
|
|
||||||
manager.ExtractSaveData(Selected);
|
|
||||||
UpdateSaveComment();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MKEY_PageDown:
|
|
||||||
if (manager.SavegameCount() > 1)
|
|
||||||
{
|
|
||||||
if (TopItem >= manager.SavegameCount() - listboxRows)
|
|
||||||
{
|
|
||||||
TopItem = 0;
|
|
||||||
if (Selected != -1) Selected = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TopItem = std::min(TopItem + listboxRows, int(manager.SavegameCount()) - listboxRows);
|
|
||||||
if (TopItem > Selected&& Selected != -1) Selected = TopItem;
|
|
||||||
}
|
|
||||||
manager.UnloadSaveData();
|
|
||||||
manager.ExtractSaveData(Selected);
|
|
||||||
UpdateSaveComment();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MKEY_PageUp:
|
|
||||||
if (manager.SavegameCount() > 1)
|
|
||||||
{
|
|
||||||
if (TopItem == 0)
|
|
||||||
{
|
|
||||||
TopItem = std::max(0, int(manager.SavegameCount()) - listboxRows);
|
|
||||||
if (Selected != -1) Selected = TopItem;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TopItem = std::max(int(TopItem - listboxRows), 0);
|
|
||||||
if (Selected >= TopItem + listboxRows) Selected = TopItem;
|
|
||||||
}
|
|
||||||
manager.UnloadSaveData();
|
|
||||||
manager.ExtractSaveData(Selected);
|
|
||||||
UpdateSaveComment();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MKEY_Enter:
|
|
||||||
return false; // This event will be handled by the subclasses
|
|
||||||
|
|
||||||
case MKEY_MBYes:
|
|
||||||
{
|
|
||||||
if (Selected < manager.SavegameCount())
|
|
||||||
{
|
|
||||||
Selected = manager.RemoveSaveSlot(Selected);
|
|
||||||
UpdateSaveComment();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return Super::MenuEvent(mkey, fromcontroller);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
bool MouseEvent(int type, int x, int y) override
|
|
||||||
{
|
|
||||||
auto& manager = savegameManager;
|
|
||||||
if (x >= listboxLeft && x < listboxLeft + listboxWidth &&
|
|
||||||
y >= listboxTop && y < listboxTop + listboxHeight)
|
|
||||||
{
|
|
||||||
int lineno = (y - listboxTop) / rowHeight;
|
|
||||||
|
|
||||||
if (TopItem + lineno < manager.SavegameCount())
|
|
||||||
{
|
|
||||||
Selected = TopItem + lineno;
|
|
||||||
manager.UnloadSaveData();
|
|
||||||
manager.ExtractSaveData(Selected);
|
|
||||||
UpdateSaveComment();
|
|
||||||
if (type == MOUSE_Release)
|
|
||||||
{
|
|
||||||
if (MenuEvent(MKEY_Enter, true))
|
|
||||||
{
|
{
|
||||||
return true;
|
// savegame info not found. This is not a savegame so leave it alone.
|
||||||
|
delete savegame;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto fr = info->NewReader();
|
||||||
|
FString title;
|
||||||
|
int check = G_ValidateSavegame(fr, &title, true);
|
||||||
|
fr.Close();
|
||||||
|
delete savegame;
|
||||||
|
if (check != 0)
|
||||||
|
{
|
||||||
|
FSaveGameNode *node = new FSaveGameNode;
|
||||||
|
node->Filename = filepath;
|
||||||
|
node->bOldVersion = check == -1;
|
||||||
|
node->bMissingWads = check == -2;
|
||||||
|
node->SaveTitle = title;
|
||||||
|
InsertSaveNode(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} while (I_FindNext (filefirst, &c_file) == 0);
|
||||||
else Selected = -1;
|
I_FindClose (filefirst);
|
||||||
}
|
|
||||||
else Selected = -1;
|
|
||||||
|
|
||||||
return Super::MouseEvent(type, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
bool Responder(event_t * ev) override
|
|
||||||
{
|
|
||||||
auto& manager = savegameManager;
|
|
||||||
if (ev->type == EV_GUI_Event)
|
|
||||||
{
|
|
||||||
if (ev->subtype == EV_GUI_KeyDown)
|
|
||||||
{
|
|
||||||
if ((unsigned)Selected < manager.SavegameCount())
|
|
||||||
{
|
|
||||||
switch (ev->data1)
|
|
||||||
{
|
|
||||||
case GK_F1:
|
|
||||||
manager.SetFileInfo(Selected);
|
|
||||||
UpdateSaveComment();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case GK_DEL:
|
|
||||||
case '\b':
|
|
||||||
{
|
|
||||||
FString EndString;
|
|
||||||
EndString.Format("%s" TEXTCOLOR_WHITE "%s" TEXTCOLOR_NORMAL "?\n\n%s",
|
|
||||||
GStrings("MNU_DELETESG"), manager.GetSavegame(Selected)->SaveTitle.GetChars(), GStrings("PRESSYN"));
|
|
||||||
M_StartMessage(EndString, 0, -1);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ev->subtype == EV_GUI_WheelUp)
|
|
||||||
{
|
|
||||||
if (TopItem > 0) TopItem--;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (ev->subtype == EV_GUI_WheelDown)
|
|
||||||
{
|
|
||||||
if (TopItem < manager.SavegameCount() - listboxRows) TopItem++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Super::Responder(ev);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
class DSaveMenu : public DLoadSaveMenu
|
|
||||||
{
|
|
||||||
using Super = DLoadSaveMenu;
|
|
||||||
FString mSaveName;
|
|
||||||
public:
|
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
DSaveMenu()
|
|
||||||
{
|
|
||||||
savegameManager.InsertNewSaveNode();
|
|
||||||
TopItem = 0;
|
|
||||||
Selected = savegameManager.ExtractSaveData (-1);
|
|
||||||
UpdateSaveComment();
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
void Destroy() override
|
|
||||||
{
|
|
||||||
if (savegameManager.RemoveNewSaveNode())
|
|
||||||
{
|
|
||||||
Selected--;
|
|
||||||
}
|
|
||||||
Super::Destroy();
|
|
||||||
}
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
bool MenuEvent (int mkey, bool fromcontroller) override
|
|
||||||
{
|
|
||||||
if (Super::MenuEvent(mkey, fromcontroller))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (Selected == -1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mkey == MKEY_Enter)
|
|
||||||
{
|
|
||||||
FString SavegameString = (Selected != 0)? savegameManager.GetSavegame(Selected)->SaveTitle : FString();
|
|
||||||
mInput = new DTextEnterMenu(this, NewConsoleFont, SavegameString, listboxWidth, false, false);
|
|
||||||
M_ActivateMenu(mInput);
|
|
||||||
mEntering = true;
|
|
||||||
}
|
|
||||||
else if (mkey == MKEY_Input)
|
|
||||||
{
|
|
||||||
mEntering = false;
|
|
||||||
mSaveName = mInput->GetText();
|
|
||||||
mInput = nullptr;
|
|
||||||
}
|
|
||||||
else if (mkey == MKEY_Abort)
|
|
||||||
{
|
|
||||||
mEntering = false;
|
|
||||||
mInput = nullptr;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
bool MouseEvent(int type, int x, int y) override
|
|
||||||
{
|
|
||||||
if (mSaveName.Len() > 0)
|
|
||||||
{
|
|
||||||
// Do not process events when saving is in progress to avoid update of the current index,
|
|
||||||
// i.e. Selected member variable must remain unchanged
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Super::MouseEvent(type, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
bool Responder (event_t *ev) override
|
|
||||||
{
|
|
||||||
if (ev->subtype == EV_GUI_KeyDown)
|
|
||||||
{
|
|
||||||
if (Selected != -1)
|
|
||||||
{
|
|
||||||
switch (ev->data1)
|
|
||||||
{
|
|
||||||
case GK_DEL:
|
|
||||||
case '\b':
|
|
||||||
// cannot delete 'new save game' item
|
|
||||||
if (Selected == 0) return true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'N':
|
|
||||||
Selected = TopItem = 0;
|
|
||||||
savegameManager.UnloadSaveData();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Super::Responder(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
void Ticker() override
|
|
||||||
{
|
|
||||||
if (mSaveName.Len() > 0)
|
|
||||||
{
|
|
||||||
savegameManager.DoSave(Selected, mSaveName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
class DLoadMenu : public DLoadSaveMenu
|
|
||||||
{
|
|
||||||
using Super = DLoadSaveMenu;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
DLoadMenu()
|
|
||||||
{
|
|
||||||
TopItem = 0;
|
|
||||||
Selected = savegameManager.ExtractSaveData(-1);
|
|
||||||
UpdateSaveComment();
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
bool MenuEvent(int mkey, bool fromcontroller) override
|
|
||||||
{
|
|
||||||
if (Super::MenuEvent(mkey, fromcontroller))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (Selected == -1 || savegameManager.SavegameCount() == 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mkey == MKEY_Enter)
|
|
||||||
{
|
|
||||||
savegameManager.LoadSavegame(Selected);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static TMenuClassDescriptor<DLoadMenu> _lm("LoadMenu");
|
|
||||||
static TMenuClassDescriptor<DSaveMenu> _sm("SaveMenu");
|
|
||||||
|
|
||||||
void RegisterLoadsaveMenus()
|
|
||||||
{
|
|
||||||
menuClasses.Push(&_sm);
|
|
||||||
menuClasses.Push(&_lm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
void FSavegameManager::PerformLoadGame(const char *f, bool s)
|
||||||
|
{
|
||||||
|
G_LoadGame(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSavegameManager::PerformSaveGame(const char *f, const char *s)
|
||||||
|
{
|
||||||
|
G_SaveGame(f, s, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
FString FSavegameManager::BuildSaveName(const char* fn, int slot)
|
||||||
|
{
|
||||||
|
return G_BuildSaveName(FStringf("%s%04d", fn, slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
FString FSavegameManager::ExtractSaveComment(FSerializer& arc)
|
||||||
|
{
|
||||||
|
FString comment, fcomment, ncomment, mtime;
|
||||||
|
|
||||||
|
arc("Creation Time", comment)
|
||||||
|
("Map Label", fcomment)
|
||||||
|
("Map Name", ncomment)
|
||||||
|
("Map Time", mtime);
|
||||||
|
|
||||||
|
comment.AppendFormat("\n%s - %s\n%s", fcomment.GetChars(), ncomment.GetChars(), mtime.GetChars());
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
FSavegameManager savegameManager;
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(FSavegameManager, GetManager)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
ACTION_RETURN_POINTER(&savegameManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,844 +0,0 @@
|
||||||
#ifndef __M_MENU_MENU_H__
|
|
||||||
#define __M_MENU_MENU_H__
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "v_font.h"
|
|
||||||
#include "c_cvars.h"
|
|
||||||
#include "version.h"
|
|
||||||
#include "textures.h"
|
|
||||||
#include "zstring.h"
|
|
||||||
#include "v_draw.h"
|
|
||||||
#include "menustate.h"
|
|
||||||
#include "gamestruct.h"
|
|
||||||
|
|
||||||
EXTERN_CVAR(Float, snd_menuvolume)
|
|
||||||
EXTERN_CVAR(Int, m_use_mouse);
|
|
||||||
|
|
||||||
enum EMax
|
|
||||||
{
|
|
||||||
MAXSKILLS = 7,
|
|
||||||
MAXVOLUMES = 7,
|
|
||||||
MAXMENUGAMEPLAYENTRIES = 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
// These get filled in by the map definition parsers of the front ends.
|
|
||||||
extern FString gSkillNames[MAXSKILLS];
|
|
||||||
extern FString gVolumeNames[MAXVOLUMES];
|
|
||||||
extern FString gVolumeSubtitles[MAXVOLUMES];
|
|
||||||
extern int32_t gVolumeFlags[MAXVOLUMES];
|
|
||||||
extern int gDefaultVolume, gDefaultSkill;
|
|
||||||
|
|
||||||
const int MENU_TICRATE = 30;
|
|
||||||
extern bool help_disabled, credits_disabled;
|
|
||||||
extern int g_currentMenu;
|
|
||||||
|
|
||||||
enum MenuTransitionType
|
|
||||||
{ // Note: This enum is for logical categories, not visual types.
|
|
||||||
MA_None,
|
|
||||||
MA_Return,
|
|
||||||
MA_Advance,
|
|
||||||
};
|
|
||||||
|
|
||||||
class DMenu;
|
|
||||||
|
|
||||||
struct MenuTransition
|
|
||||||
{
|
|
||||||
DMenu* previous;
|
|
||||||
DMenu* current;
|
|
||||||
|
|
||||||
double start;
|
|
||||||
int32_t length;
|
|
||||||
int32_t dir;
|
|
||||||
|
|
||||||
bool StartTransition(DMenu* from, DMenu* to, MenuTransitionType animtype);
|
|
||||||
bool Draw();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
EF_HIDEFROMSP = 1 << 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum MenuGameplayEntryFlags
|
|
||||||
{
|
|
||||||
MGE_Locked = 1u << 0u,
|
|
||||||
MGE_Hidden = 1u << 1u,
|
|
||||||
MGE_UserContent = 1u << 2u,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct MenuGameplayEntry
|
|
||||||
{
|
|
||||||
char name[64];
|
|
||||||
uint8_t flags;
|
|
||||||
|
|
||||||
bool isValid() const { return name[0] != '\0'; }
|
|
||||||
} MenuGameplayEntry;
|
|
||||||
|
|
||||||
typedef struct MenuGameplayStemEntry
|
|
||||||
{
|
|
||||||
MenuGameplayEntry entry;
|
|
||||||
MenuGameplayEntry subentries[MAXMENUGAMEPLAYENTRIES];
|
|
||||||
} MenuGameplayStemEntry;
|
|
||||||
|
|
||||||
extern MenuGameplayStemEntry g_MenuGameplayEntries[MAXMENUGAMEPLAYENTRIES];
|
|
||||||
|
|
||||||
|
|
||||||
enum EMenuSounds : int
|
|
||||||
{
|
|
||||||
ActivateSound,
|
|
||||||
CursorSound,
|
|
||||||
AdvanceSound,
|
|
||||||
BackSound,
|
|
||||||
CloseSound,
|
|
||||||
PageSound,
|
|
||||||
ChangeSound,
|
|
||||||
ChooseSound
|
|
||||||
};
|
|
||||||
|
|
||||||
EXTERN_CVAR(Bool, menu_sounds)
|
|
||||||
|
|
||||||
struct event_t;
|
|
||||||
class FGameTexture;
|
|
||||||
class FFont;
|
|
||||||
enum EColorRange : int;
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ENativeFontValues
|
|
||||||
{
|
|
||||||
NIT_BigFont,
|
|
||||||
NIT_SmallFont,
|
|
||||||
|
|
||||||
NIT_ActiveColor = -1,
|
|
||||||
NIT_InactiveColor = -2,
|
|
||||||
NIT_SelectedColor = -3,
|
|
||||||
|
|
||||||
NIT_ActiveState = 1,
|
|
||||||
NIT_InactiveState = 2,
|
|
||||||
NIT_SelectedState = 3
|
|
||||||
// positive values for color are direct palswap indices.
|
|
||||||
};
|
|
||||||
|
|
||||||
extern FNewGameStartup NewGameStartupInfo;
|
|
||||||
extern EMenuState menuactive;
|
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// 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,
|
|
||||||
MDESC_ImageScroller,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FMenuDescriptor
|
|
||||||
{
|
|
||||||
FName mMenuName;
|
|
||||||
FString mNetgameMessage;
|
|
||||||
int mType;
|
|
||||||
FName mClass;
|
|
||||||
|
|
||||||
virtual ~FMenuDescriptor() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class FListMenuItem;
|
|
||||||
class FOptionMenuItem;
|
|
||||||
|
|
||||||
enum ListMenuFlags
|
|
||||||
{
|
|
||||||
LMF_Centered = 1,
|
|
||||||
LMF_DontSpace = 2,
|
|
||||||
LMF_Animate = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FListMenuDescriptor : public FMenuDescriptor
|
|
||||||
{
|
|
||||||
TDeletingArray<FListMenuItem *> mItems;
|
|
||||||
FString mCaption;
|
|
||||||
int mSelectedItem;
|
|
||||||
int mSelectOfsX;
|
|
||||||
int mSelectOfsY;
|
|
||||||
FGameTexture *mSelector;
|
|
||||||
int mDisplayTop;
|
|
||||||
int mXpos, mYpos, mYbotton;
|
|
||||||
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
|
|
||||||
int mScriptId;
|
|
||||||
int mSecondaryId;
|
|
||||||
int mNativeFontNum, mNativePalNum;
|
|
||||||
float mNativeFontScale;
|
|
||||||
FFont *mFont;
|
|
||||||
EColorRange mFontColor;
|
|
||||||
EColorRange mFontColor2;
|
|
||||||
FMenuDescriptor *mRedirect; // used to redirect overlong skill and episode menus to option menu based alternatives
|
|
||||||
int mFlags;
|
|
||||||
int mSpacing;
|
|
||||||
|
|
||||||
FListMenuDescriptor()
|
|
||||||
{
|
|
||||||
Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FOptionMenuSettings
|
|
||||||
{
|
|
||||||
EColorRange mTitleColor;
|
|
||||||
EColorRange mFontColor;
|
|
||||||
EColorRange mFontColorValue;
|
|
||||||
EColorRange mFontColorMore;
|
|
||||||
EColorRange mFontColorHeader;
|
|
||||||
EColorRange mFontColorHighlight;
|
|
||||||
EColorRange mFontColorSelection;
|
|
||||||
int mLinespacing;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FOptionMenuDescriptor : public FMenuDescriptor
|
|
||||||
{
|
|
||||||
TDeletingArray<FOptionMenuItem *> mItems;
|
|
||||||
FString mTitle;
|
|
||||||
int mSelectedItem;
|
|
||||||
int mDrawTop;
|
|
||||||
int mScrollTop;
|
|
||||||
int mScrollPos;
|
|
||||||
int mIndent;
|
|
||||||
int mPosition;
|
|
||||||
bool mDontDim;
|
|
||||||
|
|
||||||
void CalcIndent();
|
|
||||||
FOptionMenuItem *GetItem(FName name);
|
|
||||||
void Reset()
|
|
||||||
{
|
|
||||||
// Reset the default settings (ignore all other values in the struct)
|
|
||||||
mPosition = 0;
|
|
||||||
mScrollTop = 0;
|
|
||||||
mIndent = 0;
|
|
||||||
mDontDim = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FImageScrollerDescriptor : public FMenuDescriptor
|
|
||||||
{
|
|
||||||
struct ScrollerItem
|
|
||||||
{
|
|
||||||
int type; // 0: fullscreen image; 1: centered text
|
|
||||||
int scriptID;
|
|
||||||
FString text;
|
|
||||||
};
|
|
||||||
int mFlags = 0;
|
|
||||||
|
|
||||||
TArray<ScrollerItem> mItems;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
bool mMouseCapture;
|
|
||||||
bool mBackbuttonSelected;
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
MOUSE_Click,
|
|
||||||
MOUSE_Move,
|
|
||||||
MOUSE_Release
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
BACKBUTTON_TIME = 4*MENU_TICRATE
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool InMenu;
|
|
||||||
|
|
||||||
DMenu *mParentMenu;
|
|
||||||
DVector2 origin = { 0,0 };
|
|
||||||
int scriptID = INT_MAX;
|
|
||||||
bool canAnimate = false;
|
|
||||||
bool isAnimated = false; // set to true when uncapped frame rate is needed.
|
|
||||||
|
|
||||||
DMenu(DMenu *parent = NULL);
|
|
||||||
virtual ~DMenu() = default;
|
|
||||||
virtual bool Responder (event_t *ev);
|
|
||||||
virtual bool MenuEvent (int mkey, bool fromcontroller);
|
|
||||||
virtual void Ticker ();
|
|
||||||
virtual void PreDraw() {}
|
|
||||||
virtual void PostDraw() {}
|
|
||||||
virtual void Drawer ();
|
|
||||||
virtual bool DimAllowed ();
|
|
||||||
virtual bool TranslateKeyboardEvents();
|
|
||||||
virtual void Close();
|
|
||||||
virtual bool MouseEvent(int type, int x, int y);
|
|
||||||
virtual void Destroy() {}
|
|
||||||
bool IsAnimated() const { return isAnimated; }
|
|
||||||
bool MouseEventBack(int type, int x, int y);
|
|
||||||
void SetCapture();
|
|
||||||
void ReleaseCapture();
|
|
||||||
void SetOrigin();
|
|
||||||
bool HasCapture()
|
|
||||||
{
|
|
||||||
return mMouseCapture;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// base class for menu items
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
class DListMenu;
|
|
||||||
|
|
||||||
class FListMenuItem
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
int mXpos, mYpos;
|
|
||||||
int mHeight;
|
|
||||||
FName mAction;
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool mEnabled, mHidden;
|
|
||||||
|
|
||||||
FListMenuItem(int xpos = 0, int ypos = 0, FName action = NAME_None)
|
|
||||||
{
|
|
||||||
mXpos = xpos;
|
|
||||||
mYpos = ypos;
|
|
||||||
mAction = action;
|
|
||||||
mEnabled = true;
|
|
||||||
mHidden = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~FListMenuItem();
|
|
||||||
|
|
||||||
virtual bool CheckCoordinate(int x, int y);
|
|
||||||
virtual void Ticker();
|
|
||||||
virtual void Drawer(DListMenu *menu, const DVector2& origin, bool selected);
|
|
||||||
virtual bool Selectable();
|
|
||||||
virtual bool Activate(FName caller);
|
|
||||||
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);
|
|
||||||
virtual int GetWidth();
|
|
||||||
virtual void DrawSelector(int xofs, int yofs, FGameTexture *tex);
|
|
||||||
void OffsetPositionY(int ydelta) { mYpos += ydelta; }
|
|
||||||
int GetY() { return mYpos; }
|
|
||||||
int GetX() { return mXpos; }
|
|
||||||
void SetX(int x) { mXpos = x; }
|
|
||||||
void SetY(int x) { mYpos = x; }
|
|
||||||
void SetHeight(int x) { mHeight = x; }
|
|
||||||
void SetAction(FName action) { mAction = action; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class FListMenuItemStaticPatch : public FListMenuItem
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
FGameTexture *mTexture;
|
|
||||||
bool mCentered;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FListMenuItemStaticPatch(int x, int y, FGameTexture *patch, bool centered);
|
|
||||||
void Drawer(DListMenu* menu, const DVector2& origin, 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(DListMenu* menu, const DVector2& origin, bool selected) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FListMenuItemNativeStaticText : public FListMenuItem
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
FString mText;
|
|
||||||
int mFontnum;
|
|
||||||
int mPalnum;
|
|
||||||
bool mCentered;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FListMenuItemNativeStaticText(int x, int y, const FString & text, int fontnum, int palnum, bool centered);
|
|
||||||
void Drawer(DListMenu* menu, const DVector2& origin, bool selected) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// selectable items
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
class FListMenuItemSelectable : public FListMenuItem
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
int mHotkey;
|
|
||||||
int mParam;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FListMenuItemSelectable(int x, int y, int height, FName childmenu, int mParam = -1);
|
|
||||||
bool CheckCoordinate(int x, int y) override;
|
|
||||||
bool Selectable() override;
|
|
||||||
bool CheckHotkey(int c) override;
|
|
||||||
bool Activate(FName caller) override;
|
|
||||||
bool MouseEvent(int type, int x, int y) override;
|
|
||||||
FName GetAction(int *pparam) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FListMenuItemText : public FListMenuItemSelectable
|
|
||||||
{
|
|
||||||
FString mText;
|
|
||||||
FFont *mFont;
|
|
||||||
EColorRange mColor;
|
|
||||||
EColorRange mColorSelected;
|
|
||||||
public:
|
|
||||||
FListMenuItemText(int x, int y, int height, int hotkey, const FString &text, FFont *font, EColorRange color, EColorRange color2, FName child, int param = 0);
|
|
||||||
~FListMenuItemText();
|
|
||||||
void Drawer(DListMenu* menu, const DVector2& origin, bool selected) override;
|
|
||||||
int GetWidth() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FListMenuItemNativeText : public FListMenuItemSelectable
|
|
||||||
{
|
|
||||||
// This draws the item with the game frontend's native text drawer and uses a front end defined font, it takes only symbolic constants as parameters.
|
|
||||||
FString mText;
|
|
||||||
int mFontnum;
|
|
||||||
int mPalnum;
|
|
||||||
float mFontscale;
|
|
||||||
public:
|
|
||||||
FListMenuItemNativeText(int x, int y, int height, int hotkey, const FString& text, int fontnum, int palnum, float fontscale, FName child, int param = 0);
|
|
||||||
~FListMenuItemNativeText();
|
|
||||||
void Drawer(DListMenu* menu, const DVector2& origin, bool selected) override;
|
|
||||||
int GetWidth() override;
|
|
||||||
void DrawSelector(int xofs, int yofs, FGameTexture* tex) override { } // The text drawer handles this itself.
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class FListMenuItemPatch : public FListMenuItemSelectable
|
|
||||||
{
|
|
||||||
FGameTexture* mTexture;
|
|
||||||
public:
|
|
||||||
FListMenuItemPatch(int x, int y, int height, int hotkey, FGameTexture* patch, FName child, int param = 0);
|
|
||||||
void Drawer(DListMenu* menu, const DVector2& origin, bool selected) override;
|
|
||||||
int GetWidth() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// list menu class runs a menu described by a FListMenuDescriptor
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
class DListMenu : public DMenu
|
|
||||||
{
|
|
||||||
typedef DMenu Super;
|
|
||||||
protected:
|
|
||||||
FListMenuDescriptor *mDesc = nullptr;
|
|
||||||
FListMenuItem *mFocusControl = nullptr;
|
|
||||||
|
|
||||||
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) override;
|
|
||||||
bool MenuEvent (int mkey, bool fromcontroller) override;
|
|
||||||
bool MouseEvent(int type, int x, int y) override;
|
|
||||||
void Ticker () override;
|
|
||||||
void Drawer () override;
|
|
||||||
void PreDraw() override;
|
|
||||||
virtual void SelectionChanged() {}
|
|
||||||
void SetFocus(FListMenuItem *fc)
|
|
||||||
{
|
|
||||||
mFocusControl = fc;
|
|
||||||
}
|
|
||||||
bool CheckFocus(FListMenuItem *fc)
|
|
||||||
{
|
|
||||||
return mFocusControl == fc;
|
|
||||||
}
|
|
||||||
void ReleaseFocus()
|
|
||||||
{
|
|
||||||
mFocusControl = NULL;
|
|
||||||
}
|
|
||||||
const FListMenuDescriptor* Descriptor() const
|
|
||||||
{
|
|
||||||
return mDesc;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// base class for menu items
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
class FOptionMenuItem : public FListMenuItem
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
FString mLabel;
|
|
||||||
bool mCentered = false;
|
|
||||||
|
|
||||||
void drawText(int x, int y, int color, const char * text, bool grayed = false);
|
|
||||||
|
|
||||||
int drawLabel(int indent, int y, EColorRange color, bool grayed = false);
|
|
||||||
void drawValue(int indent, int y, int color, const char *text, bool grayed = false);
|
|
||||||
|
|
||||||
int CursorSpace();
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
FOptionMenuItem(const char *text, FName action = NAME_None, bool center = false)
|
|
||||||
: FListMenuItem(0, 0, action)
|
|
||||||
{
|
|
||||||
mLabel = text;
|
|
||||||
mCentered = center;
|
|
||||||
}
|
|
||||||
|
|
||||||
~FOptionMenuItem();
|
|
||||||
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
|
|
||||||
{
|
|
||||||
using Super = DMenu;
|
|
||||||
bool CanScrollUp;
|
|
||||||
bool CanScrollDown;
|
|
||||||
int VisBottom;
|
|
||||||
FOptionMenuItem *mFocusControl;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
FOptionMenuDescriptor *mDesc;
|
|
||||||
|
|
||||||
int GetPosition();
|
|
||||||
|
|
||||||
public:
|
|
||||||
FOptionMenuItem *GetItem(FName name);
|
|
||||||
DOptionMenu(DMenu *parent = NULL, FOptionMenuDescriptor *desc = NULL);
|
|
||||||
virtual void Init(DMenu *parent = NULL, FOptionMenuDescriptor *desc = NULL);
|
|
||||||
int FirstSelectable();
|
|
||||||
bool Responder (event_t *ev);
|
|
||||||
bool MenuEvent (int mkey, bool fromcontroller);
|
|
||||||
bool MouseEvent(int type, int x, int y);
|
|
||||||
void Ticker ();
|
|
||||||
void Drawer ();
|
|
||||||
virtual int GetIndent();
|
|
||||||
const FOptionMenuDescriptor *GetDescriptor() const { return mDesc; }
|
|
||||||
void SetFocus(FOptionMenuItem *fc)
|
|
||||||
{
|
|
||||||
mFocusControl = fc;
|
|
||||||
}
|
|
||||||
bool CheckFocus(FOptionMenuItem *fc)
|
|
||||||
{
|
|
||||||
return mFocusControl == fc;
|
|
||||||
}
|
|
||||||
void ReleaseFocus()
|
|
||||||
{
|
|
||||||
mFocusControl = NULL;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
FFont *OptionFont();
|
|
||||||
int OptionHeight();
|
|
||||||
int OptionWidth(const char * s);
|
|
||||||
void DrawOptionText(int x, int y, int color, const char *text, bool grayed = false);
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// ImageScroller
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
class ImageScreen;
|
|
||||||
|
|
||||||
class DImageScrollerMenu : public DMenu
|
|
||||||
{
|
|
||||||
DMenu* mCurrent = nullptr;
|
|
||||||
FImageScrollerDescriptor* mDesc = nullptr;
|
|
||||||
int index = 0;
|
|
||||||
MenuTransition pageTransition = {};
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ImageScreen* newImageScreen(FImageScrollerDescriptor::ScrollerItem* desc);
|
|
||||||
|
|
||||||
public:
|
|
||||||
void Init(DMenu* parent = nullptr, FImageScrollerDescriptor* desc = nullptr);
|
|
||||||
bool MenuEvent(int mkey, bool fromcontroller);
|
|
||||||
bool MouseEvent(int type, int x, int y);
|
|
||||||
void Ticker();
|
|
||||||
void Drawer();
|
|
||||||
};
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// Input some text
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
class DTextEnterMenu : public DMenu
|
|
||||||
{
|
|
||||||
using Super = DMenu;
|
|
||||||
|
|
||||||
FString mEnterString;
|
|
||||||
int mEnterSize;
|
|
||||||
bool mInputGridOkay;
|
|
||||||
int InputGridX;
|
|
||||||
int InputGridY;
|
|
||||||
int CursorSize;
|
|
||||||
bool AllowColors;
|
|
||||||
FFont *displayFont;
|
|
||||||
|
|
||||||
|
|
||||||
void AppendChar(int ch);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// [TP] Added allowcolors
|
|
||||||
DTextEnterMenu(DMenu *parent, FFont *dpf, FString textbuffer, int maxlen, bool showgrid, bool allowcolors = false);
|
|
||||||
|
|
||||||
void Drawer ();
|
|
||||||
bool MenuEvent (int mkey, bool fromcontroller);
|
|
||||||
bool Responder(event_t *ev);
|
|
||||||
bool TranslateKeyboardEvents();
|
|
||||||
bool MouseEvent(int type, int x, int y);
|
|
||||||
const char* GetText() { return mEnterString.GetChars(); }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// Show a fullscreen image / centered text screen for an image scroller
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
class ImageScreen : public DMenu
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
const FImageScrollerDescriptor::ScrollerItem* mDesc;
|
|
||||||
public:
|
|
||||||
ImageScreen(const FImageScrollerDescriptor::ScrollerItem* it)
|
|
||||||
{
|
|
||||||
mDesc = it;
|
|
||||||
}
|
|
||||||
void Drawer() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct event_t;
|
|
||||||
void M_EnableMenu (bool on) ;
|
|
||||||
bool M_Responder (event_t *ev);
|
|
||||||
void M_Ticker (void);
|
|
||||||
void M_Drawer (void);
|
|
||||||
void M_PreviousMenu();
|
|
||||||
void M_Init (void);
|
|
||||||
void M_CreateMenus();
|
|
||||||
void M_ActivateMenu(DMenu *menu);
|
|
||||||
void M_ClearMenus (bool final = false);
|
|
||||||
void M_ParseMenuDefs();
|
|
||||||
void M_StartupSkillMenu(FNewGameStartup *gs);
|
|
||||||
int M_GetDefaultSkill();
|
|
||||||
void M_StartControlPanel (bool makeSound);
|
|
||||||
bool M_SetMenu(FName menu, int param = -1, FName callingMenu = NAME_None);
|
|
||||||
void M_NotifyNewSave (const char *file, const char *title, bool okForQuicksave);
|
|
||||||
void M_StartMessage(const char *message, int messagemode, int scriptId, FName action = NAME_None);
|
|
||||||
void M_UnhideCustomMenu(int menu, int itemmask);
|
|
||||||
void M_MenuSound(EMenuSounds snd);
|
|
||||||
void M_Autosave();
|
|
||||||
bool M_Active();
|
|
||||||
void M_DeinitMenus();
|
|
||||||
void M_UnpauseSound();
|
|
||||||
|
|
||||||
|
|
||||||
void I_SetMouseCapture();
|
|
||||||
void I_ReleaseMouseCapture();
|
|
||||||
|
|
||||||
struct MenuClassDescriptor;
|
|
||||||
extern TArray<MenuClassDescriptor*> menuClasses;
|
|
||||||
|
|
||||||
using hFunc = std::function<bool(bool)>;
|
|
||||||
DMenu* CreateMessageBoxMenu(DMenu* parent, const char* message, int messagemode, int scriptID, bool playsound, FName action = NAME_None, hFunc handler = nullptr);
|
|
||||||
|
|
||||||
|
|
||||||
struct MenuClassDescriptor
|
|
||||||
{
|
|
||||||
FName mName;
|
|
||||||
MenuClassDescriptor(const char* name) : mName(name)
|
|
||||||
{
|
|
||||||
//menuClasses.Push(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual DMenu* CreateNew() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class Menu> struct TMenuClassDescriptor : public MenuClassDescriptor
|
|
||||||
{
|
|
||||||
TMenuClassDescriptor(const char* name) : MenuClassDescriptor(name)
|
|
||||||
{}
|
|
||||||
DMenu* CreateNew()
|
|
||||||
{
|
|
||||||
return new Menu;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct FSavegameManager
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
TArray<FSaveGameNode*> SaveGames;
|
|
||||||
FSaveGameNode NewSaveNode;
|
|
||||||
int LastSaved = -1;
|
|
||||||
int LastAccessed = -1;
|
|
||||||
TArray<char> SavePicData;
|
|
||||||
FGameTexture *SavePic = nullptr;
|
|
||||||
|
|
||||||
public:
|
|
||||||
int WindowSize = 0;
|
|
||||||
FString SaveCommentString;
|
|
||||||
FSaveGameNode *quickSaveSlot = nullptr;
|
|
||||||
~FSavegameManager();
|
|
||||||
|
|
||||||
private:
|
|
||||||
int InsertSaveNode(FSaveGameNode *node);
|
|
||||||
public:
|
|
||||||
void NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave, bool forceQuicksave);
|
|
||||||
void ClearSaveGames();
|
|
||||||
|
|
||||||
void ReadSaveStrings();
|
|
||||||
void UnloadSaveData();
|
|
||||||
|
|
||||||
int RemoveSaveSlot(int index);
|
|
||||||
void LoadSavegame(int Selected);
|
|
||||||
void DoSave(int Selected, const char *savegamestring);
|
|
||||||
unsigned ExtractSaveData(int index);
|
|
||||||
void ClearSaveStuff();
|
|
||||||
bool DrawSavePic(int x, int y, int w, int h);
|
|
||||||
void DrawSaveComment(FFont *font, int cr, int x, int y, int scalefactor);
|
|
||||||
void SetFileInfo(int Selected);
|
|
||||||
unsigned SavegameCount();
|
|
||||||
FSaveGameNode *GetSavegame(int i);
|
|
||||||
void InsertNewSaveNode();
|
|
||||||
bool RemoveNewSaveNode();
|
|
||||||
|
|
||||||
void LoadGame(FSaveGameNode* node);
|
|
||||||
void SaveGame(FSaveGameNode* node, bool ok4q, bool forceq);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
extern FSavegameManager savegameManager;
|
|
||||||
extern DMenu* CurrentMenu;
|
|
||||||
|
|
||||||
bool M_IsAnimated();
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,374 +0,0 @@
|
||||||
/*
|
|
||||||
** 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.h"
|
|
||||||
#include "c_cvars.h"
|
|
||||||
#include "d_event.h"
|
|
||||||
#include "d_gui.h"
|
|
||||||
#include "v_font.h"
|
|
||||||
#include "v_text.h"
|
|
||||||
#include "v_draw.h"
|
|
||||||
#include "v_video.h"
|
|
||||||
|
|
||||||
#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)
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
// [TP] Added allowcolors
|
|
||||||
DTextEnterMenu::DTextEnterMenu(DMenu *parent, FFont *dpf, FString textbuffer, int maxlen, bool showgrid, bool allowcolors)
|
|
||||||
: DMenu(parent)
|
|
||||||
{
|
|
||||||
mEnterString = textbuffer;
|
|
||||||
mEnterSize = maxlen;
|
|
||||||
mInputGridOkay = (showgrid && (m_showinputgrid == 0)) || (m_showinputgrid >= 1);
|
|
||||||
if (mEnterString.Len() > 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;
|
|
||||||
}
|
|
||||||
AllowColors = allowcolors; // [TP]
|
|
||||||
displayFont = dpf;
|
|
||||||
CursorSize = displayFont->StringWidth(displayFont->GetCursor());
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
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;
|
|
||||||
AppendChar(ev->data1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
char ch = (char)ev->data1;
|
|
||||||
if ((ev->subtype == EV_GUI_KeyDown || ev->subtype == EV_GUI_KeyRepeat) && ch == '\b')
|
|
||||||
{
|
|
||||||
if (mEnterString.Len() > 0)
|
|
||||||
{
|
|
||||||
mEnterString.DeleteLastCharacter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ev->subtype == EV_GUI_KeyDown)
|
|
||||||
{
|
|
||||||
if (ch == GK_ESCAPE)
|
|
||||||
{
|
|
||||||
DMenu *parent = mParentMenu;
|
|
||||||
parent->MenuEvent(MKEY_Abort, false);
|
|
||||||
Close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (ch == '\r')
|
|
||||||
{
|
|
||||||
if (mEnterString.Len() > 0)
|
|
||||||
{
|
|
||||||
// [TP] If we allow color codes, colorize the string now.
|
|
||||||
//if (AllowColors)
|
|
||||||
//mEnterString = mEnterString.Filter();
|
|
||||||
|
|
||||||
DMenu *parent = mParentMenu;
|
|
||||||
parent->MenuEvent(MKEY_Input, false);
|
|
||||||
Close();
|
|
||||||
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_1;
|
|
||||||
const int cell_height = 16 * CleanYfac_1;
|
|
||||||
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))
|
|
||||||
{
|
|
||||||
//M_MenuSound(CursorSound);
|
|
||||||
if (m_use_mouse == 2) InputGridX = InputGridY = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
InputGridX = InputGridY = -1;
|
|
||||||
}
|
|
||||||
return Super::MouseEvent(type, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
void DTextEnterMenu::AppendChar(int ch)
|
|
||||||
{
|
|
||||||
FStringf newstring("%s%c%c", mEnterString.GetChars(), ch, displayFont->GetCursor());
|
|
||||||
if (mEnterSize < 0 || displayFont->StringWidth(newstring) < mEnterSize)
|
|
||||||
{
|
|
||||||
mEnterString.AppendCharacter(ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
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 (mEnterString.Len() > 0)
|
|
||||||
{
|
|
||||||
mEnterString.DeleteLastCharacter();
|
|
||||||
}
|
|
||||||
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.Len() > 0)
|
|
||||||
{
|
|
||||||
DMenu *parent = mParentMenu;
|
|
||||||
parent->MenuEvent(MKEY_Input, false);
|
|
||||||
Close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ch == '\b') // bs
|
|
||||||
{
|
|
||||||
if (mEnterString.Len() > 0)
|
|
||||||
{
|
|
||||||
mEnterString.DeleteLastCharacter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AppendChar(ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 - displayFont->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.
|
|
||||||
twod->AddColorOnlyQuad(0 /*screen->GetWidth()/2 - 13 * cell_width / 2*/,
|
|
||||||
screen->GetHeight() - INPUTGRID_HEIGHT * cell_height,
|
|
||||||
screen->GetWidth() /*13 * cell_width*/,
|
|
||||||
INPUTGRID_HEIGHT * cell_height, 0xc8000000);
|
|
||||||
|
|
||||||
if (InputGridX >= 0 && InputGridY >= 0)
|
|
||||||
{
|
|
||||||
// Highlight the background behind the selected character.
|
|
||||||
twod->AddColorOnlyQuad(
|
|
||||||
InputGridX * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen->GetWidth() / 2,
|
|
||||||
InputGridY * cell_height - INPUTGRID_HEIGHT * cell_height + screen->GetHeight(),
|
|
||||||
cell_width, cell_height, PalEntry(255, 255, 248, 220));
|
|
||||||
}
|
|
||||||
|
|
||||||
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];
|
|
||||||
auto pic = displayFont->GetChar(ch, CR_DARKGRAY, &width);
|
|
||||||
EColorRange color;
|
|
||||||
int remap;
|
|
||||||
|
|
||||||
// The highlighted character is yellow; the rest are dark gray.
|
|
||||||
color = (x == InputGridX && y == InputGridY) ? CR_YELLOW : CR_DARKGRAY;
|
|
||||||
remap = displayFont->GetColorTranslation(color);
|
|
||||||
|
|
||||||
if (pic != NULL)
|
|
||||||
{
|
|
||||||
// Draw a normal character.
|
|
||||||
DrawTexture(twod, pic, xx + cell_width/2 - width*CleanXfac_1/2, yy + top_padding,
|
|
||||||
DTA_TranslationIndex, remap,
|
|
||||||
DTA_CleanNoMove_1, 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_1 * 3 / 4;
|
|
||||||
const int x2 = x1 + width * 3 * CleanXfac_1 / 2;
|
|
||||||
const int y1 = yy + top_padding;
|
|
||||||
const int y2 = y1 + displayFont->GetHeight() * CleanYfac_1;
|
|
||||||
auto palcolor = PalEntry(255, 160, 160, 160);
|
|
||||||
twod->AddColorOnlyQuad(x1, y1, x2 - x1, CleanYfac_1, palcolor); // top
|
|
||||||
twod->AddColorOnlyQuad(x1, y2, x2 - x1, CleanYfac_1, palcolor); // bottom
|
|
||||||
twod->AddColorOnlyQuad(x1, y1+CleanYfac_1, CleanXfac_1, y2 - y1, palcolor); // left
|
|
||||||
twod->AddColorOnlyQuad(x2-CleanXfac_1, y1+CleanYfac_1, CleanXfac_1, CleanYfac_1, palcolor); // right
|
|
||||||
}
|
|
||||||
else if (ch == '\b' || ch == 0)
|
|
||||||
{
|
|
||||||
// Draw the backspace and end "characters".
|
|
||||||
const char *const str = ch == '\b' ? "BS" : "ED";
|
|
||||||
DrawText(twod, NewSmallFont, color,
|
|
||||||
xx + cell_width/2 - displayFont->StringWidth(str)*CleanXfac_1/2,
|
|
||||||
yy + top_padding, str, DTA_CleanNoMove_1, true, TAG_DONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Super::Drawer();
|
|
||||||
}
|
|
|
@ -1,468 +0,0 @@
|
||||||
/*
|
|
||||||
** 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.h"
|
|
||||||
#include "d_event.h"
|
|
||||||
#include "d_gui.h"
|
|
||||||
#include "v_text.h"
|
|
||||||
#include "v_draw.h"
|
|
||||||
#include "gstrings.h"
|
|
||||||
#include "c_dispatch.h"
|
|
||||||
#include "statistics.h"
|
|
||||||
#include "v_2ddrawer.h"
|
|
||||||
#include "v_video.h"
|
|
||||||
#include "i_time.h"
|
|
||||||
#include "engineerrors.h"
|
|
||||||
|
|
||||||
extern FSaveGameNode *quickSaveSlot;
|
|
||||||
|
|
||||||
|
|
||||||
void GameInterface::DrawCenteredTextScreen(const DVector2& origin, const char* text, int position, bool bg)
|
|
||||||
{
|
|
||||||
double scale = SmallFontScale();
|
|
||||||
int formatwidth = int(320 / scale);
|
|
||||||
auto lines = V_BreakLines(SmallFont, formatwidth, text, true);
|
|
||||||
auto fheight = bg? 10 : SmallFont->GetHeight()* scale; // Fixme: Get spacing for text pages from elsewhere.
|
|
||||||
if (!bg)
|
|
||||||
{
|
|
||||||
auto totaltextheight = lines.Size() * fheight;
|
|
||||||
position -= totaltextheight / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
double y = origin.Y + position;
|
|
||||||
for (auto& line : lines)
|
|
||||||
{
|
|
||||||
double x = origin.X + 160 - line.Width * scale * 0.5;
|
|
||||||
DrawText(twod, SmallFont, CR_UNTRANSLATED, x, y, line.Text, DTA_FullscreenScale, FSMode_Fit320x200, DTA_ScaleX, scale, DTA_ScaleY, scale, TAG_DONE);
|
|
||||||
y += fheight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DMessageBoxMenu : public DMenu
|
|
||||||
{
|
|
||||||
using Super = DMenu;
|
|
||||||
FString mFullMessage;
|
|
||||||
TArray<FBrokenLines> mMessage;
|
|
||||||
int mMessageMode;
|
|
||||||
int messageSelection;
|
|
||||||
int mMouseLeft, mMouseRight, mMouseY;
|
|
||||||
FName mAction;
|
|
||||||
std::function<bool(bool)> mActionFunc;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
DMessageBoxMenu(DMenu *parent = NULL, const char *message = NULL, int messagemode = 0, bool playsound = false, FName action = NAME_None, hFunc handler = nullptr);
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
DMessageBoxMenu::DMessageBoxMenu(DMenu *parent, const char *message, int messagemode, bool playsound, FName action, hFunc handler)
|
|
||||||
: DMenu(parent)
|
|
||||||
{
|
|
||||||
mAction = action;
|
|
||||||
mActionFunc = handler;
|
|
||||||
messageSelection = 0;
|
|
||||||
mMouseLeft = 140;
|
|
||||||
mMouseY = INT_MIN;
|
|
||||||
int mr1 = 170 + SmallFont->StringWidth(GStrings["TXT_YES"]);
|
|
||||||
int mr2 = 170 + SmallFont->StringWidth(GStrings["TXT_NO"]);
|
|
||||||
mMouseRight = std::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)
|
|
||||||
{
|
|
||||||
mFullMessage = message;
|
|
||||||
mMessage = V_BreakLines(SmallFont, 300, GStrings.localize(message));
|
|
||||||
}
|
|
||||||
mMessageMode = messagemode;
|
|
||||||
if (playsound)
|
|
||||||
{
|
|
||||||
//S_StopSound (CHAN_VOICE);
|
|
||||||
//S_Sound (CHAN_VOICE | CHANF_UI, "menu/prompt", snd_menuvolume, ATTN_NONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
void DMessageBoxMenu::Destroy()
|
|
||||||
{
|
|
||||||
mMessage.Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
void DMessageBoxMenu::CloseSound()
|
|
||||||
{
|
|
||||||
M_MenuSound(CurrentMenu ? BackSound : ::CloseSound);
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
void DMessageBoxMenu::HandleResult(bool res)
|
|
||||||
{
|
|
||||||
if (mMessageMode == 0)
|
|
||||||
{
|
|
||||||
if (mActionFunc)
|
|
||||||
{
|
|
||||||
if (mActionFunc(res)) Close();
|
|
||||||
}
|
|
||||||
else if (mAction == NAME_None && mParentMenu)
|
|
||||||
{
|
|
||||||
mParentMenu->MenuEvent(res ? MKEY_MBYes : MKEY_MBNo, false);
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
if (res) M_SetMenu(mAction, -1);
|
|
||||||
}
|
|
||||||
CloseSound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
CVAR(Bool, m_generic_messagebox, false, CVAR_ARCHIVE)
|
|
||||||
|
|
||||||
void DMessageBoxMenu::Drawer()
|
|
||||||
{
|
|
||||||
int y;
|
|
||||||
PalEntry fade = 0;
|
|
||||||
|
|
||||||
int fontheight = SmallFont->GetHeight();
|
|
||||||
//V_SetBorderNeedRefresh();
|
|
||||||
//ST_SetNeedRefresh();
|
|
||||||
|
|
||||||
y = 100;
|
|
||||||
|
|
||||||
if (m_generic_messagebox)
|
|
||||||
{
|
|
||||||
if (mMessage.Size())
|
|
||||||
{
|
|
||||||
for (unsigned i = 0; i < mMessage.Size(); i++)
|
|
||||||
y -= SmallFont->GetHeight() / 2;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < mMessage.Size(); i++)
|
|
||||||
{
|
|
||||||
DrawText(twod, 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;
|
|
||||||
DrawText(twod, SmallFont,
|
|
||||||
messageSelection == 0 ? OptionSettings.mFontColorSelection : OptionSettings.mFontColor,
|
|
||||||
160, y, GStrings["TXT_YES"], DTA_Clean, true, TAG_DONE);
|
|
||||||
DrawText(twod, SmallFont,
|
|
||||||
messageSelection == 1 ? OptionSettings.mFontColorSelection : OptionSettings.mFontColor,
|
|
||||||
160, y + fontheight + 1, GStrings["TXT_NO"], DTA_Clean, true, TAG_DONE);
|
|
||||||
|
|
||||||
if (messageSelection >= 0)
|
|
||||||
{
|
|
||||||
auto time = I_msTime() / 30;
|
|
||||||
if (((time >> 2) % 8) < 6)
|
|
||||||
{
|
|
||||||
DrawText(twod, SmallFont, OptionSettings.mFontColorSelection,
|
|
||||||
(150 - 160) * CleanXfac + screen->GetWidth() / 2,
|
|
||||||
(y + (fontheight + 1) * messageSelection - 100 + fontheight / 2 - 5) * CleanYfac + screen->GetHeight() / 2,
|
|
||||||
"\xd",
|
|
||||||
DTA_CellX, 8 * CleanXfac,
|
|
||||||
DTA_CellY, 8 * CleanYfac,
|
|
||||||
TAG_DONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
twod->ClearScreen(0xa0000000);
|
|
||||||
gi->DrawCenteredTextScreen(origin, mFullMessage, 100, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
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) && m_generic_messagebox)
|
|
||||||
{
|
|
||||||
//S_Sound (CHAN_VOICE | CHANF_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 || m_generic_messagebox)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
M_MenuSound(CursorSound);
|
|
||||||
}
|
|
||||||
messageSelection = sel;
|
|
||||||
if (type == MOUSE_Release)
|
|
||||||
{
|
|
||||||
return MenuEvent(MKEY_Enter, true);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
void M_StartMessage(const char *message, int messagemode, int scriptId, FName action)
|
|
||||||
{
|
|
||||||
if (CurrentMenu == NULL)
|
|
||||||
{
|
|
||||||
// only play a sound if no menu was active before
|
|
||||||
M_StartControlPanel(menuactive == MENU_Off);
|
|
||||||
}
|
|
||||||
DMenu *newmenu = new DMessageBoxMenu(CurrentMenu, message, messagemode, false, action);
|
|
||||||
newmenu->mParentMenu = CurrentMenu;
|
|
||||||
newmenu->scriptID = scriptId;
|
|
||||||
M_ActivateMenu(newmenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
DMenu* CreateMessageBoxMenu(DMenu* parent, const char* message, int messagemode, int scriptId, bool playsound, FName action, hFunc handler)
|
|
||||||
{
|
|
||||||
auto newmenu = new DMessageBoxMenu(CurrentMenu, message, messagemode, false, action, handler);
|
|
||||||
newmenu->scriptID = scriptId;
|
|
||||||
return newmenu;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ActivateEndGameMenu()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CCMD (menu_endgame)
|
|
||||||
{ // F7
|
|
||||||
if (!gi->CanSave())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
M_StartControlPanel (true);
|
|
||||||
FString tempstring;
|
|
||||||
tempstring << GStrings("ENDGAME") << "\n\n" << GStrings("PRESSYN");
|
|
||||||
DMenu* newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, 501, false, NAME_None, [](bool res)
|
|
||||||
{
|
|
||||||
if (res)
|
|
||||||
{
|
|
||||||
STAT_Cancel();
|
|
||||||
M_ClearMenus();
|
|
||||||
gi->QuitToTitle();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
M_ActivateMenu(newmenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
CCMD (menu_quit)
|
|
||||||
{ // F10
|
|
||||||
|
|
||||||
M_StartControlPanel (true);
|
|
||||||
|
|
||||||
FString EndString;
|
|
||||||
EndString << GStrings("CONFIRM_QUITMSG") << "\n\n" << GStrings("PRESSYN");
|
|
||||||
|
|
||||||
DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, EndString, 0, 500, false, NAME_None, [](bool res)
|
|
||||||
{
|
|
||||||
if (res) gi->ExitFromMenu();
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
M_ActivateMenu(newmenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,569 +0,0 @@
|
||||||
/*
|
|
||||||
** 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_font.h"
|
|
||||||
#include "cmdlib.h"
|
|
||||||
#include "gstrings.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.h"
|
|
||||||
#include "v_draw.h"
|
|
||||||
#include "v_2ddrawer.h"
|
|
||||||
#include "v_video.h"
|
|
||||||
#include "i_time.h"
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// Draws a string in the console font, scaled to the 8x8 cells
|
|
||||||
// used by the default console font.
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
FFont *OptionFont()
|
|
||||||
{
|
|
||||||
return NewSmallFont;
|
|
||||||
}
|
|
||||||
|
|
||||||
int OptionHeight()
|
|
||||||
{
|
|
||||||
return OptionFont()->GetHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
int OptionWidth(const char * s)
|
|
||||||
{
|
|
||||||
return OptionFont()->StringWidth(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DrawOptionText(int x, int y, int color, const char *text, bool grayed)
|
|
||||||
{
|
|
||||||
PalEntry overlay = grayed? PalEntry(96,48,0,0) : PalEntry(0,0,0);
|
|
||||||
DrawText (twod, OptionFont(), color, x, y, text, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay, TAG_END);
|
|
||||||
}
|
|
||||||
|
|
||||||
int DOptionMenu::GetPosition()
|
|
||||||
{
|
|
||||||
return mDesc->mPosition * screen->GetHeight() * 2 / CleanYfac_1 / 1080; // y position uses a 1920x1080 screen as reference but has to adjust to scaled 320x200 content.
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
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;
|
|
||||||
mDesc = desc;
|
|
||||||
if (mDesc != NULL && mDesc->mSelectedItem == -1) mDesc->mSelectedItem = FirstSelectable();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
int DOptionMenu::FirstSelectable()
|
|
||||||
{
|
|
||||||
if (mDesc != NULL)
|
|
||||||
{
|
|
||||||
// Go down to the first selectable item
|
|
||||||
int i = -1;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
while (i < (int)mDesc->mItems.Size() && !mDesc->mItems[i]->Selectable());
|
|
||||||
if (i>=0 && i < (int)mDesc->mItems.Size()) return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
int scrollamt = std::min(2, mDesc->mScrollPos);
|
|
||||||
mDesc->mScrollPos -= scrollamt;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (ev->subtype == EV_GUI_WheelDown)
|
|
||||||
{
|
|
||||||
if (CanScrollDown)
|
|
||||||
{
|
|
||||||
if (VisBottom < (int)(mDesc->mItems.Size()-2))
|
|
||||||
{
|
|
||||||
mDesc->mScrollPos += 2;
|
|
||||||
VisBottom += 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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:
|
|
||||||
if (mDesc->mSelectedItem == -1)
|
|
||||||
{
|
|
||||||
mDesc->mSelectedItem = FirstSelectable();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
|
||||||
--mDesc->mSelectedItem;
|
|
||||||
|
|
||||||
if (mDesc->mScrollPos > 0 &&
|
|
||||||
mDesc->mSelectedItem <= mDesc->mScrollTop + mDesc->mScrollPos)
|
|
||||||
{
|
|
||||||
mDesc->mScrollPos = std::max(mDesc->mSelectedItem - mDesc->mScrollTop - 1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mDesc->mSelectedItem < 0)
|
|
||||||
{
|
|
||||||
// Figure out how many lines of text fit on the menu
|
|
||||||
int y = GetPosition();
|
|
||||||
|
|
||||||
y *= CleanYfac_1;
|
|
||||||
int rowheight = OptionSettings.mLinespacing * CleanYfac_1;
|
|
||||||
int maxitems = (screen->GetHeight() - rowheight - y) / rowheight + 1;
|
|
||||||
|
|
||||||
mDesc->mScrollPos = std::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:
|
|
||||||
if (mDesc->mSelectedItem == -1)
|
|
||||||
{
|
|
||||||
mDesc->mSelectedItem = FirstSelectable();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
|
||||||
++mDesc->mSelectedItem;
|
|
||||||
|
|
||||||
if (CanScrollDown && mDesc->mSelectedItem == VisBottom)
|
|
||||||
{
|
|
||||||
mDesc->mScrollPos++;
|
|
||||||
VisBottom++;
|
|
||||||
}
|
|
||||||
if (mDesc->mSelectedItem >= (int)mDesc->mItems.Size())
|
|
||||||
{
|
|
||||||
if (startedAt == -1)
|
|
||||||
{
|
|
||||||
mDesc->mSelectedItem = -1;
|
|
||||||
mDesc->mScrollPos = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
if (mDesc->mSelectedItem != -1)
|
|
||||||
{
|
|
||||||
mDesc->mSelectedItem = mDesc->mScrollTop + mDesc->mScrollPos + 1;
|
|
||||||
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable())
|
|
||||||
{
|
|
||||||
if (++mDesc->mSelectedItem >= (int)mDesc->mItems.Size())
|
|
||||||
{
|
|
||||||
mDesc->mSelectedItem = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mDesc->mScrollPos > mDesc->mSelectedItem)
|
|
||||||
{
|
|
||||||
mDesc->mScrollPos = 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;
|
|
||||||
}
|
|
||||||
if (mDesc->mSelectedItem != -1)
|
|
||||||
{
|
|
||||||
mDesc->mSelectedItem = mDesc->mScrollTop + mDesc->mScrollPos;
|
|
||||||
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable())
|
|
||||||
{
|
|
||||||
if (++mDesc->mSelectedItem >= (int)mDesc->mItems.Size())
|
|
||||||
{
|
|
||||||
mDesc->mSelectedItem = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mDesc->mScrollPos > mDesc->mSelectedItem)
|
|
||||||
{
|
|
||||||
mDesc->mScrollPos = mDesc->mSelectedItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MKEY_Enter:
|
|
||||||
if (mDesc->mSelectedItem >= 0 && mDesc->mItems[mDesc->mSelectedItem]->Activate(mDesc->mMenuName))
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
M_MenuSound(CursorSound);
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
//M_MenuSound(CursorSound); too noisy
|
|
||||||
|
|
||||||
}
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
int DOptionMenu::GetIndent()
|
|
||||||
{
|
|
||||||
int indent = std::max(0, (mDesc->mIndent + 40) - CleanWidth_1 / 2);
|
|
||||||
return screen->GetWidth() / 2 + indent * CleanXfac_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DOptionMenu::Drawer ()
|
|
||||||
{
|
|
||||||
int y = GetPosition();
|
|
||||||
|
|
||||||
if (mDesc->mTitle.IsNotEmpty())
|
|
||||||
{
|
|
||||||
gi->DrawMenuCaption(origin, GStrings.localize(mDesc->mTitle));
|
|
||||||
}
|
|
||||||
mDesc->mDrawTop = y;
|
|
||||||
int fontheight = OptionSettings.mLinespacing * CleanYfac_1;
|
|
||||||
y *= CleanYfac_1;
|
|
||||||
|
|
||||||
int indent = GetIndent();
|
|
||||||
|
|
||||||
int ytop = y + mDesc->mScrollTop * 8 * CleanYfac_1;
|
|
||||||
int lastrow = screen->GetHeight() - OptionFont()->GetHeight() * CleanYfac_1;
|
|
||||||
|
|
||||||
unsigned i;
|
|
||||||
for (i = 0; i < mDesc->mItems.Size() && y <= lastrow; i++, y += fontheight)
|
|
||||||
{
|
|
||||||
// Don't scroll the uppermost items
|
|
||||||
if ((int)i == mDesc->mScrollTop)
|
|
||||||
{
|
|
||||||
i += mDesc->mScrollPos;
|
|
||||||
if (i >= mDesc->mItems.Size()) break; // skipped beyond end of menu
|
|
||||||
}
|
|
||||||
bool isSelected = mDesc->mSelectedItem == (int)i;
|
|
||||||
int cur_indent = mDesc->mItems[i]->Draw(mDesc, y, indent, isSelected);
|
|
||||||
if (cur_indent >= 0 && isSelected && mDesc->mItems[i]->Selectable())
|
|
||||||
{
|
|
||||||
auto time = I_msTime() / 30;
|
|
||||||
if ((((time>>2)%8) < 6) || CurrentMenu != this)
|
|
||||||
{
|
|
||||||
DrawOptionText(cur_indent + 3 * CleanXfac_1, y, OptionSettings.mFontColorSelection, "◄");
|
|
||||||
//M_DrawConText(OptionSettings.mFontColorSelection, cur_indent + 3 * CleanXfac_1, y+fontheight-9*CleanYfac_1, "\xd");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CanScrollUp = (mDesc->mScrollPos > 0);
|
|
||||||
CanScrollDown = (i < mDesc->mItems.Size());
|
|
||||||
VisBottom = i - 1;
|
|
||||||
|
|
||||||
if (CanScrollUp)
|
|
||||||
{
|
|
||||||
DrawOptionText(screen->GetWidth() - 11 * CleanXfac_1, ytop, OptionSettings.mFontColorSelection, "▲");
|
|
||||||
//M_DrawConText(CR_ORANGE, 3 * CleanXfac_1, ytop, "\x1a");
|
|
||||||
}
|
|
||||||
if (CanScrollDown)
|
|
||||||
{
|
|
||||||
DrawOptionText(screen->GetWidth() - 11 * CleanXfac_1 , y - 8*CleanYfac_1, OptionSettings.mFontColorSelection, "▼");
|
|
||||||
//M_DrawConText(CR_ORANGE, 3 * CleanXfac_1, y - 8*CleanYfac_1, "\x1b");
|
|
||||||
}
|
|
||||||
Super::Drawer();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//
|
|
||||||
// base class for menu items
|
|
||||||
//
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
FOptionMenuItem::~FOptionMenuItem()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
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 CurrentMenu->MenuEvent(MKEY_Enter, true);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int FOptionMenuItem::GetIndent()
|
|
||||||
{
|
|
||||||
if (mCentered) return 0;
|
|
||||||
if (screen->GetWidth() < 640) return screen->GetWidth() / 2;
|
|
||||||
return OptionWidth(GStrings.localize(mLabel));
|
|
||||||
}
|
|
||||||
|
|
||||||
void FOptionMenuItem::drawText(int x, int y, int color, const char * text, bool grayed)
|
|
||||||
{
|
|
||||||
DrawOptionText(x, y, color, text, grayed);
|
|
||||||
}
|
|
||||||
|
|
||||||
int FOptionMenuItem::drawLabel(int indent, int y, EColorRange color, bool grayed)
|
|
||||||
{
|
|
||||||
const char *label = GStrings.localize(mLabel);
|
|
||||||
int x;
|
|
||||||
int w = OptionWidth(label) * CleanXfac_1;
|
|
||||||
if (!mCentered) x = indent - w;
|
|
||||||
else x = (screen->GetWidth() - w) / 2;
|
|
||||||
DrawOptionText(x, y, color, label, grayed);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FOptionMenuItem::drawValue(int indent, int y, int color, const char *text, bool grayed)
|
|
||||||
{
|
|
||||||
DrawOptionText(indent + CursorSpace(), y, color, text, grayed);
|
|
||||||
}
|
|
||||||
|
|
||||||
int FOptionMenuItem::CursorSpace()
|
|
||||||
{
|
|
||||||
return (14 * CleanXfac_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 PlayerMenu : public DOptionMenu
|
|
||||||
{
|
|
||||||
using Super = DOptionMenu;
|
|
||||||
|
|
||||||
public:
|
|
||||||
void Drawer()
|
|
||||||
{
|
|
||||||
// Hack: The team item is #3. This part doesn't work properly yet.
|
|
||||||
gi->DrawPlayerSprite(origin, (mDesc->mSelectedItem == 3));
|
|
||||||
Super::Drawer();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static TMenuClassDescriptor<PlayerMenu> _ppm("NewPlayerMenu");
|
|
||||||
|
|
||||||
void RegisterOptionMenus()
|
|
||||||
{
|
|
||||||
menuClasses.Push(&_ppm);
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
725
source/core/menu/razemenu.cpp
Normal file
725
source/core/menu/razemenu.cpp
Normal file
|
@ -0,0 +1,725 @@
|
||||||
|
/*
|
||||||
|
** 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 "c_dispatch.h"
|
||||||
|
#include "d_gui.h"
|
||||||
|
#include "c_buttons.h"
|
||||||
|
#include "c_console.h"
|
||||||
|
#include "c_bind.h"
|
||||||
|
#include "d_eventbase.h"
|
||||||
|
#include "g_input.h"
|
||||||
|
#include "configfile.h"
|
||||||
|
#include "gstrings.h"
|
||||||
|
#include "menu.h"
|
||||||
|
#include "vm.h"
|
||||||
|
#include "v_video.h"
|
||||||
|
#include "i_system.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "texturemanager.h"
|
||||||
|
#include "v_draw.h"
|
||||||
|
#include "vm.h"
|
||||||
|
#include "gamestate.h"
|
||||||
|
#include "i_interface.h"
|
||||||
|
#include "d_event.h"
|
||||||
|
#include "st_start.h"
|
||||||
|
#include "i_system.h"
|
||||||
|
#include "gameconfigfile.h"
|
||||||
|
#include "gamecontrol.h"
|
||||||
|
#include "raze_sound.h"
|
||||||
|
#include "gamestruct.h"
|
||||||
|
#include "razemenu.h"
|
||||||
|
#include "mapinfo.h"
|
||||||
|
#include "statistics.h"
|
||||||
|
#include "i_net.h"
|
||||||
|
#include "savegamehelp.h"
|
||||||
|
#include "gi.h"
|
||||||
|
|
||||||
|
EXTERN_CVAR(Int, cl_gfxlocalization)
|
||||||
|
EXTERN_CVAR(Bool, m_quickexit)
|
||||||
|
EXTERN_CVAR(Bool, saveloadconfirmation) // [mxd]
|
||||||
|
EXTERN_CVAR(Bool, quicksaverotation)
|
||||||
|
EXTERN_CVAR(Bool, show_messages)
|
||||||
|
CVAR(Bool, menu_sounds, true, CVAR_ARCHIVE) // added mainly because RR's sounds are so supremely annoying.
|
||||||
|
|
||||||
|
typedef void(*hfunc)();
|
||||||
|
DMenu* CreateMessageBoxMenu(DMenu* parent, const char* message, int messagemode, bool playsound, FName action = NAME_None, hfunc handler = nullptr);
|
||||||
|
bool OkForLocalization(FTextureID texnum, const char* substitute);
|
||||||
|
void D_ToggleHud();
|
||||||
|
void I_WaitVBL(int count);
|
||||||
|
|
||||||
|
extern bool hud_toggled;
|
||||||
|
bool help_disabled;
|
||||||
|
FNewGameStartup NewGameStartupInfo;
|
||||||
|
|
||||||
|
|
||||||
|
//FNewGameStartup NewGameStartupInfo;
|
||||||
|
|
||||||
|
|
||||||
|
bool M_SetSpecialMenu(FName& menu, int param)
|
||||||
|
{
|
||||||
|
// Engine credits need a different approach to work with the option search
|
||||||
|
#if 0
|
||||||
|
// Transitions between the engine credits pages need to pop off the last slide
|
||||||
|
if (!strnicmp(menu.GetChars(), "EngineCredits", 13) && CurrentMenu && !strnicmp(CurrentMenu->GetClass()->TypeName.GetChars(), "EngineCredits", 13))
|
||||||
|
{
|
||||||
|
auto m = CurrentMenu;
|
||||||
|
CurrentMenu = m->mParentMenu;
|
||||||
|
m->mParentMenu = nullptr;
|
||||||
|
m->Destroy();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (menu.GetIndex())
|
||||||
|
{
|
||||||
|
case NAME_Mainmenu:
|
||||||
|
if (gi->CanSave()) menu = NAME_IngameMenu;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NAME_Skillmenu:
|
||||||
|
// sent from the episode menu
|
||||||
|
NewGameStartupInfo.Episode = param;
|
||||||
|
NewGameStartupInfo.Level = 0;
|
||||||
|
NewGameStartupInfo.Skill = gDefaultSkill;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case NAME_Startgame:
|
||||||
|
case NAME_StartgameNoSkill:
|
||||||
|
menu = NAME_Startgame;
|
||||||
|
NewGameStartupInfo.Skill = param;
|
||||||
|
if (menu == NAME_StartgameNoSkill) NewGameStartupInfo.Episode = param;
|
||||||
|
if (gi->StartGame(NewGameStartupInfo))
|
||||||
|
{
|
||||||
|
M_ClearMenus();
|
||||||
|
STAT_StartNewGame(gVolumeNames[NewGameStartupInfo.Episode], NewGameStartupInfo.Skill);
|
||||||
|
inputState.ClearAllInput();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case NAME_CustomSubMenu1:
|
||||||
|
menu = ENamedName(menu.GetIndex() + param);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NAME_Savegamemenu:
|
||||||
|
if (!gi->CanSave())
|
||||||
|
{
|
||||||
|
// cannot save outside the game.
|
||||||
|
M_StartMessage(GStrings("SAVEDEAD"), 1, NAME_None);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NAME_Quitmenu:
|
||||||
|
// This is no separate class
|
||||||
|
C_DoCommand("menu_quit");
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case NAME_EndGameMenu:
|
||||||
|
// This is no separate class
|
||||||
|
C_DoCommand("menu_endgame");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// End of special checks
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
void M_StartControlPanel(bool makeSound, bool)
|
||||||
|
{
|
||||||
|
static bool created = false;
|
||||||
|
// intro might call this repeatedly
|
||||||
|
if (CurrentMenu != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!created) // Cannot do this earlier.
|
||||||
|
{
|
||||||
|
created = true;
|
||||||
|
M_CreateMenus();
|
||||||
|
}
|
||||||
|
GSnd->SetSfxPaused(true, PAUSESFX_MENU);
|
||||||
|
gi->MenuOpened();
|
||||||
|
if (makeSound && menu_sounds) gi->MenuSound(ActivateSound);
|
||||||
|
M_DoStartControlPanel(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void System_MenuClosed()
|
||||||
|
{
|
||||||
|
GSnd->SetSfxPaused(false, PAUSESFX_MENU);
|
||||||
|
inputState.ClearAllInput();
|
||||||
|
gi->MenuClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void System_MenuDim()
|
||||||
|
{
|
||||||
|
if (gamestate != GS_MENUSCREEN) // With GS_MENUSCREEN we can assume that the background has been tuned for proper menu display already.
|
||||||
|
{
|
||||||
|
Dim(twod, 0, 0.5f, 0, 0, screen->GetWidth(), screen->GetHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
CCMD(menu_quit)
|
||||||
|
{ // F10
|
||||||
|
|
||||||
|
M_StartControlPanel(true);
|
||||||
|
|
||||||
|
FString EndString;
|
||||||
|
EndString << GStrings("CONFIRM_QUITMSG") << "\n\n" << GStrings("PRESSYN");
|
||||||
|
|
||||||
|
DMenu* newmenu = CreateMessageBoxMenu(CurrentMenu, EndString, 0, false, NAME_None, []()
|
||||||
|
{
|
||||||
|
gi->ExitFromMenu();
|
||||||
|
});
|
||||||
|
|
||||||
|
M_ActivateMenu(newmenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
CCMD(menu_endgame)
|
||||||
|
{ // F7
|
||||||
|
if (!gi->CanSave())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
M_StartControlPanel(true);
|
||||||
|
FString tempstring;
|
||||||
|
tempstring << GStrings("ENDGAME") << "\n\n" << GStrings("PRESSYN");
|
||||||
|
DMenu* newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []()
|
||||||
|
{
|
||||||
|
STAT_Cancel();
|
||||||
|
M_ClearMenus();
|
||||||
|
gi->QuitToTitle();
|
||||||
|
});
|
||||||
|
|
||||||
|
M_ActivateMenu(newmenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
CCMD(quicksave)
|
||||||
|
{ // F6
|
||||||
|
if (!gi->CanSave()) return;
|
||||||
|
|
||||||
|
if (savegameManager.quickSaveSlot == NULL || savegameManager.quickSaveSlot == (FSaveGameNode*)1)
|
||||||
|
{
|
||||||
|
M_StartControlPanel(true);
|
||||||
|
M_SetMenu(NAME_Savegamemenu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto slot = savegameManager.quickSaveSlot;
|
||||||
|
|
||||||
|
// [mxd]. Just save the game, no questions asked.
|
||||||
|
if (!saveloadconfirmation)
|
||||||
|
{
|
||||||
|
G_SaveGame(savegameManager.quickSaveSlot->Filename, savegameManager.quickSaveSlot->SaveTitle, true, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FString tempstring = GStrings("QSPROMPT");
|
||||||
|
tempstring.Substitute("%s", slot->SaveTitle.GetChars());
|
||||||
|
M_StartControlPanel(true);
|
||||||
|
|
||||||
|
DMenu* newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []()
|
||||||
|
{
|
||||||
|
G_SaveGame(savegameManager.quickSaveSlot->Filename, savegameManager.quickSaveSlot->SaveTitle, true, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
M_ActivateMenu(newmenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
CCMD(quickload)
|
||||||
|
{ // F9
|
||||||
|
if (netgame)
|
||||||
|
{
|
||||||
|
M_StartControlPanel(true);
|
||||||
|
M_StartMessage(GStrings("QLOADNET"), 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (savegameManager.quickSaveSlot == nullptr || savegameManager.quickSaveSlot == (FSaveGameNode*)1)
|
||||||
|
{
|
||||||
|
M_StartControlPanel(true);
|
||||||
|
// signal that whatever gets loaded should be the new quicksave
|
||||||
|
savegameManager.quickSaveSlot = (FSaveGameNode*)1;
|
||||||
|
M_SetMenu(NAME_Loadgamemenu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [mxd]. Just load the game, no questions asked.
|
||||||
|
if (!saveloadconfirmation)
|
||||||
|
{
|
||||||
|
G_LoadGame(savegameManager.quickSaveSlot->Filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FString tempstring = GStrings("QLPROMPT");
|
||||||
|
tempstring.Substitute("%s", savegameManager.quickSaveSlot->SaveTitle.GetChars());
|
||||||
|
|
||||||
|
M_StartControlPanel(true);
|
||||||
|
|
||||||
|
DMenu* newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []()
|
||||||
|
{
|
||||||
|
G_LoadGame(savegameManager.quickSaveSlot->Filename);
|
||||||
|
});
|
||||||
|
M_ActivateMenu(newmenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// Creation wrapper
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
static DMenuItemBase* CreateCustomListMenuItemText(double x, double y, int height, int hotkey, const char* text, FFont* font, PalEntry color1, PalEntry color2, FName command, int param)
|
||||||
|
{
|
||||||
|
const char* classname =
|
||||||
|
(g_gameType & GAMEFLAG_BLOOD) ? "ListMenuItemBloodTextItem" :
|
||||||
|
(g_gameType & GAMEFLAG_SW) ? "ListMenuItemSWTextItem" :
|
||||||
|
(g_gameType & GAMEFLAG_PSEXHUMED) ? "ListMenuItemExhumedTextItem" : "ListMenuItemDukeTextItem";
|
||||||
|
auto c = PClass::FindClass(classname);
|
||||||
|
auto p = c->CreateNew();
|
||||||
|
FString keystr = FString(char(hotkey));
|
||||||
|
FString textstr = text;
|
||||||
|
VMValue params[] = { p, x, y, height, &keystr, &textstr, font, int(color1.d), int(color2.d), command.GetIndex(), param };
|
||||||
|
auto f = dyn_cast<PFunction>(c->FindSymbol("InitDirect", false));
|
||||||
|
VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
|
||||||
|
return (DMenuItemBase*)p;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// Creates the episode menu
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
static void BuildEpisodeMenu()
|
||||||
|
{
|
||||||
|
// Build episode menu
|
||||||
|
int addedVolumes = 0;
|
||||||
|
DMenuDescriptor** desc = MenuDescriptors.CheckKey(NAME_Episodemenu);
|
||||||
|
if (desc != nullptr && (*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor)))
|
||||||
|
{
|
||||||
|
DListMenuDescriptor* ld = static_cast<DListMenuDescriptor*>(*desc);
|
||||||
|
|
||||||
|
DMenuItemBase* popped = nullptr;
|
||||||
|
if (ld->mItems.Size() && ld->mItems.Last()->IsKindOf(NAME_ListMenuItemBloodDripDrawer))
|
||||||
|
{
|
||||||
|
ld->mItems.Pop(popped);
|
||||||
|
}
|
||||||
|
|
||||||
|
ld->mSelectedItem = gDefaultVolume + ld->mItems.Size(); // account for pre-added items
|
||||||
|
int y = ld->mYpos;
|
||||||
|
|
||||||
|
for (int i = 0; i < MAXVOLUMES; i++)
|
||||||
|
{
|
||||||
|
if (gVolumeNames[i].IsNotEmpty() && !(gVolumeFlags[i] & EF_HIDEFROMSP))
|
||||||
|
|
||||||
|
{
|
||||||
|
int isShareware = ((g_gameType & GAMEFLAG_DUKE) && (g_gameType & GAMEFLAG_SHAREWARE) && i > 0);
|
||||||
|
auto it = CreateCustomListMenuItemText(ld->mXpos, y, ld->mLinespacing, gVolumeNames[i][0],
|
||||||
|
gVolumeNames[i], ld->mFont, 0, isShareware, NAME_Skillmenu, i); // font colors are not used, so hijack one for the shareware flag.
|
||||||
|
|
||||||
|
y += ld->mLinespacing;
|
||||||
|
ld->mItems.Push(it);
|
||||||
|
addedVolumes++;
|
||||||
|
if (gVolumeSubtitles[i].IsNotEmpty())
|
||||||
|
{
|
||||||
|
auto it = CreateListMenuItemStaticText(ld->mXpos, y, gVolumeSubtitles[i], SmallFont, CR_GRAY, false);
|
||||||
|
y += ld->mLinespacing * 6 / 10;
|
||||||
|
ld->mItems.Push(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if 0 // this needs to be backed by a working selection menu, until that gets done it must be disabled.
|
||||||
|
if (!(g_gameType & GAMEFLAG_SHAREWARE))
|
||||||
|
{
|
||||||
|
//auto it = new FListMenuItemNativeStaticText(ld->mXpos, "", NIT_SmallFont); // empty entry as spacer.
|
||||||
|
//ld->mItems.Push(it);
|
||||||
|
|
||||||
|
y += ld->mLinespacing / 3;
|
||||||
|
auto it = CreateCustomListMenuItemText(ld->mXpos, y, ld->mLinespacing, 'U', "$MNU_USERMAP", ld->mFont, 0, 0, NAME_UsermapMenu);
|
||||||
|
ld->mItems.Push(it);
|
||||||
|
addedVolumes++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (addedVolumes == 1)
|
||||||
|
{
|
||||||
|
ld->mAutoselect = 0;
|
||||||
|
}
|
||||||
|
if (popped) ld->mItems.Push(popped);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build skill menu
|
||||||
|
int addedSkills = 0;
|
||||||
|
desc = MenuDescriptors.CheckKey(NAME_Skillmenu);
|
||||||
|
if (desc != nullptr && (*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor)))
|
||||||
|
{
|
||||||
|
DListMenuDescriptor* ld = static_cast<DListMenuDescriptor*>(*desc);
|
||||||
|
DMenuItemBase* popped = nullptr;
|
||||||
|
if (ld->mItems.Size() && ld->mItems.Last()->IsKindOf(NAME_ListMenuItemBloodDripDrawer))
|
||||||
|
{
|
||||||
|
ld->mItems.Pop(popped);
|
||||||
|
}
|
||||||
|
|
||||||
|
ld->mSelectedItem = gDefaultVolume + ld->mItems.Size(); // account for pre-added items
|
||||||
|
int y = ld->mYpos;
|
||||||
|
|
||||||
|
for (int i = 0; i < MAXSKILLS; i++)
|
||||||
|
{
|
||||||
|
if (gSkillNames[i].IsNotEmpty())
|
||||||
|
{
|
||||||
|
auto it = CreateCustomListMenuItemText(ld->mXpos, y, ld->mLinespacing, gSkillNames[i][0], gSkillNames[i], ld->mFont, 0, 0, NAME_Startgame, i);
|
||||||
|
y += ld->mLinespacing;
|
||||||
|
ld->mItems.Push(it);
|
||||||
|
addedSkills++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (addedSkills == 0)
|
||||||
|
{
|
||||||
|
// Need to add one item with the default skill so that the menu does not break.
|
||||||
|
auto it = CreateCustomListMenuItemText(ld->mXpos, y, ld->mLinespacing, 0, "", ld->mFont, 0, 0, NAME_Startgame, gDefaultSkill);
|
||||||
|
ld->mItems.Push(it);
|
||||||
|
}
|
||||||
|
if (addedSkills == 1)
|
||||||
|
{
|
||||||
|
ld->mAutoselect = 0;
|
||||||
|
}
|
||||||
|
if (popped) ld->mItems.Push(popped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// Reads any XHAIRS lumps for the names of crosshairs and
|
||||||
|
// adds them to the display options menu.
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
static void InitCrosshairsList()
|
||||||
|
{
|
||||||
|
int lastlump, lump;
|
||||||
|
|
||||||
|
lastlump = 0;
|
||||||
|
|
||||||
|
FOptionValues **opt = OptionValues.CheckKey(NAME_Crosshairs);
|
||||||
|
if (opt == nullptr)
|
||||||
|
{
|
||||||
|
return; // no crosshair value list present. No need to go on.
|
||||||
|
}
|
||||||
|
|
||||||
|
FOptionValues::Pair *pair = &(*opt)->mValues[(*opt)->mValues.Reserve(1)];
|
||||||
|
pair->Value = 0;
|
||||||
|
pair->Text = "None";
|
||||||
|
|
||||||
|
while ((lump = fileSystem.FindLump("XHAIRS", &lastlump)) != -1)
|
||||||
|
{
|
||||||
|
FScanner sc(lump);
|
||||||
|
while (sc.GetNumber())
|
||||||
|
{
|
||||||
|
FOptionValues::Pair value;
|
||||||
|
value.Value = sc.Number;
|
||||||
|
sc.MustGetString();
|
||||||
|
value.Text = sc.String;
|
||||||
|
if (value.Value != 0)
|
||||||
|
{ // Check if it already exists. If not, add it.
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 1; i < (*opt)->mValues.Size(); ++i)
|
||||||
|
{
|
||||||
|
if ((*opt)->mValues[i].Value == value.Value)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i < (*opt)->mValues.Size())
|
||||||
|
{
|
||||||
|
(*opt)->mValues[i].Text = value.Text;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*opt)->mValues.Push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Defines how graphics substitution is handled.
|
||||||
|
// 0: Never replace a text-containing graphic with a font-based text.
|
||||||
|
// 1: Always replace, regardless of any missing information. Useful for testing the substitution without providing full data.
|
||||||
|
// 2: Only replace for non-default texts, i.e. if some language redefines the string's content, use it instead of the graphic. Never replace a localized graphic.
|
||||||
|
// 3: Only replace if the string is not the default and the graphic comes from the IWAD. Never replace a localized graphic.
|
||||||
|
// 4: Like 1, but lets localized graphics pass.
|
||||||
|
//
|
||||||
|
// The default is 3, which only replaces known content with non-default texts.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
bool CheckSkipGameOptionBlock(FScanner& sc) { return false; } // not applicable
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
CUSTOM_CVAR(Int, cl_gfxlocalization, 3, CVAR_ARCHIVE)
|
||||||
|
{
|
||||||
|
if (self < 0 || self > 4) self = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OkForLocalization(FTextureID texnum, const char* substitute)
|
||||||
|
{
|
||||||
|
if (!texnum.isValid()) return false;
|
||||||
|
|
||||||
|
// First the unconditional settings, 0='never' and 1='always'.
|
||||||
|
if (cl_gfxlocalization == 1 || gameinfo.forcetextinmenus) return false;
|
||||||
|
if (cl_gfxlocalization == 0 || gameinfo.forcenogfxsubstitution) return true;
|
||||||
|
return TexMan.OkForLocalization(texnum, substitute, cl_gfxlocalization);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
void SetDefaultMenuColors()
|
||||||
|
{
|
||||||
|
PClass* cls = nullptr;
|
||||||
|
//OptionSettings.mTitleColor = CR_RED;// V_FindFontColor(gameinfo.mTitleColor);
|
||||||
|
OptionSettings.mFontColor = CR_RED;
|
||||||
|
OptionSettings.mFontColorValue = CR_GRAY;
|
||||||
|
OptionSettings.mFontColorMore = CR_GRAY;
|
||||||
|
OptionSettings.mFontColorHeader = CR_GOLD;
|
||||||
|
OptionSettings.mFontColorHighlight = CR_YELLOW;
|
||||||
|
OptionSettings.mFontColorSelection = CR_BRICK;
|
||||||
|
gameinfo.mSliderColor = "Orange";
|
||||||
|
|
||||||
|
if (g_gameType & GAMEFLAG_BLOOD)
|
||||||
|
{
|
||||||
|
OptionSettings.mFontColorHeader = CR_DARKGRAY;
|
||||||
|
OptionSettings.mFontColorHighlight = CR_WHITE;
|
||||||
|
OptionSettings.mFontColorSelection = CR_DARKRED;
|
||||||
|
gameinfo.mSliderColor = "Red";
|
||||||
|
cls = PClass::FindClass("BloodMenuDelegate");
|
||||||
|
}
|
||||||
|
else if (g_gameType & GAMEFLAG_SW)
|
||||||
|
{
|
||||||
|
OptionSettings.mFontColorHeader = CR_DARKRED;
|
||||||
|
OptionSettings.mFontColorHighlight = CR_WHITE;
|
||||||
|
gameinfo.mSliderColor = "Red";
|
||||||
|
cls = PClass::FindClass("SWMenuDelegate");
|
||||||
|
}
|
||||||
|
else if (g_gameType & GAMEFLAG_PSEXHUMED)
|
||||||
|
{
|
||||||
|
OptionSettings.mFontColorHeader = CR_LIGHTBLUE;
|
||||||
|
OptionSettings.mFontColorHighlight = CR_SAPPHIRE;
|
||||||
|
OptionSettings.mFontColorSelection = CR_ORANGE;
|
||||||
|
OptionSettings.mFontColor = CR_FIRE;
|
||||||
|
gameinfo.mSliderColor = "Yellow";
|
||||||
|
cls = PClass::FindClass("ExhumedMenuDelegate");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (g_gameType & (GAMEFLAG_NAM | GAMEFLAG_NAPALM | GAMEFLAG_WW2GI))
|
||||||
|
{
|
||||||
|
OptionSettings.mFontColor = CR_DARKGREEN;
|
||||||
|
OptionSettings.mFontColorHeader = CR_DARKGRAY;
|
||||||
|
OptionSettings.mFontColorHighlight = CR_WHITE;
|
||||||
|
OptionSettings.mFontColorSelection = CR_DARKGREEN;
|
||||||
|
gameinfo.mSliderColor = "Green";
|
||||||
|
}
|
||||||
|
else if (g_gameType & GAMEFLAG_RRALL)
|
||||||
|
{
|
||||||
|
OptionSettings.mFontColor = CR_BROWN;
|
||||||
|
OptionSettings.mFontColorHeader = CR_DARKBROWN;
|
||||||
|
OptionSettings.mFontColorHighlight = CR_ORANGE;
|
||||||
|
OptionSettings.mFontColorSelection = CR_TAN;
|
||||||
|
gameinfo.mSliderColor = "Tan";
|
||||||
|
}
|
||||||
|
cls = PClass::FindClass("DukeMenuDelegate");
|
||||||
|
}
|
||||||
|
if (!cls) cls = PClass::FindClass("RazeMenuDelegate");
|
||||||
|
if (cls) menuDelegate = cls->CreateNew();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildGameMenus()
|
||||||
|
{
|
||||||
|
BuildEpisodeMenu();
|
||||||
|
InitCrosshairsList();
|
||||||
|
UpdateJoystickMenu(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// [RH] Most menus can now be accessed directly
|
||||||
|
// through console commands.
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
EXTERN_CVAR(Int, screenblocks)
|
||||||
|
|
||||||
|
CCMD(reset2defaults)
|
||||||
|
{
|
||||||
|
C_SetDefaultBindings();
|
||||||
|
C_SetCVarsToDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
CCMD(reset2saved)
|
||||||
|
{
|
||||||
|
GameConfig->DoGlobalSetup();
|
||||||
|
GameConfig->DoGameSetup(currentGame);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCMD(menu_main)
|
||||||
|
{
|
||||||
|
M_StartControlPanel(true);
|
||||||
|
M_SetMenu(NAME_Mainmenu, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCMD(openhelpmenu)
|
||||||
|
{
|
||||||
|
if (!help_disabled)
|
||||||
|
{
|
||||||
|
M_StartControlPanel(true);
|
||||||
|
M_SetMenu(NAME_HelpMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CCMD(opensavemenu)
|
||||||
|
{
|
||||||
|
if (gi->CanSave())
|
||||||
|
{
|
||||||
|
M_StartControlPanel(true);
|
||||||
|
M_SetMenu(NAME_Savegamemenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CCMD(openloadmenu)
|
||||||
|
{
|
||||||
|
M_StartControlPanel(true);
|
||||||
|
M_SetMenu(NAME_Loadgamemenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The sound system is not yet capable of resolving this properly.
|
||||||
|
DEFINE_ACTION_FUNCTION(_RazeMenuDelegate, PlaySound)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(void);
|
||||||
|
PARAM_NAME(name);
|
||||||
|
EMenuSounds soundindex;
|
||||||
|
|
||||||
|
switch (name.GetIndex())
|
||||||
|
{
|
||||||
|
case NAME_menu_cursor:
|
||||||
|
soundindex = CursorSound;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NAME_menu_choose:
|
||||||
|
soundindex = ChooseSound;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NAME_menu_backup:
|
||||||
|
soundindex = BackSound;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NAME_menu_clear:
|
||||||
|
case NAME_menu_dismiss:
|
||||||
|
soundindex = CloseSound;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NAME_menu_change:
|
||||||
|
soundindex = ChangeSound;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NAME_menu_advance:
|
||||||
|
soundindex = AdvanceSound;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
gi->MenuSound(soundindex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// C_ToggleConsole cannot be exported for security reasons as it can be used to make the engine unresponsive.
|
||||||
|
DEFINE_ACTION_FUNCTION(_RazeMenuDelegate, MenuDismissed)
|
||||||
|
{
|
||||||
|
if (CurrentMenu == nullptr && gamestate == GS_MENUSCREEN) C_ToggleConsole();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(_PlayerMenu, DrawPlayerSprite)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_INT(selected);
|
||||||
|
gi->DrawPlayerSprite(DVector2(0.,0.), selected);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
41
source/core/menu/razemenu.h
Normal file
41
source/core/menu/razemenu.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#pragma once
|
||||||
|
#include "menu.h"
|
||||||
|
#include "gamestruct.h"
|
||||||
|
#include "c_cvars.h"
|
||||||
|
#include "savegamemanager.h"
|
||||||
|
|
||||||
|
extern bool help_disabled;
|
||||||
|
|
||||||
|
void M_StartControlPanel (bool makeSound, bool scaleoverride = false);
|
||||||
|
|
||||||
|
|
||||||
|
extern FNewGameStartup NewGameStartupInfo;
|
||||||
|
void M_StartupEpisodeMenu(FNewGameStartup *gs);
|
||||||
|
void M_StartupSkillMenu(FNewGameStartup *gs);
|
||||||
|
void SetDefaultMenuColors();
|
||||||
|
void BuildGameMenus();
|
||||||
|
|
||||||
|
class FSavegameManager : public FSavegameManagerBase
|
||||||
|
{
|
||||||
|
void PerformSaveGame(const char *fn, const char *sgdesc) override;
|
||||||
|
void PerformLoadGame(const char *fn, bool) override;
|
||||||
|
FString ExtractSaveComment(FSerializer &arc) override;
|
||||||
|
FString BuildSaveName(const char* prefix, int slot) override;
|
||||||
|
void ReadSaveStrings() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern FSavegameManager savegameManager;
|
||||||
|
|
||||||
|
enum EMenuSounds : int
|
||||||
|
{
|
||||||
|
ActivateSound,
|
||||||
|
CursorSound,
|
||||||
|
AdvanceSound,
|
||||||
|
BackSound,
|
||||||
|
CloseSound,
|
||||||
|
PageSound,
|
||||||
|
ChangeSound,
|
||||||
|
ChooseSound
|
||||||
|
};
|
||||||
|
|
||||||
|
EXTERN_CVAR(Bool, menu_sounds)
|
|
@ -17,7 +17,7 @@
|
||||||
#define BEGIN_SW_NS namespace ShadowWarrior {
|
#define BEGIN_SW_NS namespace ShadowWarrior {
|
||||||
#define END_SW_NS }
|
#define END_SW_NS }
|
||||||
|
|
||||||
#define BEGIN_PS_NS namespace Powerslave {
|
#define BEGIN_PS_NS namespace Exhumed {
|
||||||
#define END_PS_NS }
|
#define END_PS_NS }
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -53,12 +53,15 @@
|
||||||
#include "gamestruct.h"
|
#include "gamestruct.h"
|
||||||
#include "automap.h"
|
#include "automap.h"
|
||||||
#include "statusbar.h"
|
#include "statusbar.h"
|
||||||
|
#include "gamestate.h"
|
||||||
|
#include "razemenu.h"
|
||||||
|
|
||||||
static CompositeSavegameWriter savewriter;
|
static CompositeSavegameWriter savewriter;
|
||||||
static FResourceFile *savereader;
|
static FResourceFile *savereader;
|
||||||
void LoadEngineState();
|
void LoadEngineState();
|
||||||
void SaveEngineState();
|
void SaveEngineState();
|
||||||
void WriteSavePic(FileWriter* file, int width, int height);
|
void WriteSavePic(FileWriter* file, int width, int height);
|
||||||
|
extern FString BackupSaveGame;
|
||||||
|
|
||||||
CVAR(String, cl_savedir, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR(String, cl_savedir, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
|
|
||||||
|
@ -564,3 +567,129 @@ void LoadEngineState()
|
||||||
fr.Close();
|
fr.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
CVAR(Bool, saveloadconfirmation, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||||
|
|
||||||
|
CVAR(Int, autosavenum, 0, CVAR_NOSET | CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||||
|
static int nextautosave = -1;
|
||||||
|
CVAR(Int, disableautosave, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||||
|
CUSTOM_CVAR(Int, autosavecount, 4, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||||
|
{
|
||||||
|
if (self < 1)
|
||||||
|
self = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CVAR(Int, quicksavenum, 0, CVAR_NOSET | CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||||
|
static int nextquicksave = -1;
|
||||||
|
CUSTOM_CVAR(Int, quicksavecount, 4, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||||
|
{
|
||||||
|
if (self < 1)
|
||||||
|
self = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoLoadGame(const char* name)
|
||||||
|
{
|
||||||
|
if (OpenSaveGameForRead(name))
|
||||||
|
{
|
||||||
|
if (gi->LoadGame())
|
||||||
|
{
|
||||||
|
gameaction = ga_level;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
I_Error("%s: Failed to load savegame", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
I_Error("%s: Failed to open savegame", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void G_LoadGame(const char *filename)
|
||||||
|
{
|
||||||
|
inputState.ClearAllInput();
|
||||||
|
gi->FreeLevelData();
|
||||||
|
DoLoadGame(filename);
|
||||||
|
BackupSaveGame = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
void G_SaveGame(const char *fn, const char *desc, bool ok4q, bool forceq)
|
||||||
|
{
|
||||||
|
if (OpenSaveGameForWrite(fn, desc))
|
||||||
|
{
|
||||||
|
if (gi->SaveGame() && FinishSavegameWrite())
|
||||||
|
{
|
||||||
|
savegameManager.NotifyNewSave(fn, desc, ok4q, forceq);
|
||||||
|
Printf(PRINT_NOTIFY, "%s\n", GStrings("GAME SAVED"));
|
||||||
|
BackupSaveGame = fn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void M_Autosave()
|
||||||
|
{
|
||||||
|
if (disableautosave) return;
|
||||||
|
if (!gi->CanSave()) return;
|
||||||
|
FString description;
|
||||||
|
FString file;
|
||||||
|
// Keep a rotating sets of autosaves
|
||||||
|
UCVarValue num;
|
||||||
|
const char* readableTime;
|
||||||
|
int count = autosavecount != 0 ? autosavecount : 1;
|
||||||
|
|
||||||
|
if (nextautosave == -1)
|
||||||
|
{
|
||||||
|
nextautosave = (autosavenum + 1) % count;
|
||||||
|
}
|
||||||
|
|
||||||
|
num.Int = nextautosave;
|
||||||
|
autosavenum.ForceSet(num, CVAR_Int);
|
||||||
|
|
||||||
|
auto Filename = G_BuildSaveName(FStringf("auto%04d", nextautosave));
|
||||||
|
readableTime = myasctime();
|
||||||
|
FStringf SaveTitle("Autosave %s", readableTime);
|
||||||
|
nextautosave = (nextautosave + 1) % count;
|
||||||
|
G_SaveGame(Filename, SaveTitle, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCMD(autosave)
|
||||||
|
{
|
||||||
|
gameaction = ga_autosave;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCMD(rotatingquicksave)
|
||||||
|
{
|
||||||
|
if (!gi->CanSave()) return;
|
||||||
|
FString description;
|
||||||
|
FString file;
|
||||||
|
// Keep a rotating sets of quicksaves
|
||||||
|
UCVarValue num;
|
||||||
|
const char* readableTime;
|
||||||
|
int count = quicksavecount != 0 ? quicksavecount : 1;
|
||||||
|
|
||||||
|
if (nextquicksave == -1)
|
||||||
|
{
|
||||||
|
nextquicksave = (quicksavenum + 1) % count;
|
||||||
|
}
|
||||||
|
|
||||||
|
num.Int = nextquicksave;
|
||||||
|
quicksavenum.ForceSet(num, CVAR_Int);
|
||||||
|
|
||||||
|
FSaveGameNode sg;
|
||||||
|
auto Filename = G_BuildSaveName(FStringf("quick%04d", nextquicksave));
|
||||||
|
readableTime = myasctime();
|
||||||
|
FStringf SaveTitle("Quicksave %s", readableTime);
|
||||||
|
nextquicksave = (nextquicksave + 1) % count;
|
||||||
|
G_SaveGame(Filename, SaveTitle, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,12 @@ class FileReader;
|
||||||
FString G_BuildSaveName (const char *prefix);
|
FString G_BuildSaveName (const char *prefix);
|
||||||
int G_ValidateSavegame(FileReader &fr, FString *savetitle, bool formenu);
|
int G_ValidateSavegame(FileReader &fr, FString *savetitle, bool formenu);
|
||||||
|
|
||||||
|
void G_LoadGame(const char* filename);
|
||||||
|
void G_SaveGame(const char* fn, const char* desc, bool ok4q, bool forceq);
|
||||||
|
|
||||||
void SaveEngineState();
|
void SaveEngineState();
|
||||||
void LoadEngineState();
|
void LoadEngineState();
|
||||||
|
void M_Autosave();
|
||||||
|
|
||||||
#define SAVEGAME_EXT ".dsave"
|
#define SAVEGAME_EXT ".dsave"
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
#include "s_soundinternal.h"
|
#include "s_soundinternal.h"
|
||||||
#include "animtexture.h"
|
#include "animtexture.h"
|
||||||
#include "gamestate.h"
|
#include "gamestate.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "raze_sound.h"
|
#include "raze_sound.h"
|
||||||
#include "SmackerDecoder.h"
|
#include "SmackerDecoder.h"
|
||||||
#include "movie/playmve.h"
|
#include "movie/playmve.h"
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
#include "m_fixed.h"
|
#include "m_fixed.h"
|
||||||
#include "gamecontrol.h"
|
#include "gamecontrol.h"
|
||||||
#include "gamestruct.h"
|
#include "gamestruct.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
#include "mapinfo.h"
|
#include "mapinfo.h"
|
||||||
|
|
||||||
#include "../version.h"
|
#include "../version.h"
|
||||||
|
|
|
@ -619,6 +619,9 @@ int tileImportFromTexture(const char* fn, int tilenum, int alphacut, int istextu
|
||||||
if (xsiz <= 0 || ysiz <= 0)
|
if (xsiz <= 0 || ysiz <= 0)
|
||||||
return -2;
|
return -2;
|
||||||
|
|
||||||
|
// create a new game texture here - we want to give it a new name!
|
||||||
|
tex = MakeGameTexture(tex->GetTexture(), FStringf("#%05d", tilenum), ETextureType::Override);
|
||||||
|
TexMan.AddGameTexture(tex);
|
||||||
TileFiles.tiledata[tilenum].backup = TileFiles.tiledata[tilenum].texture = tex;
|
TileFiles.tiledata[tilenum].backup = TileFiles.tiledata[tilenum].texture = tex;
|
||||||
if (istexture)
|
if (istexture)
|
||||||
tileSetHightileReplacement(tilenum, 0, fn, (float)(255 - alphacut) * (1.f / 255.f), 1.0f, 1.0f, 1.0, 1.0, 0);
|
tileSetHightileReplacement(tilenum, 0, fn, (float)(255 - alphacut) * (1.f / 255.f), 1.0f, 1.0f, 1.0, 1.0, 0);
|
||||||
|
@ -1028,6 +1031,27 @@ bool tileEqualTo(int me, int other)
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
|
void tileUpdateAnimations()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAXTILES; i++)
|
||||||
|
{
|
||||||
|
if (picanm[i].sf & PICANM_ANIMTYPE_MASK)
|
||||||
|
{
|
||||||
|
int j = i + animateoffs(i, 0);
|
||||||
|
|
||||||
|
auto id1 = TileFiles.tiledata[i].texture->GetID();
|
||||||
|
auto id2 = TileFiles.tiledata[j].texture->GetID();
|
||||||
|
TexMan.SetTranslation(id1, id2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// Picks a texture for rendering for a given tilenum/palette combination
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
|
||||||
bool PickTexture(int picnum, FGameTexture* tex, int paletteid, TexturePick& pick)
|
bool PickTexture(int picnum, FGameTexture* tex, int paletteid, TexturePick& pick)
|
||||||
{
|
{
|
||||||
|
@ -1194,3 +1218,22 @@ void processSetAnim(const char* cmd, FScriptPosition& pos, SetAnim& imp)
|
||||||
|
|
||||||
TileSiz tilesiz;
|
TileSiz tilesiz;
|
||||||
PicAnm picanm;
|
PicAnm picanm;
|
||||||
|
|
||||||
|
#if 0 // this only gets in if unavoidable. It'd be preferable if the script side can solely operate on texture names.
|
||||||
|
#include "vm.h"
|
||||||
|
|
||||||
|
static int GetTexture(int tile, int anim)
|
||||||
|
{
|
||||||
|
if (tile < 0 || tile >= MAXTILES) return 0;
|
||||||
|
auto tex = tileGetTexture(tile, anim);
|
||||||
|
return tex ? tex->GetID().GetIndex() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION_NATIVE(_TileFiles, GetTexture, GetTexture)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_INT(tile);
|
||||||
|
PARAM_BOOL(animate);
|
||||||
|
ACTION_RETURN_INT(GetTexture(tile, animate));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -523,6 +523,7 @@ inline FGameTexture* tileGetTexture(int tile, bool animate = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tileEqualTo(int me, int other);
|
bool tileEqualTo(int me, int other);
|
||||||
|
void tileUpdateAnimations();
|
||||||
|
|
||||||
bool PickTexture(int picnum, FGameTexture* tex, int paletteid, TexturePick& pick);
|
bool PickTexture(int picnum, FGameTexture* tex, int paletteid, TexturePick& pick);
|
||||||
|
|
||||||
|
|
|
@ -30,106 +30,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "gamestate.h"
|
#include "gamestate.h"
|
||||||
#include "mapinfo.h"
|
#include "mapinfo.h"
|
||||||
#include "gamecontrol.h"
|
#include "gamecontrol.h"
|
||||||
|
#include "v_draw.h"
|
||||||
|
#include "vm.h"
|
||||||
#include "menu/menu.h" // to override the local menu.h
|
#include "razemenu.h"
|
||||||
|
|
||||||
#include "../../glbackend/glbackend.h"
|
#include "../../glbackend/glbackend.h"
|
||||||
|
|
||||||
|
|
||||||
BEGIN_PS_NS
|
BEGIN_PS_NS
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Implements the native looking menu used for the main menu
|
|
||||||
// and the episode/skill selection screens, i.e. the parts
|
|
||||||
// that need to look authentic
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void menu_DoPlasma();
|
|
||||||
double zoomsize = 0;
|
|
||||||
|
|
||||||
class PSMainMenu : public DListMenu
|
|
||||||
{
|
|
||||||
|
|
||||||
void Init(DMenu* parent, FListMenuDescriptor* desc) override
|
|
||||||
{
|
|
||||||
DListMenu::Init(parent, desc);
|
|
||||||
PlayLocalSound(StaticSound[kSound31], 0, false, CHANF_UI);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Ticker() override
|
|
||||||
{
|
|
||||||
// handle the menu zoom-in
|
|
||||||
if (zoomsize < 1.)
|
|
||||||
{
|
|
||||||
zoomsize += 0.0625;
|
|
||||||
if (zoomsize >= 1.) {
|
|
||||||
zoomsize = 1.;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PreDraw() override
|
|
||||||
{
|
|
||||||
if (mDesc->mMenuName == NAME_Mainmenu)
|
|
||||||
menu_DoPlasma();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto nLogoTile = EXHUMED ? kExhumedLogo : kPowerslaveLogo;
|
|
||||||
DrawRel(nLogoTile, 160, 40);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Menu related game interface functions
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void GameInterface::DrawNativeMenuText(int fontnum, int state, double xpos, double ypos, float fontscale, const char* text, int flags)
|
|
||||||
{
|
|
||||||
int tilenum = (int)strtoll(text, nullptr, 0);
|
|
||||||
double y = ypos - tilesiz[tilenum].y / 2;
|
|
||||||
|
|
||||||
int8_t shade;
|
|
||||||
|
|
||||||
if (state == NIT_SelectedState)
|
|
||||||
{ // currently selected menu item
|
|
||||||
shade = Sin(I_GetBuildTime() << 4) >> 9;
|
|
||||||
}
|
|
||||||
else if (state == NIT_ActiveState) {
|
|
||||||
shade = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
shade = 25;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Todo: Replace the boxes with an empty one and draw the text with a font.
|
|
||||||
auto tex = tileGetTexture(tilenum);
|
|
||||||
|
|
||||||
DrawTexture(twod, tex, 160, y + tex->GetDisplayHeight(), DTA_FullscreenScale, FSMode_Fit320x200, DTA_CenterOffset, true, DTA_ScaleX, zoomsize, DTA_ScaleY, zoomsize,
|
|
||||||
DTA_Color, shadeToLight(shade), TAG_DONE);
|
|
||||||
|
|
||||||
// tilesizx is 51
|
|
||||||
// tilesizy is 33
|
|
||||||
|
|
||||||
if (state == NIT_SelectedState)
|
|
||||||
{
|
|
||||||
tex = tileGetTexture(kMenuCursorTile);
|
|
||||||
DrawTexture(twod, tex, 62, ypos - 12, DTA_FullscreenScale, FSMode_Fit320x200, DTA_TopLeft, true, TAG_DONE);
|
|
||||||
DrawTexture(twod, tex, 207, ypos - 12, DTA_FullscreenScale, FSMode_Fit320x200, DTA_TopLeft, true, DTA_FlipX, true, TAG_DONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void GameInterface::MenuOpened()
|
void GameInterface::MenuOpened()
|
||||||
{
|
{
|
||||||
GrabPalette();
|
GrabPalette();
|
||||||
zoomsize = 0;
|
menuDelegate->FloatVar(NAME_zoomsize) = 0;
|
||||||
StopAllSounds();
|
|
||||||
StopLocalSound();
|
StopLocalSound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,17 +50,21 @@ void GameInterface::MenuSound(EMenuSounds snd)
|
||||||
{
|
{
|
||||||
switch (snd)
|
switch (snd)
|
||||||
{
|
{
|
||||||
case CursorSound:
|
case ActivateSound:
|
||||||
PlayLocalSound(StaticSound[kSound35], 0, false, CHANF_UI);
|
PlayLocalSound(StaticSound[kSound31], 0, false, CHANF_UI);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AdvanceSound:
|
case CursorSound:
|
||||||
case BackSound:
|
PlayLocalSound(StaticSound[kSound35], 0, false, CHANF_UI);
|
||||||
PlayLocalSound(StaticSound[kSound33], 0, false, CHANF_UI);
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
case AdvanceSound:
|
||||||
return;
|
case BackSound:
|
||||||
|
PlayLocalSound(StaticSound[kSound33], 0, false, CHANF_UI);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,16 +73,10 @@ void GameInterface::QuitToTitle()
|
||||||
gameaction = ga_mainmenu;
|
gameaction = ga_mainmenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameInterface::MenuClosed()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool GameInterface::StartGame(FNewGameStartup& gs)
|
bool GameInterface::StartGame(FNewGameStartup& gs)
|
||||||
{
|
{
|
||||||
auto map = FindMapByLevelNum(gs.Episode);
|
auto map = FindMapByLevelNum(gs.Skill); // 0 is training, 1 is the regular game - the game does not have skill levels.
|
||||||
DeferedStartGame(map, gs.Skill); // 0 is training, 1 is the regular game - the game does not have skill levels.
|
DeferedStartGame(map, 1, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,26 +85,22 @@ FSavegameInfo GameInterface::GetSaveSig()
|
||||||
return { SAVESIG_PS, MINSAVEVER_PS, SAVEVER_PS };
|
return { SAVESIG_PS, MINSAVEVER_PS, SAVEVER_PS };
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameInterface::DrawMenuCaption(const DVector2& origin, const char* text)
|
|
||||||
{
|
|
||||||
// Fixme: should use the extracted font from the menu items (i.e. BigFont) and a stretched box for the menu items.
|
|
||||||
DrawText(twod, SmallFont, CR_UNTRANSLATED, 160 - SmallFont->StringWidth(text)/2, 10, text, DTA_FullscreenScale, FSMode_Fit320x200Top, TAG_DONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
END_PS_NS
|
END_PS_NS
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
using namespace Exhumed;
|
||||||
//
|
|
||||||
// Class registration
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(_ListMenuItemExhumedPlasma, Draw)
|
||||||
static TMenuClassDescriptor<Powerslave::PSMainMenu> _mm("Exhumed.MainMenu");
|
|
||||||
|
|
||||||
void RegisterPSMenus()
|
|
||||||
{
|
{
|
||||||
menuClasses.Push(&_mm);
|
menu_DoPlasma();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(_ListMenuItemExhumedLogo, Draw)
|
||||||
|
{
|
||||||
|
auto nLogoTile = EXHUMED ? kExhumedLogo : kPowerslaveLogo;
|
||||||
|
DrawRel(nLogoTile, 160, 40);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "cheathandler.h"
|
#include "cheathandler.h"
|
||||||
#include "inputstate.h"
|
#include "inputstate.h"
|
||||||
#include "d_protocol.h"
|
#include "d_protocol.h"
|
||||||
#include "core/menu/menu.h"
|
#include "texturemanager.h"
|
||||||
|
#include "razemenu.h"
|
||||||
|
|
||||||
BEGIN_PS_NS
|
BEGIN_PS_NS
|
||||||
|
|
||||||
|
@ -475,13 +476,26 @@ void ExitGame()
|
||||||
throw CExitEvent(0);
|
throw CExitEvent(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define x(a, b) registerName(#a, b);
|
||||||
|
static void SetTileNames()
|
||||||
|
{
|
||||||
|
auto registerName = [](const char* name, int index)
|
||||||
|
{
|
||||||
|
TexMan.AddAlias(name, tileGetTexture(index));
|
||||||
|
};
|
||||||
|
#include "namelist.h"
|
||||||
|
}
|
||||||
|
#undef x
|
||||||
|
|
||||||
void GameInterface::app_init()
|
void GameInterface::app_init()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
//int esi = 1;
|
//int esi = 1;
|
||||||
//int edi = esi;
|
//int edi = esi;
|
||||||
|
|
||||||
|
#if 0
|
||||||
help_disabled = true;
|
help_disabled = true;
|
||||||
|
#endif
|
||||||
// Create the global level table. Parts of the engine need it, even though the game itself does not.
|
// Create the global level table. Parts of the engine need it, even though the game itself does not.
|
||||||
for (int i = 0; i <= 32; i++)
|
for (int i = 0; i <= 32; i++)
|
||||||
{
|
{
|
||||||
|
@ -507,6 +521,7 @@ void GameInterface::app_init()
|
||||||
// temp - moving InstallEngine(); before FadeOut as we use nextpage() in FadeOut
|
// temp - moving InstallEngine(); before FadeOut as we use nextpage() in FadeOut
|
||||||
InstallEngine();
|
InstallEngine();
|
||||||
LoadDefinitions();
|
LoadDefinitions();
|
||||||
|
SetTileNames();
|
||||||
|
|
||||||
TileFiles.SetBackup();
|
TileFiles.SetBackup();
|
||||||
|
|
||||||
|
|
|
@ -237,15 +237,12 @@ struct GameInterface : ::GameInterface
|
||||||
void app_init() override;
|
void app_init() override;
|
||||||
void clearlocalinputstate() override;
|
void clearlocalinputstate() override;
|
||||||
bool GenerateSavePic() override;
|
bool GenerateSavePic() override;
|
||||||
void DrawNativeMenuText(int fontnum, int state, double xpos, double ypos, float fontscale, const char* text, int flags) override;
|
|
||||||
void MenuOpened() override;
|
void MenuOpened() override;
|
||||||
void MenuSound(EMenuSounds snd) override;
|
void MenuSound(EMenuSounds snd) override;
|
||||||
void MenuClosed() override;
|
|
||||||
bool StartGame(FNewGameStartup& gs) override;
|
bool StartGame(FNewGameStartup& gs) override;
|
||||||
FSavegameInfo GetSaveSig() override;
|
FSavegameInfo GetSaveSig() override;
|
||||||
void DrawMenuCaption(const DVector2& origin, const char* text) override;
|
bool LoadGame() override;
|
||||||
bool LoadGame(FSaveGameNode* sv) override;
|
bool SaveGame() override;
|
||||||
bool SaveGame(FSaveGameNode* sv) override;
|
|
||||||
bool CanSave() override;
|
bool CanSave() override;
|
||||||
ReservedSpace GetReservedScreenSpace(int viewsize) override { return { 0, 24 }; }
|
ReservedSpace GetReservedScreenSpace(int viewsize) override { return { 0, 24 }; }
|
||||||
void QuitToTitle() override;
|
void QuitToTitle() override;
|
||||||
|
|
|
@ -44,10 +44,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "cheathandler.h"
|
#include "cheathandler.h"
|
||||||
#include "statistics.h"
|
#include "statistics.h"
|
||||||
#include "g_input.h"
|
#include "g_input.h"
|
||||||
#include "core/menu/menu.h"
|
#include "razemenu.h"
|
||||||
#include "d_net.h"
|
#include "d_net.h"
|
||||||
#include "automap.h"
|
#include "automap.h"
|
||||||
#include "raze_music.h"
|
#include "raze_music.h"
|
||||||
|
#include "v_draw.h"
|
||||||
|
|
||||||
BEGIN_PS_NS
|
BEGIN_PS_NS
|
||||||
|
|
||||||
|
@ -137,7 +138,7 @@ static void Intermission(MapRecord *from_map, MapRecord *to_map)
|
||||||
{
|
{
|
||||||
TArray<JobDesc> jobs;
|
TArray<JobDesc> jobs;
|
||||||
|
|
||||||
StopAllSounds();
|
if (from_map) StopAllSounds();
|
||||||
bCamera = false;
|
bCamera = false;
|
||||||
automapMode = am_off;
|
automapMode = am_off;
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "status.h"
|
#include "status.h"
|
||||||
#include "view.h"
|
#include "view.h"
|
||||||
#include "menu.h"
|
#include "razemenu.h"
|
||||||
|
|
||||||
BEGIN_PS_NS
|
BEGIN_PS_NS
|
||||||
|
|
||||||
|
|
30
source/exhumed/src/namelist.h
Normal file
30
source/exhumed/src/namelist.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
x(PowerslaveLogo, 3442)
|
||||||
|
x(MenuNewGameTile, 3460)
|
||||||
|
x(MenuLoadGameTile, 3461)
|
||||||
|
x(MenuMusicTile, 3465)
|
||||||
|
x(MenuSoundFxTile, 3466)
|
||||||
|
x(MenuCursorTile, 3468)
|
||||||
|
x(MenuBlank, 3469)
|
||||||
|
x(SkullHead, 3582)
|
||||||
|
x(ExhumedLogo, 3592)
|
||||||
|
x(Energy1, 3604)
|
||||||
|
x(Energy2, 3605)
|
||||||
|
x(ClockSymbol1, 3606)
|
||||||
|
x(ClockSymbol2, 3607)
|
||||||
|
x(ClockSymbol3, 3608)
|
||||||
|
x(ClockSymbol4, 3609)
|
||||||
|
x(ClockSymbol5, 3610)
|
||||||
|
x(ClockSymbol6, 3611)
|
||||||
|
x(ClockSymbol7, 3612)
|
||||||
|
x(ClockSymbol8, 3613)
|
||||||
|
x(ClockSymbol9, 3614)
|
||||||
|
x(ClockSymbol10, 3615)
|
||||||
|
x(ClockSymbol11, 3616)
|
||||||
|
x(ClockSymbol12, 3617)
|
||||||
|
x(ClockSymbol13, 3618)
|
||||||
|
x(ClockSymbol14, 3619)
|
||||||
|
x(ClockSymbol15, 3620)
|
||||||
|
x(ClockSymbol16, 3621)
|
||||||
|
x(TileLoboLaptop, 3623)
|
||||||
|
x(TileBMGLogo, 3368)
|
||||||
|
x(TilePIELogo, 3349)
|
|
@ -3368,7 +3368,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#define kTile3346 3346
|
#define kTile3346 3346
|
||||||
#define kTile3347 3347
|
#define kTile3347 3347
|
||||||
#define kTile3348 3348
|
#define kTile3348 3348
|
||||||
#define kTilePIELogo 3349
|
|
||||||
#define kTile3350 3350
|
#define kTile3350 3350
|
||||||
#define kTile3351 3351
|
#define kTile3351 3351
|
||||||
#define kTile3352 3352
|
#define kTile3352 3352
|
||||||
|
@ -3387,7 +3386,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#define kTile3365 3365 // sky
|
#define kTile3365 3365 // sky
|
||||||
#define kTile3366 3366 // sky
|
#define kTile3366 3366 // sky
|
||||||
#define kTile3367 3367 // sky
|
#define kTile3367 3367 // sky
|
||||||
#define kTileBMGLogo 3368
|
|
||||||
#define kTile3369 3369
|
#define kTile3369 3369
|
||||||
#define kTile3370 3370
|
#define kTile3370 3370
|
||||||
#define kTile3371 3371
|
#define kTile3371 3371
|
||||||
|
@ -3461,7 +3459,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#define kTile3439 3439
|
#define kTile3439 3439
|
||||||
#define kTile3440 3440
|
#define kTile3440 3440
|
||||||
#define kTile3441 3441
|
#define kTile3441 3441
|
||||||
#define kPowerslaveLogo 3442
|
|
||||||
#define kTile3443 3443
|
#define kTile3443 3443
|
||||||
#define kTile3444 3444
|
#define kTile3444 3444
|
||||||
#define kTile3445 3445
|
#define kTile3445 3445
|
||||||
|
@ -3479,16 +3476,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#define kTile3457 3457
|
#define kTile3457 3457
|
||||||
#define kTile3458 3458
|
#define kTile3458 3458
|
||||||
#define kTile3459 3459
|
#define kTile3459 3459
|
||||||
#define kMenuNewGameTile 3460
|
|
||||||
#define kMenuLoadGameTile 3461
|
|
||||||
#define kTile3462 3462
|
#define kTile3462 3462
|
||||||
#define kTile3463 3463
|
#define kTile3463 3463
|
||||||
#define kTile3464 3464
|
#define kTile3464 3464
|
||||||
#define kMenuMusicTile 3465
|
|
||||||
#define kMenuSoundFxTile 3466
|
|
||||||
#define kTile3467 3467
|
#define kTile3467 3467
|
||||||
#define kMenuCursorTile 3468
|
|
||||||
#define kMenuBlankTitleTile 3469
|
|
||||||
#define kTile3470 3470
|
#define kTile3470 3470
|
||||||
#define kTile3471 3471
|
#define kTile3471 3471
|
||||||
#define kTile3472 3472
|
#define kTile3472 3472
|
||||||
|
@ -3601,7 +3592,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#define kTile3579 3579
|
#define kTile3579 3579
|
||||||
#define kTile3580 3580
|
#define kTile3580 3580
|
||||||
#define kTile3581 3581
|
#define kTile3581 3581
|
||||||
#define kSkullHead 3582
|
|
||||||
#define kTile3583 3583
|
#define kTile3583 3583
|
||||||
#define kTile3584 3584
|
#define kTile3584 3584
|
||||||
#define kTile3585 3585
|
#define kTile3585 3585
|
||||||
|
@ -3611,7 +3601,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#define kTile3589 3589
|
#define kTile3589 3589
|
||||||
#define kTile3590 3590
|
#define kTile3590 3590
|
||||||
#define kTile3591 3591
|
#define kTile3591 3591
|
||||||
#define kExhumedLogo 3592
|
|
||||||
#define kTile3593 3593
|
#define kTile3593 3593
|
||||||
#define kTile3594 3594
|
#define kTile3594 3594
|
||||||
#define kTile3595 3595
|
#define kTile3595 3595
|
||||||
|
@ -3623,26 +3612,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#define kTile3601 3601
|
#define kTile3601 3601
|
||||||
#define kTile3602 3602
|
#define kTile3602 3602
|
||||||
#define kTile3603 3603
|
#define kTile3603 3603
|
||||||
#define kEnergy1 3604
|
|
||||||
#define kEnergy2 3605
|
|
||||||
#define kClockSymbol1 3606
|
|
||||||
#define kClockSymbol2 3607
|
|
||||||
#define kClockSymbol3 3608
|
|
||||||
#define kClockSymbol4 3609
|
|
||||||
#define kClockSymbol5 3610
|
|
||||||
#define kClockSymbol6 3611
|
|
||||||
#define kClockSymbol7 3612
|
|
||||||
#define kClockSymbol8 3613
|
|
||||||
#define kClockSymbol9 3614
|
|
||||||
#define kClockSymbol10 3615
|
|
||||||
#define kClockSymbol11 3616
|
|
||||||
#define kClockSymbol12 3617
|
|
||||||
#define kClockSymbol13 3618
|
|
||||||
#define kClockSymbol14 3619
|
|
||||||
#define kClockSymbol15 3620
|
|
||||||
#define kClockSymbol16 3621
|
|
||||||
#define kTile3622 3622
|
#define kTile3622 3622
|
||||||
#define kTileLoboLaptop 3623
|
|
||||||
#define kTile3624 3624
|
#define kTile3624 3624
|
||||||
#define kTile3625 3625
|
#define kTile3625 3625
|
||||||
#define kTile3626 3626
|
#define kTile3626 3626
|
||||||
|
@ -6164,4 +6134,16 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#define kTile6142 6142
|
#define kTile6142 6142
|
||||||
#define kTile6143 6143
|
#define kTile6143 6143
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN_PS_NS
|
||||||
|
|
||||||
|
#define x(a, b) k##a = b,
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
#include "namelist.h"
|
||||||
|
};
|
||||||
|
#undef x
|
||||||
|
|
||||||
|
END_PS_NS
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -34,14 +34,14 @@ void LoadTextureState();
|
||||||
|
|
||||||
static TArray<SavegameHelper*> sghelpers(TArray<SavegameHelper*>::NoInit);
|
static TArray<SavegameHelper*> sghelpers(TArray<SavegameHelper*>::NoInit);
|
||||||
|
|
||||||
bool GameInterface::SaveGame(FSaveGameNode* sv)
|
bool GameInterface::SaveGame()
|
||||||
{
|
{
|
||||||
for (auto sgh : sghelpers) sgh->Save();
|
for (auto sgh : sghelpers) sgh->Save();
|
||||||
SaveTextureState();
|
SaveTextureState();
|
||||||
return 1; // CHECKME
|
return 1; // CHECKME
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameInterface::LoadGame(FSaveGameNode* sv)
|
bool GameInterface::LoadGame()
|
||||||
{
|
{
|
||||||
|
|
||||||
for (auto sgh : sghelpers) sgh->Load();
|
for (auto sgh : sghelpers) sgh->Load();
|
||||||
|
|
|
@ -222,7 +222,6 @@ void InitFX(void)
|
||||||
|
|
||||||
auto& S_sfx = soundEngine->GetSounds();
|
auto& S_sfx = soundEngine->GetSounds();
|
||||||
S_sfx.Resize(1);
|
S_sfx.Resize(1);
|
||||||
S_sfx[0].Clear(); S_sfx[0].lumpnum = sfx_empty;
|
|
||||||
for (size_t i = 0; i < kMaxSoundFiles; i++)
|
for (size_t i = 0; i < kMaxSoundFiles; i++)
|
||||||
{
|
{
|
||||||
StaticSound[i] = LoadSound(SoundFiles[i]);
|
StaticSound[i] = LoadSound(SoundFiles[i]);
|
||||||
|
|
|
@ -369,11 +369,11 @@ public:
|
||||||
DRRLevelSummaryScreen(bool dofadeout = true) : DScreenJob(dofadeout? (fadein | fadeout) : fadein)
|
DRRLevelSummaryScreen(bool dofadeout = true) : DScreenJob(dofadeout? (fadein | fadeout) : fadein)
|
||||||
{
|
{
|
||||||
if (currentLevel->flags & MI_USERMAP)
|
if (currentLevel->flags & MI_USERMAP)
|
||||||
gfx_offset = RRTILE403;
|
gfx_offset = BONUSPIC01;
|
||||||
else if (!isRRRA())
|
else if (!isRRRA())
|
||||||
gfx_offset = RRTILE403 + clamp((currentLevel->levelNumber / 100) * 7 + (currentLevel->levelNumber % 100), 0, 13);
|
gfx_offset = BONUSPIC01 + clamp((currentLevel->levelNumber / 100) * 7 + (currentLevel->levelNumber % 100), 0, 13);
|
||||||
else
|
else
|
||||||
gfx_offset = LEVELMAP + clamp((currentLevel->levelNumber / 100) * 7 + (currentLevel->levelNumber % 100), 0, 13);
|
gfx_offset = LEVELMAP01 + clamp((currentLevel->levelNumber / 100) * 7 + (currentLevel->levelNumber % 100), 0, 13);
|
||||||
|
|
||||||
|
|
||||||
lastmapname = currentLevel->DisplayName();
|
lastmapname = currentLevel->DisplayName();
|
||||||
|
@ -544,7 +544,7 @@ public:
|
||||||
int Frame(uint64_t clock, bool skiprequest)
|
int Frame(uint64_t clock, bool skiprequest)
|
||||||
{
|
{
|
||||||
int currentclock = int(clock * 120 / 1'000'000'000);
|
int currentclock = int(clock * 120 / 1'000'000'000);
|
||||||
auto tex = tileGetTexture(RRTILE8677 + ((currentclock >> 4) & 1));
|
auto tex = tileGetTexture(ENDGAME + ((currentclock >> 4) & 1));
|
||||||
DrawTexture(twod, tex, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE);
|
DrawTexture(twod, tex, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE);
|
||||||
if (!S_CheckSoundPlaying(-1, 35) && currentclock > 15*120) return 0; // make sure it stays, even if sound is off.
|
if (!S_CheckSoundPlaying(-1, 35) && currentclock > 15*120) return 0; // make sure it stays, even if sound is off.
|
||||||
if (skiprequest)
|
if (skiprequest)
|
||||||
|
|
|
@ -35,7 +35,7 @@ Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms
|
||||||
#include "gamecvars.h"
|
#include "gamecvars.h"
|
||||||
#include "gamecontrol.h"
|
#include "gamecontrol.h"
|
||||||
#include "c_bind.h"
|
#include "c_bind.h"
|
||||||
#include "menu/menu.h"
|
#include "razemenu.h"
|
||||||
#include "gstrings.h"
|
#include "gstrings.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "names.h"
|
#include "names.h"
|
||||||
|
@ -46,177 +46,12 @@ Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms
|
||||||
|
|
||||||
BEGIN_DUKE_NS
|
BEGIN_DUKE_NS
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static void Menu_DrawBackground(const DVector2 &origin)
|
|
||||||
{
|
|
||||||
DrawTexture(twod, tileGetTexture(TILE_MENUSCREEN), origin.X + 160, origin.Y + 100, DTA_FullscreenScale, FSMode_Fit320x200, DTA_Color, 0xff808080, DTA_CenterOffset, true, TAG_DONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static void Menu_DrawCursor(double x, double y, double scale, bool right)
|
|
||||||
{
|
|
||||||
int mclock = I_GetBuildTime();
|
|
||||||
const int frames = isRR() ? 16 : 7;
|
|
||||||
int picnum;
|
|
||||||
if (!right) picnum = TILE_SPINNINGNUKEICON + ((mclock >> 3) % frames);
|
|
||||||
else picnum = TILE_SPINNINGNUKEICON + frames - 1 - ((frames - 1 + (mclock >> 3)) % frames);
|
|
||||||
int light = 231 + (calcSinTableValue(mclock<<5) / 768.);
|
|
||||||
PalEntry pe(255, light, light, light);
|
|
||||||
DrawTexture(twod, tileGetTexture(picnum), x, y, DTA_FullscreenScale, FSMode_Fit320x200, DTA_ScaleX, scale, DTA_ScaleY, scale, DTA_Color, pe, DTA_CenterOffsetRel, true, TAG_DONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Implements the native looking menu used for the main menu
|
|
||||||
// and the episode/skill selection screens, i.e. the parts
|
|
||||||
// that need to look authentic
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
class DukeListMenu : public DListMenu
|
|
||||||
{
|
|
||||||
using Super = DListMenu;
|
|
||||||
protected:
|
|
||||||
|
|
||||||
void Ticker() override
|
|
||||||
{
|
|
||||||
// Lay out the menu.
|
|
||||||
int y_upper = mDesc->mYpos;
|
|
||||||
int y_lower = y_upper + mDesc->mYbotton;
|
|
||||||
int y = 0;
|
|
||||||
int spacing = 0;
|
|
||||||
const int height = 15; // cannot take value from the font because it would be inconsistent
|
|
||||||
|
|
||||||
int totalheight = 0, numvalidentries = mDesc->mItems.Size();
|
|
||||||
|
|
||||||
for (unsigned e = 0; e < mDesc->mItems.Size(); ++e)
|
|
||||||
{
|
|
||||||
auto entry = mDesc->mItems[e];
|
|
||||||
entry->mHidden = false;
|
|
||||||
entry->SetHeight(height);
|
|
||||||
totalheight += height;
|
|
||||||
}
|
|
||||||
if (mDesc->mSpacing <= 0) spacing = std::max(0, (y_lower - y_upper - totalheight) / (numvalidentries > 1 ? numvalidentries - 1 : 1));
|
|
||||||
if (spacing <= 0) spacing = mDesc->mSpacing;
|
|
||||||
|
|
||||||
int totalHeight;
|
|
||||||
for (unsigned e = 0; e < mDesc->mItems.Size(); ++e)
|
|
||||||
{
|
|
||||||
auto entry = mDesc->mItems[e];
|
|
||||||
if (!entry->mHidden)
|
|
||||||
{
|
|
||||||
entry->SetY(y_upper + y);
|
|
||||||
y += height;
|
|
||||||
totalHeight = y;
|
|
||||||
y += spacing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
class DukeMainMenu : public DukeListMenu
|
|
||||||
{
|
|
||||||
virtual void Init(DMenu* parent = nullptr, FListMenuDescriptor* desc = nullptr) override
|
|
||||||
{
|
|
||||||
DukeListMenu::Init(parent, desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PreDraw() override
|
|
||||||
{
|
|
||||||
DukeListMenu::PreDraw();
|
|
||||||
double x = origin.X + 160;
|
|
||||||
if (isRRRA())
|
|
||||||
{
|
|
||||||
DrawTexture(twod, tileGetTexture(TILE_THREEDEE), x-5, origin.Y+57, DTA_FullscreenScale, FSMode_Fit320x200Top, DTA_ScaleX, 0.253, DTA_ScaleY, 0.253, DTA_CenterOffsetRel, true, TAG_DONE);
|
|
||||||
}
|
|
||||||
else if (isRR())
|
|
||||||
{
|
|
||||||
DrawTexture(twod, tileGetTexture(TILE_INGAMEDUKETHREEDEE), x+5, origin.Y + 24, DTA_FullscreenScale, FSMode_Fit320x200Top, DTA_ScaleX, 0.36, DTA_ScaleY, 0.36, DTA_CenterOffsetRel, true, TAG_DONE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DrawTexture(twod, tileGetTexture(TILE_INGAMEDUKETHREEDEE), x, origin.Y + 29, DTA_FullscreenScale, FSMode_Fit320x200Top, DTA_CenterOffsetRel, true, TAG_DONE);
|
|
||||||
if (PLUTOPAK)
|
|
||||||
{
|
|
||||||
int mclock = I_GetBuildTime();
|
|
||||||
int light = 223 + (calcSinTableValue(mclock<<4) / 512.);
|
|
||||||
PalEntry pe(255, light, light, light);
|
|
||||||
DrawTexture(twod, tileGetTexture(TILE_PLUTOPAKSPRITE + 2), x + 100, origin.Y + 36, DTA_FullscreenScale, FSMode_Fit320x200Top, DTA_Color, pe, DTA_CenterOffsetRel, true, TAG_DONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Menu related game interface functions
|
// Menu related game interface functions
|
||||||
//
|
//
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
void GameInterface::DrawNativeMenuText(int fontnum, int state, double oxpos, double ypos, float fontscale, const char* text, int flags)
|
|
||||||
{
|
|
||||||
double xpos = oxpos;
|
|
||||||
int trans;
|
|
||||||
PalEntry pe;
|
|
||||||
|
|
||||||
double scale = isRR() ? 0.4 : 1.;
|
|
||||||
if (flags & LMF_Centered) xpos -= BigFont->StringWidth(text) * scale * 0.5;
|
|
||||||
|
|
||||||
if (state == NIT_InactiveState)
|
|
||||||
{
|
|
||||||
trans = TRANSLATION(Translation_Remap, 1);
|
|
||||||
pe = 0xffffffff;
|
|
||||||
}
|
|
||||||
else if (state == NIT_SelectedState)
|
|
||||||
{
|
|
||||||
trans = 0;
|
|
||||||
int mclock = I_GetBuildTime();
|
|
||||||
int light = 231 + (calcSinTableValue(mclock<<5) / 768.);
|
|
||||||
pe = PalEntry(255, light, light, light);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
trans = 0;
|
|
||||||
pe = 0xffa0a0a0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawText(twod, BigFont, CR_UNDEFINED, xpos, ypos, text, DTA_FullscreenScale, FSMode_Fit320x200, DTA_ScaleX, scale, DTA_ScaleY, scale, DTA_Color, pe,
|
|
||||||
DTA_TranslationIndex, trans, TAG_DONE);
|
|
||||||
|
|
||||||
if (state == NIT_SelectedState)
|
|
||||||
{
|
|
||||||
const int cursorOffset = 110;
|
|
||||||
const double cursorScale = isRR() ? 0.2 : 1.0;
|
|
||||||
const double ymid = ypos + 7; // half height must be hardcoded or layouts will break.
|
|
||||||
if (flags & LMF_Centered)
|
|
||||||
{
|
|
||||||
Menu_DrawCursor(oxpos + cursorOffset, ymid, cursorScale, false);
|
|
||||||
Menu_DrawCursor(oxpos - cursorOffset, ymid, cursorScale, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Menu_DrawCursor(oxpos - cursorOffset, ymid, cursorScale, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameInterface::MenuOpened()
|
void GameInterface::MenuOpened()
|
||||||
{
|
{
|
||||||
StopCommentary();
|
StopCommentary();
|
||||||
|
@ -253,10 +88,6 @@ void GameInterface::MenuSound(EMenuSounds snd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameInterface::MenuClosed()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GameInterface::CanSave()
|
bool GameInterface::CanSave()
|
||||||
{
|
{
|
||||||
if (ud.recstat == 2 || gamestate != GS_LEVEL) return false;
|
if (ud.recstat == 2 || gamestate != GS_LEVEL) return false;
|
||||||
|
@ -270,7 +101,7 @@ bool GameInterface::StartGame(FNewGameStartup& gs)
|
||||||
{
|
{
|
||||||
if (g_gameType & GAMEFLAG_SHAREWARE)
|
if (g_gameType & GAMEFLAG_SHAREWARE)
|
||||||
{
|
{
|
||||||
M_StartMessage(GStrings("BUYDUKE"), 1, -1);
|
M_StartMessage(GStrings("BUYDUKE"), 1, NAME_None);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -295,6 +126,7 @@ bool GameInterface::StartGame(FNewGameStartup& gs)
|
||||||
}
|
}
|
||||||
Net_ClearFifo();
|
Net_ClearFifo();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto map = FindMapByLevelNum(levelnum(gs.Episode, gs.Level));
|
auto map = FindMapByLevelNum(levelnum(gs.Episode, gs.Level));
|
||||||
if (map)
|
if (map)
|
||||||
{
|
{
|
||||||
|
@ -310,30 +142,6 @@ FSavegameInfo GameInterface::GetSaveSig()
|
||||||
return { SAVESIG_DN3D, MINSAVEVER_DN3D, SAVEVER_DN3D };
|
return { SAVESIG_DN3D, MINSAVEVER_DN3D, SAVEVER_DN3D };
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameInterface::DrawMenuCaption(const DVector2& origin, const char* text)
|
|
||||||
{
|
|
||||||
DrawTexture(twod, tileGetTexture(TILE_MENUBAR), origin.X + 160, origin.Y + 19, DTA_FullscreenScale, FSMode_Fit320x200Top, DTA_Color, 0xff808080, DTA_CenterOffsetRel, 1, TAG_DONE);
|
|
||||||
|
|
||||||
FString t = text;
|
|
||||||
size_t newlen = t.Len();
|
|
||||||
if (t[t.Len() - 1] == ':') newlen--;
|
|
||||||
if (newlen > 63) newlen = 63;
|
|
||||||
t.Truncate(newlen);
|
|
||||||
double scale = isRR() ? 0.4 : 1.0;
|
|
||||||
double x = 160 + origin.X - BigFont->StringWidth(t) * scale * 0.5;
|
|
||||||
DrawText(twod, BigFont, CR_UNTRANSLATED, x, origin.Y + 12, t, DTA_FullscreenScale, FSMode_Fit320x200Top, DTA_ScaleX, scale, DTA_ScaleY, scale, TAG_DONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameInterface::DrawCenteredTextScreen(const DVector2 &origin, const char *text, int position, bool bg)
|
|
||||||
{
|
|
||||||
if (bg) Menu_DrawBackground(origin);
|
|
||||||
else if (!isRR())
|
|
||||||
{
|
|
||||||
Menu_DrawCursor(160, 130, 1, false);
|
|
||||||
}
|
|
||||||
::GameInterface::DrawCenteredTextScreen(origin, text, position, bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameInterface::DrawPlayerSprite(const DVector2& origin, bool onteam)
|
void GameInterface::DrawPlayerSprite(const DVector2& origin, bool onteam)
|
||||||
{
|
{
|
||||||
int mclock = I_GetBuildTime();
|
int mclock = I_GetBuildTime();
|
||||||
|
@ -352,190 +160,5 @@ void GameInterface::QuitToTitle()
|
||||||
gameaction = ga_startup;
|
gameaction = ga_startup;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static void shadowminitext(int32_t xx, int32_t yy, const char* t, int32_t p)
|
|
||||||
{
|
|
||||||
double x = FixedToFloat(xx);
|
|
||||||
double y = FixedToFloat(yy);
|
|
||||||
|
|
||||||
DrawText(twod, SmallFont2, CR_UNDEFINED, x + 1, y + 1, t, DTA_FullscreenScale, FSMode_Fit320x200, DTA_Color, 0xff000000, DTA_Alpha, 0.5, TAG_DONE);
|
|
||||||
DrawText(twod, SmallFont2, CR_UNDEFINED, x, y, t, DTA_FullscreenScale, FSMode_Fit320x200, DTA_TranslationIndex, TRANSLATION(Translation_Remap, p), TAG_DONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mgametextcenter(int32_t xx, int32_t yy, const char* t)
|
|
||||||
{
|
|
||||||
double x = FixedToFloat(xx) + 160. - SmallFont->StringWidth(t) * 0.5;
|
|
||||||
double y = FixedToFloat(yy);
|
|
||||||
|
|
||||||
DrawText(twod, SmallFont, CR_UNDEFINED, x, y + 2, t, DTA_FullscreenScale, FSMode_Fit320x200, TAG_DONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// allows the front end to override certain fullscreen image menus
|
|
||||||
// with custom implementations.
|
|
||||||
//
|
|
||||||
// This is needed because the credits screens in Duke Nukem
|
|
||||||
// are either done by providing an image or by printing text, based on the version used.
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool GameInterface::DrawSpecialScreen(const DVector2& origin, int tilenum)
|
|
||||||
{
|
|
||||||
// Older versions of Duke Nukem create the credits screens manually.
|
|
||||||
// On the latest version there's real graphics for this.
|
|
||||||
bool haveCredits = !(g_gameType & GAMEFLAG_DUKE) || (VOLUMEALL && PLUTOPAK);
|
|
||||||
|
|
||||||
int32_t m, l;
|
|
||||||
if (!haveCredits)
|
|
||||||
{
|
|
||||||
if (tilenum == 2504)
|
|
||||||
{
|
|
||||||
Menu_DrawBackground(origin);
|
|
||||||
DrawMenuCaption(origin, GStrings("MNU_CREDITS"));
|
|
||||||
m = int(origin.X * 65536) + (20 << 16);
|
|
||||||
l = int(origin.Y * 65536) + (33 << 16);
|
|
||||||
|
|
||||||
shadowminitext(m, l, "Original Concept", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Todd Replogle and Allen H. Blum III", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "Produced & Directed By", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Greg Malone", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "Executive Producer", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "George Broussard", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "BUILD Engine", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Ken Silverman", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "Game Programming", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Todd Replogle", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "3D Engine/Tools/Net", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Ken Silverman", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "Network Layer/Setup Program", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Mark Dochtermann", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "Map Design", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Allen H. Blum III", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Richard Gray", 12); l += 7 << 16;
|
|
||||||
|
|
||||||
m = int(origin.X * 65536) + (180 << 16);
|
|
||||||
l = int(origin.Y * 65536) + (33 << 16);
|
|
||||||
|
|
||||||
shadowminitext(m, l, "3D Modeling", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Chuck Jones", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Sapphire Corporation", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "Artwork", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Dirk Jones, Stephen Hornback", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "James Storey, David Demaret", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Douglas R. Wood", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "Sound Engine", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Jim Dose", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "Sound & Music Development", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Robert Prince", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Lee Jackson", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "Voice Talent", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Lani Minella - Voice Producer", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Jon St. John as \"Duke Nukem\"", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "Graphic Design", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Packaging, Manual, Ads", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Robert M. Atkins", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Michael Hadwin", 12); l += 7 << 16;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (tilenum == 2505)
|
|
||||||
{
|
|
||||||
Menu_DrawBackground(origin);
|
|
||||||
DrawMenuCaption(origin, GStrings("MNU_CREDITS"));
|
|
||||||
m = int(origin.X * 65536) + (20 << 16);
|
|
||||||
l = int(origin.Y * 65536) + (33 << 16);
|
|
||||||
|
|
||||||
shadowminitext(m, l, "Special Thanks To", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Steven Blackburn, Tom Hall", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Scott Miller, Joe Siegler", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Terry Nagy, Colleen Compton", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "HASH, Inc., FormGen, Inc.", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "The 3D Realms Beta Testers", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "Nathan Anderson, Wayne Benner", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Glenn Brensinger, Rob Brown", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Erik Harris, Ken Heckbert", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Terry Herrin, Greg Hively", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Hank Leukart, Eric Baker", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Jeff Rausch, Kelly Rogers", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Mike Duncan, Doug Howell", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "Bill Blair", 12); l += 7 << 16;
|
|
||||||
|
|
||||||
m = int(origin.X * 65536) + (160 << 16);
|
|
||||||
l = int(origin.Y * 65536) + (33 << 16);
|
|
||||||
|
|
||||||
shadowminitext(m, l, "Company Product Support", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "The following companies were cool", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "enough to give us lots of stuff", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "during the making of Duke Nukem 3D.", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "Altec Lansing Multimedia", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "for tons of speakers and the", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "THX-licensed sound system.", 12); l += 7 << 16;
|
|
||||||
shadowminitext(m, l, "For info call 1-800-548-0620", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "Creative Labs, Inc.", 12); l += 7 << 16;
|
|
||||||
l += 3 << 16;
|
|
||||||
shadowminitext(m, l, "Thanks for the hardware, guys.", 12); l += 7 << 16;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (tilenum == 2506)
|
|
||||||
{
|
|
||||||
Menu_DrawBackground(origin);
|
|
||||||
DrawMenuCaption(origin, GStrings("MNU_CREDITS"));
|
|
||||||
mgametextcenter(int(origin.X * 65536), int(origin.Y * 65536) + (50 << 16), "Duke Nukem 3D is a trademark of");
|
|
||||||
mgametextcenter(int(origin.X * 65536), int(origin.Y * 65536) + (59 << 16), "3D Realms Entertainment");
|
|
||||||
mgametextcenter(int(origin.X * 65536), int(origin.Y * 65536) + (77 << 16), "Duke Nukem 3D");
|
|
||||||
mgametextcenter(int(origin.X * 65536), int(origin.Y * 65536) + (86 << 16), "(C) 1996 3D Realms Entertainment");
|
|
||||||
|
|
||||||
if (VOLUMEONE)
|
|
||||||
{
|
|
||||||
mgametextcenter(int(origin.X * 65536), int(origin.Y * 65536) + (106 << 16), "Please read LICENSE.DOC for shareware");
|
|
||||||
mgametextcenter(int(origin.X * 65536), int(origin.Y * 65536) + (115 << 16), "distribution grants and restrictions.");
|
|
||||||
}
|
|
||||||
mgametextcenter(int(origin.X * 65536), int(origin.Y * 65536) + ((VOLUMEONE ? 134 : 115) << 16), "Made in Dallas, Texas USA");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
END_DUKE_NS
|
END_DUKE_NS
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Class registration
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
static TMenuClassDescriptor<Duke3d::DukeMainMenu> _mm("Duke.MainMenu");
|
|
||||||
static TMenuClassDescriptor<Duke3d::DukeListMenu> _lm("Duke.ListMenu");
|
|
||||||
|
|
||||||
static TMenuClassDescriptor<DImageScrollerMenu> _ism("Duke.ImageScrollerMenu"); // does not implement a new class, we only need the descriptor.
|
|
||||||
|
|
||||||
void RegisterDuke3dMenus()
|
|
||||||
{
|
|
||||||
menuClasses.Push(&_mm);
|
|
||||||
menuClasses.Push(&_lm);
|
|
||||||
menuClasses.Push(&_ism);
|
|
||||||
}
|
|
||||||
|
|
|
@ -252,7 +252,6 @@ int TILE_CAMCORNER;
|
||||||
int TILE_CAMLIGHT;
|
int TILE_CAMLIGHT;
|
||||||
int TILE_STATIC;
|
int TILE_STATIC;
|
||||||
int TILE_BOTTOMSTATUSBAR;
|
int TILE_BOTTOMSTATUSBAR;
|
||||||
int TILE_SPINNINGNUKEICON;
|
|
||||||
int TILE_THREEDEE;
|
int TILE_THREEDEE;
|
||||||
int TILE_INGAMEDUKETHREEDEE;
|
int TILE_INGAMEDUKETHREEDEE;
|
||||||
int TILE_PLUTOPAKSPRITE;
|
int TILE_PLUTOPAKSPRITE;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue