2020-03-04 23:58:38 +00:00
//-------------------------------------------------------------------------
/*
Copyright ( C ) 2016 EDuke32 developers and contributors
This file is part of EDuke32 .
EDuke32 is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*/
//-------------------------------------------------------------------------
# include "ns.h" // Must come before everything else!
# include "duke3d.h"
# include "compat.h"
# include "sbar.h"
# include "menus.h"
# include "gstrings.h"
# include "quotemgr.h"
# include "c_dispatch.h"
BEGIN_DUKE_NS
// assign the character's tilenum
int GameInterface : : GetStringTile ( int font , const char * t , int f )
{
if ( f & TEXT_DIGITALNUMBER )
return * t - ' 0 ' + font ; // copied from digitalnumber
else if ( f & ( TEXT_BIGALPHANUM | TEXT_GRAYFONT ) )
{
int32_t offset = ( f & TEXT_GRAYFONT ) ? 26 : 0 ;
if ( * t > = ' 0 ' & & * t < = ' 9 ' )
return * t - ' 0 ' + font + ( ( f & TEXT_GRAYFONT ) ? 26 : - 10 ) ;
else if ( * t > = ' a ' & & * t < = ' z ' )
return * t - ' a ' + font + ( ( f & TEXT_GRAYFONT ) ? - 26 : 26 ) ;
else if ( * t > = ' A ' & & * t < = ' Z ' )
return * t - ' A ' + font ;
else switch ( * t )
{
case ' _ ' :
case ' - ' :
return font - ( 11 + offset ) ;
break ;
case ' . ' :
return font + ( BIGPERIOD - ( BIGALPHANUM + offset ) ) ;
break ;
case ' , ' :
return font + ( BIGCOMMA - ( BIGALPHANUM + offset ) ) ;
break ;
case ' ! ' :
return font + ( BIGX_ - ( BIGALPHANUM + offset ) ) ;
break ;
case ' ? ' :
return font + ( BIGQ - ( BIGALPHANUM + offset ) ) ;
break ;
case ' ; ' :
return font + ( BIGSEMI - ( BIGALPHANUM + offset ) ) ;
break ;
case ' : ' :
return font + ( BIGCOLIN - ( BIGALPHANUM + offset ) ) ;
break ;
case ' \\ ' :
case ' / ' :
return font + ( 68 - offset ) ; // 3008-2940
break ;
case ' % ' :
return font + ( 69 - offset ) ; // 3009-2940
break ;
case ' ` ' :
case ' \" ' : // could be better hacked in
case ' \' ' :
return font + ( BIGAPPOS - ( BIGALPHANUM + offset ) ) ;
break ;
default : // unknown character
fallthrough__ ;
case ' \t ' :
case ' ' :
case ' \n ' :
case ' \x7F ' :
return font ;
break ;
}
}
else
return * t - ' ! ' + font ; // uses ASCII order
}
void G_PrintGameText ( int32_t tile , int32_t x , int32_t y , const char * t ,
int32_t s , int32_t p , int32_t o ,
int32_t x1 , int32_t y1 , int32_t x2 , int32_t y2 ,
int32_t z , int32_t a )
{
int32_t f = TEXT_GAMETEXTNUMHACK ;
if ( t = = NULL )
return ;
if ( ! ( o & ROTATESPRITE_FULL16 ) )
{
x < < = 16 ;
y < < = 16 ;
}
if ( x = = ( 160 < < 16 ) )
f | = TEXT_XCENTER ;
G_ScreenText ( tile , x , y , z , 0 , 0 , t , s , p , 2 | o | ROTATESPRITE_FULL16 , a , MF_Bluefont . emptychar . x , MF_Bluefont . emptychar . y , MF_Bluefont . between . x , MF_Bluefont . between . y , MF_Bluefont . textflags | f , x1 , y1 , x2 , y2 ) ;
}
vec2_t gametext_ ( int32_t x , int32_t y , const char * t , int32_t s , int32_t p , int32_t o , int32_t a , int32_t f )
{
return G_ScreenText ( MF_Bluefont . tilenum , x , y , MF_Bluefont . zoom , 0 , 0 , t , s , p , o | 2 | 8 | 16 | ROTATESPRITE_FULL16 , a , MF_Bluefont . emptychar . x , MF_Bluefont . emptychar . y , MF_Bluefont . between . x , MF_Bluefont . between . y , MF_Bluefont . textflags | f , 0 , 0 , xdim - 1 , ydim - 1 ) ;
}
void gametext_simple ( int32_t x , int32_t y , const char * t )
{
G_ScreenText ( MF_Bluefont . tilenum , x , y , MF_Bluefont . zoom , 0 , 0 , t , 0 , MF_Bluefont . pal , 2 | 8 | 16 | ROTATESPRITE_FULL16 , 0 , MF_Bluefont . emptychar . x , MF_Bluefont . emptychar . y , MF_Bluefont . between . x , MF_Bluefont . between . y , MF_Bluefont . textflags , 0 , 0 , xdim - 1 , ydim - 1 ) ;
}
vec2_t mpgametext ( int32_t x , int32_t y , const char * t , int32_t s , int32_t o , int32_t a , int32_t f )
{
return G_ScreenText ( MF_Bluefont . tilenum , x , y , textsc ( MF_Bluefont . zoom ) , 0 , 0 , t , s , MF_Bluefont . pal , o | 2 | 8 | 16 | ROTATESPRITE_FULL16 , a , MF_Bluefont . emptychar . x , MF_Bluefont . emptychar . y , MF_Bluefont . between . x , MF_Bluefont . between . y , MF_Bluefont . textflags | f , 0 , 0 , xdim - 1 , ydim - 1 ) ;
}
vec2_t mpgametextsize ( const char * t , int32_t f )
{
return G_ScreenTextSize ( MF_Bluefont . tilenum , 0 , 0 , textsc ( MF_Bluefont . zoom ) , 0 , t , 2 | 8 | 16 | ROTATESPRITE_FULL16 , MF_Bluefont . emptychar . x , MF_Bluefont . emptychar . y , MF_Bluefont . between . x , MF_Bluefont . between . y , MF_Bluefont . textflags | f , 0 , 0 , xdim - 1 , ydim - 1 ) ;
}
// minitext_yofs: in hud_scale-independent, (<<16)-scaled, 0-200-normalized y coords,
// (sb&ROTATESPRITE_MAX) only.
int32_t minitext_yofs = 0 ;
int32_t minitext_lowercase = 0 ;
int32_t minitext_ ( int32_t x , int32_t y , const char * t , int32_t s , int32_t p , int32_t sb )
{
vec2_t dim ;
int32_t z = MF_Minifont . zoom ;
if ( t = = NULL )
{
2020-04-11 21:45:45 +00:00
Printf ( " minitext: NULL text! \n " ) ;
2020-03-04 23:58:38 +00:00
return 0 ;
}
if ( ! ( sb & ROTATESPRITE_FULL16 ) )
{
x < < = 16 ;
y < < = 16 ;
}
if ( sb & ROTATESPRITE_MAX )
{
x = sbarx16 ( x ) ;
y = minitext_yofs + sbary16 ( y ) ;
z = sbarsc ( z ) ;
}
sb & = ( ROTATESPRITE_MAX - 1 ) | RS_CENTERORIGIN ;
dim = G_ScreenText ( MF_Minifont . tilenum , x , y , z , 0 , 0 , t , s , p , sb | ROTATESPRITE_FULL16 , 0 , MF_Minifont . emptychar . x , MF_Minifont . emptychar . y , MF_Minifont . between . x , MF_Minifont . between . y , MF_Minifont . textflags , 0 , 0 , xdim - 1 , ydim - 1 ) ;
x + = dim . x ;
if ( ! ( sb & ROTATESPRITE_FULL16 ) )
x > > = 16 ;
return x ;
}
void menutext_ ( int32_t x , int32_t y , int32_t s , char const * t , int32_t o , int32_t f )
{
G_ScreenText ( MF_Redfont . tilenum , x , y - ( 12 < < 16 ) , MF_Redfont . zoom , 0 , 0 , t , s , MF_Redfont . pal , o | ROTATESPRITE_FULL16 , 0 , MF_Redfont . emptychar . x , MF_Redfont . emptychar . y , MF_Redfont . between . x , MF_Redfont . between . y , f | MF_Redfont . textflags | TEXT_LITERALESCAPE , 0 , 0 , xdim - 1 , ydim - 1 ) ;
}
void captionmenutext ( int32_t x , int32_t y , char const * t )
{
G_ScreenText ( MF_Redfont . tilenum , x , y - ( 12 < < 16 ) , MF_Redfont . zoom , 0 , 0 , t , 0 , ud . menutitle_pal , 2 | 8 | 16 | ROTATESPRITE_FULL16 , 0 , MF_Redfont . emptychar . x , MF_Redfont . emptychar . y , MF_Redfont . between . x , MF_Redfont . between . y , MF_Redfont . textflags | TEXT_LITERALESCAPE | TEXT_XCENTER | TEXT_YCENTER , 0 , 0 , xdim - 1 , ydim - 1 ) ;
}
int32_t user_quote_time [ MAXUSERQUOTES ] ;
static char user_quote [ MAXUSERQUOTES ] [ 178 ] ;
void G_AddUserQuote ( const char * daquote )
{
int32_t i ;
if ( hud_messages = = 0 ) return ;
Printf ( PRINT_MEDIUM | PRINT_NOTIFY , " %s \n " , daquote ) ;
if ( hud_messages = = 1 )
{
for ( i = MAXUSERQUOTES - 1 ; i > 0 ; i - - )
{
Bstrcpy ( user_quote [ i ] , user_quote [ i - 1 ] ) ;
user_quote_time [ i ] = user_quote_time [ i - 1 ] ;
}
Bstrcpy ( user_quote [ 0 ] , daquote ) ;
user_quote_time [ 0 ] = hud_messagetime ;
pub = NUMPAGES ;
}
}
int32_t textsc ( int32_t sc )
{
return scale ( sc , hud_textscale , 400 ) ;
}
# define FTAOPAQUETIME 30
// alpha increments of 8 --> 256 / 8 = 32 --> round up to power of 2 --> 32 --> divide by 2 --> 16 alphatabs required
static inline int32_t textsh ( uint32_t t )
{
return ( hud_glowingquotes & & ( ( videoGetRenderMode ( ) = = REND_CLASSIC & & numalphatabs < 15 ) | | t > = FTAOPAQUETIME ) )
? sintable [ ( t < < 7 ) & 2047 ] > > 11
: ( sintable [ ( FTAOPAQUETIME < < 7 ) & 2047 ] > > 11 ) ;
}
// orientation flags depending on time that a quote has still to be displayed
static inline int32_t texto ( int32_t t )
{
if ( videoGetRenderMode ( ) ! = REND_CLASSIC | | numalphatabs > = 15 | | t > 4 )
return 0 ;
if ( t > 2 )
return 1 ;
return 1 | 32 ;
}
static inline int32_t texta ( int32_t t )
{
return 255 - clamp ( t < < 3 , 0 , 255 ) ;
}
static FORCE_INLINE int32_t text_ypos ( void )
{
if ( hud_position = = 1 & & ud . screen_size = = 4 & & ud . althud = = 1 )
return 32 < < 16 ;
return 1 < < 16 ;
}
static FString text_quote ; // To put text into the quote display that does not come from the quote array. (Is it really necessary to implement everything as a hack??? :( )
// this handles both multiplayer and item pickup message type text
// both are passed on to gametext
void G_PrintGameQuotes ( int32_t snum )
{
auto const ps = g_player [ snum ] . ps ;
const int32_t reserved_quote = ( ps - > ftq > = QUOTE_RESERVED & & ps - > ftq < = QUOTE_RESERVED3 ) ;
// NOTE: QUOTE_RESERVED4 is not included.
int32_t const ybase = ( fragbarheight ( ) < < 16 ) + text_ypos ( ) ;
int32_t height = 0 ;
int32_t k = ps - > fta ;
// primary quote
do
{
if ( k < = 1 )
break ;
int32_t y = ybase ;
if ( reserved_quote )
{
y = 140 < < 16 ;
}
int32_t pal = 0 ;
int32_t x = 160 < < 16 ;
if ( text_quote . IsNotEmpty ( ) & & ps - > ftq = = - 32768 ) height = gametext_ ( x , y , text_quote , textsh ( k ) , pal , texto ( k ) , texta ( k ) , TEXT_XCENTER ) . y + ( 1 < < 16 ) ;
else height = gametext_ ( x , y , quoteMgr . GetQuote ( ps - > ftq ) , textsh ( k ) , pal , texto ( k ) , texta ( k ) , TEXT_XCENTER ) . y + ( 1 < < 16 ) ;
}
while ( 0 ) ;
// userquotes
int32_t y = ybase ;
if ( k > 1 & & ! reserved_quote )
y + = k < = 8 ? ( height * ( k - 1 ) ) > > 3 : height ;
for ( int i = 0 ; i < MAXUSERQUOTES ; i + + )
{
k = user_quote_time [ i ] ;
if ( k < = 0 )
continue ;
// int32_t const sh = hud_glowingquotes ? sintable[((totalclock+(i<<2))<<5)&2047]>>11 : 0;
height = mpgametext ( mpgametext_x , y , user_quote [ i ] , textsh ( k ) , texto ( k ) , texta ( k ) , TEXT_LINEWRAP ) . y + textsc ( 1 < < 16 ) ;
y + = k < = 4 ? ( height * ( k - 1 ) ) > > 2 : height ;
}
}
void P_DoQuote ( int32_t q , DukePlayer_t * p )
{
int32_t cq = 0 ;
if ( hud_messages = = 0 | | q < 0 | | ! ( p - > gm & MODE_GAME ) )
return ;
if ( q & MAXQUOTES )
{
cq = 1 ;
q & = ~ MAXQUOTES ;
}
if ( p - > fta > 0 & & q ! = QUOTE_RESERVED & & q ! = QUOTE_RESERVED2 )
if ( p - > ftq = = QUOTE_RESERVED | | p - > ftq = = QUOTE_RESERVED2 ) return ;
if ( p - > ftq ! = q )
{
auto qu = quoteMgr . GetQuote ( q ) ;
if ( p = = g_player [ screenpeek ] . ps & & qu [ 0 ] ! = ' \0 ' )
Printf ( ( cq ? PRINT_LOW : PRINT_MEDIUM ) | PRINT_NOTIFY , " %s \n " , qu ) ;
}
if ( hud_messages = = 1 )
{
p - > ftq = q ;
p - > fta = 100 ;
pub = NUMPAGES ;
pus = NUMPAGES ;
}
}
void GameInterface : : DoPrintMessage ( int prio , const char * t )
{
auto p = g_player [ myconnectindex ] . ps ; // text quotes always belong to the local player.
int32_t cq = 0 ;
if ( hud_messages = = 0 | | ! ( p - > gm & MODE_GAME ) )
return ;
if ( p - > fta > 0 )
if ( p - > ftq = = QUOTE_RESERVED | | p - > ftq = = QUOTE_RESERVED2 ) return ;
if ( p = = g_player [ screenpeek ] . ps )
Printf ( prio | PRINT_NOTIFY , cq ? OSDTEXT_DEFAULT " %s \n " : " %s \n " , t ) ;
if ( hud_messages = = 1 )
{
p - > fta = 100 ;
p - > ftq = - 32768 ;
text_quote = t ;
pub = NUMPAGES ;
pus = NUMPAGES ;
}
}
END_DUKE_NS