2014-06-01 17:55:23 +00:00
/*
2018-09-02 00:57:29 +00:00
* This file is part of the DXX - Rebirth project < https : //www.dxx-rebirth.com/>.
2014-06-01 17:55:23 +00:00
* It is copyright by its individual contributors , as recorded in the
* project ' s Git history . See COPYING . txt at the top level for license
* terms and a link to the Git history .
*/
2006-03-20 17:12:09 +00:00
/*
*
* Routines for displaying HUD messages . . .
*
*/
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include "hudmsg.h"
# include "pstypes.h"
# include "u_mem.h"
# include "strutil.h"
# include "console.h"
2014-11-23 04:36:58 +00:00
# include "object.h"
2006-03-20 17:12:09 +00:00
# include "inferno.h"
# include "game.h"
# include "screens.h"
# include "gauges.h"
# include "physics.h"
2012-07-07 18:35:06 +00:00
# include "dxxerror.h"
2006-03-20 17:12:09 +00:00
# include "menu.h" // For the font.
# include "collide.h"
# include "newdemo.h"
# include "player.h"
# include "gamefont.h"
# include "screens.h"
# include "text.h"
# include "laser.h"
# include "args.h"
2008-04-13 00:28:36 +00:00
# include "playsave.h"
2013-12-20 00:07:07 +00:00
# include "countarray.h"
2020-08-10 03:45:14 +00:00
# include "d_levelstate.h"
2006-03-20 17:12:09 +00:00
2020-12-26 21:17:29 +00:00
int HUD_toolong ;
2015-08-12 03:11:46 +00:00
namespace {
2017-10-14 17:10:30 +00:00
constexpr std : : integral_constant < unsigned , 150 > HUD_MESSAGE_LENGTH { } ;
2015-08-12 03:11:46 +00:00
2013-12-20 00:07:07 +00:00
struct hudmsg
2006-03-20 17:12:09 +00:00
{
2010-07-13 06:35:25 +00:00
fix time ;
2015-01-29 04:27:36 +00:00
ntstring < HUD_MESSAGE_LENGTH > message ;
template < typename M >
hudmsg ( const fix & t , M & & m ) :
2013-12-20 00:07:07 +00:00
time ( t )
{
2015-01-29 04:27:36 +00:00
message . copy_if ( m ) ;
2013-12-20 00:07:07 +00:00
}
} ;
2006-03-20 17:12:09 +00:00
2018-07-22 04:46:19 +00:00
struct hudmsg_array_t : public count_array_t < hudmsg , HUD_MAX_NUM_STOR > { } ;
2015-08-12 03:11:46 +00:00
2013-12-20 00:07:07 +00:00
static hudmsg_array_t HUD_messages ;
2006-03-20 17:12:09 +00:00
2010-07-13 06:35:25 +00:00
static int HUD_color = - 1 ;
2013-06-23 16:27:34 +00:00
static int HUD_init_message_literal_worth_showing ( int class_flag , const char * message ) ;
2020-12-26 21:17:29 +00:00
}
2006-03-20 17:12:09 +00:00
void HUD_clear_messages ( )
{
2013-12-20 00:07:07 +00:00
HUD_messages . clear ( ) ;
2010-07-13 06:35:25 +00:00
HUD_toolong = 0 ;
HUD_color = - 1 ;
2006-03-20 17:12:09 +00:00
}
2016-08-25 04:05:32 +00:00
namespace dsx {
2006-03-20 17:12:09 +00:00
// ----------------------------------------------------------------------------
// Writes a message on the HUD and checks its timer.
2017-03-11 19:56:21 +00:00
void HUD_render_message_frame ( grs_canvas & canvas )
2006-03-20 17:12:09 +00:00
{
2013-12-20 00:07:07 +00:00
int y ;
2010-07-13 06:35:25 +00:00
HUD_toolong = 0 ;
2006-03-20 17:12:09 +00:00
2013-12-20 00:07:07 +00:00
if ( HUD_messages . empty ( ) )
2006-03-20 17:12:09 +00:00
return ;
2013-12-20 00:07:07 +00:00
auto expired = [ ] ( hudmsg & h ) - > int {
if ( h . time < = FrameTime )
return 1 ;
h . time - = FrameTime ;
return 0 ;
} ;
HUD_messages . erase_if ( expired ) ;
2006-03-20 17:12:09 +00:00
2010-07-13 06:35:25 +00:00
// display last $HUD_MAX_NUM_DISP messages on the list
2013-12-20 00:07:07 +00:00
if ( ! HUD_messages . empty ( ) )
2010-07-13 06:35:25 +00:00
{
2006-03-20 17:12:09 +00:00
if ( HUD_color = = - 1 )
HUD_color = BM_XRGB ( 0 , 28 , 0 ) ;
2017-03-11 19:56:21 +00:00
gr_set_fontcolor ( canvas , HUD_color , - 1 ) ;
2008-02-24 14:41:27 +00:00
y = FSPACY ( 1 ) ;
2007-06-14 20:52:14 +00:00
2018-05-19 23:21:42 +00:00
auto & game_font = * GAME_FONT ;
const auto & & line_spacing = LINE_SPACING ( game_font , game_font ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2015-11-27 03:56:13 +00:00
if ( PlayerCfg . GuidedInBigWindow & &
2018-12-30 00:43:57 +00:00
LevelUniqueObjectState . Guided_missile . get_player_active_guided_missile ( LevelUniqueObjectState . get_objects ( ) . vmptr , Player_num ) ! = nullptr )
2015-06-13 22:42:22 +00:00
y + = line_spacing ;
2013-03-03 01:03:33 +00:00
# endif
2007-06-14 20:52:14 +00:00
2013-12-20 00:07:07 +00:00
hudmsg_array_t : : iterator i , e = HUD_messages . end ( ) ;
2017-06-10 03:31:03 +00:00
if ( HUD_messages . size ( ) < HUD_MAX_NUM_DISP )
2013-12-20 00:07:07 +00:00
i = HUD_messages . begin ( ) ;
else
i = e - HUD_MAX_NUM_DISP ;
if ( strlen ( i - > message ) > 38 )
HUD_toolong = 1 ;
for ( ; i ! = e ; + + i ) {
2018-05-19 23:21:42 +00:00
gr_string ( canvas , game_font , 0x8000 , y , & i - > message [ 0 ] ) ;
2015-06-13 22:42:22 +00:00
y + = line_spacing ;
2006-03-20 17:12:09 +00:00
}
}
}
2016-08-25 04:05:32 +00:00
}
2006-03-20 17:12:09 +00:00
2020-12-26 21:17:29 +00:00
namespace {
2013-06-23 16:19:50 +00:00
static int is_worth_showing ( int class_flag )
{
if ( PlayerCfg . NoRedundancy & & ( class_flag & HM_REDUNDANT ) )
return 0 ;
if ( PlayerCfg . MultiMessages & & ( Game_mode & GM_MULTI ) & & ! ( class_flag & HM_MULTI ) )
return 0 ;
return 1 ;
}
2020-12-26 21:17:29 +00:00
}
2006-03-20 17:12:09 +00:00
// Call to flash a message on the HUD. Returns true if message drawn.
// (message might not be drawn if previous message was same)
2013-06-23 16:19:50 +00:00
int HUD_init_message_va ( int class_flag , const char * format , va_list args )
2006-03-20 17:12:09 +00:00
{
2013-06-23 16:19:50 +00:00
if ( ! is_worth_showing ( class_flag ) )
return 0 ;
2010-10-10 10:48:24 +00:00
# ifndef macintosh
2010-07-13 06:35:25 +00:00
char message [ HUD_MESSAGE_LENGTH + 1 ] = " " ;
2010-10-10 10:48:24 +00:00
# else
char message [ 1024 ] = " " ;
# endif
2006-03-20 17:12:09 +00:00
2010-10-10 10:48:24 +00:00
# ifndef macintosh
2010-07-13 06:35:25 +00:00
vsnprintf ( message , sizeof ( char ) * HUD_MESSAGE_LENGTH , format , args ) ;
2010-10-10 10:48:24 +00:00
# else
vsprintf ( message , format , args ) ;
# endif
2013-12-22 17:18:44 +00:00
int r = HUD_init_message_literal_worth_showing ( class_flag , message ) ;
if ( r )
con_puts ( CON_HUD , message ) ;
return r ;
2013-06-23 16:27:34 +00:00
}
2006-03-20 17:12:09 +00:00
2020-12-26 21:17:29 +00:00
namespace {
2010-11-21 20:20:00 +00:00
2013-06-23 16:27:34 +00:00
static int HUD_init_message_literal_worth_showing ( int class_flag , const char * message )
{
2010-11-21 20:20:00 +00:00
// check if message is already in list and bail out if so
2013-12-20 00:07:07 +00:00
if ( ! HUD_messages . empty ( ) )
2010-07-13 06:35:25 +00:00
{
2013-12-20 00:07:07 +00:00
hudmsg_array_t : : iterator i , e = HUD_messages . end ( ) ;
2011-04-11 19:27:31 +00:00
// if "normal" message, only check if it's the same at the most recent one, if marked as "may duplicate" check whole list
2013-12-20 00:07:07 +00:00
if ( class_flag & HM_MAYDUPL )
i = HUD_messages . begin ( ) ;
else
i = e - 1 ;
for ( ; i ! = e ; + + i )
2010-07-13 06:35:25 +00:00
{
2013-12-20 00:07:07 +00:00
if ( ! d_stricmp ( message , i - > message ) )
2010-11-21 20:20:00 +00:00
{
2013-12-20 00:07:07 +00:00
i - > time = F1_0 * 2 ; // keep redundant message in list
if ( std : : distance ( i , e ) < HUD_MAX_NUM_DISP ) // if redundant message on display, update them all
{
2017-06-10 03:31:03 +00:00
if ( HUD_messages . size ( ) < HUD_MAX_NUM_DISP )
2013-12-20 00:07:07 +00:00
i = HUD_messages . begin ( ) ;
else
i = HUD_messages . end ( ) - HUD_MAX_NUM_DISP ;
for ( unsigned j = 1 ; i ! = e ; + + i , j + + )
i - > time = F1_0 * ( j * 2 ) ;
}
2010-11-21 20:20:00 +00:00
return 0 ;
}
2010-07-13 06:35:25 +00:00
}
}
2006-03-20 17:12:09 +00:00
2017-06-10 03:31:03 +00:00
if ( HUD_messages . size ( ) > = HUD_MAX_NUM_STOR )
2010-07-13 06:35:25 +00:00
{
2015-01-29 04:27:36 +00:00
std : : move ( HUD_messages . begin ( ) + 1 , HUD_messages . end ( ) , HUD_messages . begin ( ) ) ;
2013-12-20 00:07:07 +00:00
HUD_messages . pop_back ( ) ;
2006-03-20 17:12:09 +00:00
}
2013-12-20 00:07:07 +00:00
fix t ;
2017-06-10 03:31:03 +00:00
if ( HUD_messages . size ( ) + 1 < HUD_MAX_NUM_DISP )
2013-12-20 00:07:07 +00:00
t = F1_0 * 3 ; // one message - display 3 secs
2010-07-13 06:35:25 +00:00
else
{
2013-12-20 00:07:07 +00:00
hudmsg_array_t : : iterator e = HUD_messages . end ( ) , i = e - HUD_MAX_NUM_DISP ;
for ( unsigned j = 1 ; + + i ! = e ; j + + ) // multiple messages - display 2 seconds each
i - > time = F1_0 * ( j * 2 ) ;
t = F1_0 * ( ( HUD_MAX_NUM_DISP + 1 ) * 2 ) ;
2006-03-20 17:12:09 +00:00
}
2013-12-20 00:07:07 +00:00
HUD_messages . emplace_back ( t , message ) ;
2007-01-14 01:55:59 +00:00
2007-08-26 11:46:10 +00:00
if ( HUD_color = = - 1 )
HUD_color = BM_XRGB ( 0 , 28 , 0 ) ;
2006-03-20 17:12:09 +00:00
if ( Newdemo_state = = ND_STATE_RECORDING )
newdemo_record_hud_message ( message ) ;
return 1 ;
}
2020-12-26 21:17:29 +00:00
}
2013-12-08 23:37:40 +00:00
int ( HUD_init_message ) ( int class_flag , const char * format , . . . )
2006-03-20 17:12:09 +00:00
{
int ret ;
va_list args ;
va_start ( args , format ) ;
2010-11-21 20:20:00 +00:00
ret = HUD_init_message_va ( class_flag , format , args ) ;
2006-03-20 17:12:09 +00:00
va_end ( args ) ;
return ret ;
}
2013-06-23 16:27:34 +00:00
int HUD_init_message_literal ( int class_flag , const char * str )
{
if ( ! is_worth_showing ( class_flag ) )
return 0 ;
2013-12-22 17:18:44 +00:00
int r = HUD_init_message_literal_worth_showing ( class_flag , str ) ;
if ( r )
con_puts ( CON_HUD , str ) ;
return r ;
2013-06-23 16:27:34 +00:00
}
2006-03-20 17:12:09 +00:00
2017-02-11 21:42:46 +00:00
void player_dead_message ( grs_canvas & canvas )
2006-03-20 17:12:09 +00:00
{
2016-01-09 16:38:10 +00:00
if ( Player_dead_state = = player_dead_state : : exploded )
{
2018-12-01 01:58:37 +00:00
if ( get_local_player ( ) . lives = = 1 )
{
2015-09-29 02:41:22 +00:00
int x , y , w , h ;
2018-05-19 23:21:42 +00:00
auto & huge_font = * HUGE_FONT ;
gr_get_string_size ( huge_font , TXT_GAME_OVER , & w , & h , nullptr ) ;
2015-12-22 04:18:50 +00:00
const int gw = w ;
const int gh = h ;
2008-02-24 14:41:27 +00:00
w + = 20 ;
h + = 8 ;
2017-02-11 21:42:46 +00:00
x = ( canvas . cv_bitmap . bm_w - w ) / 2 ;
y = ( canvas . cv_bitmap . bm_h - h ) / 2 ;
2008-02-24 14:41:27 +00:00
2020-07-16 02:31:04 +00:00
gr_settransblend ( canvas , 14 , gr_blend : : normal ) ;
2016-02-12 04:02:28 +00:00
const uint8_t color = BM_XRGB ( 0 , 0 , 0 ) ;
2017-02-11 21:42:46 +00:00
gr_rect ( canvas , x , y , x + w , y + h , color ) ;
2020-07-16 02:31:04 +00:00
gr_settransblend ( canvas , GR_FADE_OFF , gr_blend : : normal ) ;
2008-02-24 14:41:27 +00:00
2018-05-19 23:21:42 +00:00
gr_string ( canvas , huge_font , 0x8000 , ( canvas . cv_bitmap . bm_h - h ) / 2 + h / 8 , TXT_GAME_OVER , gw , gh ) ;
2008-02-24 14:41:27 +00:00
}
if ( HUD_color = = - 1 )
HUD_color = BM_XRGB ( 0 , 28 , 0 ) ;
2017-02-11 21:42:46 +00:00
gr_set_fontcolor ( canvas , HUD_color , - 1 ) ;
2018-05-19 23:21:42 +00:00
auto & game_font = * GAME_FONT ;
gr_string ( canvas , game_font , 0x8000 , canvas . cv_bitmap . bm_h - LINE_SPACING ( game_font , game_font ) , PlayerCfg . RespawnMode = = RespawnPress : : Any ? TXT_PRESS_ANY_KEY : " Press fire key or button to continue... " ) ;
2008-02-24 14:41:27 +00:00
}
2006-03-20 17:12:09 +00:00
}