Merge branch 'typing-notifier' into 'master'

Typing Indicator

See merge request KartKrew/Kart!389
This commit is contained in:
Sal 2021-02-18 18:34:00 -05:00
commit e6a0ff727c
9 changed files with 129 additions and 0 deletions

View file

@ -233,7 +233,10 @@ void D_ProcessEvents(void)
#endif
if (eaten)
{
hu_keystrokes = true;
continue; // ate the event
}
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 quittime; // Time elapsed since user disconnected, zero if connected
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
#endif

View file

@ -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)

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->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

View file

@ -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

View file

@ -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;

View file

@ -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,27 @@ static void K_DrawRivalTagForPlayer(fixed_t x, fixed_t y)
V_DrawFixedPatch(x, y, FRACUNIT, V_HUDTRANS|V_SPLITSCREEN, kp_rival[blink], NULL);
}
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);
}
}
static void 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);
/* 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);
K_DrawTypingDot(x + 9*FRACUNIT - FRACUNIT/3, y, 47, p);
}
}
static void K_DrawNameTagForPlayer(fixed_t x, fixed_t y, player_t *p, UINT8 cnum)
{
const INT32 clr = skincolors[p->skincolor].chatcolor;
@ -2840,6 +2868,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);
}
}
}

View file

@ -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);

View file

@ -4598,6 +4598,64 @@ void P_PlayerThink(player_t *player)
player->mo->drawflags &= ~MFD_DONTDRAW;
}
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)
{
/* 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)
{
player->typing_timer--;
}
/* if we are in the grace period (including currently typing) */
if (player->typing_timer + player->typing_duration > 0)
{
/* always end the cycle on two dots */
if (player->typing_timer == 0 &&
(player->typing_duration < 16 || player->typing_duration == 40))
{
player->typing_duration = 0;
}
else if (player->typing_duration < 63)
{
player->typing_duration++;
}
else
{
player->typing_duration = 16;
}
}
}
else
{
player->typing_timer = 0;
player->typing_duration = 0;
}
player->pflags &= ~PF_SLIDING;
K_KartPlayerThink(player, cmd); // SRB2kart