2014-03-15 16:59:03 +00:00
|
|
|
// SONIC ROBO BLAST 2
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
2022-03-03 19:24:46 +00:00
|
|
|
// Copyright (C) 1999-2022 by Sonic Team Junior.
|
2014-03-15 16:59:03 +00:00
|
|
|
//
|
|
|
|
// This program is free software distributed under the
|
|
|
|
// terms of the GNU General Public License, version 2.
|
|
|
|
// See the 'LICENSE' file for more details.
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/// \file console.c
|
|
|
|
/// \brief Console drawing and input
|
|
|
|
|
|
|
|
#ifdef __GNUC__
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "doomdef.h"
|
|
|
|
#include "console.h"
|
|
|
|
#include "g_game.h"
|
|
|
|
#include "g_input.h"
|
|
|
|
#include "hu_stuff.h"
|
|
|
|
#include "keys.h"
|
2019-09-09 01:25:18 +00:00
|
|
|
#include "r_main.h"
|
2014-03-15 16:59:03 +00:00
|
|
|
#include "r_defs.h"
|
|
|
|
#include "sounds.h"
|
|
|
|
#include "st_stuff.h"
|
|
|
|
#include "s_sound.h"
|
|
|
|
#include "v_video.h"
|
|
|
|
#include "i_video.h"
|
|
|
|
#include "z_zone.h"
|
|
|
|
#include "i_system.h"
|
2020-04-28 20:08:43 +00:00
|
|
|
#include "i_threads.h"
|
2014-03-15 16:59:03 +00:00
|
|
|
#include "d_main.h"
|
|
|
|
#include "m_menu.h"
|
2017-04-29 15:40:07 +00:00
|
|
|
#include "filesrch.h"
|
2020-01-08 20:58:19 +00:00
|
|
|
#include "m_misc.h"
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
#include "win32/win_main.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HWRENDER
|
|
|
|
#include "hardware/hw_main.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define MAXHUDLINES 20
|
|
|
|
|
2020-04-28 20:08:43 +00:00
|
|
|
#ifdef HAVE_THREADS
|
|
|
|
I_mutex con_mutex;
|
|
|
|
|
|
|
|
# define Lock_state() I_lock_mutex(&con_mutex)
|
|
|
|
# define Unlock_state() I_unlock_mutex(con_mutex)
|
|
|
|
#else/*HAVE_THREADS*/
|
|
|
|
# define Lock_state()
|
|
|
|
# define Unlock_state()
|
|
|
|
#endif/*HAVE_THREADS*/
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
static boolean con_started = false; // console has been initialised
|
2020-08-15 01:27:16 +00:00
|
|
|
boolean con_startup = false; // true at game startup
|
|
|
|
boolean con_refresh = false; // screen needs refreshing
|
2014-03-15 16:59:03 +00:00
|
|
|
static boolean con_forcepic = true; // at startup toggle console translucency when first off
|
|
|
|
boolean con_recalc; // set true when screen size has changed
|
|
|
|
|
|
|
|
static tic_t con_tick; // console ticker for anim or blinking prompt cursor
|
|
|
|
// con_scrollup should use time (currenttime - lasttime)..
|
|
|
|
|
|
|
|
static boolean consoletoggle; // true when console key pushed, ticker will handle
|
|
|
|
static boolean consoleready; // console prompt is ready
|
|
|
|
|
|
|
|
INT32 con_destlines; // vid lines used by console at final position
|
|
|
|
static INT32 con_curlines; // vid lines currently used by console
|
|
|
|
|
2018-12-14 17:08:25 +00:00
|
|
|
INT32 con_clipviewtop; // (useless)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2023-02-04 16:34:43 +00:00
|
|
|
static UINT8 con_hudlines; // number of console heads up message lines
|
|
|
|
static INT32 con_hudtime[MAXHUDLINES]; // remaining time of display for hud msg lines
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
INT32 con_clearlines; // top screen lines to refresh when view reduced
|
|
|
|
boolean con_hudupdate; // when messages scroll, we need a backgrnd refresh
|
|
|
|
|
|
|
|
// console text output
|
|
|
|
static char *con_line; // console text output current line
|
|
|
|
static size_t con_cx; // cursor position in current line
|
|
|
|
static size_t con_cy; // cursor line number in con_buffer, is always
|
|
|
|
// increasing, and wrapped around in the text
|
|
|
|
// buffer using modulo.
|
|
|
|
|
|
|
|
static size_t con_totallines; // lines of console text into the console buffer
|
|
|
|
static size_t con_width; // columns of chars, depend on vid mode width
|
|
|
|
|
|
|
|
static size_t con_scrollup; // how many rows of text to scroll up (pgup/pgdn)
|
|
|
|
UINT32 con_scalefactor; // text size scale factor
|
|
|
|
|
|
|
|
// hold 32 last lines of input for history
|
|
|
|
#define CON_MAXPROMPTCHARS 256
|
2016-11-04 00:30:30 +00:00
|
|
|
#define CON_PROMPTCHAR '$'
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
static char inputlines[32][CON_MAXPROMPTCHARS]; // hold last 32 prompt lines
|
|
|
|
|
|
|
|
static INT32 inputline; // current input line number
|
|
|
|
static INT32 inputhist; // line number of history input line to restore
|
2016-11-04 00:30:30 +00:00
|
|
|
static size_t input_cur; // position of cursor in line
|
|
|
|
static size_t input_sel; // position of selection marker (I.E.: anything between this and input_cur is "selected")
|
|
|
|
static size_t input_len; // length of current line, used to bound cursor and such
|
|
|
|
// notice: input does NOT include the "$" at the start of the line. - 11/3/16
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
// protos.
|
|
|
|
static void CON_InputInit(void);
|
|
|
|
static void CON_RecalcSize(void);
|
2019-03-26 19:30:02 +00:00
|
|
|
static void CON_ChangeHeight(void);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2020-03-17 18:23:13 +00:00
|
|
|
static void CON_DrawBackpic(void);
|
2014-03-15 16:59:03 +00:00
|
|
|
static void CONS_hudlines_Change(void);
|
2016-11-02 21:26:35 +00:00
|
|
|
static void CONS_backcolor_Change(void);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
// CONSOLE VARS AND COMMANDS
|
|
|
|
//======================================================================
|
|
|
|
#ifdef macintosh
|
|
|
|
#define CON_BUFFERSIZE 4096 // my compiler can't handle local vars >32k
|
|
|
|
#else
|
|
|
|
#define CON_BUFFERSIZE 16384
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static char con_buffer[CON_BUFFERSIZE];
|
|
|
|
|
|
|
|
// how many seconds the hud messages lasts on the screen
|
2020-10-07 06:04:23 +00:00
|
|
|
static consvar_t cons_msgtimeout = CVAR_INIT ("con_hudtime", "5", CV_SAVE, CV_Unsigned, NULL);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
// number of lines displayed on the HUD
|
2023-02-04 16:34:43 +00:00
|
|
|
static CV_PossibleValue_t hudlines_cons_t[] = {{1, "MIN"}, {MAXHUDLINES, "MAX"}, {0, "None"}, {0, NULL}};
|
|
|
|
static consvar_t cons_hudlines = CVAR_INIT ("con_hudlines", "5", CV_CALL|CV_SAVE, hudlines_cons_t, CONS_hudlines_Change);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
// number of lines console move per frame
|
|
|
|
// (con_speed needs a limit, apparently)
|
|
|
|
static CV_PossibleValue_t speed_cons_t[] = {{0, "MIN"}, {64, "MAX"}, {0, NULL}};
|
2020-10-07 06:04:23 +00:00
|
|
|
static consvar_t cons_speed = CVAR_INIT ("con_speed", "8", CV_SAVE, speed_cons_t, NULL);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
// percentage of screen height to use for console
|
2020-10-07 06:04:23 +00:00
|
|
|
static consvar_t cons_height = CVAR_INIT ("con_height", "50", CV_SAVE, CV_Unsigned, NULL);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
static CV_PossibleValue_t backpic_cons_t[] = {{0, "translucent"}, {1, "picture"}, {0, NULL}};
|
|
|
|
// whether to use console background picture, or translucent mode
|
2020-10-07 06:04:23 +00:00
|
|
|
static consvar_t cons_backpic = CVAR_INIT ("con_backpic", "translucent", CV_SAVE, backpic_cons_t, NULL);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2018-12-17 19:43:59 +00:00
|
|
|
static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Black"}, {2, "Sepia"},
|
|
|
|
{3, "Brown"}, {4, "Pink"}, {5, "Raspberry"},
|
|
|
|
{6, "Red"}, {7, "Creamsicle"}, {8, "Orange"},
|
|
|
|
{9, "Gold"}, {10,"Yellow"}, {11,"Emerald"},
|
|
|
|
{12,"Green"}, {13,"Cyan"}, {14,"Steel"},
|
|
|
|
{15,"Periwinkle"}, {16,"Blue"}, {17,"Purple"},
|
|
|
|
{18,"Lavender"},
|
2016-11-02 21:26:35 +00:00
|
|
|
{0, NULL}};
|
2019-06-27 02:05:15 +00:00
|
|
|
|
2018-12-17 19:43:59 +00:00
|
|
|
|
2020-10-07 06:04:23 +00:00
|
|
|
consvar_t cons_backcolor = CVAR_INIT ("con_backcolor", "Green", CV_CALL|CV_SAVE, backcolor_cons_t, CONS_backcolor_Change);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
static void CON_Print(char *msg);
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
static void CONS_hudlines_Change(void)
|
|
|
|
{
|
|
|
|
INT32 i;
|
|
|
|
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
// Clear the currently displayed lines
|
|
|
|
for (i = 0; i < con_hudlines; i++)
|
|
|
|
con_hudtime[i] = 0;
|
|
|
|
|
|
|
|
con_hudlines = cons_hudlines.value;
|
|
|
|
|
2020-04-28 20:08:43 +00:00
|
|
|
Unlock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
CONS_Printf(M_GetText("Number of console HUD lines is now %d\n"), con_hudlines);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clear console text buffer
|
|
|
|
//
|
|
|
|
static void CONS_Clear_f(void)
|
|
|
|
{
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
memset(con_buffer, 0, CON_BUFFERSIZE);
|
|
|
|
|
|
|
|
con_cx = 0;
|
|
|
|
con_cy = con_totallines-1;
|
|
|
|
con_line = &con_buffer[con_cy*con_width];
|
|
|
|
con_scrollup = 0;
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Choose english keymap
|
|
|
|
//
|
2019-10-15 12:36:04 +00:00
|
|
|
/*static void CONS_English_f(void)
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
|
|
|
shiftxform = english_shiftxform;
|
|
|
|
CONS_Printf(M_GetText("%s keymap.\n"), M_GetText("English"));
|
2019-10-15 12:36:04 +00:00
|
|
|
}*/
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
static char *bindtable[NUMINPUTS];
|
|
|
|
|
|
|
|
static void CONS_Bind_f(void)
|
|
|
|
{
|
|
|
|
size_t na;
|
|
|
|
INT32 key;
|
|
|
|
|
|
|
|
na = COM_Argc();
|
|
|
|
|
|
|
|
if (na != 2 && na != 3)
|
|
|
|
{
|
|
|
|
CONS_Printf(M_GetText("bind <keyname> [<command>]: create shortcut keys to command(s)\n"));
|
|
|
|
CONS_Printf("\x82%s", M_GetText("Bind table :\n"));
|
|
|
|
na = 0;
|
|
|
|
for (key = 0; key < NUMINPUTS; key++)
|
|
|
|
if (bindtable[key])
|
|
|
|
{
|
2021-08-15 13:24:23 +00:00
|
|
|
CONS_Printf("%s : \"%s\"\n", G_KeyNumToName(key), bindtable[key]);
|
2014-03-15 16:59:03 +00:00
|
|
|
na = 1;
|
|
|
|
}
|
|
|
|
if (!na)
|
|
|
|
CONS_Printf(M_GetText("(empty)\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-08-15 13:24:23 +00:00
|
|
|
key = G_KeyNameToNum(COM_Argv(1));
|
2016-01-28 16:15:34 +00:00
|
|
|
if (key <= 0 || key >= NUMINPUTS)
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
|
|
|
CONS_Alert(CONS_NOTICE, M_GetText("Invalid key name\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Z_Free(bindtable[key]);
|
|
|
|
bindtable[key] = NULL;
|
|
|
|
|
|
|
|
if (na == 3)
|
|
|
|
bindtable[key] = Z_StrDup(COM_Argv(2));
|
|
|
|
}
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
// CONSOLE SETUP
|
|
|
|
//======================================================================
|
|
|
|
|
2016-11-02 21:26:35 +00:00
|
|
|
// Font colormap colors
|
|
|
|
// TODO: This could probably be improved somehow...
|
|
|
|
// These colormaps are 99% identical, with just a few changed bytes
|
2018-03-02 13:32:55 +00:00
|
|
|
// This could EASILY be handled by modifying a centralised colormap
|
|
|
|
// for software depending on the prior state - but yknow, OpenGL...
|
|
|
|
UINT8 *yellowmap, *magentamap, *lgreenmap, *bluemap, *graymap, *redmap, *orangemap, *skymap, *purplemap, *aquamap, *peridotmap, *azuremap, *brownmap, *rosymap, *invertmap;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2016-11-02 21:26:35 +00:00
|
|
|
// Console BG color
|
|
|
|
UINT8 *consolebgmap = NULL;
|
2018-11-10 03:38:55 +00:00
|
|
|
UINT8 *promptbgmap = NULL;
|
|
|
|
static UINT8 promptbgcolor = UINT8_MAX;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2018-11-10 03:38:55 +00:00
|
|
|
void CON_SetupBackColormapEx(INT32 color, boolean prompt)
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
2016-11-02 21:26:35 +00:00
|
|
|
UINT16 i, palsum;
|
2019-01-07 20:43:58 +00:00
|
|
|
UINT8 j, palindex;
|
2016-11-02 21:26:35 +00:00
|
|
|
UINT8 *pal = W_CacheLumpName(GetPalette(), PU_CACHE);
|
2018-12-17 19:43:59 +00:00
|
|
|
INT32 shift = 6;
|
2016-11-02 21:26:35 +00:00
|
|
|
|
2018-11-10 03:38:55 +00:00
|
|
|
if (color == INT32_MAX)
|
|
|
|
color = cons_backcolor.value;
|
2016-11-02 21:26:35 +00:00
|
|
|
|
2016-11-11 00:53:27 +00:00
|
|
|
shift = 6; // 12 colors -- shift of 7 means 6 colors
|
2019-01-08 02:54:38 +00:00
|
|
|
|
2018-11-10 03:38:55 +00:00
|
|
|
switch (color)
|
2016-11-02 21:26:35 +00:00
|
|
|
{
|
2018-12-17 19:43:59 +00:00
|
|
|
case 0: palindex = 15; break; // White
|
2019-06-27 02:05:15 +00:00
|
|
|
case 1: palindex = 31; break; // Black
|
|
|
|
case 2: palindex = 251; break; // Sepia
|
|
|
|
case 3: palindex = 239; break; // Brown
|
|
|
|
case 4: palindex = 215; shift = 7; break; // Pink
|
|
|
|
case 5: palindex = 37; shift = 7; break; // Raspberry
|
|
|
|
case 6: palindex = 47; shift = 7; break; // Red
|
|
|
|
case 7: palindex = 53; shift = 7; break; // Creamsicle
|
|
|
|
case 8: palindex = 63; break; // Orange
|
|
|
|
case 9: palindex = 56; shift = 7; break; // Gold
|
|
|
|
case 10: palindex = 79; shift = 7; break; // Yellow
|
|
|
|
case 11: palindex = 119; shift = 7; break; // Emerald
|
|
|
|
case 12: palindex = 111; break; // Green
|
|
|
|
case 13: palindex = 136; shift = 7; break; // Cyan
|
|
|
|
case 14: palindex = 175; shift = 7; break; // Steel
|
|
|
|
case 15: palindex = 166; shift = 7; break; // Periwinkle
|
|
|
|
case 16: palindex = 159; break; // Blue
|
|
|
|
case 17: palindex = 187; shift = 7; break; // Purple
|
|
|
|
case 18: palindex = 199; shift = 7; break; // Lavender
|
2019-01-08 02:54:38 +00:00
|
|
|
// Default green
|
2019-06-27 02:05:15 +00:00
|
|
|
default: palindex = 111; break;
|
2019-01-08 02:54:38 +00:00
|
|
|
}
|
2018-11-10 03:38:55 +00:00
|
|
|
|
|
|
|
if (prompt)
|
|
|
|
{
|
|
|
|
if (!promptbgmap)
|
|
|
|
promptbgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
|
|
|
|
|
|
|
if (color == promptbgcolor)
|
|
|
|
return;
|
|
|
|
else
|
|
|
|
promptbgcolor = color;
|
|
|
|
}
|
|
|
|
else if (!consolebgmap)
|
|
|
|
consolebgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2016-11-02 21:26:35 +00:00
|
|
|
// setup background colormap
|
|
|
|
for (i = 0, j = 0; i < 768; i += 3, j++)
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
2016-11-11 00:53:27 +00:00
|
|
|
palsum = (pal[i] + pal[i+1] + pal[i+2]) >> shift;
|
2018-11-10 03:38:55 +00:00
|
|
|
if (prompt)
|
|
|
|
promptbgmap[j] = (UINT8)(palindex - palsum);
|
|
|
|
else
|
|
|
|
consolebgmap[j] = (UINT8)(palindex - palsum);
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-10 03:38:55 +00:00
|
|
|
void CON_SetupBackColormap(void)
|
|
|
|
{
|
|
|
|
CON_SetupBackColormapEx(cons_backcolor.value, false);
|
|
|
|
CON_SetupBackColormapEx(1, true); // default to gray
|
|
|
|
}
|
|
|
|
|
2016-11-02 21:26:35 +00:00
|
|
|
static void CONS_backcolor_Change(void)
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
2018-11-10 03:38:55 +00:00
|
|
|
CON_SetupBackColormapEx(cons_backcolor.value, false);
|
2016-11-02 21:26:35 +00:00
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2016-11-02 21:26:35 +00:00
|
|
|
static void CON_SetupColormaps(void)
|
|
|
|
{
|
|
|
|
INT32 i;
|
2020-10-19 02:59:34 +00:00
|
|
|
UINT8 *memorysrc = (UINT8 *)Z_Malloc((256*15), PU_STATIC, NULL);
|
2018-03-02 13:32:55 +00:00
|
|
|
|
|
|
|
magentamap = memorysrc;
|
|
|
|
yellowmap = (magentamap+256);
|
|
|
|
lgreenmap = (yellowmap+256);
|
|
|
|
bluemap = (lgreenmap+256);
|
|
|
|
redmap = (bluemap+256);
|
|
|
|
graymap = (redmap+256);
|
|
|
|
orangemap = (graymap+256);
|
|
|
|
skymap = (orangemap+256);
|
|
|
|
purplemap = (skymap+256);
|
|
|
|
aquamap = (purplemap+256);
|
|
|
|
peridotmap = (aquamap+256);
|
|
|
|
azuremap = (peridotmap+256);
|
|
|
|
brownmap = (azuremap+256);
|
|
|
|
rosymap = (brownmap+256);
|
|
|
|
invertmap = (rosymap+256);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
// setup the other colormaps, for console text
|
|
|
|
|
|
|
|
// these don't need to be aligned, unless you convert the
|
|
|
|
// V_DrawMappedPatch() into optimised asm.
|
|
|
|
|
2018-03-02 13:32:55 +00:00
|
|
|
for (i = 0; i < (256*15); i++, ++memorysrc)
|
|
|
|
*memorysrc = (UINT8)(i & 0xFF); // remap each color to itself...
|
|
|
|
|
2020-10-19 02:59:34 +00:00
|
|
|
#define colset(map, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
|
|
|
|
map[0x0] = (UINT8)a;\
|
|
|
|
map[0x1] = (UINT8)b;\
|
|
|
|
map[0x2] = (UINT8)c;\
|
|
|
|
map[0x3] = (UINT8)d;\
|
|
|
|
map[0x4] = (UINT8)e;\
|
|
|
|
map[0x5] = (UINT8)f;\
|
|
|
|
map[0x6] = (UINT8)g;\
|
|
|
|
map[0x7] = (UINT8)h;\
|
|
|
|
map[0x8] = (UINT8)i;\
|
|
|
|
map[0x9] = (UINT8)j;\
|
|
|
|
map[0xA] = (UINT8)k;\
|
|
|
|
map[0xB] = (UINT8)l;\
|
|
|
|
map[0xC] = (UINT8)m;\
|
|
|
|
map[0xD] = (UINT8)n;\
|
|
|
|
map[0xE] = (UINT8)o;\
|
|
|
|
map[0xF] = (UINT8)p;
|
|
|
|
|
2020-12-14 22:14:20 +00:00
|
|
|
// Tried to keep the colors vanilla while adding some shades in between them ~SonicX8000
|
|
|
|
|
|
|
|
// 0x1 0x3 0x9 0xF
|
2020-12-16 04:19:57 +00:00
|
|
|
colset(magentamap, 177, 177, 178, 178, 178, 180, 180, 180, 182, 182, 182, 182, 184, 184, 184, 185);
|
2020-12-14 22:14:20 +00:00
|
|
|
colset(yellowmap, 82, 82, 73, 73, 73, 64, 64, 64, 66, 66, 66, 66, 67, 67, 67, 68);
|
2020-12-16 04:19:57 +00:00
|
|
|
colset(lgreenmap, 96, 96, 98, 98, 98, 101, 101, 101, 104, 104, 104, 104, 106, 106, 106, 107);
|
2020-12-14 22:14:20 +00:00
|
|
|
colset(bluemap, 146, 146, 147, 147, 147, 149, 149, 149, 152, 152, 152, 152, 155, 155, 155, 157);
|
|
|
|
colset(redmap, 32, 32, 33, 33, 33, 35, 35, 35, 39, 39, 39, 39, 42, 42, 42, 44);
|
|
|
|
colset(graymap, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23);
|
|
|
|
colset(orangemap, 50, 50, 52, 52, 52, 54, 54, 54, 56, 56, 56, 56, 59, 59, 59, 60);
|
|
|
|
colset(skymap, 129, 129, 130, 130, 130, 131, 131, 131, 133, 133, 133, 133, 135, 135, 135, 136);
|
|
|
|
colset(purplemap, 160, 160, 161, 161, 161, 162, 162, 162, 163, 163, 163, 163, 164, 164, 164, 165);
|
|
|
|
colset(aquamap, 120, 120, 121, 121, 121, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 125);
|
2020-12-14 18:52:24 +00:00
|
|
|
colset(peridotmap, 72, 72, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 94);
|
2020-12-14 22:14:20 +00:00
|
|
|
colset(azuremap, 144, 144, 145, 145, 145, 146, 146, 146, 170, 170, 170, 170, 171, 171, 171, 172);
|
|
|
|
colset(brownmap, 219, 219, 221, 221, 221, 222, 222, 222, 224, 224, 224, 224, 227, 227, 227, 229);
|
|
|
|
colset(rosymap, 200, 200, 201, 201, 201, 202, 202, 202, 203, 203, 203, 203, 204, 204, 204, 205);
|
2018-03-02 13:32:55 +00:00
|
|
|
|
|
|
|
#undef colset
|
2016-11-02 21:26:35 +00:00
|
|
|
|
2020-10-19 02:59:34 +00:00
|
|
|
// Yeah just straight up invert it like a normal person
|
|
|
|
for (i = 0x00; i <= 0x1F; i++)
|
|
|
|
invertmap[0x1F - i] = i;
|
|
|
|
|
2016-11-02 21:26:35 +00:00
|
|
|
// Init back colormap
|
|
|
|
CON_SetupBackColormap();
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Setup the console text buffer
|
|
|
|
//
|
|
|
|
void CON_Init(void)
|
|
|
|
{
|
|
|
|
INT32 i;
|
|
|
|
|
|
|
|
for (i = 0; i < NUMINPUTS; i++)
|
|
|
|
bindtable[i] = NULL;
|
|
|
|
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
// clear all lines
|
|
|
|
memset(con_buffer, 0, CON_BUFFERSIZE);
|
|
|
|
|
|
|
|
// make sure it is ready for the loading screen
|
|
|
|
con_width = 0;
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
CON_RecalcSize();
|
|
|
|
|
2016-11-02 21:26:35 +00:00
|
|
|
CON_SetupColormaps();
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
//note: CON_Ticker should always execute at least once before D_Display()
|
|
|
|
con_clipviewtop = -1; // -1 does not clip
|
|
|
|
|
|
|
|
con_hudlines = atoi(cons_hudlines.defaultvalue);
|
|
|
|
|
2020-04-28 20:08:43 +00:00
|
|
|
Unlock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
// setup console input filtering
|
|
|
|
CON_InputInit();
|
|
|
|
|
|
|
|
// register our commands
|
|
|
|
//
|
|
|
|
COM_AddCommand("cls", CONS_Clear_f);
|
2019-10-15 12:36:04 +00:00
|
|
|
//COM_AddCommand("english", CONS_English_f);
|
2014-03-15 16:59:03 +00:00
|
|
|
// set console full screen for game startup MAKE SURE VID_Init() done !!!
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
con_destlines = vid.height;
|
|
|
|
con_curlines = vid.height;
|
|
|
|
|
2020-04-28 20:08:43 +00:00
|
|
|
Unlock_state();
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
if (!dedicated)
|
|
|
|
{
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
con_started = true;
|
2020-08-15 01:27:16 +00:00
|
|
|
con_startup = true;
|
|
|
|
con_refresh = true; // needs explicit screen refresh until we are in the main game loop
|
2014-03-15 16:59:03 +00:00
|
|
|
consoletoggle = false;
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
CV_RegisterVar(&cons_msgtimeout);
|
|
|
|
CV_RegisterVar(&cons_hudlines);
|
|
|
|
CV_RegisterVar(&cons_speed);
|
|
|
|
CV_RegisterVar(&cons_height);
|
|
|
|
CV_RegisterVar(&cons_backpic);
|
|
|
|
CV_RegisterVar(&cons_backcolor);
|
|
|
|
COM_AddCommand("bind", CONS_Bind_f);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
con_started = true;
|
2020-08-15 01:27:16 +00:00
|
|
|
con_startup = false;
|
|
|
|
con_refresh = false; // disable explicit screen refresh
|
2014-03-15 16:59:03 +00:00
|
|
|
consoletoggle = true;
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
}
|
2020-12-26 23:19:14 +00:00
|
|
|
|
|
|
|
void CON_StartRefresh(void)
|
|
|
|
{
|
|
|
|
if (con_startup)
|
|
|
|
con_refresh = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CON_StopRefresh(void)
|
|
|
|
{
|
|
|
|
if (con_startup)
|
|
|
|
con_refresh = false;
|
|
|
|
}
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
// Console input initialization
|
|
|
|
//
|
|
|
|
static void CON_InputInit(void)
|
|
|
|
{
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
// prepare the first prompt line
|
|
|
|
memset(inputlines, 0, sizeof (inputlines));
|
|
|
|
inputline = 0;
|
2016-11-04 00:30:30 +00:00
|
|
|
input_cur = input_sel = input_len = 0;
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
// CONSOLE EXECUTION
|
|
|
|
//======================================================================
|
|
|
|
|
|
|
|
// Called at screen size change to set the rows and line size of the
|
|
|
|
// console text buffer.
|
|
|
|
//
|
|
|
|
static void CON_RecalcSize(void)
|
|
|
|
{
|
|
|
|
size_t conw, oldcon_width, oldnumlines, i, oldcon_cy;
|
|
|
|
char *tmp_buffer;
|
|
|
|
char *string;
|
|
|
|
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
switch (cv_constextsize.value)
|
|
|
|
{
|
|
|
|
case V_NOSCALEPATCH:
|
|
|
|
con_scalefactor = 1;
|
|
|
|
break;
|
|
|
|
case V_SMALLSCALEPATCH:
|
|
|
|
con_scalefactor = vid.smalldupx;
|
|
|
|
break;
|
|
|
|
case V_MEDSCALEPATCH:
|
|
|
|
con_scalefactor = vid.meddupx;
|
|
|
|
break;
|
|
|
|
default: // Full scaling
|
|
|
|
con_scalefactor = vid.dupx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
con_recalc = false;
|
|
|
|
|
|
|
|
if (dedicated)
|
|
|
|
conw = 1;
|
|
|
|
else
|
|
|
|
conw = (vid.width>>3) / con_scalefactor - 2;
|
|
|
|
|
|
|
|
if (con_curlines == vid.height) // first init
|
|
|
|
{
|
|
|
|
con_curlines = vid.height;
|
|
|
|
con_destlines = vid.height;
|
|
|
|
}
|
|
|
|
|
2019-03-26 19:30:02 +00:00
|
|
|
if (con_destlines > 0) // Resize console if already open
|
|
|
|
{
|
|
|
|
CON_ChangeHeight();
|
|
|
|
con_curlines = con_destlines;
|
|
|
|
}
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
// check for change of video width
|
|
|
|
if (conw == con_width)
|
2020-04-28 20:08:43 +00:00
|
|
|
{
|
|
|
|
Unlock_state();
|
2014-03-15 16:59:03 +00:00
|
|
|
return; // didn't change
|
2020-04-28 20:08:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Unlock_state();
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
tmp_buffer = Z_Malloc(CON_BUFFERSIZE, PU_STATIC, NULL);
|
|
|
|
string = Z_Malloc(CON_BUFFERSIZE, PU_STATIC, NULL); // BP: it is a line but who know
|
|
|
|
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
oldcon_width = con_width;
|
|
|
|
oldnumlines = con_totallines;
|
|
|
|
oldcon_cy = con_cy;
|
|
|
|
M_Memcpy(tmp_buffer, con_buffer, CON_BUFFERSIZE);
|
|
|
|
|
|
|
|
if (conw < 1)
|
|
|
|
con_width = (BASEVIDWIDTH>>3) - 2;
|
|
|
|
else
|
|
|
|
con_width = conw;
|
|
|
|
|
|
|
|
con_width += 11; // Graue 06-19-2004 up to 11 control chars per line
|
|
|
|
|
|
|
|
con_totallines = CON_BUFFERSIZE / con_width;
|
|
|
|
memset(con_buffer, ' ', CON_BUFFERSIZE);
|
|
|
|
|
|
|
|
con_cx = 0;
|
|
|
|
con_cy = con_totallines-1;
|
|
|
|
con_line = &con_buffer[con_cy*con_width];
|
|
|
|
con_scrollup = 0;
|
|
|
|
|
2020-04-28 20:08:43 +00:00
|
|
|
Unlock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
// re-arrange console text buffer to keep text
|
|
|
|
if (oldcon_width) // not the first time
|
|
|
|
{
|
|
|
|
for (i = oldcon_cy + 1; i < oldcon_cy + oldnumlines; i++)
|
|
|
|
{
|
|
|
|
if (tmp_buffer[(i%oldnumlines)*oldcon_width])
|
|
|
|
{
|
|
|
|
M_Memcpy(string, &tmp_buffer[(i%oldnumlines)*oldcon_width], oldcon_width);
|
|
|
|
conw = oldcon_width - 1;
|
|
|
|
while (string[conw] == ' ' && conw)
|
|
|
|
conw--;
|
|
|
|
string[conw+1] = '\n';
|
|
|
|
string[conw+2] = '\0';
|
|
|
|
CON_Print(string);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Z_Free(string);
|
|
|
|
Z_Free(tmp_buffer);
|
|
|
|
}
|
|
|
|
|
2019-03-26 19:30:02 +00:00
|
|
|
static void CON_ChangeHeight(void)
|
|
|
|
{
|
2020-04-28 20:08:43 +00:00
|
|
|
INT32 minheight;
|
|
|
|
|
|
|
|
Lock_state();
|
|
|
|
|
|
|
|
minheight = 20 * con_scalefactor; // 20 = 8+8+4
|
2019-03-26 19:30:02 +00:00
|
|
|
|
|
|
|
// toggle console in
|
|
|
|
con_destlines = (cons_height.value*vid.height)/100;
|
|
|
|
if (con_destlines < minheight)
|
|
|
|
con_destlines = minheight;
|
|
|
|
else if (con_destlines > vid.height)
|
|
|
|
con_destlines = vid.height;
|
|
|
|
|
|
|
|
con_destlines &= ~0x3; // multiple of text row height
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2019-03-26 19:30:02 +00:00
|
|
|
}
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
// Handles Console moves in/out of screen (per frame)
|
|
|
|
//
|
|
|
|
static void CON_MoveConsole(void)
|
|
|
|
{
|
2020-04-28 20:08:43 +00:00
|
|
|
fixed_t conspeed;
|
|
|
|
|
|
|
|
Lock_state();
|
|
|
|
|
|
|
|
conspeed = FixedDiv(cons_speed.value*vid.fdupy, FRACUNIT);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
// instant
|
|
|
|
if (!cons_speed.value)
|
|
|
|
{
|
|
|
|
con_curlines = con_destlines;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// up/down move to dest
|
|
|
|
if (con_curlines < con_destlines)
|
|
|
|
{
|
|
|
|
con_curlines += FixedInt(conspeed);
|
|
|
|
if (con_curlines > con_destlines)
|
|
|
|
con_curlines = con_destlines;
|
|
|
|
}
|
|
|
|
else if (con_curlines > con_destlines)
|
|
|
|
{
|
|
|
|
con_curlines -= FixedInt(conspeed);
|
|
|
|
if (con_curlines < con_destlines)
|
|
|
|
con_curlines = con_destlines;
|
|
|
|
}
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Clear time of console heads up messages
|
|
|
|
//
|
|
|
|
void CON_ClearHUD(void)
|
|
|
|
{
|
|
|
|
INT32 i;
|
|
|
|
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
for (i = 0; i < con_hudlines; i++)
|
|
|
|
con_hudtime[i] = 0;
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Force console to move out immediately
|
|
|
|
// note: con_ticker will set consoleready false
|
|
|
|
void CON_ToggleOff(void)
|
|
|
|
{
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
if (!con_destlines)
|
2020-04-28 20:08:43 +00:00
|
|
|
{
|
|
|
|
Unlock_state();
|
2014-03-15 16:59:03 +00:00
|
|
|
return;
|
2020-04-28 20:08:43 +00:00
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
con_destlines = 0;
|
|
|
|
con_curlines = 0;
|
|
|
|
CON_ClearHUD();
|
|
|
|
con_forcepic = 0;
|
|
|
|
con_clipviewtop = -1; // remove console clipping of view
|
2020-01-01 23:45:28 +00:00
|
|
|
|
|
|
|
I_UpdateMouseGrab();
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
boolean CON_Ready(void)
|
|
|
|
{
|
2020-04-28 20:08:43 +00:00
|
|
|
boolean ready;
|
|
|
|
Lock_state();
|
|
|
|
{
|
|
|
|
ready = consoleready;
|
|
|
|
}
|
|
|
|
Unlock_state();
|
|
|
|
return ready;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Console ticker: handles console move in/out, cursor blinking
|
|
|
|
//
|
|
|
|
void CON_Ticker(void)
|
|
|
|
{
|
|
|
|
INT32 i;
|
2020-04-28 20:08:43 +00:00
|
|
|
INT32 minheight;
|
|
|
|
|
|
|
|
Lock_state();
|
|
|
|
|
|
|
|
minheight = 20 * con_scalefactor; // 20 = 8+8+4
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
// cursor blinking
|
|
|
|
con_tick++;
|
|
|
|
con_tick &= 7;
|
|
|
|
|
|
|
|
// console key was pushed
|
|
|
|
if (consoletoggle)
|
|
|
|
{
|
|
|
|
consoletoggle = false;
|
|
|
|
|
|
|
|
// toggle off console
|
|
|
|
if (con_destlines > 0)
|
|
|
|
{
|
|
|
|
con_destlines = 0;
|
|
|
|
CON_ClearHUD();
|
2020-01-01 23:45:28 +00:00
|
|
|
I_UpdateMouseGrab();
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
else
|
2019-03-26 19:30:02 +00:00
|
|
|
CON_ChangeHeight();
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// console movement
|
|
|
|
if (con_destlines != con_curlines)
|
|
|
|
CON_MoveConsole();
|
|
|
|
|
|
|
|
// clip the view, so that the part under the console is not drawn
|
|
|
|
con_clipviewtop = -1;
|
|
|
|
if (cons_backpic.value) // clip only when using an opaque background
|
|
|
|
{
|
|
|
|
if (con_curlines > 0)
|
|
|
|
con_clipviewtop = con_curlines - viewwindowy - 1 - 10;
|
|
|
|
// NOTE: BIG HACK::SUBTRACT 10, SO THAT WATER DON'T COPY LINES OF THE CONSOLE
|
|
|
|
// WINDOW!!! (draw some more lines behind the bottom of the console)
|
|
|
|
if (con_clipviewtop < 0)
|
|
|
|
con_clipviewtop = -1; // maybe not necessary, provided it's < 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if console ready for prompt
|
|
|
|
if (con_destlines >= minheight)
|
|
|
|
consoleready = true;
|
|
|
|
else
|
|
|
|
consoleready = false;
|
|
|
|
|
|
|
|
// make overlay messages disappear after a while
|
|
|
|
for (i = 0; i < con_hudlines; i++)
|
|
|
|
{
|
|
|
|
con_hudtime[i]--;
|
|
|
|
if (con_hudtime[i] < 0)
|
|
|
|
con_hudtime[i] = 0;
|
|
|
|
}
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
2016-11-04 00:30:30 +00:00
|
|
|
//
|
|
|
|
// ----
|
|
|
|
//
|
|
|
|
// Shortcuts for adding and deleting characters, strings, and sections
|
|
|
|
// Necessary due to moving cursor
|
|
|
|
//
|
|
|
|
|
2016-11-04 09:02:26 +00:00
|
|
|
static void CON_InputClear(void)
|
2016-11-04 00:30:30 +00:00
|
|
|
{
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2016-11-04 00:30:30 +00:00
|
|
|
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
|
|
|
|
input_cur = input_sel = input_len = 0;
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2016-11-04 00:30:30 +00:00
|
|
|
}
|
|
|
|
|
2016-11-04 09:02:26 +00:00
|
|
|
static void CON_InputSetString(const char *c)
|
2016-11-04 00:30:30 +00:00
|
|
|
{
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2016-11-04 00:30:30 +00:00
|
|
|
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
|
|
|
|
strcpy(inputlines[inputline], c);
|
|
|
|
input_cur = input_sel = input_len = strlen(c);
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2016-11-04 00:30:30 +00:00
|
|
|
}
|
|
|
|
|
2016-11-04 09:02:26 +00:00
|
|
|
static void CON_InputAddString(const char *c)
|
2016-11-04 00:30:30 +00:00
|
|
|
{
|
|
|
|
size_t csize = strlen(c);
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Lock_state();
|
|
|
|
|
2016-11-04 00:30:30 +00:00
|
|
|
if (input_len + csize > CON_MAXPROMPTCHARS-1)
|
2020-04-28 20:08:43 +00:00
|
|
|
{
|
|
|
|
Unlock_state();
|
2016-11-04 00:30:30 +00:00
|
|
|
return;
|
2020-04-28 20:08:43 +00:00
|
|
|
}
|
2016-11-04 00:30:30 +00:00
|
|
|
if (input_cur != input_len)
|
|
|
|
memmove(&inputlines[inputline][input_cur+csize], &inputlines[inputline][input_cur], input_len-input_cur);
|
|
|
|
memcpy(&inputlines[inputline][input_cur], c, csize);
|
|
|
|
input_len += csize;
|
|
|
|
input_sel = (input_cur += csize);
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2016-11-04 00:30:30 +00:00
|
|
|
}
|
|
|
|
|
2016-11-04 09:02:26 +00:00
|
|
|
static void CON_InputDelSelection(void)
|
2016-11-04 00:30:30 +00:00
|
|
|
{
|
|
|
|
size_t start, end, len;
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Lock_state();
|
|
|
|
|
2021-01-05 19:20:02 +00:00
|
|
|
if (!input_cur)
|
|
|
|
{
|
|
|
|
Unlock_state();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-11-04 00:30:30 +00:00
|
|
|
if (input_cur > input_sel)
|
|
|
|
{
|
|
|
|
start = input_sel;
|
|
|
|
end = input_cur;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
start = input_cur;
|
|
|
|
end = input_sel;
|
|
|
|
}
|
|
|
|
len = (end - start);
|
|
|
|
|
|
|
|
if (end != input_len)
|
2016-11-04 02:36:43 +00:00
|
|
|
memmove(&inputlines[inputline][start], &inputlines[inputline][end], input_len-end);
|
2016-11-04 00:30:30 +00:00
|
|
|
memset(&inputlines[inputline][input_len - len], 0, len);
|
|
|
|
|
|
|
|
input_len -= len;
|
|
|
|
input_sel = input_cur = start;
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2016-11-04 00:30:30 +00:00
|
|
|
}
|
|
|
|
|
2016-11-04 09:02:26 +00:00
|
|
|
static void CON_InputAddChar(char c)
|
2016-11-04 00:30:30 +00:00
|
|
|
{
|
|
|
|
if (input_len >= CON_MAXPROMPTCHARS-1)
|
|
|
|
return;
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Lock_state();
|
|
|
|
|
2016-11-04 00:30:30 +00:00
|
|
|
if (input_cur != input_len)
|
|
|
|
memmove(&inputlines[inputline][input_cur+1], &inputlines[inputline][input_cur], input_len-input_cur);
|
|
|
|
inputlines[inputline][input_cur++] = c;
|
|
|
|
inputlines[inputline][++input_len] = 0;
|
|
|
|
input_sel = input_cur;
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2016-11-04 00:30:30 +00:00
|
|
|
}
|
|
|
|
|
2016-11-04 09:02:26 +00:00
|
|
|
static void CON_InputDelChar(void)
|
2016-11-04 00:30:30 +00:00
|
|
|
{
|
|
|
|
if (!input_cur)
|
|
|
|
return;
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Lock_state();
|
|
|
|
|
2016-11-04 00:30:30 +00:00
|
|
|
if (input_cur != input_len)
|
|
|
|
memmove(&inputlines[inputline][input_cur-1], &inputlines[inputline][input_cur], input_len-input_cur);
|
|
|
|
inputlines[inputline][--input_len] = 0;
|
|
|
|
input_sel = --input_cur;
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2016-11-04 00:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// ----
|
|
|
|
//
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
// Handles console key input
|
|
|
|
//
|
|
|
|
boolean CON_Responder(event_t *ev)
|
|
|
|
{
|
2016-11-02 22:23:22 +00:00
|
|
|
static UINT8 consdown = false; // console is treated differently due to rare usage
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
// sequential completions a la 4dos
|
|
|
|
static char completion[80];
|
|
|
|
|
2020-08-14 07:00:16 +00:00
|
|
|
static INT32 skips;
|
|
|
|
|
|
|
|
static INT32 com_skips;
|
|
|
|
static INT32 var_skips;
|
|
|
|
static INT32 alias_skips;
|
|
|
|
|
|
|
|
const char *cmd = NULL;
|
2023-01-27 01:26:28 +00:00
|
|
|
INT32 key;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
if (chat_on)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// let go keyup events, don't eat them
|
|
|
|
if (ev->type != ev_keydown && ev->type != ev_console)
|
|
|
|
{
|
2023-01-27 01:26:28 +00:00
|
|
|
if (ev->key == gamecontrol[GC_CONSOLE][0] || ev->key == gamecontrol[GC_CONSOLE][1])
|
2014-03-15 16:59:03 +00:00
|
|
|
consdown = false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-01-27 01:26:28 +00:00
|
|
|
key = ev->key;
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
// check for console toggle key
|
|
|
|
if (ev->type != ev_console)
|
|
|
|
{
|
Introducing Marathon Run. (I was going to call it Marathon Mode, but NiGHTS Mode being right next to it on the menu looked terrible.)
Basically a dedicated Record Attack-like experience for speedrunning the game as a continuous chunk rather than ILs. Has several quality of life features.
Benefits include:
* An unambiguous real-time bar across the bottom of the screen, always displaying the current time, ticking up until you reach the ending.
* Disable the console (pausing is still allowed, but the timer will still increment).
* Automatically skip intermissions as if you're holding down the spin button.
* Show centiseconds on HUD automatically, like record attack.
* "Live Event Backups" - a category of run fit for major events like GDQ, where recovery from crashes or chokes makes for better entertainment. Essentially a modified SP savefile, down to using the same basic functions, but has its own filename and tweaked internal layout.
* "spmarathon_start" MainCfg block parameter and "marathonnext" mapheader parameter, allowing for a customised flow (makes this fit for purpose for an eventual SUGOI port).
* Disabling inter-level custom cutscenes by default with a menu option to toggle this (won't show up if the mod doesn't *have* any custom cutscenes), although either way ending cutscenes (vanilla or custom) remain intact since is time is called before them.
* Won't show up if you have a mod that consists of only one level (determined by spmarathon_start's nextlevel; this won't trip if you manually set its marathonnext).
* Unconditional gratitude on the evaluation screen, instead of a negging "Try again..." if you didn't get all the emeralds (which you may not have been aiming for).
* Gorgeous new menu (no new assets required, unless you wanna give it a header later).
Changes which were required for the above but affect other areas of the game include:
* "useBlackRock" MainCFG block parameter, which can be used to disable the presence of the Black Rock or Egg Rock in both the Evaluation screen and the Marathon Run menu (for total conversions with different stories).
* Disabling Continues in NiGHTS mode, to match the most common singleplayer experience post 2.2.4's release (is reverted if useContinues is set to true).
* Hiding the exitmove "powerup" outside of multiplayer. (Okay, this isn't really related, I just saw this bug in action a lot while doing test runs and got annoyed enough to fix it here.)
* The ability to use V_DrawPromptBack (in hardcode only at the moment, but) to draw in terms of pixels rather than rows of text, by providing negative instead of positive inputs).
* A refactoring of redundant game saves smattered across the ending, credits, and evaluation - in addition to saving the game slightly earlier.
* Minor m_menu.c touchups and refactorings here and there.
Built using feedback from the official server's #speedruns channel, among other places.
2020-05-14 22:10:00 +00:00
|
|
|
if (modeattacking || metalrecording || marathonmode)
|
2014-03-15 16:59:03 +00:00
|
|
|
return false;
|
|
|
|
|
2023-01-27 01:26:28 +00:00
|
|
|
if (key == gamecontrol[GC_CONSOLE][0] || key == gamecontrol[GC_CONSOLE][1])
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
|
|
|
if (consdown) // ignore repeat
|
|
|
|
return true;
|
|
|
|
consoletoggle = true;
|
|
|
|
consdown = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check other keys only if console prompt is active
|
|
|
|
if (!consoleready && key < NUMINPUTS) // metzgermeister: boundary check!!
|
|
|
|
{
|
2020-02-18 00:37:13 +00:00
|
|
|
if (! menuactive && bindtable[key])
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
|
|
|
COM_BufAddText(bindtable[key]);
|
|
|
|
COM_BufAddText("\n");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// escape key toggle off console
|
|
|
|
if (key == KEY_ESCAPE)
|
|
|
|
{
|
|
|
|
consoletoggle = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-04 02:36:43 +00:00
|
|
|
// Always eat ctrl/shift/alt if console open, so the menu doesn't get ideas
|
|
|
|
if (key == KEY_LSHIFT || key == KEY_RSHIFT
|
|
|
|
|| key == KEY_LCTRL || key == KEY_RCTRL
|
|
|
|
|| key == KEY_LALT || key == KEY_RALT)
|
2014-03-15 16:59:03 +00:00
|
|
|
return true;
|
|
|
|
|
2020-01-08 09:03:44 +00:00
|
|
|
if (key == KEY_LEFTARROW)
|
|
|
|
{
|
|
|
|
if (input_cur != 0)
|
2020-01-08 10:54:17 +00:00
|
|
|
{
|
|
|
|
if (ctrldown)
|
2020-01-08 20:58:19 +00:00
|
|
|
input_cur = M_JumpWordReverse(inputlines[inputline], input_cur);
|
2020-01-08 10:54:17 +00:00
|
|
|
else
|
|
|
|
--input_cur;
|
|
|
|
}
|
2020-01-08 09:03:44 +00:00
|
|
|
if (!shiftdown)
|
|
|
|
input_sel = input_cur;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (key == KEY_RIGHTARROW)
|
|
|
|
{
|
2020-01-08 20:58:19 +00:00
|
|
|
if (input_cur < input_len)
|
2020-01-08 09:03:44 +00:00
|
|
|
{
|
2020-01-08 20:58:19 +00:00
|
|
|
if (ctrldown)
|
|
|
|
input_cur += M_JumpWord(&inputlines[inputline][input_cur]);
|
2020-01-08 09:03:44 +00:00
|
|
|
else
|
|
|
|
++input_cur;
|
|
|
|
}
|
|
|
|
if (!shiftdown)
|
|
|
|
input_sel = input_cur;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-07-24 11:06:04 +00:00
|
|
|
// backspace and delete command prompt
|
|
|
|
if (input_sel != input_cur)
|
|
|
|
{
|
|
|
|
if (key == KEY_BACKSPACE || key == KEY_DEL)
|
|
|
|
{
|
|
|
|
CON_InputDelSelection();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (key == KEY_BACKSPACE)
|
|
|
|
{
|
|
|
|
if (ctrldown)
|
|
|
|
{
|
|
|
|
input_sel = M_JumpWordReverse(inputlines[inputline], input_cur);
|
|
|
|
CON_InputDelSelection();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
CON_InputDelChar();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (key == KEY_DEL)
|
|
|
|
{
|
|
|
|
if (input_cur == input_len)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (ctrldown)
|
|
|
|
{
|
|
|
|
input_sel = input_cur + M_JumpWord(&inputlines[inputline][input_cur]);
|
|
|
|
CON_InputDelSelection();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++input_cur;
|
|
|
|
CON_InputDelChar();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-11-03 08:43:57 +00:00
|
|
|
// ctrl modifier -- changes behavior, adds shortcuts
|
|
|
|
if (ctrldown)
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
|
|
|
// show all cvars/commands that match what we have inputted
|
2016-11-03 08:43:57 +00:00
|
|
|
if (key == KEY_TAB)
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
2016-11-04 00:30:30 +00:00
|
|
|
size_t i, len;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2016-11-04 00:30:30 +00:00
|
|
|
if (!completion[0])
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
2016-11-04 00:30:30 +00:00
|
|
|
if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' '))
|
|
|
|
return true;
|
|
|
|
strcpy(completion, inputlines[inputline]);
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
2016-11-04 00:30:30 +00:00
|
|
|
len = strlen(completion);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
//first check commands
|
|
|
|
CONS_Printf("\nCommands:\n");
|
2016-11-03 08:43:57 +00:00
|
|
|
for (i = 0, cmd = COM_CompleteCommand(completion, i); cmd; cmd = COM_CompleteCommand(completion, ++i))
|
|
|
|
CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, cmd+len);
|
|
|
|
if (i == 0) CONS_Printf(" (none)\n");
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
//now we move on to CVARs
|
|
|
|
CONS_Printf("Variables:\n");
|
2016-11-03 08:43:57 +00:00
|
|
|
for (i = 0, cmd = CV_CompleteVar(completion, i); cmd; cmd = CV_CompleteVar(completion, ++i))
|
|
|
|
CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, cmd+len);
|
|
|
|
if (i == 0) CONS_Printf(" (none)\n");
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2020-08-14 07:00:16 +00:00
|
|
|
//and finally aliases
|
|
|
|
CONS_Printf("Aliases:\n");
|
|
|
|
for (i = 0, cmd = COM_CompleteAlias(completion, i); cmd; cmd = COM_CompleteAlias(completion, ++i))
|
|
|
|
CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, cmd+len);
|
|
|
|
if (i == 0) CONS_Printf(" (none)\n");
|
|
|
|
|
|
|
|
completion[0] = 0;
|
|
|
|
|
2016-11-03 08:43:57 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// ---
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2016-11-03 08:43:57 +00:00
|
|
|
if (key == KEY_HOME) // oldest text in buffer
|
|
|
|
{
|
|
|
|
con_scrollup = (con_totallines-((con_curlines-16)>>3));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (key == KEY_END) // most recent text in buffer
|
|
|
|
{
|
|
|
|
con_scrollup = 0;
|
|
|
|
return true;
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2016-11-03 08:43:57 +00:00
|
|
|
if (key == 'x' || key == 'X')
|
|
|
|
{
|
2016-11-04 00:30:30 +00:00
|
|
|
if (input_sel > input_cur)
|
|
|
|
I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur);
|
|
|
|
else
|
|
|
|
I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel);
|
|
|
|
CON_InputDelSelection();
|
|
|
|
completion[0] = 0;
|
2016-11-03 08:43:57 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (key == 'c' || key == 'C')
|
|
|
|
{
|
2016-11-04 00:30:30 +00:00
|
|
|
if (input_sel > input_cur)
|
|
|
|
I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur);
|
|
|
|
else
|
|
|
|
I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel);
|
2014-03-15 16:59:03 +00:00
|
|
|
return true;
|
|
|
|
}
|
2016-11-03 08:43:57 +00:00
|
|
|
else if (key == 'v' || key == 'V')
|
|
|
|
{
|
2016-11-04 00:30:30 +00:00
|
|
|
const char *paste = I_ClipboardPaste();
|
|
|
|
if (input_sel != input_cur)
|
|
|
|
CON_InputDelSelection();
|
|
|
|
if (paste != NULL)
|
|
|
|
CON_InputAddString(paste);
|
|
|
|
completion[0] = 0;
|
2014-03-15 16:59:03 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-11-04 00:30:30 +00:00
|
|
|
// Select all
|
|
|
|
if (key == 'a' || key == 'A')
|
|
|
|
{
|
|
|
|
input_sel = 0;
|
|
|
|
input_cur = input_len;
|
2016-11-03 08:43:57 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-02-20 17:06:03 +00:00
|
|
|
// ...why shouldn't it eat the key? if it doesn't, it just means you
|
|
|
|
// can control Sonic from the console, which is silly
|
2018-07-31 09:10:02 +00:00
|
|
|
return true;//return false;
|
2016-11-03 08:43:57 +00:00
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2016-11-03 08:43:57 +00:00
|
|
|
// command completion forward (tab) and backward (shift-tab)
|
|
|
|
if (key == KEY_TAB)
|
|
|
|
{
|
2014-03-15 16:59:03 +00:00
|
|
|
// sequential command completion forward and backward
|
|
|
|
|
|
|
|
// remember typing for several completions (a-la-4dos)
|
2016-11-04 00:30:30 +00:00
|
|
|
if (!completion[0])
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
2016-11-04 00:30:30 +00:00
|
|
|
if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' '))
|
|
|
|
return true;
|
|
|
|
strcpy(completion, inputlines[inputline]);
|
2020-08-14 07:00:16 +00:00
|
|
|
skips = 0;
|
|
|
|
com_skips = 0;
|
|
|
|
var_skips = 0;
|
|
|
|
alias_skips = 0;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (shiftdown)
|
|
|
|
{
|
2020-08-14 07:00:16 +00:00
|
|
|
if (skips > 0)
|
|
|
|
skips--;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-08-14 07:00:16 +00:00
|
|
|
skips++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (skips <= com_skips)
|
|
|
|
{
|
|
|
|
cmd = COM_CompleteCommand(completion, skips);
|
|
|
|
|
|
|
|
if (cmd && skips == com_skips)
|
|
|
|
{
|
|
|
|
com_skips ++;
|
|
|
|
var_skips ++;
|
|
|
|
alias_skips++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cmd && skips <= var_skips)
|
|
|
|
{
|
|
|
|
cmd = CV_CompleteVar(completion, skips - com_skips);
|
|
|
|
|
|
|
|
if (cmd && skips == var_skips)
|
|
|
|
{
|
|
|
|
var_skips ++;
|
|
|
|
alias_skips++;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-14 07:00:16 +00:00
|
|
|
if (!cmd && skips <= alias_skips)
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
2020-08-14 07:00:16 +00:00
|
|
|
cmd = COM_CompleteAlias(completion, skips - var_skips);
|
|
|
|
|
|
|
|
if (cmd && skips == alias_skips)
|
|
|
|
{
|
|
|
|
alias_skips++;
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd)
|
2020-08-14 07:00:16 +00:00
|
|
|
{
|
2016-11-04 00:30:30 +00:00
|
|
|
CON_InputSetString(va("%s ", cmd));
|
2020-08-14 07:00:16 +00:00
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
else
|
|
|
|
{
|
2020-08-14 07:00:16 +00:00
|
|
|
skips--;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// move up (backward) in console textbuffer
|
|
|
|
if (key == KEY_PGUP)
|
|
|
|
{
|
|
|
|
if (con_scrollup < (con_totallines-((con_curlines-16)>>3)))
|
|
|
|
con_scrollup++;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (key == KEY_PGDN)
|
|
|
|
{
|
|
|
|
if (con_scrollup > 0)
|
|
|
|
con_scrollup--;
|
|
|
|
return true;
|
|
|
|
}
|
2016-11-04 00:30:30 +00:00
|
|
|
else if (key == KEY_HOME)
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
2016-11-04 00:30:30 +00:00
|
|
|
input_cur = 0;
|
|
|
|
if (!shiftdown)
|
|
|
|
input_sel = input_cur;
|
2014-03-15 16:59:03 +00:00
|
|
|
return true;
|
|
|
|
}
|
2016-11-04 00:30:30 +00:00
|
|
|
else if (key == KEY_END)
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
2016-11-04 00:30:30 +00:00
|
|
|
input_cur = input_len;
|
|
|
|
if (!shiftdown)
|
|
|
|
input_sel = input_cur;
|
2014-03-15 16:59:03 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-11-04 00:30:30 +00:00
|
|
|
// At this point we're messing with input
|
|
|
|
// Clear completion
|
|
|
|
completion[0] = 0;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
// command enter
|
|
|
|
if (key == KEY_ENTER)
|
|
|
|
{
|
2016-11-04 00:30:30 +00:00
|
|
|
if (!input_len)
|
2014-03-15 16:59:03 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// push the command
|
2016-11-04 00:30:30 +00:00
|
|
|
COM_BufAddText(inputlines[inputline]);
|
2014-03-15 16:59:03 +00:00
|
|
|
COM_BufAddText("\n");
|
|
|
|
|
2016-11-04 00:30:30 +00:00
|
|
|
CONS_Printf("\x86""%c""\x80""%s\n", CON_PROMPTCHAR, inputlines[inputline]);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
inputline = (inputline+1) & 31;
|
|
|
|
inputhist = inputline;
|
2016-11-04 00:30:30 +00:00
|
|
|
CON_InputClear();
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// move back in input history
|
|
|
|
if (key == KEY_UPARROW)
|
|
|
|
{
|
|
|
|
// copy one of the previous inputlines to the current
|
|
|
|
do
|
|
|
|
inputhist = (inputhist - 1) & 31; // cycle back
|
2016-11-04 00:30:30 +00:00
|
|
|
while (inputhist != inputline && !inputlines[inputhist][0]);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
// stop at the last history input line, which is the
|
|
|
|
// current line + 1 because we cycle through the 32 input lines
|
|
|
|
if (inputhist == inputline)
|
|
|
|
inputhist = (inputline + 1) & 31;
|
|
|
|
|
2016-11-04 00:30:30 +00:00
|
|
|
CON_InputSetString(inputlines[inputhist]);
|
2014-03-15 16:59:03 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// move forward in input history
|
|
|
|
if (key == KEY_DOWNARROW)
|
|
|
|
{
|
|
|
|
if (inputhist == inputline)
|
|
|
|
return true;
|
|
|
|
do
|
|
|
|
inputhist = (inputhist + 1) & 31;
|
2016-11-04 00:30:30 +00:00
|
|
|
while (inputhist != inputline && !inputlines[inputhist][0]);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
// back to currentline
|
|
|
|
if (inputhist == inputline)
|
2016-11-04 00:30:30 +00:00
|
|
|
CON_InputClear();
|
2014-03-15 16:59:03 +00:00
|
|
|
else
|
2016-11-04 00:30:30 +00:00
|
|
|
CON_InputSetString(inputlines[inputhist]);
|
2014-03-15 16:59:03 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// allow people to use keypad in console (good for typing IP addresses) - Calum
|
|
|
|
if (key >= KEY_KEYPAD7 && key <= KEY_KPADDEL)
|
|
|
|
{
|
2017-09-29 18:46:23 +00:00
|
|
|
char keypad_translation[] = {'7','8','9','-',
|
|
|
|
'4','5','6','+',
|
|
|
|
'1','2','3',
|
|
|
|
'0','.'};
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
key = keypad_translation[key - KEY_KEYPAD7];
|
|
|
|
}
|
|
|
|
else if (key == KEY_KPADSLASH)
|
|
|
|
key = '/';
|
|
|
|
|
2018-08-19 09:25:20 +00:00
|
|
|
if (key >= 'a' && key <= 'z')
|
|
|
|
{
|
|
|
|
if (capslock ^ shiftdown)
|
|
|
|
key = shiftxform[key];
|
|
|
|
}
|
|
|
|
else if (shiftdown)
|
2014-03-15 16:59:03 +00:00
|
|
|
key = shiftxform[key];
|
|
|
|
|
|
|
|
// enter a char into the command prompt
|
|
|
|
if (key < 32 || key > 127)
|
2018-07-31 09:10:02 +00:00
|
|
|
return true;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2016-11-04 00:30:30 +00:00
|
|
|
if (input_sel != input_cur)
|
|
|
|
CON_InputDelSelection();
|
|
|
|
CON_InputAddChar(key);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert a new line in the console text buffer
|
|
|
|
//
|
|
|
|
static void CON_Linefeed(void)
|
|
|
|
{
|
|
|
|
// set time for heads up messages
|
2023-02-04 16:34:43 +00:00
|
|
|
if (con_hudlines)
|
|
|
|
con_hudtime[con_cy%con_hudlines] = cons_msgtimeout.value*TICRATE;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
con_cy++;
|
|
|
|
con_cx = 0;
|
|
|
|
|
|
|
|
con_line = &con_buffer[(con_cy%con_totallines)*con_width];
|
|
|
|
memset(con_line, ' ', con_width);
|
|
|
|
|
|
|
|
// make sure the view borders are refreshed if hud messages scroll
|
|
|
|
con_hudupdate = true; // see HU_Erase()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Outputs text into the console text buffer
|
|
|
|
static void CON_Print(char *msg)
|
|
|
|
{
|
|
|
|
size_t l;
|
|
|
|
INT32 controlchars = 0; // for color changing
|
2018-03-22 04:12:48 +00:00
|
|
|
char color = '\x80'; // keep color across lines
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
if (msg == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (*msg == '\3') // chat text, makes ding sound
|
|
|
|
S_StartSound(NULL, sfx_radio);
|
|
|
|
else if (*msg == '\4') // chat action, dings and is in yellow
|
|
|
|
{
|
|
|
|
*msg = '\x82'; // yellow
|
|
|
|
S_StartSound(NULL, sfx_radio);
|
|
|
|
}
|
|
|
|
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
if (!(*msg & 0x80))
|
|
|
|
{
|
|
|
|
con_line[con_cx++] = '\x80';
|
|
|
|
controlchars = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (*msg)
|
|
|
|
{
|
|
|
|
// skip non-printable characters and white spaces
|
|
|
|
while (*msg && *msg <= ' ')
|
|
|
|
{
|
|
|
|
if (*msg & 0x80)
|
|
|
|
{
|
2018-03-22 04:12:48 +00:00
|
|
|
color = con_line[con_cx++] = *(msg++);
|
2014-03-15 16:59:03 +00:00
|
|
|
controlchars++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (*msg == '\r') // carriage return
|
|
|
|
{
|
|
|
|
con_cy--;
|
|
|
|
CON_Linefeed();
|
2018-03-22 04:12:48 +00:00
|
|
|
color = '\x80';
|
2014-03-15 16:59:03 +00:00
|
|
|
controlchars = 0;
|
|
|
|
}
|
|
|
|
else if (*msg == '\n') // linefeed
|
|
|
|
{
|
|
|
|
CON_Linefeed();
|
2018-03-22 04:12:48 +00:00
|
|
|
con_line[con_cx++] = color;
|
|
|
|
controlchars = 1;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
else if (*msg == ' ') // space
|
|
|
|
{
|
|
|
|
con_line[con_cx++] = ' ';
|
|
|
|
if (con_cx - controlchars >= con_width-11)
|
|
|
|
{
|
|
|
|
CON_Linefeed();
|
2018-03-22 04:12:48 +00:00
|
|
|
con_line[con_cx++] = color;
|
|
|
|
controlchars = 1;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (*msg == '\t')
|
|
|
|
{
|
|
|
|
// adds tab spaces for nice layout in console
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
con_line[con_cx++] = ' ';
|
|
|
|
} while ((con_cx - controlchars) % 4 != 0);
|
|
|
|
|
|
|
|
if (con_cx - controlchars >= con_width-11)
|
|
|
|
{
|
|
|
|
CON_Linefeed();
|
2018-03-22 04:12:48 +00:00
|
|
|
con_line[con_cx++] = color;
|
|
|
|
controlchars = 1;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
msg++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*msg == '\0')
|
2020-04-28 20:08:43 +00:00
|
|
|
{
|
2020-05-15 00:23:06 +00:00
|
|
|
Unlock_state();
|
2014-03-15 16:59:03 +00:00
|
|
|
return;
|
2020-04-28 20:08:43 +00:00
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
// printable character
|
|
|
|
for (l = 0; l < (con_width-11) && msg[l] > ' '; l++)
|
|
|
|
;
|
|
|
|
|
|
|
|
// word wrap
|
|
|
|
if ((con_cx - controlchars) + l > con_width-11)
|
|
|
|
{
|
|
|
|
CON_Linefeed();
|
2018-03-22 04:12:48 +00:00
|
|
|
con_line[con_cx++] = color;
|
|
|
|
controlchars = 1;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// a word at a time
|
|
|
|
for (; l > 0; l--)
|
|
|
|
con_line[con_cx++] = *(msg++);
|
|
|
|
}
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CON_LogMessage(const char *msg)
|
|
|
|
{
|
2017-09-29 18:46:23 +00:00
|
|
|
char txt[8192], *t;
|
2014-03-15 16:59:03 +00:00
|
|
|
const char *p = msg, *e = txt+sizeof (txt)-2;
|
|
|
|
|
|
|
|
for (t = txt; *p != '\0'; p++)
|
|
|
|
{
|
|
|
|
if (*p == '\n' || *p >= ' ') // don't log or console print CON_Print's control characters
|
|
|
|
*t++ = *p;
|
|
|
|
|
|
|
|
if (t >= e)
|
|
|
|
{
|
|
|
|
*t = '\0'; //end of string
|
|
|
|
I_OutputMsg("%s", txt); //print string
|
|
|
|
t = txt; //reset t pointer
|
|
|
|
memset(txt,'\0', sizeof (txt)); //reset txt
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*t = '\0'; //end of string
|
|
|
|
I_OutputMsg("%s", txt);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Console print! Wahooo! Lots o fun!
|
|
|
|
//
|
|
|
|
|
|
|
|
void CONS_Printf(const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list argptr;
|
|
|
|
static char *txt = NULL;
|
2020-10-10 20:01:10 +00:00
|
|
|
boolean refresh;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
if (txt == NULL)
|
|
|
|
txt = malloc(8192);
|
|
|
|
|
|
|
|
va_start(argptr, fmt);
|
|
|
|
vsprintf(txt, fmt, argptr);
|
|
|
|
va_end(argptr);
|
|
|
|
|
|
|
|
// echo console prints to log file
|
|
|
|
DEBFILE(txt);
|
|
|
|
|
2020-07-25 22:55:51 +00:00
|
|
|
// write message in con text buffer
|
|
|
|
if (con_started)
|
2014-03-15 16:59:03 +00:00
|
|
|
CON_Print(txt);
|
|
|
|
|
|
|
|
CON_LogMessage(txt);
|
|
|
|
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
// make sure new text is visible
|
|
|
|
con_scrollup = 0;
|
2020-10-10 20:01:10 +00:00
|
|
|
refresh = con_refresh;
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
// if not in display loop, force screen update
|
2020-10-10 20:01:10 +00:00
|
|
|
if (refresh)
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
2020-10-10 20:01:10 +00:00
|
|
|
CON_Drawer(); // here we display the console text
|
2014-03-15 16:59:03 +00:00
|
|
|
I_FinishUpdate(); // page flip or blit buffer
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CONS_Alert(alerttype_t level, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list argptr;
|
|
|
|
static char *txt = NULL;
|
|
|
|
|
|
|
|
if (txt == NULL)
|
|
|
|
txt = malloc(8192);
|
|
|
|
|
|
|
|
va_start(argptr, fmt);
|
|
|
|
vsprintf(txt, fmt, argptr);
|
|
|
|
va_end(argptr);
|
|
|
|
|
|
|
|
switch (level)
|
|
|
|
{
|
|
|
|
case CONS_NOTICE:
|
2017-04-29 15:40:07 +00:00
|
|
|
// no notice for notices, hehe
|
2014-03-15 16:59:03 +00:00
|
|
|
CONS_Printf("\x83" "%s" "\x80 ", M_GetText("NOTICE:"));
|
|
|
|
break;
|
|
|
|
case CONS_WARNING:
|
2017-04-29 15:40:07 +00:00
|
|
|
refreshdirmenu |= REFRESHDIR_WARNING;
|
2014-03-15 16:59:03 +00:00
|
|
|
CONS_Printf("\x82" "%s" "\x80 ", M_GetText("WARNING:"));
|
|
|
|
break;
|
|
|
|
case CONS_ERROR:
|
2017-04-29 15:40:07 +00:00
|
|
|
refreshdirmenu |= REFRESHDIR_ERROR;
|
2014-03-15 16:59:03 +00:00
|
|
|
CONS_Printf("\x85" "%s" "\x80 ", M_GetText("ERROR:"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// I am lazy and I feel like just letting CONS_Printf take care of things.
|
|
|
|
// Is that okay?
|
|
|
|
CONS_Printf("%s", txt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CONS_Debug(INT32 debugflags, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list argptr;
|
|
|
|
static char *txt = NULL;
|
|
|
|
|
|
|
|
if ((cv_debug & debugflags) != debugflags)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (txt == NULL)
|
|
|
|
txt = malloc(8192);
|
|
|
|
|
|
|
|
va_start(argptr, fmt);
|
|
|
|
vsprintf(txt, fmt, argptr);
|
|
|
|
va_end(argptr);
|
|
|
|
|
|
|
|
// Again I am lazy, oh well
|
|
|
|
CONS_Printf("%s", txt);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Print an error message, and wait for ENTER key to continue.
|
|
|
|
// To make sure the user has seen the message
|
|
|
|
//
|
|
|
|
void CONS_Error(const char *msg)
|
|
|
|
{
|
2020-08-15 01:27:16 +00:00
|
|
|
#if defined(RPC_NO_WINDOWS_H) && defined(_WINDOWS)
|
2014-03-15 16:59:03 +00:00
|
|
|
if (!graphics_started)
|
|
|
|
{
|
|
|
|
MessageBoxA(vid.WndParent, msg, "SRB2 Warning", MB_OK);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
CONS_Printf("\x82%s", msg); // write error msg in different colour
|
|
|
|
CONS_Printf(M_GetText("Press ENTER to continue\n"));
|
|
|
|
|
|
|
|
// dirty quick hack, but for the good cause
|
|
|
|
while (I_GetKey() != KEY_ENTER)
|
|
|
|
I_OsPolling();
|
|
|
|
}
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
// CONSOLE DRAW
|
|
|
|
//======================================================================
|
|
|
|
|
|
|
|
// draw console prompt line
|
|
|
|
//
|
|
|
|
static void CON_DrawInput(void)
|
|
|
|
{
|
|
|
|
INT32 charwidth = (INT32)con_scalefactor << 3;
|
2016-11-04 00:30:30 +00:00
|
|
|
const char *p = inputlines[inputline];
|
|
|
|
size_t c, clen, cend;
|
|
|
|
UINT8 lellip = 0, rellip = 0;
|
|
|
|
INT32 x, y, i;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
y = con_curlines - 12 * con_scalefactor;
|
2016-11-04 00:30:30 +00:00
|
|
|
x = charwidth*2;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2016-11-04 02:36:43 +00:00
|
|
|
clen = con_width-13;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
2016-11-04 00:30:30 +00:00
|
|
|
if (input_len <= clen)
|
|
|
|
{
|
|
|
|
c = 0;
|
|
|
|
clen = input_len;
|
|
|
|
}
|
|
|
|
else // input line scrolls left if it gets too long
|
|
|
|
{
|
|
|
|
clen -= 2; // There will always be some extra truncation -- but where is what we'll find out
|
|
|
|
|
|
|
|
if (input_cur <= clen/2)
|
|
|
|
{
|
|
|
|
// Close enough to right edge to show all
|
|
|
|
c = 0;
|
|
|
|
// Always will truncate right side from this position, so always draw right ellipsis
|
|
|
|
rellip = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Cursor in the middle (or right side) of input
|
|
|
|
// Move over for the ellipsis
|
|
|
|
c = input_cur - (clen/2) + 2;
|
|
|
|
x += charwidth*2;
|
|
|
|
lellip = 1;
|
|
|
|
|
|
|
|
if (c + clen >= input_len)
|
|
|
|
{
|
|
|
|
// Cursor in the right side of input
|
|
|
|
// We were too far over, so move back
|
|
|
|
c = input_len - clen;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Cursor in the middle -- ellipses on both sides
|
|
|
|
clen -= 2;
|
|
|
|
rellip = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lellip)
|
|
|
|
{
|
2016-11-04 02:36:43 +00:00
|
|
|
x -= charwidth*3;
|
|
|
|
if (input_sel < c)
|
2016-11-11 00:53:27 +00:00
|
|
|
V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 77 | V_NOSCALESTART);
|
2016-11-04 02:36:43 +00:00
|
|
|
for (i = 0; i < 3; ++i, x += charwidth)
|
2017-04-14 19:43:30 +00:00
|
|
|
V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, true);
|
2016-11-04 00:30:30 +00:00
|
|
|
}
|
|
|
|
else
|
2017-04-14 19:43:30 +00:00
|
|
|
V_DrawCharacter(x-charwidth, y, CON_PROMPTCHAR | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, true);
|
2016-11-04 00:30:30 +00:00
|
|
|
|
|
|
|
for (cend = c + clen; c < cend; ++c, x += charwidth)
|
|
|
|
{
|
|
|
|
if ((input_sel > c && input_cur <= c) || (input_sel <= c && input_cur > c))
|
|
|
|
{
|
2016-11-11 00:53:27 +00:00
|
|
|
V_DrawFill(x, y, charwidth, (10 * con_scalefactor), 77 | V_NOSCALESTART);
|
2017-04-14 19:43:30 +00:00
|
|
|
V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_YELLOWMAP | V_NOSCALESTART, true);
|
2016-11-04 00:30:30 +00:00
|
|
|
}
|
|
|
|
else
|
2017-04-14 19:43:30 +00:00
|
|
|
V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, true);
|
2016-11-04 00:30:30 +00:00
|
|
|
|
|
|
|
if (c == input_cur && con_tick >= 4)
|
2017-04-14 19:43:30 +00:00
|
|
|
V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, true);
|
2016-11-04 00:30:30 +00:00
|
|
|
}
|
|
|
|
if (cend == input_cur && con_tick >= 4)
|
2017-04-14 19:43:30 +00:00
|
|
|
V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, true);
|
2016-11-04 00:30:30 +00:00
|
|
|
if (rellip)
|
|
|
|
{
|
2016-11-04 02:36:43 +00:00
|
|
|
if (input_sel > cend)
|
2016-11-11 00:53:27 +00:00
|
|
|
V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 77 | V_NOSCALESTART);
|
2016-11-04 00:30:30 +00:00
|
|
|
for (i = 0; i < 3; ++i, x += charwidth)
|
2017-04-14 19:43:30 +00:00
|
|
|
V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, true);
|
2016-11-04 00:30:30 +00:00
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// draw the last lines of console text to the top of the screen
|
|
|
|
static void CON_DrawHudlines(void)
|
|
|
|
{
|
|
|
|
UINT8 *p;
|
|
|
|
size_t i;
|
|
|
|
INT32 y;
|
|
|
|
INT32 charflags = 0;
|
|
|
|
INT32 charwidth = 8 * con_scalefactor;
|
|
|
|
INT32 charheight = 8 * con_scalefactor;
|
|
|
|
|
2023-02-04 16:34:43 +00:00
|
|
|
if (!con_hudlines)
|
2014-03-15 16:59:03 +00:00
|
|
|
return;
|
|
|
|
|
2018-08-19 09:12:21 +00:00
|
|
|
if (chat_on && OLDCHAT)
|
2018-07-31 09:10:02 +00:00
|
|
|
y = charheight; // leave place for chat input in the first row of text (only do it if consolechat is on.)
|
2014-03-15 16:59:03 +00:00
|
|
|
else
|
|
|
|
y = 0;
|
|
|
|
|
2023-02-04 16:34:43 +00:00
|
|
|
for (i = con_cy - con_hudlines; i <= con_cy; i++)
|
2014-03-15 16:59:03 +00:00
|
|
|
{
|
|
|
|
size_t c;
|
|
|
|
INT32 x;
|
|
|
|
|
|
|
|
if ((signed)i < 0)
|
|
|
|
continue;
|
|
|
|
if (con_hudtime[i%con_hudlines] == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
p = (UINT8 *)&con_buffer[(i%con_totallines)*con_width];
|
|
|
|
|
|
|
|
for (c = 0, x = 0; c < con_width; c++, x += charwidth, p++)
|
|
|
|
{
|
|
|
|
while (*p & 0x80) // Graue 06-19-2004
|
|
|
|
{
|
|
|
|
charflags = (*p & 0x7f) << V_CHARCOLORSHIFT;
|
|
|
|
p++;
|
2021-03-25 17:43:30 +00:00
|
|
|
c++;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
2021-04-06 20:06:44 +00:00
|
|
|
if (c >= con_width)
|
|
|
|
break;
|
2014-03-15 16:59:03 +00:00
|
|
|
if (*p < HU_FONTSTART)
|
|
|
|
;//charwidth = 4 * con_scalefactor;
|
|
|
|
else
|
|
|
|
{
|
2020-11-22 23:02:47 +00:00
|
|
|
//charwidth = (hu_font['A'-HU_FONTSTART]->width) * con_scalefactor;
|
2017-04-14 19:43:30 +00:00
|
|
|
V_DrawCharacter(x, y, (INT32)(*p) | charflags | cv_constextsize.value | V_NOSCALESTART, true);
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-14 19:43:30 +00:00
|
|
|
//V_DrawCharacter(x, y, (p[c]&0xff) | cv_constextsize.value | V_NOSCALESTART, true);
|
2014-03-15 16:59:03 +00:00
|
|
|
y += charheight;
|
|
|
|
}
|
|
|
|
|
|
|
|
// top screen lines that might need clearing when view is reduced
|
|
|
|
con_clearlines = y; // this is handled by HU_Erase();
|
|
|
|
}
|
|
|
|
|
2020-03-17 18:23:13 +00:00
|
|
|
// Lactozilla: Draws the console's background picture.
|
|
|
|
static void CON_DrawBackpic(void)
|
|
|
|
{
|
|
|
|
patch_t *con_backpic;
|
|
|
|
lumpnum_t piclump;
|
|
|
|
int x, w, h;
|
|
|
|
|
2020-08-28 21:11:38 +00:00
|
|
|
// Get the lumpnum for CONSBACK, STARTUP (Only during game startup) or fallback into MISSING.
|
|
|
|
if (con_startup)
|
|
|
|
piclump = W_CheckNumForName("STARTUP");
|
|
|
|
else
|
|
|
|
piclump = W_CheckNumForName("CONSBACK");
|
|
|
|
|
2020-03-17 18:23:13 +00:00
|
|
|
if (piclump == LUMPERROR)
|
|
|
|
piclump = W_GetNumForName("MISSING");
|
|
|
|
|
2020-08-14 23:48:15 +00:00
|
|
|
// Cache the patch.
|
|
|
|
con_backpic = W_CachePatchNum(piclump, PU_PATCH);
|
2020-03-17 18:23:13 +00:00
|
|
|
|
|
|
|
// Center the backpic, and draw a vertically cropped patch.
|
|
|
|
w = (con_backpic->width * vid.dupx);
|
|
|
|
x = (vid.width / 2) - (w / 2);
|
|
|
|
h = con_curlines/vid.dupy;
|
|
|
|
|
|
|
|
// If the patch doesn't fill the entire screen,
|
|
|
|
// then fill the sides with a solid color.
|
|
|
|
if (x > 0)
|
|
|
|
{
|
2020-08-08 08:16:47 +00:00
|
|
|
column_t *column = (column_t *)((UINT8 *)(con_backpic->columns) + (con_backpic->columnofs[0]));
|
2020-03-17 18:23:13 +00:00
|
|
|
if (!column->topdelta)
|
|
|
|
{
|
|
|
|
UINT8 *source = (UINT8 *)(column) + 3;
|
|
|
|
INT32 color = (source[0] | V_NOSCALESTART);
|
|
|
|
// left side
|
|
|
|
V_DrawFill(0, 0, x, con_curlines, color);
|
|
|
|
// right side
|
|
|
|
V_DrawFill((x + w), 0, (vid.width - w), con_curlines, color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-14 23:48:15 +00:00
|
|
|
// Draw the patch.
|
2020-12-11 22:43:38 +00:00
|
|
|
V_DrawCroppedPatch(x << FRACBITS, 0, FRACUNIT, FRACUNIT, V_NOSCALESTART, con_backpic, NULL,
|
|
|
|
0, (BASEVIDHEIGHT - h) << FRACBITS, BASEVIDWIDTH << FRACBITS, h << FRACBITS);
|
2020-03-17 18:23:13 +00:00
|
|
|
|
|
|
|
// Unlock the cached patch.
|
|
|
|
W_UnlockCachedPatch(con_backpic);
|
|
|
|
}
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
// draw the console background, text, and prompt if enough place
|
|
|
|
//
|
|
|
|
static void CON_DrawConsole(void)
|
|
|
|
{
|
|
|
|
UINT8 *p;
|
|
|
|
size_t i;
|
|
|
|
INT32 y;
|
|
|
|
INT32 charflags = 0;
|
|
|
|
INT32 charwidth = (INT32)con_scalefactor << 3;
|
|
|
|
INT32 charheight = charwidth;
|
|
|
|
INT32 minheight = 20 * con_scalefactor; // 20 = 8+8+4
|
|
|
|
|
|
|
|
if (con_curlines <= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
//FIXME: refresh borders only when console bg is translucent
|
|
|
|
con_clearlines = con_curlines; // clear console draw from view borders
|
|
|
|
con_hudupdate = true; // always refresh while console is on
|
|
|
|
|
|
|
|
// draw console background
|
|
|
|
if (cons_backpic.value || con_forcepic)
|
2020-03-17 18:23:13 +00:00
|
|
|
CON_DrawBackpic();
|
2014-03-15 16:59:03 +00:00
|
|
|
else
|
|
|
|
{
|
2014-08-04 03:49:33 +00:00
|
|
|
// inu: no more width (was always 0 and vid.width)
|
|
|
|
if (rendermode != render_none)
|
2016-11-02 21:26:35 +00:00
|
|
|
V_DrawFadeConsBack(con_curlines); // translucent background
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// draw console text lines from top to bottom
|
|
|
|
if (con_curlines < minheight)
|
|
|
|
return;
|
|
|
|
|
|
|
|
i = con_cy - con_scrollup;
|
|
|
|
|
|
|
|
// skip the last empty line due to the cursor being at the start of a new line
|
2018-03-20 06:15:16 +00:00
|
|
|
i--;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
i -= (con_curlines - minheight) / charheight;
|
|
|
|
|
|
|
|
if (rendermode == render_none) return;
|
|
|
|
|
|
|
|
for (y = (con_curlines-minheight) % charheight; y <= con_curlines-minheight; y += charheight, i++)
|
|
|
|
{
|
|
|
|
INT32 x;
|
|
|
|
size_t c;
|
|
|
|
|
|
|
|
p = (UINT8 *)&con_buffer[((i > 0 ? i : 0)%con_totallines)*con_width];
|
|
|
|
|
|
|
|
for (c = 0, x = charwidth; c < con_width; c++, x += charwidth, p++)
|
|
|
|
{
|
|
|
|
while (*p & 0x80)
|
|
|
|
{
|
|
|
|
charflags = (*p & 0x7f) << V_CHARCOLORSHIFT;
|
|
|
|
p++;
|
2021-03-25 17:43:30 +00:00
|
|
|
c++;
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
2021-04-06 20:06:44 +00:00
|
|
|
if (c >= con_width)
|
|
|
|
break;
|
2017-04-14 19:43:30 +00:00
|
|
|
V_DrawCharacter(x, y, (INT32)(*p) | charflags | cv_constextsize.value | V_NOSCALESTART, true);
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// draw prompt if enough place (not while game startup)
|
|
|
|
if ((con_curlines == con_destlines) && (con_curlines >= minheight) && !con_startup)
|
|
|
|
CON_DrawInput();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Console refresh drawer, call each frame
|
|
|
|
//
|
|
|
|
void CON_Drawer(void)
|
|
|
|
{
|
2020-04-28 20:08:43 +00:00
|
|
|
Lock_state();
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
if (!con_started || !graphics_started)
|
2020-04-28 20:08:43 +00:00
|
|
|
{
|
|
|
|
Unlock_state();
|
2014-03-15 16:59:03 +00:00
|
|
|
return;
|
2020-04-28 20:08:43 +00:00
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
if (con_recalc)
|
2019-09-09 00:37:24 +00:00
|
|
|
{
|
2014-03-15 16:59:03 +00:00
|
|
|
CON_RecalcSize();
|
2019-09-09 19:20:17 +00:00
|
|
|
if (con_curlines <= 0)
|
|
|
|
CON_ClearHUD();
|
2019-09-09 00:37:24 +00:00
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
if (con_curlines > 0)
|
|
|
|
CON_DrawConsole();
|
2017-09-15 19:34:46 +00:00
|
|
|
else if (gamestate == GS_LEVEL
|
A good and bad ending cutscene now exist.
Also:
* SPR2_XTRA - instead of defining lumpnames in S_SKIN, those kinds of assets can just be bundled into the spriteset. Required for ending cutscene stuff, I guess, but also done for HUD life icon and character select image (aside from Sonic&Tails, still SOC'd in).
* Minor oversights in SPR2 support corrected.
* Better evaluation, featuring ending assets.
* Intro has warping-in blackrock, reusing ending assets.
* Cutscene text now supports lowercase (intro and custom).
* Disable the asset-fucking "gamma correction" I put in over two years ago when implementing colour cube. (This is the only thing I could move into another branch if you MUST, but it's basically invisble in the diff so w/e.)
* Don't blank the screen if the top left pixel of a screen-covering patch is transparent. (Checked via nonzero topdelta for first column)
Bugs:
* OPENGL ONLY: The first ~20 frames of both endings are fucked. A little help here? Might be HWR_DrawFadeFill's fault, which I just created. OR it could be in f_finale, but I doubt it, since it doesn't appear in Software.
2019-07-27 23:32:57 +00:00
|
|
|
|| gamestate == GS_INTERMISSION || gamestate == GS_ENDING || gamestate == GS_CUTSCENE
|
2017-09-15 19:34:46 +00:00
|
|
|
|| gamestate == GS_CREDITS || gamestate == GS_EVALUATION)
|
2014-03-15 16:59:03 +00:00
|
|
|
CON_DrawHudlines();
|
2020-04-28 20:08:43 +00:00
|
|
|
|
|
|
|
Unlock_state();
|
2014-03-15 16:59:03 +00:00
|
|
|
}
|