From dd5223f4d71b241ab633457136eec61f7c47c0af Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 16 Feb 2021 09:24:22 -0800 Subject: [PATCH 1/7] 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. --- src/d_main.c | 3 +++ src/d_player.h | 3 +++ src/d_ticcmd.h | 2 ++ src/g_game.c | 22 ++++++++++++++++++++++ src/hu_stuff.c | 3 +++ src/hu_stuff.h | 3 +++ src/k_hud.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/p_user.c | 31 +++++++++++++++++++++++++++++++ 8 files changed, 112 insertions(+) diff --git a/src/d_main.c b/src/d_main.c index 045d558ed..3936559d5 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -233,7 +233,10 @@ void D_ProcessEvents(void) #endif if (eaten) + { + hu_keystrokes = true; continue; // ate the event + } G_Responder(ev); } diff --git a/src/d_player.h b/src/d_player.h index 95fd8adea..5ed5af013 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -697,6 +697,9 @@ typedef struct player_s tic_t jointime; // Timer when player joins game to change skin/color 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 fixed_t fovadd; // adjust FOV for hw rendering #endif diff --git a/src/d_ticcmd.h b/src/d_ticcmd.h index ed72659e5..17c41cfbf 100644 --- a/src/d_ticcmd.h +++ b/src/d_ticcmd.h @@ -54,6 +54,8 @@ typedef enum // ticcmd flags #define TICCMD_RECEIVED 1 +#define TICCMD_TYPING 2/* chat window or console open */ +#define TICCMD_KEYSTROKE 4/* chat character input */ #if defined(_MSC_VER) #pragma pack(1) diff --git a/src/g_game.c b/src/g_game.c index 6cc1f9aa2..9f203e413 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -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->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. 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) @@ -1357,7 +1367,10 @@ boolean G_Responder(event_t *ev) if (gamestate == GS_LEVEL) { if (HU_Responder(ev)) + { + hu_keystrokes = true; return true; // chat ate the event + } if (AM_Responder(ev)) return true; // automap ate it // map the event (key/mouse/joy) to a gamecontrol @@ -1374,7 +1387,10 @@ boolean G_Responder(event_t *ev) else if (gamestate == GS_CUTSCENE) { if (HU_Responder(ev)) + { + hu_keystrokes = true; return true; // chat ate the event + } 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? { if (HU_Responder(ev)) + { + hu_keystrokes = true; return true; // chat ate the event + } 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) if (HU_Responder(ev)) + { + hu_keystrokes = true; return true; // chat ate the event + } // allow spy mode changes even during the demo if (gamestate == GS_LEVEL && ev->type == ev_keydown diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 35f977bd6..2e6ff3600 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -78,6 +78,7 @@ patch_t *frameslash; // framerate stuff. Used in screen.c static player_t *plr; boolean chat_on; // entering a chat message? +boolean hu_keystrokes; // :) static char w_chat[HU_MAXMSGLEN]; static size_t c_input = 0; // let's try to make the chat input less shitty. static boolean headsupactive = false; @@ -879,6 +880,8 @@ void HU_Ticker(void) hu_showscores = !chat_on; else hu_showscores = false; + + hu_keystrokes = false; } #ifndef NONET diff --git a/src/hu_stuff.h b/src/hu_stuff.h index afbbe7b73..6a425926b 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -94,6 +94,9 @@ void HU_AddChatText(const char *text, boolean playsound); // set true when entering a chat message extern boolean chat_on; +// keystrokes in the console or chat window +extern boolean hu_keystrokes; + extern patch_t *pinggfx[5]; extern patch_t *framecounter; extern patch_t *frameslash; diff --git a/src/k_hud.c b/src/k_hud.c index 87cda81cc..2e635581d 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -133,6 +133,9 @@ static patch_t *kp_check[6]; static patch_t *kp_rival[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_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 sprintf(buffer, "K_EGGNx"); 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); } +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) { const INT32 clr = skincolors[p->skincolor].chatcolor; @@ -2840,6 +2884,7 @@ static void K_drawKartNameTags(void) if (K_ShowPlayerNametag(ntplayer) == true) { K_DrawNameTagForPlayer(result.x, result.y, ntplayer, cnum); + K_DrawTypingNotifier(result.x, result.y, ntplayer); } } } diff --git a/src/p_user.c b/src/p_user.c index e4785b249..6577b3eae 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4588,6 +4588,37 @@ void P_PlayerThink(player_t *player) 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; K_KartPlayerThink(player, cmd); // SRB2kart From 196d310052bc312f17a3fb4b979ca6209ba6aeff Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 16 Feb 2021 10:48:24 -0800 Subject: [PATCH 2/7] Sacrifice fun for readability :( --- src/d_player.h | 4 ++-- src/k_hud.c | 24 +++++------------------- src/p_user.c | 18 ++++++++++++++++-- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 5ed5af013..f2883eaa2 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -697,8 +697,8 @@ typedef struct player_s tic_t jointime; // Timer when player joins game to change skin/color 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 + UINT8 typing_timer; // Counts down while keystrokes are not emitted + UINT8 typing_duration; // How long since resumed timer #ifdef HWRENDER fixed_t fovadd; // adjust FOV for hw rendering diff --git a/src/k_hud.c b/src/k_hud.c index 2e635581d..53859fe62 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2605,20 +2605,15 @@ static void K_DrawRivalTagForPlayer(fixed_t x, fixed_t y) 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) +static void 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) +static void K_DrawTypingNotifier(fixed_t x, fixed_t y, player_t *p) { if (p->cmd.flags & TICCMD_TYPING) { @@ -2627,18 +2622,9 @@ static boolean K_DrawTypingNotifier(fixed_t x, fixed_t y, player_t *p) 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; + 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); } } diff --git a/src/p_user.c b/src/p_user.c index 6577b3eae..82c1da681 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4590,6 +4590,12 @@ void P_PlayerThink(player_t *player) if (cmd->flags & TICCMD_TYPING) { + /* + typing_duration is slow to start and slow to stop. + + typing_timer counts down a grace period before the player is not + actually considered typing anymore. + */ if (cmd->flags & TICCMD_KEYSTROKE) { player->typing_timer = 15; @@ -4599,18 +4605,26 @@ void P_PlayerThink(player_t *player) player->typing_timer--; } + /* if we are in the grace period (including currently typing) */ if (player->typing_timer + player->typing_duration > 0) { - /* lag a little bit so we always get more than just a singular dot */ + /* + If one dot was already displayed, let the duration continue to + display two dots for a bit, before actually resetting. + */ if (player->typing_timer == 0 && (player->typing_duration < 16 || player->typing_duration > 39)) { player->typing_duration = 0; } - else + else if (player->typing_duration < 63) { player->typing_duration++; } + else + { + player->typing_duration = 0; + } } } else From 8f9d9d783be815ab517b7ab2a6818e44c28cb57f Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 16 Feb 2021 10:59:36 -0800 Subject: [PATCH 3/7] Adjust dot timing to look a bit nicer * The cycle always ends on two dots. * The second dot gets drawn slightly sooner after a wrap. --- src/p_user.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 82c1da681..d69fd2304 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4608,12 +4608,9 @@ void P_PlayerThink(player_t *player) /* if we are in the grace period (including currently typing) */ if (player->typing_timer + player->typing_duration > 0) { - /* - If one dot was already displayed, let the duration continue to - display two dots for a bit, before actually resetting. - */ + /* always end the cycle on two dots */ if (player->typing_timer == 0 && - (player->typing_duration < 16 || player->typing_duration > 39)) + (player->typing_duration < 16 || player->typing_duration == 40)) { player->typing_duration = 0; } @@ -4623,7 +4620,8 @@ void P_PlayerThink(player_t *player) } else { - player->typing_duration = 0; + /* spend slightly less time on the first dot after wrapping */ + player->typing_duration = 20; } } } From 46e4d5c8eed56db3185d70bdb7141f1892ce2571 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 16 Feb 2021 11:03:19 -0800 Subject: [PATCH 4/7] Add typing_timer and typing_duration to netsave --- src/p_saveg.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/p_saveg.c b/src/p_saveg.c index e24e3d2f7..dc3523759 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -277,6 +277,9 @@ static void P_NetArchivePlayers(void) WRITESINT8(save_p, players[i].glanceDir); + WRITEUINT8(save_p, players[i].typing_timer); + WRITEUINT8(save_p, players[i].typing_duration); + // respawnvars_t WRITEUINT8(save_p, players[i].respawn.state); WRITEUINT32(save_p, K_GetWaypointHeapIndex(players[i].respawn.wp)); @@ -483,6 +486,9 @@ static void P_NetUnArchivePlayers(void) players[i].glanceDir = READSINT8(save_p); + players[i].typing_timer = READUINT8(save_p); + players[i].typing_duration = READUINT8(save_p); + // respawnvars_t players[i].respawn.state = READUINT8(save_p); players[i].respawn.wp = (waypoint_t *)(size_t)READUINT32(save_p); From 34744b03b16af1ae984cccb705ebc4480bf0e6a2 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 16 Feb 2021 12:08:47 -0800 Subject: [PATCH 5/7] Nevermind the part about making the first dot end sooner, might be a bird moment --- src/p_user.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index d69fd2304..0cb2eac29 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4620,8 +4620,7 @@ void P_PlayerThink(player_t *player) } else { - /* spend slightly less time on the first dot after wrapping */ - player->typing_duration = 20; + player->typing_duration = 16; } } } From 62ca6218271cb9e669ae089b2c160516c12a68b0 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 16 Feb 2021 13:03:36 -0800 Subject: [PATCH 6/7] Handle typing dot y offset in lump One less thing to do in the code. --- src/k_hud.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 53859fe62..843f0e2a3 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2619,8 +2619,6 @@ static void K_DrawTypingNotifier(fixed_t x, fixed_t y, player_t *p) { 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 */ K_DrawTypingDot(x + 3*FRACUNIT, y, 15, p); K_DrawTypingDot(x + 6*FRACUNIT - FRACUNIT/3, y, 31, p); From a3c72c0158448000bb56c34ddcb4d79cf04ea5e0 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 16 Feb 2021 14:50:00 -0800 Subject: [PATCH 7/7] Speed up the cycle if typing quickly --- src/p_user.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/p_user.c b/src/p_user.c index 0cb2eac29..2312279e4 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4598,6 +4598,22 @@ void P_PlayerThink(player_t *player) */ if (cmd->flags & TICCMD_KEYSTROKE) { + /* speed up if we are typing quickly! */ + if (player->typing_duration > 0 && player->typing_timer > 12) + { + if (player->typing_duration < 16) + { + player->typing_duration = 24; + } + else + { + /* slows down a tiny bit as it approaches the next dot */ + const UINT8 step = (((player->typing_duration + 15) & ~15) - + player->typing_duration) / 2; + player->typing_duration += max(step, 4); + } + } + player->typing_timer = 15; } else if (player->typing_timer > 0)