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
2018-12-01 15:53:54 +00:00
IMPLEMENT_CLASS ( DHUDFont , true , false ) ;
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 ] )
2018-12-02 13:24:26 +00:00
IMPLEMENT_POINTER ( AltHud )
2016-11-05 16:08:54 +00:00
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 ) ;
//---------------------------------------------------------------------------
//
// 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 )
{
2018-11-25 07:17:37 +00:00
num = players [ consoleplayer ] . camera - > player - > ReadyWeapon - > IntVar ( NAME_Crosshair ) ;
2016-03-01 15:47:10 +00:00
}
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 ;
2018-12-07 02:01:40 +00:00
CrosshairImage = TexMan . GetTexture ( texid ) ;
2016-03-01 15:47:10 +00:00
}
//---------------------------------------------------------------------------
//
// 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 ) ;
}
2018-06-29 10:47:06 +00:00
static void CreateGameInfoStatusBar ( bool & shouldWarn )
{
auto cls = PClass : : FindClass ( gameinfo . statusbarclass ) ;
if ( cls = = nullptr )
{
if ( shouldWarn )
{
Printf ( TEXTCOLOR_RED " Unknown status bar class \" %s \" \n " , gameinfo . statusbarclass . GetChars ( ) ) ;
shouldWarn = false ;
}
}
else
{
if ( cls - > IsDescendantOf ( RUNTIME_CLASS ( DBaseStatusBar ) ) )
{
StatusBar = ( DBaseStatusBar * ) cls - > CreateNew ( ) ;
}
else if ( shouldWarn )
{
Printf ( TEXTCOLOR_RED " Status bar class \" %s \" is not derived from BaseStatusBar \n " , gameinfo . statusbarclass . GetChars ( ) ) ;
shouldWarn = false ;
}
}
}
2017-03-25 17:31:53 +00:00
void ST_CreateStatusBar ( bool bTitleLevel )
{
if ( StatusBar ! = NULL )
{
StatusBar - > Destroy ( ) ;
StatusBar = NULL ;
}
2018-06-29 10:47:06 +00:00
bool shouldWarn = true ;
2017-03-25 17:31:53 +00:00
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
{
2018-06-29 10:47:06 +00:00
CreateGameInfoStatusBar ( shouldWarn ) ;
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 )
{
2018-06-29 10:47:06 +00:00
CreateGameInfoStatusBar ( shouldWarn ) ;
2017-05-21 10:05:46 +00:00
}
2017-03-25 17:31:53 +00:00
}
if ( StatusBar = = nullptr )
{
2018-08-18 23:14:15 +00:00
FName defname = NAME_None ;
2017-03-25 17:31:53 +00:00
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 )
{
2018-06-29 10:47:06 +00:00
assert ( cls - > IsDescendantOf ( RUNTIME_CLASS ( DBaseStatusBar ) ) ) ;
2017-03-25 17:31:53 +00:00
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 } ;
2018-12-02 13:24:26 +00:00
// Create the AltHud object. Todo: Make class type configurable.
FName classname = " AltHud " ;
auto cls = PClass : : FindClass ( classname ) ;
if ( cls )
{
AltHud = cls - > CreateNew ( ) ;
2018-12-03 16:35:53 +00:00
VMFunction * func = PClass : : FindFunction ( classname , " Init " ) ;
2018-12-02 13:24:26 +00:00
if ( func ! = nullptr )
{
VMValue params [ ] = { AltHud } ;
VMCall ( func , params , countof ( params ) , nullptr , 0 ) ;
}
}
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
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 ;
}
2019-01-07 08:14:52 +00:00
Messages [ i ] = nullptr ;
2016-03-01 15:47:10 +00:00
}
2018-12-02 13:24:26 +00:00
if ( AltHud ) AltHud - > Destroy ( ) ;
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
}
//---------------------------------------------------------------------------
//
2018-12-02 13:03:03 +00:00
//
2017-03-25 17:31:53 +00:00
//
//---------------------------------------------------------------------------
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 ;
}
//---------------------------------------------------------------------------
//
2018-12-02 13:03:03 +00:00
//
2017-03-25 17:31:53 +00:00
//
//---------------------------------------------------------------------------
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 ;
}
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 ] ;
2019-01-05 09:53:06 +00:00
TObjPtr < 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
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 ;
2019-01-05 09:53:06 +00:00
TObjPtr < 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
}
//---------------------------------------------------------------------------
//
// 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 ] ;
2019-01-05 09:53:06 +00:00
TObjPtr < 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 ;
2019-01-07 08:14:52 +00:00
probe - > Next = nullptr ;
2016-03-01 15:47:10 +00:00
return probe ;
}
}
return NULL ;
}
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 ] ;
2019-01-05 09:53:06 +00:00
TObjPtr < 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 ;
2019-01-07 08:14:52 +00:00
probe - > Next = nullptr ;
2016-03-01 15:47:10 +00:00
return probe ;
}
}
return NULL ;
}
//---------------------------------------------------------------------------
//
// 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
2019-01-07 08:14:52 +00:00
Messages [ i ] = nullptr ;
2016-03-01 15:47:10 +00:00
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 ;
}
}
}
//---------------------------------------------------------------------------
//
// 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 ' ) ) ;
}
2019-01-07 15:56:44 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
static FTextureID GetBorderTexture ( FLevelLocals * Level )
{
if ( Level ! = nullptr & & Level - > info ! = nullptr & & Level - > info - > BorderTexture . Len ( ) ! = 0 )
{
auto picnum = TexMan . CheckForTexture ( Level - > info - > BorderTexture , ETextureType : : Flat ) ;
if ( picnum . isValid ( ) ) return picnum ;
}
return TexMan . CheckForTexture ( gameinfo . BorderFlat , ETextureType : : Flat ) ;
}
//==========================================================================
//
// R_RefreshViewBorder
//
// Draws the border around the player view, if needed.
//
//==========================================================================
void DBaseStatusBar : : RefreshViewBorder ( )
{
if ( setblocks < 10 )
{
int Width = screen - > GetWidth ( ) ;
if ( viewwidth = = Width )
{
return ;
}
2019-01-27 23:55:21 +00:00
auto tex = GetBorderTexture ( currentUILevel ) ;
2019-01-07 15:56:44 +00:00
screen - > DrawBorder ( tex , 0 , 0 , Width , viewwindowy ) ;
screen - > DrawBorder ( tex , 0 , viewwindowy , viewwindowx , viewheight + viewwindowy ) ;
screen - > DrawBorder ( tex , viewwindowx + viewwidth , viewwindowy , Width , viewheight + viewwindowy ) ;
screen - > DrawBorder ( tex , 0 , viewwindowy + viewheight , Width , StatusBar - > GetTopOfStatusbar ( ) ) ;
screen - > DrawFrame ( viewwindowx , viewwindowy , viewwidth , viewheight ) ;
}
}
2016-03-01 15:47:10 +00:00
//---------------------------------------------------------------------------
//
// 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 ;
2019-01-07 15:56:44 +00:00
if ( x = = 0 & & y = = SCREENHEIGHT ) return ;
2019-01-27 23:55:21 +00:00
auto tex = GetBorderTexture ( currentUILevel ) ;
2016-03-01 15:47:10 +00:00
if ( ! CompleteBorder )
{
if ( y < SCREENHEIGHT )
{
2019-01-07 15:56:44 +00:00
screen - > DrawBorder ( tex , x + 1 , y , SCREENWIDTH , y + 1 ) ;
screen - > DrawBorder ( tex , 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 ;
}
2019-01-07 15:56:44 +00:00
screen - > DrawBorder ( tex , 0 , y , x + 1 , SCREENHEIGHT ) ;
screen - > DrawBorder ( tex , x2 - 1 , y , SCREENWIDTH , SCREENHEIGHT ) ;
2016-03-01 15:47:10 +00:00
if ( setblocks > = 10 )
{
2018-12-07 01:43:27 +00:00
FTexture * p = TexMan . GetTextureByName ( gameinfo . Border . b ) ;
2016-03-01 15:47:10 +00:00
if ( p ! = NULL )
{
2018-12-06 00:11:04 +00:00
screen - > FlatFill ( 0 , y , x , y + p - > GetDisplayHeight ( ) , p , true ) ;
screen - > FlatFill ( x2 , y , SCREENWIDTH , y + p - > GetDisplayHeight ( ) , p , true ) ;
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
}
2018-12-06 00:11:04 +00:00
w = int ( CrosshairImage - > GetDisplayWidth ( ) * size ) ;
h = int ( CrosshairImage - > GetDisplayHeight ( ) * 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
}
}
}
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 ;
2018-10-31 18:13:54 +00:00
auto lines = V_BreakLines ( SmallFont , linelen , CPlayer - > LogText ) ;
2016-03-01 15:47:10 +00:00
int height = 20 ;
2018-10-31 18:13:54 +00:00
for ( unsigned i = 0 ; i < lines . Size ( ) ; i + + ) height + = SmallFont - > GetHeight ( ) + 1 ;
2016-03-01 15:47:10 +00:00
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 ;
2018-11-01 11:37:11 +00:00
for ( const FBrokenLines & line : lines )
2016-03-01 15:47:10 +00:00
{
2018-11-01 11:37:11 +00:00
screen - > DrawText ( SmallFont , CR_UNTRANSLATED , x , y , line . Text ,
2016-03-01 15:47:10 +00:00
DTA_KeepRatio , true ,
DTA_VirtualWidth , hudwidth , DTA_VirtualHeight , hudheight , TAG_DONE ) ;
y + = SmallFont - > GetHeight ( ) + 1 ;
}
}
}
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 ;
}
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 : : 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-12-01 16:17:08 +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
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.
//
//---------------------------------------------------------------------------
2018-12-04 16:00:48 +00:00
AActor * DBaseStatusBar : : ValidateInvFirst ( int numVisible ) const
2016-03-01 15:47:10 +00:00
{
2018-12-01 16:46:20 +00:00
IFVM ( BaseStatusBar , ValidateInvFirst )
2016-03-01 15:47:10 +00:00
{
2018-12-04 16:00:48 +00:00
VMValue params [ ] = { const_cast < DBaseStatusBar * > ( this ) , numVisible } ;
AActor * item ;
2018-12-01 16:46:20 +00:00
VMReturn ret ( ( void * * ) & item ) ;
VMCall ( func , params , 2 , & ret , 1 ) ;
return item ;
2016-03-01 15:47:10 +00:00
}
2018-12-01 16:46:20 +00:00
return nullptr ;
2016-03-01 15:47:10 +00:00
}
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
}
}
//============================================================================
//
// 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 ;
2018-12-07 01:53:18 +00:00
FTexture * tex = TexMan . GetTexture ( texture , ! ( flags & DI_DONTANIMATE ) ) ;
2017-03-26 16:41:24 +00:00
2018-12-06 00:11:04 +00:00
double texwidth = tex - > GetDisplayWidthDouble ( ) * scaleX ;
double texheight = tex - > GetDisplayHeightDouble ( ) * scaleY ;
2017-03-26 16:41:24 +00:00
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-12-06 00:11:04 +00:00
case DI_ITEM_HOFFSET : x - = tex - > GetDisplayLeftOffsetDouble ( ) * 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-12-06 00:11:04 +00:00
case DI_ITEM_VOFFSET : y - = tex - > GetDisplayTopOffsetDouble ( ) * 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
//============================================================================
//
// 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 ;
2018-12-15 13:25:30 +00:00
FTexture * c = font - > GetChar ( ( unsigned char ) ch , fontcolor , & width ) ;
2017-03-24 19:07:22 +00:00
if ( c = = NULL ) //missing character.
{
continue ;
}
if ( ! monospaced ) //If we are monospaced lets use the offset
2018-12-06 00:11:04 +00:00
x + = ( c - > GetDisplayLeftOffsetDouble ( ) + 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 ;
2018-12-06 00:11:04 +00:00
rw = c - > GetDisplayWidthDouble ( ) ;
rh = c - > GetDisplayHeightDouble ( ) ;
2017-03-24 19:07:22 +00:00
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-12-06 00:11:04 +00:00
x + = width + spacing - ( c - > GetDisplayLeftOffsetDouble ( ) + 1 ) ;
2017-03-24 19:07:22 +00:00
else
x + = spacing ;
}
2017-03-24 01:38:44 +00:00
}
2018-12-01 15:53:54 +00:00
void SBar_DrawString ( DBaseStatusBar * self , DHUDFont * font , const FString & string , double x , double y , int flags , int trans , double alpha , int wrapwidth , int linespacing )
2017-03-24 01:38:44 +00:00
{
2018-12-01 15:53:54 +00:00
if ( font = = nullptr ) ThrowAbortException ( X_READ_NIL , nullptr ) ;
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 )
{
2018-10-31 18:13:54 +00:00
auto brk = V_BreakLines ( font - > mFont , wrapwidth , string , true ) ;
for ( auto & line : brk )
2017-03-24 01:38:44 +00:00
{
2018-10-31 18:13:54 +00:00
self - > DrawString ( font - > mFont , line . Text , x , y , flags , alpha , trans , font - > mSpacing , font - > mMonospaced , font - > mShadowX , font - > mShadowY ) ;
2017-03-26 16:41:24 +00:00
y + = font - > mFont - > GetHeight ( ) + linespacing ;
2017-03-24 01:38:44 +00:00
}
}
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
}
}
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
}
//============================================================================
//
// 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
}
2017-03-30 10:13:28 +00:00
//============================================================================
//
// 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 ) ;
}
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
}
}
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
2017-03-24 19:07:22 +00:00
enum ENumFlags
{
2018-01-07 22:04:51 +00:00
FNF_WHENNOTZERO = 0x1 ,
FNF_FILLZEROS = 0x2 ,
2017-03-24 19:07:22 +00:00
} ;
2018-12-01 15:53:54 +00:00
void FormatNumber ( int number , int minsize , int maxsize , int flags , const FString & prefix , FString * result )
2017-03-24 19:07:22 +00:00
{
static int maxvals [ ] = { 1 , 9 , 99 , 999 , 9999 , 99999 , 999999 , 9999999 , 99999999 , 999999999 } ;
2018-12-01 15:53:54 +00:00
if ( number = = 0 & & ( flags & FNF_WHENNOTZERO ) )
{
* result = " " ;
return ;
}
2017-03-24 19:07:22 +00:00
if ( maxsize > 0 & & maxsize < 10 )
{
number = clamp ( number , - maxvals [ maxsize - 1 ] , maxvals [ maxsize ] ) ;
}
2018-12-01 15:53:54 +00:00
FString & fmt = * result ;
2017-03-24 19:07:22 +00:00
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 ) ;
2017-03-25 00:22:42 +00:00
}
2017-03-26 23:02:10 +00:00
2018-12-01 13:01:03 +00:00
//---------------------------------------------------------------------------
//
// Weapons List
//
//---------------------------------------------------------------------------
2018-12-01 15:53:54 +00:00
2018-12-04 16:00:48 +00:00
int GetInventoryIcon ( AActor * item , uint32_t flags , int * applyscale )
2018-12-01 13:01:03 +00:00
{
if ( applyscale ! = NULL )
{
* applyscale = false ;
}
2018-12-03 23:22:26 +00:00
if ( item = = nullptr ) return 0 ;
2018-12-01 13:01:03 +00:00
2018-12-03 23:22:26 +00:00
FTextureID picnum , Icon = item - > TextureIDVar ( NAME_Icon ) , AltIcon = item - > TextureIDVar ( NAME_AltHUDIcon ) ;
2018-12-01 13:01:03 +00:00
FState * state = NULL , * ReadyState ;
picnum . SetNull ( ) ;
if ( flags & DI_ALTICONFIRST )
{
if ( ! ( flags & DI_SKIPALTICON ) & & AltIcon . isValid ( ) )
picnum = AltIcon ;
else if ( ! ( flags & DI_SKIPICON ) )
picnum = Icon ;
}
else
{
2018-12-03 23:22:26 +00:00
if ( ! ( flags & DI_SKIPICON ) & & Icon . isValid ( ) )
2018-12-01 13:01:03 +00:00
picnum = Icon ;
else if ( ! ( flags & DI_SKIPALTICON ) )
picnum = AltIcon ;
}
if ( ! picnum . isValid ( ) ) //isNull() is bad for checking, because picnum could be also invalid (-1)
{
if ( ! ( flags & DI_SKIPSPAWN ) & & item - > SpawnState & & item - > SpawnState - > sprite ! = 0 )
{
state = item - > SpawnState ;
if ( applyscale ! = NULL & & ! ( flags & DI_FORCESCALE ) )
{
* applyscale = true ;
}
}
// no spawn state - now try the ready state if it's weapon
else if ( ! ( flags & DI_SKIPREADY ) & & item - > GetClass ( ) - > IsDescendantOf ( NAME_Weapon ) & & ( ReadyState = item - > FindState ( NAME_Ready ) ) & & ReadyState - > sprite ! = 0 )
{
state = ReadyState ;
}
if ( state & & ( unsigned ) state - > sprite < ( unsigned ) sprites . Size ( ) )
{
spritedef_t * sprdef = & sprites [ state - > sprite ] ;
spriteframe_t * sprframe = & SpriteFrames [ sprdef - > spriteframes + state - > GetFrame ( ) ] ;
picnum = sprframe - > Texture [ 0 ] ;
}
}
2018-12-03 20:56:06 +00:00
return picnum . GetIndex ( ) ;
2018-12-01 13:01:03 +00:00
}