2019-11-05 18:57:48 +00:00
/*
* * c_console . cpp
* * Implements the console itself
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright 1998 - 2006 Randy Heit
* * 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 <string>
# include "templates.h"
# include "version.h"
# include "c_bind.h"
# include "c_console.h"
# include "c_cvars.h"
# include "c_dispatch.h"
2020-04-11 22:04:02 +00:00
# include "gamestate.h"
2019-11-05 18:57:48 +00:00
# include "v_text.h"
# include "filesystem.h"
# include "d_gui.h"
# include "cmdlib.h"
# include "d_event.h"
# include "c_consolebuffer.h"
# include "utf8.h"
# include "v_2ddrawer.h"
# include "v_draw.h"
# include "v_font.h"
# include "printf.h"
2019-11-06 22:40:10 +00:00
# include "inputstate.h"
2019-12-04 22:07:02 +00:00
# include "i_time.h"
# include "gamecvars.h"
2019-12-23 18:37:40 +00:00
# include "i_system.h"
2020-02-16 19:08:04 +00:00
# include "s_soundinternal.h"
2020-04-11 21:50:43 +00:00
# include "engineerrors.h"
2020-04-12 06:09:38 +00:00
# include "gamecontrol.h"
2020-05-25 15:11:32 +00:00
# include "v_video.h"
# include "v_draw.h"
2020-04-23 20:58:02 +00:00
# include "g_input.h"
2020-10-04 16:31:48 +00:00
# include "razemenu.h"
2020-07-21 22:42:50 +00:00
# include "raze_music.h"
2020-09-29 20:20:25 +00:00
# include "gstrings.h"
2020-10-04 16:31:48 +00:00
# include "menustate.h"
2020-10-04 22:46:24 +00:00
# include "i_interface.h"
2020-10-09 22:51:26 +00:00
# include "vm.h"
2020-10-10 21:16:08 +00:00
# include "gi.h"
# include "texturemanager.h"
# include "c_commandbuffer.h"
2019-11-05 18:57:48 +00:00
# define LEFTMARGIN 8
# define RIGHTMARGIN 8
# define BOTTOMARGIN 12
extern bool hud_toggled ;
void D_ToggleHud ( ) ;
CUSTOM_CVAR ( Int , con_buffersize , - 1 , CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
{
// ensure a minimum size
if ( self > = 0 & & self < 128 ) self = 128 ;
}
FConsoleBuffer * conbuffer ;
2020-10-10 21:16:08 +00:00
static FTextureID conback ;
2019-11-05 18:57:48 +00:00
static uint32_t conshade ;
static bool conline ;
extern bool advancedemo ;
extern FBaseCVar * CVars ;
extern FConsoleCommand * Commands [ FConsoleCommand : : HASH_SIZE ] ;
int ConWidth ;
bool vidactive = false ;
bool cursoron = false ;
int ConBottom , ConScroll , RowAdjust ;
2020-04-11 22:04:02 +00:00
uint64_t CursorTicker ;
2019-11-05 18:57:48 +00:00
constate_e ConsoleState = c_up ;
2020-08-26 12:33:19 +00:00
double NotifyFontScale = 1 ;
2020-08-19 14:40:54 +00:00
2020-10-09 22:51:26 +00:00
DEFINE_GLOBAL ( NotifyFontScale )
2020-08-26 12:33:19 +00:00
void C_SetNotifyFontScale ( double scale )
2020-08-19 14:40:54 +00:00
{
NotifyFontScale = scale ;
}
2019-11-05 18:57:48 +00:00
static int TopLine , InsertLine ;
static void ClearConsole ( ) ;
struct GameAtExit
{
GameAtExit ( FString str ) : Command ( str ) { }
GameAtExit * Next ;
FString Command ;
} ;
static GameAtExit * ExitCmdList ;
# define SCROLLUP 1
# define SCROLLDN 2
# define SCROLLNO 0
// Buffer for AddToConsole()
static char * work = NULL ;
static int worklen = 0 ;
CVAR ( Float , con_notifytime , 3.f , CVAR_ARCHIVE )
2020-08-25 16:03:15 +00:00
CUSTOM_CVAR ( Float , con_notifyscale , 1 , CVAR_ARCHIVE )
2019-11-05 18:57:48 +00:00
{
2020-08-25 16:03:15 +00:00
if ( self < 0.36f ) self = 0.36f ;
if ( self > 1 ) self = 1 ;
2019-11-05 18:57:48 +00:00
}
2020-08-25 16:03:15 +00:00
CVAR ( Bool , con_centernotify , false , CVAR_ARCHIVE )
CVAR ( Bool , con_notify_advanced , false , CVAR_ARCHIVE )
2020-08-23 20:39:53 +00:00
CVAR ( Bool , con_pulsetext , false , CVAR_ARCHIVE )
2019-11-05 18:57:48 +00:00
CUSTOM_CVAR ( Int , con_scale , 0 , CVAR_ARCHIVE )
{
if ( self < 0 ) self = 0 ;
}
CUSTOM_CVAR ( Float , con_alpha , 0.75f , CVAR_ARCHIVE )
{
if ( self < 0.f ) self = 0.f ;
if ( self > 1.f ) self = 1.f ;
}
// Command to run when Ctrl-D is pressed at start of line
CVAR ( String , con_ctrl_d , " " , CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
CVAR ( Int , developer , 0 , CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
EXTERN_CVAR ( Int , uiscale ) ;
struct History
{
struct History * Older ;
struct History * Newer ;
FString String ;
} ;
# define MAXHISTSIZE 50
static struct History * HistHead = NULL , * HistTail = NULL , * HistPos = NULL ;
static int HistSize ;
# define NUMNOTIFIES 4
# define NOTIFYFADETIME 6
struct FNotifyText
{
int TimeOut ;
2020-04-11 22:04:02 +00:00
int Ticker ;
2019-11-05 18:57:48 +00:00
int PrintLevel ;
FString Text ;
} ;
struct FNotifyBuffer
{
public :
FNotifyBuffer ( ) ;
void AddString ( int printlevel , FString source ) ;
void Shift ( int maxlines ) ;
void Clear ( ) { Text . Clear ( ) ; }
void Tick ( ) ;
void Draw ( ) ;
2020-08-23 20:39:53 +00:00
void DrawNative ( ) ;
2019-11-05 18:57:48 +00:00
private :
TArray < FNotifyText > Text ;
int Top ;
int TopGoal ;
enum { NEWLINE , APPENDLINE , REPLACELINE } AddType ;
} ;
static FNotifyBuffer NotifyStrings ;
CUSTOM_CVAR ( Int , con_notifylines , NUMNOTIFIES , CVAR_GLOBALCONFIG | CVAR_ARCHIVE )
{
NotifyStrings . Shift ( self ) ;
}
2020-08-23 20:39:53 +00:00
int PrintColors [ PRINTLEVELS + 2 ] = { CR_UNTRANSLATED , CR_GOLD , CR_GRAY , CR_GREEN , CR_GREEN , CR_UNTRANSLATED } ;
2019-11-05 18:57:48 +00:00
static void setmsgcolor ( int index , int color ) ;
FILE * Logfile = NULL ;
FIntCVar msglevel ( " msg " , 0 , CVAR_ARCHIVE ) ;
2020-08-23 20:39:53 +00:00
CUSTOM_CVAR ( Int , msg0color , CR_UNTRANSLATED , CVAR_ARCHIVE )
2019-11-05 18:57:48 +00:00
{
setmsgcolor ( 0 , self ) ;
}
2020-08-23 20:39:53 +00:00
CUSTOM_CVAR ( Int , msg1color , CR_GOLD , CVAR_ARCHIVE )
2019-11-05 18:57:48 +00:00
{
setmsgcolor ( 1 , self ) ;
}
2020-08-23 20:39:53 +00:00
CUSTOM_CVAR ( Int , msg2color , CR_GRAY , CVAR_ARCHIVE )
2019-11-05 18:57:48 +00:00
{
setmsgcolor ( 2 , self ) ;
}
2020-08-23 20:39:53 +00:00
CUSTOM_CVAR ( Int , msg3color , CR_GREEN , CVAR_ARCHIVE )
2019-11-05 18:57:48 +00:00
{
setmsgcolor ( 3 , self ) ;
}
2020-08-23 20:39:53 +00:00
CUSTOM_CVAR ( Int , msg4color , CR_GREEN , CVAR_ARCHIVE )
2019-11-05 18:57:48 +00:00
{
setmsgcolor ( 4 , self ) ;
}
2020-08-23 20:39:53 +00:00
CUSTOM_CVAR ( Int , msgmidcolor , CR_UNTRANSLATED , CVAR_ARCHIVE )
2019-11-05 18:57:48 +00:00
{
setmsgcolor ( PRINTLEVELS , self ) ;
}
2020-08-23 20:39:53 +00:00
CUSTOM_CVAR ( Int , msgmidcolor2 , CR_BROWN , CVAR_ARCHIVE )
2019-11-05 18:57:48 +00:00
{
setmsgcolor ( PRINTLEVELS + 1 , self ) ;
}
void C_InitConback ( )
{
conback = TexMan . CheckForTexture ( " CONBACK " , ETextureType : : MiscPatch ) ;
if ( ! conback . isValid ( ) )
{
conback = TexMan . GetTextureID ( gameinfo . TitlePage , ETextureType : : MiscPatch ) ;
conshade = MAKEARGB ( 175 , 0 , 0 , 0 ) ;
conline = true ;
}
else
{
conshade = 0 ;
conline = false ;
}
}
void C_InitConsole ( int width , int height , bool ingame )
{
int cwidth , cheight ;
vidactive = ingame ;
if ( CurrentConsoleFont ! = NULL )
{
2020-04-05 20:51:53 +00:00
cwidth = CurrentConsoleFont - > GetCharWidth ( ' M ' ) ;
2019-11-05 18:57:48 +00:00
cheight = CurrentConsoleFont - > GetHeight ( ) ;
}
else
{
cwidth = cheight = 8 ;
}
ConWidth = ( width - LEFTMARGIN - RIGHTMARGIN ) ;
2020-10-10 21:16:08 +00:00
CmdLine . ConCols = ConWidth / cwidth ;
2019-11-05 18:57:48 +00:00
if ( conbuffer = = NULL ) conbuffer = new FConsoleBuffer ;
}
//==========================================================================
//
// CCMD atexit
//
//==========================================================================
2020-04-11 22:04:02 +00:00
UNSAFE_CCMD ( atexit )
2019-11-05 18:57:48 +00:00
{
if ( argv . argc ( ) = = 1 )
{
Printf ( " Registered atexit commands: \n " ) ;
GameAtExit * record = ExitCmdList ;
while ( record ! = NULL )
{
Printf ( " %s \n " , record - > Command . GetChars ( ) ) ;
record = record - > Next ;
}
return ;
}
for ( int i = 1 ; i < argv . argc ( ) ; + + i )
{
GameAtExit * record = new GameAtExit ( argv [ i ] ) ;
record - > Next = ExitCmdList ;
ExitCmdList = record ;
}
}
//==========================================================================
//
// C_DeinitConsole
//
// Executes the contents of the atexit cvar, if any, at quit time.
// Then releases all of the console's memory.
//
//==========================================================================
void C_DeinitConsole ( )
{
GameAtExit * cmd = ExitCmdList ;
while ( cmd ! = NULL )
{
GameAtExit * next = cmd - > Next ;
AddCommandString ( cmd - > Command ) ;
delete cmd ;
cmd = next ;
}
// Free command history
History * hist = HistTail ;
while ( hist ! = NULL )
{
History * next = hist - > Newer ;
delete hist ;
hist = next ;
}
HistTail = HistHead = HistPos = NULL ;
// Free cvars allocated at runtime
FBaseCVar * var , * next , * * nextp ;
for ( var = CVars , nextp = & CVars ; var ! = NULL ; var = next )
{
next = var - > m_Next ;
if ( var - > GetFlags ( ) & CVAR_UNSETTABLE )
{
delete var ;
* nextp = next ;
}
else
{
nextp = & var - > m_Next ;
}
}
// Free alias commands. (i.e. The "commands" that can be allocated
// at runtime.)
for ( size_t i = 0 ; i < countof ( Commands ) ; + + i )
{
FConsoleCommand * cmd = Commands [ i ] ;
while ( cmd ! = NULL )
{
FConsoleCommand * next = cmd - > m_Next ;
if ( cmd - > IsAlias ( ) )
{
delete cmd ;
}
cmd = next ;
}
}
// Make sure all tab commands are cleared before the memory for
// their names is deallocated.
C_ClearTabCommands ( ) ;
2019-12-24 17:53:29 +00:00
C_ClearDynCCmds ( ) ;
2019-11-05 18:57:48 +00:00
// Free AddToConsole()'s work buffer
if ( work ! = NULL )
{
free ( work ) ;
work = NULL ;
worklen = 0 ;
}
if ( conbuffer ! = NULL )
{
delete conbuffer ;
conbuffer = NULL ;
}
}
static void ClearConsole ( )
{
if ( conbuffer ! = NULL )
{
conbuffer - > Clear ( ) ;
}
TopLine = InsertLine = 0 ;
}
static void setmsgcolor ( int index , int color )
{
if ( ( unsigned ) color > = ( unsigned ) NUM_TEXT_COLORS )
color = 0 ;
PrintColors [ index ] = color ;
}
FNotifyBuffer : : FNotifyBuffer ( )
{
Top = TopGoal = 0 ;
AddType = NEWLINE ;
}
void FNotifyBuffer : : Shift ( int maxlines )
{
if ( maxlines > = 0 & & Text . Size ( ) > ( unsigned ) maxlines )
{
Text . Delete ( 0 , Text . Size ( ) - maxlines ) ;
}
}
void FNotifyBuffer : : AddString ( int printlevel , FString source )
{
TArray < FBrokenLines > lines ;
int width ;
2020-07-26 08:31:12 +00:00
if ( hud_messages = = 0 | |
2020-08-25 16:28:50 +00:00
screen = = nullptr | |
2019-11-05 18:57:48 +00:00
source . IsEmpty ( ) | |
2020-07-21 22:42:50 +00:00
gamestate = = GS_FULLCONSOLE | |
2020-08-10 22:46:27 +00:00
gamestate = = GS_MENUSCREEN | |
2019-11-05 18:57:48 +00:00
con_notifylines = = 0 )
return ;
2020-08-25 16:03:15 +00:00
auto screenratio = ActiveRatio ( screen - > GetWidth ( ) , screen - > GetHeight ( ) ) ;
2019-11-05 18:57:48 +00:00
2020-06-30 20:01:43 +00:00
FFont * font = generic_ui ? NewSmallFont : SmallFont ? SmallFont : AlternativeSmallFont ;
2019-11-05 18:57:48 +00:00
if ( font = = nullptr ) return ; // Without an initialized font we cannot handle the message (this is for those which come here before the font system is ready.)
2020-08-25 16:03:15 +00:00
double fontscale = ( generic_ui ? 0.7 : NotifyFontScale ) * con_notifyscale ;
width = int ( 320 * ( screenratio / 1.333 ) / fontscale ) ;
2019-11-05 18:57:48 +00:00
if ( AddType = = APPENDLINE & & Text . Size ( ) > 0 & & Text [ Text . Size ( ) - 1 ] . PrintLevel = = printlevel )
{
FString str = Text [ Text . Size ( ) - 1 ] . Text + source ;
2020-08-25 16:03:15 +00:00
lines = V_BreakLines ( font , width , str ) ;
2019-11-05 18:57:48 +00:00
}
else
{
2020-08-25 16:03:15 +00:00
lines = V_BreakLines ( font , width , source ) ;
2019-11-05 18:57:48 +00:00
if ( AddType = = APPENDLINE )
{
AddType = NEWLINE ;
}
}
if ( lines . Size ( ) = = 0 )
return ;
for ( auto & line : lines )
{
FNotifyText newline ;
newline . Text = line . Text ;
2020-04-11 22:04:02 +00:00
newline . TimeOut = int ( con_notifytime * GameTicRate ) ;
newline . Ticker = 0 ;
2019-11-05 18:57:48 +00:00
newline . PrintLevel = printlevel ;
if ( AddType = = NEWLINE | | Text . Size ( ) = = 0 )
{
if ( con_notifylines > 0 )
{
Shift ( con_notifylines - 1 ) ;
}
Text . Push ( newline ) ;
}
else
{
Text [ Text . Size ( ) - 1 ] = newline ;
}
AddType = NEWLINE ;
}
switch ( source [ source . Len ( ) - 1 ] )
{
case ' \r ' : AddType = REPLACELINE ; break ;
case ' \n ' : AddType = NEWLINE ; break ;
default : AddType = APPENDLINE ; break ;
}
TopGoal = 0 ;
}
void AddToConsole ( int printlevel , const char * text )
{
conbuffer - > AddText ( printlevel , MakeUTF8 ( text ) ) ;
}
//==========================================================================
//
//
//
//==========================================================================
void WriteLineToLog ( FILE * LogFile , const char * outline )
{
// Strip out any color escape sequences before writing to the log file
TArray < char > copy ( strlen ( outline ) + 1 ) ;
const char * srcp = outline ;
char * dstp = copy . Data ( ) ;
while ( * srcp ! = 0 )
{
if ( * srcp ! = TEXTCOLOR_ESCAPE )
{
* dstp + + = * srcp + + ;
}
else if ( srcp [ 1 ] = = ' [ ' )
{
srcp + = 2 ;
while ( * srcp ! = ' ] ' & & * srcp ! = 0 ) srcp + + ;
if ( * srcp = = ' ] ' ) srcp + + ;
}
else
{
if ( srcp [ 1 ] ! = 0 ) srcp + = 2 ;
else break ;
}
}
* dstp = 0 ;
fputs ( copy . Data ( ) , LogFile ) ;
fflush ( LogFile ) ;
}
2020-04-11 21:50:43 +00:00
extern bool gameisdead ;
2019-11-05 18:57:48 +00:00
int PrintString ( int iprintlevel , const char * outline )
{
2020-04-11 21:50:43 +00:00
if ( gameisdead )
return 0 ;
2019-11-05 18:57:48 +00:00
if ( ! conbuffer ) return 0 ; // when called too early
int printlevel = iprintlevel & PRINT_TYPES ;
if ( printlevel < msglevel | | * outline = = ' \0 ' )
{
return 0 ;
}
if ( printlevel ! = PRINT_LOG | | Logfile ! = nullptr )
{
// Convert everything coming through here to UTF-8 so that all console text is in a consistent format
int count ;
outline = MakeUTF8 ( outline , & count ) ;
if ( printlevel ! = PRINT_LOG )
{
I_PrintStr ( outline ) ;
conbuffer - > AddText ( printlevel , outline ) ;
2020-08-23 20:39:53 +00:00
if ( ! ( iprintlevel & PRINT_NONOTIFY ) )
2019-11-05 18:57:48 +00:00
{
2020-10-10 21:16:08 +00:00
if ( screen & & vidactive & & ( ( iprintlevel & PRINT_NOTIFY ) | | con_notify_advanced ) )
2020-08-23 20:39:53 +00:00
{
NotifyStrings . AddString ( printlevel , outline ) ;
}
2019-11-05 18:57:48 +00:00
}
}
if ( Logfile ! = nullptr & & ! ( iprintlevel & PRINT_NOLOG ) )
{
WriteLineToLog ( Logfile , outline ) ;
}
return count ;
}
return 0 ; // Don't waste time on calculating this if nothing at all was printed...
}
2020-09-04 20:23:38 +00:00
void C_ClearMessages ( )
{
NotifyStrings . Clear ( ) ;
}
2019-11-05 18:57:48 +00:00
int VPrintf ( int printlevel , const char * format , va_list parms )
{
FString outline ;
outline . VFormat ( format , parms ) ;
return PrintString ( printlevel , outline . GetChars ( ) ) ;
}
int Printf ( int printlevel , const char * format , . . . )
{
va_list argptr ;
int count ;
va_start ( argptr , format ) ;
count = VPrintf ( printlevel , format , argptr ) ;
va_end ( argptr ) ;
return count ;
}
int Printf ( const char * format , . . . )
{
va_list argptr ;
int count ;
va_start ( argptr , format ) ;
count = VPrintf ( PRINT_HIGH , format , argptr ) ;
va_end ( argptr ) ;
return count ;
}
int DPrintf ( int level , const char * format , . . . )
{
va_list argptr ;
int count ;
if ( developer > = level )
{
va_start ( argptr , format ) ;
count = VPrintf ( PRINT_HIGH , format , argptr ) ;
va_end ( argptr ) ;
return count ;
}
else
{
return 0 ;
}
}
void C_FlushDisplay ( )
{
NotifyStrings . Clear ( ) ;
}
void C_AdjustBottom ( )
{
2020-07-21 22:42:50 +00:00
if ( gamestate = = GS_FULLCONSOLE | | gamestate = = GS_STARTUP )
ConBottom = twod - > GetHeight ( ) ;
else if ( ConBottom > twod - > GetHeight ( ) / 2 | | ConsoleState = = c_down )
2020-04-11 21:27:37 +00:00
ConBottom = twod - > GetHeight ( ) / 2 ;
2019-11-05 18:57:48 +00:00
}
void C_NewModeAdjust ( )
{
2020-04-30 10:28:10 +00:00
C_InitConsole ( screen - > GetWidth ( ) , screen - > GetHeight ( ) , true ) ;
2019-11-05 18:57:48 +00:00
C_FlushDisplay ( ) ;
C_AdjustBottom ( ) ;
}
int consoletic = 0 ;
void C_Ticker ( )
{
static int lasttic = 0 ;
consoletic + + ;
if ( lasttic = = 0 )
lasttic = consoletic - 1 ;
if ( con_buffersize > 0 )
{
conbuffer - > ResizeBuffer ( con_buffersize ) ;
}
if ( ConsoleState ! = c_up )
{
if ( ConsoleState = = c_falling )
{
2020-04-11 21:27:37 +00:00
ConBottom + = ( consoletic - lasttic ) * ( twod - > GetHeight ( ) * 2 / 25 ) ;
if ( ConBottom > = twod - > GetHeight ( ) / 2 )
2019-11-05 18:57:48 +00:00
{
2020-04-11 21:27:37 +00:00
ConBottom = twod - > GetHeight ( ) / 2 ;
2019-11-05 18:57:48 +00:00
ConsoleState = c_down ;
}
}
else if ( ConsoleState = = c_rising )
{
2020-04-11 21:27:37 +00:00
ConBottom - = ( consoletic - lasttic ) * ( twod - > GetHeight ( ) * 2 / 25 ) ;
2019-11-05 18:57:48 +00:00
if ( ConBottom < = 0 )
{
ConsoleState = c_up ;
ConBottom = 0 ;
}
}
}
lasttic = consoletic ;
NotifyStrings . Tick ( ) ;
}
void FNotifyBuffer : : Tick ( )
{
if ( TopGoal > Top )
{
Top + + ;
}
else if ( TopGoal < Top )
{
Top - - ;
}
// Remove lines from the beginning that have expired.
unsigned i ;
for ( i = 0 ; i < Text . Size ( ) ; + + i )
{
2020-04-11 22:04:02 +00:00
Text [ i ] . Ticker + + ;
}
for ( i = 0 ; i < Text . Size ( ) ; + + i )
{
if ( Text [ i ] . TimeOut ! = 0 & & Text [ i ] . TimeOut > Text [ i ] . Ticker )
2019-11-05 18:57:48 +00:00
break ;
}
2020-04-11 22:04:02 +00:00
if ( i > 0 )
2019-11-05 18:57:48 +00:00
{
Text . Delete ( 0 , i ) ;
2020-06-30 20:01:43 +00:00
FFont * font = generic_ui ? NewSmallFont : SmallFont ? SmallFont : AlternativeSmallFont ;
2020-08-19 14:40:54 +00:00
Top + = font - > GetHeight ( ) / NotifyFontScale ;
2019-11-05 18:57:48 +00:00
}
}
2020-08-23 20:39:53 +00:00
void FNotifyBuffer : : DrawNative ( )
{
// Native display is:
// * centered at the top and pulsing for Duke
// * centered shifted down and not pulsing for Shadow Warrior
// * top left for Exhumed
// * 4 lines with the tiny font for Blood. (same mechanic as the regular one, just a different font and scale.)
bool center = g_gameType & ( GAMEFLAG_DUKE | GAMEFLAG_NAM | GAMEFLAG_WW2GI | GAMEFLAG_RR | GAMEFLAG_SW ) ;
bool pulse = g_gameType & ( GAMEFLAG_DUKE | GAMEFLAG_NAM | GAMEFLAG_WW2GI | GAMEFLAG_RR ) ;
unsigned topline = g_gameType & GAMEFLAG_BLOOD ? 0 : Text . Size ( ) - 1 ;
FFont * font = g_gameType & GAMEFLAG_BLOOD ? SmallFont2 : SmallFont ;
int line = ( g_gameType & GAMEFLAG_BLOOD ) ? Top : ( g_gameType & GAMEFLAG_SW ) ? 40 : font - > GetDisplacement ( ) ;
bool canskip = ( g_gameType & GAMEFLAG_BLOOD ) ;
2020-08-25 16:03:15 +00:00
double scale = 1 / ( NotifyFontScale * con_notifyscale ) ;
int lineadv = font - > GetHeight ( ) / NotifyFontScale ;
2020-08-23 20:39:53 +00:00
for ( unsigned i = topline ; i < Text . Size ( ) ; + + i )
{
FNotifyText & notify = Text [ i ] ;
if ( notify . TimeOut = = 0 )
continue ;
int j = notify . TimeOut - notify . Ticker ;
if ( j > 0 )
{
double alpha = g_gameType & GAMEFLAG_BLOOD ? ( ( j < NOTIFYFADETIME ) ? 1. * j / NOTIFYFADETIME : 1 ) : 1 ;
if ( pulse )
{
alpha * = 0.7 + 0.3 * sin ( I_msTime ( ) / 100. ) ;
}
if ( ! center )
{
DrawText ( twod , font , CR_UNTRANSLATED , 0 , line , notify . Text ,
DTA_FullscreenScale , FSMode_ScaleToHeight ,
2020-08-25 16:03:15 +00:00
DTA_VirtualWidthF , 320 * scale , DTA_VirtualHeightF , 200 * scale , DTA_KeepRatio , true ,
2020-08-23 20:39:53 +00:00
DTA_Alpha , alpha , TAG_DONE ) ;
}
else
{
2020-08-25 16:03:15 +00:00
DrawText ( twod , font , CR_UNTRANSLATED , 160 * scale - font - > StringWidth ( notify . Text ) / 2 , line , notify . Text ,
2020-08-23 20:39:53 +00:00
DTA_FullscreenScale , FSMode_ScaleToHeight ,
2020-08-25 16:03:15 +00:00
DTA_VirtualWidthF , 320 * scale , DTA_VirtualHeightF , 200 * scale ,
2020-08-23 20:39:53 +00:00
DTA_Alpha , alpha , TAG_DONE ) ;
}
line + = lineadv ;
canskip = false ;
}
else
{
notify . TimeOut = 0 ;
}
}
if ( canskip )
{
Top = TopGoal ;
}
}
2020-09-29 20:20:25 +00:00
static bool printNative ( )
{
// Blood originally uses its tiny font for the notify display which does not play along well with localization because it is too small
if ( con_notify_advanced ) return false ;
if ( ! ( g_gameType & GAMEFLAG_BLOOD ) ) return true ;
auto p = GStrings [ " REQUIRED_CHARACTERS " ] ;
if ( p & & * p ) return false ;
return true ;
}
2019-11-05 18:57:48 +00:00
void FNotifyBuffer : : Draw ( )
{
2020-08-10 22:46:27 +00:00
if ( gamestate = = GS_FULLCONSOLE | | gamestate = = GS_MENUSCREEN )
2020-07-21 22:42:50 +00:00
return ;
2019-11-05 18:57:48 +00:00
2020-09-29 20:20:25 +00:00
if ( printNative ( ) )
2020-08-23 20:39:53 +00:00
{
DrawNative ( ) ;
return ;
}
bool center = ( con_centernotify ! = 0.f ) ;
int color ;
2020-08-25 16:03:15 +00:00
bool canskip = true ;
2020-08-23 20:39:53 +00:00
2019-11-05 18:57:48 +00:00
2020-08-25 16:03:15 +00:00
FFont * font = generic_ui ? NewSmallFont : SmallFont ? SmallFont : AlternativeSmallFont ;
double nfscale = ( generic_ui ? 0.7 : NotifyFontScale ) ;
double scale = 1 / ( * con_notifyscale ) ;
2019-11-05 18:57:48 +00:00
2020-08-25 16:03:15 +00:00
int line = Top + font - > GetDisplacement ( ) / nfscale ;
int lineadv = font - > GetHeight ( ) / nfscale ;
2019-11-05 18:57:48 +00:00
for ( unsigned i = 0 ; i < Text . Size ( ) ; + + i )
{
FNotifyText & notify = Text [ i ] ;
if ( notify . TimeOut = = 0 )
continue ;
2020-08-23 20:39:53 +00:00
int j = notify . TimeOut - notify . Ticker ;
2019-11-05 18:57:48 +00:00
if ( j > 0 )
{
double alpha = ( j < NOTIFYFADETIME ) ? 1. * j / NOTIFYFADETIME : 1 ;
2020-08-23 20:39:53 +00:00
if ( con_pulsetext )
2020-06-30 20:53:15 +00:00
{
alpha * = 0.7 + 0.3 * sin ( I_msTime ( ) / 100. ) ;
}
2019-11-05 18:57:48 +00:00
if ( notify . PrintLevel > = PRINTLEVELS )
color = CR_UNTRANSLATED ;
else
color = PrintColors [ notify . PrintLevel ] ;
if ( ! center )
2020-08-19 14:40:54 +00:00
DrawText ( twod , font , color , 0 , line * NotifyFontScale , notify . Text ,
2020-08-25 16:03:15 +00:00
DTA_FullscreenScale , FSMode_ScaleToHeight ,
DTA_VirtualWidthF , 320. * scale ,
DTA_VirtualHeightF , 200. * scale ,
2019-11-05 18:57:48 +00:00
DTA_KeepRatio , true ,
DTA_Alpha , alpha , TAG_DONE ) ;
else
2020-08-25 16:03:15 +00:00
DrawText ( twod , font , color , 160 * scale - font - > StringWidth ( notify . Text ) / 2. ,
2019-11-05 18:57:48 +00:00
line , notify . Text ,
2020-08-25 16:03:15 +00:00
DTA_FullscreenScale , FSMode_ScaleToHeight ,
DTA_VirtualWidthF , 320. * scale ,
DTA_VirtualHeightF , 200. * scale ,
2019-11-05 18:57:48 +00:00
DTA_Alpha , alpha , TAG_DONE ) ;
line + = lineadv ;
canskip = false ;
}
else
{
notify . TimeOut = 0 ;
}
}
if ( canskip )
{
Top = TopGoal ;
}
}
void C_DrawConsole ( )
{
static int oldbottom = 0 ;
int lines , left , offset ;
2020-05-25 15:11:32 +00:00
int textScale = active_con_scale ( twod ) ;
2019-11-05 18:57:48 +00:00
left = LEFTMARGIN ;
lines = ( ConBottom / textScale - CurrentConsoleFont - > GetHeight ( ) * 2 ) / CurrentConsoleFont - > GetHeight ( ) ;
if ( - CurrentConsoleFont - > GetHeight ( ) + lines * CurrentConsoleFont - > GetHeight ( ) > ConBottom / textScale - CurrentConsoleFont - > GetHeight ( ) * 7 / 2 )
{
offset = - CurrentConsoleFont - > GetHeight ( ) / 2 ;
lines - - ;
}
else
{
offset = - CurrentConsoleFont - > GetHeight ( ) ;
}
oldbottom = ConBottom ;
2020-09-05 16:41:18 +00:00
if ( ConsoleState = = c_up & & gamestate ! = GS_INTRO & & gamestate ! = GS_INTERMISSION )
2019-11-05 18:57:48 +00:00
{
NotifyStrings . Draw ( ) ;
return ;
}
else if ( ConBottom )
{
int visheight ;
visheight = ConBottom ;
2020-10-10 21:16:08 +00:00
if ( conback . isValid ( ) )
2019-11-05 18:57:48 +00:00
{
2020-10-10 21:16:08 +00:00
DrawTexture ( twod , TexMan . GetGameTexture ( conback ) , 0 , visheight - screen - > GetHeight ( ) ,
DTA_DestWidth , twod - > GetWidth ( ) ,
DTA_DestHeight , twod - > GetHeight ( ) ,
DTA_ColorOverlay , conshade ,
DTA_Alpha , ( gamestate ! = GS_FULLCONSOLE ) ? ( double ) con_alpha : 1. ,
DTA_Masked , false ,
TAG_DONE ) ;
2019-11-05 18:57:48 +00:00
}
else
{
PalEntry pe ( ( uint8_t ) ( con_alpha * 255 ) , 0 , 0 , 0 ) ;
2019-12-30 18:29:32 +00:00
twod - > AddColorOnlyQuad ( 0 , 0 , screen - > GetWidth ( ) , visheight , pe ) ;
2019-11-05 18:57:48 +00:00
}
if ( conline & & visheight < screen - > GetHeight ( ) )
{
2020-10-11 05:44:51 +00:00
twod - > AddColorOnlyQuad ( 0 , visheight , screen - > GetWidth ( ) , 1 , 0xff000000 ) ;
2019-11-05 18:57:48 +00:00
}
if ( ConBottom > = 12 )
{
if ( textScale = = 1 )
2020-04-11 21:27:37 +00:00
DrawText ( twod , CurrentConsoleFont , CR_ORANGE , twod - > GetWidth ( ) - 8 -
2019-11-05 18:57:48 +00:00
CurrentConsoleFont - > StringWidth ( GetVersionString ( ) ) ,
ConBottom / textScale - CurrentConsoleFont - > GetHeight ( ) - 4 ,
GetVersionString ( ) , TAG_DONE ) ;
else
2020-04-11 21:27:37 +00:00
DrawText ( twod , CurrentConsoleFont , CR_ORANGE , twod - > GetWidth ( ) / textScale - 8 -
2019-11-05 18:57:48 +00:00
CurrentConsoleFont - > StringWidth ( GetVersionString ( ) ) ,
ConBottom / textScale - CurrentConsoleFont - > GetHeight ( ) - 4 ,
GetVersionString ( ) ,
2020-04-11 21:27:37 +00:00
DTA_VirtualWidth , twod - > GetWidth ( ) / textScale ,
DTA_VirtualHeight , twod - > GetHeight ( ) / textScale ,
2019-11-05 18:57:48 +00:00
DTA_KeepRatio , true , TAG_DONE ) ;
}
}
if ( menuactive ! = MENU_Off )
{
return ;
}
if ( lines > 0 )
{
// No more enqueuing because adding new text to the console won't touch the actual print data.
conbuffer - > FormatText ( CurrentConsoleFont , ConWidth / textScale ) ;
unsigned int consolelines = conbuffer - > GetFormattedLineCount ( ) ;
FBrokenLines * blines = conbuffer - > GetLines ( ) ;
FBrokenLines * printline = blines + consolelines - 1 - RowAdjust ;
int bottomline = ConBottom / textScale - CurrentConsoleFont - > GetHeight ( ) * 2 - 4 ;
for ( FBrokenLines * p = printline ; p > = blines & & lines > 0 ; p - - , lines - - )
{
if ( textScale = = 1 )
{
2019-12-30 18:29:32 +00:00
DrawText ( twod , CurrentConsoleFont , CR_TAN , LEFTMARGIN , offset + lines * CurrentConsoleFont - > GetHeight ( ) , p - > Text , TAG_DONE ) ;
2019-11-05 18:57:48 +00:00
}
else
{
2019-12-30 18:29:32 +00:00
DrawText ( twod , CurrentConsoleFont , CR_TAN , LEFTMARGIN , offset + lines * CurrentConsoleFont - > GetHeight ( ) , p - > Text ,
2020-04-11 21:27:37 +00:00
DTA_VirtualWidth , twod - > GetWidth ( ) / textScale ,
DTA_VirtualHeight , twod - > GetHeight ( ) / textScale ,
2019-11-05 18:57:48 +00:00
DTA_KeepRatio , true , TAG_DONE ) ;
}
}
if ( ConBottom > = 20 )
{
2020-04-11 22:04:02 +00:00
if ( gamestate ! = GS_STARTUP )
2019-11-05 18:57:48 +00:00
{
2020-04-11 22:04:02 +00:00
auto now = I_msTime ( ) ;
if ( now > CursorTicker )
{
CursorTicker = now + 500 ;
cursoron = ! cursoron ;
}
2019-11-05 18:57:48 +00:00
CmdLine . Draw ( left , bottomline , textScale , cursoron ) ;
}
if ( RowAdjust & & ConBottom > = CurrentConsoleFont - > GetHeight ( ) * 7 / 2 )
{
// Indicate that the view has been scrolled up (10)
// and if we can scroll no further (12)
if ( textScale = = 1 )
2020-04-11 21:27:37 +00:00
DrawChar ( twod , CurrentConsoleFont , CR_GREEN , 0 , bottomline , RowAdjust = = conbuffer - > GetFormattedLineCount ( ) ? 12 : 10 , TAG_DONE ) ;
2019-11-05 18:57:48 +00:00
else
2019-12-30 18:29:32 +00:00
DrawChar ( twod , CurrentConsoleFont , CR_GREEN , 0 , bottomline , RowAdjust = = conbuffer - > GetFormattedLineCount ( ) ? 12 : 10 ,
2020-04-11 21:27:37 +00:00
DTA_VirtualWidth , twod - > GetWidth ( ) / textScale ,
DTA_VirtualHeight , twod - > GetHeight ( ) / textScale ,
2019-11-05 18:57:48 +00:00
DTA_KeepRatio , true , TAG_DONE ) ;
}
}
}
}
void C_FullConsole ( )
{
2020-07-21 22:42:50 +00:00
/*
2019-11-05 18:57:48 +00:00
if ( hud_toggled )
D_ToggleHud ( ) ;
if ( demoplayback )
G_CheckDemoStatus ( ) ;
D_QuitNetGame ( ) ;
advancedemo = false ;
2020-07-21 22:42:50 +00:00
*/
2019-11-05 18:57:48 +00:00
ConsoleState = c_down ;
HistPos = NULL ;
TabbedLast = false ;
TabbedList = false ;
if ( gamestate ! = GS_STARTUP )
{
gamestate = GS_FULLCONSOLE ;
2020-07-21 22:42:50 +00:00
Mus_Stop ( ) ;
2019-11-05 18:57:48 +00:00
}
2020-07-21 22:42:50 +00:00
C_AdjustBottom ( ) ;
2019-11-05 18:57:48 +00:00
}
void C_ToggleConsole ( )
{
2020-07-21 22:42:50 +00:00
if ( gamestate = = GS_INTRO ) // blocked
2019-11-05 18:57:48 +00:00
{
2020-07-21 22:42:50 +00:00
return ;
2019-11-05 18:57:48 +00:00
}
2020-08-10 22:46:27 +00:00
if ( gamestate = = GS_MENUSCREEN )
2020-07-21 22:42:50 +00:00
{
gamestate = GS_FULLCONSOLE ;
C_FullConsole ( ) ;
}
else if ( ! chatmodeon & & ( ConsoleState = = c_up | | ConsoleState = = c_rising ) & & menuactive = = MENU_Off )
2019-11-05 18:57:48 +00:00
{
ConsoleState = c_falling ;
HistPos = NULL ;
TabbedLast = false ;
TabbedList = false ;
2020-04-23 19:18:40 +00:00
2019-11-05 18:57:48 +00:00
}
2020-07-21 22:42:50 +00:00
else if ( gamestate ! = GS_FULLCONSOLE & & gamestate ! = GS_STARTUP )
2019-11-05 18:57:48 +00:00
{
ConsoleState = c_rising ;
C_FlushDisplay ( ) ;
}
}
void C_HideConsole ( )
{
2020-04-11 22:04:02 +00:00
if ( gamestate ! = GS_FULLCONSOLE )
2019-11-05 18:57:48 +00:00
{
ConsoleState = c_up ;
ConBottom = 0 ;
HistPos = NULL ;
}
}
static bool C_HandleKey ( event_t * ev , FCommandBuffer & buffer )
{
int data1 = ev - > data1 ;
bool keepappending = false ;
switch ( ev - > subtype )
{
default :
return false ;
case EV_GUI_Char :
if ( ev - > data2 )
{
// Bash-style shortcuts
if ( data1 = = ' b ' )
{
buffer . CursorWordLeft ( ) ;
break ;
}
else if ( data1 = = ' f ' )
{
buffer . CursorWordRight ( ) ;
break ;
}
}
// Add keypress to command line
buffer . AddChar ( data1 ) ;
HistPos = NULL ;
TabbedLast = false ;
TabbedList = false ;
break ;
case EV_GUI_WheelUp :
case EV_GUI_WheelDown :
if ( ! ( ev - > data3 & GKM_SHIFT ) )
{
data1 = GK_PGDN + EV_GUI_WheelDown - ev - > subtype ;
}
else
{
data1 = GK_DOWN + EV_GUI_WheelDown - ev - > subtype ;
}
// Intentional fallthrough
case EV_GUI_KeyDown :
case EV_GUI_KeyRepeat :
switch ( data1 )
{
case ' \t ' :
// Try to do tab-completion
C_TabComplete ( ( ev - > data3 & GKM_SHIFT ) ? false : true ) ;
break ;
case GK_PGUP :
if ( ev - > data3 & ( GKM_SHIFT | GKM_CTRL ) )
{ // Scroll console buffer up one page
2020-09-27 07:29:37 +00:00
RowAdjust + = ( twod - > GetHeight ( ) - 4 ) / active_con_scale ( twod ) /
2020-07-21 22:42:50 +00:00
( ( gamestate = = GS_FULLCONSOLE | | gamestate = = GS_STARTUP ) ? CurrentConsoleFont - > GetHeight ( ) : CurrentConsoleFont - > GetHeight ( ) * 2 ) - 3 ;
2019-11-05 18:57:48 +00:00
}
else if ( RowAdjust < conbuffer - > GetFormattedLineCount ( ) )
{ // Scroll console buffer up
if ( ev - > subtype = = EV_GUI_WheelUp )
{
RowAdjust + = 3 ;
}
else
{
RowAdjust + + ;
}
if ( RowAdjust > conbuffer - > GetFormattedLineCount ( ) )
{
RowAdjust = conbuffer - > GetFormattedLineCount ( ) ;
}
}
break ;
case GK_PGDN :
if ( ev - > data3 & ( GKM_SHIFT | GKM_CTRL ) )
{ // Scroll console buffer down one page
2020-09-27 07:29:37 +00:00
const int scrollamt = ( twod - > GetHeight ( ) - 4 ) / active_con_scale ( twod ) /
2020-07-21 22:42:50 +00:00
( ( gamestate = = GS_FULLCONSOLE | | gamestate = = GS_STARTUP ) ? CurrentConsoleFont - > GetHeight ( ) : CurrentConsoleFont - > GetHeight ( ) * 2 ) - 3 ;
2019-11-05 18:57:48 +00:00
if ( RowAdjust < scrollamt )
{
RowAdjust = 0 ;
}
else
{
RowAdjust - = scrollamt ;
}
}
else if ( RowAdjust > 0 )
{ // Scroll console buffer down
if ( ev - > subtype = = EV_GUI_WheelDown )
{
RowAdjust = std : : max ( 0 , RowAdjust - 3 ) ;
}
else
{
RowAdjust - - ;
}
}
break ;
case GK_HOME :
if ( ev - > data3 & GKM_CTRL )
{ // Move to top of console buffer
RowAdjust = conbuffer - > GetFormattedLineCount ( ) ;
}
else
{ // Move cursor to start of line
buffer . CursorStart ( ) ;
}
break ;
case GK_END :
if ( ev - > data3 & GKM_CTRL )
{ // Move to bottom of console buffer
RowAdjust = 0 ;
}
else
{ // Move cursor to end of line
buffer . CursorEnd ( ) ;
}
break ;
case GK_LEFT :
// Move cursor left one character
buffer . CursorLeft ( ) ;
break ;
case GK_RIGHT :
// Move cursor right one character
buffer . CursorRight ( ) ;
break ;
case ' \b ' :
// Erase character to left of cursor
buffer . DeleteLeft ( ) ;
TabbedLast = false ;
TabbedList = false ;
break ;
case GK_DEL :
// Erase character under cursor
buffer . DeleteRight ( ) ;
TabbedLast = false ;
TabbedList = false ;
break ;
case GK_UP :
// Move to previous entry in the command history
if ( HistPos = = NULL )
{
HistPos = HistHead ;
}
else if ( HistPos - > Older )
{
HistPos = HistPos - > Older ;
}
if ( HistPos )
{
buffer . SetString ( HistPos - > String ) ;
}
TabbedLast = false ;
TabbedList = false ;
break ;
case GK_DOWN :
// Move to next entry in the command history
if ( HistPos & & HistPos - > Newer )
{
HistPos = HistPos - > Newer ;
buffer . SetString ( HistPos - > String ) ;
}
else
{
HistPos = NULL ;
buffer . SetString ( " " ) ;
}
TabbedLast = false ;
TabbedList = false ;
break ;
case ' X ' :
if ( ev - > data3 & GKM_CTRL )
{
buffer . SetString ( " " ) ;
TabbedLast = TabbedList = false ;
}
break ;
case ' D ' :
if ( ev - > data3 & GKM_CTRL & & buffer . TextLength ( ) = = 0 )
{ // Control-D pressed on an empty line
if ( strlen ( con_ctrl_d ) = = 0 )
{
break ; // Replacement is empty, so do nothing
}
buffer . SetString ( * con_ctrl_d ) ;
}
else
{
break ;
}
// Intentional fall-through for command(s) added with Ctrl-D
case ' \r ' :
{
// Execute command line (ENTER)
FString bufferText = buffer . GetText ( ) ;
bufferText . StripLeftRight ( ) ;
Printf ( 127 , TEXTCOLOR_WHITE " ]%s \n " , bufferText . GetChars ( ) ) ;
if ( bufferText . Len ( ) = = 0 )
{
// Command line is empty, so do nothing to the history
}
else if ( HistHead & & HistHead - > String . CompareNoCase ( bufferText ) = = 0 )
{
// Command line was the same as the previous one,
// so leave the history list alone
}
else
{
// Command line is different from last command line,
// or there is nothing in the history list,
// so add it to the history list.
History * temp = new History ;
temp - > String = bufferText ;
temp - > Older = HistHead ;
if ( HistHead )
{
HistHead - > Newer = temp ;
}
temp - > Newer = NULL ;
HistHead = temp ;
if ( ! HistTail )
{
HistTail = temp ;
}
if ( HistSize = = MAXHISTSIZE )
{
HistTail = HistTail - > Newer ;
delete HistTail - > Older ;
HistTail - > Older = NULL ;
}
else
{
HistSize + + ;
}
}
HistPos = NULL ;
buffer . SetString ( " " ) ;
AddCommandString ( bufferText ) ;
TabbedLast = false ;
TabbedList = false ;
break ;
}
case ' ` ' :
// Check to see if we have ` bound to the console before accepting
// it as a way to close the console.
if ( Bindings . GetBinding ( KEY_GRAVE ) . CompareNoCase ( " toggleconsole " ) )
{
break ;
}
case GK_ESCAPE :
// Close console and clear command line. But if we're in the
// fullscreen console mode, there's nothing to fall back on
// if it's closed, so open the main menu instead.
if ( gamestate = = GS_STARTUP )
{
return false ;
}
else if ( gamestate = = GS_FULLCONSOLE )
{
C_DoCommand ( " menu_main " ) ;
}
else
{
buffer . SetString ( " " ) ;
HistPos = NULL ;
C_ToggleConsole ( ) ;
}
break ;
case ' C ' :
case ' V ' :
TabbedLast = false ;
TabbedList = false ;
# ifdef __APPLE__
if ( ev - > data3 & GKM_META )
# else // !__APPLE__
if ( ev - > data3 & GKM_CTRL )
# endif // __APPLE__
{
if ( data1 = = ' C ' )
{ // copy to clipboard
if ( buffer . TextLength ( ) > 0 )
{
I_PutInClipboard ( buffer . GetText ( ) ) ;
}
}
else
{ // paste from clipboard
buffer . AddString ( I_GetFromClipboard ( false ) ) ;
HistPos = NULL ;
}
break ;
}
break ;
// Bash-style shortcuts
case ' A ' :
if ( ev - > data3 & GKM_CTRL )
{
buffer . CursorStart ( ) ;
}
break ;
case ' E ' :
if ( ev - > data3 & GKM_CTRL )
{
buffer . CursorEnd ( ) ;
}
break ;
case ' W ' :
if ( ev - > data3 & GKM_CTRL )
{
buffer . DeleteWordLeft ( ) ;
keepappending = true ;
TabbedLast = false ;
TabbedList = false ;
}
break ;
case ' U ' :
if ( ev - > data3 & GKM_CTRL )
{
buffer . DeleteLineLeft ( ) ;
keepappending = true ;
TabbedLast = false ;
TabbedList = false ;
}
break ;
case ' K ' :
if ( ev - > data3 & GKM_CTRL )
{
buffer . DeleteLineRight ( ) ;
keepappending = true ;
TabbedLast = false ;
TabbedList = false ;
}
break ;
case ' Y ' :
if ( ev - > data3 & GKM_CTRL )
{
buffer . AddYankBuffer ( ) ;
TabbedLast = false ;
TabbedList = false ;
HistPos = NULL ;
}
break ;
}
break ;
# ifdef __unix__
case EV_GUI_MButtonDown :
buffer . AddString ( I_GetFromClipboard ( true ) ) ;
HistPos = NULL ;
break ;
# endif
}
buffer . AppendToYankBuffer = keepappending ;
// Ensure that the cursor is always visible while typing
2020-04-11 22:04:02 +00:00
CursorTicker = I_msTime ( ) + 500 ;
2019-11-05 18:57:48 +00:00
cursoron = 1 ;
return true ;
}
bool C_Responder ( event_t * ev )
{
if ( ev - > type ! = EV_GUI_Event | |
ConsoleState = = c_up | |
2020-07-21 22:42:50 +00:00
ConsoleState = = c_rising | |
menuactive ! = MENU_Off )
2019-11-05 18:57:48 +00:00
{
return false ;
}
return C_HandleKey ( ev , CmdLine ) ;
}
CCMD ( history )
{
struct History * hist = HistTail ;
while ( hist )
{
Printf ( " %s \n " , hist - > String . GetChars ( ) ) ;
hist = hist - > Newer ;
}
}
CCMD ( clear )
{
C_FlushDisplay ( ) ;
ClearConsole ( ) ;
}
CCMD ( echo )
{
int last = argv . argc ( ) - 1 ;
for ( int i = 1 ; i < = last ; + + i )
{
FString formatted = strbin1 ( argv [ i ] ) ;
Printf ( " %s%s " , formatted . GetChars ( ) , i ! = last ? " " : " \n " ) ;
}
}
2019-11-06 22:40:10 +00:00
CCMD ( toggleconsole )
{
C_ToggleConsole ( ) ;
}
2019-11-05 18:57:48 +00:00
/* Printing in the middle of the screen */
CVAR ( Float , con_midtime , 3.f , CVAR_ARCHIVE )
const char * console_bar = " ---------------------------------------- " ;
void C_MidPrint ( FFont * font , const char * msg , bool bold )
{
2020-06-14 16:57:55 +00:00
#if 0 // The Build engine cannot do this at the moment. Q: Implement and redirect some messages here?
2019-11-05 18:57:48 +00:00
if ( StatusBar = = nullptr | | screen = = nullptr )
return ;
// [MK] allow the status bar to take over MidPrint
IFVIRTUALPTR ( StatusBar , DBaseStatusBar , ProcessMidPrint )
{
FString msgstr = msg ;
VMValue params [ ] = { ( DObject * ) StatusBar , font , & msgstr , bold } ;
int rv ;
VMReturn ret ( & rv ) ;
VMCall ( func , params , countof ( params ) , & ret , 1 ) ;
if ( ! ! rv ) return ;
}
if ( msg ! = nullptr )
{
auto color = ( EColorRange ) PrintColors [ bold ? PRINTLEVELS + 1 : PRINTLEVELS ] ;
2020-09-27 07:29:37 +00:00
Printf ( PRINT_HIGH | PRINT_NONOTIFY , TEXTCOLOR_ESCAPESTR " %c%s \n %s \n %s \n " , color , console_bar , msg , console_bar ) ;
2019-11-05 18:57:48 +00:00
StatusBar - > AttachMessage ( Create < DHUDMessage > ( font , msg , 1.5f , 0.375f , 0 , 0 , color , con_midtime ) , MAKE_ID ( ' C ' , ' N ' , ' T ' , ' R ' ) ) ;
}
else
{
StatusBar - > DetachMessage ( MAKE_ID ( ' C ' , ' N ' , ' T ' , ' R ' ) ) ;
}
# endif
2020-06-14 16:57:55 +00:00
}
2019-11-05 18:57:48 +00:00