Draw an icon above players when they are typing in chat or console

A little speech bubble is drawn, with dots cycling as they type.
No typing = no dots.
This commit is contained in:
James R 2021-02-16 09:24:22 -08:00
parent 4993d2ce39
commit dd5223f4d7
8 changed files with 112 additions and 0 deletions

View file

@ -233,7 +233,10 @@ void D_ProcessEvents(void)
#endif #endif
if (eaten) if (eaten)
{
hu_keystrokes = true;
continue; // ate the event continue; // ate the event
}
G_Responder(ev); G_Responder(ev);
} }

View file

@ -697,6 +697,9 @@ typedef struct player_s
tic_t jointime; // Timer when player joins game to change skin/color tic_t jointime; // Timer when player joins game to change skin/color
tic_t quittime; // Time elapsed since user disconnected, zero if connected tic_t quittime; // Time elapsed since user disconnected, zero if connected
UINT8 typing_timer : 4; // Counts down while keystrokes are not emitted
UINT8 typing_duration : 6; // How long since resumed timer
#ifdef HWRENDER #ifdef HWRENDER
fixed_t fovadd; // adjust FOV for hw rendering fixed_t fovadd; // adjust FOV for hw rendering
#endif #endif

View file

@ -54,6 +54,8 @@ typedef enum
// ticcmd flags // ticcmd flags
#define TICCMD_RECEIVED 1 #define TICCMD_RECEIVED 1
#define TICCMD_TYPING 2/* chat window or console open */
#define TICCMD_KEYSTROKE 4/* chat character input */
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma pack(1) #pragma pack(1)

View file

