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 "m_swap.h"
# include "w_wad.h"
# include "v_text.h"
# include "s_sound.h"
# include "gi.h"
# include "doomstat.h"
# include "g_level.h"
# include "d_net.h"
# include "colormatcher.h"
# include "v_palette.h"
# include "d_player.h"
2016-09-20 08:27:53 +00:00
# include "serializer.h"
2016-03-01 15:47:10 +00:00
# include "gstrings.h"
2016-09-20 08:27:53 +00:00
# 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-01-15 22:21:38 +00:00
# include "virtual.h"
2017-03-24 01:12:03 +00:00
# include "p_acs.h"
2017-03-23 14:18:09 +00:00
# include "r_data/r_translate.h"
2017-03-25 17:31:53 +00:00
# include "sbarinfo.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-25 17:31:53 +00:00
CVAR ( Int , hud_scale , - 1 , CVAR_ARCHIVE ) ;
2016-03-01 15:47:10 +00:00
2016-09-07 09:34:49 +00:00
int active_con_scaletext ( ) ;
2016-09-06 17:48:14 +00:00
2016-03-01 15:47:10 +00:00
DBaseStatusBar * StatusBar ;
extern int setblocks ;
2017-03-25 17:31:53 +00:00
int gST_Y ;
2016-03-01 15:47:10 +00:00
FTexture * CrosshairImage ;
static int CrosshairNum ;
// [RH] Base blending values (for e.g. underwater)
int BaseBlendR , BaseBlendG , BaseBlendB ;
float BaseBlendA ;
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?
CUSTOM_CVAR ( Bool , st_scale , true , CVAR_ARCHIVE )
{
if ( StatusBar )
{
2017-03-21 19:09:09 +00:00
StatusBar - > CallSetScaled ( self ) ;
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 ) ;
2016-11-11 09:18:39 +00:00
CVAR ( Float , underwater_fade_scalar , 1.0f , CVAR_ARCHIVE ) // [Nash] user-settable underwater blend intensity
2016-03-01 15:47:10 +00:00
//---------------------------------------------------------------------------
//
// 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 ;
}
//---------------------------------------------------------------------------
//
// 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 ( CrosshairImage ! = NULL )
{
CrosshairImage - > Unload ( ) ;
}
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 ) ;
FTextureID texid = TexMan . CheckForTexture ( name , FTexture : : TEX_MiscPatch , FTextureManager : : TEXMAN_TryAny | FTextureManager : : TEXMAN_ShortNameOnly ) ;
if ( ! texid . isValid ( ) )
{
mysnprintf ( name , countof ( name ) , " XHAIR%c1 " , size ) ;
texid = TexMan . CheckForTexture ( name , FTexture : : TEX_MiscPatch , FTextureManager : : TEXMAN_TryAny | FTextureManager : : TEXMAN_ShortNameOnly ) ;
if ( ! texid . isValid ( ) )
{
texid = TexMan . CheckForTexture ( " XHAIRS1 " , FTexture : : TEX_MiscPatch , FTextureManager : : TEXMAN_TryAny | FTextureManager : : TEXMAN_ShortNameOnly ) ;
}
}
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
//
//---------------------------------------------------------------------------
void ST_CreateStatusBar ( bool bTitleLevel )
{
if ( StatusBar ! = NULL )
{
StatusBar - > Destroy ( ) ;
StatusBar = NULL ;
}
if ( bTitleLevel )
{
StatusBar = new DBaseStatusBar ( ) ;
StatusBar - > SetSize ( 0 ) ;
}
else if ( gameinfo . statusbarclassfile > = gameinfo . statusbarfile )
{
auto cls = PClass : : FindClass ( gameinfo . statusbarclass ) ;
if ( cls ! = nullptr )
{
StatusBar = ( DBaseStatusBar * ) cls - > CreateNew ( ) ;
IFVIRTUALPTR ( StatusBar , DBaseStatusBar , Init )
{
VMValue params [ ] = { StatusBar } ;
GlobalVMStack . Call ( func , params , 1 , nullptr , 0 ) ;
}
}
}
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 ) ;
}
}
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 ( ) ;
IFVIRTUALPTR ( StatusBar , DBaseStatusBar , Init )
{
VMValue params [ ] = { StatusBar } ;
GlobalVMStack . Call ( func , params , 1 , nullptr , 0 ) ;
}
}
}
}
if ( StatusBar = = nullptr )
{
StatusBar = new DBaseStatusBar ( ) ;
StatusBar - > SetSize ( 0 ) ;
}
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
}
void DBaseStatusBar : : SetSize ( int reltop , int hres , int vres )
{
RelTop = reltop ;
2016-03-01 15:47:10 +00:00
HorizontalResolution = hres ;
2017-01-20 21:45:09 +00:00
VerticalResolution = vres ;
2016-03-01 15:47:10 +00:00
2017-03-22 16:29:13 +00:00
CallSetScaled ( st_scale ) ;
2016-03-01 15:47:10 +00:00
}
2017-03-22 16:29:13 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , SetSize )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_INT_DEF ( rt ) ;
PARAM_INT_DEF ( vw ) ;
PARAM_INT_DEF ( vh ) ;
self - > SetSize ( rt , vw , vh ) ;
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 )
{
DHUDMessage * msg = Messages [ i ] ;
while ( msg )
{
DHUDMessage * next = msg - > Next ;
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
//
//---------------------------------------------------------------------------
//[BL] Added force argument to have forcescaled mean forcescaled.
2017-01-20 21:45:09 +00:00
// - Also, if the VerticalResolution is something other than the default (200)
2016-03-01 15:47:10 +00:00
// We should always obey the value of scale.
void DBaseStatusBar : : SetScaled ( bool scale , bool force )
{
Scaled = ( RelTop ! = 0 | | force ) & & ( ( SCREENWIDTH ! = 320 | | HorizontalResolution ! = 320 ) & & scale ) ;
if ( ! Scaled )
{
ST_X = ( SCREENWIDTH - HorizontalResolution ) / 2 ;
ST_Y = SCREENHEIGHT - RelTop ;
2017-01-20 09:51:21 +00:00
gST_Y = ST_Y ;
2016-03-01 15:47:10 +00:00
if ( RelTop > 0 )
{
2017-01-20 21:45:09 +00:00
Displacement = double ( ( ST_Y * VerticalResolution / SCREENHEIGHT ) - ( VerticalResolution - RelTop ) ) / RelTop ;
2016-03-01 15:47:10 +00:00
}
else
{
Displacement = 0 ;
}
}
else
{
ST_X = 0 ;
2017-01-20 21:45:09 +00:00
ST_Y = VerticalResolution - RelTop ;
2016-09-12 13:51:50 +00:00
float aspect = ActiveRatio ( SCREENWIDTH , SCREENHEIGHT ) ;
2016-09-13 21:26:30 +00:00
if ( ! AspectTallerThanWide ( aspect ) )
2016-03-01 15:47:10 +00:00
{ // Normal resolution
2017-01-20 21:45:09 +00:00
gST_Y = Scale ( ST_Y , SCREENHEIGHT , VerticalResolution ) ;
2016-03-01 15:47:10 +00:00
}
else
{ // 5:4 resolution
2017-01-20 21:45:09 +00:00
gST_Y = Scale ( ST_Y - VerticalResolution / 2 , SCREENHEIGHT * 3 , Scale ( VerticalResolution , AspectBaseHeight ( aspect ) , 200 ) ) + SCREENHEIGHT / 2
2016-09-12 13:51:50 +00:00
+ ( SCREENHEIGHT - SCREENHEIGHT * AspectMultiplier ( aspect ) / 48 ) / 2 ;
2016-03-01 15:47:10 +00:00
}
Displacement = 0 ;
}
2017-03-21 19:09:09 +00:00
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , SetScaled )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_BOOL ( scale ) ;
PARAM_BOOL_DEF ( force ) ;
self - > SetScaled ( scale , force ) ;
return 0 ;
}
void DBaseStatusBar : : CallSetScaled ( bool scale , bool force )
{
IFVIRTUAL ( DBaseStatusBar , SetScaled )
{
VMValue params [ ] = { ( DObject * ) this , scale , force } ;
GlobalVMStack . Call ( func , params , countof ( params ) , nullptr , 0 ) ;
}
else SetScaled ( scale , force ) ;
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 ;
}
if ( hud_scale > 0 ) // use the scale as an absolute value, but also factor in the specified resolution of the HUD
{
scale = hud_scale ;
}
else if ( uiscale = = 0 )
{
return defaultScale ;
}
else
{
scale = MAX < int > ( 1 , uiscale ) ;
}
// 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.
int realscale = MAX < int > ( 1 , ( 320 * scale ) / HorizontalResolution ) ;
return { double ( realscale ) , double ( realscale ) } ;
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , GetHUDScale )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
ACTION_RETURN_VEC2 ( self - > GetHUDScale ( ) ) ;
}
//---------------------------------------------------------------------------
//
// PROC GetHUDScale
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : BeginStatusBar ( int resW , int resH , int relTop , bool completeborder , bool forceScaled )
{
SetSize ( relTop , resW , resH ) ;
SetScaled ( st_scale , forceScaled ) ;
CompleteBorder = completeborder ;
fullscreenOffsets = false ;
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , BeginStatusBar )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_INT ( w ) ;
PARAM_INT ( h ) ;
PARAM_INT ( r ) ;
PARAM_BOOL_DEF ( cb ) ;
PARAM_BOOL_DEF ( fs ) ;
self - > BeginStatusBar ( w , h , r , cb , fs ) ;
return 0 ;
}
//---------------------------------------------------------------------------
//
// PROC GetHUDScale
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : BeginHUD ( int resW , int resH , double Alpha , bool forcescaled )
{
SetSize ( 0 , resW , resH ) ; // this intentionally resets the relative top to force the caller to go through BeginStatusBar and not just reset some variables.
this - > Alpha = Alpha ;
ForcedScale = forcescaled ;
CompleteBorder = false ;
fullscreenOffsets = true ;
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , BeginHUD )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_INT ( w ) ;
PARAM_INT ( h ) ;
PARAM_FLOAT ( a ) ;
PARAM_BOOL_DEF ( fs ) ;
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 } ;
GlobalVMStack . Call ( func , params , countof ( params ) , nullptr , 0 ) ;
}
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 )
{
DHUDMessage * msg = Messages [ i ] ;
DHUDMessage * * prev = & Messages [ i ] ;
while ( msg )
{
DHUDMessage * next = msg - > Next ;
if ( msg - > Tick ( ) )
{
* 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-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 } ;
GlobalVMStack . Call ( func , params , countof ( params ) , nullptr , 0 ) ;
}
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
//
//---------------------------------------------------------------------------
2017-03-08 17:44:37 +00:00
void DBaseStatusBar : : AttachMessage ( DHUDMessage * msg , uint32_t id , int layer )
2016-03-01 15:47:10 +00:00
{
DHUDMessage * old = NULL ;
DHUDMessage * * prev ;
DObject * container = this ;
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 )
{
container = * prev ;
prev = & ( * prev ) - > Next ;
}
msg - > Next = * prev ;
msg - > SBarID = id ;
* prev = msg ;
GC : : WriteBarrier ( container , msg ) ;
}
//---------------------------------------------------------------------------
//
// PROC DetachMessage
//
//---------------------------------------------------------------------------
DHUDMessage * DBaseStatusBar : : DetachMessage ( DHUDMessage * msg )
{
for ( size_t i = 0 ; i < countof ( Messages ) ; + + i )
{
DHUDMessage * probe = Messages [ i ] ;
DHUDMessage * * prev = & Messages [ i ] ;
while ( probe & & probe ! = msg )
{
prev = & probe - > Next ;
probe = probe - > Next ;
}
if ( probe ! = NULL )
{
* prev = probe - > Next ;
probe - > Next = NULL ;
return probe ;
}
}
return NULL ;
}
2017-03-08 17:44:37 +00:00
DHUDMessage * DBaseStatusBar : : DetachMessage ( uint32_t id )
2016-03-01 15:47:10 +00:00
{
for ( size_t i = 0 ; i < countof ( Messages ) ; + + i )
{
DHUDMessage * probe = Messages [ i ] ;
DHUDMessage * * prev = & Messages [ i ] ;
while ( probe & & probe - > SBarID ! = id )
{
prev = & probe - > Next ;
probe = probe - > Next ;
}
if ( probe ! = NULL )
{
* prev = probe - > Next ;
probe - > Next = NULL ;
return probe ;
}
}
return NULL ;
}
//---------------------------------------------------------------------------
//
// PROC DetachAllMessages
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : DetachAllMessages ( )
{
for ( size_t i = 0 ; i < countof ( Messages ) ; + + i )
{
DHUDMessage * probe = Messages [ i ] ;
Messages [ i ] = NULL ;
while ( probe ! = NULL )
{
DHUDMessage * next = probe - > Next ;
probe - > Destroy ( ) ;
probe = next ;
}
}
}
//---------------------------------------------------------------------------
//
// PROC ShowPlayerName
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : ShowPlayerName ( )
{
EColorRange color ;
color = ( CPlayer = = & players [ consoleplayer ] ) ? CR_GOLD : CR_GREEN ;
AttachMessage ( new DHUDMessageFadeOut ( SmallFont , CPlayer - > userinfo . GetName ( ) ,
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 ) ;
x = ( ratio < 1.5f | | ! Scaled ) ? ST_X : SCREENWIDTH * ( 48 - AspectMultiplier ( ratio ) ) / ( 48 * 2 ) ;
2017-01-20 09:51:21 +00:00
y = x = = ST_X & & x > 0 ? ST_Y : gST_Y ;
2016-03-01 15:47:10 +00:00
if ( ! CompleteBorder )
{
if ( y < SCREENHEIGHT )
{
V_DrawBorder ( x + 1 , y , SCREENWIDTH , y + 1 ) ;
V_DrawBorder ( x + 1 , SCREENHEIGHT - 1 , SCREENWIDTH , SCREENHEIGHT ) ;
}
}
else
{
x = SCREENWIDTH ;
}
if ( x > 0 )
{
if ( ! CompleteBorder )
{
2016-09-12 13:51:50 +00:00
x2 = ratio < 1.5f | | ! Scaled ? ST_X + HorizontalResolution :
SCREENWIDTH - ( SCREENWIDTH * ( 48 - AspectMultiplier ( ratio ) ) + 48 * 2 - 1 ) / ( 48 * 2 ) ;
2016-03-01 15:47:10 +00:00
}
else
{
x2 = SCREENWIDTH ;
}
V_DrawBorder ( 0 , y , x + 1 , SCREENHEIGHT ) ;
V_DrawBorder ( x2 - 1 , y , SCREENWIDTH , SCREENHEIGHT ) ;
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 ) ;
}
}
}
}
2017-03-21 19:09:09 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , RefreshBackground )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
self - > RefreshBackground ( ) ;
return 0 ;
}
2016-03-01 15:47:10 +00:00
//---------------------------------------------------------------------------
//
// 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 )
{
DHUDMessage * msg = Messages [ layer ] ;
int visibility = 0 ;
if ( viewactive )
{
visibility | = HUDMSG_NotWith3DView ;
}
if ( automapactive )
{
visibility | = viewactive ? HUDMSG_NotWithOverlayMap : HUDMSG_NotWithFullMap ;
}
while ( msg )
{
DHUDMessage * next = msg - > Next ;
msg - > Draw ( bottom , visibility ) ;
msg = next ;
}
}
//---------------------------------------------------------------------------
//
// Draw
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : Draw ( EHudState state )
{
// HUD_AltHud state is for popups only
if ( state = = HUD_AltHud )
return ;
char line [ 64 + 10 ] ;
2017-03-21 19:09:09 +00:00
if ( state = = HUD_StatusBar )
2016-03-01 15:47:10 +00:00
{
RefreshBackground ( ) ;
}
if ( idmypos )
{ // Draw current coordinates
int height = SmallFont - > GetHeight ( ) ;
char labels [ 3 ] = { ' X ' , ' Y ' , ' Z ' } ;
int i ;
int vwidth ;
int vheight ;
int xpos ;
int y ;
2016-09-07 09:34:49 +00:00
if ( active_con_scaletext ( ) = = 1 )
2016-03-01 15:47:10 +00:00
{
vwidth = SCREENWIDTH ;
vheight = SCREENHEIGHT ;
xpos = vwidth - 80 ;
2017-01-20 09:51:21 +00:00
y = gST_Y - height ;
2016-03-01 15:47:10 +00:00
}
2016-09-07 09:34:49 +00:00
else if ( active_con_scaletext ( ) > 1 )
2016-08-04 23:43:56 +00:00
{
2016-09-07 09:34:49 +00:00
vwidth = SCREENWIDTH / active_con_scaletext ( ) ;
vheight = SCREENHEIGHT / active_con_scaletext ( ) ;
2016-08-04 23:43:56 +00:00
xpos = vwidth - SmallFont - > StringWidth ( " X: -00000 " ) - 6 ;
2017-01-20 09:51:21 +00:00
y = gST_Y / 4 - height ;
2016-08-04 23:43:56 +00:00
}
2016-03-01 15:47:10 +00:00
else
{
vwidth = SCREENWIDTH / 2 ;
vheight = SCREENHEIGHT / 2 ;
xpos = vwidth - SmallFont - > StringWidth ( " X: -00000 " ) - 6 ;
2017-01-20 09:51:21 +00:00
y = gST_Y / 2 - height ;
2016-03-01 15:47:10 +00:00
}
if ( gameinfo . gametype = = GAME_Strife )
{
2016-09-07 09:34:49 +00:00
if ( active_con_scaletext ( ) = = 1 )
2016-03-01 15:47:10 +00:00
y - = height * 4 ;
2016-09-07 09:34:49 +00:00
else if ( active_con_scaletext ( ) > 3 )
2016-08-04 23:43:56 +00:00
y - = height ;
2016-03-01 15:47:10 +00:00
else
y - = height * 2 ;
}
2016-03-24 00:46:11 +00:00
DVector3 pos = CPlayer - > mo - > Pos ( ) ;
for ( i = 2 ; i > = 0 ; y - = height , - - i )
2016-03-01 15:47:10 +00:00
{
2016-03-24 00:46:11 +00:00
mysnprintf ( line , countof ( line ) , " %c: %d " , labels [ i ] , int ( pos [ i ] ) ) ;
2016-03-01 15:47:10 +00:00
screen - > DrawText ( SmallFont , CR_GREEN , xpos , y , line ,
DTA_KeepRatio , true ,
DTA_VirtualWidth , vwidth , DTA_VirtualHeight , vheight ,
TAG_DONE ) ;
V_SetBorderNeedRefresh ( ) ;
}
}
if ( viewactive )
{
if ( CPlayer & & CPlayer - > camera & & CPlayer - > camera - > player )
{
DrawCrosshair ( ) ;
}
}
else if ( automapactive )
{
int y , time = Tics2Seconds ( level . time ) , height ;
int totaltime = Tics2Seconds ( level . totaltime ) ;
EColorRange highlight = ( gameinfo . gametype & GAME_DoomChex ) ?
CR_UNTRANSLATED : CR_YELLOW ;
height = SmallFont - > GetHeight ( ) * CleanYfac ;
// Draw timer
y = 8 ;
if ( am_showtime )
{
mysnprintf ( line , countof ( line ) , " %02d:%02d:%02d " , time / 3600 , ( time % 3600 ) / 60 , time % 60 ) ; // Time
screen - > DrawText ( SmallFont , CR_GREY , SCREENWIDTH - 80 * CleanXfac , y , line , DTA_CleanNoMove , true , TAG_DONE ) ;
y + = 8 * CleanYfac ;
}
if ( am_showtotaltime )
{
mysnprintf ( line , countof ( line ) , " %02d:%02d:%02d " , totaltime / 3600 , ( totaltime % 3600 ) / 60 , totaltime % 60 ) ; // Total time
screen - > DrawText ( SmallFont , CR_GREY , SCREENWIDTH - 80 * CleanXfac , y , line , DTA_CleanNoMove , true , TAG_DONE ) ;
}
// Draw map name
2017-01-20 09:51:21 +00:00
y = gST_Y - height ;
2016-03-01 15:47:10 +00:00
if ( gameinfo . gametype = = GAME_Heretic & & SCREENWIDTH > 320 & & ! Scaled )
{
y - = 8 ;
}
else if ( gameinfo . gametype = = GAME_Hexen )
{
if ( Scaled )
{
y - = Scale ( 11 , SCREENHEIGHT , 200 ) ;
}
else
{
if ( SCREENWIDTH < 640 )
{
y - = 12 ;
}
else
{ // Get past the tops of the gargoyles' wings
y - = 28 ;
}
}
}
else if ( gameinfo . gametype = = GAME_Strife )
{
if ( Scaled )
{
y - = Scale ( 8 , SCREENHEIGHT , 200 ) ;
}
else
{
y - = 8 ;
}
}
FString mapname ;
ST_FormatMapName ( mapname , TEXTCOLOR_GREY ) ;
screen - > DrawText ( SmallFont , highlight ,
( SCREENWIDTH - SmallFont - > StringWidth ( mapname ) * CleanXfac ) / 2 , y , mapname ,
DTA_CleanNoMove , true , TAG_DONE ) ;
if ( ! deathmatch )
{
int y = 8 ;
// Draw monster count
if ( am_showmonsters )
{
mysnprintf ( line , countof ( line ) , " %s " TEXTCOLOR_GREY " %d/%d " ,
GStrings ( " AM_MONSTERS " ) , level . killed_monsters , level . total_monsters ) ;
screen - > DrawText ( SmallFont , highlight , 8 , y , line ,
DTA_CleanNoMove , true , TAG_DONE ) ;
y + = height ;
}
// Draw secret count
if ( am_showsecrets )
{
mysnprintf ( line , countof ( line ) , " %s " TEXTCOLOR_GREY " %d/%d " ,
GStrings ( " AM_SECRETS " ) , level . found_secrets , level . total_secrets ) ;
screen - > DrawText ( SmallFont , highlight , 8 , y , line ,
DTA_CleanNoMove , true , TAG_DONE ) ;
y + = height ;
}
// Draw item count
if ( am_showitems )
{
mysnprintf ( line , countof ( line ) , " %s " TEXTCOLOR_GREY " %d/%d " ,
GStrings ( " AM_ITEMS " ) , level . found_items , level . total_items ) ;
screen - > DrawText ( SmallFont , highlight , 8 , y , line ,
DTA_CleanNoMove , true , TAG_DONE ) ;
}
}
}
}
2017-03-21 19:09:09 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , Draw )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_INT ( state ) ;
self - > Draw ( ( EHudState ) state ) ;
return 0 ;
}
void DBaseStatusBar : : CallDraw ( EHudState state )
{
IFVIRTUAL ( DBaseStatusBar , Draw )
{
VMValue params [ ] = { ( DObject * ) this , state , r_viewpoint . TicFrac } ;
GlobalVMStack . Call ( func , params , countof ( params ) , nullptr , 0 ) ;
}
else Draw ( state ) ;
}
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
2016-09-07 09:34:49 +00:00
if ( active_con_scaletext ( ) = = 0 )
2016-03-01 15:47:10 +00:00
{
hudwidth = SCREENWIDTH / CleanXfac ;
hudheight = SCREENHEIGHT / CleanYfac ;
2016-09-06 17:48:14 +00:00
}
else
{
2016-09-07 09:34:49 +00:00
hudwidth = SCREENWIDTH / active_con_scaletext ( ) ;
hudheight = SCREENHEIGHT / active_con_scaletext ( ) ;
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 )
{
VMValue params [ ] = { ( DObject * ) this } ;
int rv ;
VMReturn ret ( & rv ) ;
GlobalVMStack . Call ( func , params , countof ( params ) , & ret , 1 ) ;
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 } ;
GlobalVMStack . Call ( func , params , countof ( params ) , nullptr , 0 ) ;
}
2016-03-01 15:47:10 +00:00
}
//---------------------------------------------------------------------------
//
// DrawBottomStuff
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : DrawBottomStuff ( EHudState state )
{
2017-01-20 09:51:21 +00:00
DrawMessages ( HUDMSGLayer_UnderHUD , ( state = = HUD_StatusBar ) ? gST_Y : SCREENHEIGHT ) ;
2016-03-01 15:47:10 +00:00
}
//---------------------------------------------------------------------------
//
// DrawTopStuff
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : DrawTopStuff ( EHudState state )
{
if ( demoplayback & & demover ! = DEMOGAMEVERSION )
{
screen - > DrawText ( SmallFont , CR_TAN , 0 , ST_Y - 40 * CleanYfac ,
" 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 } ;
GlobalVMStack . Call ( func , params , 1 , nullptr , 0 ) ;
}
fullscreenOffsets = saved ;
}
2016-03-01 15:47:10 +00:00
if ( automapactive & & ! viewactive )
{
2017-01-20 09:51:21 +00:00
DrawMessages ( HUDMSGLayer_OverMap , ( state = = HUD_StatusBar ) ? gST_Y : SCREENHEIGHT ) ;
2016-03-01 15:47:10 +00:00
}
2017-01-20 09:51:21 +00:00
DrawMessages ( HUDMSGLayer_OverHUD , ( state = = HUD_StatusBar ) ? gST_Y : SCREENHEIGHT ) ;
2016-03-01 15:47:10 +00:00
DrawConsistancy ( ) ;
DrawWaiting ( ) ;
if ( ShowLog & & MustDrawLog ( state ) ) DrawLog ( ) ;
if ( noisedebug )
{
S_NoiseDebug ( ) ;
}
}
//---------------------------------------------------------------------------
//
// BlendView
//
//---------------------------------------------------------------------------
void DBaseStatusBar : : BlendView ( float blend [ 4 ] )
{
2016-11-11 09:18:39 +00:00
// [Nash] Allow user to set blend intensity
float cnt = ( BaseBlendA * underwater_fade_scalar ) ;
V_AddBlend ( BaseBlendR / 255.f , BaseBlendG / 255.f , BaseBlendB / 255.f , cnt , blend ) ;
2016-03-01 15:47:10 +00:00
V_AddPlayerBlend ( CPlayer , blend , 1.0f , 228 ) ;
if ( screen - > Accel2D | | ( CPlayer - > camera ! = NULL & & menuactive = = MENU_Off & & ConsoleState = = c_up ) )
{
player_t * player = ( CPlayer - > camera ! = NULL & & CPlayer - > camera - > player ! = NULL ) ? CPlayer - > camera - > player : CPlayer ;
V_AddBlend ( player - > BlendR , player - > BlendG , player - > BlendB , player - > BlendA , blend ) ;
}
V_SetBlend ( ( int ) ( blend [ 0 ] * 255.0f ) , ( int ) ( blend [ 1 ] * 255.0f ) ,
( int ) ( blend [ 2 ] * 255.0f ) , ( int ) ( blend [ 3 ] * 256.0f ) ) ;
}
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 ) ;
BorderTopRefresh = screen - > GetPageCount ( ) ;
}
}
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 ) ;
BorderTopRefresh = screen - > GetPageCount ( ) ;
}
}
void DBaseStatusBar : : FlashItem ( const PClass * itemtype )
{
2017-03-21 19:09:09 +00:00
IFVIRTUAL ( DBaseStatusBar , FlashItem )
{
VMValue params [ ] = { ( DObject * ) this , ( PClass * ) itemtype } ;
GlobalVMStack . Call ( func , params , countof ( params ) , nullptr , 0 ) ;
}
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 } ;
GlobalVMStack . Call ( func , params , countof ( params ) , nullptr , 0 ) ;
}
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 } ;
GlobalVMStack . Call ( func , params , countof ( params ) , nullptr , 0 ) ;
}
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 ( )
{
st_scale . Callback ( ) ;
2017-03-24 01:12:03 +00:00
int x , y ;
V_CalcCleanFacs ( HorizontalResolution , VerticalResolution , SCREENWIDTH , SCREENHEIGHT , & x , & y ) ;
2017-03-25 17:31:53 +00:00
defaultScale = { ( double ) x , ( double ) y } ;
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 )
{
DHUDMessage * message = Messages [ i ] ;
while ( message ! = NULL )
{
message - > ScreenSizeChanged ( ) ;
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 } ;
GlobalVMStack . Call ( func , params , countof ( params ) , nullptr , 0 ) ;
}
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
//
//============================================================================
void DBaseStatusBar : : DrawGraphic ( FTextureID texture , bool animate , double x , double y , double Alpha , bool translatable , bool dim ,
2017-03-24 01:12:03 +00:00
int imgAlign , int screenalign , bool alphamap , double width , double height )
2017-03-23 14:18:09 +00:00
{
if ( ! texture . isValid ( ) )
return ;
2017-03-24 01:12:03 +00:00
Alpha * = this - > Alpha ;
if ( Alpha < = 0 ) return ;
x + = drawOffset . X ;
y + = drawOffset . Y ;
2017-03-23 14:18:09 +00:00
FTexture * tex = animate ? TexMan ( texture ) : TexMan [ texture ] ;
switch ( imgAlign & HMASK )
{
case HCENTER : x - = width / 2 ; break ;
case RIGHT : x - = width ; break ;
case HOFFSET : x - = tex - > GetScaledLeftOffsetDouble ( ) * width / tex - > GetScaledWidthDouble ( ) ; break ;
}
switch ( imgAlign & VMASK )
{
case VCENTER : y - = height / 2 ; break ;
case BOTTOM : y - = height ; break ;
case VOFFSET : y - = tex - > GetScaledTopOffsetDouble ( ) * height / tex - > GetScaledHeightDouble ( ) ; break ;
}
2017-03-24 01:12:03 +00:00
if ( ! fullscreenOffsets )
2017-03-23 14:18:09 +00:00
{
x + = ST_X ;
y + = ST_Y ;
// Todo: Allow other scaling values, too.
if ( Scaled )
{
screen - > VirtualToRealCoords ( x , y , width , height , HorizontalResolution , VerticalResolution , true , true ) ;
}
}
else
{
double orgx , orgy ;
switch ( screenalign & HMASK )
{
default : orgx = 0 ; break ;
case HCENTER : orgx = screen - > GetWidth ( ) / 2 ; break ;
case RIGHT : orgx = screen - > GetWidth ( ) ; break ;
}
switch ( screenalign & VMASK )
{
default : orgy = 0 ; break ;
case VCENTER : orgy = screen - > GetHeight ( ) / 2 ; break ;
case BOTTOM : orgy = screen - > GetHeight ( ) ; break ;
}
if ( screenalign = = ( RIGHT | TOP ) & & vid_fps ) y + = 10 ;
2017-03-25 17:31:53 +00:00
DVector2 Scale = GetHUDScale ( ) ;
x * = Scale . X ;
y * = Scale . Y ;
width * = Scale . X ;
height * = 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 ,
DTA_DestWidthF , width ,
DTA_DestHeightF , height ,
DTA_TranslationIndex , translatable ? GetTranslation ( ) : 0 ,
2017-03-24 10:55:04 +00:00
DTA_ColorOverlay , dim ? MAKEARGB ( 170 , 0 , 0 , 0 ) : 0 ,
2017-03-23 14:18:09 +00:00
DTA_Alpha , Alpha ,
DTA_AlphaChannel , alphamap ,
DTA_FillColor , alphamap ? 0 : - 1 ) ;
}
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , DrawGraphic )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_INT ( texid ) ;
PARAM_BOOL ( animate ) ;
PARAM_FLOAT ( x ) ;
PARAM_FLOAT ( y ) ;
PARAM_FLOAT ( alpha ) ;
PARAM_BOOL ( translatable ) ;
PARAM_BOOL ( dim ) ;
PARAM_INT ( ialign ) ;
PARAM_INT ( salign ) ;
PARAM_BOOL ( alphamap ) ;
PARAM_FLOAT ( w ) ;
PARAM_FLOAT ( h ) ;
2017-03-24 01:12:03 +00:00
self - > DrawGraphic ( FSetTextureID ( texid ) , animate , x , y , alpha , translatable , dim , ialign , salign , alphamap , w , h ) ;
2017-03-23 14:18:09 +00:00
return 0 ;
}
2017-03-24 01:38:44 +00:00
//============================================================================
//
// draw stuff
//
//============================================================================
void DBaseStatusBar : : DrawString ( FFont * font , const FString & cstring , double x , double y , double Alpha , int translation , int align , int screenalign , int spacing , bool monospaced , int shadowX , int shadowY )
{
switch ( align )
{
default :
break ;
case ALIGN_RIGHT :
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 ;
case ALIGN_CENTER :
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
switch ( screenalign & HMASK )
{
default : orgx = 0 ; break ;
case HCENTER : orgx = screen - > GetWidth ( ) / 2 ; break ;
case RIGHT : orgx = screen - > GetWidth ( ) ; break ;
}
switch ( screenalign & VMASK )
{
default : orgy = 0 ; break ;
case VCENTER : orgy = screen - > GetHeight ( ) / 2 ; break ;
case BOTTOM : orgy = screen - > GetHeight ( ) ; break ;
}
if ( screenalign = = ( RIGHT | TOP ) & & vid_fps ) orgy + = 10 ;
}
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
x + = ( c - > LeftOffset + 1 ) ; //ignore x offsets since we adapt to character size
double rx , ry , rw , rh ;
rx = x + drawOffset . X ;
ry = y + drawOffset . Y ;
rw = c - > GetScaledWidthDouble ( ) ;
rh = c - > GetScaledHeightDouble ( ) ;
if ( monospaced )
{
// align the character in the monospaced cell according to the general alignment to ensure that it gets positioned properly
// (i.e. right aligned text aligns to the right edge of the character and not the empty part of the cell.)
switch ( align )
{
default :
break ;
case ALIGN_CENTER :
rx - = ( spacing ) / 2 ;
break ;
case ALIGN_RIGHT :
rx - = spacing ;
break ;
}
}
if ( ! fullscreenOffsets )
{
rx + = ST_X ;
2017-03-24 23:35:19 +00:00
ry + = ST_Y ;
// Todo: Allow other scaling values, too.
2017-03-24 19:07:22 +00:00
if ( Scaled )
{
2017-03-24 23:35:19 +00:00
screen - > VirtualToRealCoords ( rx , ry , rw , rh , HorizontalResolution , VerticalResolution , true ) ;
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.
if ( shadowX ! = 0 | | shadowY ! = 0 )
{
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 )
x + = width + spacing - ( c - > LeftOffset + 1 ) ;
else
x + = spacing ;
}
2017-03-24 01:38:44 +00:00
}
2017-03-24 19:07:22 +00:00
2017-03-24 01:38:44 +00:00
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , DrawString )
{
PARAM_SELF_PROLOGUE ( DBaseStatusBar ) ;
PARAM_POINTER ( font , FFont ) ;
PARAM_STRING ( string ) ;
PARAM_FLOAT ( x ) ;
PARAM_FLOAT ( y ) ;
PARAM_FLOAT ( alpha ) ;
2017-03-24 19:07:22 +00:00
PARAM_INT ( trans ) ;
2017-03-24 01:38:44 +00:00
PARAM_INT ( ialign ) ;
PARAM_INT ( salign ) ;
PARAM_INT_DEF ( spacing ) ;
PARAM_BOOL_DEF ( monospaced ) ;
PARAM_INT_DEF ( shadowX ) ;
PARAM_INT_DEF ( shadowY ) ;
PARAM_INT_DEF ( wrapwidth ) ;
PARAM_INT_DEF ( linespacing ) ;
if ( wrapwidth > 0 )
{
FBrokenLines * brk = V_BreakLines ( font , wrapwidth , string , true ) ;
for ( int i = 0 ; brk [ i ] . Width > = 0 ; i + + )
{
self - > DrawString ( font , brk [ i ] . Text , x , y , alpha , trans , ialign , salign , spacing , monospaced , shadowX , shadowY ) ;
y + = font - > GetHeight ( ) + linespacing ;
}
V_FreeBrokenLines ( brk ) ;
}
else
{
self - > DrawString ( font , string , x , y , alpha , trans , ialign , salign , spacing , monospaced , shadowX , shadowY ) ;
}
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 , ST_X ) ;
DEFINE_FIELD ( DBaseStatusBar , ST_Y ) ;
DEFINE_FIELD ( DBaseStatusBar , RelTop ) ;
DEFINE_FIELD ( DBaseStatusBar , HorizontalResolution ) ;
DEFINE_FIELD ( DBaseStatusBar , VerticalResolution ) ;
DEFINE_FIELD ( DBaseStatusBar , Scaled ) ;
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-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
{
FNF_FILLZEROS ,
FNF_WHENNOTZERO ,
} ;
DEFINE_ACTION_FUNCTION ( DBaseStatusBar , FormatNumber )
{
PARAM_PROLOGUE ;
PARAM_INT ( number ) ;
PARAM_INT ( minsize ) ;
PARAM_INT ( maxsize ) ;
PARAM_INT ( flags ) ;
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_POINTER ( player , player_t ) ;
PARAM_STRING ( def_face ) ;
PARAM_INT ( accuracy ) ;
PARAM_INT_DEF ( stateflags ) ;
auto tex = self - > mugshot . GetFace ( player , def_face , accuracy , ( FMugShot : : StateFlags ) stateflags ) ;
ACTION_RETURN_INT ( tex ? tex - > id . GetIndex ( ) : - 1 ) ;
}