2016-03-01 15:47:10 +00:00
/*
* * shared_sbar . cpp
* * Base status bar implementation
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright 1998 - 2006 Randy Heit
2017-03-25 17:31:53 +00:00
* * Copyright 2017 Christoph Oelckers
2016-03-01 15:47:10 +00:00
* * 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 <assert.h>
# include "templates.h"
# include "sbar.h"
# include "c_cvars.h"
# include "c_dispatch.h"
# include "c_console.h"
# include "v_video.h"
# include "w_wad.h"
# include "s_sound.h"
# include "gi.h"
# include "doomstat.h"
# include "g_level.h"
# include "d_net.h"
# include "d_player.h"
2016-09-20 08:27:53 +00:00
# include "serializer.h"
# include "r_utility.h"
2016-10-12 17:22:33 +00:00
# include "cmdlib.h"
2017-01-08 17:45:30 +00:00
# include "g_levellocals.h"
2017-04-12 23:12:04 +00:00
# include "vm.h"
2017-03-24 01:12:03 +00:00
# include "p_acs.h"
2017-03-25 17:31:53 +00:00
# include "sbarinfo.h"
2017-03-29 21:51:53 +00:00
# include "events.h"
2016-03-01 15:47:10 +00:00
# include "../version.h"
2016-03-24 00:46:11 +00:00
# define XHAIRSHRINKSIZE (1. / 18)
# define XHAIRPICKUPSIZE (2+XHAIRSHRINKSIZE)
2016-03-01 15:47:10 +00:00
# define POWERUPICONSIZE 32
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( DBaseStatusBar , false , true )
2016-11-05 16:08:54 +00:00
IMPLEMENT_POINTERS_START ( DBaseStatusBar )
IMPLEMENT_POINTER ( Messages [ 0 ] )
IMPLEMENT_POINTER ( Messages [ 1 ] )
IMPLEMENT_POINTER ( Messages [ 2 ] )
IMPLEMENT_POINTERS_END
2016-03-01 15:47:10 +00:00
EXTERN_CVAR ( Bool , am_showmonsters )
EXTERN_CVAR ( Bool , am_showsecrets )
EXTERN_CVAR ( Bool , am_showitems )
EXTERN_CVAR ( Bool , am_showtime )
EXTERN_CVAR ( Bool , am_showtotaltime )
EXTERN_CVAR ( Bool , noisedebug )
EXTERN_CVAR ( Int , con_scaletext )
2017-03-24 01:12:03 +00:00
EXTERN_CVAR ( Bool , vid_fps )
2017-03-28 20:51:37 +00:00
CVAR ( Int , hud_scale , 0 , CVAR_ARCHIVE ) ;
2016-03-01 15:47:10 +00:00
2016-09-06 17:48:14 +00:00
2016-03-01 15:47:10 +00:00
DBaseStatusBar * StatusBar ;
extern int setblocks ;
FTexture * CrosshairImage ;
static int CrosshairNum ;
CVAR ( Int , paletteflash , 0 , CVAR_ARCHIVE )
CVAR ( Flag , pf_hexenweaps , paletteflash , PF_HEXENWEAPONS )
CVAR ( Flag , pf_poison , paletteflash , PF_POISON )
CVAR ( Flag , pf_ice , paletteflash , PF_ICE )
CVAR ( Flag , pf_hazard , paletteflash , PF_HAZARD )
// Stretch status bar to full screen width?
2017-03-30 00:16:23 +00:00
CUSTOM_CVAR ( Int , st_scale , 0 , CVAR_ARCHIVE )
2017-03-29 17:23:40 +00:00
{
if ( self < - 1 )
{
self = - 1 ;
return ;
}
if ( StatusBar )
{
StatusBar - > SetScale ( ) ;
setsizeneeded = true ;
}
}
2017-03-30 00:16:23 +00:00
CUSTOM_CVAR ( Bool , hud_aspectscale , false , CVAR_ARCHIVE )
2016-03-01 15:47:10 +00:00
{
if ( StatusBar )
{
2017-03-29 17:23:40 +00:00
StatusBar - > SetScale ( ) ;
2016-03-01 15:47:10 +00:00
setsizeneeded = true ;
}
}
CVAR ( Int , crosshair , 0 , CVAR_ARCHIVE )
CVAR ( Bool , crosshairforce , false , CVAR_ARCHIVE )
CVAR ( Color , crosshaircolor , 0xff0000 , CVAR_ARCHIVE ) ;
CVAR ( Bool , crosshairhealth , true , CVAR_ARCHIVE ) ;
2016-08-04 23:43:56 +00:00
CVAR ( Float , crosshairscale , 1.0 , CVAR_ARCHIVE ) ;
2016-03-01 15:47:10 +00:00
CVAR ( Bool , crosshairgrow , false , CVAR_ARCHIVE ) ;
CUSTOM_CVAR ( Int , am_showmaplabel , 2 , CVAR_ARCHIVE )
{
if ( self < 0 | | self > 2 ) self = 2 ;
}
CVAR ( Bool , idmypos , false , 0 ) ;
//---------------------------------------------------------------------------
//
// Format the map name, include the map label if wanted
//
//---------------------------------------------------------------------------
void ST_FormatMapName ( FString & mapname , const char * mapnamecolor )
{
cluster_info_t * cluster = FindClusterInfo ( level . cluster ) ;
bool ishub = ( cluster ! = NULL & & ( cluster - > flags & CLUSTER_HUB ) ) ;
if ( am_showmaplabel = = 1 | | ( am_showmaplabel = = 2 & & ! ishub ) )
{
mapname < < level . MapName < < " : " ;
}
mapname < < mapnamecolor < < level . LevelName ;
}
2017-03-29 12:20:22 +00:00
DEFINE_ACTION_FUNCTION ( FLevelLocals , FormatMapName )
{
PARAM_SELF_STRUCT_PROLOGUE ( FLevelLocals ) ;
PARAM_INT ( cr ) ;
char mapnamecolor [ 3 ] = { ' \34 ' , char ( cr + ' A ' ) , 0 } ;
FString rets ;
ST_FormatMapName ( rets , mapnamecolor ) ;
ACTION_RETURN_STRING ( rets ) ;
}
2016-03-01 15:47:10 +00:00
//---------------------------------------------------------------------------
//
// Load crosshair definitions
//
//---------------------------------------------------------------------------
void ST_LoadCrosshair ( bool alwaysload )
{
int num = 0 ;
char name [ 16 ] , size ;
if ( ! crosshairforce & &
players [ consoleplayer ] . camera ! = NULL & &
players [ consoleplayer ] . camera - > player ! = NULL & &
players [ consoleplayer ] . camera - > player - > ReadyWeapon ! = NULL )
{
num = players [ consoleplayer ] . camera - > player - > ReadyWeapon - > Crosshair ;
}
if ( num = = 0 )
{
num = crosshair ;
}
if ( ! alwaysload & & CrosshairNum = = num & & CrosshairImage ! = NULL )
{ // No change.
return ;
}
if ( num = = 0 )
{
CrosshairNum = 0 ;
CrosshairImage = NULL ;
return ;
}
if ( num < 0 )
{
num = - num ;
}
size = ( SCREENWIDTH < 640 ) ? ' S ' : ' B ' ;
mysnprintf ( name , countof ( name ) , " XHAIR%c%d " , size , num ) ;
2018-03-25 18:26:16 +00:00
FTextureID texid = TexMan . CheckForTexture ( name , ETextureType : : MiscPatch , FTextureManager : : TEXMAN_TryAny | FTextureManager : : TEXMAN_ShortNameOnly ) ;
2016-03-01 15:47:10 +00:00
if ( ! texid . isValid ( ) )
{
mysnprintf ( name , countof ( name ) , " XHAIR%c1 " , size ) ;
2018-03-25 18:26:16 +00:00
texid = TexMan . CheckForTexture ( name , ETextureType : : MiscPatch , FTextureManager : : TEXMAN_TryAny | FTextureManager : : TEXMAN_ShortNameOnly ) ;
2016-03-01 15:47:10 +00:00
if ( ! texid . isValid ( ) )
{
2018-03-25 18:26:16 +00:00
texid = TexMan . CheckForTexture ( " XHAIRS1 " , ETextureType : : MiscPatch , FTextureManager : : TEXMAN_TryAny | FTextureManager : : TEXMAN_ShortNameOnly ) ;
2016-03-01 15:47:10 +00:00
}
}
CrosshairNum = num ;
CrosshairImage = TexMan [ texid ] ;
}
//---------------------------------------------------------------------------
//
// ST_Clear
//
//---------------------------------------------------------------------------
void ST_Clear ( )
{
if ( StatusBar ! = NULL )
{
StatusBar - > Destroy ( ) ;
StatusBar = NULL ;
}
CrosshairImage = NULL ;
CrosshairNum = 0 ;
}
2017-03-25 17:31:53 +00:00
//---------------------------------------------------------------------------
//
// create a new status bar
//
//---------------------------------------------------------------------------
2017-03-31 09:53:28 +00:00
static void CreateBaseStatusBar ( )
{
assert ( nullptr = = StatusBar ) ;
PClass * const statusBarClass = PClass : : FindClass ( " BaseStatusBar " ) ;
assert ( nullptr ! = statusBarClass ) ;
StatusBar = static_cast < DBaseStatusBar * > ( statusBarClass - > CreateNew ( ) ) ;
StatusBar - > SetSize ( 0 ) ;
}
2017-03-25 17:31:53 +00:00
void ST_CreateStatusBar ( bool bTitleLevel )
{
if ( StatusBar ! = NULL )
{
StatusBar - > Destroy ( ) ;
StatusBar = NULL ;
}
if ( bTitleLevel )
{
2017-03-31 09:53:28 +00:00
CreateBaseStatusBar ( ) ;
2017-03-25 17:31:53 +00:00
}
2017-03-26 23:02:10 +00:00
else
2017-03-25 17:31:53 +00:00
{
2017-03-26 23:02:10 +00:00
// The old rule of 'what came last wins' goes here, as well.
// If the most recent SBARINFO definition comes before a status bar class definition it will be picked,
// if the class is defined later, this will be picked. If both come from the same file, the class definition will win.
int sbarinfolump = Wads . CheckNumForName ( " SBARINFO " ) ;
int sbarinfofile = Wads . GetLumpFile ( sbarinfolump ) ;
if ( gameinfo . statusbarclassfile > = gameinfo . statusbarfile & & gameinfo . statusbarclassfile > = sbarinfofile )
2017-03-25 17:31:53 +00:00
{
2017-03-26 23:02:10 +00:00
auto cls = PClass : : FindClass ( gameinfo . statusbarclass ) ;
if ( cls ! = nullptr )
2017-03-25 17:31:53 +00:00
{
2017-03-26 23:02:10 +00:00
StatusBar = ( DBaseStatusBar * ) cls - > CreateNew ( ) ;
2017-03-25 17:31:53 +00:00
}
}
}
if ( StatusBar = = nullptr & & SBarInfoScript [ SCRIPT_CUSTOM ] ! = nullptr )
{
int cstype = SBarInfoScript [ SCRIPT_CUSTOM ] - > GetGameType ( ) ;
//Did the user specify a "base"
if ( cstype = = GAME_Any ) //Use the default, empty or custom.
{
StatusBar = CreateCustomStatusBar ( SCRIPT_CUSTOM ) ;
}
else
{
StatusBar = CreateCustomStatusBar ( SCRIPT_DEFAULT ) ;
}
2017-05-21 10:05:46 +00:00
// SBARINFO failed so try the current statusbarclass again.
if ( StatusBar = = nullptr )
{
auto cls = PClass : : FindClass ( gameinfo . statusbarclass ) ;
if ( cls ! = nullptr )
{
StatusBar = ( DBaseStatusBar * ) cls - > CreateNew ( ) ;
}
}
2017-03-25 17:31:53 +00:00
}
if ( StatusBar = = nullptr )
{
FName defname ;
if ( gameinfo . gametype & GAME_DoomChex ) defname = " DoomStatusBar " ;
else if ( gameinfo . gametype = = GAME_Heretic ) defname = " HereticStatusBar " ;
else if ( gameinfo . gametype = = GAME_Hexen ) defname = " HexenStatusBar " ;
else if ( gameinfo . gametype = = GAME_Strife ) defname = " StrifeStatusBar " ;
if ( defname ! = NAME_None )
{
auto cls = PClass : : FindClass ( defname ) ;
if ( cls ! = nullptr )
{
StatusBar = ( DBaseStatusBar * ) cls - > CreateNew ( ) ;
}
}
}
if ( StatusBar = = nullptr )
{
2017-03-31 09:53:28 +00:00
CreateBaseStatusBar ( ) ;
}
IFVIRTUALPTR ( StatusBar , DBaseStatusBar , Init )
{
VMValue params [ ] = { StatusBar } ;
2017-04-12 23:12:04 +00:00
VMCall ( func , params , 1 , nullptr , 0 ) ;
2017-03-25 17:31:53 +00:00
}
GC : : WriteBarrier ( StatusBar ) ;
StatusBar - > AttachToPlayer ( & players [ consoleplayer ] ) ;
StatusBar - > NewGame ( ) ;
}
2016-03-01 15:47:10 +00:00
//---------------------------------------------------------------------------
//
// Constructor
//
//---------------------------------------------------------------------------
2017-03-22 16:29:13 +00:00
DBaseStatusBar : : DBaseStatusBar ( )
2016-03-01 15:47:10 +00:00
{
CompleteBorder = false ;
Centering = false ;
FixedOrigin = false ;
2016-03-24 00:46:11 +00:00
CrosshairSize = 1. ;
2016-03-01 15:47:10 +00:00
memset ( Messages , 0 , sizeof ( Messages ) ) ;
Displacement = 0 ;
CPlayer = NULL ;
ShowLog = false ;
2017-03-25 17:31:53 +00:00
defaultScale = { ( double ) CleanXfac , ( double ) CleanYfac } ;
2017-03-22 16:29:13 +00:00
}
2018-06-17 11:35:25 +00:00
static void ValidateResolution ( int & hres , int & vres )
{
if ( hres = = 0 )
{
static const int HORIZONTAL_RESOLUTION_DEFAULT = 320 ;
hres = HORIZONTAL_RESOLUTION_DEFAULT ;
}
if ( vres = = 0 )
{
static const int VERTICAL_RESOLUTION_DEFAULT = 200 ;
vres = VERTICAL_RESOLUTION_DEFAULT ;
}
}
2017-03-29 17:23:40 +00:00
void DBaseStatusBar : : SetSize ( int reltop , int hres , int vres , int hhres , int hvres )
{
2018-06-17 11:35:25 +00:00
ValidateResolution ( hres , vres ) ;
2017-03-29 17:23:40 +00:00
BaseRelTop = reltop ;
BaseSBarHorizontalResolution = hres ;
BaseSBarVerticalResolution = vres ;
BaseHUDHorizontalResolution = hhres < 0 ? hres : hhres ;
BaseHUDVerticalResolution = hvres < 0 ? vres : hvres ;
SetDrawSize ( reltop , hres , vres ) ;
}
void DBaseStatusBar : : SetDrawSize ( int reltop , int hres , int vres )
2017-03-22 16:29:13 +00:00
{
2018-06-17 11:35:25 +00:00
ValidateResolution ( hres , vres ) ;
2017-03-22 16:29:13 +00:00
RelTop = reltop ;
2016-03-01 15:47:10 +00:00
HorizontalResolution = hres ;
2017-01-20 21:45:09 +00:00
VerticalResolution = vres ;
2017-03-25 20:40:17 +00:00
int x , y ;
V_CalcCleanFacs ( hres , vres , SCREENWIDTH , SCREENHEIGHT , & x , & y ) ;
defaultScale = { ( double ) x , ( double ) y } ;
2016-03-01 15:47:10 +00:00
2017-03-29 17:23:40 +00:00
SetScale ( ) ; // recalculate positioning info.
2016-03-01 15:47:10 +00:00
}
2017-03-29 17:23:40 +00:00
2017-03-22 16:29:13 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , SetSize )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
2017-03-29 17:23:40 +00:00
PARAM_INT ( rt ) ;
PARAM_INT ( vw ) ;
PARAM_INT ( vh ) ;
PARAM_INT_DEF ( hvw ) ;
PARAM_INT_DEF ( hvh ) ;
self - > SetSize ( rt , vw , vh , hvw , hvh ) ;
2017-03-22 16:29:13 +00:00
return 0 ;
}
2016-03-01 15:47:10 +00:00
//---------------------------------------------------------------------------
//
// PROP Destroy
//
//---------------------------------------------------------------------------
2017-01-12 21:49:18 +00:00
void DBaseStatusBar : : OnDestroy ( )
2016-03-01 15:47:10 +00:00
{
for ( size_t i = 0 ; i < countof ( Messages ) ; + + i )
{
2018-03-01 09:32:19 +00:00
DHUDMessageBase * msg = Messages [ i ] ;
2016-03-01 15:47:10 +00:00
while ( msg )
{
2018-03-01 09:32:19 +00:00
DHUDMessageBase * next = msg - > Next ;
2016-03-01 15:47:10 +00:00
msg - > Destroy ( ) ;
msg = next ;
}
Messages [ i ] = NULL ;
}
2017-01-12 21:49:18 +00:00
Super : : OnDestroy ( ) ;
2016-03-01 15:47:10 +00:00
}
//---------------------------------------------------------------------------
//
// PROC SetScaled
//
//---------------------------------------------------------------------------
2017-03-29 17:23:40 +00:00
void DBaseStatusBar : : SetScale ( )
2016-03-01 15:47:10 +00:00
{
2018-06-17 11:35:25 +00:00
ValidateResolution ( HorizontalResolution , VerticalResolution ) ;
2017-03-29 17:23:40 +00:00
int w = SCREENWIDTH ;
int h = SCREENHEIGHT ;
2017-03-30 00:16:23 +00:00
if ( st_scale < 0 | | ForcedScale )
2016-03-01 15:47:10 +00:00
{
2017-03-29 17:23:40 +00:00
// This is the classic fullscreen scale with aspect ratio compensation.
int sby = VerticalResolution - RelTop ;
float aspect = ActiveRatio ( w , h ) ;
2016-09-13 21:26:30 +00:00
if ( ! AspectTallerThanWide ( aspect ) )
2017-03-29 17:23:40 +00:00
{
// Wider or equal than 4:3
SBarTop = Scale ( sby , h , VerticalResolution ) ;
double width4_3 = w * 1.333 / aspect ;
ST_X = int ( ( w - width4_3 ) / 2 ) ;
2016-03-01 15:47:10 +00:00
}
else
{ // 5:4 resolution
2017-03-29 17:23:40 +00:00
ST_X = 0 ;
// this was far more obtuse before...
double height4_3 = h * aspect / 1.333 ;
SBarTop = int ( h - height4_3 + sby * height4_3 / VerticalResolution ) ;
2016-03-01 15:47:10 +00:00
}
Displacement = 0 ;
2017-03-29 17:23:40 +00:00
SBarScale . X = - 1 ;
ST_Y = 0 ;
2016-03-01 15:47:10 +00:00
}
2017-03-29 17:23:40 +00:00
else
{
// Since status bars and HUDs can be designed for non 320x200 screens this needs to be factored in here.
// The global scaling factors are for resources at 320x200, so if the actual ones are higher resolution
// the resulting scaling factor needs to be reduced accordingly.
2017-03-30 00:16:23 +00:00
int realscale = clamp ( ( 320 * GetUIScale ( st_scale ) ) / HorizontalResolution , 1 , w / HorizontalResolution ) ;
2017-03-21 19:09:09 +00:00
2017-03-30 00:16:23 +00:00
double realscaley = realscale * ( hud_aspectscale ? 1.2 : 1. ) ;
2017-03-21 19:09:09 +00:00
2017-03-29 17:23:40 +00:00
ST_X = ( w - HorizontalResolution * realscale ) / 2 ;
SBarTop = int ( h - RelTop * realscaley ) ;
if ( RelTop > 0 )
{
Displacement = double ( ( SBarTop * VerticalResolution / h ) - ( VerticalResolution - RelTop ) ) / RelTop / realscaley ;
}
else
{
Displacement = 0 ;
}
SBarScale . X = realscale ;
SBarScale . Y = realscaley ;
ST_Y = int ( h - VerticalResolution * realscaley ) ;
2017-03-21 19:09:09 +00:00
}
2016-03-01 15:47:10 +00:00
}
2017-03-25 17:31:53 +00:00
//---------------------------------------------------------------------------
//
// PROC GetHUDScale
//
//---------------------------------------------------------------------------
DVector2 DBaseStatusBar : : GetHUDScale ( ) const
{
int scale ;
if ( hud_scale < 0 | | ForcedScale ) // a negative value is the equivalent to the old boolean hud_scale. This can yield different values for x and y for higher resolutions.
{
return defaultScale ;
}
2017-03-30 00:16:23 +00:00
scale = GetUIScale ( hud_scale ) ;
2017-03-25 17:31:53 +00:00
2018-06-17 11:35:25 +00:00
int hres = HorizontalResolution ;
int vres = VerticalResolution ;
ValidateResolution ( hres , vres ) ;
2017-03-25 17:31:53 +00:00
// Since status bars and HUDs can be designed for non 320x200 screens this needs to be factored in here.
// The global scaling factors are for resources at 320x200, so if the actual ones are higher resolution
// the resulting scaling factor needs to be reduced accordingly.
2018-06-17 11:35:25 +00:00
int realscale = MAX < int > ( 1 , ( 320 * scale ) / hres ) ;
2017-03-30 00:16:23 +00:00
return { double ( realscale ) , double ( realscale * ( hud_aspectscale ? 1.2 : 1. ) ) } ;
2017-03-25 17:31:53 +00:00
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , GetHUDScale )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
ACTION_RETURN_VEC2 ( self - > GetHUDScale ( ) ) ;
}
//---------------------------------------------------------------------------
//
// PROC GetHUDScale
//
//---------------------------------------------------------------------------
2017-03-29 17:23:40 +00:00
void DBaseStatusBar : : BeginStatusBar ( int resW , int resH , int relTop , bool forceScaled )
2017-03-25 17:31:53 +00:00
{
2017-03-29 17:23:40 +00:00
SetDrawSize ( relTop < 0 ? BaseRelTop : relTop , resW < 0 ? BaseSBarHorizontalResolution : resW , resH < 0 ? BaseSBarVerticalResolution : resH ) ;
ForcedScale = forceScaled ;
2017-03-25 17:31:53 +00:00
fullscreenOffsets = false ;
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , BeginStatusBar )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_BOOL_DEF ( fs ) ;
2017-03-29 17:23:40 +00:00
PARAM_INT_DEF ( w ) ;
PARAM_INT_DEF ( h ) ;
PARAM_INT_DEF ( r ) ;
self - > BeginStatusBar ( w , h , r , fs ) ;
2017-03-25 17:31:53 +00:00
return 0 ;
}
//---------------------------------------------------------------------------
//
// PROC GetHUDScale
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : BeginHUD ( int resW , int resH , double Alpha , bool forcescaled )
{
2017-03-29 17:23:40 +00:00
SetDrawSize ( RelTop , resW < 0 ? BaseHUDHorizontalResolution : resW , resH < 0 ? BaseHUDVerticalResolution : resH ) ;
2017-03-25 17:31:53 +00:00
this - > Alpha = Alpha ;
ForcedScale = forcescaled ;
CompleteBorder = false ;
fullscreenOffsets = true ;
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , BeginHUD )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
2017-03-29 17:23:40 +00:00
PARAM_FLOAT_DEF ( a ) ;
2017-03-25 17:31:53 +00:00
PARAM_BOOL_DEF ( fs ) ;
2017-03-29 17:23:40 +00:00
PARAM_INT_DEF ( w ) ;
PARAM_INT_DEF ( h ) ;
2017-03-25 17:31:53 +00:00
self - > BeginHUD ( w , h , a , fs ) ;
return 0 ;
}
2016-03-01 15:47:10 +00:00
//---------------------------------------------------------------------------
//
// PROC AttachToPlayer
//
//---------------------------------------------------------------------------
2017-03-22 16:29:13 +00:00
void DBaseStatusBar : : AttachToPlayer ( player_t * player )
2016-03-01 15:47:10 +00:00
{
2017-03-21 19:09:09 +00:00
IFVIRTUAL ( DBaseStatusBar , AttachToPlayer )
{
VMValue params [ ] = { ( DObject * ) this , player } ;
2017-04-12 23:12:04 +00:00
VMCall ( func , params , countof ( params ) , nullptr , 0 ) ;
2017-03-21 19:09:09 +00:00
}
2016-03-01 15:47:10 +00:00
}
//---------------------------------------------------------------------------
//
2017-03-21 19:09:09 +00:00
// PROC GetPlayer
2016-03-01 15:47:10 +00:00
//
//---------------------------------------------------------------------------
2017-03-21 19:09:09 +00:00
int DBaseStatusBar : : GetPlayer ( )
2016-03-01 15:47:10 +00:00
{
2017-03-21 19:09:09 +00:00
return int ( CPlayer - players ) ;
2016-03-01 15:47:10 +00:00
}
//---------------------------------------------------------------------------
//
// PROC Tick
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : Tick ( )
{
for ( size_t i = 0 ; i < countof ( Messages ) ; + + i )
{
2018-03-01 09:32:19 +00:00
DHUDMessageBase * msg = Messages [ i ] ;
DHUDMessageBase * * prev = & Messages [ i ] ;
2016-03-01 15:47:10 +00:00
while ( msg )
{
2018-03-01 09:32:19 +00:00
DHUDMessageBase * next = msg - > Next ;
2016-03-01 15:47:10 +00:00
2018-03-01 10:45:19 +00:00
if ( msg - > CallTick ( ) )
2016-03-01 15:47:10 +00:00
{
* prev = next ;
msg - > Destroy ( ) ;
}
else
{
prev = & msg - > Next ;
}
msg = next ;
}
// If the crosshair has been enlarged, shrink it.
2016-03-24 00:46:11 +00:00
if ( CrosshairSize > 1. )
2016-03-01 15:47:10 +00:00
{
CrosshairSize - = XHAIRSHRINKSIZE ;
2016-03-24 00:46:11 +00:00
if ( CrosshairSize < 1. )
2016-03-01 15:47:10 +00:00
{
2016-03-24 00:46:11 +00:00
CrosshairSize = 1. ;
2016-03-01 15:47:10 +00:00
}
}
}
2017-03-27 19:01:40 +00:00
if ( artiflashTick > 0 )
artiflashTick - - ;
if ( itemflashFade > 0 )
{
itemflashFade - = 1 / 14. ;
if ( itemflashFade < 0 )
{
itemflashFade = 0 ;
}
}
2016-03-01 15:47:10 +00:00
}
2017-03-21 19:09:09 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , Tick )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
self - > Tick ( ) ;
return 0 ;
}
void DBaseStatusBar : : CallTick ( )
{
IFVIRTUAL ( DBaseStatusBar , Tick )
{
VMValue params [ ] = { ( DObject * ) this } ;
2017-04-12 23:12:04 +00:00
VMCall ( func , params , countof ( params ) , nullptr , 0 ) ;
2017-03-21 19:09:09 +00:00
}
else Tick ( ) ;
2017-03-25 00:22:42 +00:00
mugshot . Tick ( CPlayer ) ;
2017-03-21 19:09:09 +00:00
}
2016-03-01 15:47:10 +00:00
//---------------------------------------------------------------------------
//
// PROC AttachMessage
//
//---------------------------------------------------------------------------
2018-03-01 09:32:19 +00:00
void DBaseStatusBar : : AttachMessage ( DHUDMessageBase * msg , uint32_t id , int layer )
2016-03-01 15:47:10 +00:00
{
2018-03-01 09:32:19 +00:00
DHUDMessageBase * old = NULL ;
DHUDMessageBase * * prev ;
2016-03-01 15:47:10 +00:00
old = ( id = = 0 | | id = = 0xFFFFFFFF ) ? NULL : DetachMessage ( id ) ;
if ( old ! = NULL )
{
old - > Destroy ( ) ;
}
// Merge unknown layers into the default layer.
if ( ( size_t ) layer > = countof ( Messages ) )
{
layer = HUDMSGLayer_Default ;
}
prev = & Messages [ layer ] ;
// The ID serves as a priority, where lower numbers appear in front of
// higher numbers. (i.e. The list is sorted in descending order, since
// it gets drawn back to front.)
while ( * prev ! = NULL & & ( * prev ) - > SBarID > id )
{
prev = & ( * prev ) - > Next ;
}
msg - > Next = * prev ;
msg - > SBarID = id ;
* prev = msg ;
2018-04-16 11:44:45 +00:00
GC : : WriteBarrier ( msg ) ;
2016-03-01 15:47:10 +00:00
}
2018-03-01 10:45:19 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , AttachMessage )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_OBJECT ( msg , DHUDMessageBase ) ;
2018-03-07 14:00:08 +00:00
PARAM_UINT_DEF ( id ) ;
PARAM_INT_DEF ( layer ) ;
2018-03-01 10:45:19 +00:00
self - > AttachMessage ( msg , id , layer ) ;
return 0 ;
}
2016-03-01 15:47:10 +00:00
//---------------------------------------------------------------------------
//
// PROC DetachMessage
//
//---------------------------------------------------------------------------
2018-03-01 09:32:19 +00:00
DHUDMessageBase * DBaseStatusBar : : DetachMessage ( DHUDMessageBase * msg )
2016-03-01 15:47:10 +00:00
{
for ( size_t i = 0 ; i < countof ( Messages ) ; + + i )
{
2018-03-01 09:32:19 +00:00
DHUDMessageBase * probe = Messages [ i ] ;
DHUDMessageBase * * prev = & Messages [ i ] ;
2016-03-01 15:47:10 +00:00
while ( probe & & probe ! = msg )
{
prev = & probe - > Next ;
probe = probe - > Next ;
}
if ( probe ! = NULL )
{
* prev = probe - > Next ;
probe - > Next = NULL ;
return probe ;
}
}
return NULL ;
}
2018-03-01 10:45:19 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , DetachMessage )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_OBJECT ( msg , DHUDMessageBase ) ;
ACTION_RETURN_OBJECT ( self - > DetachMessage ( msg ) ) ;
}
2018-03-01 09:32:19 +00:00
DHUDMessageBase * DBaseStatusBar : : DetachMessage ( uint32_t id )
2016-03-01 15:47:10 +00:00
{
for ( size_t i = 0 ; i < countof ( Messages ) ; + + i )
{
2018-03-01 09:32:19 +00:00
DHUDMessageBase * probe = Messages [ i ] ;
DHUDMessageBase * * prev = & Messages [ i ] ;
2016-03-01 15:47:10 +00:00
while ( probe & & probe - > SBarID ! = id )
{
prev = & probe - > Next ;
probe = probe - > Next ;
}
if ( probe ! = NULL )
{
* prev = probe - > Next ;
probe - > Next = NULL ;
return probe ;
}
}
return NULL ;
}
2018-03-01 10:45:19 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , DetachMessageID )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_INT ( id ) ;
ACTION_RETURN_OBJECT ( self - > DetachMessage ( id ) ) ;
}
2016-03-01 15:47:10 +00:00
//---------------------------------------------------------------------------
//
// PROC DetachAllMessages
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : DetachAllMessages ( )
{
for ( size_t i = 0 ; i < countof ( Messages ) ; + + i )
{
2018-03-01 09:32:19 +00:00
DHUDMessageBase * probe = Messages [ i ] ;
2016-03-01 15:47:10 +00:00
Messages [ i ] = NULL ;
while ( probe ! = NULL )
{
2018-03-01 09:32:19 +00:00
DHUDMessageBase * next = probe - > Next ;
2016-03-01 15:47:10 +00:00
probe - > Destroy ( ) ;
probe = next ;
}
}
}
2018-03-01 10:45:19 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , DetachAllMessages )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
self - > DetachAllMessages ( ) ;
return 0 ;
}
2016-03-01 15:47:10 +00:00
//---------------------------------------------------------------------------
//
// PROC ShowPlayerName
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : ShowPlayerName ( )
{
EColorRange color ;
color = ( CPlayer = = & players [ consoleplayer ] ) ? CR_GOLD : CR_GREEN ;
2017-04-14 11:31:58 +00:00
AttachMessage ( Create < DHUDMessageFadeOut > ( SmallFont , CPlayer - > userinfo . GetName ( ) ,
2016-03-01 15:47:10 +00:00
1.5f , 0.92f , 0 , 0 , color , 2.f , 0.35f ) , MAKE_ID ( ' P ' , ' N ' , ' A ' , ' M ' ) ) ;
}
//---------------------------------------------------------------------------
//
// RefreshBackground
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : RefreshBackground ( ) const
{
2016-09-12 13:51:50 +00:00
int x , x2 , y ;
2016-03-01 15:47:10 +00:00
2016-09-12 13:51:50 +00:00
float ratio = ActiveRatio ( SCREENWIDTH , SCREENHEIGHT ) ;
2017-03-29 17:23:40 +00:00
x = ST_X ;
y = SBarTop ;
2016-03-01 15:47:10 +00:00
if ( ! CompleteBorder )
{
if ( y < SCREENHEIGHT )
{
2018-03-26 21:16:27 +00:00
screen - > DrawBorder ( x + 1 , y , SCREENWIDTH , y + 1 ) ;
screen - > DrawBorder ( x + 1 , SCREENHEIGHT - 1 , SCREENWIDTH , SCREENHEIGHT ) ;
2016-03-01 15:47:10 +00:00
}
}
else
{
x = SCREENWIDTH ;
}
if ( x > 0 )
{
if ( ! CompleteBorder )
{
2017-03-29 17:23:40 +00:00
x2 = SCREENWIDTH - ST_X ;
2016-03-01 15:47:10 +00:00
}
else
{
x2 = SCREENWIDTH ;
}
2018-03-26 21:16:27 +00:00
screen - > DrawBorder ( 0 , y , x + 1 , SCREENHEIGHT ) ;
screen - > DrawBorder ( x2 - 1 , y , SCREENWIDTH , SCREENHEIGHT ) ;
2016-03-01 15:47:10 +00:00
if ( setblocks > = 10 )
{
FTexture * p = TexMan [ gameinfo . Border . b ] ;
if ( p ! = NULL )
{
screen - > FlatFill ( 0 , y , x , y + p - > GetHeight ( ) , p , true ) ;
screen - > FlatFill ( x2 , y , SCREENWIDTH , y + p - > GetHeight ( ) , p , true ) ;
}
}
}
}
//---------------------------------------------------------------------------
//
// DrawCrosshair
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : DrawCrosshair ( )
{
2017-03-08 17:44:37 +00:00
uint32_t color ;
2016-03-24 00:46:11 +00:00
double size ;
2016-03-01 15:47:10 +00:00
int w , h ;
// Don't draw the crosshair in chasecam mode
if ( players [ consoleplayer ] . cheats & CF_CHASECAM )
return ;
ST_LoadCrosshair ( ) ;
// Don't draw the crosshair if there is none
2017-03-11 22:28:07 +00:00
if ( CrosshairImage = = NULL | | gamestate = = GS_TITLELEVEL | | r_viewpoint . camera - > health < = 0 )
2016-03-01 15:47:10 +00:00
{
return ;
}
2016-08-04 23:43:56 +00:00
if ( crosshairscale > 0.0f )
2016-03-01 15:47:10 +00:00
{
2016-08-04 23:43:56 +00:00
size = SCREENHEIGHT * crosshairscale / 200. ;
2016-03-01 15:47:10 +00:00
}
else
{
2016-03-24 00:46:11 +00:00
size = 1. ;
2016-03-01 15:47:10 +00:00
}
if ( crosshairgrow )
{
2016-03-24 00:46:11 +00:00
size * = CrosshairSize ;
2016-03-01 15:47:10 +00:00
}
2016-03-24 00:46:11 +00:00
w = int ( CrosshairImage - > GetWidth ( ) * size ) ;
h = int ( CrosshairImage - > GetHeight ( ) * size ) ;
2016-03-01 15:47:10 +00:00
if ( crosshairhealth )
{
int health = Scale ( CPlayer - > health , 100 , CPlayer - > mo - > GetDefault ( ) - > health ) ;
if ( health > = 85 )
{
color = 0x00ff00 ;
}
else
{
int red , green ;
health - = 25 ;
if ( health < 0 )
{
health = 0 ;
}
if ( health < 30 )
{
red = 255 ;
green = health * 255 / 30 ;
}
else
{
red = ( 60 - health ) * 255 / 30 ;
green = 255 ;
}
color = ( red < < 16 ) | ( green < < 8 ) ;
}
}
else
{
color = crosshaircolor ;
}
screen - > DrawTexture ( CrosshairImage ,
viewwidth / 2 + viewwindowx ,
viewheight / 2 + viewwindowy ,
DTA_DestWidth , w ,
DTA_DestHeight , h ,
DTA_AlphaChannel , true ,
2017-03-23 14:18:09 +00:00
DTA_FillColor , color & 0xFFFFFF ,
2016-03-01 15:47:10 +00:00
TAG_DONE ) ;
}
//---------------------------------------------------------------------------
//
// FlashCrosshair
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : FlashCrosshair ( )
{
CrosshairSize = XHAIRPICKUPSIZE ;
}
//---------------------------------------------------------------------------
//
// DrawMessages
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : DrawMessages ( int layer , int bottom )
{
2018-03-01 09:32:19 +00:00
DHUDMessageBase * msg = Messages [ layer ] ;
2016-03-01 15:47:10 +00:00
int visibility = 0 ;
if ( viewactive )
{
visibility | = HUDMSG_NotWith3DView ;
}
if ( automapactive )
{
visibility | = viewactive ? HUDMSG_NotWithOverlayMap : HUDMSG_NotWithFullMap ;
}
while ( msg )
{
2018-03-01 09:32:19 +00:00
DHUDMessageBase * next = msg - > Next ;
2018-03-01 10:45:19 +00:00
msg - > CallDraw ( bottom , visibility ) ;
2016-03-01 15:47:10 +00:00
msg = next ;
}
}
//---------------------------------------------------------------------------
//
// Draw
//
//---------------------------------------------------------------------------
2018-06-19 07:00:50 +00:00
void DBaseStatusBar : : Draw ( EHudState state , double ticFrac )
2016-03-01 15:47:10 +00:00
{
// HUD_AltHud state is for popups only
if ( state = = HUD_AltHud )
return ;
2017-03-21 19:09:09 +00:00
if ( state = = HUD_StatusBar )
2016-03-01 15:47:10 +00:00
{
RefreshBackground ( ) ;
}
if ( idmypos )
2017-03-29 21:51:53 +00:00
{
// Draw current coordinates
IFVIRTUAL ( DBaseStatusBar , DrawMyPos )
{
VMValue params [ ] = { ( DObject * ) this } ;
2017-04-12 23:12:04 +00:00
VMCall ( func , params , countof ( params ) , nullptr , 0 ) ;
2017-03-29 21:51:53 +00:00
}
2016-03-01 15:47:10 +00:00
}
if ( viewactive )
{
if ( CPlayer & & CPlayer - > camera & & CPlayer - > camera - > player )
{
DrawCrosshair ( ) ;
}
}
else if ( automapactive )
{
2017-03-29 12:20:22 +00:00
IFVIRTUAL ( DBaseStatusBar , DrawAutomapHUD )
2016-03-01 15:47:10 +00:00
{
2017-03-29 12:20:22 +00:00
VMValue params [ ] = { ( DObject * ) this , r_viewpoint . TicFrac } ;
2017-04-12 23:12:04 +00:00
VMCall ( func , params , countof ( params ) , nullptr , 0 ) ;
2016-03-01 15:47:10 +00:00
}
}
}
2017-03-21 19:09:09 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , Draw )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_INT ( state ) ;
2018-06-19 07:00:50 +00:00
PARAM_FLOAT ( ticFrac ) ;
self - > Draw ( ( EHudState ) state , ticFrac ) ;
2017-03-21 19:09:09 +00:00
return 0 ;
}
2018-06-19 07:00:50 +00:00
void DBaseStatusBar : : CallDraw ( EHudState state , double ticFrac )
2017-03-21 19:09:09 +00:00
{
IFVIRTUAL ( DBaseStatusBar , Draw )
{
2018-06-19 07:00:50 +00:00
VMValue params [ ] = { ( DObject * ) this , state , ticFrac } ;
2017-04-12 23:12:04 +00:00
VMCall ( func , params , countof ( params ) , nullptr , 0 ) ;
2017-03-21 19:09:09 +00:00
}
2018-06-19 07:00:50 +00:00
else Draw ( state , ticFrac ) ;
2017-03-28 11:06:24 +00:00
screen - > ClearClipRect ( ) ; // make sure the scripts don't leave a valid clipping rect behind.
2017-03-29 17:23:40 +00:00
BeginStatusBar ( BaseSBarHorizontalResolution , BaseSBarVerticalResolution , BaseRelTop , false ) ;
2017-03-21 19:09:09 +00:00
}
2016-03-01 15:47:10 +00:00
void DBaseStatusBar : : DrawLog ( )
{
int hudwidth , hudheight ;
if ( CPlayer - > LogText . IsNotEmpty ( ) )
{
// This uses the same scaling as regular HUD messages
2017-03-30 00:16:23 +00:00
auto scale = active_con_scaletext ( ) ;
hudwidth = SCREENWIDTH / scale ;
hudheight = SCREENHEIGHT / scale ;
2016-03-01 15:47:10 +00:00
int linelen = hudwidth < 640 ? Scale ( hudwidth , 9 , 10 ) - 40 : 560 ;
FBrokenLines * lines = V_BreakLines ( SmallFont , linelen , CPlayer - > LogText ) ;
int height = 20 ;
for ( int i = 0 ; lines [ i ] . Width ! = - 1 ; i + + ) height + = SmallFont - > GetHeight ( ) + 1 ;
int x , y , w ;
if ( linelen < 560 )
{
x = hudwidth / 20 ;
y = hudheight / 8 ;
w = hudwidth - 2 * x ;
}
else
{
x = ( hudwidth > > 1 ) - 300 ;
y = hudheight * 3 / 10 - ( height > > 1 ) ;
if ( y < 0 ) y = 0 ;
w = 600 ;
}
screen - > Dim ( 0 , 0.5f , Scale ( x , SCREENWIDTH , hudwidth ) , Scale ( y , SCREENHEIGHT , hudheight ) ,
Scale ( w , SCREENWIDTH , hudwidth ) , Scale ( height , SCREENHEIGHT , hudheight ) ) ;
x + = 20 ;
y + = 10 ;
for ( int i = 0 ; lines [ i ] . Width ! = - 1 ; i + + )
{
screen - > DrawText ( SmallFont , CR_UNTRANSLATED , x , y , lines [ i ] . Text ,
DTA_KeepRatio , true ,
DTA_VirtualWidth , hudwidth , DTA_VirtualHeight , hudheight , TAG_DONE ) ;
y + = SmallFont - > GetHeight ( ) + 1 ;
}
V_FreeBrokenLines ( lines ) ;
}
}
2017-03-21 19:09:09 +00:00
bool DBaseStatusBar : : MustDrawLog ( EHudState state )
2016-03-01 15:47:10 +00:00
{
2017-03-21 19:09:09 +00:00
IFVIRTUAL ( DBaseStatusBar , MustDrawLog )
{
2017-06-02 08:05:39 +00:00
VMValue params [ ] = { ( DObject * ) this , int ( state ) } ;
2017-03-21 19:09:09 +00:00
int rv ;
VMReturn ret ( & rv ) ;
2017-04-12 23:12:04 +00:00
VMCall ( func , params , countof ( params ) , & ret , 1 ) ;
2017-03-21 19:09:09 +00:00
return ! ! rv ;
}
2016-03-01 15:47:10 +00:00
return true ;
}
2017-03-25 17:31:53 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , SetMugshotState )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_STRING ( statename ) ;
PARAM_BOOL ( wait ) ;
PARAM_BOOL ( reset ) ;
self - > mugshot . SetState ( statename , wait , reset ) ;
return 0 ;
}
2016-03-01 15:47:10 +00:00
void DBaseStatusBar : : SetMugShotState ( const char * stateName , bool waitTillDone , bool reset )
{
2017-03-22 16:29:13 +00:00
IFVIRTUAL ( DBaseStatusBar , SetMugShotState )
{
FString statestring = stateName ;
VMValue params [ ] = { ( DObject * ) this , & statestring , waitTillDone , reset } ;
2017-04-12 23:12:04 +00:00
VMCall ( func , params , countof ( params ) , nullptr , 0 ) ;
2017-03-22 16:29:13 +00:00
}
2016-03-01 15:47:10 +00:00
}
//---------------------------------------------------------------------------
//
// DrawBottomStuff
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : DrawBottomStuff ( EHudState state )
{
2017-03-29 17:23:40 +00:00
DrawMessages ( HUDMSGLayer_UnderHUD , ( state = = HUD_StatusBar ) ? GetTopOfStatusbar ( ) : SCREENHEIGHT ) ;
2016-03-01 15:47:10 +00:00
}
//---------------------------------------------------------------------------
//
// DrawTopStuff
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : DrawTopStuff ( EHudState state )
{
if ( demoplayback & & demover ! = DEMOGAMEVERSION )
{
2017-03-29 17:23:40 +00:00
screen - > DrawText ( SmallFont , CR_TAN , 0 , GetTopOfStatusbar ( ) - 40 * CleanYfac ,
2016-03-01 15:47:10 +00:00
" Demo was recorded with a different version \n "
" of " GAMENAME " . Expect it to go out of sync. " ,
DTA_CleanNoMove , true , TAG_DONE ) ;
}
2017-03-24 21:57:44 +00:00
if ( state ! = HUD_AltHud )
{
auto saved = fullscreenOffsets ;
fullscreenOffsets = true ;
IFVIRTUAL ( DBaseStatusBar , DrawPowerups )
{
VMValue params [ ] = { ( DObject * ) this } ;
2017-04-12 23:12:04 +00:00
VMCall ( func , params , 1 , nullptr , 0 ) ;
2017-03-24 21:57:44 +00:00
}
fullscreenOffsets = saved ;
}
2016-03-01 15:47:10 +00:00
if ( automapactive & & ! viewactive )
{
2017-03-29 17:23:40 +00:00
DrawMessages ( HUDMSGLayer_OverMap , ( state = = HUD_StatusBar ) ? GetTopOfStatusbar ( ) : SCREENHEIGHT ) ;
2016-03-01 15:47:10 +00:00
}
2017-03-29 17:23:40 +00:00
DrawMessages ( HUDMSGLayer_OverHUD , ( state = = HUD_StatusBar ) ? GetTopOfStatusbar ( ) : SCREENHEIGHT ) ;
2017-03-29 21:51:53 +00:00
E_RenderOverlay ( state ) ;
2016-03-01 15:47:10 +00:00
DrawConsistancy ( ) ;
DrawWaiting ( ) ;
if ( ShowLog & & MustDrawLog ( state ) ) DrawLog ( ) ;
if ( noisedebug )
{
S_NoiseDebug ( ) ;
}
}
void DBaseStatusBar : : DrawConsistancy ( ) const
{
static bool firsttime = true ;
int i ;
char conbuff [ 64 ] , * buff_p ;
if ( ! netgame )
return ;
buff_p = NULL ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( playeringame [ i ] & & players [ i ] . inconsistant )
{
if ( buff_p = = NULL )
{
strcpy ( conbuff , " Out of sync with: " ) ;
buff_p = conbuff + 17 ;
}
* buff_p + + = ' ' ;
* buff_p + + = ' 1 ' + i ;
* buff_p = 0 ;
}
}
if ( buff_p ! = NULL )
{
if ( firsttime )
{
firsttime = false ;
if ( debugfile )
{
fprintf ( debugfile , " %s as of tic %d (%d) \n " , conbuff ,
players [ 1 - consoleplayer ] . inconsistant ,
players [ 1 - consoleplayer ] . inconsistant / ticdup ) ;
}
}
screen - > DrawText ( SmallFont , CR_GREEN ,
( screen - > GetWidth ( ) - SmallFont - > StringWidth ( conbuff ) * CleanXfac ) / 2 ,
0 , conbuff , DTA_CleanNoMove , true , TAG_DONE ) ;
}
}
void DBaseStatusBar : : DrawWaiting ( ) const
{
int i ;
char conbuff [ 64 ] , * buff_p ;
if ( ! netgame )
return ;
buff_p = NULL ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( playeringame [ i ] & & players [ i ] . waiting )
{
if ( buff_p = = NULL )
{
strcpy ( conbuff , " Waiting for: " ) ;
buff_p = conbuff + 12 ;
}
* buff_p + + = ' ' ;
* buff_p + + = ' 1 ' + i ;
* buff_p = 0 ;
}
}
if ( buff_p ! = NULL )
{
screen - > DrawText ( SmallFont , CR_ORANGE ,
( screen - > GetWidth ( ) - SmallFont - > StringWidth ( conbuff ) * CleanXfac ) / 2 ,
SmallFont - > GetHeight ( ) * CleanYfac , conbuff , DTA_CleanNoMove , true , TAG_DONE ) ;
}
}
void DBaseStatusBar : : FlashItem ( const PClass * itemtype )
{
2017-03-21 19:09:09 +00:00
IFVIRTUAL ( DBaseStatusBar , FlashItem )
{
VMValue params [ ] = { ( DObject * ) this , ( PClass * ) itemtype } ;
2017-04-12 23:12:04 +00:00
VMCall ( func , params , countof ( params ) , nullptr , 0 ) ;
2017-03-21 19:09:09 +00:00
}
2016-03-01 15:47:10 +00:00
}
void DBaseStatusBar : : NewGame ( )
{
2017-03-21 19:09:09 +00:00
IFVIRTUAL ( DBaseStatusBar , NewGame )
{
VMValue params [ ] = { ( DObject * ) this } ;
2017-04-12 23:12:04 +00:00
VMCall ( func , params , countof ( params ) , nullptr , 0 ) ;
2017-03-21 19:09:09 +00:00
}
2017-03-25 00:22:42 +00:00
mugshot . Reset ( ) ;
2016-03-01 15:47:10 +00:00
}
2017-03-22 16:29:13 +00:00
void DBaseStatusBar : : ShowPop ( int pop )
2017-03-21 19:09:09 +00:00
{
IFVIRTUAL ( DBaseStatusBar , ShowPop )
{
VMValue params [ ] = { ( DObject * ) this , pop } ;
2017-04-12 23:12:04 +00:00
VMCall ( func , params , countof ( params ) , nullptr , 0 ) ;
2017-03-21 19:09:09 +00:00
}
2016-03-01 15:47:10 +00:00
}
2017-03-21 19:09:09 +00:00
2016-09-20 08:27:53 +00:00
void DBaseStatusBar : : SerializeMessages ( FSerializer & arc )
2016-03-01 15:47:10 +00:00
{
2016-09-20 08:27:53 +00:00
arc . Array ( " hudmessages " , Messages , 3 , true ) ;
2016-03-01 15:47:10 +00:00
}
void DBaseStatusBar : : ScreenSizeChanged ( )
{
2017-03-25 20:40:17 +00:00
// We need to recalculate the sizing info
SetSize ( RelTop , HorizontalResolution , VerticalResolution ) ;
2017-03-24 01:12:03 +00:00
2016-03-01 15:47:10 +00:00
for ( size_t i = 0 ; i < countof ( Messages ) ; + + i )
{
2018-03-01 09:32:19 +00:00
DHUDMessageBase * message = Messages [ i ] ;
2016-03-01 15:47:10 +00:00
while ( message ! = NULL )
{
2018-03-01 10:45:19 +00:00
message - > CallScreenSizeChanged ( ) ;
2016-03-01 15:47:10 +00:00
message = message - > Next ;
}
}
}
2017-03-21 19:09:09 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , ScreenSizeChanged )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
self - > ScreenSizeChanged ( ) ;
return 0 ;
}
void DBaseStatusBar : : CallScreenSizeChanged ( )
{
IFVIRTUAL ( DBaseStatusBar , ScreenSizeChanged )
{
VMValue params [ ] = { ( DObject * ) this } ;
2017-04-12 23:12:04 +00:00
VMCall ( func , params , countof ( params ) , nullptr , 0 ) ;
2017-03-21 19:09:09 +00:00
}
else ScreenSizeChanged ( ) ;
}
2016-03-01 15:47:10 +00:00
//---------------------------------------------------------------------------
//
// ValidateInvFirst
//
// Returns an inventory item that, when drawn as the first item, is sure to
// include the selected item in the inventory bar.
//
//---------------------------------------------------------------------------
AInventory * DBaseStatusBar : : ValidateInvFirst ( int numVisible ) const
{
AInventory * item ;
int i ;
if ( CPlayer - > mo - > InvFirst = = NULL )
{
CPlayer - > mo - > InvFirst = CPlayer - > mo - > FirstInv ( ) ;
if ( CPlayer - > mo - > InvFirst = = NULL )
{ // Nothing to show
return NULL ;
}
}
assert ( CPlayer - > mo - > InvFirst - > Owner = = CPlayer - > mo ) ;
// If there are fewer than numVisible items shown, see if we can shift the
// view left to show more.
for ( i = 0 , item = CPlayer - > mo - > InvFirst ; item ! = NULL & & i < numVisible ; + + i , item = item - > NextInv ( ) )
{ }
while ( i < numVisible )
{
item = CPlayer - > mo - > InvFirst - > PrevInv ( ) ;
if ( item = = NULL )
{
break ;
}
else
{
CPlayer - > mo - > InvFirst = item ;
+ + i ;
}
}
if ( CPlayer - > mo - > InvSel = = NULL )
{
// Nothing selected, so don't move the view.
return CPlayer - > mo - > InvFirst = = NULL ? CPlayer - > mo - > Inventory : CPlayer - > mo - > InvFirst ;
}
else
{
// Check if InvSel is already visible
for ( item = CPlayer - > mo - > InvFirst , i = numVisible ;
item ! = NULL & & i ! = 0 ;
item = item - > NextInv ( ) , - - i )
{
if ( item = = CPlayer - > mo - > InvSel )
{
return CPlayer - > mo - > InvFirst ;
}
}
// Check if InvSel is to the right of the visible range
for ( i = 1 ; item ! = NULL ; item = item - > NextInv ( ) , + + i )
{
if ( item = = CPlayer - > mo - > InvSel )
{
// Found it. Now advance InvFirst
for ( item = CPlayer - > mo - > InvFirst ; i ! = 0 ; - - i )
{
item = item - > NextInv ( ) ;
}
return item ;
}
}
// Check if InvSel is to the left of the visible range
for ( item = CPlayer - > mo - > Inventory ;
item ! = CPlayer - > mo - > InvSel ;
item = item - > NextInv ( ) )
{ }
if ( item ! = NULL )
{
// Found it, so let it become the first item shown
return item ;
}
// Didn't find the selected item, so don't move the view.
// This should never happen, so let debug builds assert.
assert ( item ! = NULL ) ;
return CPlayer - > mo - > InvFirst ;
}
}
2017-03-21 19:09:09 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , ValidateInvFirst )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_INT ( num ) ;
ACTION_RETURN_POINTER ( self - > ValidateInvFirst ( num ) ) ;
}
2017-03-23 14:18:09 +00:00
uint32_t DBaseStatusBar : : GetTranslation ( ) const
{
if ( gameinfo . gametype & GAME_Raven )
return TRANSLATION ( TRANSLATION_PlayersExtra , int ( CPlayer - players ) ) ;
return TRANSLATION ( TRANSLATION_Players , int ( CPlayer - players ) ) ;
}
//============================================================================
//
// draw stuff
//
//============================================================================
2017-03-28 23:59:03 +00:00
void DBaseStatusBar : : StatusbarToRealCoords ( double & x , double & y , double & w , double & h ) const
{
2017-03-29 17:23:40 +00:00
if ( SBarScale . X = = - 1 | | ForcedScale )
2017-03-28 23:59:03 +00:00
{
2018-06-17 11:35:25 +00:00
int hres = HorizontalResolution ;
int vres = VerticalResolution ;
ValidateResolution ( hres , vres ) ;
screen - > VirtualToRealCoords ( x , y , w , h , hres , vres , true , true ) ;
2017-03-28 23:59:03 +00:00
}
else
{
2017-03-29 17:23:40 +00:00
x = ST_X + x * SBarScale . X ;
y = ST_Y + y * SBarScale . Y ;
w * = SBarScale . X ;
h * = SBarScale . Y ;
2017-03-28 23:59:03 +00:00
}
}
2017-03-29 12:20:22 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , StatusbarToRealCoords )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_FLOAT ( x ) ;
PARAM_FLOAT_DEF ( y ) ;
PARAM_FLOAT_DEF ( w ) ;
PARAM_FLOAT_DEF ( h ) ;
self - > StatusbarToRealCoords ( x , y , w , h ) ;
if ( numret > 0 ) ret [ 0 ] . SetFloat ( x ) ;
if ( numret > 1 ) ret [ 1 ] . SetFloat ( y ) ;
if ( numret > 2 ) ret [ 2 ] . SetFloat ( w ) ;
if ( numret > 3 ) ret [ 3 ] . SetFloat ( h ) ;
return MIN ( 4 , numret ) ;
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , GetTopOfStatusbar )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
2017-03-29 17:23:40 +00:00
ACTION_RETURN_INT ( self - > GetTopOfStatusbar ( ) ) ;
2017-03-29 12:20:22 +00:00
}
2017-03-28 23:59:03 +00:00
//============================================================================
//
// draw stuff
//
//============================================================================
2017-03-26 16:41:24 +00:00
void DBaseStatusBar : : DrawGraphic ( FTextureID texture , double x , double y , int flags , double Alpha , double boxwidth , double boxheight , double scaleX , double scaleY )
2017-03-23 14:18:09 +00:00
{
if ( ! texture . isValid ( ) )
return ;
2017-03-26 16:41:24 +00:00
FTexture * tex = ( flags & DI_DONTANIMATE ) ? TexMan [ texture ] : TexMan ( texture ) ;
double texwidth = tex - > GetScaledWidthDouble ( ) * scaleX ;
double texheight = tex - > GetScaledHeightDouble ( ) * scaleY ;
if ( boxwidth > 0 | | boxheight > 0 )
{
2017-03-27 19:01:40 +00:00
if ( ! ( flags & DI_FORCEFILL ) )
2017-03-26 16:41:24 +00:00
{
2017-03-27 19:01:40 +00:00
double scale1 = 1. , scale2 = 1. ;
2017-03-26 16:41:24 +00:00
2017-03-27 19:01:40 +00:00
if ( boxwidth > 0 & & ( boxwidth < texwidth | | ( flags & DI_FORCESCALE ) ) )
{
scale1 = boxwidth / texwidth ;
}
if ( boxheight ! = - 1 & & ( boxheight < texheight | | ( flags & DI_FORCESCALE ) ) )
{
scale2 = boxheight / texheight ;
}
2017-03-26 16:41:24 +00:00
2017-03-27 19:01:40 +00:00
if ( flags & DI_FORCESCALE )
{
if ( boxwidth < = 0 | | ( boxheight > 0 & & scale2 < scale1 ) )
scale1 = scale2 ;
}
else scale1 = MIN ( scale1 , scale2 ) ;
boxwidth = texwidth * scale1 ;
boxheight = texheight * scale1 ;
}
2017-03-26 16:41:24 +00:00
}
else
{
boxwidth = texwidth ;
boxheight = texheight ;
}
// resolve auto-alignment before making any adjustments to the position values.
if ( ! ( flags & DI_SCREEN_MANUAL_ALIGN ) )
{
if ( x < 0 ) flags | = DI_SCREEN_RIGHT ;
else flags | = DI_SCREEN_LEFT ;
if ( y < 0 ) flags | = DI_SCREEN_BOTTOM ;
else flags | = DI_SCREEN_TOP ;
}
2017-03-24 01:12:03 +00:00
Alpha * = this - > Alpha ;
if ( Alpha < = 0 ) return ;
x + = drawOffset . X ;
y + = drawOffset . Y ;
2017-03-26 16:41:24 +00:00
switch ( flags & DI_ITEM_HMASK )
2017-03-23 14:18:09 +00:00
{
2017-03-26 16:41:24 +00:00
case DI_ITEM_HCENTER : x - = boxwidth / 2 ; break ;
case DI_ITEM_RIGHT : x - = boxwidth ; break ;
2018-03-31 08:37:46 +00:00
case DI_ITEM_HOFFSET : x - = tex - > GetScaledLeftOffsetDouble ( 0 ) * boxwidth / texwidth ; break ;
2017-03-23 14:18:09 +00:00
}
2017-03-26 16:41:24 +00:00
switch ( flags & DI_ITEM_VMASK )
2017-03-23 14:18:09 +00:00
{
2017-03-26 23:02:10 +00:00
case DI_ITEM_VCENTER : y - = boxheight / 2 ; break ;
case DI_ITEM_BOTTOM : y - = boxheight ; break ;
2018-03-31 08:37:46 +00:00
case DI_ITEM_VOFFSET : y - = tex - > GetScaledTopOffsetDouble ( 0 ) * boxheight / texheight ; break ;
2017-03-23 14:18:09 +00:00
}
2017-03-24 01:12:03 +00:00
if ( ! fullscreenOffsets )
2017-03-23 14:18:09 +00:00
{
2017-03-28 23:59:03 +00:00
StatusbarToRealCoords ( x , y , boxwidth , boxheight ) ;
2017-03-23 14:18:09 +00:00
}
else
{
double orgx , orgy ;
2017-03-26 16:41:24 +00:00
switch ( flags & DI_SCREEN_HMASK )
2017-03-23 14:18:09 +00:00
{
default : orgx = 0 ; break ;
2017-03-26 16:41:24 +00:00
case DI_SCREEN_HCENTER : orgx = screen - > GetWidth ( ) / 2 ; break ;
case DI_SCREEN_RIGHT : orgx = screen - > GetWidth ( ) ; break ;
2017-03-23 14:18:09 +00:00
}
2017-03-26 16:41:24 +00:00
switch ( flags & DI_SCREEN_VMASK )
2017-03-23 14:18:09 +00:00
{
default : orgy = 0 ; break ;
2017-03-26 16:41:24 +00:00
case DI_SCREEN_VCENTER : orgy = screen - > GetHeight ( ) / 2 ; break ;
case DI_SCREEN_BOTTOM : orgy = screen - > GetHeight ( ) ; break ;
2017-03-23 14:18:09 +00:00
}
2017-03-26 16:41:24 +00:00
// move stuff in the top right corner a bit down if the fps counter is on.
if ( ( flags & ( DI_SCREEN_HMASK | DI_SCREEN_VMASK ) ) = = DI_SCREEN_RIGHT_TOP & & vid_fps ) y + = 10 ;
2017-03-23 14:18:09 +00:00
2017-03-25 17:31:53 +00:00
DVector2 Scale = GetHUDScale ( ) ;
x * = Scale . X ;
y * = Scale . Y ;
2017-03-26 16:41:24 +00:00
boxwidth * = Scale . X ;
boxheight * = Scale . Y ;
2017-03-23 14:18:09 +00:00
x + = orgx ;
y + = orgy ;
}
screen - > DrawTexture ( tex , x , y ,
DTA_TopOffset , 0 ,
DTA_LeftOffset , 0 ,
2017-03-26 16:41:24 +00:00
DTA_DestWidthF , boxwidth ,
DTA_DestHeightF , boxheight ,
DTA_TranslationIndex , ( flags & DI_TRANSLATABLE ) ? GetTranslation ( ) : 0 ,
DTA_ColorOverlay , ( flags & DI_DIM ) ? MAKEARGB ( 170 , 0 , 0 , 0 ) : 0 ,
2017-03-23 14:18:09 +00:00
DTA_Alpha , Alpha ,
2017-03-26 16:41:24 +00:00
DTA_AlphaChannel , ! ! ( flags & DI_ALPHAMAPPED ) ,
2017-04-02 08:38:59 +00:00
DTA_FillColor , ( flags & DI_ALPHAMAPPED ) ? 0 : - 1 ,
2018-03-22 12:22:39 +00:00
DTA_FlipX , ! ! ( flags & DI_MIRROR ) ,
2017-04-02 08:38:59 +00:00
TAG_DONE ) ;
2017-03-23 14:18:09 +00:00
}
2017-03-26 16:41:24 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , DrawTexture )
2017-03-23 14:18:09 +00:00
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_INT ( texid ) ;
PARAM_FLOAT ( x ) ;
PARAM_FLOAT ( y ) ;
2017-03-26 16:41:24 +00:00
PARAM_INT_DEF ( flags ) ;
PARAM_FLOAT_DEF ( alpha ) ;
PARAM_FLOAT_DEF ( w ) ;
PARAM_FLOAT_DEF ( h ) ;
PARAM_FLOAT_DEF ( scaleX ) ;
PARAM_FLOAT_DEF ( scaleY ) ;
2017-03-28 22:45:53 +00:00
if ( ! screen - > HasBegun2D ( ) ) ThrowAbortException ( X_OTHER , " Attempt to draw to screen outside a draw function " ) ;
2017-03-26 16:41:24 +00:00
self - > DrawGraphic ( FSetTextureID ( texid ) , x , y , flags , alpha , w , h , scaleX , scaleY ) ;
return 0 ;
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , DrawImage )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_STRING ( texid ) ;
PARAM_FLOAT ( x ) ;
PARAM_FLOAT ( y ) ;
PARAM_INT_DEF ( flags ) ;
PARAM_FLOAT_DEF ( alpha ) ;
PARAM_FLOAT_DEF ( w ) ;
PARAM_FLOAT_DEF ( h ) ;
PARAM_FLOAT_DEF ( scaleX ) ;
PARAM_FLOAT_DEF ( scaleY ) ;
2017-03-28 22:45:53 +00:00
if ( ! screen - > HasBegun2D ( ) ) ThrowAbortException ( X_OTHER , " Attempt to draw to screen outside a draw function " ) ;
2018-03-25 18:26:16 +00:00
self - > DrawGraphic ( TexMan . CheckForTexture ( texid , ETextureType : : Any ) , x , y , flags , alpha , w , h , scaleX , scaleY ) ;
2017-03-23 14:18:09 +00:00
return 0 ;
}
2017-03-24 01:38:44 +00:00
//============================================================================
//
2017-03-26 16:41:24 +00:00
// encapsulates all settings a HUD font may need
2017-03-24 01:38:44 +00:00
//
//============================================================================
2017-03-26 16:41:24 +00:00
class DHUDFont : public DObject
{
// this blocks CreateNew on this class which is the intent here.
DECLARE_ABSTRACT_CLASS ( DHUDFont , DObject ) ;
public :
FFont * mFont ;
int mSpacing ;
bool mMonospaced ;
int mShadowX ;
int mShadowY ;
DHUDFont ( FFont * f , int sp , bool ms , int sx , int sy )
: mFont ( f ) , mSpacing ( sp ) , mMonospaced ( ms ) , mShadowX ( sx ) , mShadowY ( sy )
{ }
} ;
IMPLEMENT_CLASS ( DHUDFont , true , false ) ;
DEFINE_ACTION_FUNCTION ( DHUDFont , Create )
2017-03-24 01:38:44 +00:00
{
2017-03-26 16:41:24 +00:00
PARAM_PROLOGUE ;
PARAM_POINTER ( fnt , FFont ) ;
PARAM_INT_DEF ( spac ) ;
PARAM_BOOL_DEF ( mono ) ;
PARAM_INT_DEF ( sx ) ;
PARAM_INT_DEF ( sy ) ;
2017-04-14 11:31:58 +00:00
ACTION_RETURN_POINTER ( Create < DHUDFont > ( fnt , spac , mono , sy , sy ) ) ;
2017-03-26 16:41:24 +00:00
}
2017-03-26 23:02:10 +00:00
DEFINE_FIELD ( DHUDFont , mFont ) ;
2017-03-26 16:41:24 +00:00
//============================================================================
//
// draw a string
//
//============================================================================
void DBaseStatusBar : : DrawString ( FFont * font , const FString & cstring , double x , double y , int flags , double Alpha , int translation , int spacing , bool monospaced , int shadowX , int shadowY )
{
switch ( flags & DI_TEXT_ALIGN )
2017-03-24 01:38:44 +00:00
{
default :
break ;
2017-03-26 16:41:24 +00:00
case DI_TEXT_ALIGN_RIGHT :
2017-03-24 01:38:44 +00:00
if ( ! monospaced )
x - = static_cast < int > ( font - > StringWidth ( cstring ) + ( spacing * cstring . Len ( ) ) ) ;
else //monospaced, so just multiply the character size
x - = static_cast < int > ( ( spacing ) * cstring . Len ( ) ) ;
break ;
2017-03-26 16:41:24 +00:00
case DI_TEXT_ALIGN_CENTER :
2017-03-24 01:38:44 +00:00
if ( ! monospaced )
x - = static_cast < int > ( font - > StringWidth ( cstring ) + ( spacing * cstring . Len ( ) ) ) / 2 ;
else //monospaced, so just multiply the character size
x - = static_cast < int > ( ( spacing ) * cstring . Len ( ) ) / 2 ;
break ;
}
2017-03-24 19:07:22 +00:00
const uint8_t * str = ( const uint8_t * ) cstring . GetChars ( ) ;
const EColorRange boldTranslation = EColorRange ( translation ? translation - 1 : NumTextColors - 1 ) ;
int fontcolor = translation ;
double orgx = 0 , orgy = 0 ;
2017-03-25 17:31:53 +00:00
DVector2 Scale ;
2017-03-24 19:07:22 +00:00
if ( fullscreenOffsets )
{
2017-03-25 17:31:53 +00:00
Scale = GetHUDScale ( ) ;
shadowX * = ( int ) Scale . X ;
shadowY * = ( int ) Scale . Y ;
2017-03-24 19:07:22 +00:00
2017-03-26 16:41:24 +00:00
switch ( flags & DI_SCREEN_HMASK )
2017-03-24 19:07:22 +00:00
{
default : orgx = 0 ; break ;
2017-03-26 16:41:24 +00:00
case DI_SCREEN_HCENTER : orgx = screen - > GetWidth ( ) / 2 ; break ;
case DI_SCREEN_RIGHT : orgx = screen - > GetWidth ( ) ; break ;
2017-03-24 19:07:22 +00:00
}
2017-03-26 16:41:24 +00:00
switch ( flags & DI_SCREEN_VMASK )
2017-03-24 19:07:22 +00:00
{
default : orgy = 0 ; break ;
2017-03-26 16:41:24 +00:00
case DI_SCREEN_VCENTER : orgy = screen - > GetHeight ( ) / 2 ; break ;
case DI_SCREEN_BOTTOM : orgy = screen - > GetHeight ( ) ; break ;
2017-03-24 19:07:22 +00:00
}
2017-03-26 16:41:24 +00:00
// move stuff in the top right corner a bit down if the fps counter is on.
if ( ( flags & ( DI_SCREEN_HMASK | DI_SCREEN_VMASK ) ) = = DI_SCREEN_RIGHT_TOP & & vid_fps ) y + = 10 ;
2017-03-24 19:07:22 +00:00
}
2017-03-25 17:31:53 +00:00
else
{
Scale = { 1. , 1. } ;
}
2017-03-24 19:07:22 +00:00
int ch ;
while ( ch = * str + + , ch ! = ' \0 ' )
{
if ( ch = = ' ' )
{
x + = monospaced ? spacing : font - > GetSpaceWidth ( ) + spacing ;
continue ;
}
else if ( ch = = TEXTCOLOR_ESCAPE )
{
EColorRange newColor = V_ParseFontColor ( str , translation , boldTranslation ) ;
if ( newColor ! = CR_UNDEFINED )
fontcolor = newColor ;
continue ;
}
int width ;
FTexture * c = font - > GetChar ( ( unsigned char ) ch , & width ) ;
if ( c = = NULL ) //missing character.
{
continue ;
}
if ( ! monospaced ) //If we are monospaced lets use the offset
2018-03-31 08:37:46 +00:00
x + = ( c - > GetLeftOffset ( 0 ) + 1 ) ; //ignore x offsets since we adapt to character size
2017-03-24 19:07:22 +00:00
double rx , ry , rw , rh ;
rx = x + drawOffset . X ;
ry = y + drawOffset . Y ;
rw = c - > GetScaledWidthDouble ( ) ;
rh = c - > GetScaledHeightDouble ( ) ;
if ( ! fullscreenOffsets )
{
2017-03-28 23:59:03 +00:00
StatusbarToRealCoords ( rx , ry , rw , rh ) ;
2017-03-24 19:07:22 +00:00
}
else
{
2017-03-25 17:31:53 +00:00
rx * = Scale . X ;
ry * = Scale . Y ;
rw * = Scale . X ;
rh * = Scale . Y ;
2017-03-24 19:07:22 +00:00
rx + = orgx ;
ry + = orgy ;
}
// This is not really such a great way to draw shadows because they can overlap with previously drawn characters.
// This may have to be changed to draw the shadow text up front separately.
2017-03-26 20:04:58 +00:00
if ( ( shadowX ! = 0 | | shadowY ! = 0 ) & & ! ( flags & DI_NOSHADOW ) )
2017-03-24 19:07:22 +00:00
{
screen - > DrawChar ( font , CR_UNTRANSLATED , rx + shadowX , ry + shadowY , ch ,
DTA_DestWidthF , rw ,
DTA_DestHeightF , rh ,
DTA_Alpha , ( Alpha * HR_SHADOW ) ,
DTA_FillColor , 0 ,
TAG_DONE ) ;
}
screen - > DrawChar ( font , fontcolor , rx , ry , ch ,
DTA_DestWidthF , rw ,
DTA_DestHeightF , rh ,
DTA_Alpha , Alpha ,
TAG_DONE ) ;
if ( ! monospaced )
2018-03-31 08:37:46 +00:00
x + = width + spacing - ( c - > GetLeftOffset ( 0 ) + 1 ) ;
2017-03-24 19:07:22 +00:00
else
x + = spacing ;
}
2017-03-24 01:38:44 +00:00
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , DrawString )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
2018-06-17 11:35:25 +00:00
PARAM_POINTER_NOT_NULL ( font , DHUDFont ) ;
2017-03-24 01:38:44 +00:00
PARAM_STRING ( string ) ;
PARAM_FLOAT ( x ) ;
PARAM_FLOAT ( y ) ;
2017-03-26 16:41:24 +00:00
PARAM_INT_DEF ( flags ) ;
PARAM_INT_DEF ( trans ) ;
PARAM_FLOAT_DEF ( alpha ) ;
2017-03-24 01:38:44 +00:00
PARAM_INT_DEF ( wrapwidth ) ;
PARAM_INT_DEF ( linespacing ) ;
2017-03-28 22:45:53 +00:00
if ( ! screen - > HasBegun2D ( ) ) ThrowAbortException ( X_OTHER , " Attempt to draw to screen outside a draw function " ) ;
2017-03-26 16:41:24 +00:00
// resolve auto-alignment before making any adjustments to the position values.
if ( ! ( flags & DI_SCREEN_MANUAL_ALIGN ) )
{
if ( x < 0 ) flags | = DI_SCREEN_RIGHT ;
else flags | = DI_SCREEN_LEFT ;
if ( y < 0 ) flags | = DI_SCREEN_BOTTOM ;
else flags | = DI_SCREEN_TOP ;
}
2017-03-24 01:38:44 +00:00
if ( wrapwidth > 0 )
{
2017-03-26 16:41:24 +00:00
FBrokenLines * brk = V_BreakLines ( font - > mFont , wrapwidth , string , true ) ;
2017-03-24 01:38:44 +00:00
for ( int i = 0 ; brk [ i ] . Width > = 0 ; i + + )
{
2017-03-26 16:41:24 +00:00
self - > DrawString ( font - > mFont , brk [ i ] . Text , x , y , flags , alpha , trans , font - > mSpacing , font - > mMonospaced , font - > mShadowX , font - > mShadowY ) ;
y + = font - > mFont - > GetHeight ( ) + linespacing ;
2017-03-24 01:38:44 +00:00
}
V_FreeBrokenLines ( brk ) ;
}
else
{
2017-03-26 16:41:24 +00:00
self - > DrawString ( font - > mFont , string , x , y , flags , alpha , trans , font - > mSpacing , font - > mMonospaced , font - > mShadowX , font - > mShadowY ) ;
2017-03-24 01:38:44 +00:00
}
return 0 ;
}
2017-03-28 09:00:05 +00:00
//============================================================================
//
// draw stuff
//
//============================================================================
2017-04-02 10:56:26 +00:00
void DBaseStatusBar : : TransformRect ( double & x , double & y , double & w , double & h , int flags )
2017-03-28 09:00:05 +00:00
{
// resolve auto-alignment before making any adjustments to the position values.
if ( ! ( flags & DI_SCREEN_MANUAL_ALIGN ) )
{
if ( x < 0 ) flags | = DI_SCREEN_RIGHT ;
else flags | = DI_SCREEN_LEFT ;
if ( y < 0 ) flags | = DI_SCREEN_BOTTOM ;
else flags | = DI_SCREEN_TOP ;
}
x + = drawOffset . X ;
y + = drawOffset . Y ;
if ( ! fullscreenOffsets )
{
2017-03-28 23:59:03 +00:00
StatusbarToRealCoords ( x , y , w , h ) ;
2017-03-28 09:00:05 +00:00
}
else
{
double orgx , orgy ;
switch ( flags & DI_SCREEN_HMASK )
{
default : orgx = 0 ; break ;
case DI_SCREEN_HCENTER : orgx = screen - > GetWidth ( ) / 2 ; break ;
case DI_SCREEN_RIGHT : orgx = screen - > GetWidth ( ) ; break ;
}
switch ( flags & DI_SCREEN_VMASK )
{
default : orgy = 0 ; break ;
case DI_SCREEN_VCENTER : orgy = screen - > GetHeight ( ) / 2 ; break ;
case DI_SCREEN_BOTTOM : orgy = screen - > GetHeight ( ) ; break ;
}
// move stuff in the top right corner a bit down if the fps counter is on.
if ( ( flags & ( DI_SCREEN_HMASK | DI_SCREEN_VMASK ) ) = = DI_SCREEN_RIGHT_TOP & & vid_fps ) y + = 10 ;
DVector2 Scale = GetHUDScale ( ) ;
x * = Scale . X ;
y * = Scale . Y ;
w * = Scale . X ;
h * = Scale . Y ;
x + = orgx ;
y + = orgy ;
}
2017-04-02 10:56:26 +00:00
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , TransformRect )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_FLOAT ( x ) ;
PARAM_FLOAT ( y ) ;
PARAM_FLOAT ( w ) ;
PARAM_FLOAT ( h ) ;
PARAM_INT_DEF ( flags ) ;
self - > TransformRect ( x , y , w , h , flags ) ;
if ( numret > 0 ) ret [ 0 ] . SetFloat ( x ) ;
if ( numret > 1 ) ret [ 1 ] . SetFloat ( y ) ;
if ( numret > 2 ) ret [ 2 ] . SetFloat ( w ) ;
if ( numret > 3 ) ret [ 3 ] . SetFloat ( h ) ;
return MIN ( 4 , numret ) ;
}
//============================================================================
//
// draw stuff
//
//============================================================================
void DBaseStatusBar : : Fill ( PalEntry color , double x , double y , double w , double h , int flags )
{
double Alpha = color . a * this - > Alpha / 255 ;
if ( Alpha < = 0 ) return ;
TransformRect ( x , y , w , h , flags ) ;
2017-03-29 00:24:04 +00:00
int x1 = int ( x ) ;
int y1 = int ( y ) ;
int ww = int ( x + w - x1 ) ; // account for scaling to non-integers. Truncating the values separately would fail for cases like
2017-04-02 10:56:26 +00:00
int hh = int ( y + h - y1 ) ; // y=3.5, height = 5.5 where adding both values gives a larger integer than adding the two integers.
2017-03-29 00:24:04 +00:00
screen - > Dim ( color , float ( Alpha ) , x1 , y1 , ww , hh ) ;
2017-03-28 09:00:05 +00:00
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , Fill )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_COLOR ( color ) ;
PARAM_FLOAT ( x ) ;
PARAM_FLOAT ( y ) ;
PARAM_FLOAT ( w ) ;
PARAM_FLOAT ( h ) ;
PARAM_INT_DEF ( flags ) ;
2017-03-28 22:45:53 +00:00
if ( ! screen - > HasBegun2D ( ) ) ThrowAbortException ( X_OTHER , " Attempt to draw to screen outside a draw function " ) ;
2017-03-30 10:13:28 +00:00
self - > Fill ( color , x , y , w , h , flags ) ;
return 0 ;
}
//============================================================================
//
// draw stuff
//
//============================================================================
void DBaseStatusBar : : SetClipRect ( double x , double y , double w , double h , int flags )
{
2017-04-02 10:56:26 +00:00
TransformRect ( x , y , w , h , flags ) ;
2017-03-30 10:13:28 +00:00
int x1 = int ( x ) ;
int y1 = int ( y ) ;
int ww = int ( x + w - x1 ) ; // account for scaling to non-integers. Truncating the values separately would fail for cases like
int hh = int ( y + h - y1 ) ; // y=3.5, height = 5.5 where adding both values gives a larger integer than adding the two integers.
screen - > SetClipRect ( x1 , y1 , ww , hh ) ;
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , SetClipRect )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_FLOAT ( x ) ;
PARAM_FLOAT ( y ) ;
PARAM_FLOAT ( w ) ;
PARAM_FLOAT ( h ) ;
PARAM_INT_DEF ( flags ) ;
self - > SetClipRect ( x , y , w , h , flags ) ;
2017-03-28 09:00:05 +00:00
return 0 ;
}
2016-03-01 15:47:10 +00:00
//============================================================================
//
// CCMD showpop
//
// Asks the status bar to show a pop screen.
//
//============================================================================
CCMD ( showpop )
{
if ( argv . argc ( ) ! = 2 )
{
Printf ( " Usage: showpop <popnumber> \n " ) ;
}
else if ( StatusBar ! = NULL )
{
int popnum = atoi ( argv [ 1 ] ) ;
if ( popnum < 0 )
{
popnum = 0 ;
}
2017-03-22 16:29:13 +00:00
StatusBar - > ShowPop ( popnum ) ;
2017-03-21 19:09:09 +00:00
}
}
DEFINE_FIELD ( DBaseStatusBar , RelTop ) ;
DEFINE_FIELD ( DBaseStatusBar , HorizontalResolution ) ;
DEFINE_FIELD ( DBaseStatusBar , VerticalResolution ) ;
DEFINE_FIELD ( DBaseStatusBar , Centering ) ;
DEFINE_FIELD ( DBaseStatusBar , FixedOrigin ) ;
DEFINE_FIELD ( DBaseStatusBar , CompleteBorder ) ;
DEFINE_FIELD ( DBaseStatusBar , CrosshairSize ) ;
DEFINE_FIELD ( DBaseStatusBar , Displacement ) ;
DEFINE_FIELD ( DBaseStatusBar , CPlayer ) ;
2017-03-22 16:29:13 +00:00
DEFINE_FIELD ( DBaseStatusBar , ShowLog ) ;
2017-03-24 01:12:03 +00:00
DEFINE_FIELD ( DBaseStatusBar , Alpha ) ;
DEFINE_FIELD ( DBaseStatusBar , drawOffset ) ;
DEFINE_FIELD ( DBaseStatusBar , drawClip ) ;
DEFINE_FIELD ( DBaseStatusBar , fullscreenOffsets ) ;
2017-03-25 17:31:53 +00:00
DEFINE_FIELD ( DBaseStatusBar , defaultScale ) ;
2017-03-27 19:01:40 +00:00
DEFINE_FIELD ( DBaseStatusBar , artiflashTick ) ;
DEFINE_FIELD ( DBaseStatusBar , itemflashFade ) ;
2017-03-22 16:29:13 +00:00
2017-03-21 19:09:09 +00:00
DEFINE_GLOBAL ( StatusBar ) ;
2017-03-22 18:56:21 +00:00
static DObject * InitObject ( PClass * type , int paramnum , VM_ARGS )
{
auto obj = type - > CreateNew ( ) ;
// Todo: init
return obj ;
}
2017-03-24 01:12:03 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , GetGlobalACSString )
{
PARAM_PROLOGUE ;
PARAM_INT ( index ) ;
ACTION_RETURN_STRING ( FBehavior : : StaticLookupString ( ACS_GlobalVars [ index ] ) ) ;
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , GetGlobalACSArrayString )
{
PARAM_PROLOGUE ;
PARAM_INT ( arrayno ) ;
PARAM_INT ( index ) ;
ACTION_RETURN_STRING ( FBehavior : : StaticLookupString ( ACS_GlobalArrays [ arrayno ] [ index ] ) ) ;
}
2017-03-24 19:07:22 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , GetGlobalACSValue )
{
PARAM_PROLOGUE ;
PARAM_INT ( index ) ;
ACTION_RETURN_INT ( ACS_GlobalVars [ index ] ) ;
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , GetGlobalACSArrayValue )
{
PARAM_PROLOGUE ;
PARAM_INT ( arrayno ) ;
PARAM_INT ( index ) ;
ACTION_RETURN_INT ( ACS_GlobalArrays [ arrayno ] [ index ] ) ;
}
enum ENumFlags
{
2018-01-07 22:04:51 +00:00
FNF_WHENNOTZERO = 0x1 ,
FNF_FILLZEROS = 0x2 ,
2017-03-24 19:07:22 +00:00
} ;
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , FormatNumber )
{
PARAM_PROLOGUE ;
PARAM_INT ( number ) ;
2017-03-26 16:41:24 +00:00
PARAM_INT_DEF ( minsize ) ;
PARAM_INT_DEF ( maxsize ) ;
PARAM_INT_DEF ( flags ) ;
2017-03-24 19:07:22 +00:00
PARAM_STRING_DEF ( prefix ) ;
static int maxvals [ ] = { 1 , 9 , 99 , 999 , 9999 , 99999 , 999999 , 9999999 , 99999999 , 999999999 } ;
if ( number = = 0 & & ( flags & FNF_WHENNOTZERO ) ) ACTION_RETURN_STRING ( " " ) ;
if ( maxsize > 0 & & maxsize < 10 )
{
number = clamp ( number , - maxvals [ maxsize - 1 ] , maxvals [ maxsize ] ) ;
}
FString fmt ;
if ( minsize < = 1 ) fmt . Format ( " %s%d " , prefix . GetChars ( ) , number ) ;
else if ( flags & FNF_FILLZEROS ) fmt . Format ( " %s%0*d " , prefix . GetChars ( ) , minsize , number ) ;
else fmt . Format ( " %s%*d " , prefix . GetChars ( ) , minsize , number ) ;
ACTION_RETURN_STRING ( fmt ) ;
}
2017-03-25 00:22:42 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , ReceivedWeapon )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
self - > mugshot . Grin ( ) ;
return 0 ;
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , GetMugshot )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_INT ( accuracy ) ;
PARAM_INT_DEF ( stateflags ) ;
2017-03-26 20:04:58 +00:00
PARAM_STRING_DEF ( def_face ) ;
auto tex = self - > mugshot . GetFace ( self - > CPlayer , def_face , accuracy , ( FMugShot : : StateFlags ) stateflags ) ;
2017-03-25 00:22:42 +00:00
ACTION_RETURN_INT ( tex ? tex - > id . GetIndex ( ) : - 1 ) ;
}
2017-03-26 23:02:10 +00:00