2019-11-22 21:52:11 +00:00
//-------------------------------------------------------------------------
/*
Copyright ( C ) 2016 EDuke32 developers and contributors
Copyright ( C ) 2019 Christoph Oelckers
This 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 "cheats.h"
# include "compat.h"
# include "demo.h"
# include "duke3d.h"
# include "input.h"
# include "menus.h"
# include "osdcmds.h"
# include "savegame.h"
# include "game.h"
# include "superfasthash.h"
# include "gamecvars.h"
# include "gamecontrol.h"
# include "c_bind.h"
# include "menu/menu.h"
2019-11-25 22:21:51 +00:00
# include "gstrings.h"
2019-11-26 23:41:26 +00:00
# include "version.h"
2019-11-28 00:02:45 +00:00
# include "namesdyn.h"
2019-11-29 00:28:13 +00:00
# include "menus.h"
2019-11-22 21:52:11 +00:00
# include "../../glbackend/glbackend.h"
BEGIN_DUKE_NS
# define MENU_MARGIN_REGULAR 40
# define MENU_MARGIN_WIDE 32
# define MENU_MARGIN_CENTER 160
# define MENU_HEIGHT_CENTER 100
2019-11-23 22:05:24 +00:00
2019-11-23 16:50:36 +00:00
enum MenuTextFlags_t
{
MT_Selected = 1 < < 0 ,
MT_Disabled = 1 < < 1 ,
MT_XCenter = 1 < < 2 ,
MT_XRight = 1 < < 3 ,
MT_YCenter = 1 < < 4 ,
MT_Literal = 1 < < 5 ,
MT_RightSide = 1 < < 6 ,
} ;
2019-11-22 21:52:11 +00:00
2019-11-23 11:41:13 +00:00
// common font types
// tilenums are set after namesdyn runs.
// These are also modifiable by scripts.
// emptychar x,y between x,y zoom cursorLeft cursorCenter cursorScale textflags
// tilenum shade_deselected shade_disabled pal pal_selected pal_deselected pal_disabled
MenuFont_t MF_Redfont = { { 5 < < 16 , 15 < < 16 } , { 0 , 0 } , 65536 , 20 < < 16 , 110 < < 16 , 65536 , TEXT_BIGALPHANUM | TEXT_UPPERCASE ,
- 1 , 10 , 0 , 0 , 0 , 0 , 1 ,
0 , 0 , 1 } ;
MenuFont_t MF_Bluefont = { { 5 < < 16 , 7 < < 16 } , { 0 , 0 } , 65536 , 10 < < 16 , 110 < < 16 , 32768 , 0 ,
- 1 , 10 , 0 , 0 , 10 , 10 , 16 ,
0 , 0 , 16 } ;
MenuFont_t MF_Minifont = { { 4 < < 16 , 5 < < 16 } , { 1 < < 16 , 1 < < 16 } , 65536 , 10 < < 16 , 110 < < 16 , 32768 , 0 ,
- 1 , 10 , 0 , 0 , 2 , 2 , 0 ,
0 , 0 , 16 } ;
2019-11-23 22:05:24 +00:00
/*
This function prepares data after ART and CON have been processed .
It also initializes some data in loops rather than statically at compile time .
*/
void Menu_Init ( void )
{
// prepare menu fonts
// check if tilenum is -1 in case it was set in EVENT_SETDEFAULTS
if ( ( unsigned ) MF_Redfont . tilenum > = MAXTILES ) MF_Redfont . tilenum = BIGALPHANUM ;
if ( ( unsigned ) MF_Bluefont . tilenum > = MAXTILES ) MF_Bluefont . tilenum = STARTALPHANUM ;
if ( ( unsigned ) MF_Minifont . tilenum > = MAXTILES ) MF_Minifont . tilenum = MINIFONT ;
MF_Redfont . emptychar . y = tilesiz [ MF_Redfont . tilenum ] . y < < 16 ;
MF_Bluefont . emptychar . y = tilesiz [ MF_Bluefont . tilenum ] . y < < 16 ;
MF_Minifont . emptychar . y = tilesiz [ MF_Minifont . tilenum ] . y < < 16 ;
if ( ! minitext_lowercase )
MF_Minifont . textflags | = TEXT_UPPERCASE ;
#if 0
// prepare sound setup
# ifndef EDUKE32_STANDALONE
if ( WW2GI )
ME_SOUND_DUKETALK . name = " GI talk: " ;
else if ( NAM )
ME_SOUND_DUKETALK . name = " Grunt talk: " ;
# endif
// prepare shareware
if ( VOLUMEONE )
{
// blue out episodes beyond the first
for ( i = 1 ; i < g_volumeCnt ; + + i )
{
if ( MEL_EPISODE [ i ] )
{
ME_EPISODE [ i ] . entry = & MEO_EPISODE_SHAREWARE ;
ME_EPISODE [ i ] . flags | = MEF_LookDisabled ;
}
}
M_EPISODE . numEntries = g_volumeCnt ; // remove User Map (and spacer)
MEOS_NETOPTIONS_EPISODE . numOptions = 1 ;
MenuEntry_DisableOnCondition ( & ME_NETOPTIONS_EPISODE , 1 ) ;
}
// prepare pre-Atomic
if ( ! VOLUMEALL | | ! PLUTOPAK )
{
// prepare credits
M_CREDITS . title = M_CREDITS2 . title = M_CREDITS3 . title = s_Credits ;
}
2019-11-25 22:21:51 +00:00
2019-11-23 22:05:24 +00:00
# endif
}
2019-11-27 23:02:36 +00:00
static void Menu_DrawBackground ( const DVector2 & origin )
{
rotatesprite_fs ( int ( origin . X * 65536 ) + ( MENU_MARGIN_CENTER < < 16 ) , int ( origin . Y * 65536 ) + ( 100 < < 16 ) , 65536L , 0 , MENUSCREEN , 16 , 0 , 10 + 64 ) ;
}
2019-11-25 23:20:21 +00:00
static void Menu_DrawTopBar ( const DVector2 & origin )
2019-11-22 21:52:11 +00:00
{
if ( ( G_GetLogoFlags ( ) & LOGO_NOTITLEBAR ) = = 0 )
2019-11-25 23:20:21 +00:00
rotatesprite_fs ( int ( origin . X * 65536 ) + ( MENU_MARGIN_CENTER < < 16 ) , int ( origin . Y * 65536 ) + ( 19 < < 16 ) , MF_Redfont . cursorScale , 0 , MENUBAR , 16 , 0 , 10 ) ;
2019-11-22 21:52:11 +00:00
}
2019-11-25 23:20:21 +00:00
static void Menu_DrawTopBarCaption ( const char * caption , const DVector2 & origin )
2019-11-22 21:52:11 +00:00
{
static char t [ 64 ] ;
size_t const srclen = strlen ( caption ) ;
size_t const dstlen = min ( srclen , ARRAY_SIZE ( t ) - 1 ) ;
memcpy ( t , caption , dstlen ) ;
t [ dstlen ] = ' \0 ' ;
char * p = & t [ dstlen - 1 ] ;
if ( * p = = ' : ' )
* p = ' \0 ' ;
2019-11-25 23:20:21 +00:00
captionmenutext ( int ( origin . X * 65536 ) + ( MENU_MARGIN_CENTER < < 16 ) , int ( origin . Y * 65536 ) + ( 24 < < 16 ) + ( ( 15 > > 1 ) < < 16 ) , t ) ;
2019-11-22 21:52:11 +00:00
}
2019-11-23 16:50:36 +00:00
static void Menu_GetFmt ( const MenuFont_t * font , uint8_t const status , int32_t * s , int32_t * z )
2019-11-23 11:41:13 +00:00
{
2019-11-23 16:50:36 +00:00
if ( status & MT_Selected )
* s = VM_OnEventWithReturn ( EVENT_MENUSHADESELECTED , - 1 , myconnectindex , sintable [ ( ( int32_t ) totalclock < < 5 ) & 2047 ] > > 12 ) ;
else
* s = font - > shade_deselected ;
// sum shade values
if ( status & MT_Disabled )
* s + = font - > shade_disabled ;
2019-11-23 11:41:13 +00:00
2019-11-23 16:50:36 +00:00
if ( FURY & & status & MT_Selected )
* z + = ( * z > > 4 ) ;
2019-11-23 11:41:13 +00:00
}
2019-11-23 16:50:36 +00:00
static vec2_t Menu_Text ( int32_t x , int32_t y , const MenuFont_t * font , const char * t , uint8_t status , int32_t ydim_upper , int32_t ydim_lower )
2019-11-23 11:41:13 +00:00
{
2019-11-23 16:50:36 +00:00
int32_t s , p , ybetween = font - > between . y ;
int32_t f = font - > textflags ;
if ( status & MT_XCenter )
f | = TEXT_XCENTER ;
if ( status & MT_XRight )
f | = TEXT_XRIGHT ;
if ( status & MT_YCenter )
{
f | = TEXT_YCENTER | TEXT_YOFFSETZERO ;
ybetween = font - > emptychar . y ; // <^ the battle against 'Q'
}
if ( status & MT_Literal )
f | = TEXT_LITERALESCAPE ;
int32_t z = font - > zoom ;
if ( status & MT_Disabled )
p = ( status & MT_RightSide ) ? font - > pal_disabled_right : font - > pal_disabled ;
else if ( status & MT_Selected )
p = ( status & MT_RightSide ) ? font - > pal_selected_right : font - > pal_selected ;
else
2019-11-26 16:42:57 +00:00
p = ( status & MT_RightSide ) ? font - > pal_deselected_right : font - > pal_deselected ;
2019-11-23 16:50:36 +00:00
2019-11-26 16:42:57 +00:00
Menu_GetFmt ( font , status , & s , & z ) ;
2019-11-23 16:50:36 +00:00
2019-11-26 16:42:57 +00:00
return G_ScreenText ( font - > tilenum , x , y , z , 0 , 0 , t , s , p , 2 | 8 | 16 | ROTATESPRITE_FULL16 , 0 , font - > emptychar . x , font - > emptychar . y , font - > between . x , ybetween , f , 0 , ydim_upper , xdim - 1 , ydim_lower ) ;
2019-11-23 16:50:36 +00:00
}
2019-11-27 23:02:36 +00:00
static vec2_t mgametextcenterat ( int32_t x , int32_t y , char const * t , int32_t f = 0 )
{
return G_ScreenText ( MF_Bluefont . tilenum , x , y , MF_Bluefont . zoom , 0 , 0 , t , 0 , MF_Bluefont . pal , 2 | 8 | 16 | ROTATESPRITE_FULL16 , 0 , MF_Bluefont . emptychar . x , MF_Bluefont . emptychar . y , MF_Bluefont . between . x , MF_Bluefont . between . y , MF_Bluefont . textflags | f | TEXT_XCENTER , 0 , 0 , xdim - 1 , ydim - 1 ) ;
}
static vec2_t mgametextcenter ( int32_t x , int32_t y , char const * t , int32_t f = 0 )
{
return mgametextcenterat ( ( MENU_MARGIN_CENTER < < 16 ) + x , y , t , f ) ;
}
2019-11-23 16:50:36 +00:00
static int32_t Menu_CursorShade ( void )
{
return VM_OnEventWithReturn ( EVENT_MENUCURSORSHADE , - 1 , myconnectindex , 4 - ( sintable [ ( ( int32_t ) totalclock < < 4 ) & 2047 ] > > 11 ) ) ;
2019-11-23 11:41:13 +00:00
}
2019-11-23 16:50:36 +00:00
static void Menu_DrawCursorCommon ( int32_t x , int32_t y , int32_t z , int32_t picnum , int32_t ydim_upper = 0 , int32_t ydim_lower = ydim - 1 )
2019-11-23 11:41:13 +00:00
{
2019-11-23 16:50:36 +00:00
rotatesprite_ ( x , y , z , 0 , picnum , Menu_CursorShade ( ) , 0 , 2 | 8 , 0 , 0 , 0 , ydim_upper , xdim - 1 , ydim_lower ) ;
}
static void Menu_DrawCursorLeft ( int32_t x , int32_t y , int32_t z )
{
if ( FURY ) return ;
Menu_DrawCursorCommon ( x , y , z , VM_OnEventWithReturn ( EVENT_MENUCURSORLEFT , - 1 , myconnectindex , SPINNINGNUKEICON + ( ( ( int32_t ) totalclock > > 3 ) % 7 ) ) ) ;
}
static void Menu_DrawCursorRight ( int32_t x , int32_t y , int32_t z )
{
if ( FURY ) return ;
Menu_DrawCursorCommon ( x , y , z , VM_OnEventWithReturn ( EVENT_MENUCURSORRIGHT , - 1 , myconnectindex , SPINNINGNUKEICON + 6 - ( ( 6 + ( ( int32_t ) totalclock > > 3 ) ) % 7 ) ) ) ;
}
static int Menu_GetFontHeight ( int fontnum )
{
auto & font = fontnum = = NIT_BigFont ? MF_Redfont : fontnum = = NIT_SmallFont ? MF_Bluefont : MF_Minifont ;
return font . get_yline ( ) ;
}
2019-11-28 00:02:45 +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
//
//----------------------------------------------------------------------------
2019-11-22 21:52:11 +00:00
class DukeListMenu : public DListMenu
{
using Super = DListMenu ;
protected :
2019-11-27 22:35:12 +00:00
void SelectionChanged ( ) override
{
if ( mDesc - > mScriptId = = 110 )
{
// Hack alert: Ion Fury depends on the skill getting set globally when the selection changes because the script cannot detect actual selection changes.
// Yuck!
ud . m_player_skill = mDesc - > mSelectedItem + 1 ;
}
}
2019-11-22 21:52:11 +00:00
virtual void CallScript ( int event , bool getorigin = false )
{
2019-11-25 23:20:21 +00:00
ud . returnvar [ 0 ] = int ( origin . X * 65536 ) ;
ud . returnvar [ 1 ] = int ( origin . Y * 65536 ) ;
2019-11-22 21:52:11 +00:00
ud . returnvar [ 2 ] = mDesc - > mSelectedItem ;
VM_OnEventWithReturn ( event , g_player [ screenpeek ] . ps - > i , screenpeek , mDesc - > mScriptId ) ;
if ( getorigin )
{
2019-11-25 23:20:21 +00:00
origin . X = ud . returnvar [ 0 ] / 65536. ;
origin . Y = ud . returnvar [ 1 ] / 65536. ;
2019-11-22 21:52:11 +00:00
}
}
2019-11-23 16:50:36 +00:00
void Ticker ( ) override
{
2019-11-23 22:05:24 +00:00
auto lf = G_GetLogoFlags ( ) ;
help_disabled = ( lf & LOGO_NOHELP ) ;
credits_disabled = ( lf & LOGO_NOCREDITS ) ;
2019-11-23 16:50:36 +00:00
// Lay out the menu. Since scripts are allowed to mess around with the font this needs to be redone each frame.
int32_t y_upper = mDesc - > mYpos ;
int32_t y_lower = y_upper + mDesc - > mYbotton ;
int32_t y = 0 ;
int32_t calculatedentryspacing = 0 ;
int32_t const height = Menu_GetFontHeight ( mDesc - > mNativeFontNum ) > > 16 ;
int32_t totalheight = 0 , numvalidentries = mDesc - > mItems . Size ( ) ;
2019-11-23 22:05:24 +00:00
for ( unsigned e = 0 ; e < mDesc - > mItems . Size ( ) ; + + e )
2019-11-23 16:50:36 +00:00
{
2019-11-23 22:05:24 +00:00
auto entry = mDesc - > mItems [ e ] ;
entry - > mHidden = false ;
if ( entry - > GetAction ( nullptr ) = = NAME_HelpMenu & & help_disabled )
{
entry - > mHidden = true ;
numvalidentries - - ;
continue ;
}
else if ( entry - > GetAction ( nullptr ) = = NAME_CreditsMenu & & credits_disabled )
{
entry - > mHidden = true ;
numvalidentries - - ;
continue ;
}
2019-11-25 17:41:39 +00:00
entry - > SetHeight ( height ) ;
2019-11-23 16:50:36 +00:00
totalheight + = height ;
}
2019-11-24 21:31:27 +00:00
if ( mDesc - > mSpacing < = 0 ) calculatedentryspacing = std : : max ( 0 , ( y_lower - y_upper - totalheight ) / ( numvalidentries > 1 ? numvalidentries - 1 : 1 ) ) ;
if ( calculatedentryspacing < = 0 ) calculatedentryspacing = mDesc - > mSpacing ;
2019-11-23 16:50:36 +00:00
// totalHeight calculating pass
int totalHeight ;
2019-11-24 19:40:53 +00:00
for ( unsigned e = 0 ; e < mDesc - > mItems . Size ( ) ; + + e )
2019-11-23 16:50:36 +00:00
{
auto entry = mDesc - > mItems [ e ] ;
2019-11-23 22:05:24 +00:00
if ( ! entry - > mHidden )
{
entry - > SetY ( y_upper + y ) ;
y + = height ;
totalHeight = y ;
y + = calculatedentryspacing ;
}
2019-11-23 16:50:36 +00:00
}
}
2019-11-22 21:52:11 +00:00
void PreDraw ( ) override
{
2019-12-01 16:48:56 +00:00
CallScript ( CurrentMenu = = this ? EVENT_DISPLAYMENU : EVENT_DISPLAYINACTIVEMENU , true ) ;
2019-11-28 23:37:19 +00:00
Super : : PreDraw ( ) ;
2019-11-22 21:52:11 +00:00
}
void PostDraw ( ) override
{
CallScript ( CurrentMenu = = this ? EVENT_DISPLAYMENUREST : EVENT_DISPLAYINACTIVEMENUREST , false ) ;
}
} ;
class DukeNewGameCustomSubMenu : public DukeListMenu
{
virtual void CallScript ( int event , bool getorigin ) override
{
// This needs to get the secondary ID to the script.
ud . returnvar [ 3 ] = mDesc - > mSecondaryId ;
DukeListMenu : : CallScript ( event , getorigin ) ;
}
} ;
2019-12-01 14:31:08 +00:00
class DukeMainMenu : public DukeListMenu
2019-11-22 21:52:11 +00:00
{
void PreDraw ( ) override
{
DukeListMenu : : PreDraw ( ) ;
if ( ( G_GetLogoFlags ( ) & LOGO_NOGAMETITLE ) = = 0 )
{
2019-11-25 23:20:21 +00:00
rotatesprite_fs ( int ( origin . X * 65536 ) + ( MENU_MARGIN_CENTER < < 16 ) , int ( origin . Y * 65536 ) + ( ( 28 ) < < 16 ) , 65536L , 0 , INGAMEDUKETHREEDEE , 0 , 0 , 10 ) ;
2019-11-22 21:52:11 +00:00
if ( PLUTOPAK ) // JBF 20030804
2019-11-25 23:20:21 +00:00
rotatesprite_fs ( int ( origin . X * 65536 ) + ( ( MENU_MARGIN_CENTER + 100 ) < < 16 ) , int ( origin . Y * 65536 ) + ( 36 < < 16 ) , 65536L , 0 , PLUTOPAKSPRITE + 2 , ( sintable [ ( ( int32_t ) totalclock < < 4 ) & 2047 ] > > 11 ) , 0 , 2 + 8 ) ;
2019-11-22 21:52:11 +00:00
}
}
} ;
2019-12-01 16:48:56 +00:00
//----------------------------------------------------------------------------
//
// Hack to display Ion Fury's credits screens
//
//----------------------------------------------------------------------------
class DukeImageScreen : public ImageScreen
{
public :
DukeImageScreen ( FImageScrollerDescriptor : : ScrollerItem * desc )
: ImageScreen ( desc )
{ }
void CallScript ( int event , bool getorigin = false )
{
ud . returnvar [ 0 ] = int ( origin . X * 65536 ) ;
ud . returnvar [ 1 ] = int ( origin . Y * 65536 ) ;
ud . returnvar [ 2 ] = 0 ;
VM_OnEventWithReturn ( event , g_player [ screenpeek ] . ps - > i , screenpeek , mDesc - > scriptID ) ;
if ( getorigin )
{
origin . X = ud . returnvar [ 0 ] / 65536. ;
origin . Y = ud . returnvar [ 1 ] / 65536. ;
}
}
void Drawer ( ) override
{
// Hack alert: The Ion Fury scripts - being true to the entire design here, take the current menu value
// not from the passed variable but instead from the global current_menu, so we have to temporarily alter that here.
// Ugh. (Talk about "broken by design"...)
auto cm = g_currentMenu ;
g_currentMenu = mDesc - > scriptID ;
auto o = origin ;
CallScript ( EVENT_DISPLAYMENU , true ) ;
ImageScreen : : Drawer ( ) ;
CallScript ( EVENT_DISPLAYMENUREST , false ) ;
g_currentMenu = cm ;
origin = o ;
}
} ;
class DDukeImageScrollerMenu : public DImageScrollerMenu
{
ImageScreen * newImageScreen ( FImageScrollerDescriptor : : ScrollerItem * desc ) override
{
return new DukeImageScreen ( desc ) ;
}
} ;
2019-11-28 00:02:45 +00:00
//----------------------------------------------------------------------------
//
// Menu related game interface functions
//
//----------------------------------------------------------------------------
2019-12-01 14:31:08 +00:00
void GameInterface : : DrawNativeMenuText ( int fontnum , int state , double xpos , double ypos , float fontscale , const char * text , int flags )
{
int ydim_upper = 0 ;
int ydim_lower = ydim - 1 ;
//int32_t const indent = 0; // not set for any relevant menu
int x = int ( xpos * 65536 ) ;
uint8_t status = 0 ;
if ( state = = NIT_SelectedState )
status | = MT_Selected ;
if ( state = = NIT_InactiveState )
status | = MT_Disabled ;
if ( flags & LMF_Centered )
status | = MT_XCenter ;
bool const dodraw = true ;
MenuFont_t & font = fontnum = = NIT_BigFont ? MF_Redfont : fontnum = = NIT_SmallFont ? MF_Bluefont : MF_Minifont ;
int32_t const height = font . get_yline ( ) ;
status | = MT_YCenter ;
2019-12-01 16:48:56 +00:00
int32_t const y_internal = int ( ypos * 65536 ) + ( ( height > > 17 ) < < 16 ) ; // -menu->scrollPos;
2019-12-01 14:31:08 +00:00
vec2_t textsize ;
if ( dodraw )
textsize = Menu_Text ( x , y_internal , & font , text , status , ydim_upper , ydim_lower ) ;
if ( dodraw & & ( status & MT_Selected ) & & state ! = 1 )
{
if ( status & MT_XCenter )
{
Menu_DrawCursorLeft ( x + font . cursorCenterPosition , y_internal , font . cursorScale ) ;
Menu_DrawCursorRight ( x - font . cursorCenterPosition , y_internal , font . cursorScale ) ;
}
else
Menu_DrawCursorLeft ( x /*+ indent*/ - font . cursorLeftPosition , y_internal , font . cursorScale ) ;
}
}
2019-11-28 00:30:24 +00:00
2019-11-28 00:02:45 +00:00
void GameInterface : : MenuOpened ( )
2019-11-27 23:02:36 +00:00
{
2019-11-28 00:02:45 +00:00
S_PauseSounds ( true ) ;
if ( ( ! g_netServer & & ud . multimode < 2 ) )
{
ready2send = 0 ;
totalclock = ototalclock ;
screenpeek = myconnectindex ;
}
2019-11-30 00:03:14 +00:00
auto & gm = g_player [ myconnectindex ] . ps - > gm ;
if ( gm & MODE_GAME )
{
gm | = MODE_MENU ;
}
2019-11-28 00:02:45 +00:00
}
2019-11-27 23:02:36 +00:00
2019-11-29 00:28:13 +00:00
void GameInterface : : MenuSound ( EMenuSounds snd )
2019-11-28 00:02:45 +00:00
{
switch ( snd )
2019-11-27 23:02:36 +00:00
{
2019-11-29 00:28:13 +00:00
case CursorSound :
2019-12-16 23:29:38 +00:00
S_PlaySound ( KICK_HIT , CHAN_AUTO , CHANF_UI ) ;
2019-11-28 00:02:45 +00:00
break ;
2019-11-27 23:02:36 +00:00
2019-11-29 00:28:13 +00:00
case AdvanceSound :
2019-12-16 23:29:38 +00:00
S_PlaySound ( PISTOL_BODYHIT , CHAN_AUTO , CHANF_UI ) ;
2019-11-28 00:02:45 +00:00
break ;
2019-11-29 00:28:13 +00:00
case CloseSound :
2019-12-16 23:29:38 +00:00
S_PlaySound ( EXITMENUSOUND , CHAN_AUTO , CHANF_UI ) ;
2019-11-29 00:28:13 +00:00
break ;
2019-11-27 23:02:36 +00:00
2019-11-28 00:02:45 +00:00
default :
return ;
2019-11-27 23:02:36 +00:00
}
2019-11-28 00:02:45 +00:00
}
2019-11-27 23:02:36 +00:00
2019-11-28 00:02:45 +00:00
void GameInterface : : MenuClosed ( )
{
2019-11-30 00:03:14 +00:00
auto & gm = g_player [ myconnectindex ] . ps - > gm ;
if ( gm & MODE_GAME )
{
if ( gm & MODE_MENU )
I_ClearAllInput ( ) ;
// The following lines are here so that you cannot close the menu when no game is running.
gm & = ~ MODE_MENU ;
if ( ( ! g_netServer & & ud . multimode < 2 ) & & ud . recstat ! = 2 )
{
ready2send = 1 ;
totalclock = ototalclock ;
CAMERACLOCK = ( int32_t ) totalclock ;
CAMERADIST = 65536 ;
// Reset next-viewscreen-redraw counter.
// XXX: are there any other cases like that in need of handling?
if ( g_curViewscreen > = 0 )
actor [ g_curViewscreen ] . t_data [ 0 ] = ( int32_t ) totalclock ;
}
G_UpdateScreenArea ( ) ;
2019-11-28 00:02:45 +00:00
S_PauseSounds ( false ) ;
2019-11-30 00:03:14 +00:00
}
2019-11-28 00:02:45 +00:00
}
bool GameInterface : : CanSave ( )
{
if ( ud . recstat = = 2 ) return false ;
auto & myplayer = * g_player [ myconnectindex ] . ps ;
if ( sprite [ myplayer . i ] . extra < = 0 )
2019-11-27 23:02:36 +00:00
{
2019-11-28 00:02:45 +00:00
P_DoQuote ( QUOTE_SAVE_DEAD , & myplayer ) ;
return false ;
}
return true ;
}
void GameInterface : : CustomMenuSelection ( int menu , int item )
{
ud . returnvar [ 0 ] = item ;
ud . returnvar [ 1 ] = - 1 ;
VM_OnEventWithReturn ( EVENT_NEWGAMECUSTOM , - 1 , myconnectindex , menu ) ;
}
2019-11-27 23:02:36 +00:00
2019-11-28 00:02:45 +00:00
void GameInterface : : StartGame ( FGameStartup & gs )
{
int32_t skillsound = PISTOL_BODYHIT ;
switch ( gs . Skill )
{
case 0 :
skillsound = JIBBED_ACTOR6 ;
break ;
case 1 :
skillsound = BONUS_SPEECH1 ;
break ;
case 2 :
skillsound = DUKE_GETWEAPON2 ;
break ;
case 3 :
skillsound = JIBBED_ACTOR5 ;
break ;
}
ud . m_player_skill = gs . Skill + 1 ;
2019-12-16 08:19:04 +00:00
if ( menu_sounds & & skillsound > = 0 & & SoundEnabled ( ) )
2019-12-12 17:43:27 +00:00
{
2019-12-16 23:29:38 +00:00
S_PlaySound ( skillsound , CHAN_AUTO , CHANF_UI ) ;
2019-12-16 08:19:04 +00:00
while ( S_CheckSoundPlaying ( skillsound ) )
{
S_Update ( ) ;
gameHandleEvents ( ) ;
}
2019-12-12 17:43:27 +00:00
}
2019-11-28 00:02:45 +00:00
ud . m_respawn_monsters = ( gs . Skill = = 3 ) ;
ud . m_monsters_off = ud . monsters_off = 0 ;
ud . m_respawn_items = 0 ;
ud . m_respawn_inventory = 0 ;
ud . multimode = 1 ;
ud . m_volume_number = gs . Episode ;
2019-12-11 22:41:05 +00:00
m_level_number = gs . Level ;
2019-11-28 00:02:45 +00:00
G_NewGame_EnterLevel ( ) ;
}
FSavegameInfo GameInterface : : GetSaveSig ( )
{
return { SAVESIG_DN3D , MINSAVEVER_DN3D , SAVEVER_DN3D } ;
}
2019-11-28 23:37:19 +00:00
void GameInterface : : DrawMenuCaption ( const DVector2 & origin , const char * text )
{
Menu_DrawTopBar ( origin ) ;
Menu_DrawTopBarCaption ( text , origin ) ;
}
2019-11-28 00:02:45 +00:00
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
static void shadowminitext ( int32_t x , int32_t y , const char * t , int32_t p )
{
int32_t f = 0 ;
if ( ! minitext_lowercase )
f | = TEXT_UPPERCASE ;
G_ScreenTextShadow ( 1 , 1 , MINIFONT , x , y , 65536 , 0 , 0 , t , 0 , p , 2 | 8 | 16 | ROTATESPRITE_FULL16 , 0 , 4 < < 16 , 8 < < 16 , 1 < < 16 , 0 , f , 0 , 0 , xdim - 1 , ydim - 1 ) ;
}
//----------------------------------------------------------------------------
//
// allows the front end to override certain fullscreen image menus
// with custom implementations.
//
// This is needed because the credits screens in Duke Nukem
// are eithrr 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 = VOLUMEALL & & PLUTOPAK ;
int32_t m , l ;
if ( ! haveCredits )
{
if ( tilenum = = CREDITSTEXT1 )
2019-11-27 23:02:36 +00:00
{
2019-11-28 00:02:45 +00:00
Menu_DrawBackground ( origin ) ;
2019-11-27 23:02:36 +00:00
m = int ( origin . X * 65536 ) + ( 20 < < 16 ) ;
l = int ( origin . Y * 65536 ) + ( 33 < < 16 ) ;
2019-11-28 00:02:45 +00:00
2019-11-27 23:02:36 +00:00
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 ;
2019-11-28 00:02:45 +00:00
2019-11-27 23:02:36 +00:00
m = int ( origin . X * 65536 ) + ( 180 < < 16 ) ;
l = int ( origin . Y * 65536 ) + ( 33 < < 16 ) ;
2019-11-28 00:02:45 +00:00
2019-11-27 23:02:36 +00:00
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 ;
2019-11-28 00:02:45 +00:00
return true ;
}
else if ( tilenum = = CREDITSTEXT2__STATIC )
{
Menu_DrawBackground ( origin ) ;
2019-11-27 23:02:36 +00:00
m = int ( origin . X * 65536 ) + ( 20 < < 16 ) ;
l = int ( origin . Y * 65536 ) + ( 33 < < 16 ) ;
2019-11-28 00:02:45 +00:00
2019-11-27 23:02:36 +00:00
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 ;
2019-11-28 00:02:45 +00:00
2019-11-27 23:02:36 +00:00
m = int ( origin . X * 65536 ) + ( 160 < < 16 ) ;
l = int ( origin . Y * 65536 ) + ( 33 < < 16 ) ;
2019-11-28 00:02:45 +00:00
2019-11-27 23:02:36 +00:00
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 ;
2019-11-28 00:02:45 +00:00
return true ;
}
else if ( tilenum = = CREDITSTEXT3 )
{
Menu_DrawBackground ( origin ) ;
2019-11-27 23:02:36 +00:00
mgametextcenter ( int ( origin . X * 65536 ) , int ( origin . Y * 65536 ) + ( 50 < < 16 ) , " Duke Nukem 3D is a trademark of \n "
2019-11-28 00:02:45 +00:00
" 3D Realms Entertainment "
" \n "
" Duke Nukem 3D \n "
" (C) 1996 3D Realms Entertainment " ) ;
2019-11-27 23:02:36 +00:00
if ( VOLUMEONE )
{
mgametextcenter ( int ( origin . X * 65536 ) , int ( origin . Y * 65536 ) + ( 106 < < 16 ) , " Please read LICENSE.DOC for shareware \n "
2019-11-28 00:02:45 +00:00
" distribution grants and restrictions. " ) ;
2019-11-27 23:02:36 +00:00
}
mgametextcenter ( int ( origin . X * 65536 ) , int ( origin . Y * 65536 ) + ( ( VOLUMEONE ? 134 : 115 ) < < 16 ) , " Made in Dallas, Texas USA " ) ;
2019-11-28 00:02:45 +00:00
return true ;
2019-11-27 23:02:36 +00:00
}
}
2019-11-28 00:02:45 +00:00
return false ;
2019-11-23 22:05:24 +00:00
}
2019-12-05 22:17:55 +00:00
void GameInterface : : DrawCenteredTextScreen ( const DVector2 & origin , const char * text , int position , bool bg )
2019-11-23 22:05:24 +00:00
{
2019-12-05 22:17:55 +00:00
if ( bg ) Menu_DrawBackground ( origin ) ;
2019-12-06 17:36:49 +00:00
else
{
// Only used for the confirmation screen.
int lines = 1 ;
for ( int i = 0 ; text [ i ] ; i + + ) if ( text [ i ] = = ' \n ' ) lines + + ;
int height = lines * Menu_GetFontHeight ( NIT_SmallFont ) ;
position - = height > > 17 ;
Menu_DrawCursorLeft ( 160 < < 16 , 130 < < 16 , 65536 ) ;
}
2019-11-28 00:02:45 +00:00
mgametextcenter ( int ( origin . X * 65536 ) , int ( ( origin . Y + position ) * 65536 ) , text ) ;
2019-11-23 22:05:24 +00:00
}
2019-12-05 18:52:46 +00:00
void GameInterface : : DrawPlayerSprite ( const DVector2 & origin , bool onteam )
2019-12-04 00:38:51 +00:00
{
2019-12-05 18:52:46 +00:00
rotatesprite_fs ( int ( origin . X * 65536 ) + ( 260 < < 16 ) , int ( origin . Y * 65536 ) + ( ( 24 + ( tilesiz [ APLAYER ] . y > > 1 ) ) < < 16 ) , 49152L , 0 , 1441 - ( ( ( ( 4 - ( ( int32_t ) totalclock > > 4 ) ) ) & 3 ) * 5 ) , 0 , onteam ? G_GetTeamPalette ( playerteam ) : G_CheckPlayerColor ( playercolor ) , 10 ) ;
2019-12-04 00:38:51 +00:00
}
2019-11-26 22:20:54 +00:00
2019-12-06 17:36:49 +00:00
void GameInterface : : QuitToTitle ( )
{
g_player [ myconnectindex ] . ps - > gm = MODE_DEMO ;
if ( ud . recstat = = 1 )
G_CloseDemoWrite ( ) ;
artClearMapArt ( ) ;
}
2019-11-28 00:02:45 +00:00
END_DUKE_NS
2019-11-26 23:41:26 +00:00
2019-11-28 00:02:45 +00:00
//----------------------------------------------------------------------------
//
// Class registration
//
//----------------------------------------------------------------------------
2019-11-26 23:41:26 +00:00
2019-11-22 21:52:11 +00:00
2019-12-01 14:31:08 +00:00
static TMenuClassDescriptor < Duke : : DukeMainMenu > _mm ( " Duke.MainMenu " ) ;
2019-11-22 21:52:11 +00:00
static TMenuClassDescriptor < Duke : : DukeListMenu > _lm ( " Duke.ListMenu " ) ;
static TMenuClassDescriptor < Duke : : DukeNewGameCustomSubMenu > _ngcsm ( " Duke.NewGameCustomSubMenu " ) ;
2019-12-01 16:48:56 +00:00
static TMenuClassDescriptor < Duke : : DDukeImageScrollerMenu > _ism ( " Duke.ImageScrollerMenu " ) ;
2019-11-22 21:52:11 +00:00
void RegisterDukeMenus ( )
{
menuClasses . Push ( & _mm ) ;
menuClasses . Push ( & _lm ) ;
menuClasses . Push ( & _ngcsm ) ;
2019-12-01 16:48:56 +00:00
menuClasses . Push ( & _ism ) ;
2019-11-22 21:52:11 +00:00
}