2019-12-01 09:18:38 +00:00
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/*
|
|
|
|
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
|
|
|
Copyright (C) 2019 Nuke.YKT
|
|
|
|
|
|
|
|
This file is part of NBlood.
|
|
|
|
|
|
|
|
NBlood is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License version 2
|
|
|
|
as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include "ns.h" // Must come before everything else!
|
|
|
|
|
|
|
|
#include "build.h"
|
|
|
|
#include "compat.h"
|
2020-07-31 19:05:09 +00:00
|
|
|
#include "mmulti.h"
|
|
|
|
#include "c_bind.h"
|
|
|
|
#include "menu.h"
|
|
|
|
#include "gamestate.h"
|
|
|
|
|
2019-12-01 09:18:38 +00:00
|
|
|
#include "blood.h"
|
|
|
|
#include "globals.h"
|
|
|
|
#include "qav.h"
|
|
|
|
#include "view.h"
|
2020-07-25 16:53:44 +00:00
|
|
|
#include "sound.h"
|
2020-08-14 19:01:27 +00:00
|
|
|
#include "v_video.h"
|
2019-12-01 09:18:38 +00:00
|
|
|
|
|
|
|
bool ShowOptionMenu();
|
|
|
|
|
|
|
|
BEGIN_BLD_NS
|
|
|
|
|
2019-12-01 14:31:08 +00:00
|
|
|
class CGameMenuItemQAV
|
2019-12-01 09:18:38 +00:00
|
|
|
{
|
2019-12-01 14:31:08 +00:00
|
|
|
public:
|
|
|
|
int m_nX, m_nY;
|
|
|
|
TArray<uint8_t> raw;
|
|
|
|
int at2c;
|
|
|
|
int lastTick;
|
|
|
|
bool bWideScreen;
|
|
|
|
bool bClearBackground;
|
|
|
|
CGameMenuItemQAV(int, int, const char*, bool widescreen = false, bool clearbackground = false);
|
|
|
|
void Draw(void);
|
|
|
|
};
|
2019-12-01 09:18:38 +00:00
|
|
|
|
2019-12-01 14:31:08 +00:00
|
|
|
CGameMenuItemQAV::CGameMenuItemQAV(int a3, int a4, const char* name, bool widescreen, bool clearbackground)
|
2019-12-01 09:18:38 +00:00
|
|
|
{
|
2019-12-01 14:31:08 +00:00
|
|
|
m_nY = a4;
|
|
|
|
m_nX = a3;
|
|
|
|
bWideScreen = widescreen;
|
|
|
|
bClearBackground = clearbackground;
|
2019-12-01 09:18:38 +00:00
|
|
|
|
2019-12-01 14:31:08 +00:00
|
|
|
if (name)
|
|
|
|
{
|
|
|
|
// NBlood read this directly from the file system cache, but let's better store the data locally for robustness.
|
2019-12-07 09:31:27 +00:00
|
|
|
raw = fileSystem.LoadFile(name, 0);
|
2019-12-01 14:31:08 +00:00
|
|
|
if (raw.Size() != 0)
|
|
|
|
{
|
|
|
|
auto data = (QAV*)raw.Data();
|
|
|
|
data->nSprite = -1;
|
|
|
|
data->x = m_nX;
|
|
|
|
data->y = m_nY;
|
|
|
|
data->Preload();
|
|
|
|
at2c = data->at10;
|
|
|
|
lastTick = (int)totalclock;
|
|
|
|
}
|
|
|
|
}
|
2019-12-01 09:18:38 +00:00
|
|
|
}
|
|
|
|
|
2019-12-01 14:31:08 +00:00
|
|
|
void CGameMenuItemQAV::Draw(void)
|
2019-12-01 09:18:38 +00:00
|
|
|
{
|
2019-12-01 14:31:08 +00:00
|
|
|
if (bClearBackground)
|
2020-06-12 18:31:23 +00:00
|
|
|
twod->ClearScreen();
|
2019-12-01 09:18:38 +00:00
|
|
|
|
2019-12-01 14:31:08 +00:00
|
|
|
if (raw.Size() > 0)
|
2019-12-01 09:18:38 +00:00
|
|
|
{
|
2019-12-01 14:31:08 +00:00
|
|
|
auto data = (QAV*)raw.Data();
|
|
|
|
ClockTicks backFC = gFrameClock;
|
|
|
|
gFrameClock = totalclock;
|
|
|
|
int nTicks = (int)totalclock - lastTick;
|
|
|
|
lastTick = (int)totalclock;
|
|
|
|
at2c -= nTicks;
|
|
|
|
if (at2c <= 0 || at2c > data->at10)
|
|
|
|
{
|
|
|
|
at2c = data->at10;
|
|
|
|
}
|
|
|
|
data->Play(data->at10 - at2c - nTicks, data->at10 - at2c, -1, NULL);
|
2020-08-14 19:12:32 +00:00
|
|
|
|
2019-12-01 14:31:08 +00:00
|
|
|
if (bWideScreen)
|
|
|
|
{
|
|
|
|
int xdim43 = scale(ydim, 4, 3);
|
|
|
|
int nCount = (xdim + xdim43 - 1) / xdim43;
|
|
|
|
int backX = data->x;
|
|
|
|
for (int i = 0; i < nCount; i++)
|
|
|
|
{
|
2020-08-14 19:18:14 +00:00
|
|
|
data->Draw(data->at10 - at2c, 10 + kQavOrientationLeft, 0, 0, false);
|
2019-12-01 14:31:08 +00:00
|
|
|
data->x += 320;
|
|
|
|
}
|
|
|
|
data->x = backX;
|
|
|
|
}
|
2019-12-01 09:18:38 +00:00
|
|
|
else
|
2020-08-14 19:18:14 +00:00
|
|
|
data->Draw(data->at10 - at2c, 10, 0, 0, false);
|
2019-12-01 14:31:08 +00:00
|
|
|
|
|
|
|
gFrameClock = backFC;
|
2019-12-01 09:18:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-01 14:31:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
static std::unique_ptr<CGameMenuItemQAV> itemBloodQAV; // This must be global to ensure that the animation remains consistent across menus.
|
|
|
|
|
|
|
|
|
2019-12-01 09:18:38 +00:00
|
|
|
void UpdateNetworkMenus(void)
|
|
|
|
{
|
2019-12-01 21:54:52 +00:00
|
|
|
// For now disable the network menu item as it is not yet functional.
|
2020-04-11 22:02:48 +00:00
|
|
|
for (auto name : { NAME_Mainmenu, NAME_IngameMenu })
|
2019-12-01 09:18:38 +00:00
|
|
|
{
|
2019-12-01 21:54:52 +00:00
|
|
|
FMenuDescriptor** desc = MenuDescriptors.CheckKey(name);
|
|
|
|
if (desc != NULL && (*desc)->mType == MDESC_ListMenu)
|
|
|
|
{
|
|
|
|
FListMenuDescriptor* ld = static_cast<FListMenuDescriptor*>(*desc);
|
|
|
|
for (auto& li : ld->mItems)
|
|
|
|
{
|
|
|
|
if (li->GetAction(nullptr) == NAME_MultiMenu)
|
|
|
|
{
|
|
|
|
li->mEnabled = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-01 09:18:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-01 14:31:08 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// 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()
|
|
|
|
{
|
2020-08-14 19:01:27 +00:00
|
|
|
// 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();
|
2019-12-01 14:31:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2019-12-01 19:17:30 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2019-12-01 14:31:08 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// 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 - ((int)totalclock & 63);
|
2020-07-31 19:05:09 +00:00
|
|
|
auto gamefont = fontnum == NIT_BigFont ? BigFont : fontnum == NIT_SmallFont ? SmallFont : SmallFont2;
|
2019-12-01 14:31:08 +00:00
|
|
|
|
|
|
|
if (flags & LMF_Centered)
|
|
|
|
{
|
2020-07-31 19:05:09 +00:00
|
|
|
int width = gamefont->StringWidth(text);
|
|
|
|
xpos -= width / 2;
|
2019-12-01 14:31:08 +00:00
|
|
|
}
|
2020-08-10 18:27:00 +00:00
|
|
|
DrawText(twod, gamefont, CR_UNDEFINED, xpos+1, ypos+1, text, DTA_Color, 0xff000000, //DTA_Alpha, 0.5,
|
2020-08-14 19:01:27 +00:00
|
|
|
DTA_FullscreenScale, FSMode_ScaleToFit43, DTA_VirtualWidth, 320, DTA_VirtualHeight, 200, TAG_DONE);
|
2020-07-31 19:05:57 +00:00
|
|
|
|
|
|
|
DrawText(twod, gamefont, CR_UNDEFINED, xpos, ypos, text, DTA_TranslationIndex, TRANSLATION(Translation_Remap, pal), DTA_Color, shadeToLight(shade),
|
2020-08-14 19:01:27 +00:00
|
|
|
DTA_FullscreenScale, FSMode_ScaleToFit43, DTA_VirtualWidth, 320, DTA_VirtualHeight, 200, TAG_DONE);
|
2019-12-01 14:31:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GameInterface::MenuOpened()
|
|
|
|
{
|
|
|
|
itemBloodQAV.reset(new CGameMenuItemQAV(160, 100, "BDRIP.QAV", true));
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameInterface::MenuClosed()
|
|
|
|
{
|
|
|
|
itemBloodQAV.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GameInterface::CanSave()
|
|
|
|
{
|
2020-07-29 21:18:08 +00:00
|
|
|
return (gamestate == GS_LEVEL && gPlayer[myconnectindex].pXSprite->health != 0);
|
2019-12-01 14:31:08 +00:00
|
|
|
}
|
|
|
|
|
2020-04-23 19:18:40 +00:00
|
|
|
void GameInterface::StartGame(FNewGameStartup& gs)
|
2019-12-01 14:31:08 +00:00
|
|
|
{
|
2020-02-17 18:43:58 +00:00
|
|
|
sfxKillAllSounds();
|
2019-12-01 19:17:30 +00:00
|
|
|
gGameOptions.nDifficulty = gs.Skill;
|
|
|
|
gSkill = gs.Skill;
|
2020-08-16 11:26:57 +00:00
|
|
|
gStartNewGame = FindMapByLevelNum(levelnum(gs.Episode, gs.Level));
|
2020-08-03 18:51:31 +00:00
|
|
|
cheatReset();
|
2019-12-01 14:31:08 +00:00
|
|
|
}
|
2019-12-01 09:18:38 +00:00
|
|
|
|
|
|
|
FSavegameInfo GameInterface::GetSaveSig()
|
|
|
|
{
|
|
|
|
return { SAVESIG_BLD, MINSAVEVER_BLD, SAVEVER_BLD };
|
|
|
|
}
|
|
|
|
|
2020-08-02 15:45:03 +00:00
|
|
|
// This also gets used by the summary and the loading screen
|
|
|
|
void DrawMenuCaption(const char* text)
|
2019-12-01 14:31:08 +00:00
|
|
|
{
|
2020-07-31 18:39:02 +00:00
|
|
|
double scalex = 1.; // Expand the box if the text is longer
|
2020-07-31 19:05:09 +00:00
|
|
|
int width = BigFont->StringWidth(text);
|
2020-07-31 18:39:02 +00:00
|
|
|
int boxwidth = tileWidth(2038);
|
|
|
|
if (boxwidth - 10 < width) scalex = double(width) / (boxwidth - 10);
|
|
|
|
|
2020-08-14 19:01:27 +00:00
|
|
|
DrawTexture(twod, tileGetTexture(2038, true), 160, 20, DTA_FullscreenScale, FSMode_ScaleToFit43Top, DTA_VirtualWidth, 320, DTA_VirtualHeight, 200, DTA_CenterOffsetRel, true, DTA_ScaleX, scalex, TAG_DONE);
|
|
|
|
DrawText(twod, BigFont, CR_UNDEFINED, 160 - width/2, 20 - tileHeight(4193) / 2, text, DTA_FullscreenScale, FSMode_ScaleToFit43Top, DTA_VirtualWidth, 320, DTA_VirtualHeight, 200, TAG_DONE);
|
2019-12-01 14:31:08 +00:00
|
|
|
}
|
|
|
|
|
2020-08-02 15:45:03 +00:00
|
|
|
void GameInterface::DrawMenuCaption(const DVector2& origin, const char* text)
|
|
|
|
{
|
|
|
|
Blood::DrawMenuCaption(text);
|
|
|
|
}
|
|
|
|
|
2019-12-05 22:17:55 +00:00
|
|
|
void GameInterface::DrawCenteredTextScreen(const DVector2& origin, const char* text, int position, bool bg)
|
|
|
|
{
|
|
|
|
if (text)
|
|
|
|
{
|
2020-07-31 19:05:09 +00:00
|
|
|
int height = SmallFont->GetHeight();
|
2019-12-06 17:36:49 +00:00
|
|
|
|
|
|
|
auto lines = FString(text).Split("\n");
|
|
|
|
int y = 100 - (height * lines.Size() / 2);
|
|
|
|
for (auto& l : lines)
|
|
|
|
{
|
2020-07-31 19:05:57 +00:00
|
|
|
int width = SmallFont->StringWidth(l);
|
2019-12-06 17:36:49 +00:00
|
|
|
int x = 160 - width / 2;
|
2020-08-14 19:01:27 +00:00
|
|
|
DrawText(twod, SmallFont, CR_UNTRANSLATED, x, y, l, DTA_FullscreenScale, FSMode_ScaleToFit43, DTA_VirtualWidth, 320, DTA_VirtualHeight, 200, TAG_DONE);
|
2019-12-06 17:36:49 +00:00
|
|
|
y += height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameInterface::QuitToTitle()
|
|
|
|
{
|
|
|
|
if (gGameOptions.nGameType == 0 || numplayers == 1)
|
|
|
|
{
|
|
|
|
gQuitGame = true;
|
|
|
|
gRestartGame = true;
|
2019-12-05 22:17:55 +00:00
|
|
|
}
|
2019-12-06 17:36:49 +00:00
|
|
|
else
|
|
|
|
gQuitRequest = 2;
|
2019-12-05 22:17:55 +00:00
|
|
|
}
|
2019-12-01 09:18:38 +00:00
|
|
|
|
|
|
|
END_BLD_NS
|
2019-12-01 14:31:08 +00:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Class registration
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
static TMenuClassDescriptor<Blood::BloodListMenu> _lm("Blood.ListMenu");
|
2020-02-12 22:41:26 +00:00
|
|
|
static TMenuClassDescriptor<Blood::BloodListMenu> _mm("Blood.MainMenu");
|
2019-12-01 19:17:30 +00:00
|
|
|
static TMenuClassDescriptor<Blood::DBloodImageScrollerMenu> _im("Blood.ImageScrollerMenu");
|
2019-12-01 14:31:08 +00:00
|
|
|
|
|
|
|
void RegisterBloodMenus()
|
|
|
|
{
|
|
|
|
menuClasses.Push(&_lm);
|
2020-02-12 22:41:26 +00:00
|
|
|
menuClasses.Push(&_mm);
|
2019-12-01 19:17:30 +00:00
|
|
|
menuClasses.Push(&_im);
|
2019-12-01 14:31:08 +00:00
|
|
|
}
|