@ -1120,6 +1120,16 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
cmd->latency = modeattacking ? 0 : (leveltime & 0xFF); // Send leveltime when this tic was generated to the server for control lag calculations cmd->latency = modeattacking ? 0 : (leveltime & 0xFF); // Send leveltime when this tic was generated to the server for control lag calculations
cmd->flags = 0; cmd->flags = 0;
if (chat_on || CON_Ready())
{
cmd->flags |= TICCMD_TYPING;
if (hu_keystrokes)
{
cmd->flags |= TICCMD_KEYSTROKE;
}
}
/* Lua: Allow this hook to overwrite ticcmd. /* Lua: Allow this hook to overwrite ticcmd.
We check if we're actually in a level because for some reason this Hook would run in menus and on the titlescreen otherwise. We check if we're actually in a level because for some reason this Hook would run in menus and on the titlescreen otherwise.
Be aware that within this hook, nothing but this player's cmd can be edited (otherwise we'd run in some pretty bad synching problems since this is clientsided, or something) Be aware that within this hook, nothing but this player's cmd can be edited (otherwise we'd run in some pretty bad synching problems since this is clientsided, or something)
@ -1357,7 +1367,10 @@ boolean G_Responder(event_t *ev)
if (gamestate == GS_LEVEL) if (gamestate == GS_LEVEL)
{ {
if (HU_Responder(ev)) if (HU_Responder(ev))
{
hu_keystrokes = true;
return true; // chat ate the event return true; // chat ate the event
}
if (AM_Responder(ev)) if (AM_Responder(ev))
return true; // automap ate it return true; // automap ate it
// map the event (key/mouse/joy) to a gamecontrol // map the event (key/mouse/joy) to a gamecontrol
@ -1374,7 +1387,10 @@ boolean G_Responder(event_t *ev)
else if (gamestate == GS_CUTSCENE) else if (gamestate == GS_CUTSCENE)
{ {
if (HU_Responder(ev)) if (HU_Responder(ev))
{
hu_keystrokes = true;
return true; // chat ate the event return true; // chat ate the event
}
if (F_CutsceneResponder(ev)) if (F_CutsceneResponder(ev))
{ {
@ -1385,7 +1401,10 @@ boolean G_Responder(event_t *ev)
else if (gamestate == GS_CREDITS || gamestate == GS_ENDING) // todo: keep ending here? else if (gamestate == GS_CREDITS || gamestate == GS_ENDING) // todo: keep ending here?
{ {
if (HU_Responder(ev)) if (HU_Responder(ev))
{
hu_keystrokes = true;
return true; // chat ate the event return true; // chat ate the event
}
if (F_CreditResponder(ev)) if (F_CreditResponder(ev))
{ {
@ -1408,7 +1427,10 @@ boolean G_Responder(event_t *ev)
} }
else if (gamestate == GS_INTERMISSION || gamestate == GS_VOTING || gamestate == GS_EVALUATION) else if (gamestate == GS_INTERMISSION || gamestate == GS_VOTING || gamestate == GS_EVALUATION)
if (HU_Responder(ev)) if (HU_Responder(ev))
{
hu_keystrokes = true;
return true; // chat ate the event return true; // chat ate the event
}
// allow spy mode changes even during the demo // allow spy mode changes even during the demo
if (gamestate == GS_LEVEL && ev->type == ev_keydown if (gamestate == GS_LEVEL && ev->type == ev_keydown

View file

@ -78,6 +78,7 @@ patch_t *frameslash; // framerate stuff. Used in screen.c
static player_t *plr; static player_t *plr;
boolean chat_on; // entering a chat message? boolean chat_on; // entering a chat message?
boolean hu_keystrokes; // :)
static char w_chat[HU_MAXMSGLEN]; static char w_chat[HU_MAXMSGLEN];
static size_t c_input = 0; // let's try to make the chat input less shitty. static size_t c_input = 0; // let's try to make the chat input less shitty.
static boolean headsupactive = false; static boolean headsupactive = false;
@ -879,6 +880,8 @@ void HU_Ticker(void)
hu_showscores = !chat_on; hu_showscores = !chat_on;
else else
hu_showscores = false; hu_showscores = false;
hu_keystrokes = false;
} }
#ifndef NONET #ifndef NONET

View file

@ -94,6 +94,9 @@ void HU_AddChatText(const char *text, boolean playsound);
// set true when entering a chat message // set true when entering a chat message
extern boolean chat_on; extern boolean chat_on;
// keystrokes in the console or chat window
extern boolean hu_keystrokes;
extern patch_t *pinggfx[5]; extern patch_t *pinggfx[5];
extern patch_t *framecounter; extern patch_t *framecounter;
extern patch_t *frameslash; extern patch_t *frameslash;

View file

@ -133,6 +133,9 @@ static patch_t *kp_check[6];
static patch_t *kp_rival[2]; static patch_t *kp_rival[2];
static patch_t *kp_localtag[4][2]; static patch_t *kp_localtag[4][2];
static patch_t *kp_talk;
static patch_t *kp_typdot;
static patch_t *kp_eggnum[4]; static patch_t *kp_eggnum[4];
static patch_t *kp_flameshieldmeter[104][2]; static patch_t *kp_flameshieldmeter[104][2];
@ -503,6 +506,10 @@ void K_LoadKartHUDGraphics(void)
} }
} }
// Typing indicator
kp_talk = W_CachePatchName("K_TALK", PU_HUDGFX);
kp_typdot = W_CachePatchName("K_TYPDOT", PU_HUDGFX);
// Eggman warning numbers // Eggman warning numbers
sprintf(buffer, "K_EGGNx"); sprintf(buffer, "K_EGGNx");
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
@ -2598,6 +2605,43 @@ static void K_DrawRivalTagForPlayer(fixed_t x, fixed_t y)
V_DrawFixedPatch(x, y, FRACUNIT, V_HUDTRANS|V_SPLITSCREEN, kp_rival[blink], NULL); V_DrawFixedPatch(x, y, FRACUNIT, V_HUDTRANS|V_SPLITSCREEN, kp_rival[blink], NULL);
} }
static boolean K_DrawTypingDot(fixed_t x, fixed_t y, UINT8 duration, player_t *p)
{
if (p->typing_duration > duration)
{
V_DrawFixedPatch(x, y, FRACUNIT, V_HUDTRANS|V_SPLITSCREEN, kp_typdot, NULL);
return true;
}
else
{
return false;
}
}
static boolean K_DrawTypingNotifier(fixed_t x, fixed_t y, player_t *p)
{
if (p->cmd.flags & TICCMD_TYPING)
{
V_DrawFixedPatch(x, y, FRACUNIT, V_HUDTRANS|V_SPLITSCREEN, kp_talk, NULL);
y += 4*FRACUNIT;
/* spacing closer with the last two looks a better most of the time */
(void)
(
K_DrawTypingDot(x + 3*FRACUNIT, y, 15, p) &&
K_DrawTypingDot(x + 6*FRACUNIT - FRACUNIT/3, y, 31, p) &&
K_DrawTypingDot(x + 9*FRACUNIT - FRACUNIT/3, y, 47, p)
);
return true;
}
else
{
return false;
}
}
static void K_DrawNameTagForPlayer(fixed_t x, fixed_t y, player_t *p, UINT8 cnum) static void K_DrawNameTagForPlayer(fixed_t x, fixed_t y, player_t *p, UINT8 cnum)
{ {
const INT32 clr = skincolors[p->skincolor].chatcolor; const INT32 clr = skincolors[p->skincolor].chatcolor;
@ -2840,6 +2884,7 @@ static void K_drawKartNameTags(void)
if (K_ShowPlayerNametag(ntplayer) == true) if (K_ShowPlayerNametag(ntplayer) == true)
{ {
K_DrawNameTagForPlayer(result.x, result.y, ntplayer, cnum); K_DrawNameTagForPlayer(result.x, result.y, ntplayer, cnum);
K_DrawTypingNotifier(result.x, result.y, ntplayer);
} }
} }
} }

View file

@ -4588,6 +4588,37 @@ void P_PlayerThink(player_t *player)
player->mo->drawflags &= ~MFD_DONTDRAW; player->mo->drawflags &= ~MFD_DONTDRAW;
} }
if (cmd->flags & TICCMD_TYPING)
{
if (cmd->flags & TICCMD_KEYSTROKE)
{
player->typing_timer = 15;
}
else if (player->typing_timer > 0)
{
player->typing_timer--;
}
if (player->typing_timer + player->typing_duration > 0)
{
/* lag a little bit so we always get more than just a singular dot */
if (player->typing_timer == 0 &&
(player->typing_duration < 16 || player->typing_duration > 39))
{
player->typing_duration = 0;
}
else
{
player->typing_duration++;
}
}
}
else
{
player->typing_timer = 0;
player->typing_duration = 0;
}
player->pflags &= ~PF_SLIDING; player->pflags &= ~PF_SLIDING;
K_KartPlayerThink(player, cmd); // SRB2kart K_KartPlayerThink(player, cmd); // SRB2kart