Merge pull request #130 from LJSonik/console-and-chat-improvement

Chat and console improvements
This commit is contained in:
Alam Arias 2016-11-03 02:05:47 -04:00 committed by GitHub
commit d4ee063c4c
3 changed files with 498 additions and 153 deletions

View file

@ -91,11 +91,13 @@ 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
static size_t input_cx; // position in current input line
static INT32 input_selection; // selection border in current input line, -1 if no selection
// protos.
static void CON_InputInit(void);
static void CON_RecalcSize(void);
static void CON_DeleteSelectedText(void);
static void CONS_hudlines_Change(void);
static void CON_DrawBackpic(patch_t *pic, INT32 startx, INT32 destwidth);
//static void CON_DrawBackpic2(pic_t *pic, INT32 startx, INT32 destwidth);
@ -394,6 +396,7 @@ static void CON_InputInit(void)
inputlines[i][0] = CON_PROMPTCHAR;
inputline = 0;
input_cx = 1;
input_selection = -1;
}
//======================================================================
@ -618,6 +621,25 @@ void CON_Ticker(void)
}
}
// Deletes selected text, assuming there is, and resets selection.
// Also sets the cursor to the correct position.
//
static void CON_DeleteSelectedText(void)
{
UINT32 i, j;
char *line = inputlines[inputline];
size_t selstart = min(input_cx, (size_t)input_selection);
size_t selend = max(input_cx, (size_t)input_selection);
for (i = selstart, j = selend; line[j]; ++i, ++j)
line[i] = line[j];
while (line[i])
line[i++] = 0;
input_cx = selstart;
input_selection = -1;
}
// Handles console key input
//
boolean CON_Responder(event_t *ev)
@ -704,6 +726,9 @@ boolean CON_Responder(event_t *ev)
// command completion forward (tab) and backward (shift-tab)
if (key == KEY_TAB)
{
input_cx = strlen(inputlines[inputline]); // make sure the cursor is at the end of the string, in case we were inserting
input_selection = -1; // make sure there is no text selected, it would look odd
// show all cvars/commands that match what we have inputted
if (ctrldown)
{
@ -839,21 +864,51 @@ boolean CON_Responder(event_t *ev)
return true;
}
if (key == KEY_HOME) // oldest text in buffer
if (key == KEY_HOME)
{
con_scrollup = (con_totallines-((con_curlines-16)>>3));
if (shiftdown)
{
if (input_selection == -1)
input_selection = input_cx;
}
else
input_selection = -1;
if (ctrldown)
con_scrollup = (con_totallines-((con_curlines-16)>>3)); // oldest text in buffer
else
input_cx = 1;
if ((INT32)input_cx == input_selection)
input_selection = -1;
return true;
}
else if (key == KEY_END) // most recent text in buffer
else if (key == KEY_END)
{
con_scrollup = 0;
if (shiftdown)
{
if (input_selection == -1)
input_selection = input_cx;
}
else
input_selection = -1;
if (ctrldown)
con_scrollup = 0; // most recent text in buffer
else
input_cx = strlen(inputlines[inputline]);
if ((INT32)input_cx == input_selection)
input_selection = -1;
return true;
}
// command enter
if (key == KEY_ENTER)
{
if (input_cx < 2)
if (strlen(inputlines[inputline]) < 2)
return true;
// push the command
@ -868,18 +923,107 @@ boolean CON_Responder(event_t *ev)
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
inputlines[inputline][0] = CON_PROMPTCHAR;
input_cx = 1;
input_selection = -1;
return true;
}
// backspace command prompt
// backspace command prompt or delete selected text
if (key == KEY_BACKSPACE)
{
if (input_selection == -1)
{
if (input_cx > 1)
{
UINT32 i, j;
char *line = inputlines[inputline];
for (i = input_cx - 1, j = input_cx; line[j]; ++i, ++j)
line[i] = line[j];
line[i] = 0;
input_cx--;
inputlines[inputline][input_cx] = 0;
}
}
else
CON_DeleteSelectedText();
return true;
}
// delete character under cursor or selected text
if (key == KEY_DEL)
{
if (input_selection == -1)
{
UINT32 i, j;
char *line = inputlines[inputline];
for (i = input_cx, j = input_cx + 1; line[j]; ++i, ++j)
line[i] = line[j];
line[i] = 0;
}
else
CON_DeleteSelectedText();
return true;
}
if (key == KEY_LEFTARROW)
{
if (shiftdown)
{
if (input_selection == -1)
input_selection = input_cx;
}
else
input_selection = -1;
// move cursor to previous word
if (ctrldown)
{
char *line = inputlines[inputline];
while (input_cx > 1 && line[input_cx - 1] == ' ')
input_cx--;
while (input_cx > 1 && line[input_cx - 1] != ' ')
input_cx--;
}
// move cursor left
else if (input_cx > 1)
input_cx--;
if ((INT32)input_cx == input_selection)
input_selection = -1;
return true;
}
if (key == KEY_RIGHTARROW)
{
if (shiftdown)
{
if (input_selection == -1)
input_selection = input_cx;
}
else
input_selection = -1;
// move cursor to next word
if (ctrldown)
{
char *line = inputlines[inputline];
while (line[input_cx] && line[input_cx] != ' ')
input_cx++;
while (line[input_cx] && line[input_cx] == ' ')
input_cx++;
}
// move cursor right
else if (inputlines[inputline][input_cx])
input_cx++;
if ((INT32)input_cx == input_selection)
input_selection = -1;
return true;
}
@ -950,13 +1094,21 @@ boolean CON_Responder(event_t *ev)
return false;
// add key to cmd line here
if (input_cx < CON_MAXPROMPTCHARS)
if (strlen(inputlines[inputline]) < CON_MAXPROMPTCHARS - 1)
{
INT32 i, j;
char *line = inputlines[inputline];
if (key >= 'A' && key <= 'Z' && !shiftdown) //this is only really necessary for dedicated servers
key = key + 'a' - 'A';
inputlines[inputline][input_cx] = (char)key;
inputlines[inputline][input_cx + 1] = 0;
if (input_selection != -1)
CON_DeleteSelectedText();
for (i = strlen(line), j = i + 1; j > (INT32)input_cx; --i, --j)
line[j] = line[i];
line[input_cx] = (char)key;
input_cx++;
}
@ -1246,6 +1398,7 @@ static void CON_DrawInput(void)
size_t c;
INT32 x, y;
INT32 charwidth = (INT32)con_scalefactor << 3;
INT32 f = cv_constextsize.value | V_NOSCALESTART;
// input line scrolls left if it gets too long
p = inputlines[inputline];
@ -1254,14 +1407,44 @@ static void CON_DrawInput(void)
y = con_curlines - 12 * con_scalefactor;
if (input_selection == -1)
{
for (c = 0, x = charwidth; c < con_width-11; c++, x += charwidth)
V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
V_DrawCharacter(x, y, p[c] | f, !cv_allcaps.value);
}
else
{
size_t selstart = min(input_cx, (size_t)input_selection);
size_t selend = max(input_cx, (size_t)input_selection);
for (c = 0, x = charwidth; c < selstart && c < con_width-11; c++, x += charwidth)
V_DrawCharacter(x, y, p[c] | f, !cv_allcaps.value);
f |= V_YELLOWMAP;
for (; c < selend && c < con_width-11; c++, x += charwidth)
V_DrawCharacter(x, y, p[c] | f, !cv_allcaps.value);
f &= ~V_YELLOWMAP;
for (; c < con_width-11; c++, x += charwidth)
V_DrawCharacter(x, y, p[c] | f, !cv_allcaps.value);
}
//for (c = 0, x = charwidth; c < con_width-11; c++, x += charwidth)
//V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
// draw the blinking cursor
//
x = ((input_cx >= con_width-11) ? (INT32)(con_width-11) : (INT32)((input_cx + 1)) * charwidth);
if (con_tick < 4)
V_DrawCharacter(x, y, '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
{
if (inputlines[inputline][input_cx])
//V_DrawCharacter(x - 2 * con_scalefactor, y, '|' | f, !cv_allcaps.value);
V_DrawCharacter(x, y + 2 * con_scalefactor, '_' | f, !cv_allcaps.value);
else
V_DrawCharacter(x, y, '_' | f, !cv_allcaps.value);
}
/*x = ((input_cx >= con_width-11) ? (INT32)(con_width-11) : (INT32)((input_cx + 1)) * charwidth);
if (con_tick < 4)
V_DrawCharacter(x, y, '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);*/
}
// draw the last lines of console text to the top of the screen

View file

@ -73,6 +73,9 @@ patch_t *cred_font[CRED_FONTSIZE];
static player_t *plr;
boolean chat_on; // entering a chat message?
static char w_chat[HU_MAXMSGLEN];
static size_t chat_pos; // position of the cursor in the chat
static INT32 chat_selection; // selection border in current input line, -1 if no selection
static boolean teamtalk = false;
static boolean headsupactive = false;
boolean hu_showscores; // draw rankings
static char hu_tick;
@ -106,6 +109,7 @@ static patch_t *crosshair[HU_CROSSHAIRS]; // 3 precached crosshair graphics
static void HU_DrawRankings(void);
static void HU_DrawCoopOverlay(void);
static void HU_DrawNetplayCoopOverlay(void);
static void HU_DeleteSelectedText(void);
//======================================================================
// KEYBOARD LAYOUTS FOR ENTERING TEXT
@ -621,36 +625,183 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
}
#endif
// Deletes selected text, assuming there is, and resets selection.
// Also sets the cursor to the correct position.
//
static void HU_DeleteSelectedText(void)
{
UINT32 i, j;
size_t selstart = min(chat_pos, (size_t)chat_selection);
size_t selend = max(chat_pos, (size_t)chat_selection);
for (i = selstart, j = selend; w_chat[j]; ++i, ++j)
w_chat[i] = w_chat[j];
while (w_chat[i])
w_chat[i++] = 0;
chat_pos = selstart;
chat_selection = -1;
}
// Handles key input and string input
//
static inline boolean HU_keyInChatString(char *s, char ch)
static void HU_keyInChatString(UINT32 key, boolean shiftdown, boolean ctrldown)
{
size_t l;
switch (key)
{
case KEY_ESCAPE:
chat_on = false;
break;
case KEY_ENTER:
{
// send automatically the message (no more chat char)
char buf[2+256];
size_t ci = 2;
char *cp = w_chat;
if ((ch >= HU_FONTSTART && ch <= HU_FONTEND && hu_font[ch-HU_FONTSTART])
|| ch == ' ') // Allow spaces, of course
while (*cp)
{
l = strlen(s);
if (l < HU_MAXMSGLEN - 1)
{
s[l++] = ch;
s[l]=0;
return true;
if (*cp >= ' ' && !(*cp & 0x80))
buf[ci++] = *cp;
cp++;
}
return false;
}
else if (ch == KEY_BACKSPACE)
buf[ci] = 0;
// last minute mute check
if (cv_mute.value && !(server || adminplayer == consoleplayer))
{
l = strlen(s);
if (l)
s[--l] = 0;
CONS_Alert(CONS_NOTICE, M_GetText("The chat is muted. You can't say anything at the moment.\n"));
return;
}
if (ci > 2) // don't send target+flags+empty message.
{
if (teamtalk)
buf[0] = -1; // target
else
return false;
buf[0] = 0; // target
buf[1] = 0; // flags
SendNetXCmd(XD_SAY, buf, 2 + strlen(&buf[2]) + 1);
}
else if (ch != KEY_ENTER)
return false; // did not eat key
return true; // ate the key
chat_on = false;
break;
}
// cursor moving
case KEY_LEFTARROW:
case KEY_RIGHTARROW:
case KEY_HOME:
case KEY_END:
if (shiftdown)
{
if (chat_selection == -1)
chat_selection = chat_pos;
}
else
chat_selection = -1;
switch (key)
{
case KEY_LEFTARROW:
// move cursor to previous word
if (ctrldown)
{
while (chat_pos > 0 && w_chat[chat_pos - 1] == ' ')
chat_pos--;
while (chat_pos > 0 && w_chat[chat_pos - 1] != ' ')
chat_pos--;
}
// move cursor left
else if (chat_pos > 0)
chat_pos--;
break;
case KEY_RIGHTARROW:
// move cursor to next word
if (ctrldown)
{
while (w_chat[chat_pos] && w_chat[chat_pos] != ' ')
chat_pos++;
while (w_chat[chat_pos] && w_chat[chat_pos] == ' ')
chat_pos++;
}
// move cursor right
else if (w_chat[chat_pos])
chat_pos++;
break;
case KEY_HOME:
chat_pos = 0;
break;
case KEY_END:
chat_pos = strlen(w_chat);
}
if ((INT32)chat_pos == chat_selection)
chat_selection = -1;
break;
// backspace or delete selected text
case KEY_BACKSPACE:
if (chat_selection == -1)
{
if (chat_pos > 0)
{
UINT32 i, j;
for (i = chat_pos - 1, j = chat_pos; w_chat[j]; ++i, ++j)
w_chat[i] = w_chat[j];
w_chat[i] = 0;
chat_pos--;
}
}
else
HU_DeleteSelectedText();
break;
// delete character under cursor
case KEY_DEL:
if (chat_selection == -1)
{
UINT32 i, j;
for (i = chat_pos, j = chat_pos + 1; w_chat[j]; ++i, ++j)
w_chat[i] = w_chat[j];
w_chat[i] = 0;
}
else
HU_DeleteSelectedText();
break;
default:
// allow people to use keypad in chat
if (key >= KEY_KEYPAD7 && key <= KEY_KPADDEL)
{
XBOXSTATIC char keypad_translation[] = {'7','8','9','-',
'4','5','6','+',
'1','2','3',
'0','.'};
key = keypad_translation[key - KEY_KEYPAD7];
}
else if (key == KEY_KPADSLASH)
key = '/';
// use console translations
if (shiftdown)
key = shiftxform[key];
if ((key >= HU_FONTSTART && key <= HU_FONTEND && hu_font[key-HU_FONTSTART])
|| key == ' ') // Allow spaces, of course
{
if (strlen(w_chat) < HU_MAXMSGLEN - 1)
{
UINT32 i, j;
if (chat_selection != -1)
HU_DeleteSelectedText();
for (i = strlen(w_chat), j = i + 1; j > chat_pos; --i, --j)
w_chat[j] = w_chat[i];
w_chat[chat_pos] = (char)key;
chat_pos++;
}
}
}
}
//
@ -669,86 +820,9 @@ void HU_Ticker(void)
hu_showscores = false;
}
#define QUEUESIZE 256
static boolean teamtalk = false;
static char chatchars[QUEUESIZE];
static INT32 head = 0, tail = 0;
//
// HU_dequeueChatChar
//
char HU_dequeueChatChar(void)
{
char c;
if (head != tail)
{
c = chatchars[tail];
tail = (tail + 1) & (QUEUESIZE-1);
}
else
c = 0;
return c;
}
//
//
static void HU_queueChatChar(char c)
{
// send automaticly the message (no more chat char)
if (c == KEY_ENTER)
{
char buf[2+256];
size_t ci = 2;
do {
c = HU_dequeueChatChar();
if (!c || (c >= ' ' && !(c & 0x80))) // copy printable characters and terminating '\0' only.
buf[ci++]=c;
} while (c);
// last minute mute check
if (cv_mute.value && !(server || adminplayer == consoleplayer))
{
CONS_Alert(CONS_NOTICE, M_GetText("The chat is muted. You can't say anything at the moment.\n"));
return;
}
if (ci > 3) // don't send target+flags+empty message.
{
if (teamtalk)
buf[0] = -1; // target
else
buf[0] = 0; // target
buf[1] = 0; // flags
SendNetXCmd(XD_SAY, buf, 2 + strlen(&buf[2]) + 1);
}
return;
}
if (((head + 1) & (QUEUESIZE-1)) == tail)
CONS_Printf(M_GetText("[Message unsent]\n")); // message not sent
else
{
if (c == KEY_BACKSPACE)
{
if (tail != head)
head = (head - 1) & (QUEUESIZE-1);
}
else
{
chatchars[head] = c;
head = (head + 1) & (QUEUESIZE-1);
}
}
}
// REMOVE? Now this has become pretty useless IMO
void HU_clearChatChars(void)
{
while (tail != head)
HU_queueChatChar(KEY_BACKSPACE);
chat_on = false;
}
@ -758,13 +832,19 @@ void HU_clearChatChars(void)
boolean HU_Responder(event_t *ev)
{
static boolean shiftdown = false;
UINT8 c;
static boolean ctrldown = false;
INT32 key = ev->data1; // only valid if ev->type is a key event
if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT)
if (key == KEY_LSHIFT || key == KEY_RSHIFT)
{
shiftdown = (ev->type == ev_keydown);
return chat_on;
}
else if (key == KEY_LCTRL || key == KEY_RCTRL)
{
ctrldown = (ev->type == ev_keydown);
return chat_on;
}
if (ev->type != ev_keydown)
return false;
@ -774,42 +854,36 @@ boolean HU_Responder(event_t *ev)
if (!chat_on)
{
// enter chat mode
if ((ev->data1 == gamecontrol[gc_talkkey][0] || ev->data1 == gamecontrol[gc_talkkey][1])
if ((key == gamecontrol[gc_talkkey][0] || key == gamecontrol[gc_talkkey][1])
&& netgame && (!cv_mute.value || server || (adminplayer == consoleplayer)))
{
if (cv_mute.value && !(server || adminplayer == consoleplayer))
return false;
// we already checked for this two lines before...
//if (cv_mute.value && !(server || adminplayer == consoleplayer))
//return false;
chat_on = true;
w_chat[0] = 0;
chat_pos = 0;
chat_selection = -1;
teamtalk = false;
return true;
}
if ((ev->data1 == gamecontrol[gc_teamkey][0] || ev->data1 == gamecontrol[gc_teamkey][1])
if ((key == gamecontrol[gc_teamkey][0] || key == gamecontrol[gc_teamkey][1])
&& netgame && (!cv_mute.value || server || (adminplayer == consoleplayer)))
{
if (cv_mute.value && !(server || adminplayer == consoleplayer))
return false;
// we already checked for this two lines before...
//if (cv_mute.value && !(server || adminplayer == consoleplayer))
//return false;
chat_on = true;
w_chat[0] = 0;
chat_pos = 0;
chat_selection = -1;
teamtalk = true;
return true;
}
}
else // if chat_on
{
c = (UINT8)ev->data1;
// use console translations
if (shiftdown)
c = shiftxform[c];
if (HU_keyInChatString(w_chat,c))
HU_queueChatChar(c);
if (c == KEY_ENTER)
chat_on = false;
else if (c == KEY_ESCAPE)
chat_on = false;
HU_keyInChatString(key, shiftdown, ctrldown);
return true;
}
return false;
@ -826,7 +900,7 @@ boolean HU_Responder(event_t *ev)
//
static void HU_DrawChat(void)
{
INT32 t = 0, c = 0, y = HU_INPUTY;
INT32 t = 0, f = 0, c = 0, y = HU_INPUTY;
size_t i = 0;
const char *ntalk = "Say: ", *ttalk = "Say-Team: ";
const char *talk = ntalk;
@ -844,6 +918,8 @@ static void HU_DrawChat(void)
#endif
}
f = cv_constextsize.value | V_NOSCALESTART;
while (talk[i])
{
if (talk[i] < HU_FONTSTART)
@ -854,12 +930,15 @@ static void HU_DrawChat(void)
else
{
//charwidth = SHORT(hu_font[talk[i]-HU_FONTSTART]->width) * con_scalefactor;
V_DrawCharacter(HU_INPUTX + c, y, talk[i++] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
V_DrawCharacter(HU_INPUTX + c, y, talk[i++] | f, !cv_allcaps.value);
}
c += charwidth;
}
f |= t;
i = 0;
if (chat_selection == -1)
{
while (w_chat[i])
{
//Hurdler: isn't it better like that?
@ -871,7 +950,34 @@ static void HU_DrawChat(void)
else
{
//charwidth = SHORT(hu_font[w_chat[i]-HU_FONTSTART]->width) * con_scalefactor;
V_DrawCharacter(HU_INPUTX + c, y, w_chat[i++] | cv_constextsize.value | V_NOSCALESTART | t, !cv_allcaps.value);
V_DrawCharacter(HU_INPUTX + c, y, w_chat[i++] | f, !cv_allcaps.value);
}
c += charwidth;
if (c >= vid.width)
{
c = 0;
y += charheight;
}
}
}
else
{
size_t selstart = min(chat_pos, (size_t)chat_selection);
size_t selend = max(chat_pos, (size_t)chat_selection);
while (i < selstart)
{
//Hurdler: isn't it better like that?
if (w_chat[i] < HU_FONTSTART)
{
++i;
//charwidth = 4 * con_scalefactor;
}
else
{
//charwidth = SHORT(hu_font[w_chat[i]-HU_FONTSTART]->width) * con_scalefactor;
V_DrawCharacter(HU_INPUTX + c, y, w_chat[i++] | f, !cv_allcaps.value);
}
c += charwidth;
@ -882,8 +988,65 @@ static void HU_DrawChat(void)
}
}
f &= ~t;
f |= V_YELLOWMAP;
while (i < selend)
{
//Hurdler: isn't it better like that?
if (w_chat[i] < HU_FONTSTART)
{
++i;
//charwidth = 4 * con_scalefactor;
}
else
{
//charwidth = SHORT(hu_font[w_chat[i]-HU_FONTSTART]->width) * con_scalefactor;
V_DrawCharacter(HU_INPUTX + c, y, w_chat[i++] | f, !cv_allcaps.value);
}
c += charwidth;
if (c >= vid.width)
{
c = 0;
y += charheight;
}
}
f &= ~V_YELLOWMAP;
f |= t;
while (w_chat[i])
{
//Hurdler: isn't it better like that?
if (w_chat[i] < HU_FONTSTART)
{
++i;
//charwidth = 4 * con_scalefactor;
}
else
{
//charwidth = SHORT(hu_font[w_chat[i]-HU_FONTSTART]->width) * con_scalefactor;
V_DrawCharacter(HU_INPUTX + c, y, w_chat[i++] | f, !cv_allcaps.value);
}
c += charwidth;
if (c >= vid.width)
{
c = 0;
y += charheight;
}
}
}
if (hu_tick < 4)
V_DrawCharacter(HU_INPUTX + c, y, '_' | cv_constextsize.value |V_NOSCALESTART|t, !cv_allcaps.value);
{
if (w_chat[chat_pos])
{
i = (strlen(talk) + chat_pos) * charwidth;
c = i % vid.width;
y = HU_INPUTY + i / vid.width * charheight + 2 * con_scalefactor;
}
V_DrawCharacter(HU_INPUTX + c, y, '_' | f, !cv_allcaps.value);
}
}

View file

@ -93,7 +93,6 @@ boolean HU_Responder(event_t *ev);
void HU_Ticker(void);
void HU_Drawer(void);
char HU_dequeueChatChar(void);
void HU_Erase(void);
void HU_clearChatChars(void);
void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer);