From af6340741eb0054ed084cfe3786c197ca05e3211 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 27 Dec 2023 01:52:38 -0500 Subject: [PATCH 1/2] Add speed to gametype Set a specific gamespeed per gametype. KARTSPEED_AUTO for it to be decided by game settings. Wanted this for a while, but also it makes game speed display logic for DRP very straightforward. --- src/deh_soc.c | 25 +++++++++++++++++++++++++ src/doomstat.h | 1 + src/g_game.c | 5 +++++ src/hu_stuff.c | 2 +- src/lua_baselib.c | 10 ++++++++++ src/p_setup.cpp | 22 +++++++++++++--------- 6 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 047a396af..e5864f88f 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -784,6 +784,7 @@ void readgametype(MYFILE *f, char *gtname) INT32 newgtpointlimit = 0; INT32 newgttimelimit = 0; UINT8 newgtinttype = 0; + SINT8 newgtspeed = KARTSPEED_AUTO; // KARTSPEED_EASY char gtconst[MAXLINELEN]; char gppic[9]; char gppicmini[9]; @@ -850,6 +851,29 @@ void readgametype(MYFILE *f, char *gtname) // Case sensitive newgtinttype = (int)get_number(word2lwr); } + else if (fastcmp(word, "GAMESPEED")) + { + if (fasticmp(word2, "EASY")) + { + newgtspeed = KARTSPEED_EASY; + } + else if (fasticmp(word2, "NORMAL")) + { + newgtspeed = KARTSPEED_NORMAL; + } + else if (fasticmp(word2, "HARD")) + { + newgtspeed = KARTSPEED_HARD; + } + else if (fasticmp(word2, "ANY")) + { + newgtspeed = KARTSPEED_AUTO; + } + else + { + deh_warning("readgametype %s: unknown gamespeed name %s\n", gtname, word2); + } + } // Type of level else if (fastcmp(word, "TYPEOFLEVEL")) { @@ -942,6 +966,7 @@ void readgametype(MYFILE *f, char *gtname) newgametype->intermission = newgtinttype; newgametype->pointlimit = newgtpointlimit; newgametype->timelimit = newgttimelimit; + newgametype->speed = newgtspeed; gametypes[numgametypes++] = newgametype; diff --git a/src/doomstat.h b/src/doomstat.h index 011d21c78..2ce04ea0f 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -624,6 +624,7 @@ struct gametype_t UINT32 rules; UINT32 tol; UINT8 intermission; + SINT8 speed; INT32 pointlimit; INT32 timelimit; char gppic[9]; diff --git a/src/g_game.c b/src/g_game.c index 73edf9909..03e286d80 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3181,6 +3181,7 @@ static gametype_t defaultgametypes[] = GTR_CIRCUIT|GTR_BOTS|GTR_ENCORE, TOL_RACE, int_time, + KARTSPEED_AUTO, 0, 0, "", @@ -3194,6 +3195,7 @@ static gametype_t defaultgametypes[] = GTR_SPHERES|GTR_BUMPERS|GTR_PAPERITEMS|GTR_POWERSTONES|GTR_KARMA|GTR_ITEMARROWS|GTR_PRISONS|GTR_BATTLESTARTS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_CLOSERPLAYERS, TOL_BATTLE, int_scoreortimeattack, + KARTSPEED_EASY, 0, 3, "TT_RNDB", @@ -3207,6 +3209,7 @@ static gametype_t defaultgametypes[] = GTR_CATCHER|GTR_SPECIALSTART|GTR_ROLLINGSTART|GTR_CIRCUIT|GTR_NOPOSITION, TOL_SPECIAL, int_time, + KARTSPEED_AUTO, 0, 0, "TT_RNDSS", @@ -3220,6 +3223,7 @@ static gametype_t defaultgametypes[] = GTR_BOSS|GTR_SPHERES|GTR_BUMPERS|GTR_POINTLIMIT|GTR_CLOSERPLAYERS|GTR_NOCUPSELECT|GTR_ENCORE, TOL_VERSUS, int_scoreortimeattack, + KARTSPEED_EASY, 0, 0, "", @@ -3233,6 +3237,7 @@ static gametype_t defaultgametypes[] = GTR_CHECKPOINTS|GTR_NOMP|GTR_NOCUPSELECT|GTR_NOPOSITION, TOL_TUTORIAL, int_none, + KARTSPEED_EASY, 0, 0, "", diff --git a/src/hu_stuff.c b/src/hu_stuff.c index dad44cbcd..a013ddc19 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2516,7 +2516,7 @@ static void HU_DrawRankings(void) V_DrawCenteredString(256, 8, 0, "POINT LIMIT"); V_DrawCenteredString(256, 16, hilicol, va("%d", g_pointlimit)); } - else if (gametyperules & GTR_CIRCUIT) + else if (gametypes[gametype]->speed == KARTSPEED_AUTO) { V_DrawCenteredString(256, 8, 0, "GAME SPEED"); V_DrawCenteredString(256, 16, hilicol, (cv_4thgear.value) ? va("4th Gear") : kartspeed_cons_t[1+gamespeed].strvalue); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 8eb4b406b..60916c580 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2567,6 +2567,7 @@ static int lib_gAddGametype(lua_State *L) INT32 newgtpointlimit = 0; INT32 newgttimelimit = 0; UINT8 newgtinttype = 0; + SINT8 newgtspeed = KARTSPEED_AUTO; INT16 j; luaL_checktype(L, 1, LUA_TTABLE); @@ -2632,6 +2633,14 @@ static int lib_gAddGametype(lua_State *L) if (!lua_isstring(L, 3)) TYPEERROR("gppicmini", LUA_TSTRING) gppicmini = lua_tostring(L, 3); + } else if (i == 10 || (k && fasticmp(k, "speed"))) { + if (!lua_isnumber(L, 3)) + TYPEERROR("speed", LUA_TNUMBER) + newgtspeed = (UINT32)lua_tointeger(L, 3); + if (newgtspeed < KARTSPEED_AUTO || newgtspeed > KARTSPEED_HARD) + { + newgtspeed = KARTSPEED_AUTO; + } } lua_pop(L, 1); } @@ -2672,6 +2681,7 @@ static int lib_gAddGametype(lua_State *L) newgametype->intermission = newgtinttype; newgametype->pointlimit = newgtpointlimit; newgametype->timelimit = newgttimelimit; + newgametype->speed = newgtspeed; if (gppic != NULL) { diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 5e472be84..97956f579 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -7673,7 +7673,8 @@ static void P_InitLevelSettings(void) g_exit.retry = false; // Gamespeed and frantic items - gamespeed = KARTSPEED_EASY; + const boolean multi_speed = (gametypes[gametype]->speed == KARTSPEED_AUTO); + gamespeed = multi_speed ? KARTSPEED_EASY : gametypes[gametype]->speed; franticitems = false; if (K_PodiumSequence() == true) @@ -7688,7 +7689,7 @@ static void P_InitLevelSettings(void) } else if (grandprixinfo.gp == true) { - if (gametyperules & GTR_CIRCUIT) + if (multi_speed) { gamespeed = grandprixinfo.gamespeed; } @@ -7698,18 +7699,21 @@ static void P_InitLevelSettings(void) || tutorialchallenge == TUTORIALSKIP_INPROGRESS ) { - if ((gametyperules & GTR_CATCHER) && encoremode == false) + if (multi_speed) { - gamespeed = KARTSPEED_NORMAL; - } - else if (gametyperules & GTR_CIRCUIT) - { - gamespeed = KARTSPEED_HARD; + if ((gametyperules & GTR_CATCHER) && encoremode == false) + { + gamespeed = KARTSPEED_NORMAL; + } + else + { + gamespeed = KARTSPEED_HARD; + } } } else { - if (gametyperules & GTR_CIRCUIT) + if (multi_speed) { if (cv_kartspeed.value == KARTSPEED_AUTO) gamespeed = ((speedscramble == -1) ? KARTSPEED_NORMAL : (UINT8)speedscramble); From d41ca3711a335e581c42afebe98082e41252ae0c Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 27 Dec 2023 22:46:29 -0500 Subject: [PATCH 2/2] Update Discord RP for Ring Racers --- src/d_netcmd.c | 5 - src/deh_soc.c | 1 + src/discord.c | 602 +++++++++++++++++++------ src/discord.h | 14 + src/menus/transient/discord-requests.c | 4 +- src/r_skins.c | 13 + 6 files changed, 483 insertions(+), 156 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 071142470..c93115091 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1242,11 +1242,6 @@ static void Got_NameAndColor(const UINT8 **cp, INT32 playernum) // set follower K_SetFollowerByNum(playernum, follower); - -#ifdef HAVE_DISCORDRPC - if (playernum == consoleplayer) - DRPC_UpdatePresence(); -#endif } enum { diff --git a/src/deh_soc.c b/src/deh_soc.c index e5864f88f..930746a12 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -52,6 +52,7 @@ #include "filesrch.h" // refreshdirmenu #include "k_follower.h" #include "doomstat.h" // MAXMUSNAMES +#include "discord.h" // Loops through every constant and operation in word and performs its calculations, returning the final value. fixed_t get_number(const char *word) diff --git a/src/discord.c b/src/discord.c index 12d2998cc..a4ca79fba 100644 --- a/src/discord.c +++ b/src/discord.c @@ -28,6 +28,9 @@ #include "byteptr.h" #include "stun.h" #include "i_tcp.h" // current_port +#include "k_grandprix.h" +#include "k_battle.h" +#include "m_cond.h" // M_GameTrulyStarted #include "discord.h" #include "doomdef.h" @@ -35,6 +38,10 @@ // Feel free to provide your own, if you care enough to create another Discord app for this :P #define DISCORD_APPID "977470696852684833" +#ifdef DEVELOP +#define DISCORD_SECRETIVE +#endif + // length of IP strings #define IP_SIZE 21 @@ -42,8 +49,31 @@ struct discordInfo_s discordInfo; discordRequest_t *discordRequestList = NULL; +size_t g_discord_skins = 0; + static char self_ip[IP_SIZE]; +/*-------------------------------------------------- + const char *DRPC_HideUsername(const char *input) + + See header file for description. +--------------------------------------------------*/ +const char *DRPC_HideUsername(const char *input) +{ + static char buffer[5]; + int i; + + buffer[0] = input[0]; + + for (i = 1; i < 4; ++i) + { + buffer[i] = '.'; + } + + buffer[4] = '\0'; + return buffer; +} + /*-------------------------------------------------- static char *DRPC_XORIPString(const char *input) @@ -94,11 +124,11 @@ static void DRPC_HandleReady(const DiscordUser *user) { if (cv_discordstreamer.value) { - CONS_Printf("Discord: connected to %s\n", user->username); + CONS_Printf("Discord: connected to %s\n", DRPC_HideUsername(user->username)); } else { - CONS_Printf("Discord: connected to %s#%s (%s)\n", user->username, user->discriminator, user->userId); + CONS_Printf("Discord: connected to %s (%s)\n", user->username, user->userId); } } @@ -234,8 +264,10 @@ static void DRPC_HandleJoinRequest(const DiscordUser *requestUser) newRequest->username = Z_Calloc(344, PU_STATIC, NULL); snprintf(newRequest->username, 344, "%s", requestUser->username); +#if 0 newRequest->discriminator = Z_Calloc(8, PU_STATIC, NULL); snprintf(newRequest->discriminator, 8, "%s", requestUser->discriminator); +#endif newRequest->userID = Z_Calloc(32, PU_STATIC, NULL); snprintf(newRequest->userID, 32, "%s", requestUser->userId); @@ -301,7 +333,9 @@ void DRPC_RemoveRequest(discordRequest_t *removeRequest) } Z_Free(removeRequest->username); +#if 0 Z_Free(removeRequest->discriminator); +#endif Z_Free(removeRequest->userID); Z_Free(removeRequest); } @@ -394,6 +428,68 @@ static void DRPC_EmptyRequests(void) } } +#ifndef DISCORD_SECRETIVE +/*-------------------------------------------------- + static boolean DRPC_DisplayGonerSetup(void) + + Returns true if we're in the initial + tutorial game state. +--------------------------------------------------*/ +static boolean DRPC_DisplayGonerSetup(void) +{ + if (M_GameTrulyStarted()) + { + // We're past all that tutorial stuff. + return false; + } + + if (Playing()) + { + // Need to check a bunch of stuff manually, + // since with command line and/or console you + // can play a bit of the game without fully + // fully starting the game. + + if (netgame) + { + // We smuggled into a netgame early, + // show the netgame's info. + return false; + } + + if (tutorialchallenge == TUTORIALSKIP_INPROGRESS) + { + // Attempting the Dirty Bubble Challenge + return true; + } + + // If it's not GT_TUTORIAL, it's directly + // command line into a specific map. + return (gametype == GT_TUTORIAL); + } + + // If we're in a menu, and the game hasn't started, + // then we're definitely in goner setup. + return true; +} +#endif + +enum { + DISCORD_GS_UNKNOWN, + DISCORD_GS_CUSTOM, + DISCORD_GS_RACE, + DISCORD_GS_BATTLE, + DISCORD_GS_TUTORIAL, + DISCORD_GS_TIMEATTACK, + DISCORD_GS_GRANDPRIX, + DISCORD_GS_VOTING, + DISCORD_GS_MENU, + DISCORD_GS_REPLAY, + DISCORD_GS_TITLE, + DISCORD_GS_CREDITS, + DISCORD_GS_GONER +}; + /*-------------------------------------------------- void DRPC_UpdatePresence(void) @@ -401,17 +497,6 @@ static void DRPC_EmptyRequests(void) --------------------------------------------------*/ void DRPC_UpdatePresence(void) { -#ifdef USEMAPIMG - char mapimg[8+1]; -#endif -#ifndef DEVELOP - char detailstr[48+1]; - char mapname[5+21+21+2+1]; - - char charimg[4+SKINNAMESIZE+1]; - char charname[11+SKINNAMESIZE+1]; -#endif - boolean joinSecretSet = false; char *clientJoinSecret = NULL; @@ -432,14 +517,12 @@ void DRPC_UpdatePresence(void) return; } -#ifdef DEVELOP +#ifdef DISCORD_SECRETIVE // This way, we can use the invite feature in-dev, but not have snoopers seeing any potential secrets! :P - discordPresence.largeImageKey = "miscdevelop"; + discordPresence.largeImageKey = "misc_develop"; discordPresence.largeImageText = "No peeking!"; discordPresence.state = "Development EXE"; -#endif // DEVELOP - // Server info if (netgame) { if (DRPC_InvitesAreAllowed() == true) @@ -459,7 +542,170 @@ void DRPC_UpdatePresence(void) } } -#ifndef DEVELOP + discordPresence.partyId = server_context; // Thanks, whoever gave us Mumble support, for implementing the EXACT thing Discord wanted for this field! + discordPresence.partySize = D_NumPlayers(); // Players in server + discordPresence.partyMax = discordInfo.maxPlayers; // Max players + } + else + { + // Reset discord info if you're not in a place that uses it! + // Important for if you join a server that compiled without HAVE_DISCORDRPC, + // so that you don't ever end up using bad information from another server. + memset(&discordInfo, 0, sizeof(discordInfo)); + } + +#else + + char detailstr[128]; + char localstr[128]; + + char charimg[32]; + char charname[128]; + + char gtname[128]; + + UINT8 gs = DISCORD_GS_UNKNOWN; + if (DRPC_DisplayGonerSetup()) + { + gs = DISCORD_GS_GONER; + } + else if (demo.playback) + { + switch (demo.attract) + { + case DEMO_ATTRACT_TITLE: + { + gs = DISCORD_GS_TITLE; + break; + } + case DEMO_ATTRACT_CREDITS: + { + gs = DISCORD_GS_CREDITS; + break; + } + default: + { + gs = DISCORD_GS_REPLAY; + break; + } + } + } + else + { + switch (gamestate) + { + case GS_LEVEL: + case GS_INTERMISSION: + { + if (grandprixinfo.gp == true) + { + gs = DISCORD_GS_GRANDPRIX; + } + else if (modeattacking) + { + gs = DISCORD_GS_TIMEATTACK; + } + else if (gametype >= GT_FIRSTFREESLOT) + { + gs = DISCORD_GS_CUSTOM; + } + else + { + switch (gametype) + { + case GT_RACE: + { + gs = DISCORD_GS_RACE; + break; + } + case GT_BATTLE: + { + gs = DISCORD_GS_BATTLE; + break; + } + case GT_TUTORIAL: + { + gs = DISCORD_GS_TUTORIAL; + break; + } + case GT_SPECIAL: + case GT_VERSUS: + { + // You're using command line. + // Just patch over this for now. + gs = DISCORD_GS_GRANDPRIX; + break; + } + default: + { + break; // leave as UNKNOWN... + } + } + } + break; + } + case GS_CEREMONY: + { + gs = DISCORD_GS_GRANDPRIX; + break; + } + case GS_VOTING: + { + gs = DISCORD_GS_VOTING; + break; + } + case GS_TITLESCREEN: + { + gs = DISCORD_GS_TITLE; + break; + } + case GS_CREDITS: + { + gs = DISCORD_GS_CREDITS; + break; + } + default: + { + gs = DISCORD_GS_MENU; + break; + } + } + } + + // Server info + if (gs == DISCORD_GS_GONER) + { + if (Playing()) + { + discordPresence.state = "TRAINING DATA"; + } + else if (gamedata->gonerlevel >= GDGONER_OUTRO) + { + discordPresence.state = "EVALUATION"; + } + else + { + discordPresence.state = "MISSING DATA"; + } + } + else if (netgame) + { + if (DRPC_InvitesAreAllowed() == true) + { + const char *join; + + // Grab the host's IP for joining. + if ((join = DRPC_GetServerIP()) != NULL) + { + discordPresence.joinSecret = DRPC_XORIPString(join); + joinSecretSet = true; + } + else + { + return; + } + } + if (cv_advertise.value) { discordPresence.state = "Public"; @@ -468,7 +714,6 @@ void DRPC_UpdatePresence(void) { discordPresence.state = "Private"; } -#endif // DEVELOP discordPresence.partyId = server_context; // Thanks, whoever gave us Mumble support, for implementing the EXACT thing Discord wanted for this field! discordPresence.partySize = D_NumPlayers(); // Players in server @@ -481,71 +726,115 @@ void DRPC_UpdatePresence(void) // so that you don't ever end up using bad information from another server. memset(&discordInfo, 0, sizeof(discordInfo)); -#ifndef DEVELOP - // Offline info if (Playing()) - discordPresence.state = "Offline"; - else if (demo.playback && !demo.attract) - discordPresence.state = "Watching Replay"; - else - discordPresence.state = "Menu"; -#endif // DEVELOP - } - -#ifndef DEVELOP - // Gametype info - if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_VOTING) && Playing()) - { - if (modeattacking) - discordPresence.details = "Time Attack"; + { + snprintf(localstr, 128, "Local (%dP)", splitscreen + 1); + discordPresence.state = localstr; + } else { - snprintf(detailstr, 48, "%s%s%s", - gametypes[gametype]->name, - (gametyperules & GTR_CIRCUIT) ? va(" | %s", kartspeed_cons_t[gamespeed].strvalue) : "", - (encoremode == true) ? " | Encore" : "" - ); - discordPresence.details = detailstr; + switch (gs) + { + case DISCORD_GS_REPLAY: + { + discordPresence.state = "Watching Replay"; + break; + } + case DISCORD_GS_TITLE: + { + discordPresence.state = "Title Screen"; + break; + } + case DISCORD_GS_CREDITS: + { + discordPresence.state = "Watching Credits"; + break; + } + default: + { + discordPresence.state = "Menu"; + break; + } + } } } - if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) // Map info - && !(demo.playback && demo.attract)) + if (gs == DISCORD_GS_GONER) { -#ifdef USEMAPIMG - if ((gamemap >= 1 && gamemap <= 60) // supported race maps - || (gamemap >= 136 && gamemap <= 164)) // supported battle maps - { - //FIXME - //snprintf(mapimg, 8, "%s", G_BuildMapName(gamemap)); - strlwr(mapimg); - discordPresence.largeImageKey = mapimg; // Map image - } - else -#endif - if (mapheaderinfo[gamemap-1]->menuflags & LF2_HIDEINMENU) - { - // Hell map, use the method that got you here :P - discordPresence.largeImageKey = "miscdice"; - } - else - { - // This is probably a custom map! - discordPresence.largeImageKey = "mapcustom"; - } + // Gametype info + discordPresence.details = "Setup"; - if (mapheaderinfo[gamemap-1]->menuflags & LF2_HIDEINMENU) + discordPresence.largeImageKey = "gs_goner"; + discordPresence.largeImageText = "NO SIGNAL"; + } + else + { + // Gametype info + if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_VOTING || gamestate == GS_CEREMONY) && Playing()) { - // Hell map, hide the name - discordPresence.largeImageText = "Map: ???"; - } - else - { - // Map name on tool tip - char *title = G_BuildMapTitle(gamemap); - snprintf(mapname, 48, "Map: %s", title); - Z_Free(title); - discordPresence.largeImageText = mapname; + if (grandprixinfo.gp) + { + char roundstr[32]; + + if (gamestate == GS_CEREMONY) + { + snprintf(roundstr, 32, " | Ceremony"); + } + else + { + switch (grandprixinfo.eventmode) + { + case GPEVENT_BONUS: + { + snprintf(roundstr, 32, " | Bonus"); + break; + } + case GPEVENT_SPECIAL: + { + snprintf(roundstr, 32, " | Special"); + break; + } + case GPEVENT_NONE: + { + if (roundqueue.position > 0 && roundqueue.position <= roundqueue.size) + { + snprintf(roundstr, 32, " | Round %d", roundqueue.position); + } + break; + } + } + } + + snprintf(detailstr, 128, "Grand Prix%s | %s", + roundstr, + grandprixinfo.masterbots ? "Master" : kartspeed_cons_t[grandprixinfo.gamespeed + 1].strvalue + ); + discordPresence.details = detailstr; + } + else if (battleprisons == true) + { + discordPresence.details = "Prison Break"; + } + else if (modeattacking) + { + if (modeattacking & ATTACKING_SPB) + { + discordPresence.details = "SPB Attack"; + } + else + { + discordPresence.details = "Time Attack"; + } + } + else + { + snprintf(detailstr, 128, "%s%s%s", + gametypes[gametype]->name, + (gametypes[gametype]->speed == KARTSPEED_AUTO) ? va(" | %s", kartspeed_cons_t[gamespeed + 1].strvalue) : "", + (encoremode == true) ? " | Encore" : "" + ); + discordPresence.details = detailstr; + } } if (gamestate == GS_LEVEL && Playing()) @@ -561,90 +850,105 @@ void DRPC_UpdatePresence(void) discordPresence.endTimestamp = mapTimeEnd; } } - } - else if (gamestate == GS_VOTING) - { - discordPresence.largeImageKey = ((gametype == GT_BATTLE) ? "miscredplanet" : "miscblueplanet"); - discordPresence.largeImageText = "Voting"; - } - else - { - discordPresence.largeImageKey = "misctitle"; - discordPresence.largeImageText = "Title Screen"; - } - // Character info - if (Playing() && playeringame[consoleplayer] && !players[consoleplayer].spectator) - { - // Supported skin names - static const char *supportedSkins[] = { - // base game - "sonic", - "tails", - "knuckles", - "eggman", - "metalsonic", - // bonus chars - "flicky", - "motobug", - "amy", - "mighty", - "ray", - "espio", - "vector", - "chao", - "gamma", - "chaos", - "shadow", - "rouge", - "herochao", - "darkchao", - "cream", - "omega", - "blaze", - "silver", - "wonderboy", - "arle", - "nights", - "sakura", - "ulala", - "beat", - "vyse", - "aiai", - "kiryu", - "aigis", - "miku", - "doom", - NULL - }; - - boolean customChar = true; - UINT8 checkSkin = 0; - - // Character image - while (supportedSkins[checkSkin] != NULL) + // Gametype image + switch (gs) { - if (!strcmp(skins[players[consoleplayer].skin].name, supportedSkins[checkSkin])) + case DISCORD_GS_CUSTOM: { - snprintf(charimg, 21, "char%s", supportedSkins[checkSkin]); - discordPresence.smallImageKey = charimg; - customChar = false; + discordPresence.largeImageKey = "custom_gs"; + snprintf(gtname, 128, "%s", gametypes[gametype]->name); + discordPresence.largeImageText = gtname; + break; + } + case DISCORD_GS_RACE: + { + discordPresence.largeImageKey = "gs_race"; + discordPresence.largeImageText = "Race"; + break; + } + case DISCORD_GS_BATTLE: + { + discordPresence.largeImageKey = "gs_battle"; + discordPresence.largeImageText = "Battle"; + break; + } + case DISCORD_GS_TUTORIAL: + { + discordPresence.largeImageKey = "gs_tutorial"; + discordPresence.largeImageText = "Tutorial"; + break; + } + case DISCORD_GS_TIMEATTACK: + { + discordPresence.largeImageKey = "gs_timeattack"; + discordPresence.largeImageText = "Time Attack"; + break; + } + case DISCORD_GS_GRANDPRIX: + { + discordPresence.largeImageKey = "gs_grandprix"; + discordPresence.largeImageText = "Grand Prix"; + break; + } + case DISCORD_GS_VOTING: + { + discordPresence.largeImageKey = "gs_voting"; + discordPresence.largeImageText = "Voting"; + break; + } + case DISCORD_GS_MENU: + { + discordPresence.largeImageKey = "gs_menu"; + discordPresence.largeImageText = "Menu"; + break; + } + case DISCORD_GS_REPLAY: + { + discordPresence.largeImageKey = "gs_replay"; + discordPresence.largeImageText = "Watching Replay"; + break; + } + case DISCORD_GS_TITLE: + { + discordPresence.largeImageKey = "gs_title"; + discordPresence.largeImageText = "Title Screen"; + break; + } + case DISCORD_GS_CREDITS: + { + discordPresence.largeImageKey = "gs_credits"; + discordPresence.largeImageText = "Credits"; + break; + } + default: + { + discordPresence.largeImageKey = "misc_develop"; + discordPresence.largeImageText = "Invalid DRPC state?"; break; } - - checkSkin++; } - if (customChar == true) + // Character info + if (Playing() && playeringame[consoleplayer] && !players[consoleplayer].spectator) { - // Use the custom character icon! - discordPresence.smallImageKey = "charcustom"; - } + // Character image + if ((unsigned)players[consoleplayer].skin < g_discord_skins) // Supported skins + { + snprintf(charimg, 32, "char_%s", skins[ players[consoleplayer].skin ].name); + discordPresence.smallImageKey = charimg; + } + else + { + // Use the custom character icon! + discordPresence.smallImageKey = "custom_char"; + } - snprintf(charname, 28, "Character: %s", skins[players[consoleplayer].skin].realname); - discordPresence.smallImageText = charname; // Character name + snprintf(charname, 128, "Character: %s", skins[players[consoleplayer].skin].realname); + discordPresence.smallImageText = charname; // Character name + } } -#endif // DEVELOP +#endif // DISCORD_SECRETIVE if (joinSecretSet == false) { diff --git a/src/discord.h b/src/discord.h index 587be6a42..7613a665b 100644 --- a/src/discord.h +++ b/src/discord.h @@ -33,7 +33,9 @@ extern struct discordInfo_s { struct discordRequest_t { char *username; // Discord user name. +#if 0 // Good night, sweet prince... char *discriminator; // Discord discriminator (The little hashtag thing after the username). Separated for a "hide discriminators" cvar. +#endif char *userID; // The ID of the Discord user, gets used with Discord_Respond() // HAHAHA, no. @@ -48,6 +50,18 @@ struct discordRequest_t { extern discordRequest_t *discordRequestList; +extern size_t g_discord_skins; + +/*-------------------------------------------------- + const char *DRPC_HideUsername(const char *input); + + Handle usernames while cv_discordstreamer is activated. + (The loss of discriminators is still a dumbass regression + that I will never forgive the Discord developers for.) +--------------------------------------------------*/ + +const char *DRPC_HideUsername(const char *input); + /*-------------------------------------------------- void DRPC_RemoveRequest(void); diff --git a/src/menus/transient/discord-requests.c b/src/menus/transient/discord-requests.c index 19a54c097..6848b746e 100644 --- a/src/menus/transient/discord-requests.c +++ b/src/menus/transient/discord-requests.c @@ -107,9 +107,9 @@ const char *M_GetDiscordName(discordRequest_t *r) return ""; if (cv_discordstreamer.value) - return r->username; + return DRPC_HideUsername(r->username); - return va("%s#%s", r->username, r->discriminator); + return r->username; } #endif // HAVE_DISCORDRPC diff --git a/src/r_skins.c b/src/r_skins.c index 7ae373015..528c891ab 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -35,6 +35,7 @@ #include "k_kart.h" // K_KartResetPlayerColor #endif #include "k_grandprix.h" // K_CanChangeRules +#include "discord.h" #ifdef HWRENDER #include "hardware/hw_md2.h" #endif @@ -184,6 +185,13 @@ void R_InitSkins(void) R_AddSkins((UINT16)i, true); R_PatchSkins((UINT16)i, true); R_LoadSpriteInfoLumps(i, wadfiles[i]->numlumps); + +#ifdef HAVE_DISCORDRPC + if (i == mainwads) + { + g_discord_skins = numskins; + } +#endif } ST_ReloadSkinFaceGraphics(); M_UpdateConditionSetsPending(); @@ -430,6 +438,11 @@ static void SetSkin(player_t *player, INT32 skinnum) // for replays: We have changed our skin mid-game; let the game know so it can do the same in the replay! demo_extradata[(player-players)] |= DXD_SKIN; + +#ifdef HAVE_DISCORDRPC + if (player - players == consoleplayer) + DRPC_UpdatePresence(); +#endif } // Gets the player to the first usuable skin in the game.