From 041dd73555e35a111607e9133fe451fa73a5ca2e Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 12 Dec 2021 03:51:00 -0800 Subject: [PATCH 01/63] Let players switch skin at any time (even when moving) if they are playing alone Playing in local splitscreen also counts as "alone". Actually removes the restriction of only being able to change skin when not moving altogether. It's annoying, especially if you're getting bullied in POSITION. --- src/d_netcmd.c | 24 ++++++++++++++++++++---- src/d_netcmd.h | 1 + src/m_menu.c | 8 ++++---- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 2556ab0ac..b1bf608e1 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1298,6 +1298,22 @@ UINT8 CanChangeSkin(INT32 playernum) return true; } +boolean CanChangeSkinWhilePlaying(INT32 playernum) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; ++i) + { + if (D_IsPlayerHumanAndGaming(i) && + !P_IsLocalPlayer(&players[i])) + { + return CanChangeSkin(playernum); + } + } + + return true; +} + static void ForceAllSkins(INT32 forcedskin) { INT32 i, j; @@ -5442,7 +5458,7 @@ static void Skin_OnChange(void) return; } - if (CanChangeSkin(consoleplayer) && !P_PlayerMoving(consoleplayer)) + if (CanChangeSkinWhilePlaying(consoleplayer)) SendNameAndColor(0); else { @@ -5461,7 +5477,7 @@ static void Skin2_OnChange(void) if (!Playing() || !splitscreen) return; // do whatever you want - if (CanChangeSkin(g_localplayers[1]) && !P_PlayerMoving(g_localplayers[1])) + if (CanChangeSkinWhilePlaying(g_localplayers[1])) SendNameAndColor(1); else { @@ -5475,7 +5491,7 @@ static void Skin3_OnChange(void) if (!Playing() || splitscreen < 2) return; // do whatever you want - if (CanChangeSkin(g_localplayers[2]) && !P_PlayerMoving(g_localplayers[2])) + if (CanChangeSkinWhilePlaying(g_localplayers[2])) SendNameAndColor(2); else { @@ -5489,7 +5505,7 @@ static void Skin4_OnChange(void) if (!Playing() || splitscreen < 3) return; // do whatever you want - if (CanChangeSkin(g_localplayers[3]) && !P_PlayerMoving(g_localplayers[3])) + if (CanChangeSkinWhilePlaying(g_localplayers[3])) SendNameAndColor(3); else { diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 41dc3fdf7..7354a555f 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -225,5 +225,6 @@ void D_SetPassword(const char *pw); // used for the player setup menu UINT8 CanChangeSkin(INT32 playernum); +boolean CanChangeSkinWhilePlaying(INT32 playernum); #endif diff --git a/src/m_menu.c b/src/m_menu.c index 150b64d9c..64382d156 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -9866,7 +9866,7 @@ static void M_SetupMultiPlayer(INT32 choice) break; // disable skin changes if we can't actually change skins - if (!CanChangeSkin(consoleplayer)) + if (!CanChangeSkinWhilePlaying(consoleplayer)) MP_PlayerSetupMenu[2].status = (IT_GRAYEDOUT); else MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER|IT_STRING); @@ -9909,7 +9909,7 @@ static void M_SetupMultiPlayer2(INT32 choice) break; // disable skin changes if we can't actually change skins - if (splitscreen && !CanChangeSkin(g_localplayers[1])) + if (splitscreen && !CanChangeSkinWhilePlaying(g_localplayers[1])) MP_PlayerSetupMenu[2].status = (IT_GRAYEDOUT); else MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER | IT_STRING); @@ -9952,7 +9952,7 @@ static void M_SetupMultiPlayer3(INT32 choice) break; // disable skin changes if we can't actually change skins - if (splitscreen > 1 && !CanChangeSkin(g_localplayers[2])) + if (splitscreen > 1 && !CanChangeSkinWhilePlaying(g_localplayers[2])) MP_PlayerSetupMenu[2].status = (IT_GRAYEDOUT); else MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER | IT_STRING); @@ -9995,7 +9995,7 @@ static void M_SetupMultiPlayer4(INT32 choice) break; // disable skin changes if we can't actually change skins - if (splitscreen > 2 && !CanChangeSkin(g_localplayers[3])) + if (splitscreen > 2 && !CanChangeSkinWhilePlaying(g_localplayers[3])) MP_PlayerSetupMenu[2].status = (IT_GRAYEDOUT); else MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER | IT_STRING); From 20b56544ac67e13a880bc098889bef38059e81a1 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 12 Dec 2021 03:53:17 -0800 Subject: [PATCH 02/63] Default do not let players change skin after POSITION --- src/d_netcmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index b1bf608e1..b3d7ba795 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -249,7 +249,7 @@ static consvar_t cv_fishcake = CVAR_INIT ("fishcake", "Off", CV_CALL|CV_NOSHOWHE #endif static consvar_t cv_dummyconsvar = CVAR_INIT ("dummyconsvar", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff, DummyConsvar_OnChange); -consvar_t cv_restrictskinchange = CVAR_INIT ("restrictskinchange", "No", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL); +consvar_t cv_restrictskinchange = CVAR_INIT ("restrictskinchange", "Yes", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL); consvar_t cv_allowteamchange = CVAR_INIT ("allowteamchange", "Yes", CV_NETVAR, CV_YesNo, NULL); static CV_PossibleValue_t ingamecap_cons_t[] = {{0, "MIN"}, {MAXPLAYERS-1, "MAX"}, {0, NULL}}; @@ -1289,7 +1289,7 @@ UINT8 CanChangeSkin(INT32 playernum) return true; // Not in game, so you can change - if (players[playernum].spectator || players[playernum].playerstate == PST_DEAD || players[playernum].playerstate == PST_REBORN) + if (players[playernum].spectator) return true; return false; From 638efe18c99002041f7ee9218326241e05b0f610 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 11 Jun 2022 05:17:50 -0700 Subject: [PATCH 03/63] Bail CanChangeSkinWhilePlaying if forceskin --- src/d_netcmd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index b3d7ba795..88659396a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1302,6 +1302,10 @@ boolean CanChangeSkinWhilePlaying(INT32 playernum) { INT32 i; + // Force skin in effect. + if ((cv_forceskin.value != -1)) + return false; + for (i = 0; i < MAXPLAYERS; ++i) { if (D_IsPlayerHumanAndGaming(i) && From 0e3a3b2face6d51f66169cfa2620cadc38f03744 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 2 Jan 2022 15:39:16 +0100 Subject: [PATCH 04/63] Cleanup blank chatbox checking code --- src/hu_stuff.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index f4f52f5cf..e22f6c651 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1028,25 +1028,15 @@ void HU_Ticker(void) static boolean teamtalk = false; -// Clear spaces so we don't end up with messages only made out of emptiness -static boolean HU_clearChatSpaces(void) +static boolean HU_chatboxContainsOnlySpaces(void) { - size_t i = 0; // Used to just check our message - char c; // current character we're iterating. - boolean nothingbutspaces = true; + size_t i; - for (; i < strlen(w_chat); i++) // iterate through message and eradicate all spaces that don't belong. - { - c = w_chat[i]; - if (!c) - break; // if there's nothing, it's safe to assume our message has ended, so let's not waste any more time here. + for (i = 0; w_chat[i]; i++) + if (w_chat[i] != ' ') + return false; - if (c != ' ') // Isn't a space - { - nothingbutspaces = false; - } - } - return nothingbutspaces; + return true; } // @@ -1062,8 +1052,9 @@ static void HU_queueChatChar(INT32 c) size_t ci = 2; INT32 target = 0; - if (HU_clearChatSpaces()) // Avoids being able to send empty messages, or something. - return; // If this returns true, that means our message was NOTHING but spaces, so don't send it period. + // if our message was nothing but spaces, don't send it. + if (HU_chatboxContainsOnlySpaces()) + return; do { c = w_chat[-2+ci++]; From cdb809a4340122f77400454c24d47d7fabb607b2 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 2 Jan 2022 15:41:54 +0100 Subject: [PATCH 05/63] Cleanup chatbox reset code # Conflicts: # src/hu_stuff.c --- src/hu_stuff.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index e22f6c651..7644bcb2d 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1048,7 +1048,6 @@ static void HU_queueChatChar(INT32 c) { char buf[2+256]; char *msg = &buf[2]; - size_t i; size_t ci = 2; INT32 target = 0; @@ -1061,15 +1060,8 @@ static void HU_queueChatChar(INT32 c) if (!c || (c >= ' ' && !(c & 0x80))) // copy printable characters and terminating '\0' only. buf[ci-1]=c; } while (c); - i = 0; - for (;(i Date: Sun, 2 Jan 2022 15:48:31 +0100 Subject: [PATCH 06/63] Cleanup chatbox sanitizing code --- src/hu_stuff.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 7644bcb2d..430c56a1a 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1048,18 +1048,21 @@ static void HU_queueChatChar(INT32 c) { char buf[2+256]; char *msg = &buf[2]; - size_t ci = 2; + size_t ci; INT32 target = 0; // if our message was nothing but spaces, don't send it. if (HU_chatboxContainsOnlySpaces()) return; - do { - c = w_chat[-2+ci++]; - if (!c || (c >= ' ' && !(c & 0x80))) // copy printable characters and terminating '\0' only. - buf[ci-1]=c; - } while (c); + // copy printable characters and terminating '\0' only. + for (ci = 2; w_chat[ci-2]; ci++) + { + c = w_chat[ci-2]; + if (c >= ' ' && !(c & 0x80)) + buf[ci] = c; + }; + buf[ci] = '\0'; memset(w_chat, '\0', HU_MAXMSGLEN); c_input = 0; From 2ccb2229140e2e15adb3be41f504ce35a53217d0 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 2 Jan 2022 17:08:10 +0100 Subject: [PATCH 07/63] Cleanup chat code a little # Conflicts: # src/hu_stuff.c --- src/hu_stuff.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 430c56a1a..8b024fe1c 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1039,11 +1039,8 @@ static boolean HU_chatboxContainsOnlySpaces(void) return true; } -// -// -static void HU_queueChatChar(INT32 c) +static void HU_queueChatChar(char c) { - // send automaticly the message (no more chat char) if (c == KEY_ENTER) { char buf[2+256]; @@ -1093,7 +1090,7 @@ static void HU_queueChatChar(INT32 c) strncpy(playernum, msg+3, 3); // check for undesirable characters in our "number" - if (((playernum[0] < '0') || (playernum[0] > '9')) || ((playernum[1] < '0') || (playernum[1] > '9'))) + if (!(isdigit(playernum[0]) && isdigit(playernum[1]))) { // check if playernum[1] is a space if (playernum[1] == ' ') @@ -1106,17 +1103,13 @@ static void HU_queueChatChar(INT32 c) } } // I'm very bad at C, I swear I am, additional checks eww! - if (spc != 0) + if (spc != 0 && msg[5] != ' ') { - if (msg[5] != ' ') - { - HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); - return; - } + HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); + return; } target = atoi(playernum); // turn that into a number - //CONS_Printf("%d\n", target); // check for target player, if it doesn't exist then we can't send the message! if (target < MAXPLAYERS && playeringame[target]) // player exists @@ -1133,11 +1126,7 @@ static void HU_queueChatChar(INT32 c) } if (ci > 3) // don't send target+flags+empty message. { - if (teamtalk) - buf[0] = -1; // target - else - buf[0] = target; - + buf[0] = teamtalk ? -1 : target; // target buf[1] = 0; // flags SendNetXCmd(XD_SAY, buf, 2 + strlen(&buf[2]) + 1); } From 4fc770aa7be1a45a6933b21c5ad377eb3c05f6b3 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 2 Jan 2022 17:38:49 +0100 Subject: [PATCH 08/63] Group related chat stuff together # Conflicts: # src/hu_stuff.c --- src/hu_stuff.c | 143 ++++++++++++++++++++++++------------------------- 1 file changed, 71 insertions(+), 72 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 8b024fe1c..f78bfa16b 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -845,71 +845,6 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) #endif } -// Handles key input and string input -// -static inline boolean HU_keyInChatString(char *s, char ch) -{ - size_t l; - - if ((ch >= HU_FONTSTART && ch <= HU_FONTEND && fontv[HU_FONT].font[ch-HU_FONTSTART]) - || ch == ' ') // Allow spaces, of course - { - l = strlen(s); - if (l < HU_MAXMSGLEN - 1) - { - if (c_input >= strlen(s)) // don't do anything complicated - { - s[l++] = ch; - s[l]=0; - } - else - { - // move everything past c_input for new characters: - size_t m = HU_MAXMSGLEN-1; - while (m>=c_input) - { - if (s[m]) - s[m+1] = (s[m]); - if (m == 0) // prevent overflow - break; - m--; - } - s[c_input] = ch; // and replace this. - } - c_input++; - return true; - } - return false; - } - else if (ch == KEY_BACKSPACE) - { - size_t i = c_input; - - if (c_input <= 0) - return false; - - if (!s[i-1]) - return false; - - if (i >= strlen(s)-1) - { - s[strlen(s)-1] = 0; - c_input--; - return false; - } - - for (; (i < HU_MAXMSGLEN); i++) - { - s[i-1] = s[i]; - } - c_input--; - } - else if (ch != KEY_ENTER) - return false; // did not eat key - - return true; // ate the key -} - #endif // @@ -1027,6 +962,10 @@ void HU_Ticker(void) #ifndef NONET static boolean teamtalk = false; +static boolean justscrolleddown; +static boolean justscrolledup; +static INT16 typelines = 1; // number of drawfill lines we need when drawing the chat. it's some weird hack and might be one frame off but I'm lazy to make another loop. +// It's up here since it has to be reset when we open the chat. static boolean HU_chatboxContainsOnlySpaces(void) { @@ -1133,6 +1072,73 @@ static void HU_queueChatChar(char c) return; } } + +// Handles key input and string input +// +static inline boolean HU_keyInChatString(char *s, char ch) +{ + size_t l; + + if ((ch >= HU_FONTSTART && ch <= HU_FONTEND && hu_font[ch-HU_FONTSTART]) + || ch == ' ') // Allow spaces, of course + { + l = strlen(s); + if (l < HU_MAXMSGLEN - 1) + { + if (c_input >= strlen(s)) // don't do anything complicated + { + s[l++] = ch; + s[l]=0; + } + else + { + + // move everything past c_input for new characters: + size_t m = HU_MAXMSGLEN-1; + while (m>=c_input) + { + if (s[m]) + s[m+1] = (s[m]); + if (m == 0) // prevent overflow + break; + m--; + } + s[c_input] = ch; // and replace this. + } + c_input++; + return true; + } + return false; + } + else if (ch == KEY_BACKSPACE) + { + size_t i = c_input; + + if (c_input <= 0) + return false; + + if (!s[i-1]) + return false; + + if (i >= strlen(s)-1) + { + s[strlen(s)-1] = 0; + c_input--; + return false; + } + + for (; (i < HU_MAXMSGLEN); i++) + { + s[i-1] = s[i]; + } + c_input--; + } + else if (ch != KEY_ENTER) + return false; // did not eat key + + return true; // ate the key +} + #endif void HU_clearChatChars(void) @@ -1144,13 +1150,6 @@ void HU_clearChatChars(void) I_UpdateMouseGrab(); } -#ifndef NONET -static boolean justscrolleddown; -static boolean justscrolledup; -static INT16 typelines = 1; // number of drawfill lines we need when drawing the chat. it's some weird hack and might be one frame off but I'm lazy to make another loop. -// It's up here since it has to be reset when we open the chat. -#endif - // // Returns true if key eaten // From 4c59bb3b2b5e9782b8aa4672b02d22bd85e1e2ae Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 2 Jan 2022 17:55:14 +0100 Subject: [PATCH 09/63] Turn HU_queueChatChar into HU_sendChatMessage # Conflicts: # src/hu_stuff.c --- src/hu_stuff.c | 180 +++++++++++++++++++++++-------------------------- 1 file changed, 84 insertions(+), 96 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index f78bfa16b..b4a3d2fbb 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -978,104 +978,99 @@ static boolean HU_chatboxContainsOnlySpaces(void) return true; } -static void HU_queueChatChar(char c) +static void HU_sendChatMessage(void) { - if (c == KEY_ENTER) + char buf[2+256]; + char *msg = &buf[2]; + size_t ci; + INT32 target = 0; + + // if our message was nothing but spaces, don't send it. + if (HU_chatboxContainsOnlySpaces()) + return; + + // copy printable characters and terminating '\0' only. + for (ci = 2; w_chat[ci-2]; ci++) { - char buf[2+256]; - char *msg = &buf[2]; - size_t ci; - INT32 target = 0; + char c = w_chat[ci-2]; + if (c >= ' ' && !(c & 0x80)) + buf[ci] = c; + }; + buf[ci] = '\0'; - // if our message was nothing but spaces, don't send it. - if (HU_chatboxContainsOnlySpaces()) - return; + memset(w_chat, '\0', HU_MAXMSGLEN); + c_input = 0; - // copy printable characters and terminating '\0' only. - for (ci = 2; w_chat[ci-2]; ci++) + // last minute mute check + if (CHAT_MUTE) + { + HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85"), false); + return; + } + + if (strlen(msg) > 4 && strnicmp(msg, "/pm", 3) == 0) // used /pm + { + INT32 spc = 1; // used if playernum[1] is a space. + char playernum[3]; + const char *newmsg; + + // what we're gonna do now is check if the player exists + // with that logic, characters 4 and 5 are our numbers: + + // teamtalk can't send PMs, just don't send it, else everyone would be able to see it, and no one wants to see your sex RP sicko. + if (teamtalk) { - c = w_chat[ci-2]; - if (c >= ' ' && !(c & 0x80)) - buf[ci] = c; - }; - buf[ci] = '\0'; - - memset(w_chat, '\0', HU_MAXMSGLEN); - c_input = 0; - - // last minute mute check - if (CHAT_MUTE) - { - HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85"), false); + HU_AddChatText(va("%sCannot send sayto in Say-Team.", "\x85"), false); return; } - if (strlen(msg) > 4 && strnicmp(msg, "/pm", 3) == 0) // used /pm + strncpy(playernum, msg+3, 3); + // check for undesirable characters in our "number" + if (!(isdigit(playernum[0]) && isdigit(playernum[1]))) { - INT32 spc = 1; // used if playernum[1] is a space. - char playernum[3]; - const char *newmsg; - - // what we're gonna do now is check if the player exists - // with that logic, characters 4 and 5 are our numbers: - - // teamtalk can't send PMs, just don't send it, else everyone would be able to see it, and no one wants to see your sex RP sicko. - if (teamtalk) - { - HU_AddChatText(va("%sCannot send sayto in Say-Team.", "\x85"), false); - return; - } - - strncpy(playernum, msg+3, 3); - - // check for undesirable characters in our "number" - if (!(isdigit(playernum[0]) && isdigit(playernum[1]))) - { - // check if playernum[1] is a space - if (playernum[1] == ' ') - spc = 0; - // let it slide - else - { - HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); - return; - } - } - // I'm very bad at C, I swear I am, additional checks eww! - if (spc != 0 && msg[5] != ' ') + // check if playernum[1] is a space + if (playernum[1] == ' ') + spc = 0; + // let it slide + else { HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); return; } - - target = atoi(playernum); // turn that into a number - - // check for target player, if it doesn't exist then we can't send the message! - if (target < MAXPLAYERS && playeringame[target]) // player exists - target++; // even though playernums are from 0 to 31, target is 1 to 32, so up that by 1 to have it work! - else - { - HU_AddChatText(va("\x82NOTICE: \x80Player %d does not exist.", target), false); // same - return; - } - - // we need to get rid of the /pm - newmsg = msg+5+spc; - strlcpy(msg, newmsg, 255); } - if (ci > 3) // don't send target+flags+empty message. + // I'm very bad at C, I swear I am, additional checks eww! + if (spc != 0 && msg[5] != ' ') { - buf[0] = teamtalk ? -1 : target; // target - buf[1] = 0; // flags - SendNetXCmd(XD_SAY, buf, 2 + strlen(&buf[2]) + 1); + HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); + return; } - return; + + target = atoi(playernum); // turn that into a number + + // check for target player, if it doesn't exist then we can't send the message! + if (target < MAXPLAYERS && playeringame[target]) // player exists + target++; // even though playernums are from 0 to 31, target is 1 to 32, so up that by 1 to have it work! + else + { + HU_AddChatText(va("\x82NOTICE: \x80Player %d does not exist.", target), false); // same + return; + } + + // we need to get rid of the /pm + newmsg = msg+5+spc; + strlcpy(msg, newmsg, 255); + } + if (ci > 3) // don't send target+flags+empty message. + { + buf[0] = teamtalk ? -1 : target; // target + buf[1] = 0; // flags + SendNetXCmd(XD_SAY, buf, 2 + strlen(&buf[2]) + 1); } } // Handles key input and string input // -static inline boolean HU_keyInChatString(char *s, char ch) +static inline void HU_keyInChatString(char *s, char ch) { size_t l; @@ -1106,25 +1101,25 @@ static inline boolean HU_keyInChatString(char *s, char ch) s[c_input] = ch; // and replace this. } c_input++; - return true; + return; } - return false; + return; } else if (ch == KEY_BACKSPACE) { size_t i = c_input; if (c_input <= 0) - return false; + return; if (!s[i-1]) - return false; + return; if (i >= strlen(s)-1) { s[strlen(s)-1] = 0; c_input--; - return false; + return; } for (; (i < HU_MAXMSGLEN); i++) @@ -1133,10 +1128,6 @@ static inline boolean HU_keyInChatString(char *s, char ch) } c_input--; } - else if (ch != KEY_ENTER) - return false; // did not eat key - - return true; // ate the key } #endif @@ -1246,14 +1237,9 @@ boolean HU_Responder(event_t *ev) { memcpy(&w_chat[chatlen], paste, pastelen); // copy all of that. c_input += pastelen; - /*size_t i = 0; - for (;i= c_input) @@ -1270,12 +1256,11 @@ boolean HU_Responder(event_t *ev) } } - if (!CHAT_MUTE && HU_keyInChatString(w_chat,c)) - { - HU_queueChatChar(c); - } if (c == KEY_ENTER) { + if (!CHAT_MUTE) + HU_sendChatMessage(); + chat_on = false; c_input = 0; // reset input cursor chat_scrollmedown = true; // you hit enter, so you might wanna autoscroll to see what you just sent. :) @@ -1316,6 +1301,9 @@ boolean HU_Responder(event_t *ev) else c_input++; } + else if (!CHAT_MUTE) + HU_keyInChatString(w_chat, c); + return true; } #endif From 5d406375a80d539907733f75667667950e6bc4a7 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 2 Jan 2022 23:06:34 +0100 Subject: [PATCH 10/63] Cleanup and fix chat deleting and pasting # Conflicts: # src/hu_stuff.c # src/hu_stuff.h --- src/hu_stuff.c | 88 +++++++++----------------------------------------- src/hu_stuff.h | 4 +-- 2 files changed, 18 insertions(+), 74 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index b4a3d2fbb..01f5bde1f 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -81,8 +81,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 char w_chat[HU_MAXMSGLEN + 1]; static size_t c_input = 0; // let's try to make the chat input less shitty. static boolean headsupactive = false; boolean hu_showscores; // draw rankings @@ -998,7 +997,7 @@ static void HU_sendChatMessage(void) }; buf[ci] = '\0'; - memset(w_chat, '\0', HU_MAXMSGLEN); + memset(w_chat, '\0', sizeof(w_chat)); c_input = 0; // last minute mute check @@ -1068,64 +1067,27 @@ static void HU_sendChatMessage(void) } } +// // Handles key input and string input // static inline void HU_keyInChatString(char *s, char ch) { - size_t l; - if ((ch >= HU_FONTSTART && ch <= HU_FONTEND && hu_font[ch-HU_FONTSTART]) || ch == ' ') // Allow spaces, of course { - l = strlen(s); - if (l < HU_MAXMSGLEN - 1) - { - if (c_input >= strlen(s)) // don't do anything complicated - { - s[l++] = ch; - s[l]=0; - } - else - { - - // move everything past c_input for new characters: - size_t m = HU_MAXMSGLEN-1; - while (m>=c_input) - { - if (s[m]) - s[m+1] = (s[m]); - if (m == 0) // prevent overflow - break; - m--; - } - s[c_input] = ch; // and replace this. - } - c_input++; + if (strlen(s) >= HU_MAXMSGLEN) return; - } - return; + + memmove(&s[c_input + 1], &s[c_input], strlen(s) - c_input + 1); + s[c_input] = ch; + c_input++; } else if (ch == KEY_BACKSPACE) { - size_t i = c_input; - if (c_input <= 0) return; - if (!s[i-1]) - return; - - if (i >= strlen(s)-1) - { - s[strlen(s)-1] = 0; - c_input--; - return; - } - - for (; (i < HU_MAXMSGLEN); i++) - { - s[i-1] = s[i]; - } + memmove(&s[c_input - 1], &s[c_input], strlen(s) - c_input + 1); c_input--; } } @@ -1134,7 +1096,7 @@ static inline void HU_keyInChatString(char *s, char ch) void HU_clearChatChars(void) { - memset(w_chat, '\0', HU_MAXMSGLEN); + memset(w_chat, '\0', sizeof(w_chat)); chat_on = false; c_input = 0; @@ -1219,12 +1181,11 @@ boolean HU_Responder(event_t *ev) // pasting. pasting is cool. chat is a bit limited, though :( if (((c == 'v' || c == 'V') && ctrldown) && !CHAT_MUTE) { - const char *paste = I_ClipboardPaste(); + const char *paste; size_t chatlen; size_t pastelen; - // create a dummy string real quickly - + paste = I_ClipboardPaste(); if (paste == NULL) return true; @@ -1233,27 +1194,10 @@ boolean HU_Responder(event_t *ev) if (chatlen+pastelen > HU_MAXMSGLEN) return true; // we can't paste this!! - if (c_input >= strlen(w_chat)) // add it at the end of the string. - { - memcpy(&w_chat[chatlen], paste, pastelen); // copy all of that. - c_input += pastelen; - return true; - } - else // otherwise, we need to shift everything and make space, etc etc - { - size_t i = HU_MAXMSGLEN-1; - while (i >= c_input) - { - if (w_chat[i]) - w_chat[i+pastelen] = w_chat[i]; - if (i == 0) // prevent overflow - break; - i--; - } - memcpy(&w_chat[c_input], paste, pastelen); // copy all of that. - c_input += pastelen; - return true; - } + memmove(&w_chat[c_input + pastelen], &w_chat[c_input], pastelen); + memcpy(&w_chat[c_input], paste, pastelen); // copy all of that. + c_input += pastelen; + return true; } if (c == KEY_ENTER) diff --git a/src/hu_stuff.h b/src/hu_stuff.h index d81dba2a6..bbe906fa9 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -80,8 +80,8 @@ typedef struct //------------------------------------ // chat stuff //------------------------------------ -#define HU_MAXMSGLEN 224 -#define CHAT_BUFSIZE 64 // that's enough messages, right? We'll delete the older ones when that gets out of hand. +#define HU_MAXMSGLEN 223 +#define CHAT_BUFSIZE 64 // that's enough messages, right? We'll delete the older ones when that gets out of hand. #define NETSPLITSCREEN // why the hell WOULDN'T we want this? #ifdef NETSPLITSCREEN #define OLDCHAT (cv_consolechat.value == 1 || dedicated || vid.width < 640) From cf6dfecc6a622b0a45afa565f3a5f4982d5d6607 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 2 Jan 2022 23:19:34 +0100 Subject: [PATCH 11/63] Cleanup chat event handling # Conflicts: # src/hu_stuff.c --- src/hu_stuff.c | 53 ++++++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 01f5bde1f..8e027f6b4 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1067,31 +1067,6 @@ static void HU_sendChatMessage(void) } } -// -// Handles key input and string input -// -static inline void HU_keyInChatString(char *s, char ch) -{ - if ((ch >= HU_FONTSTART && ch <= HU_FONTEND && hu_font[ch-HU_FONTSTART]) - || ch == ' ') // Allow spaces, of course - { - if (strlen(s) >= HU_MAXMSGLEN) - return; - - memmove(&s[c_input + 1], &s[c_input], strlen(s) - c_input + 1); - s[c_input] = ch; - c_input++; - } - else if (ch == KEY_BACKSPACE) - { - if (c_input <= 0) - return; - - memmove(&s[c_input - 1], &s[c_input], strlen(s) - c_input + 1); - c_input--; - } -} - #endif void HU_clearChatChars(void) @@ -1179,12 +1154,15 @@ boolean HU_Responder(event_t *ev) c = CON_ShiftChar(c); // pasting. pasting is cool. chat is a bit limited, though :( - if (((c == 'v' || c == 'V') && ctrldown) && !CHAT_MUTE) + if ((c == 'v' || c == 'V') && ctrldown) { const char *paste; size_t chatlen; size_t pastelen; + if (CHAT_MUTE) + return true; + paste = I_ClipboardPaste(); if (paste == NULL) return true; @@ -1199,8 +1177,7 @@ boolean HU_Responder(event_t *ev) c_input += pastelen; return true; } - - if (c == KEY_ENTER) + else if (c == KEY_ENTER) { if (!CHAT_MUTE) HU_sendChatMessage(); @@ -1245,8 +1222,24 @@ boolean HU_Responder(event_t *ev) else c_input++; } - else if (!CHAT_MUTE) - HU_keyInChatString(w_chat, c); + else if ((c >= HU_FONTSTART && c <= HU_FONTEND && hu_font[c-HU_FONTSTART]) + || c == ' ') // Allow spaces, of course + { + if (CHAT_MUTE || strlen(w_chat) >= HU_MAXMSGLEN) + return true; + + memmove(&w_chat[c_input + 1], &w_chat[c_input], strlen(w_chat) - c_input + 1); + w_chat[c_input] = c; + c_input++; + } + else if (c == KEY_BACKSPACE) + { + if (CHAT_MUTE || c_input <= 0) + return true; + + memmove(&w_chat[c_input - 1], &w_chat[c_input], strlen(w_chat) - c_input + 1); + c_input--; + } return true; } From bc62dc821438dd557a1572b39a5113e513b9a629 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Mon, 3 Jan 2022 00:06:20 +0100 Subject: [PATCH 12/63] Fix single-letter messages not being sent --- src/hu_stuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 8e027f6b4..389d245f4 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1059,7 +1059,7 @@ static void HU_sendChatMessage(void) newmsg = msg+5+spc; strlcpy(msg, newmsg, 255); } - if (ci > 3) // don't send target+flags+empty message. + if (ci > 2) // don't send target+flags+empty message. { buf[0] = teamtalk ? -1 : target; // target buf[1] = 0; // flags From de4eed6af24f091bf8547ec991eaf6ddf5545b24 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Mon, 3 Jan 2022 00:06:43 +0100 Subject: [PATCH 13/63] Add SKIPSTRINGN macro --- src/byteptr.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/byteptr.h b/src/byteptr.h index fd178ba3b..fd3c523cb 100644 --- a/src/byteptr.h +++ b/src/byteptr.h @@ -143,7 +143,8 @@ FUNCINLINE static ATTRINLINE UINT32 readulong(void *ptr) #define WRITESTRING(p,s) do { size_t tmp_i = 0; for (; s[tmp_i] != '\0'; tmp_i++) WRITECHAR(p, s[tmp_i]); WRITECHAR(p, '\0');} while (0) #define WRITEMEM(p,s,n) do { memcpy(p, s, n); p += n; } while (0) -#define SKIPSTRING(p) while (READCHAR(p) != '\0') +#define SKIPSTRING(p) while (READCHAR(p) != '\0') +#define SKIPSTRINGN(p,n) ({ size_t tmp_i = 0; for (; tmp_i < n && READCHAR(p) != '\0'; tmp_i++); }) #define READSTRINGN(p,s,n) do { size_t tmp_i = 0; for (; tmp_i < n && (s[tmp_i] = READCHAR(p)) != '\0'; tmp_i++); s[tmp_i] = '\0';} while (0) #define READSTRING(p,s) do { size_t tmp_i = 0; for (; (s[tmp_i] = READCHAR(p)) != '\0'; tmp_i++); s[tmp_i] = '\0';} while (0) From 94f691f21646889eb0b16396bbef8ff3cff1bf0c Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Mon, 3 Jan 2022 00:08:23 +0100 Subject: [PATCH 14/63] Fix long chat messages crashing the game --- src/hu_stuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 389d245f4..69e77020c 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -651,7 +651,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) target = READSINT8(*p); flags = READUINT8(*p); msg = (char *)*p; - SKIPSTRING(*p); + SKIPSTRINGN(*p, HU_MAXMSGLEN); if ((cv_mute.value || flags & (HU_CSAY|HU_SERVER_SAY)) && playernum != serverplayer && !(IsPlayerAdmin(playernum))) { From 47c7351928f958244a222970b2e16c2bdc795eb2 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Mon, 3 Jan 2022 00:30:16 +0100 Subject: [PATCH 15/63] Support delete key in chatbox --- src/hu_stuff.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 69e77020c..10c92a72c 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1240,6 +1240,13 @@ boolean HU_Responder(event_t *ev) memmove(&w_chat[c_input - 1], &w_chat[c_input], strlen(w_chat) - c_input + 1); c_input--; } + else if (c == KEY_DEL) + { + if (CHAT_MUTE || c_input >= strlen(w_chat)) + return true; + + memmove(&w_chat[c_input], &w_chat[c_input + 1], strlen(w_chat) - c_input); + } return true; } From d3d2205932fe20d7f6ee01dbdb7822a2eb01da15 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Mon, 3 Jan 2022 22:37:19 +0100 Subject: [PATCH 16/63] Fix long chat messages causing net command failures --- src/hu_stuff.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 10c92a72c..a2f069b77 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -641,7 +641,8 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) SINT8 target; UINT8 flags; const char *dispname; - char *msg; + char msgbuf[HU_MAXMSGLEN + 1]; + char *msg = msgbuf; boolean action = false; char *ptr; INT32 spam_eatmsg = 0; @@ -650,8 +651,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) target = READSINT8(*p); flags = READUINT8(*p); - msg = (char *)*p; - SKIPSTRINGN(*p, HU_MAXMSGLEN); + READSTRINGN(*p, msgbuf, HU_MAXMSGLEN); if ((cv_mute.value || flags & (HU_CSAY|HU_SERVER_SAY)) && playernum != serverplayer && !(IsPlayerAdmin(playernum))) { @@ -995,7 +995,11 @@ static void HU_sendChatMessage(void) if (c >= ' ' && !(c & 0x80)) buf[ci] = c; }; - buf[ci] = '\0'; + if (ci-2 < HU_MAXMSGLEN) + { + buf[ci] = '\0'; + ci++; + } memset(w_chat, '\0', sizeof(w_chat)); c_input = 0; @@ -1063,7 +1067,7 @@ static void HU_sendChatMessage(void) { buf[0] = teamtalk ? -1 : target; // target buf[1] = 0; // flags - SendNetXCmd(XD_SAY, buf, 2 + strlen(&buf[2]) + 1); + SendNetXCmd(XD_SAY, buf, ci); } } From c7e495bf8ba1221bddc50264fce7dfb2933594fb Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Mon, 10 Jan 2022 18:56:42 +0100 Subject: [PATCH 17/63] Make byte stream manipulation code easier to read # Conflicts: # src/byteptr.h --- src/byteptr.h | 61 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/src/byteptr.h b/src/byteptr.h index fd3c523cb..56a739eb3 100644 --- a/src/byteptr.h +++ b/src/byteptr.h @@ -139,13 +139,58 @@ FUNCINLINE static ATTRINLINE UINT32 readulong(void *ptr) #undef DEALIGNED -#define WRITESTRINGN(p,s,n) do { size_t tmp_i = 0; for (; tmp_i < n && s[tmp_i] != '\0'; tmp_i++) WRITECHAR(p, s[tmp_i]); if (tmp_i < n) WRITECHAR(p, '\0');} while (0) -#define WRITESTRING(p,s) do { size_t tmp_i = 0; for (; s[tmp_i] != '\0'; tmp_i++) WRITECHAR(p, s[tmp_i]); WRITECHAR(p, '\0');} while (0) -#define WRITEMEM(p,s,n) do { memcpy(p, s, n); p += n; } while (0) +#define WRITESTRINGN(p, s, n) ({ \ + size_t tmp_i; \ + \ + for (tmp_i = 0; tmp_i < n && s[tmp_i] != '\0'; tmp_i++) \ + WRITECHAR(p, s[tmp_i]); \ + \ + if (tmp_i < n) \ + WRITECHAR(p, '\0'); \ +}) -#define SKIPSTRING(p) while (READCHAR(p) != '\0') -#define SKIPSTRINGN(p,n) ({ size_t tmp_i = 0; for (; tmp_i < n && READCHAR(p) != '\0'; tmp_i++); }) +#define WRITESTRING(p, s) ({ \ + size_t tmp_i; \ + \ + for (tmp_i = 0; s[tmp_i] != '\0'; tmp_i++) \ + WRITECHAR(p, s[tmp_i]); \ + \ + WRITECHAR(p, '\0'); \ +}) -#define READSTRINGN(p,s,n) do { size_t tmp_i = 0; for (; tmp_i < n && (s[tmp_i] = READCHAR(p)) != '\0'; tmp_i++); s[tmp_i] = '\0';} while (0) -#define READSTRING(p,s) do { size_t tmp_i = 0; for (; (s[tmp_i] = READCHAR(p)) != '\0'; tmp_i++); s[tmp_i] = '\0';} while (0) -#define READMEM(p,s,n) do { memcpy(s, p, n); p += n; } while (0) +#define WRITEMEM(p, s, n) ({ \ + memcpy(p, s, n); \ + p += n; \ +}) + +#define SKIPSTRING(p) while (READCHAR(p) != '\0') + +#define SKIPSTRINGN(p, n) ({ \ + size_t tmp_i = 0; \ + \ + while (tmp_i < n && READCHAR(p) != '\0') \ + tmp_i++; \ +}) + +#define READSTRINGN(p, s, n) ({ \ + size_t tmp_i = 0; \ + \ + while (tmp_i < n && (s[tmp_i] = READCHAR(p)) != '\0') \ + tmp_i++; \ + \ + s[tmp_i] = '\0'; \ +}) + +#define READSTRING(p, s) ({ \ + size_t tmp_i = 0; \ + \ + while ((s[tmp_i] = READCHAR(p)) != '\0') \ + tmp_i++; \ + \ + s[tmp_i] = '\0'; \ +}) + +#define READMEM(p, s, n) ({ \ + memcpy(s, p, n); \ + p += n; \ +}) From 8558323c445e23f76feded33e94294fbf58ed1cf Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Mon, 10 Jan 2022 18:57:18 +0100 Subject: [PATCH 18/63] Add READSTRINGL and WRITESTRINGL macros --- src/byteptr.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/byteptr.h b/src/byteptr.h index 56a739eb3..cd7e912b6 100644 --- a/src/byteptr.h +++ b/src/byteptr.h @@ -149,6 +149,15 @@ FUNCINLINE static ATTRINLINE UINT32 readulong(void *ptr) WRITECHAR(p, '\0'); \ }) +#define WRITESTRINGL(p, s, n) ({ \ + size_t tmp_i; \ + \ + for (tmp_i = 0; tmp_i < n - 1 && s[tmp_i] != '\0'; tmp_i++) \ + WRITECHAR(p, s[tmp_i]); \ + \ + WRITECHAR(p, '\0'); \ +}) + #define WRITESTRING(p, s) ({ \ size_t tmp_i; \ \ @@ -181,6 +190,15 @@ FUNCINLINE static ATTRINLINE UINT32 readulong(void *ptr) s[tmp_i] = '\0'; \ }) +#define READSTRINGL(p, s, n) ({ \ + size_t tmp_i = 0; \ + \ + while (tmp_i < n - 1 && (s[tmp_i] = READCHAR(p)) != '\0') \ + tmp_i++; \ + \ + s[tmp_i] = '\0'; \ +}) + #define READSTRING(p, s) ({ \ size_t tmp_i = 0; \ \ From 75e4f07e12a52386bf57177f892b420f9f423e64 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Mon, 10 Jan 2022 19:31:41 +0100 Subject: [PATCH 19/63] Fix say command and its variants using hardcoded buffer size --- src/hu_stuff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index a2f069b77..2b38697c4 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -464,7 +464,7 @@ void HU_AddChatText(const char *text, boolean playsound) static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags) { - char buf[254]; + char buf[2 + HU_MAXMSGLEN + 1]; size_t numwords, ix; char *msg = &buf[2]; const size_t msgspace = sizeof buf - 2; @@ -541,7 +541,7 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags) } buf[0] = target; newmsg = msg+5+spc; - strlcpy(msg, newmsg, 252); + strlcpy(msg, newmsg, HU_MAXMSGLEN + 1); } SendNetXCmd(XD_SAY, buf, strlen(msg) + 1 + msg-buf); From 32e7442d0040fdd5efbf7ddbac44aef3fabe0126 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Mon, 10 Jan 2022 19:57:15 +0100 Subject: [PATCH 20/63] Revert "Fix long chat messages causing net command failures" This reverts commit 13778247990d60c2ad8aa5729bc0397ab764eaaa. --- src/hu_stuff.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 2b38697c4..74eb13813 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -641,8 +641,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) SINT8 target; UINT8 flags; const char *dispname; - char msgbuf[HU_MAXMSGLEN + 1]; - char *msg = msgbuf; + char *msg; boolean action = false; char *ptr; INT32 spam_eatmsg = 0; @@ -651,7 +650,8 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) target = READSINT8(*p); flags = READUINT8(*p); - READSTRINGN(*p, msgbuf, HU_MAXMSGLEN); + msg = (char *)*p; + SKIPSTRINGN(*p, HU_MAXMSGLEN); if ((cv_mute.value || flags & (HU_CSAY|HU_SERVER_SAY)) && playernum != serverplayer && !(IsPlayerAdmin(playernum))) { @@ -995,11 +995,7 @@ static void HU_sendChatMessage(void) if (c >= ' ' && !(c & 0x80)) buf[ci] = c; }; - if (ci-2 < HU_MAXMSGLEN) - { - buf[ci] = '\0'; - ci++; - } + buf[ci] = '\0'; memset(w_chat, '\0', sizeof(w_chat)); c_input = 0; @@ -1067,7 +1063,7 @@ static void HU_sendChatMessage(void) { buf[0] = teamtalk ? -1 : target; // target buf[1] = 0; // flags - SendNetXCmd(XD_SAY, buf, ci); + SendNetXCmd(XD_SAY, buf, 2 + strlen(&buf[2]) + 1); } } From 0036559bef02cf1223e8286cc27a6a1680e13728 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Mon, 10 Jan 2022 20:03:29 +0100 Subject: [PATCH 21/63] Add SKIPSTRINGL macro --- src/byteptr.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/byteptr.h b/src/byteptr.h index cd7e912b6..79e3f99c0 100644 --- a/src/byteptr.h +++ b/src/byteptr.h @@ -181,6 +181,8 @@ FUNCINLINE static ATTRINLINE UINT32 readulong(void *ptr) tmp_i++; \ }) +#define SKIPSTRINGL(p, n) SKIPSTRINGN(p, n) + #define READSTRINGN(p, s, n) ({ \ size_t tmp_i = 0; \ \ From 9f37c240a400c2205b27b88b9c8d884ff5a48a9a Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Mon, 10 Jan 2022 20:05:58 +0100 Subject: [PATCH 22/63] Fix long chat messages causing net command failures --- src/hu_stuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 74eb13813..fe8d57667 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -651,7 +651,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) target = READSINT8(*p); flags = READUINT8(*p); msg = (char *)*p; - SKIPSTRINGN(*p, HU_MAXMSGLEN); + SKIPSTRINGL(*p, HU_MAXMSGLEN + 1); if ((cv_mute.value || flags & (HU_CSAY|HU_SERVER_SAY)) && playernum != serverplayer && !(IsPlayerAdmin(playernum))) { From d5367d2e657f973ac3e571dcbe96c509655ab4bc Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Mon, 10 Jan 2022 20:12:27 +0100 Subject: [PATCH 23/63] Fix message sending code using hardcoded buffer size --- src/hu_stuff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index fe8d57667..4707927d5 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -979,7 +979,7 @@ static boolean HU_chatboxContainsOnlySpaces(void) static void HU_sendChatMessage(void) { - char buf[2+256]; + char buf[2 + HU_MAXMSGLEN + 1]; char *msg = &buf[2]; size_t ci; INT32 target = 0; @@ -1057,7 +1057,7 @@ static void HU_sendChatMessage(void) // we need to get rid of the /pm newmsg = msg+5+spc; - strlcpy(msg, newmsg, 255); + strlcpy(msg, newmsg, HU_MAXMSGLEN + 1); } if (ci > 2) // don't send target+flags+empty message. { From e9d7c2eee3af3c241579bac777a96dfefd71896e Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 5 Sep 2022 16:37:44 +0100 Subject: [PATCH 24/63] Fix regressions in merge process - Re-replace `hu_font` with `fontv[HU_FONT].font` - Re-init hu_keystrokes --- src/hu_stuff.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 4707927d5..f88884c50 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -80,6 +80,7 @@ patch_t *framecounter; patch_t *frameslash; // framerate stuff. Used in screen.c static player_t *plr; +boolean hu_keystrokes; // :) boolean chat_on; // entering a chat message? static char w_chat[HU_MAXMSGLEN + 1]; static size_t c_input = 0; // let's try to make the chat input less shitty. @@ -1222,7 +1223,7 @@ boolean HU_Responder(event_t *ev) else c_input++; } - else if ((c >= HU_FONTSTART && c <= HU_FONTEND && hu_font[c-HU_FONTSTART]) + else if ((c >= HU_FONTSTART && c <= HU_FONTEND && fontv[HU_FONT].font[c-HU_FONTSTART]) || c == ' ') // Allow spaces, of course { if (CHAT_MUTE || strlen(w_chat) >= HU_MAXMSGLEN) @@ -1796,8 +1797,8 @@ static void HU_DrawChat_Old(void) size_t i = 0; const char *ntalk = "Say: ", *ttalk = "Say-Team: "; const char *talk = ntalk; - INT32 charwidth = 8 * con_scalefactor; //(hu_font['A'-HU_FONTSTART]->width) * con_scalefactor; - INT32 charheight = 8 * con_scalefactor; //(hu_font['A'-HU_FONTSTART]->height) * con_scalefactor; + INT32 charwidth = 8 * con_scalefactor; //(fontv[HU_FONT].font['A'-HU_FONTSTART]->width) * con_scalefactor; + INT32 charheight = 8 * con_scalefactor; //(fontv[HU_FONT].font['A'-HU_FONTSTART]->height) * con_scalefactor; if (teamtalk) { talk = ttalk; @@ -1818,7 +1819,7 @@ static void HU_DrawChat_Old(void) } else { - //charwidth = (hu_font[talk[i]-HU_FONTSTART]->width) * con_scalefactor; + //charwidth = (fontv[HU_FONT].font[talk[i]-HU_FONTSTART]->width) * con_scalefactor; V_DrawCharacter(HU_INPUTX + c, y, talk[i++] | cv_constextsize.value | V_NOSCALESTART, true); } c += charwidth; @@ -1846,7 +1847,7 @@ static void HU_DrawChat_Old(void) } else { - //charwidth = (hu_font[w_chat[i]-HU_FONTSTART]->width) * con_scalefactor; + //charwidth = (fontv[HU_FONT].font[w_chat[i]-HU_FONTSTART]->width) * con_scalefactor; V_DrawCharacter(HU_INPUTX + c, y, w_chat[i++] | cv_constextsize.value | V_NOSCALESTART | t, true); } From 9e11eff9d843b6c63a931ef4d9a96c5f182060e1 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 5 Sep 2022 16:49:27 +0100 Subject: [PATCH 25/63] Perform incantations so the byteptr.h macros are valid ISO C --- src/byteptr.h | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/byteptr.h b/src/byteptr.h index 79e3f99c0..5d1b50630 100644 --- a/src/byteptr.h +++ b/src/byteptr.h @@ -139,7 +139,7 @@ FUNCINLINE static ATTRINLINE UINT32 readulong(void *ptr) #undef DEALIGNED -#define WRITESTRINGN(p, s, n) ({ \ +#define WRITESTRINGN(p, s, n) do { \ size_t tmp_i; \ \ for (tmp_i = 0; tmp_i < n && s[tmp_i] != '\0'; tmp_i++) \ @@ -147,70 +147,70 @@ FUNCINLINE static ATTRINLINE UINT32 readulong(void *ptr) \ if (tmp_i < n) \ WRITECHAR(p, '\0'); \ -}) +} while (0) -#define WRITESTRINGL(p, s, n) ({ \ +#define WRITESTRINGL(p, s, n) do { \ size_t tmp_i; \ \ for (tmp_i = 0; tmp_i < n - 1 && s[tmp_i] != '\0'; tmp_i++) \ WRITECHAR(p, s[tmp_i]); \ \ WRITECHAR(p, '\0'); \ -}) +} while (0) -#define WRITESTRING(p, s) ({ \ +#define WRITESTRING(p, s) do { \ size_t tmp_i; \ \ for (tmp_i = 0; s[tmp_i] != '\0'; tmp_i++) \ WRITECHAR(p, s[tmp_i]); \ \ WRITECHAR(p, '\0'); \ -}) +} while (0) -#define WRITEMEM(p, s, n) ({ \ - memcpy(p, s, n); \ - p += n; \ -}) +#define WRITEMEM(p, s, n) do { \ + memcpy(p, s, n); \ + p += n; \ +} while (0) #define SKIPSTRING(p) while (READCHAR(p) != '\0') -#define SKIPSTRINGN(p, n) ({ \ +#define SKIPSTRINGN(p, n) do { \ size_t tmp_i = 0; \ \ while (tmp_i < n && READCHAR(p) != '\0') \ tmp_i++; \ -}) +} while (0) #define SKIPSTRINGL(p, n) SKIPSTRINGN(p, n) -#define READSTRINGN(p, s, n) ({ \ +#define READSTRINGN(p, s, n) do { \ size_t tmp_i = 0; \ \ while (tmp_i < n && (s[tmp_i] = READCHAR(p)) != '\0') \ tmp_i++; \ \ s[tmp_i] = '\0'; \ -}) +} while (0) -#define READSTRINGL(p, s, n) ({ \ +#define READSTRINGL(p, s, n) do { \ size_t tmp_i = 0; \ \ while (tmp_i < n - 1 && (s[tmp_i] = READCHAR(p)) != '\0') \ tmp_i++; \ \ s[tmp_i] = '\0'; \ -}) +} while (0) -#define READSTRING(p, s) ({ \ +#define READSTRING(p, s) do { \ size_t tmp_i = 0; \ \ while ((s[tmp_i] = READCHAR(p)) != '\0') \ tmp_i++; \ \ s[tmp_i] = '\0'; \ -}) +} while (0) -#define READMEM(p, s, n) ({ \ - memcpy(s, p, n); \ - p += n; \ -}) +#define READMEM(p, s, n) do { \ + memcpy(s, p, n); \ + p += n; \ +} while (0) From f6b62b6ac6c4a80478a51084c0ff0fcb9b52dbc8 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 11:07:25 -0400 Subject: [PATCH 26/63] Clean up water skip conditions - Use Digital Empire's water running conditions (fully prevents ever being able to water-run on water that isn't level) - Code cleanup of other parts of this code - Made the threshold for water skipping much more strict - Fixed water skip being scaled to player scale instead of map scale - Make water run / tripwire easier for rubberbanding bots --- src/k_kart.c | 27 +++++++++++- src/k_kart.h | 2 + src/p_mobj.c | 121 +++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 119 insertions(+), 31 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 5406e6427..369830fb7 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3232,7 +3232,7 @@ tripwirepass_t K_TripwirePassConditions(player_t *player) if ( player->flamedash || - player->speed > 2 * K_GetKartSpeed(player, false, true) + player->speed > 2 * K_GetKartSpeed(player, false, false) ) return TRIPWIRE_BOOST; @@ -3250,6 +3250,11 @@ boolean K_TripwirePass(player_t *player) return (player->tripwirePass != TRIPWIRE_NONE); } +boolean K_MovingHorizontally(mobj_t *mobj) +{ + return (P_AproxDistance(mobj->momx, mobj->momy) / 5 > abs(mobj->momz)); +} + boolean K_WaterRun(player_t *player) { if ( @@ -3257,12 +3262,30 @@ boolean K_WaterRun(player_t *player) player->sneakertimer || player->tiregrease || player->flamedash || - player->speed > 2 * K_GetKartSpeed(player, false, true) + player->speed > 2 * K_GetKartSpeed(player, false, false) ) return true; return false; } +boolean K_WaterSkip(player_t *player) +{ + if (player->waterskip >= 2) + { + // Already finished waterskipping. + return false; + } + + if (player->waterskip > 0) + { + // Already waterskipping. + // Simply make sure you haven't slowed down drastically. + return (player->speed > 20 * mapobjectscale); + } + + return K_MovingHorizontally(player->mo); +} + static fixed_t K_FlameShieldDashVar(INT32 val) { // 1 second = 75% + 50% top speed diff --git a/src/k_kart.h b/src/k_kart.h index 1c75288e5..7bb9f2b6a 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -142,7 +142,9 @@ boolean K_ApplyOffroad(player_t *player); boolean K_SlopeResistance(player_t *player); tripwirepass_t K_TripwirePassConditions(player_t *player); boolean K_TripwirePass(player_t *player); +boolean K_MovingHorizontally(mobj_t *mobj); boolean K_WaterRun(player_t *player); +boolean K_WaterSkip(player_t *player); void K_ApplyTripWire(player_t *player, tripwirestate_t state); INT16 K_GetSpindashChargeTime(player_t *player); fixed_t K_GetSpindashChargeSpeed(player_t *player); diff --git a/src/p_mobj.c b/src/p_mobj.c index 9b868360a..c4640cc3a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3073,25 +3073,92 @@ boolean P_SceneryZMovement(mobj_t *mo) return true; } +// // P_CanRunOnWater // -// Returns true if player can waterrun on the 3D floor +// Returns true if player can water run on a 3D floor // boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) { - boolean flip = player->mo->eflags & MFE_VERTICALFLIP; - fixed_t surfaceheight = flip ? player->mo->waterbottom : player->mo->watertop; - fixed_t playerbottom = flip ? (player->mo->z + player->mo->height) : player->mo->z; - fixed_t clip = flip ? (surfaceheight - playerbottom) : (playerbottom - surfaceheight); - fixed_t span = player->mo->watertop - player->mo->waterbottom; + const boolean flip = (player->mo->eflags & MFE_VERTICALFLIP); + fixed_t surfaceheight = INT32_MAX; + fixed_t playerbottom = INT32_MAX; + fixed_t surfDiff = INT32_MAX; + fixed_t maxStep = INT32_MAX; + boolean doifit = false; - return - clip > -(player->mo->height / 2) && - span > player->mo->height && - player->speed / 5 > abs(player->mo->momz) && - player->speed > K_GetKartSpeed(player, false, false) && - K_WaterRun(player) && - (rover->flags & FF_SWIMMABLE); + pslope_t *waterSlope = NULL; + angle_t ourZAng = 0; + angle_t waterZAng = 0; + + if (rover == NULL) + { + // No rover. + return false; + } + + if (!(rover->flags & FF_SWIMMABLE)) + { + // It's not even a water FOF. + return false; + } + + if (player->carry != CR_NONE) // Special carry state. + { + // No good player state. + return false; + } + + if (P_IsObjectOnGround(player->mo) == false) + { + // Don't allow jumping onto water to start a water run. + // (Already water running still counts as being on the ground.) + return false; + } + + if (K_WaterRun(player) == false) + { + // Basic conditions for enabling water run. + return false; + } + + if (player->mo->standingslope != NULL) + { + ourZAng = player->mo->standingslope->zangle; + } + + waterSlope = (flip ? *rover->b_slope : *rover->t_slope); + if (waterSlope != NULL) + { + waterZAng = waterSlope->zangle; + } + + if (ourZAng != waterZAng) + { + // The surface slopes are different. + return false; + } + + surfaceheight = flip ? P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y) : P_GetFFloorTopZAt(rover, player->mo->x, player->mo->y); + playerbottom = flip ? (player->mo->z + player->mo->height) : player->mo->z; + + doifit = flip ? (surfaceheight - player->mo->floorz >= player->mo->height) : (player->mo->ceilingz - surfaceheight >= player->mo->height); + + if (!doifit) + { + // Player can't fit in this space. + return false; + } + + surfDiff = flip ? (surfaceheight - playerbottom) : (playerbottom - surfaceheight); + maxStep = P_GetThingStepUp(player->mo); + if (surfDiff <= maxStep && surfDiff >= 0) + { + // We start water run IF we can step-down! + return true; + } + + return false; } boolean P_CheckSolidFFloorSurface(player_t *player, ffloor_t *rover) @@ -3308,23 +3375,19 @@ void P_MobjCheckWater(mobj_t *mobj) splish->destscale = mobj->scale; P_SetScale(splish, mobj->scale); + + // skipping stone! + if (K_WaterSkip(p) == true) + { + const fixed_t hop = 5 * mapobjectscale; + + mobj->momx = (4*mobj->momx)/5; + mobj->momy = (4*mobj->momy)/5; + mobj->momz = hop * P_MobjFlip(mobj); + + p->waterskip++; + } } - - // skipping stone! - if (p && p->waterskip < 2 - && ((p->speed/3 > abs(mobj->momz)) // Going more forward than horizontal, so you can skip across the water. - || (p->speed > 20*mapobjectscale && p->waterskip)) // Already skipped once, so you can skip once more! - && (splashValid == true)) - { - const fixed_t hop = 5 * mobj->scale; - - mobj->momx = (4*mobj->momx)/5; - mobj->momy = (4*mobj->momy)/5; - mobj->momz = hop * P_MobjFlip(mobj); - - p->waterskip++; - } - } else if (P_MobjFlip(mobj) * mobj->momz > 0) { From 884f710269b8d91fa59503c702dc3683857b3d4a Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 11:43:55 -0400 Subject: [PATCH 27/63] Add minimum strafe to water physics --- src/k_kart.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 369830fb7..028bd84ce 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8871,12 +8871,13 @@ INT32 K_GetUnderwaterTurnAdjust(player_t *player) { INT32 steer = (K_GetKartTurnValue(player, player->steering) << TICCMD_REDUCE); + fixed_t minimum = INT32_MAX; if (!player->drift) steer = 9 * steer / 5; - return FixedMul(steer, 8 * FixedDiv(player->speed, - 2 * K_GetKartSpeed(player, false, true) / 3)); + minimum = 2 * K_GetKartSpeed(player, false, true) / 3; + return FixedMul(steer, 8 * FixedDiv(max(player->speed, minimum), minimum)); } else return 0; From 841bcf36195bfef62bec3ead5601ff6a28b460c7 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 12:31:33 -0400 Subject: [PATCH 28/63] Allow non-players to water skip/run Water skipping is enabled for Orbinaut, Jawz, and Ballhog currently. Jawz can water run, as long as their target is on/above the plane they're at -- once their target goes into the water, they'll start skipping. --- src/d_player.h | 1 - src/k_kart.c | 90 +++++++++++++++++++++++++++++++++++---------- src/k_kart.h | 4 +- src/lua_baselib.c | 5 ++- src/lua_mobjlib.c | 8 ++++ src/lua_playerlib.c | 4 -- src/p_local.h | 6 +-- src/p_map.c | 6 +-- src/p_maputl.c | 4 +- src/p_mobj.c | 89 ++++++++++++++++++++++++++------------------ src/p_mobj.h | 1 + src/p_saveg.c | 13 ++++++- 12 files changed, 158 insertions(+), 73 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index c31837757..fcf87c520 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -438,7 +438,6 @@ typedef struct player_s INT32 underwatertilt; fixed_t offroad; // In Super Mario Kart, going offroad has lee-way of about 1 second before you start losing speed - UINT8 waterskip; // Water skipping counter UINT16 tiregrease; // Reduced friction timer after hitting a spring UINT16 springstars; // Spawn stars around a player when they hit a spring diff --git a/src/k_kart.c b/src/k_kart.c index 078e4f831..5a83d51cc 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3255,35 +3255,90 @@ boolean K_MovingHorizontally(mobj_t *mobj) return (P_AproxDistance(mobj->momx, mobj->momy) / 5 > abs(mobj->momz)); } -boolean K_WaterRun(player_t *player) +boolean K_WaterRun(mobj_t *mobj) { - if ( - player->invincibilitytimer || - player->sneakertimer || - player->tiregrease || - player->flamedash || - player->speed > 2 * K_GetKartSpeed(player, false, false) - ) - return true; - return false; + switch (mobj->type) + { + case MT_JAWZ: + { + if (mobj->tracer != NULL && P_MobjWasRemoved(mobj->tracer) == false) + { + fixed_t jawzFeet = P_GetMobjFeet(mobj); + fixed_t chaseFeet = P_GetMobjFeet(mobj->tracer); + fixed_t footDiff = (chaseFeet - jawzFeet) * P_MobjFlip(mobj); + + // Water run if the player we're chasing is above/equal to us. + // Start water skipping if they're underneath the water. + return (footDiff > -mobj->tracer->height); + } + + return false; + } + + case MT_PLAYER: + { + if (mobj->player == NULL) + { + return false; + } + + if (mobj->player->invincibilitytimer + || mobj->player->sneakertimer + || mobj->player->tiregrease + || mobj->player->flamedash + || mobj->player->speed > 2 * K_GetKartSpeed(mobj->player, false, false)) + { + return true; + } + + return false; + } + + default: + { + return false; + } + } } -boolean K_WaterSkip(player_t *player) +boolean K_WaterSkip(mobj_t *mobj) { - if (player->waterskip >= 2) + if (mobj->waterskip >= 2) { // Already finished waterskipping. return false; } - if (player->waterskip > 0) + switch (mobj->type) + { + case MT_PLAYER: + case MT_ORBINAUT: + case MT_JAWZ: + case MT_BALLHOG: + { + // Allow + break; + } + + default: + { + // Don't allow + return false; + } + } + + if (mobj->waterskip > 0) { // Already waterskipping. // Simply make sure you haven't slowed down drastically. - return (player->speed > 20 * mapobjectscale); + return (P_AproxDistance(mobj->momx, mobj->momy) > 20 * mapobjectscale); + } + else + { + // Need to be moving horizontally and not vertically + // to be able to start a water skip. + return K_MovingHorizontally(mobj); } - - return K_MovingHorizontally(player->mo); } static fixed_t K_FlameShieldDashVar(INT32 val) @@ -7980,9 +8035,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } } - if (P_IsObjectOnGround(player->mo)) - player->waterskip = 0; - if (player->instashield) player->instashield--; diff --git a/src/k_kart.h b/src/k_kart.h index 7bb9f2b6a..71169fec0 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -143,8 +143,8 @@ boolean K_SlopeResistance(player_t *player); tripwirepass_t K_TripwirePassConditions(player_t *player); boolean K_TripwirePass(player_t *player); boolean K_MovingHorizontally(mobj_t *mobj); -boolean K_WaterRun(player_t *player); -boolean K_WaterSkip(player_t *player); +boolean K_WaterRun(mobj_t *mobj); +boolean K_WaterSkip(mobj_t *mobj); void K_ApplyTripWire(player_t *player, tripwirestate_t state); INT16 K_GetSpindashChargeTime(player_t *player); fixed_t K_GetSpindashChargeSpeed(player_t *player); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index bd05ae8b5..7a72b31dc 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -954,12 +954,15 @@ static int lib_pCheckDeathPitCollide(lua_State *L) static int lib_pCheckSolidLava(lua_State *L) { + mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR)); //HUDSAFE INLEVEL + if (!mo) + return LUA_ErrInvalid(L, "mobj_t"); if (!rover) return LUA_ErrInvalid(L, "ffloor_t"); - lua_pushboolean(L, P_CheckSolidLava(rover)); + lua_pushboolean(L, P_CheckSolidLava(mo, rover)); return 1; } diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 418a43bf9..ecd87f49f 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -100,6 +100,7 @@ enum mobj_e { mobj_spryoff, mobj_sprzoff, mobj_hitlag, + mobj_waterskip, mobj_dispoffset }; @@ -181,6 +182,7 @@ static const char *const mobj_opt[] = { "spryoff", "sprzoff", "hitlag", + "waterskip", "dispoffset", NULL}; @@ -460,6 +462,9 @@ static int mobj_get(lua_State *L) case mobj_hitlag: lua_pushinteger(L, mo->hitlag); break; + case mobj_waterskip: + lua_pushinteger(L, mo->waterskip); + break; case mobj_dispoffset: lua_pushinteger(L, mo->dispoffset); break; @@ -835,6 +840,9 @@ static int mobj_set(lua_State *L) case mobj_hitlag: mo->hitlag = luaL_checkinteger(L, 3); break; + case mobj_waterskip: + mo->waterskip = (UINT8)luaL_checkinteger(L, 3); + break; case mobj_dispoffset: mo->dispoffset = luaL_checkinteger(L, 3); break; diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 85e73a12f..c5f5cc4d0 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -264,8 +264,6 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->aizdriftturn); else if (fastcmp(field,"offroad")) lua_pushinteger(L, plr->offroad); - else if (fastcmp(field,"waterskip")) - lua_pushinteger(L, plr->waterskip); else if (fastcmp(field,"tiregrease")) lua_pushinteger(L, plr->tiregrease); else if (fastcmp(field,"springstars")) @@ -634,8 +632,6 @@ static int player_set(lua_State *L) plr->aizdriftturn = luaL_checkinteger(L, 3); else if (fastcmp(field,"offroad")) plr->offroad = luaL_checkinteger(L, 3); - else if (fastcmp(field,"waterskip")) - plr->waterskip = luaL_checkinteger(L, 3); else if (fastcmp(field,"tiregrease")) plr->tiregrease = luaL_checkinteger(L, 3); else if (fastcmp(field,"springstars")) diff --git a/src/p_local.h b/src/p_local.h index 5fc73f1a2..37edb2b67 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -315,7 +315,7 @@ fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, f boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover); boolean P_CheckDeathPitCollide(mobj_t *mo); -boolean P_CheckSolidLava(ffloor_t *rover); +boolean P_CheckSolidLava(mobj_t *mobj, ffloor_t *rover); void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motype); mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zofs, mobjtype_t type); @@ -337,8 +337,8 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled void P_Attract(mobj_t *source, mobj_t *enemy, boolean nightsgrab); mobj_t *P_GetClosestAxis(mobj_t *source); -boolean P_CanRunOnWater(player_t *player, ffloor_t *rover); -boolean P_CheckSolidFFloorSurface(player_t *player, ffloor_t *rover); +boolean P_CanRunOnWater(mobj_t *mobj, ffloor_t *rover); +boolean P_CheckSolidFFloorSurface(mobj_t *mobj, ffloor_t *rover); void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot); diff --git a/src/p_map.c b/src/p_map.c index 07d610fb8..ba2147bac 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1940,7 +1940,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) continue; } - if (thing->player && P_CheckSolidFFloorSurface(thing->player, rover)) + if (P_CheckSolidFFloorSurface(thing, rover)) ; else if (thing->type == MT_SKIM && (rover->flags & FF_SWIMMABLE)) ; @@ -2524,9 +2524,7 @@ static boolean P_WaterRunning(mobj_t *thing) static boolean P_WaterStepUp(mobj_t *thing) { - player_t *player = thing->player; - return (player && player->waterskip) || - P_WaterRunning(thing); + return (thing->waterskip > 0 || P_WaterRunning(thing)); } fixed_t P_BaseStepUp(void) diff --git a/src/p_maputl.c b/src/p_maputl.c index 09e5cdd5d..74fe2331d 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -777,7 +777,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) if (!(rover->flags & FF_EXISTS)) continue; - if (mobj->player && P_CheckSolidFFloorSurface(mobj->player, rover)) + if (P_CheckSolidFFloorSurface(mobj, rover)) ; else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player) || (rover->flags & FF_BLOCKOTHERS && !mobj->player))) @@ -821,7 +821,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) if (!(rover->flags & FF_EXISTS)) continue; - if (mobj->player && P_CheckSolidFFloorSurface(mobj->player, rover)) + if (P_CheckSolidFFloorSurface(mobj, rover)) ; else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player) || (rover->flags & FF_BLOCKOTHERS && !mobj->player))) diff --git a/src/p_mobj.c b/src/p_mobj.c index ac6306823..8f350cbe7 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1105,6 +1105,11 @@ fixed_t P_GetMobjGravity(mobj_t *mo) } } + if (mo->waterskip > 0) + { + gravityadd = (4*gravityadd)/3; + } + if (mo->player) { if (mo->flags2 & MF2_OBJECTFLIP) @@ -1118,11 +1123,6 @@ fixed_t P_GetMobjGravity(mobj_t *mo) P_PlayerFlip(mo); } - if (mo->player->waterskip) - { - gravityadd = (4*gravityadd)/3; - } - if (mo->player->trickpanel >= 2) { gravityadd = (5*gravityadd)/2; @@ -1938,7 +1938,7 @@ void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motype) topheight = P_GetFOFTopZ(mo, sector, rover, mo->x, mo->y, NULL); bottomheight = P_GetFOFBottomZ(mo, sector, rover, mo->x, mo->y, NULL); - if (mo->player && P_CheckSolidFFloorSurface(mo->player, rover)) // only the player should stand on lava or run on water + if (P_CheckSolidFFloorSurface(mo, rover)) // only the player should stand on lava or run on water ; else if (motype != 0 && rover->flags & FF_SWIMMABLE) // "scenery" only continue; @@ -2097,11 +2097,18 @@ boolean P_CheckDeathPitCollide(mobj_t *mo) return false; } -boolean P_CheckSolidLava(ffloor_t *rover) +boolean P_CheckSolidLava(mobj_t *mobj, ffloor_t *rover) { + if (mobj->player == NULL) + { + return false; + } + if (rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3 && !(rover->master->flags & ML_BLOCKPLAYERS)) - return true; + { + return true; + } return false; } @@ -3084,11 +3091,13 @@ boolean P_SceneryZMovement(mobj_t *mo) // // Returns true if player can water run on a 3D floor // -boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) +boolean P_CanRunOnWater(mobj_t *mobj, ffloor_t *rover) { - const boolean flip = (player->mo->eflags & MFE_VERTICALFLIP); + const boolean flip = (mobj->eflags & MFE_VERTICALFLIP); + player_t *player = mobj->player; + fixed_t surfaceheight = INT32_MAX; - fixed_t playerbottom = INT32_MAX; + fixed_t mobjbottom = INT32_MAX; fixed_t surfDiff = INT32_MAX; fixed_t maxStep = INT32_MAX; boolean doifit = false; @@ -3109,28 +3118,29 @@ boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) return false; } - if (player->carry != CR_NONE) // Special carry state. + if (player != NULL + && player->carry != CR_NONE) // Special carry state. { // No good player state. return false; } - if (P_IsObjectOnGround(player->mo) == false) + if (P_IsObjectOnGround(mobj) == false) { // Don't allow jumping onto water to start a water run. // (Already water running still counts as being on the ground.) return false; } - if (K_WaterRun(player) == false) + if (K_WaterRun(mobj) == false) { // Basic conditions for enabling water run. return false; } - if (player->mo->standingslope != NULL) + if (mobj->standingslope != NULL) { - ourZAng = player->mo->standingslope->zangle; + ourZAng = mobj->standingslope->zangle; } waterSlope = (flip ? *rover->b_slope : *rover->t_slope); @@ -3145,19 +3155,19 @@ boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) return false; } - surfaceheight = flip ? P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y) : P_GetFFloorTopZAt(rover, player->mo->x, player->mo->y); - playerbottom = flip ? (player->mo->z + player->mo->height) : player->mo->z; + surfaceheight = flip ? P_GetFFloorBottomZAt(rover, mobj->x, mobj->y) : P_GetFFloorTopZAt(rover, mobj->x, mobj->y); + mobjbottom = flip ? (mobj->z + mobj->height) : mobj->z; - doifit = flip ? (surfaceheight - player->mo->floorz >= player->mo->height) : (player->mo->ceilingz - surfaceheight >= player->mo->height); + doifit = flip ? (surfaceheight - mobj->floorz >= mobj->height) : (mobj->ceilingz - surfaceheight >= mobj->height); if (!doifit) { - // Player can't fit in this space. + // Object can't fit in this space. return false; } - surfDiff = flip ? (surfaceheight - playerbottom) : (playerbottom - surfaceheight); - maxStep = P_GetThingStepUp(player->mo); + surfDiff = flip ? (surfaceheight - mobjbottom) : (mobjbottom - surfaceheight); + maxStep = P_GetThingStepUp(mobj); if (surfDiff <= maxStep && surfDiff >= 0) { // We start water run IF we can step-down! @@ -3167,10 +3177,10 @@ boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) return false; } -boolean P_CheckSolidFFloorSurface(player_t *player, ffloor_t *rover) +boolean P_CheckSolidFFloorSurface(mobj_t *mobj, ffloor_t *rover) { - return P_CheckSolidLava(rover) || - P_CanRunOnWater(player, rover); + return P_CheckSolidLava(mobj, rover) || + P_CanRunOnWater(mobj, rover); } // @@ -3286,16 +3296,24 @@ void P_MobjCheckWater(mobj_t *mobj) return; } - if (p && !p->waterskip && - p->curshield != KSHIELD_BUBBLE && wasinwater) + if (P_IsObjectOnGround(mobj) == true) { - S_StartSound(mobj, sfx_s3k38); + mobj->waterskip = 0; } - if ((p) // Players - || (mobj->flags & MF_PUSHABLE) // Pushables - || ((mobj->info->flags & MF_PUSHABLE) && mobj->fuse) // Previously pushable, might be moving still - ) + if (mobj->waterskip == 0 && wasinwater) + { + if (p && p->curshield == KSHIELD_BUBBLE) + { + ; + } + else + { + S_StartSound(mobj, sfx_s3k38); + } + } + + if (mobj->flags & MF_APPLYTERRAIN) { fixed_t waterZ = INT32_MAX; fixed_t solidZ = INT32_MAX; @@ -3383,7 +3401,7 @@ void P_MobjCheckWater(mobj_t *mobj) P_SetScale(splish, mobj->scale); // skipping stone! - if (K_WaterSkip(p) == true) + if (K_WaterSkip(mobj) == true) { const fixed_t hop = 5 * mapobjectscale; @@ -3391,11 +3409,11 @@ void P_MobjCheckWater(mobj_t *mobj) mobj->momy = (4*mobj->momy)/5; mobj->momz = hop * P_MobjFlip(mobj); - p->waterskip++; + mobj->waterskip++; } } } - else if (P_MobjFlip(mobj) * mobj->momz > 0) + else { if (splashValid == true && !(mobj->eflags & MFE_UNDERWATER)) // underwater check to prevent splashes on opposite side { @@ -9935,6 +9953,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->colorized = false; mobj->hitlag = 0; + mobj->waterskip = 0; // Set shadowscale here, before spawn hook so that Lua can change it P_DefaultMobjShadowScale(mobj); diff --git a/src/p_mobj.h b/src/p_mobj.h index 4cdacea6d..8ef307aab 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -409,6 +409,7 @@ typedef struct mobj_s struct mobj_s *terrainOverlay; // Overlay sprite object for terrain INT32 hitlag; // Sal-style hit lag, straight from Captain Fetch's jowls + UINT8 waterskip; // Water skipping counter INT32 dispoffset; diff --git a/src/p_saveg.c b/src/p_saveg.c index 233056f21..dd77337b9 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -280,7 +280,6 @@ static void P_NetArchivePlayers(void) WRITEINT32(save_p, players[i].underwatertilt); WRITEFIXED(save_p, players[i].offroad); - WRITEUINT8(save_p, players[i].waterskip); WRITEUINT16(save_p, players[i].tiregrease); WRITEUINT16(save_p, players[i].springstars); @@ -577,7 +576,6 @@ static void P_NetUnArchivePlayers(void) players[i].underwatertilt = READINT32(save_p); players[i].offroad = READFIXED(save_p); - players[i].waterskip = READUINT8(save_p); players[i].tiregrease = READUINT16(save_p); players[i].springstars = READUINT16(save_p); @@ -1638,6 +1636,7 @@ typedef enum MD2_ITNEXT = 1<<27, MD2_LASTMOMZ = 1<<28, MD2_TERRAIN = 1<<29, + MD2_WATERSKIP = 1<<30, } mobj_diff2_t; typedef enum @@ -1872,6 +1871,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) } if (mobj->hitlag) diff2 |= MD2_HITLAG; + if (mobj->waterskip) + diff2 |= MD2_WATERSKIP; if (mobj->dispoffset) diff2 |= MD2_DISPOFFSET; if (mobj == waypointcap) @@ -2082,6 +2083,10 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) { WRITEINT32(save_p, mobj->hitlag); } + if (diff2 & MD2_WATERSKIP) + { + WRITEUINT8(save_p, mobj->waterskip); + } if (diff2 & MD2_DISPOFFSET) { WRITEINT32(save_p, mobj->dispoffset); @@ -3191,6 +3196,10 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) { mobj->hitlag = READINT32(save_p); } + if (diff2 & MD2_WATERSKIP) + { + mobj->waterskip = READUINT8(save_p); + } if (diff2 & MD2_DISPOFFSET) { mobj->dispoffset = READINT32(save_p); From 6ca979d53ee9234ee0be0ef0dbb750477ce7cd34 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 12:35:23 -0400 Subject: [PATCH 29/63] Oops, thought this was a splash, not the gasp... Whoops! --- src/p_mobj.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 8f350cbe7..ca77a8f14 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3301,16 +3301,13 @@ void P_MobjCheckWater(mobj_t *mobj) mobj->waterskip = 0; } - if (mobj->waterskip == 0 && wasinwater) + if (p != NULL + && p->curshield != KSHIELD_BUBBLE + && mobj->waterskip == 0 + && wasinwater) { - if (p && p->curshield == KSHIELD_BUBBLE) - { - ; - } - else - { - S_StartSound(mobj, sfx_s3k38); - } + // Play the gasp sound + S_StartSound(mobj, sfx_s3k38); } if (mobj->flags & MF_APPLYTERRAIN) From afc2a0dcdc09c9dcd34e00682feb9719c4d2cd1a Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 13:09:30 -0400 Subject: [PATCH 30/63] Properly spawn effects for the other objects --- src/k_kart.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/k_kart.h | 1 + src/p_mobj.c | 28 +++++++--- src/p_user.c | 94 --------------------------------- 4 files changed, 167 insertions(+), 102 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 5a83d51cc..43e14fbdd 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3341,6 +3341,152 @@ boolean K_WaterSkip(mobj_t *mobj) } } +void K_SpawnWaterRunParticles(mobj_t *mobj) +{ + fixed_t runSpeed = 14 * mobj->scale; + fixed_t curSpeed = INT32_MAX; + fixed_t topSpeed = INT32_MAX; + fixed_t trailScale = FRACUNIT; + + if (mobj->momz != 0) + { + // Only while touching ground. + return; + } + + if (mobj->watertop == INT32_MAX || mobj->waterbottom == INT32_MIN) + { + // Invalid water plane. + return; + } + + if (mobj->player != NULL) + { + if (mobj->player->spectator) + { + // Not as spectator. + return; + } + + if (mobj->player->carry == CR_SLIDING) + { + // Not in water slides. + return; + } + + topSpeed = K_GetKartSpeed(mobj->player, false, false); + runSpeed = FixedMul(runSpeed, mobj->movefactor); + } + else + { + topSpeed = FixedMul(mobj->scale, K_GetKartSpeedFromStat(5)); + } + + curSpeed = P_AproxDistance(mobj->momx, mobj->momy); + + if (curSpeed <= runSpeed) + { + // Not fast enough. + return; + } + + // Near the water plane. + if ((!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + mobj->height >= mobj->watertop && mobj->z <= mobj->watertop) + || (mobj->eflags & MFE_VERTICALFLIP && mobj->z + mobj->height >= mobj->waterbottom && mobj->z <= mobj->waterbottom)) + { + if (topSpeed > runSpeed) + { + trailScale = FixedMul(FixedDiv(curSpeed - runSpeed, topSpeed - runSpeed), mapobjectscale); + } + else + { + trailScale = mapobjectscale; // Scaling is based off difference between runspeed and top speed + } + + if (trailScale > 0) + { + const angle_t forwardangle = K_MomentumAngle(mobj); + const fixed_t playerVisualRadius = mobj->radius + (8 * mobj->scale); + const size_t numFrames = S_WATERTRAIL8 - S_WATERTRAIL1; + const statenum_t curOverlayFrame = S_WATERTRAIL1 + (leveltime % numFrames); + const statenum_t curUnderlayFrame = S_WATERTRAILUNDERLAY1 + (leveltime % numFrames); + fixed_t x1, x2, y1, y2; + mobj_t *water; + + x1 = mobj->x + mobj->momx + P_ReturnThrustX(mobj, forwardangle + ANGLE_90, playerVisualRadius); + y1 = mobj->y + mobj->momy + P_ReturnThrustY(mobj, forwardangle + ANGLE_90, playerVisualRadius); + x1 = x1 + P_ReturnThrustX(mobj, forwardangle, playerVisualRadius); + y1 = y1 + P_ReturnThrustY(mobj, forwardangle, playerVisualRadius); + + x2 = mobj->x + mobj->momx + P_ReturnThrustX(mobj, forwardangle - ANGLE_90, playerVisualRadius); + y2 = mobj->y + mobj->momy + P_ReturnThrustY(mobj, forwardangle - ANGLE_90, playerVisualRadius); + x2 = x2 + P_ReturnThrustX(mobj, forwardangle, playerVisualRadius); + y2 = y2 + P_ReturnThrustY(mobj, forwardangle, playerVisualRadius); + + // Left + // underlay + water = P_SpawnMobj(x1, y1, + ((mobj->eflags & MFE_VERTICALFLIP) ? mobj->waterbottom - FixedMul(mobjinfo[MT_WATERTRAILUNDERLAY].height, mobj->scale) : mobj->watertop), MT_WATERTRAILUNDERLAY); + P_InitAngle(water, forwardangle - ANGLE_180 - ANGLE_22h); + water->destscale = trailScale; + water->momx = mobj->momx; + water->momy = mobj->momy; + water->momz = mobj->momz; + P_SetScale(water, trailScale); + P_SetMobjState(water, curUnderlayFrame); + + // overlay + water = P_SpawnMobj(x1, y1, + ((mobj->eflags & MFE_VERTICALFLIP) ? mobj->waterbottom - FixedMul(mobjinfo[MT_WATERTRAIL].height, mobj->scale) : mobj->watertop), MT_WATERTRAIL); + P_InitAngle(water, forwardangle - ANGLE_180 - ANGLE_22h); + water->destscale = trailScale; + water->momx = mobj->momx; + water->momy = mobj->momy; + water->momz = mobj->momz; + P_SetScale(water, trailScale); + P_SetMobjState(water, curOverlayFrame); + + // Right + // Underlay + water = P_SpawnMobj(x2, y2, + ((mobj->eflags & MFE_VERTICALFLIP) ? mobj->waterbottom - FixedMul(mobjinfo[MT_WATERTRAILUNDERLAY].height, mobj->scale) : mobj->watertop), MT_WATERTRAILUNDERLAY); + P_InitAngle(water, forwardangle - ANGLE_180 + ANGLE_22h); + water->destscale = trailScale; + water->momx = mobj->momx; + water->momy = mobj->momy; + water->momz = mobj->momz; + P_SetScale(water, trailScale); + P_SetMobjState(water, curUnderlayFrame); + + // Overlay + water = P_SpawnMobj(x2, y2, + ((mobj->eflags & MFE_VERTICALFLIP) ? mobj->waterbottom - FixedMul(mobjinfo[MT_WATERTRAIL].height, mobj->scale) : mobj->watertop), MT_WATERTRAIL); + P_InitAngle(water, forwardangle - ANGLE_180 + ANGLE_22h); + water->destscale = trailScale; + water->momx = mobj->momx; + water->momy = mobj->momy; + water->momz = mobj->momz; + P_SetScale(water, trailScale); + P_SetMobjState(water, curOverlayFrame); + + if (!S_SoundPlaying(mobj, sfx_s3kdbs)) + { + const INT32 volume = (min(trailScale, FRACUNIT) * 255) / FRACUNIT; + S_StartSoundAtVolume(mobj, sfx_s3kdbs, volume); + } + } + + // Little water sound while touching water - just a nicety. + if ((mobj->eflags & MFE_TOUCHWATER) && !(mobj->eflags & MFE_UNDERWATER)) + { + if (P_RandomChance(PR_BUBBLE, FRACUNIT/2) && leveltime % TICRATE == 0) + { + S_StartSound(mobj, sfx_floush); + } + } + } +} + static fixed_t K_FlameShieldDashVar(INT32 val) { // 1 second = 75% + 50% top speed diff --git a/src/k_kart.h b/src/k_kart.h index 71169fec0..117422ffe 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -145,6 +145,7 @@ boolean K_TripwirePass(player_t *player); boolean K_MovingHorizontally(mobj_t *mobj); boolean K_WaterRun(mobj_t *mobj); boolean K_WaterSkip(mobj_t *mobj); +void K_SpawnWaterRunParticles(mobj_t *mobj); void K_ApplyTripWire(player_t *player, tripwirestate_t state); INT16 K_GetSpindashChargeTime(player_t *player); fixed_t K_GetSpindashChargeSpeed(player_t *player); diff --git a/src/p_mobj.c b/src/p_mobj.c index ca77a8f14..3ab7b2c3b 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3284,10 +3284,23 @@ void P_MobjCheckWater(mobj_t *mobj) } } - // Spectators and dead players don't get to do any of the things after this. - if (p && (p->spectator || p->playerstate != PST_LIVE)) + if (P_IsObjectOnGround(mobj) == true) { - return; + mobj->waterskip = 0; + } + + if (p != NULL) + { + // Spectators and dead players don't get to do any of the things after this. + if (p->spectator || p->playerstate != PST_LIVE) + { + return; + } + } + + if (mobj->flags & MF_APPLYTERRAIN) + { + K_SpawnWaterRunParticles(mobj); } // The rest of this code only executes on a water state change. @@ -3296,11 +3309,6 @@ void P_MobjCheckWater(mobj_t *mobj) return; } - if (P_IsObjectOnGround(mobj) == true) - { - mobj->waterskip = 0; - } - if (p != NULL && p->curshield != KSHIELD_BUBBLE && mobj->waterskip == 0 @@ -6795,11 +6803,13 @@ static boolean P_MobjRegularThink(mobj_t *mobj) case MT_ORBINAUT: { Obj_OrbinautThink(mobj); + P_MobjCheckWater(mobj); break; } case MT_JAWZ: { Obj_JawzThink(mobj); + P_MobjCheckWater(mobj); break; } case MT_EGGMANITEM: @@ -6863,6 +6873,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (mobj->threshold > 0) mobj->threshold--; + + P_MobjCheckWater(mobj); } break; case MT_SINK: diff --git a/src/p_user.c b/src/p_user.c index 3c3f67449..ca8b10c62 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2292,100 +2292,6 @@ void P_MovePlayer(player_t *player) //GAMEPLAY STUFF// ////////////////// - if (((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height >= player->mo->watertop && player->mo->z <= player->mo->watertop) - || (player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height >= player->mo->waterbottom && player->mo->z <= player->mo->waterbottom)) - && (player->speed > runspd) - && player->mo->momz == 0 && player->carry != CR_SLIDING && !player->spectator) - { - fixed_t playerTopSpeed = K_GetKartSpeed(player, false, false); - fixed_t trailScale = FixedMul(FixedDiv(player->speed - runspd, playerTopSpeed - runspd), mapobjectscale); - - if (playerTopSpeed > runspd) - trailScale = FixedMul(FixedDiv(player->speed - runspd, playerTopSpeed - runspd), mapobjectscale); - else - trailScale = mapobjectscale; // Scaling is based off difference between runspeed and top speed - - if (trailScale > 0) - { - const angle_t forwardangle = K_MomentumAngle(player->mo); - const fixed_t playerVisualRadius = player->mo->radius + (8 * player->mo->scale); - const size_t numFrames = S_WATERTRAIL8 - S_WATERTRAIL1; - const statenum_t curOverlayFrame = S_WATERTRAIL1 + (leveltime % numFrames); - const statenum_t curUnderlayFrame = S_WATERTRAILUNDERLAY1 + (leveltime % numFrames); - fixed_t x1, x2, y1, y2; - mobj_t *water; - - x1 = player->mo->x + player->mo->momx + P_ReturnThrustX(player->mo, forwardangle + ANGLE_90, playerVisualRadius); - y1 = player->mo->y + player->mo->momy + P_ReturnThrustY(player->mo, forwardangle + ANGLE_90, playerVisualRadius); - x1 = x1 + P_ReturnThrustX(player->mo, forwardangle, playerVisualRadius); - y1 = y1 + P_ReturnThrustY(player->mo, forwardangle, playerVisualRadius); - - x2 = player->mo->x + player->mo->momx + P_ReturnThrustX(player->mo, forwardangle - ANGLE_90, playerVisualRadius); - y2 = player->mo->y + player->mo->momy + P_ReturnThrustY(player->mo, forwardangle - ANGLE_90, playerVisualRadius); - x2 = x2 + P_ReturnThrustX(player->mo, forwardangle, playerVisualRadius); - y2 = y2 + P_ReturnThrustY(player->mo, forwardangle, playerVisualRadius); - - // Left - // underlay - water = P_SpawnMobj(x1, y1, - ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_WATERTRAILUNDERLAY].height, player->mo->scale) : player->mo->watertop), MT_WATERTRAILUNDERLAY); - P_InitAngle(water, forwardangle - ANGLE_180 - ANGLE_22h); - water->destscale = trailScale; - water->momx = player->mo->momx; - water->momy = player->mo->momy; - water->momz = player->mo->momz; - P_SetScale(water, trailScale); - P_SetMobjState(water, curUnderlayFrame); - - // overlay - water = P_SpawnMobj(x1, y1, - ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_WATERTRAIL].height, player->mo->scale) : player->mo->watertop), MT_WATERTRAIL); - P_InitAngle(water, forwardangle - ANGLE_180 - ANGLE_22h); - water->destscale = trailScale; - water->momx = player->mo->momx; - water->momy = player->mo->momy; - water->momz = player->mo->momz; - P_SetScale(water, trailScale); - P_SetMobjState(water, curOverlayFrame); - - // Right - // Underlay - water = P_SpawnMobj(x2, y2, - ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_WATERTRAILUNDERLAY].height, player->mo->scale) : player->mo->watertop), MT_WATERTRAILUNDERLAY); - P_InitAngle(water, forwardangle - ANGLE_180 + ANGLE_22h); - water->destscale = trailScale; - water->momx = player->mo->momx; - water->momy = player->mo->momy; - water->momz = player->mo->momz; - P_SetScale(water, trailScale); - P_SetMobjState(water, curUnderlayFrame); - - // Overlay - water = P_SpawnMobj(x2, y2, - ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_WATERTRAIL].height, player->mo->scale) : player->mo->watertop), MT_WATERTRAIL); - P_InitAngle(water, forwardangle - ANGLE_180 + ANGLE_22h); - water->destscale = trailScale; - water->momx = player->mo->momx; - water->momy = player->mo->momy; - water->momz = player->mo->momz; - P_SetScale(water, trailScale); - P_SetMobjState(water, curOverlayFrame); - - if (!S_SoundPlaying(player->mo, sfx_s3kdbs)) - { - const INT32 volume = (min(trailScale, FRACUNIT) * 255) / FRACUNIT; - S_StartSoundAtVolume(player->mo, sfx_s3kdbs, volume); - } - } - } - - // Little water sound while touching water - just a nicety. - if ((player->mo->eflags & MFE_TOUCHWATER) && !(player->mo->eflags & MFE_UNDERWATER) && !player->spectator) - { - if (P_RandomChance(PR_BUBBLE, FRACUNIT/2) && leveltime % TICRATE == 0) - S_StartSound(player->mo, sfx_floush); - } - //////////////////////////// //SPINNING AND SPINDASHING// //////////////////////////// From e34ec94721d3d9e57333fd7f49f8b9e153e1088e Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 18:14:44 -0400 Subject: [PATCH 31/63] Smoothly adjust underwater turn nerf The actual issue was that turning was nerfed by a flat x0.5 when strafing was enabled, but the strafe amount was speed based. This meant that you got way less turning at low speed, and no strafe to make up for it. --- src/k_kart.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 43e14fbdd..bf7200b8a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8974,6 +8974,16 @@ INT16 K_UpdateSteeringValue(INT16 inputSteering, INT16 destSteering) return outputSteering; } +static fixed_t K_GetUnderwaterStrafeMul(player_t *player) +{ + const fixed_t minSpeed = 11 * player->mo->scale; + fixed_t baseline = INT32_MAX; + + baseline = 2 * K_GetKartSpeed(player, false, true) / 3; + + return max(0, FixedDiv(player->speed - minSpeed, baseline - minSpeed)); +} + INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) { fixed_t turnfixed = turnvalue * FRACUNIT; @@ -9051,10 +9061,10 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) turnfixed = FixedMul(turnfixed, FRACUNIT + player->handleboost); } - if ((player->mo->eflags & MFE_UNDERWATER) && - player->speed > 11 * player->mo->scale) + if (player->mo->eflags & MFE_UNDERWATER) { - turnfixed /= 2; + fixed_t div = min(FRACUNIT + K_GetUnderwaterStrafeMul(player), 2*FRACUNIT); + turnfixed = FixedDiv(turnfixed, div); } // Weight has a small effect on turning @@ -9065,18 +9075,15 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) INT32 K_GetUnderwaterTurnAdjust(player_t *player) { - if ((player->mo->eflags & MFE_UNDERWATER) && - player->speed > 11 * player->mo->scale) + if (player->mo->eflags & MFE_UNDERWATER) { INT32 steer = (K_GetKartTurnValue(player, player->steering) << TICCMD_REDUCE); - fixed_t minimum = INT32_MAX; if (!player->drift) steer = 9 * steer / 5; - minimum = 2 * K_GetKartSpeed(player, false, true) / 3; - return FixedMul(steer, 8 * FixedDiv(max(player->speed, minimum), minimum)); + return FixedMul(steer, 8 * K_GetUnderwaterStrafeMul(player)); } else return 0; From 66da84f1f7398640d1cfe8a3327b5f9f468b1741 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 19:18:06 -0400 Subject: [PATCH 32/63] Fixes for various maps - Don't skip on sloped water. Prevents water skipping on the top of the waterfall and then continuing the skip onto the water at the bottom in Aqueduct Crystal. - Fix Nova Shore regression in this branch by prevents water running if you can step down onto real ground. --- src/p_mobj.c | 51 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 3ab7b2c3b..b7814d0db 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3097,8 +3097,12 @@ boolean P_CanRunOnWater(mobj_t *mobj, ffloor_t *rover) player_t *player = mobj->player; fixed_t surfaceheight = INT32_MAX; - fixed_t mobjbottom = INT32_MAX; fixed_t surfDiff = INT32_MAX; + + fixed_t floorheight = INT32_MAX; + fixed_t floorDiff = INT32_MAX; + + fixed_t mobjbottom = INT32_MAX; fixed_t maxStep = INT32_MAX; boolean doifit = false; @@ -3142,38 +3146,48 @@ boolean P_CanRunOnWater(mobj_t *mobj, ffloor_t *rover) { ourZAng = mobj->standingslope->zangle; } - + waterSlope = (flip ? *rover->b_slope : *rover->t_slope); if (waterSlope != NULL) { waterZAng = waterSlope->zangle; } - + if (ourZAng != waterZAng) { // The surface slopes are different. return false; } - + surfaceheight = flip ? P_GetFFloorBottomZAt(rover, mobj->x, mobj->y) : P_GetFFloorTopZAt(rover, mobj->x, mobj->y); mobjbottom = flip ? (mobj->z + mobj->height) : mobj->z; - + doifit = flip ? (surfaceheight - mobj->floorz >= mobj->height) : (mobj->ceilingz - surfaceheight >= mobj->height); - + if (!doifit) { // Object can't fit in this space. return false; } - - surfDiff = flip ? (surfaceheight - mobjbottom) : (mobjbottom - surfaceheight); + maxStep = P_GetThingStepUp(mobj); + + surfDiff = flip ? (surfaceheight - mobjbottom) : (mobjbottom - surfaceheight); if (surfDiff <= maxStep && surfDiff >= 0) { // We start water run IF we can step-down! + floorheight = flip ? P_GetSectorCeilingZAt(mobj->subsector->sector, mobj->x, mobj->y) : P_GetSectorFloorZAt(mobj->subsector->sector, mobj->x, mobj->y); + floorDiff = flip ? (floorheight - mobjbottom) : (mobjbottom - floorheight); + if (floorDiff <= maxStep && floorDiff >= 0) + { + // ... but NOT if real floor is in range. + // FIXME: Count solid FOFs in this check + return false; + } + return true; } - + return false; } @@ -3202,6 +3216,8 @@ void P_MobjCheckWater(mobj_t *mobj) boolean wasgroundpounding = false; fixed_t top2 = P_GetSectorCeilingZAt(sector, mobj->x, mobj->y); fixed_t bot2 = P_GetSectorFloorZAt(sector, mobj->x, mobj->y); + pslope_t *topslope = NULL; + pslope_t *bottomslope = NULL; // Default if no water exists. mobj->watertop = mobj->waterbottom = mobj->z - 1000*FRACUNIT; @@ -3244,6 +3260,9 @@ void P_MobjCheckWater(mobj_t *mobj) mobj->watertop = topheight; mobj->waterbottom = bottomheight; + topslope = *rover->t_slope; + bottomslope = *rover->b_slope; + // Just touching the water? if (((mobj->eflags & MFE_VERTICALFLIP) && thingtop - height < bottomheight) || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + height > topheight)) @@ -3281,6 +3300,8 @@ void P_MobjCheckWater(mobj_t *mobj) mobj->watertop = mobj->z; mobj->waterbottom = mobj->z - height; } + + topslope = bottomslope = NULL; } } @@ -3323,6 +3344,7 @@ void P_MobjCheckWater(mobj_t *mobj) fixed_t waterZ = INT32_MAX; fixed_t solidZ = INT32_MAX; fixed_t diff = INT32_MAX; + INT32 waterDelta = 0; fixed_t thingZ = INT32_MAX; boolean splashValid = false; @@ -3331,11 +3353,19 @@ void P_MobjCheckWater(mobj_t *mobj) { waterZ = mobj->waterbottom; solidZ = mobj->ceilingz; + if (bottomslope) + { + waterDelta = bottomslope->zdelta; + } } else { waterZ = mobj->watertop; solidZ = mobj->floorz; + if (topslope) + { + waterDelta = topslope->zdelta; + } } diff = waterZ - solidZ; @@ -3406,7 +3436,8 @@ void P_MobjCheckWater(mobj_t *mobj) P_SetScale(splish, mobj->scale); // skipping stone! - if (K_WaterSkip(mobj) == true) + if (K_WaterSkip(mobj) == true + && abs(waterDelta) < FRACUNIT/21) // Only on flat water { const fixed_t hop = 5 * mapobjectscale; From a3caba4f2044fe06d022d18cb8c1c58e973d4eb2 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 27 Sep 2022 23:44:22 -0700 Subject: [PATCH 33/63] Add P_IsKartFieldItem, an item that is not attached to a player --- src/p_mobj.c | 53 ++++++++++++++++++++++++++++++++++++++++------------ src/p_mobj.h | 1 + 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 9b08f0e75..396a31acf 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -4992,20 +4992,49 @@ cont: } // Kartitem stuff. + +// This item is never attached to a player -- it can DIE +// unconditionally in death sectors. +boolean P_IsKartFieldItem(INT32 type) +{ + switch (type) + { + case MT_BANANA: + case MT_EGGMANITEM: + case MT_ORBINAUT: + case MT_JAWZ: + case MT_SSMINE: + case MT_LANDMINE: + case MT_BALLHOG: + case MT_BUBBLESHIELDTRAP: + case MT_POGOSPRING: + case MT_SINK: + case MT_DROPTARGET: + return true; + + default: + return false; + } +} + boolean P_IsKartItem(INT32 type) { - if (type == MT_EGGMANITEM || type == MT_EGGMANITEM_SHIELD || - type == MT_BANANA || type == MT_BANANA_SHIELD || - type == MT_DROPTARGET || type == MT_DROPTARGET_SHIELD || - type == MT_ORBINAUT || type == MT_ORBINAUT_SHIELD || - type == MT_JAWZ || type == MT_JAWZ_SHIELD || - type == MT_SSMINE || type == MT_SSMINE_SHIELD || - type == MT_SINK || type == MT_SINK_SHIELD || - type == MT_SPB || type == MT_BALLHOG || type == MT_BUBBLESHIELDTRAP || - type == MT_LANDMINE) - return true; - else - return false; + switch (type) + { + case MT_EGGMANITEM_SHIELD: + case MT_BANANA_SHIELD: + case MT_DROPTARGET_SHIELD: + case MT_ORBINAUT_SHIELD: + case MT_JAWZ_SHIELD: + case MT_SSMINE_SHIELD: + case MT_SINK_SHIELD: + case MT_SPB: + case MT_HYUDORO: + return true; + + default: + return P_IsKartFieldItem(type); + } } // Called when a kart item "thinks" diff --git a/src/p_mobj.h b/src/p_mobj.h index 4cdacea6d..b31eeb6b9 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -499,6 +499,7 @@ void P_RunCachedActions(void); void P_AddCachedAction(mobj_t *mobj, INT32 statenum); // kartitem stuff: Returns true if the specified 'type' is one of the kart item constants we want in the kitemcap list +boolean P_IsKartFieldItem(INT32 type); boolean P_IsKartItem(INT32 type); void P_AddKartItem(mobj_t *thing); // needs to be called in k_kart.c void P_RunKartItems(void); From cf026462299f528ad753bcc47bb8ee20b032a7fa Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 27 Sep 2022 23:52:51 -0700 Subject: [PATCH 34/63] Add K_CanDeleteKartItem HAKAI --- src/p_mobj.c | 37 +++++++++++++++++++++---------------- src/p_mobj.h | 1 + 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 396a31acf..2cf01bd66 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2179,17 +2179,6 @@ boolean P_ZMovement(mobj_t *mo) case MT_BIGTUMBLEWEED: case MT_LITTLETUMBLEWEED: case MT_SHELL: - // SRB2kart stuff that should die in pits - // Shouldn't stop moving along the Z if there's no speed though! - case MT_EGGMANITEM: - case MT_BANANA: - case MT_ORBINAUT: - case MT_JAWZ: - case MT_BALLHOG: - case MT_SSMINE: - case MT_LANDMINE: - case MT_DROPTARGET: - case MT_BUBBLESHIELDTRAP: // Remove stuff from death pits. if (P_CheckDeathPitCollide(mo)) { @@ -2271,6 +2260,17 @@ boolean P_ZMovement(mobj_t *mo) } break; default: + // SRB2kart stuff that should die in pits + // Shouldn't stop moving along the Z if there's no speed though! + if (P_CanDeleteKartItem(mo->type)) + { + // Remove stuff from death pits. + if (P_CheckDeathPitCollide(mo)) + { + P_RemoveMobj(mo); + return false; + } + } break; } @@ -5037,6 +5037,15 @@ boolean P_IsKartItem(INT32 type) } } +// This item can die in death sectors. There may be some +// special conditions for items that don't switch types... +// TODO: just make a general function for things that should +// die like this? +boolean P_CanDeleteKartItem(INT32 type) +{ + return P_IsKartFieldItem(type); +} + // Called when a kart item "thinks" void P_AddKartItem(mobj_t *thing) { @@ -9329,11 +9338,7 @@ void P_MobjThinker(mobj_t *mobj) return; // Destroy items sector special - if (mobj->type == MT_BANANA || mobj->type == MT_EGGMANITEM - || mobj->type == MT_ORBINAUT || mobj->type == MT_BALLHOG - || mobj->type == MT_JAWZ - || mobj->type == MT_SSMINE || mobj->type == MT_BUBBLESHIELDTRAP - || mobj->type == MT_LANDMINE) + if (P_CanDeleteKartItems(mobj->type)) { if (mobj->health > 0 && P_MobjTouchingSectorSpecial(mobj, 4, 7, true)) { diff --git a/src/p_mobj.h b/src/p_mobj.h index b31eeb6b9..3b3c7832f 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -501,6 +501,7 @@ void P_AddCachedAction(mobj_t *mobj, INT32 statenum); // kartitem stuff: Returns true if the specified 'type' is one of the kart item constants we want in the kitemcap list boolean P_IsKartFieldItem(INT32 type); boolean P_IsKartItem(INT32 type); +boolean P_CanDeleteKartItem(INT32 type); void P_AddKartItem(mobj_t *thing); // needs to be called in k_kart.c void P_RunKartItems(void); From d66b82605b9b8bdd52c5fb9dd0a969cd6cb006fc Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 23 Sep 2022 02:09:33 -0700 Subject: [PATCH 35/63] Cleanup order and indentation of item definitions --- src/d_netcmd.c | 4 +- src/d_netcmd.h | 37 +++++++++++++--- src/k_hud.c | 22 ++++----- src/k_kart.c | 118 ++++++++++++++++++++++++------------------------- 4 files changed, 102 insertions(+), 79 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index dcc351fb9..b4a4f4761 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -362,7 +362,6 @@ consvar_t cv_joyscale[MAXSPLITSCREENPLAYERS] = { //Alam: Dummy for save #endif // SRB2kart -consvar_t cv_superring = CVAR_INIT ("superring", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_sneaker = CVAR_INIT ("sneaker", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_rocketsneaker = CVAR_INIT ("rocketsneaker", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_invincibility = CVAR_INIT ("invincibility", "On", CV_NETVAR, CV_OnOff, NULL); @@ -372,7 +371,6 @@ consvar_t cv_orbinaut = CVAR_INIT ("orbinaut", "On", CV_NETVAR, CV_OnOff, consvar_t cv_jawz = CVAR_INIT ("jawz", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_mine = CVAR_INIT ("mine", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_landmine = CVAR_INIT ("landmine", "On", CV_NETVAR, CV_OnOff, NULL); -consvar_t cv_droptarget = CVAR_INIT ("droptarget", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_ballhog = CVAR_INIT ("ballhog", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_selfpropelledbomb = CVAR_INIT ("selfpropelledbomb", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_grow = CVAR_INIT ("grow", "On", CV_NETVAR, CV_OnOff, NULL); @@ -382,7 +380,9 @@ consvar_t cv_bubbleshield = CVAR_INIT ("bubbleshield", "On", CV_NETVAR, CV_O consvar_t cv_flameshield = CVAR_INIT ("flameshield", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_hyudoro = CVAR_INIT ("hyudoro", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_pogospring = CVAR_INIT ("pogospring", "On", CV_NETVAR, CV_OnOff, NULL); +consvar_t cv_superring = CVAR_INIT ("superring", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_kitchensink = CVAR_INIT ("kitchensink", "On", CV_NETVAR, CV_OnOff, NULL); +consvar_t cv_droptarget = CVAR_INIT ("droptarget", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_dualsneaker = CVAR_INIT ("dualsneaker", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_triplesneaker = CVAR_INIT ("triplesneaker", "On", CV_NETVAR, CV_OnOff, NULL); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 0114c726f..2f12db961 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -72,14 +72,37 @@ extern consvar_t cv_pause; extern consvar_t cv_restrictskinchange, cv_allowteamchange, cv_maxplayers, cv_respawntime; // SRB2kart items -extern consvar_t cv_superring, cv_sneaker, cv_rocketsneaker, cv_invincibility, cv_banana; -extern consvar_t cv_eggmanmonitor, cv_orbinaut, cv_jawz, cv_mine, cv_landmine, cv_droptarget; -extern consvar_t cv_ballhog, cv_selfpropelledbomb, cv_grow, cv_shrink; -extern consvar_t cv_lightningshield, cv_bubbleshield, cv_flameshield; -extern consvar_t cv_hyudoro, cv_pogospring, cv_kitchensink; +extern consvar_t + cv_sneaker, + cv_rocketsneaker, + cv_invincibility, + cv_banana, + cv_eggmanmonitor, + cv_orbinaut, + cv_jawz, + cv_mine, + cv_landmine, + cv_ballhog, + cv_selfpropelledbomb, + cv_grow, + cv_shrink, + cv_lightningshield, + cv_bubbleshield, + cv_flameshield, + cv_hyudoro, + cv_pogospring, + cv_superring, + cv_kitchensink, + cv_droptarget; -extern consvar_t cv_dualsneaker, cv_triplesneaker, cv_triplebanana, cv_decabanana; -extern consvar_t cv_tripleorbinaut, cv_quadorbinaut, cv_dualjawz; +extern consvar_t + cv_dualsneaker, + cv_triplesneaker, + cv_triplebanana, + cv_decabanana, + cv_tripleorbinaut, + cv_quadorbinaut, + cv_dualjawz; extern consvar_t cv_kartminimap; extern consvar_t cv_kartcheck; diff --git a/src/k_hud.c b/src/k_hud.c index 14e526dd2..2d752a7ef 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -111,7 +111,7 @@ static patch_t *kp_itemtimer[2]; static patch_t *kp_itemmulsticker[2]; static patch_t *kp_itemx; -static patch_t *kp_superring[2]; +static patch_t *kp_sadface[2]; static patch_t *kp_sneaker[2]; static patch_t *kp_rocketsneaker[2]; static patch_t *kp_invincibility[13]; @@ -121,7 +121,6 @@ static patch_t *kp_orbinaut[5]; static patch_t *kp_jawz[2]; static patch_t *kp_mine[2]; static patch_t *kp_landmine[2]; -static patch_t *kp_droptarget[2]; static patch_t *kp_ballhog[2]; static patch_t *kp_selfpropelledbomb[2]; static patch_t *kp_grow[2]; @@ -131,8 +130,9 @@ static patch_t *kp_bubbleshield[2]; static patch_t *kp_flameshield[2]; static patch_t *kp_hyudoro[2]; static patch_t *kp_pogospring[2]; +static patch_t *kp_superring[2]; static patch_t *kp_kitchensink[2]; -static patch_t *kp_sadface[2]; +static patch_t *kp_droptarget[2]; static patch_t *kp_check[6]; @@ -390,7 +390,7 @@ void K_LoadKartHUDGraphics(void) HU_UpdatePatch(&kp_itemmulsticker[0], "K_ITMUL"); HU_UpdatePatch(&kp_itemx, "K_ITX"); - HU_UpdatePatch(&kp_superring[0], "K_ITRING"); + HU_UpdatePatch(&kp_sadface[0], "K_ITSAD"); HU_UpdatePatch(&kp_sneaker[0], "K_ITSHOE"); HU_UpdatePatch(&kp_rocketsneaker[0], "K_ITRSHE"); @@ -411,7 +411,6 @@ void K_LoadKartHUDGraphics(void) HU_UpdatePatch(&kp_jawz[0], "K_ITJAWZ"); HU_UpdatePatch(&kp_mine[0], "K_ITMINE"); HU_UpdatePatch(&kp_landmine[0], "K_ITLNDM"); - HU_UpdatePatch(&kp_droptarget[0], "K_ITDTRG"); HU_UpdatePatch(&kp_ballhog[0], "K_ITBHOG"); HU_UpdatePatch(&kp_selfpropelledbomb[0], "K_ITSPB"); HU_UpdatePatch(&kp_grow[0], "K_ITGROW"); @@ -421,8 +420,9 @@ void K_LoadKartHUDGraphics(void) HU_UpdatePatch(&kp_flameshield[0], "K_ITFLMS"); HU_UpdatePatch(&kp_hyudoro[0], "K_ITHYUD"); HU_UpdatePatch(&kp_pogospring[0], "K_ITPOGO"); + HU_UpdatePatch(&kp_superring[0], "K_ITRING"); HU_UpdatePatch(&kp_kitchensink[0], "K_ITSINK"); - HU_UpdatePatch(&kp_sadface[0], "K_ITSAD"); + HU_UpdatePatch(&kp_droptarget[0], "K_ITDTRG"); sprintf(buffer, "FSMFGxxx"); for (i = 0; i < 104; i++) @@ -447,7 +447,7 @@ void K_LoadKartHUDGraphics(void) HU_UpdatePatch(&kp_itemtimer[1], "K_ISIMER"); HU_UpdatePatch(&kp_itemmulsticker[1], "K_ISMUL"); - HU_UpdatePatch(&kp_superring[1], "K_ISRING"); + HU_UpdatePatch(&kp_sadface[1], "K_ISSAD"); HU_UpdatePatch(&kp_sneaker[1], "K_ISSHOE"); HU_UpdatePatch(&kp_rocketsneaker[1], "K_ISRSHE"); sprintf(buffer, "K_ISINVx"); @@ -462,7 +462,6 @@ void K_LoadKartHUDGraphics(void) HU_UpdatePatch(&kp_jawz[1], "K_ISJAWZ"); HU_UpdatePatch(&kp_mine[1], "K_ISMINE"); HU_UpdatePatch(&kp_landmine[1], "K_ISLNDM"); - HU_UpdatePatch(&kp_droptarget[1], "K_ISDTRG"); HU_UpdatePatch(&kp_ballhog[1], "K_ISBHOG"); HU_UpdatePatch(&kp_selfpropelledbomb[1], "K_ISSPB"); HU_UpdatePatch(&kp_grow[1], "K_ISGROW"); @@ -472,8 +471,9 @@ void K_LoadKartHUDGraphics(void) HU_UpdatePatch(&kp_flameshield[1], "K_ISFLMS"); HU_UpdatePatch(&kp_hyudoro[1], "K_ISHYUD"); HU_UpdatePatch(&kp_pogospring[1], "K_ISPOGO"); + HU_UpdatePatch(&kp_superring[1], "K_ISRING"); HU_UpdatePatch(&kp_kitchensink[1], "K_ISSINK"); - HU_UpdatePatch(&kp_sadface[1], "K_ISSAD"); + HU_UpdatePatch(&kp_droptarget[1], "K_ISDTRG"); sprintf(buffer, "FSMFSxxx"); for (i = 0; i < 104; i++) @@ -662,8 +662,6 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny) return (tiny ? "K_ISMINE" : "K_ITMINE"); case KITEM_LANDMINE: return (tiny ? "K_ISLNDM" : "K_ITLNDM"); - case KITEM_DROPTARGET: - return (tiny ? "K_ISDTRG" : "K_ITDTRG"); case KITEM_BALLHOG: return (tiny ? "K_ISBHOG" : "K_ITBHOG"); case KITEM_SPB: @@ -686,6 +684,8 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny) return (tiny ? "K_ISRING" : "K_ITRING"); case KITEM_KITCHENSINK: return (tiny ? "K_ISSINK" : "K_ITSINK"); + case KITEM_DROPTARGET: + return (tiny ? "K_ISDTRG" : "K_ITDTRG"); case KRITEM_TRIPLEORBINAUT: return (tiny ? "K_ISORBN" : "K_ITORB3"); case KRITEM_QUADORBINAUT: diff --git a/src/k_kart.c b/src/k_kart.c index 5aa1aaeba..36dd53b46 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -218,7 +218,6 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_jawz); CV_RegisterVar(&cv_mine); CV_RegisterVar(&cv_landmine); - CV_RegisterVar(&cv_droptarget); CV_RegisterVar(&cv_ballhog); CV_RegisterVar(&cv_selfpropelledbomb); CV_RegisterVar(&cv_grow); @@ -230,6 +229,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_pogospring); CV_RegisterVar(&cv_superring); CV_RegisterVar(&cv_kitchensink); + CV_RegisterVar(&cv_droptarget); CV_RegisterVar(&cv_dualsneaker); CV_RegisterVar(&cv_triplesneaker); @@ -350,68 +350,68 @@ consvar_t *KartItemCVars[NUMKARTRESULTS-1] = // Less ugly 2D arrays static UINT8 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = { - //P-Odds 0 1 2 3 4 5 6 7 - /*Sneaker*/ { 0, 0, 2, 4, 6, 0, 0, 0 }, // Sneaker - /*Rocket Sneaker*/ { 0, 0, 0, 0, 0, 2, 4, 6 }, // Rocket Sneaker - /*Invincibility*/ { 0, 0, 0, 0, 3, 4, 5, 7 }, // Invincibility - /*Banana*/ { 2, 3, 1, 0, 0, 0, 0, 0 }, // Banana - /*Eggman Monitor*/ { 1, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor - /*Orbinaut*/ { 5, 5, 2, 2, 0, 0, 0, 0 }, // Orbinaut - /*Jawz*/ { 0, 4, 2, 1, 0, 0, 0, 0 }, // Jawz - /*Mine*/ { 0, 3, 3, 1, 0, 0, 0, 0 }, // Mine - /*Land Mine*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Land Mine - /*Ballhog*/ { 0, 0, 2, 2, 0, 0, 0, 0 }, // Ballhog - /*Self-Propelled Bomb*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Self-Propelled Bomb - /*Grow*/ { 0, 0, 0, 1, 2, 3, 0, 0 }, // Grow - /*Shrink*/ { 0, 0, 0, 0, 0, 1, 3, 2 }, // Shrink - /*Lightning Shield*/ { 1, 0, 0, 0, 0, 0, 0, 0 }, // Lightning Shield - /*Bubble Shield*/ { 0, 1, 2, 1, 0, 0, 0, 0 }, // Bubble Shield - /*Flame Shield*/ { 0, 0, 0, 0, 0, 1, 3, 5 }, // Flame Shield - /*Hyudoro*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Hyudoro - /*Pogo Spring*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Pogo Spring - /*Super Ring*/ { 2, 1, 1, 0, 0, 0, 0, 0 }, // Super Ring - /*Kitchen Sink*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink - /*Drop Target*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target - /*Sneaker x2*/ { 0, 0, 2, 2, 2, 0, 0, 0 }, // Sneaker x2 - /*Sneaker x3*/ { 0, 0, 0, 1, 6, 9, 5, 0 }, // Sneaker x3 - /*Banana x3*/ { 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3 - /*Banana x10*/ { 0, 0, 0, 1, 0, 0, 0, 0 }, // Banana x10 - /*Orbinaut x3*/ { 0, 0, 1, 0, 0, 0, 0, 0 }, // Orbinaut x3 - /*Orbinaut x4*/ { 0, 0, 0, 2, 0, 0, 0, 0 }, // Orbinaut x4 - /*Jawz x2*/ { 0, 0, 1, 2, 1, 0, 0, 0 } // Jawz x2 + //B C D E F G H I + { 0, 0, 2, 4, 6, 0, 0, 0 }, // Sneaker + { 0, 0, 0, 0, 0, 2, 4, 6 }, // Rocket Sneaker + { 0, 0, 0, 0, 3, 4, 5, 7 }, // Invincibility + { 2, 3, 1, 0, 0, 0, 0, 0 }, // Banana + { 1, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor + { 5, 5, 2, 2, 0, 0, 0, 0 }, // Orbinaut + { 0, 4, 2, 1, 0, 0, 0, 0 }, // Jawz + { 0, 3, 3, 1, 0, 0, 0, 0 }, // Mine + { 3, 0, 0, 0, 0, 0, 0, 0 }, // Land Mine + { 0, 0, 2, 2, 0, 0, 0, 0 }, // Ballhog + { 0, 0, 0, 0, 0, 2, 4, 0 }, // Self-Propelled Bomb + { 0, 0, 0, 1, 2, 3, 0, 0 }, // Grow + { 0, 0, 0, 0, 0, 1, 3, 2 }, // Shrink + { 1, 0, 0, 0, 0, 0, 0, 0 }, // Lightning Shield + { 0, 1, 2, 1, 0, 0, 0, 0 }, // Bubble Shield + { 0, 0, 0, 0, 0, 1, 3, 5 }, // Flame Shield + { 3, 0, 0, 0, 0, 0, 0, 0 }, // Hyudoro + { 0, 0, 0, 0, 0, 0, 0, 0 }, // Pogo Spring + { 2, 1, 1, 0, 0, 0, 0, 0 }, // Super Ring + { 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink + { 3, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target + { 0, 0, 2, 2, 2, 0, 0, 0 }, // Sneaker x2 + { 0, 0, 0, 1, 6, 9, 5, 0 }, // Sneaker x3 + { 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3 + { 0, 0, 0, 1, 0, 0, 0, 0 }, // Banana x10 + { 0, 0, 1, 0, 0, 0, 0, 0 }, // Orbinaut x3 + { 0, 0, 0, 2, 0, 0, 0, 0 }, // Orbinaut x4 + { 0, 0, 1, 2, 1, 0, 0, 0 } // Jawz x2 }; static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS][2] = { - //P-Odds 0 1 - /*Sneaker*/ { 2, 1 }, // Sneaker - /*Rocket Sneaker*/ { 0, 0 }, // Rocket Sneaker - /*Invincibility*/ { 4, 1 }, // Invincibility - /*Banana*/ { 0, 0 }, // Banana - /*Eggman Monitor*/ { 1, 0 }, // Eggman Monitor - /*Orbinaut*/ { 8, 0 }, // Orbinaut - /*Jawz*/ { 8, 1 }, // Jawz - /*Mine*/ { 6, 1 }, // Mine - /*Land Mine*/ { 2, 0 }, // Land Mine - /*Ballhog*/ { 2, 1 }, // Ballhog - /*Self-Propelled Bomb*/ { 0, 0 }, // Self-Propelled Bomb - /*Grow*/ { 2, 1 }, // Grow - /*Shrink*/ { 0, 0 }, // Shrink - /*Lightning Shield*/ { 4, 0 }, // Lightning Shield - /*Bubble Shield*/ { 1, 0 }, // Bubble Shield - /*Flame Shield*/ { 1, 0 }, // Flame Shield - /*Hyudoro*/ { 2, 0 }, // Hyudoro - /*Pogo Spring*/ { 3, 0 }, // Pogo Spring - /*Super Ring*/ { 0, 0 }, // Super Ring - /*Kitchen Sink*/ { 0, 0 }, // Kitchen Sink - /*Drop Target*/ { 2, 0 }, // Drop Target - /*Sneaker x2*/ { 0, 0 }, // Sneaker x2 - /*Sneaker x3*/ { 0, 1 }, // Sneaker x3 - /*Banana x3*/ { 0, 0 }, // Banana x3 - /*Banana x10*/ { 1, 1 }, // Banana x10 - /*Orbinaut x3*/ { 2, 0 }, // Orbinaut x3 - /*Orbinaut x4*/ { 1, 1 }, // Orbinaut x4 - /*Jawz x2*/ { 5, 1 } // Jawz x2 + //K L + { 2, 1 }, // Sneaker + { 0, 0 }, // Rocket Sneaker + { 4, 1 }, // Invincibility + { 0, 0 }, // Banana + { 1, 0 }, // Eggman Monitor + { 8, 0 }, // Orbinaut + { 8, 1 }, // Jawz + { 6, 1 }, // Mine + { 2, 0 }, // Land Mine + { 2, 1 }, // Ballhog + { 0, 0 }, // Self-Propelled Bomb + { 2, 1 }, // Grow + { 0, 0 }, // Shrink + { 4, 0 }, // Lightning Shield + { 1, 0 }, // Bubble Shield + { 1, 0 }, // Flame Shield + { 2, 0 }, // Hyudoro + { 3, 0 }, // Pogo Spring + { 0, 0 }, // Super Ring + { 0, 0 }, // Kitchen Sink + { 2, 0 }, // Drop Target + { 0, 0 }, // Sneaker x2 + { 0, 1 }, // Sneaker x3 + { 0, 0 }, // Banana x3 + { 1, 1 }, // Banana x10 + { 2, 0 }, // Orbinaut x3 + { 1, 1 }, // Orbinaut x4 + { 5, 1 } // Jawz x2 }; #define DISTVAR (2048) // Magic number distance for use with item roulette tiers From 7b301452cc749becec5010bcc1221400d3250871 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 24 Aug 2022 21:57:51 -0700 Subject: [PATCH 36/63] Add Garden Top related states MT_GARDENTOP S_GARDENTOP KITEM_GARDENTOP KSHIELD_TOP --- src/d_netcmd.c | 1 + src/d_netcmd.h | 3 ++- src/d_player.h | 4 +++- src/deh_tables.c | 11 +++++++++ src/info.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ src/info.h | 10 ++++++++ src/k_hud.c | 7 ++++++ src/k_kart.c | 21 ++++++++++++++--- 8 files changed, 113 insertions(+), 5 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index b4a4f4761..32d2cd5dd 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -383,6 +383,7 @@ consvar_t cv_pogospring = CVAR_INIT ("pogospring", "On", CV_NETVAR, CV_OnOf consvar_t cv_superring = CVAR_INIT ("superring", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_kitchensink = CVAR_INIT ("kitchensink", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_droptarget = CVAR_INIT ("droptarget", "On", CV_NETVAR, CV_OnOff, NULL); +consvar_t cv_gardentop = CVAR_INIT ("gardentop", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_dualsneaker = CVAR_INIT ("dualsneaker", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_triplesneaker = CVAR_INIT ("triplesneaker", "On", CV_NETVAR, CV_OnOff, NULL); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 2f12db961..95e7a47f0 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -93,7 +93,8 @@ extern consvar_t cv_pogospring, cv_superring, cv_kitchensink, - cv_droptarget; + cv_droptarget, + cv_gardentop; extern consvar_t cv_dualsneaker, diff --git a/src/d_player.h b/src/d_player.h index f2943dd18..4ac51e245 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -159,7 +159,8 @@ Run this macro, then #undef FOREACH afterward FOREACH (POGOSPRING, 18),\ FOREACH (SUPERRING, 19),\ FOREACH (KITCHENSINK, 20),\ - FOREACH (DROPTARGET, 21) + FOREACH (DROPTARGET, 21),\ + FOREACH (GARDENTOP, 22) typedef enum { @@ -187,6 +188,7 @@ typedef enum KSHIELD_LIGHTNING = 1, KSHIELD_BUBBLE = 2, KSHIELD_FLAME = 3, + KSHIELD_TOP = 4, NUMKARTSHIELDS } kartshields_t; diff --git a/src/deh_tables.c b/src/deh_tables.c index a0084ec85..23d1874e6 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3740,6 +3740,14 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_FLAMESHIELDLINE3", "S_FLAMESHIELDFLASH", + // Marble Garden Zone Spinning Top + "S_GARDENTOP_FLOATING", + "S_GARDENTOP_SINKING1", + "S_GARDENTOP_SINKING2", + "S_GARDENTOP_SINKING3", + "S_GARDENTOP_DEAD", + "S_GARDENTOPSPARK", + // Caked-Up Booty-Sheet Ghost "S_HYUDORO", @@ -5346,6 +5354,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_FLAMESHIELDUNDERLAY", "MT_FLAMESHIELDPAPER", "MT_BUBBLESHIELDTRAP", + "MT_GARDENTOP", + "MT_GARDENTOPSPARK", "MT_HYUDORO", "MT_HYUDORO_CENTER", @@ -6668,6 +6678,7 @@ struct int_const_s const INT_CONST[] = { {"KSHIELD_LIGHTNING",KSHIELD_LIGHTNING}, {"KSHIELD_BUBBLE",KSHIELD_BUBBLE}, {"KSHIELD_FLAME",KSHIELD_FLAME}, + {"KSHIELD_TOP",KSHIELD_TOP}, {"NUMKARTSHIELDS",NUMKARTSHIELDS}, // kartspinoutflags_t diff --git a/src/info.c b/src/info.c index a5fe03bf2..42abd5b2e 100644 --- a/src/info.c +++ b/src/info.c @@ -4320,6 +4320,13 @@ state_t states[NUMSTATES] = {SPR_FLML, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE|14, 7, {NULL}, 6, 1, S_NULL}, // S_FLAMESHIELDLINE3 {SPR_FLMF, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_FLAMESHIELDFLASH + {SPR_GTOP, FF_ANIMATE, -1, {NULL}, 5, 1, S_NULL}, // S_GARDENTOP_FLOATING + {SPR_GTOP, 0, 1, {NULL}, 5, 1, S_GARDENTOP_SINKING2}, // S_GARDENTOP_SINKING1 + {SPR_GTOP, 2, 1, {NULL}, 5, 1, S_GARDENTOP_SINKING3}, // S_GARDENTOP_SINKING2 + {SPR_GTOP, 4, 1, {NULL}, 5, 1, S_GARDENTOP_SINKING1}, // S_GARDENTOP_SINKING3 + {SPR_GTOP, FF_ANIMATE, 100, {A_Scream}, 5, 1, S_NULL}, // S_GARDENTOP_DEAD + {SPR_BDRF, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 5, 2, S_NULL}, // S_GARDENTOPSPARK + {SPR_HYUU, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_HYUDORO {SPR_GRWP, FF_FULLBRIGHT|FF_ANIMATE, 13, {NULL}, 7, 1, S_NULL}, // S_GROW_PARTICLE @@ -24065,6 +24072,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_GARDENTOP + -1, // doomednum + S_GARDENTOP_FLOATING, // spawnstate + 8, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 4, // reactiontime + sfx_s3k8b, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_GARDENTOP_DEAD, // deathstate + S_NULL, // xdeathstate + sfx_s3k7a, // deathsound + 40*FRACUNIT, // speed + 30*FRACUNIT, // radius + 68*FRACUNIT, // height + -1, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_GARDENTOPSPARK + -1, // doomednum + S_GARDENTOPSPARK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 8*FRACUNIT, // height + 1, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP|MF_NOSQUISH, // flags + S_NULL // raisestate + }, + { // MT_HYUDORO -1, // doomednum S_HYUDORO, // spawnstate diff --git a/src/info.h b/src/info.h index 29e2695bf..48850f5d0 100644 --- a/src/info.h +++ b/src/info.h @@ -4750,6 +4750,14 @@ typedef enum state S_FLAMESHIELDLINE3, S_FLAMESHIELDFLASH, + // Marble Garden Zone Spinning Top + S_GARDENTOP_FLOATING, + S_GARDENTOP_SINKING1, + S_GARDENTOP_SINKING2, + S_GARDENTOP_SINKING3, + S_GARDENTOP_DEAD, + S_GARDENTOPSPARK, + // Caked-Up Booty-Sheet Ghost S_HYUDORO, @@ -6392,6 +6400,8 @@ typedef enum mobj_type MT_FLAMESHIELDUNDERLAY, MT_FLAMESHIELDPAPER, MT_BUBBLESHIELDTRAP, + MT_GARDENTOP, + MT_GARDENTOPSPARK, MT_HYUDORO, MT_HYUDORO_CENTER, diff --git a/src/k_hud.c b/src/k_hud.c index 2d752a7ef..6b4703d2b 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -133,6 +133,7 @@ static patch_t *kp_pogospring[2]; static patch_t *kp_superring[2]; static patch_t *kp_kitchensink[2]; static patch_t *kp_droptarget[2]; +static patch_t *kp_gardentop[2]; static patch_t *kp_check[6]; @@ -423,6 +424,7 @@ void K_LoadKartHUDGraphics(void) HU_UpdatePatch(&kp_superring[0], "K_ITRING"); HU_UpdatePatch(&kp_kitchensink[0], "K_ITSINK"); HU_UpdatePatch(&kp_droptarget[0], "K_ITDTRG"); + HU_UpdatePatch(&kp_gardentop[0], "K_ITGTOP"); sprintf(buffer, "FSMFGxxx"); for (i = 0; i < 104; i++) @@ -474,6 +476,7 @@ void K_LoadKartHUDGraphics(void) HU_UpdatePatch(&kp_superring[1], "K_ISRING"); HU_UpdatePatch(&kp_kitchensink[1], "K_ISSINK"); HU_UpdatePatch(&kp_droptarget[1], "K_ISDTRG"); + HU_UpdatePatch(&kp_gardentop[1], "K_ISGTOP"); sprintf(buffer, "FSMFSxxx"); for (i = 0; i < 104; i++) @@ -686,6 +689,8 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny) return (tiny ? "K_ISSINK" : "K_ITSINK"); case KITEM_DROPTARGET: return (tiny ? "K_ISDTRG" : "K_ITDTRG"); + case KITEM_GARDENTOP: + return (tiny ? "K_ISGTOP" : "K_ITGTOP"); case KRITEM_TRIPLEORBINAUT: return (tiny ? "K_ISORBN" : "K_ITORB3"); case KRITEM_QUADORBINAUT: @@ -721,6 +726,7 @@ static patch_t *K_GetCachedItemPatch(INT32 item, UINT8 offset) kp_superring, kp_kitchensink, kp_droptarget, + kp_gardentop, }; if (item == KITEM_SAD || (item > KITEM_NONE && item < NUMKARTITEMS)) @@ -4456,6 +4462,7 @@ static void K_drawDistributionDebugger(void) kp_superring[1], kp_kitchensink[1], kp_droptarget[1], + kp_gardentop[1], kp_sneaker[1], kp_sneaker[1], diff --git a/src/k_kart.c b/src/k_kart.c index 36dd53b46..d556b97f4 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -230,6 +230,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_superring); CV_RegisterVar(&cv_kitchensink); CV_RegisterVar(&cv_droptarget); + CV_RegisterVar(&cv_gardentop); CV_RegisterVar(&cv_dualsneaker); CV_RegisterVar(&cv_triplesneaker); @@ -336,6 +337,7 @@ consvar_t *KartItemCVars[NUMKARTRESULTS-1] = &cv_superring, &cv_kitchensink, &cv_droptarget, + &cv_gardentop, &cv_dualsneaker, &cv_triplesneaker, &cv_triplebanana, @@ -372,6 +374,7 @@ static UINT8 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = { 2, 1, 1, 0, 0, 0, 0, 0 }, // Super Ring { 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink { 3, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target + { 0, 0, 0, 0, 0, 0, 0, 0 }, // Garden Top { 0, 0, 2, 2, 2, 0, 0, 0 }, // Sneaker x2 { 0, 0, 0, 1, 6, 9, 5, 0 }, // Sneaker x3 { 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3 @@ -405,6 +408,7 @@ static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS][2] = { 0, 0 }, // Super Ring { 0, 0 }, // Kitchen Sink { 2, 0 }, // Drop Target + { 0, 0 }, // Garden Top { 0, 0 }, // Sneaker x2 { 0, 1 }, // Sneaker x3 { 0, 0 }, // Banana x3 @@ -442,6 +446,7 @@ INT32 K_GetShieldFromItem(INT32 item) case KITEM_LIGHTNINGSHIELD: return KSHIELD_LIGHTNING; case KITEM_BUBBLESHIELD: return KSHIELD_BUBBLE; case KITEM_FLAMESHIELD: return KSHIELD_FLAME; + case KITEM_GARDENTOP: return KSHIELD_TOP; default: return KSHIELD_NONE; } } @@ -715,10 +720,20 @@ INT32 K_KartGetItemOdds( if (players[i].exiting) pexiting++; - if (shieldtype != KSHIELD_NONE && shieldtype == K_GetShieldFromItem(players[i].itemtype)) + switch (shieldtype) { - // Don't allow more than one of each shield type at a time - return 0; + case KSHIELD_NONE: + /* Marble Garden Top is not REALLY + a Sonic 3 shield */ + case KSHIELD_TOP: + break; + + default: + if (shieldtype == K_GetShieldFromItem(players[i].itemtype)) + { + // Don't allow more than one of each shield type at a time + return 0; + } } if (players[i].position == 1) From 77bc259986832fb0802759153c96ba57669b4f0f Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 23 Sep 2022 05:25:40 -0700 Subject: [PATCH 37/63] Separate water skipping condition into K_WaterSkip --- src/k_kart.c | 11 +++++++++++ src/k_kart.h | 1 + src/p_mobj.c | 5 +---- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index d556b97f4..646d0587b 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3277,6 +3277,17 @@ boolean K_WaterRun(player_t *player) return false; } +boolean K_WaterSkip(player_t *player) +{ + if (player->speed/3 > abs(player->mo->momz)) // Going more forward than horizontal, so you can skip across the water. + return true; + + if (player->speed > 20*mapobjectscale && player->waterskip) // Already skipped once, so you can skip once more! + return true; + + return false; +} + static fixed_t K_FlameShieldDashVar(INT32 val) { // 1 second = 75% + 50% top speed diff --git a/src/k_kart.h b/src/k_kart.h index 1c75288e5..03ecb80b3 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -143,6 +143,7 @@ boolean K_SlopeResistance(player_t *player); tripwirepass_t K_TripwirePassConditions(player_t *player); boolean K_TripwirePass(player_t *player); boolean K_WaterRun(player_t *player); +boolean K_WaterSkip(player_t *player); void K_ApplyTripWire(player_t *player, tripwirestate_t state); INT16 K_GetSpindashChargeTime(player_t *player); fixed_t K_GetSpindashChargeSpeed(player_t *player); diff --git a/src/p_mobj.c b/src/p_mobj.c index 9b08f0e75..69c5c5c5d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3317,10 +3317,7 @@ void P_MobjCheckWater(mobj_t *mobj) } // skipping stone! - if (p && p->waterskip < 2 - && ((p->speed/3 > abs(mobj->momz)) // Going more forward than horizontal, so you can skip across the water. - || (p->speed > 20*mapobjectscale && p->waterskip)) // Already skipped once, so you can skip once more! - && (splashValid == true)) + if (p && p->waterskip < 2 && K_WaterSkip(p) && (splashValid == true)) { const fixed_t hop = 5 * mobj->scale; From aba30a1c166f366ea89b030399a2ba0e5bdcec10 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 23 Sep 2022 05:27:48 -0700 Subject: [PATCH 38/63] Rebalance item odds around Garden Top --- src/k_kart.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 646d0587b..4bafa7aa0 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -353,9 +353,9 @@ consvar_t *KartItemCVars[NUMKARTRESULTS-1] = static UINT8 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = { //B C D E F G H I - { 0, 0, 2, 4, 6, 0, 0, 0 }, // Sneaker - { 0, 0, 0, 0, 0, 2, 4, 6 }, // Rocket Sneaker - { 0, 0, 0, 0, 3, 4, 5, 7 }, // Invincibility + { 0, 0, 2, 3, 4, 0, 0, 0 }, // Sneaker + { 0, 0, 0, 0, 0, 3, 4, 5 }, // Rocket Sneaker + { 0, 0, 0, 0, 2, 5, 5, 7 }, // Invincibility { 2, 3, 1, 0, 0, 0, 0, 0 }, // Banana { 1, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor { 5, 5, 2, 2, 0, 0, 0, 0 }, // Orbinaut @@ -364,8 +364,8 @@ static UINT8 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = { 3, 0, 0, 0, 0, 0, 0, 0 }, // Land Mine { 0, 0, 2, 2, 0, 0, 0, 0 }, // Ballhog { 0, 0, 0, 0, 0, 2, 4, 0 }, // Self-Propelled Bomb - { 0, 0, 0, 1, 2, 3, 0, 0 }, // Grow - { 0, 0, 0, 0, 0, 1, 3, 2 }, // Shrink + { 0, 0, 0, 0, 2, 5, 0, 0 }, // Grow + { 0, 0, 0, 0, 0, 2, 4, 2 }, // Shrink { 1, 0, 0, 0, 0, 0, 0, 0 }, // Lightning Shield { 0, 1, 2, 1, 0, 0, 0, 0 }, // Bubble Shield { 0, 0, 0, 0, 0, 1, 3, 5 }, // Flame Shield @@ -374,9 +374,9 @@ static UINT8 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = { 2, 1, 1, 0, 0, 0, 0, 0 }, // Super Ring { 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink { 3, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target - { 0, 0, 0, 0, 0, 0, 0, 0 }, // Garden Top + { 0, 0, 0, 3, 5, 0, 0, 0 }, // Garden Top { 0, 0, 2, 2, 2, 0, 0, 0 }, // Sneaker x2 - { 0, 0, 0, 1, 6, 9, 5, 0 }, // Sneaker x3 + { 0, 0, 0, 0, 4, 4, 4, 0 }, // Sneaker x3 { 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3 { 0, 0, 0, 1, 0, 0, 0, 0 }, // Banana x10 { 0, 0, 1, 0, 0, 0, 0, 0 }, // Orbinaut x3 @@ -408,7 +408,7 @@ static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS][2] = { 0, 0 }, // Super Ring { 0, 0 }, // Kitchen Sink { 2, 0 }, // Drop Target - { 0, 0 }, // Garden Top + { 4, 0 }, // Garden Top { 0, 0 }, // Sneaker x2 { 0, 1 }, // Sneaker x3 { 0, 0 }, // Banana x3 From a6f206cd6275de6132dffcfa5d9397df19372817 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 24 Sep 2022 22:17:32 -0700 Subject: [PATCH 39/63] Add topdriftheld and topinfirst to player_t --- src/d_player.h | 2 ++ src/p_saveg.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/d_player.h b/src/d_player.h index 4ac51e245..9f310f1ed 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -601,6 +601,8 @@ typedef struct player_s UINT8 kickstartaccel; UINT8 stairjank; + UINT8 topdriftheld; + UINT8 topinfirst; UINT8 shrinkLaserDelay; diff --git a/src/p_saveg.c b/src/p_saveg.c index 233056f21..53542053d 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -379,6 +379,8 @@ static void P_NetArchivePlayers(void) WRITEUINT8(save_p, players[i].kickstartaccel); WRITEUINT8(save_p, players[i].stairjank); + WRITEUINT8(save_p, players[i].topdriftheld); + WRITEUINT8(save_p, players[i].topinfirst); WRITEUINT8(save_p, players[i].shrinkLaserDelay); @@ -676,6 +678,8 @@ static void P_NetUnArchivePlayers(void) players[i].kickstartaccel = READUINT8(save_p); players[i].stairjank = READUINT8(save_p); + players[i].topdriftheld = READUINT8(save_p); + players[i].topinfirst = READUINT8(save_p); players[i].shrinkLaserDelay = READUINT8(save_p); From b5cdf252982ed3a6e849c5b1e4602cc5a772f250 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 25 Sep 2022 07:42:52 -0700 Subject: [PATCH 40/63] Add P_LerpFlip --- src/p_tick.c | 8 ++++++++ src/p_tick.h | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/src/p_tick.c b/src/p_tick.c index 708ed6ca8..ad83abca6 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -44,6 +44,14 @@ INT32 P_AltFlip(INT32 n, tic_t tics) return leveltime % (2 * tics) < tics ? n : -(n); } +// Please read p_tick.h +INT32 P_LerpFlip(INT32 n, tic_t tics) +{ + const tic_t w = 2 * tics; + + return P_AltFlip(((leveltime % w) - tics) * n, w); +} + // // THINKERS // All thinkers should be allocated by Z_Calloc diff --git a/src/p_tick.h b/src/p_tick.h index 7b10a5f28..f892942ea 100644 --- a/src/p_tick.h +++ b/src/p_tick.h @@ -35,4 +35,12 @@ mobj_t *P_SetTarget(mobj_t **mo, mobj_t *target); // killough 11/98 INT32 P_AltFlip(INT32 value, tic_t tics); #define P_RandomFlip(value) P_AltFlip(value, 1) +// Multiply value back and forth between -(tics) and +(tics). +// Example output P_ModulateFlip(2, 2): +// Tic: 0 1 2 3 4 5 6 7 8 +// Val: -4 -2 0 2 4 2 0 -2 -4 +// A half cycle (one direction) takes 2 * tics. +// A full cycle takes 4 * tics. +INT32 P_LerpFlip(INT32 value, tic_t tics); + #endif From 5063a4acf108aea56717f0a672a2360484eb03d4 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 28 Sep 2022 00:52:55 -0700 Subject: [PATCH 41/63] The Garden Top This is all the visual effects and item logic of the Top minus (almost all [1]) physics adjustments when a player is riding one. While on a Top: - Otherwordly humming while floating - Cannot drift [1]. Instead, holding drift begins grinding the Top into the ground -- sparks fly out - Sprite tilts left and right as you turn - No wheel screech when turning too far - Speed lines while holding drift - Tripwire Boost effect scales to cover you AND the Top - One hit and you lose it - Throwing forward, getting hit or just losing it because you were in first place for too long: the Top flies out from under you and begins snaking like crazy - Throwing backward also makes the Top fly out from under you but it also thrusts you forward. The Top dies instantly so it's not dangerous ;-) - If you're in first for too long, it begins vibrating - If you tumble, it dances across your entire screen A loose top will tumble anyone it hits. --- src/d_player.h | 2 + src/k_kart.c | 232 ++++++++++++++- src/k_kart.h | 5 + src/k_objects.h | 8 + src/objects/Sourcefile | 1 + src/objects/gardentop.c | 612 ++++++++++++++++++++++++++++++++++++++++ src/objects/orbinaut.c | 14 +- src/p_inter.c | 6 + src/p_map.c | 10 +- src/p_mobj.c | 37 ++- src/p_user.c | 7 + src/r_patchrotation.c | 10 + 12 files changed, 923 insertions(+), 21 deletions(-) create mode 100644 src/objects/gardentop.c diff --git a/src/d_player.h b/src/d_player.h index 9f310f1ed..fb4208d2c 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -290,6 +290,8 @@ typedef enum #define ITEMSCALE_GROW 1 #define ITEMSCALE_SHRINK 2 +#define GARDENTOP_MAXGRINDTIME (45) + // player_t struct for all respawn variables typedef struct respawnvars_s { diff --git a/src/k_kart.c b/src/k_kart.c index 4bafa7aa0..dee43b1a0 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2414,7 +2414,7 @@ void K_SpawnDriftBoostClipSpark(mobj_t *clip) spark->momy = clip->momx/2; } -void K_SpawnNormalSpeedLines(player_t *player) +static void K_SpawnGenericSpeedLines(player_t *player, boolean top) { mobj_t *fast = P_SpawnMobj(player->mo->x + (P_RandomRange(PR_DECORATION,-36,36) * player->mo->scale), player->mo->y + (P_RandomRange(PR_DECORATION,-36,36) * player->mo->scale), @@ -2422,20 +2422,40 @@ void K_SpawnNormalSpeedLines(player_t *player) MT_FASTLINE); P_SetTarget(&fast->target, player->mo); - P_InitAngle(fast, K_MomentumAngle(player->mo)); fast->momx = 3*player->mo->momx/4; fast->momy = 3*player->mo->momy/4; fast->momz = 3*P_GetMobjZMovement(player->mo)/4; - K_MatchGenericExtraFlags(fast, player->mo); + fast->z += player->mo->sprzoff; - if (player->tripwireLeniency) + if (top) { - fast->destscale = fast->destscale * 2; - P_SetScale(fast, 3*fast->scale/2); + P_InitAngle(fast, player->mo->angle); + P_SetScale(fast, (fast->destscale = + 3 * fast->destscale / 2)); + + fast->spritexscale = 3*FRACUNIT; + } + else + { + P_InitAngle(fast, K_MomentumAngle(player->mo)); + + if (player->tripwireLeniency) + { + fast->destscale = fast->destscale * 2; + P_SetScale(fast, 3*fast->scale/2); + } } - if (player->eggmanexplode) + K_MatchGenericExtraFlags(fast, player->mo); + + if (top) + { + fast->color = SKINCOLOR_SUNSLAM; + fast->colorized = true; + fast->renderflags |= RF_ADD; + } + else if (player->eggmanexplode) { // Make it red when you have the eggman speed boost fast->color = SKINCOLOR_RED; @@ -2463,6 +2483,16 @@ void K_SpawnNormalSpeedLines(player_t *player) } } +void K_SpawnNormalSpeedLines(player_t *player) +{ + K_SpawnGenericSpeedLines(player, false); +} + +void K_SpawnGardenTopSpeedLines(player_t *player) +{ + K_SpawnGenericSpeedLines(player, true); +} + void K_SpawnInvincibilitySpeedLines(mobj_t *mo) { mobj_t *fast = P_SpawnMobjFromMobj(mo, @@ -2561,14 +2591,21 @@ static void K_SpawnGrowShrinkParticles(mobj_t *mo, INT32 timer) void K_SpawnBumpEffect(mobj_t *mo) { + mobj_t *top = mo->player ? K_GetGardenTop(mo->player) : NULL; + mobj_t *fx = P_SpawnMobj(mo->x, mo->y, mo->z, MT_BUMP); + if (mo->eflags & MFE_VERTICALFLIP) fx->eflags |= MFE_VERTICALFLIP; else fx->eflags &= ~MFE_VERTICALFLIP; + fx->scale = mo->scale; - S_StartSound(mo, sfx_s3k49); + if (top) + S_StartSound(mo, top->info->attacksound); + else + S_StartSound(mo, sfx_s3k49); } static SINT8 K_GlanceAtPlayers(player_t *glancePlayer) @@ -2723,6 +2760,10 @@ void K_KartMoveAnimation(player_t *player) drift = intsign(player->aizdriftturn); turndir = 0; } + else if (player->curshield == KSHIELD_TOP) + { + drift = -turndir; + } else if (turndir == 0 && drift == 0) { // Only try glancing if you're driving straight. @@ -3288,6 +3329,46 @@ boolean K_WaterSkip(player_t *player) return false; } +boolean K_IsRidingFloatingTop(player_t *player) +{ + if (player->curshield != KSHIELD_TOP) + { + return false; + } + + return !Obj_GardenTopPlayerIsGrinding(player); +} + +boolean K_IsHoldingDownTop(player_t *player) +{ + if (player->curshield != KSHIELD_TOP) + { + return false; + } + + if ((K_GetKartButtons(player) & BT_DRIFT) != BT_DRIFT) + { + return false; + } + + return true; +} + +mobj_t *K_GetGardenTop(player_t *player) +{ + if (player->curshield != KSHIELD_TOP) + { + return NULL; + } + + if (player->mo == NULL) + { + return NULL; + } + + return player->mo->hnext; +} + static fixed_t K_FlameShieldDashVar(INT32 val) { // 1 second = 75% + 50% top speed @@ -4698,6 +4779,19 @@ fixed_t K_ItemScaleForPlayer(player_t *player) } } +fixed_t K_DefaultPlayerRadius(player_t *player) +{ + mobj_t *top = K_GetGardenTop(player); + + if (top) + { + return top->radius; + } + + return FixedMul(player->mo->scale, + player->mo->info->radius); +} + static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, INT32 flags2, fixed_t speed, SINT8 dir) { mobj_t *th; @@ -4812,6 +4906,9 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I th->destscale = th->destscale << 1; th->scalespeed = abs(th->destscale - th->scale) / (2*TICRATE); break; + case MT_GARDENTOP: + th->movefactor = finalspeed; + break; default: break; } @@ -5472,8 +5569,11 @@ void K_DriftDustHandling(mobj_t *spawner) dust->destscale = spawner->scale * 3; dust->scalespeed = spawner->scale/12; - if (leveltime % 6 == 0) - S_StartSound(spawner, sfx_screec); + if (!spawner->player || !K_GetGardenTop(spawner->player)) + { + if (leveltime % 6 == 0) + S_StartSound(spawner, sfx_screec); + } K_MatchGenericExtraFlags(dust, spawner); @@ -5633,7 +5733,7 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, if (missile) // Shootables { - if (dir < 0 && mapthing != MT_SPB) + if (dir < 0 && mapthing != MT_SPB && mapthing != MT_GARDENTOP) { // Shoot backward mo = K_SpawnKartMissile(player->mo, mapthing, (player->mo->angle + ANGLE_180) + angleOffset, 0, PROJSPEED, dir); @@ -6244,7 +6344,7 @@ void K_DropHnextList(player_t *player, boolean keepshields) flip = P_MobjFlip(player->mo); ponground = P_IsObjectOnGround(player->mo); - if (shield != KSHIELD_NONE && !keepshields) + if (shield != KSHIELD_NONE && shield != KSHIELD_TOP && !keepshields) { if (shield == KSHIELD_LIGHTNING) { @@ -6296,6 +6396,9 @@ void K_DropHnextList(player_t *player, boolean keepshields) orbit = false; type = MT_EGGMANITEM; break; + case MT_GARDENTOP: + Obj_GardenTopDestroy(player); + return; // intentionally do nothing case MT_ROCKETSNEAKER: case MT_SINK_SHIELD: @@ -7602,6 +7705,33 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) { const boolean onground = P_IsObjectOnGround(player->mo); + /* reset sprite offsets :) */ + player->mo->sprxoff = 0; + player->mo->spryoff = 0; + player->mo->sprzoff = 0; + player->mo->spritexoffset = 0; + player->mo->spriteyoffset = 0; + + if (player->curshield == KSHIELD_TOP) + { + mobj_t *top = K_GetGardenTop(player); + + if (top) + { + /* FIXME: I cannot figure out how offset the + player correctly in real time to pivot around + the BOTTOM of the Top. This hack plus the one + in R_PlayerSpriteRotation. */ + player->mo->spritexoffset += FixedMul( + FixedDiv(top->height, top->scale), + FINESINE(top->rollangle >> ANGLETOFINESHIFT)); + + player->mo->sprzoff += top->sprzoff + ( + P_GetMobjHead(top) - + P_GetMobjFeet(player->mo)); + } + } + K_UpdateOffroad(player); K_UpdateDraft(player); K_UpdateEngineSounds(player); // Thanks, VAda! @@ -8049,8 +8179,20 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (cmd->buttons & BT_DRIFT) { + if (player->curshield == KSHIELD_TOP) + { + if (player->topdriftheld <= GARDENTOP_MAXGRINDTIME) + player->topdriftheld++; + + // Squish :) + player->mo->spritexscale = 6*FRACUNIT/4; + player->mo->spriteyscale = 2*FRACUNIT/4; + + if (leveltime & 1) + K_SpawnGardenTopSpeedLines(player); + } // Only allow drifting while NOT trying to do an spindash input. - if ((K_GetKartButtons(player) & BT_EBRAKEMASK) != BT_EBRAKEMASK) + else if ((K_GetKartButtons(player) & BT_EBRAKEMASK) != BT_EBRAKEMASK) { player->pflags |= PF_DRIFTINPUT; } @@ -8187,7 +8329,7 @@ void K_KartResetPlayerColor(player_t *player) finalise: - if (player->curshield) + if (player->curshield && player->curshield != KSHIELD_TOP) { fullbright = true; } @@ -9245,6 +9387,7 @@ void K_KartUpdatePosition(player_t *player) fixed_t position = 1; fixed_t oldposition = player->position; fixed_t i; + INT32 realplayers = 0; if (player->spectator || !player->mo) { @@ -9259,6 +9402,8 @@ void K_KartUpdatePosition(player_t *player) if (!playeringame[i] || players[i].spectator || !players[i].mo) continue; + realplayers++; + if (gametyperules & GTR_CIRCUIT) { if (player->exiting) // End of match standings @@ -9322,6 +9467,33 @@ void K_KartUpdatePosition(player_t *player) if (oldposition != position) // Changed places? player->positiondelay = 10; // Position number growth + /* except in FREE PLAY */ + if (player->curshield == KSHIELD_TOP && + (gametyperules & GTR_CIRCUIT) && + realplayers > 1) + { + /* grace period so you don't fall off INSTANTLY */ + if (position == 1 && player->topinfirst < 2*TICRATE) + { + player->topinfirst++; + } + else + { + if (position == 1) + { + Obj_GardenTopThrow(player); + } + else + { + player->topinfirst = 0; + } + } + } + else + { + player->topinfirst = 0; + } + player->position = position; } @@ -9473,6 +9645,7 @@ void K_KartEbrakeVisuals(player_t *p) p->mo->hprev->angle = p->mo->angle; p->mo->hprev->fuse = TICRATE/2; // When we leave spindash for any reason, make sure this bubble goes away soon after. K_FlipFromObject(p->mo->hprev, p->mo); + p->mo->hprev->sprzoff = p->mo->sprzoff; } if (!p->spindash) @@ -10490,6 +10663,37 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } } break; + case KITEM_GARDENTOP: + if (ATTACK_IS_DOWN && NO_HYUDORO) + { + if (player->curshield != KSHIELD_TOP) + { + player->topinfirst = 0; + Obj_GardenTopDeploy(player->mo); + } + else + { + if (player->throwdir == -1) + { + mobj_t *top = Obj_GardenTopDestroy(player); + + // Fly off the Top at high speed + P_Thrust(player->mo, K_MomentumAngle(player->mo), 80 * player->mo->scale); + P_SetObjectMomZ(player->mo, player->mo->height / 2, true); + + top->momx = player->mo->momx; + top->momy = player->mo->momy; + top->momz = player->mo->momz; + } + else + { + Obj_GardenTopThrow(player); + S_StartSound(player->mo, sfx_tossed); // play only when actually thrown :^,J + K_PlayAttackTaunt(player->mo); + } + } + } + break; case KITEM_BUBBLESHIELD: if (player->curshield != KSHIELD_BUBBLE) { diff --git a/src/k_kart.h b/src/k_kart.h index 03ecb80b3..47e7f2006 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -69,6 +69,7 @@ void K_SpawnDashDustRelease(player_t *player); void K_SpawnDriftBoostClip(player_t *player); void K_SpawnDriftBoostClipSpark(mobj_t *clip); void K_SpawnNormalSpeedLines(player_t *player); +void K_SpawnGardenTopSpeedLines(player_t *player); void K_SpawnInvincibilitySpeedLines(mobj_t *mo); void K_SpawnBumpEffect(mobj_t *mo); void K_KartMoveAnimation(player_t *player); @@ -144,6 +145,9 @@ tripwirepass_t K_TripwirePassConditions(player_t *player); boolean K_TripwirePass(player_t *player); boolean K_WaterRun(player_t *player); boolean K_WaterSkip(player_t *player); +boolean K_IsRidingFloatingTop(player_t *player); +boolean K_IsHoldingDownTop(player_t *player); +mobj_t *K_GetGardenTop(player_t *player); void K_ApplyTripWire(player_t *player, tripwirestate_t state); INT16 K_GetSpindashChargeTime(player_t *player); fixed_t K_GetSpindashChargeSpeed(player_t *player); @@ -170,6 +174,7 @@ UINT8 K_GetOrbinautItemFrame(UINT8 count); boolean K_IsSPBInGame(void); void K_KartEbrakeVisuals(player_t *p); void K_HandleDirectionalInfluence(player_t *player); +fixed_t K_DefaultPlayerRadius(player_t *player); // sound stuff for lua void K_PlayAttackTaunt(mobj_t *source); diff --git a/src/k_objects.h b/src/k_objects.h index 7679db658..b5b58b800 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -8,6 +8,14 @@ void Obj_HyudoroThink(mobj_t *actor); void Obj_HyudoroCenterThink(mobj_t *actor); void Obj_HyudoroCollide(mobj_t *special, mobj_t *toucher); +/* Garden Top */ +void Obj_GardenTopDeploy(mobj_t *rider); +mobj_t *Obj_GardenTopThrow(player_t *player); +mobj_t *Obj_GardenTopDestroy(player_t *player); +void Obj_GardenTopThink(mobj_t *top); +void Obj_GardenTopSparkThink(mobj_t *spark); +boolean Obj_GardenTopPlayerIsGrinding(player_t *player); + /* Shrink */ void Obj_PohbeeThinker(mobj_t *pohbee); void Obj_PohbeeRemoved(mobj_t *pohbee); diff --git a/src/objects/Sourcefile b/src/objects/Sourcefile index 339175b0c..044c9b576 100644 --- a/src/objects/Sourcefile +++ b/src/objects/Sourcefile @@ -1,4 +1,5 @@ hyudoro.c +gardentop.c shrink.c item-debris.c spb.c diff --git a/src/objects/gardentop.c b/src/objects/gardentop.c new file mode 100644 index 000000000..38154636f --- /dev/null +++ b/src/objects/gardentop.c @@ -0,0 +1,612 @@ +#include "../doomdef.h" +#include "../doomstat.h" +#include "../info.h" +#include "../k_kart.h" +#include "../k_objects.h" +#include "../m_random.h" +#include "../p_local.h" +#include "../r_local.h" +#include "../s_sound.h" + +// TODO: separate from this file +static fixed_t K_FlipZOffset(mobj_t *us, mobj_t *them) +{ + fixed_t z = 0; + + if (them->eflags & MFE_VERTICALFLIP) + z += them->height; + + if (us->eflags & MFE_VERTICALFLIP) + z -= us->height; + + return z; +} + +#define SPARKCOLOR SKINCOLOR_ROBIN + +enum { + TOP_ANCHORED, + TOP_LOOSE, +}; + +#define topsfx_floating sfx_s3k7d +#define topsfx_grinding sfx_s3k79 +#define topsfx_lift sfx_s3ka0 + +#define rider_top(o) ((o)->hnext) + +#define top_mode(o) ((o)->extravalue1) +#define top_float(o) ((o)->lastlook) +#define top_sound(o) ((o)->extravalue2) +#define top_soundtic(o) ((o)->movecount) + +/* TOP_ANCHORED */ +#define top_rider(o) ((o)->tracer) + +/* TOP_LOOSE */ +#define top_waveangle(o) ((o)->movedir) +/* wavepause will take mobjinfo reactiontime automatically */ +#define top_wavepause(o) ((o)->reactiontime) + +#define spark_top(o) ((o)->target) +#define spark_angle(o) ((o)->movedir) + +static inline player_t * +get_rider_player (mobj_t *rider) +{ + return rider ? rider->player : NULL; +} + +static inline player_t * +get_top_rider_player (mobj_t *top) +{ + return get_rider_player(top_rider(top)); +} + +static inline boolean +is_top_grind_input (mobj_t *top) +{ + player_t *player = get_top_rider_player(top); + + return player && K_IsHoldingDownTop(player); +} + +static inline boolean +is_top_grinding (mobj_t *top) +{ + if (top_float(top) > 0) + return false; + + if (!P_IsObjectOnGround(top)) + return false; + + return true; +} + +static inline fixed_t +grind_spark_base_scale (player_t *player) +{ + return FRACUNIT/2 + + player->topdriftheld * FRACUNIT + / GARDENTOP_MAXGRINDTIME; +} + +static inline INT32 +get_player_steer_tilt +( player_t * player, + INT32 stages) +{ + return player->steering + * stages + + // 1 degree for a full turn + / KART_FULLTURN + * ANG1 + + // stages is for fractions of a full turn, divide to + // get a fraction of a degree + / stages + + // angle is inverted in reverse gravity + * P_MobjFlip(player->mo); +} + +static inline fixed_t +goofy_shake (fixed_t n) +{ + return P_RandomRange(PR_DECORATION, -1, 1) * n; +} + +static inline void +init_top +( mobj_t * top, + INT32 mode) +{ + top_mode(top) = mode; + top_float(top) = 0; + top_sound(top) = sfx_None; + top_waveangle(top) = 0; +} + +static void +spawn_spark +( mobj_t * top, + angle_t angle) +{ + mobj_t *spark = P_SpawnMobjFromMobj( + top, 0, 0, 0, MT_GARDENTOPSPARK); + + P_SetTarget(&spark_top(spark), top); + + spark_angle(spark) = angle; + + spark->color = SPARKCOLOR; + spark->spriteyscale = 3*FRACUNIT/4; +} + +static void +spawn_spark_circle +( mobj_t * top, + UINT8 n) +{ + const angle_t a = ANGLE_MAX / n; + + UINT8 i; + + for (i = 0; i < n; ++i) + { + spawn_spark(top, i * a); + } +} + +static void +spawn_grind_spark (mobj_t *top) +{ + mobj_t *rider = top_rider(top); + mobj_t *spark; + + player_t *player = NULL; + + fixed_t x = 0; + fixed_t y = 0; + + angle_t angle = top->angle; + + if (rider) + { + const fixed_t speed = -20 * top->scale; + + angle = K_MomentumAngle(rider); + + x = P_ReturnThrustX(rider, angle, speed); + y = P_ReturnThrustY(rider, angle, speed); + + player = get_rider_player(rider); + } + + spark = P_SpawnMobjFromMobj( + top, x, y, 0, MT_DRIFTSPARK); + + spark->momx = x; + spark->momy = y; + + P_SetMobjState(spark, S_DRIFTSPARK_A1); + + spark->angle = angle; + spark->color = SPARKCOLOR; + + if (player) + { + spark->destscale = FixedMul(spark->destscale, + grind_spark_base_scale(player)); + + P_SetScale(spark, spark->destscale); + } +} + +static void +loop_sfx +( mobj_t * top, + sfxenum_t sfx) +{ + switch (sfx) + { + case topsfx_floating: + if (S_SoundPlaying(top, sfx)) + { + return; + } + break; + + case topsfx_grinding: + if ((sfxenum_t)top_sound(top) != sfx) + { + top_soundtic(top) = leveltime; + } + + /* FIXME: could this sound just be looped + normally? :face_holding_back_tears: */ + if ((leveltime - top_soundtic(top)) % 28 > 0) + { + return; + } + break; + + default: + break; + } + + S_StartSound(top, sfx); +} + +static void +modulate (mobj_t *top) +{ + const fixed_t max_hover = top->height / 4; + const fixed_t hover_step = max_hover / 4; + + sfxenum_t ambience = sfx_None; + + if (is_top_grind_input(top)) + { + if (top_float(top) == max_hover) + { + P_SetMobjState(top, S_GARDENTOP_SINKING1); + } + + if (top_float(top) > 0) + { + top_float(top) -= hover_step; + } + else if (P_IsObjectOnGround(top)) + { + spawn_grind_spark(top); + ambience = topsfx_grinding; + } + } + else + { + if (top_float(top) == 0) + { + P_SetMobjState(top, S_GARDENTOP_FLOATING); + + S_StopSoundByID(top, topsfx_grinding); + S_StartSound(top, topsfx_lift); + } + + if (top_float(top) < max_hover) + { + top_float(top) += hover_step; + } + else + { + ambience = topsfx_floating; + } + } + + top->sprzoff = top_float(top) * P_MobjFlip(top); + + if (ambience) + { + loop_sfx(top, ambience); + } + + top_sound(top) = ambience; +} + +static void +tilt (mobj_t *top) +{ + player_t *player = get_top_rider_player(top); + + INT32 tilt = top->rollangle; + + if (is_top_grind_input(top)) + { + const angle_t tiltmax = ANGLE_22h; + + tilt += get_player_steer_tilt(player, 4); + + if (abs(tilt) > tiltmax) + { + tilt = intsign(tilt) * tiltmax; + } + } + else + { + const angle_t decay = ANG1 * 2; + + if (abs(tilt) > decay) + { + tilt -= intsign(tilt) * decay; + } + else + { + tilt = 0; + } + } + + top->rollangle = tilt; + + /* Vibrate left and right if you're about to lose it. */ + if (player && player->topinfirst) + { + top->spritexoffset = P_LerpFlip(32*FRACUNIT, 1); + } + else + { + top->spritexoffset = 0; + } + + /* Go ABSOLUTELY NUTS if the player is tumbling... */ + if (player && player->tumbleBounces > 0) + { + const fixed_t yofs = 48 * FRACUNIT; + const fixed_t ofs3d = 24 * top->scale; + + /* spriteyoffset scales, e.g. with K_Squish */ + top->spriteyoffset = FixedDiv( + goofy_shake(yofs), top->spriteyscale); + + top->sprxoff = goofy_shake(ofs3d); + top->spryoff = goofy_shake(ofs3d); + } + else + { + top->spriteyoffset = 0; + top->sprxoff = 0; + top->spryoff = 0; + } +} + +static void +anchor_top (mobj_t *top) +{ + mobj_t *rider = top_rider(top); + player_t *player = get_rider_player(rider); + + if (player && player->curshield != KSHIELD_TOP) + { + P_RemoveMobj(top); + return; + } + + tilt(top); + + P_MoveOrigin(top, rider->x, rider->y, + rider->z + K_FlipZOffset(top, rider)); + + K_GenericExtraFlagsNoZAdjust(top, rider); + + /* Copying the Z momentum lets the Top squash and stretch + as it falls with the player. Don't copy the X/Y + momentum because then it would always get slightly + ahead of the player. */ + top->momx = 0; + top->momy = 0; + top->momz = rider->momz; + + /* The Z momentum can put the Top slightly ahead of the + player in that axis too. It looks cool if the Top + falls below you but not if it bounces up. */ + if (top->momz * P_MobjFlip(top) > 0) + { + top->momz = 0; + } + + /* match rider's slope tilt */ + top->pitch = rider->pitch; + top->roll = rider->roll; +} + +static void +loose_think (mobj_t *top) +{ + const fixed_t thrustamount = top->movefactor; + const angle_t momangle = K_MomentumAngle(top); + + angle_t ang = top->angle; + + mobj_t *ghost = P_SpawnGhostMobj(top); + ghost->colorized = true; // already has color! + + if (AngleDelta(ang, momangle) > ANGLE_90) + { + top->angle = momangle; + } + + if (top_wavepause(top)) + { + top_wavepause(top)--; + } + else + { + /* oscillate between +90 and -90 degrees */ + ang += AbsAngle(top_waveangle(top)) - ANGLE_90; + } + + P_InstaThrust(top, top->angle, thrustamount); + P_Thrust(top, ang, thrustamount); + + //top_waveangle(top) = (angle_t)top_waveangle(top) + ANG10; + top_waveangle(top) += ANG10; + + /* intangibility grace period */ + if (top->threshold > 0) + { + top->threshold--; + } +} + +static void +anchor_spark (mobj_t *spark) +{ + mobj_t *top = spark_top(spark); + mobj_t *rider = top_rider(top); + player_t *player = get_rider_player(rider); + + const angle_t angle = top->angle + spark_angle(spark); + const fixed_t x = P_ReturnThrustX(top, angle, spark->scale); + const fixed_t y = P_ReturnThrustY(top, angle, spark->scale); + + /* FIXME: THIS FUNCTION FUCKING SUCKS */ + K_FlipFromObject(spark, top); + + P_MoveOrigin(spark, top->x + x, top->y + y, + top->z + K_FlipZOffset(spark, top)); + + spark->angle = angle; + + if (player) + { + const fixed_t topspeed = + K_GetKartSpeed(player, false, false); + + const fixed_t speed = FixedHypot( + rider->momx, rider->momy); + + P_SetScale(spark, FixedMul(top->scale, FRACUNIT/2 + + FixedDiv(speed / 2, topspeed))); + } +} + +void +Obj_GardenTopDeploy (mobj_t *rider) +{ + player_t *player = rider->player; + + mobj_t *top = P_SpawnMobjFromMobj( + rider, 0, 0, 0, MT_GARDENTOP); + + init_top(top, TOP_ANCHORED); + + top->flags |= MF_NOCLIPHEIGHT; + + /* only the player's shadow needs to be rendered */ + top->shadowscale = 0; + + P_SetTarget(&top_rider(top), rider); + P_SetTarget(&rider_top(rider), top); + + if (player) + { + player->curshield = KSHIELD_TOP; + rider->radius = K_DefaultPlayerRadius(player); + } + + spawn_spark_circle(top, 6); +} + +mobj_t * +Obj_GardenTopThrow (player_t *player) +{ + mobj_t *top = K_GetGardenTop(player); + + if (top) + { + const fixed_t oldfloat = top_float(top); + const fixed_t height = top->height; + + K_UpdateHnextList(player, true); + + /* Sucks that another one needs to be spawned but + this way, the throwing function can be used. */ + top = K_ThrowKartItem( + player, true, MT_GARDENTOP, 1, 0, 0); + + init_top(top, TOP_LOOSE); + + top_float(top) = oldfloat; + top_waveangle(top) = 0; + + /* prevents it from hitting us on its way out */ + top->threshold = 20; + + /* ensure it's tangible */ + top->flags &= ~(MF_NOCLIPTHING); + + /* Put player PHYSICALLY on top. While riding the + Top, player collision was used and the player + technically remained on the ground. Now they + should fall off. */ + P_SetOrigin(player->mo, player->mo->x, player->mo->y, + player->mo->z + height * P_MobjFlip(player->mo)); + + if (player->itemamount > 0) + player->itemamount--; + + if (player->itemamount <= 0) + player->itemtype = KITEM_NONE; + + player->curshield = KSHIELD_NONE; + + player->mo->radius = K_DefaultPlayerRadius(player); + } + + return top; +} + +mobj_t * +Obj_GardenTopDestroy (player_t *player) +{ + mobj_t *top = Obj_GardenTopThrow(player); + + if (top) + { + /* kill kill kill die die die */ + P_KillMobj(top, NULL, NULL, DMG_NORMAL); + } + + return top; +} + +void +Obj_GardenTopThink (mobj_t *top) +{ + modulate(top); + + switch (top_mode(top)) + { + case TOP_ANCHORED: + if (top_rider(top)) + { + anchor_top(top); + } + break; + + case TOP_LOOSE: + loose_think(top); + break; + } +} + +void +Obj_GardenTopSparkThink (mobj_t *spark) +{ + mobj_t *top = spark_top(spark); + + if (!top) + { + P_RemoveMobj(spark); + return; + } + + anchor_spark(spark); + + if (is_top_grinding(top)) + { + spark->renderflags ^= RF_DONTDRAW; + } + else + { + spark->renderflags |= RF_DONTDRAW; + } +} + +boolean +Obj_GardenTopPlayerIsGrinding (player_t *player) +{ + mobj_t *top = K_GetGardenTop(player); + + return top ? is_top_grinding(top) : false; +} diff --git a/src/objects/orbinaut.c b/src/objects/orbinaut.c index 0c04c4b67..ac209ec16 100644 --- a/src/objects/orbinaut.c +++ b/src/objects/orbinaut.c @@ -143,6 +143,7 @@ void Obj_OrbinautThink(mobj_t *th) boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) { boolean damageitem = false; + boolean tumbleitem = false; boolean sprung = false; if ((orbinaut_selfdelay(t1) > 0 && t2->hitlag > 0) @@ -173,6 +174,11 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) return true; } + if (t1->type == MT_GARDENTOP) + { + tumbleitem = true; + } + if (t2->player) { if ((t2->player->flashing > 0 && t2->hitlag == 0) @@ -190,7 +196,8 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) else { // Player Damage - P_DamageMobj(t2, t1, t1->target, 1, DMG_WIPEOUT|DMG_WOMBO); + P_DamageMobj(t2, t1, t1->target, 1, DMG_WOMBO | + (tumbleitem ? DMG_TUMBLE : DMG_WIPEOUT)); K_KartBouncing(t2, t1); S_StartSound(t2, sfx_s3k7b); } @@ -233,6 +240,11 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) damageitem = true; } + if (t1->type == MT_GARDENTOP) + { + damageitem = false; + } + if (damageitem) { // This Item Damage diff --git a/src/p_inter.c b/src/p_inter.c index 19f03c664..c4e186949 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2014,6 +2014,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da player->emeralds = 0; K_CheckEmeralds(source->player); } + + /* Drop "shield" immediately on contact. */ + if (source->player->curshield == KSHIELD_TOP) + { + Obj_GardenTopDestroy(source->player); + } } else { diff --git a/src/p_map.c b/src/p_map.c index 62baa23e6..c2b688730 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -866,6 +866,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) && (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ || tmthing->type == MT_BANANA || tmthing->type == MT_EGGMANITEM || tmthing->type == MT_BALLHOG || tmthing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || tmthing->type == MT_SINK + || tmthing->type == MT_GARDENTOP || (tmthing->type == MT_PLAYER && thing->target != tmthing))) { // see if it went over / under @@ -881,6 +882,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) && (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG || thing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || thing->type == MT_SINK + || thing->type == MT_GARDENTOP || (thing->type == MT_PLAYER && tmthing->target != thing))) { // see if it went over / under @@ -901,6 +903,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) && (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ || tmthing->type == MT_BANANA || tmthing->type == MT_EGGMANITEM || tmthing->type == MT_BALLHOG || tmthing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || tmthing->type == MT_SINK + || tmthing->type == MT_GARDENTOP || (tmthing->type == MT_PLAYER))) { // see if it went over / under @@ -915,6 +918,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) && (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG || thing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || thing->type == MT_SINK + || thing->type == MT_GARDENTOP || (thing->type == MT_PLAYER))) { // see if it went over / under @@ -932,7 +936,8 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return BMIT_CONTINUE; if (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ - || tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD) + || tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD + || tmthing->type == MT_GARDENTOP) { // see if it went over / under if (tmthing->z > thing->z + thing->height) @@ -943,7 +948,8 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return Obj_OrbinautJawzCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ - || thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD) + || thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD + || thing->type == MT_GARDENTOP) { // see if it went over / under if (tmthing->z > thing->z + thing->height) diff --git a/src/p_mobj.c b/src/p_mobj.c index 69c5c5c5d..cfbea3185 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1734,6 +1734,7 @@ void P_XYMovement(mobj_t *mo) switch (mo->type) { case MT_ORBINAUT: // Orbinaut speed decreasing + case MT_GARDENTOP: if (mo->health > 1) { S_StartSound(mo, mo->info->attacksound); @@ -6324,6 +6325,7 @@ static boolean P_MobjDeadThink(mobj_t *mobj) return false; } /* FALLTHRU */ + case MT_GARDENTOP: case MT_ORBINAUT_SHIELD: case MT_BANANA_SHIELD: case MT_EGGMANITEM_SHIELD: @@ -7028,7 +7030,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } } break; - case MT_TRIPWIREBOOST: + case MT_TRIPWIREBOOST: { + mobj_t *top; + fixed_t newHeight; + fixed_t newScale; + if (!mobj->target || !mobj->target->health || !mobj->target->player || !mobj->target->player->tripwireLeniency) { @@ -7036,10 +7042,21 @@ static boolean P_MobjRegularThink(mobj_t *mobj) return false; } + newHeight = mobj->target->height; + newScale = mobj->target->scale; + + top = K_GetGardenTop(mobj->target->player); + + if (top) + { + newHeight += 5 * top->height / 4; + newScale = FixedMul(newScale, FixedDiv(newHeight / 2, mobj->target->height)); + } + mobj->angle = K_MomentumAngle(mobj->target); - P_MoveOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z + (mobj->target->height >> 1)); - mobj->destscale = mobj->target->scale; - P_SetScale(mobj, mobj->target->scale); + P_MoveOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z + (newHeight / 2)); + mobj->destscale = newScale; + P_SetScale(mobj, newScale); if (mobj->extravalue1) { @@ -7111,6 +7128,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } } break; + } case MT_BOOSTFLAME: if (!mobj->target || !mobj->target->health) { @@ -7682,6 +7700,16 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } break; } + case MT_GARDENTOP: + { + Obj_GardenTopThink(mobj); + break; + } + case MT_GARDENTOPSPARK: + { + Obj_GardenTopSparkThink(mobj); + break; + } case MT_HYUDORO: { Obj_HyudoroThink(mobj); @@ -9727,6 +9755,7 @@ static void P_DefaultMobjShadowScale(mobj_t *thing) case MT_BUBBLESHIELD: case MT_BUBBLESHIELDTRAP: case MT_FLAMESHIELD: + case MT_GARDENTOP: thing->shadowscale = FRACUNIT; break; case MT_RING: diff --git a/src/p_user.c b/src/p_user.c index 5261b84cb..8e03c1d43 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3263,6 +3263,13 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } } + /* The Top is Big Large so zoom out */ + if (player->curshield == KSHIELD_TOP) + { + camdist += 40 * mapobjectscale; + camheight += 40 * mapobjectscale; + } + if (!resetcalled && (leveltime >= introtime && timeover != 2) && (t_cam_rotate[num] != -42)) { diff --git a/src/r_patchrotation.c b/src/r_patchrotation.c index e2506baa5..d3a844396 100644 --- a/src/r_patchrotation.c +++ b/src/r_patchrotation.c @@ -42,6 +42,8 @@ static angle_t R_PlayerSpriteRotation(player_t *player, player_t *viewPlayer) angle_t rollAngle = 0; + mobj_t *top = K_GetGardenTop(player); + if (player->mo->eflags & MFE_UNDERWATER) { rollAngle -= player->underwatertilt; @@ -61,6 +63,14 @@ static angle_t R_PlayerSpriteRotation(player_t *player, player_t *viewPlayer) (17 / player->stairjank)); } + if (top) + { + /* FIXME: why does it not look right at more acute + angles without this? There's a related hack to + spritexoffset in K_KartPlayerThink. */ + rollAngle += 3 * (INT32)top->rollangle / 2; + } + return rollAngle; } From 56a5432f41f974e15d0e0c14a68781a2441c6e3d Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 25 Aug 2022 01:34:23 -0700 Subject: [PATCH 42/63] Adjust most player physics for Garden Top - Auto accel - 800% acceleration - 110% top speed - Infinite tether like Lightning Shield - Resists going upward on slopes - Less friction - Can always turn your sprite - Turning speed does not get weaker at high speeds - Turning speed is normal underwater - Keeps moving in momentum direction, regardless of how you turn - Releasing a drift redirects all your momentum in that direction - Floats over bananas, damage sectors and offroad - No stair janking while floating - Hold drift for extra gravity. Not only does this fast fall (this stacks with true fast falling), it builds momentum down slopes too! - Parries Big Players (Grow), Invincibility, Flame Shield and, of course, other Tops -- all except if you're grinding - Wipes out anyone you touch - Infinite weight like Bubble Shield - Does not water skip - Does not water run while holding drift --- src/k_collide.c | 15 +++++++--- src/k_kart.c | 78 +++++++++++++++++++++++++++++++++++++++++++++---- src/p_map.c | 5 ++++ src/p_mobj.c | 33 ++++++++++++++++----- src/p_spec.c | 4 +-- src/p_user.c | 21 ++++++++++++- 6 files changed, 135 insertions(+), 21 deletions(-) diff --git a/src/k_collide.c b/src/k_collide.c index e4a536403..978993339 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -66,17 +66,22 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2) if (t1->type == MT_BANANA && t1->health > 1) S_StartSound(t2, sfx_bsnipe); + damageitem = true; + if (t2->player->flamedash && t2->player->itemtype == KITEM_FLAMESHIELD) { // Melt item S_StartSound(t2, sfx_s3k43); } + else if (K_IsRidingFloatingTop(t2->player)) + { + // Float over silly banana + damageitem = false; + } else { P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL|DMG_WOMBO); } - - damageitem = true; } else if (t2->type == MT_BANANA || t2->type == MT_BANANA_SHIELD || t2->type == MT_ORBINAUT || t2->type == MT_ORBINAUT_SHIELD @@ -774,11 +779,13 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2) // Clash instead of damage if both parties have any of these conditions t1Condition = (K_IsBigger(t1, t2) == true) || (t1->player->invincibilitytimer > 0) - || (t1->player->flamedash > 0 && t1->player->itemtype == KITEM_FLAMESHIELD); + || (t1->player->flamedash > 0 && t1->player->itemtype == KITEM_FLAMESHIELD) + || (t1->player->curshield == KSHIELD_TOP && !K_IsHoldingDownTop(t1->player)); t2Condition = (K_IsBigger(t2, t1) == true) || (t2->player->invincibilitytimer > 0) - || (t2->player->flamedash > 0 && t2->player->itemtype == KITEM_FLAMESHIELD); + || (t2->player->flamedash > 0 && t2->player->itemtype == KITEM_FLAMESHIELD) + || (t2->player->curshield == KSHIELD_TOP && !K_IsHoldingDownTop(t2->player)); if (t1Condition == true && t2Condition == true) { diff --git a/src/k_kart.c b/src/k_kart.c index dee43b1a0..df403b881 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1374,7 +1374,13 @@ static fixed_t K_PlayerWeight(mobj_t *mobj, mobj_t *against) if (!mobj->player) return weight; - if (against && !P_MobjWasRemoved(against) && against->player + if (against && (against->type == MT_GARDENTOP || (against->player && against->player->curshield == KSHIELD_TOP))) + { + /* Players bumping into a Top get zero weight -- the + Top rider is immovable. */ + weight = 0; + } + else if (against && !P_MobjWasRemoved(against) && against->player && ((!P_PlayerInPain(against->player) && P_PlayerInPain(mobj->player)) // You're hurt || (against->player->itemtype == KITEM_BUBBLESHIELD && mobj->player->itemtype != KITEM_BUBBLESHIELD))) // They have a Bubble Shield { @@ -1962,6 +1968,18 @@ static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t cur #undef CHAOTIXBANDLEN } +static boolean K_HasInfiniteTether(player_t *player) +{ + switch (player->curshield) + { + case KSHIELD_LIGHTNING: + case KSHIELD_TOP: + return true; + } + + return false; +} + /** \brief Updates the player's drafting values once per frame \param player player object passed from K_KartPlayerThink @@ -1976,7 +1994,7 @@ static void K_UpdateDraft(player_t *player) UINT8 leniency; UINT8 i; - if (player->itemtype == KITEM_LIGHTNINGSHIELD) + if (K_HasInfiniteTether(player)) { // Lightning Shield gets infinite draft distance as its (other) passive effect. draftdistance = 0; @@ -3267,6 +3285,8 @@ boolean K_ApplyOffroad(player_t *player) { if (player->invincibilitytimer || player->hyudorotimer || player->sneakertimer) return false; + if (K_IsRidingFloatingTop(player)) + return false; return true; } @@ -3274,6 +3294,8 @@ boolean K_SlopeResistance(player_t *player) { if (player->invincibilitytimer || player->sneakertimer || player->tiregrease || player->flamedash) return true; + if (player->curshield == KSHIELD_TOP) + return true; return false; } @@ -3320,6 +3342,9 @@ boolean K_WaterRun(player_t *player) boolean K_WaterSkip(player_t *player) { + if (player->curshield == KSHIELD_TOP) + return false; + if (player->speed/3 > abs(player->mo->momz)) // Going more forward than horizontal, so you can skip across the water. return true; @@ -3531,7 +3556,7 @@ static void K_GetKartBoostPower(player_t *player) draftspeed *= 2; } - if (player->itemtype == KITEM_LIGHTNINGSHIELD) + if (K_HasInfiniteTether(player)) { // infinite tether draftspeed *= 2; @@ -3653,6 +3678,10 @@ fixed_t K_GetKartAccel(player_t *player) if (gametype == GT_BATTLE && player->bumpers <= 0) k_accel *= 2; + // Marble Garden Top gets 800% accel + if (player->curshield == KSHIELD_TOP) + k_accel *= 8; + return FixedMul(k_accel, (FRACUNIT + player->accelboost) / 4); } @@ -3742,17 +3771,35 @@ SINT8 K_GetForwardMove(player_t *player) forwardmove = MAXPLMOVE; } + if (player->curshield == KSHIELD_TOP) + { + if (forwardmove < 0 || + (K_GetKartButtons(player) & BT_DRIFT)) + { + forwardmove = 0; + } + else + { + forwardmove = MAXPLMOVE; + } + } + return forwardmove; } fixed_t K_GetNewSpeed(player_t *player) { const fixed_t accelmax = 4000; - const fixed_t p_speed = K_GetKartSpeed(player, true, true); + fixed_t p_speed = K_GetKartSpeed(player, true, true); fixed_t p_accel = K_GetKartAccel(player); fixed_t newspeed, oldspeed, finalspeed; + if (player->curshield == KSHIELD_TOP) + { + p_speed = 11 * p_speed / 10; + } + if (K_PlayerUsesBotMovement(player) == true && player->botvars.rubberband > 0) { // Acceleration is tied to top speed... @@ -8964,13 +9011,25 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) if ((currentSpeed <= 0) // Not moving && ((K_GetKartButtons(player) & BT_EBRAKEMASK) != BT_EBRAKEMASK) // Not e-braking && (player->respawn.state == RESPAWNST_NONE) // Not respawning + && (player->curshield != KSHIELD_TOP) // Not riding a Top && (P_IsObjectOnGround(player->mo) == true)) // On the ground { return 0; } p_maxspeed = K_GetKartSpeed(player, false, true); - p_speed = min(currentSpeed, (p_maxspeed * 2)); + + if (player->curshield == KSHIELD_TOP) + { + // Do not downscale turning speed with faster + // movement speed; behaves as if turning in place. + p_speed = 0; + } + else + { + p_speed = min(currentSpeed, (p_maxspeed * 2)); + } + weightadjust = FixedDiv((p_maxspeed * 3) - p_speed, (p_maxspeed * 3) + (player->kartweight * FRACUNIT)); if (K_PlayerUsesBotMovement(player)) @@ -8997,7 +9056,9 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) turnfixed = FixedMul(turnfixed, FRACUNIT + player->handleboost); } - if ((player->mo->eflags & MFE_UNDERWATER) && + if (player->curshield == KSHIELD_TOP) + ; + else if ((player->mo->eflags & MFE_UNDERWATER) && player->speed > 11 * player->mo->scale) { turnfixed /= 2; @@ -10013,6 +10074,11 @@ void K_AdjustPlayerFriction(player_t *player) player->mo->friction += ((FRACUNIT - prevfriction) / greasetics) * player->tiregrease; } + if (player->curshield == KSHIELD_TOP) + { + player->mo->friction += 1024; + } + /* if (K_PlayerEBrake(player) == true) { diff --git a/src/p_map.c b/src/p_map.c index c2b688730..bb6b2de15 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2850,6 +2850,11 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) thing->terrain = NULL; } + if (thing->player && K_IsRidingFloatingTop(thing->player)) + { + stairjank = false; + } + /* FIXME: slope step down (even up) has some false positives, so just ignore them entirely. */ if (stairjank && !oldslope && !thing->standingslope && diff --git a/src/p_mobj.c b/src/p_mobj.c index cfbea3185..1e9264ab1 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1133,7 +1133,11 @@ fixed_t P_GetMobjGravity(mobj_t *mo) gravityadd = FixedMul(TUMBLEGRAVITY, gravityadd); } - if (mo->player->fastfall != 0) + if (K_IsHoldingDownTop(mo->player)) + { + gravityadd = (5*gravityadd)/2; + } + else if (mo->player->fastfall != 0) { // Fast falling gravityadd *= 4; @@ -3092,13 +3096,26 @@ boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) fixed_t clip = flip ? (surfaceheight - playerbottom) : (playerbottom - surfaceheight); fixed_t span = player->mo->watertop - player->mo->waterbottom; - return - clip > -(player->mo->height / 2) && - span > player->mo->height && - player->speed / 5 > abs(player->mo->momz) && - player->speed > K_GetKartSpeed(player, false, false) && - K_WaterRun(player) && - (rover->flags & FF_SWIMMABLE); + if (!(rover->flags & FF_SWIMMABLE) || + clip < -(player->mo->height / 2) || + span < player->mo->height) + { + return false; + } + + if (player->curshield == KSHIELD_TOP) + { + return (K_GetKartButtons(player) & BT_DRIFT) != BT_DRIFT; + } + + if (K_WaterRun(player) && + player->speed / 5 > abs(player->mo->momz) && + player->speed > K_GetKartSpeed(player, false, false)) + { + return true; + } + + return false; } boolean P_CheckSolidFFloorSurface(player_t *player, ffloor_t *rover) diff --git a/src/p_spec.c b/src/p_spec.c index b8c103f70..7e3624036 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4426,7 +4426,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers switch (special) { case 1: // Damage (Generic) - if (roversector || P_MobjReadyToTrigger(player->mo, sector)) + if (!K_IsRidingFloatingTop(player) && (roversector || P_MobjReadyToTrigger(player->mo, sector))) P_DamageMobj(player->mo, NULL, NULL, 1, DMG_NORMAL); break; case 2: // Damage (Water) // SRB2kart - These three damage types are now offroad sectors @@ -4434,7 +4434,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers case 4: // Damage (Electrical) break; case 5: // Spikes - if (roversector || P_MobjReadyToTrigger(player->mo, sector)) + if (!K_IsRidingFloatingTop(player) && (roversector || P_MobjReadyToTrigger(player->mo, sector))) P_DamageMobj(player->mo, NULL, NULL, 1, DMG_NORMAL); break; case 6: // Death Pit (Camera Mod) diff --git a/src/p_user.c b/src/p_user.c index 8e03c1d43..622299bf8 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1801,7 +1801,7 @@ static void P_3dMovement(player_t *player) // Get the old momentum; this will be needed at the end of the function! -SH oldMagnitude = R_PointToDist2(player->mo->momx - player->cmomx, player->mo->momy - player->cmomy, 0, 0); - if (player->stairjank > 8 && leveltime & 3) + if ((player->stairjank > 8 && leveltime & 3) || K_IsRidingFloatingTop(player)) { movepushangle = K_MomentumAngle(player->mo); } @@ -1884,6 +1884,7 @@ static void P_3dMovement(player_t *player) if (player->mo->movefactor != FRACUNIT) // Friction-scaled acceleration... movepushforward = FixedMul(movepushforward, player->mo->movefactor); + if (player->curshield != KSHIELD_TOP) { INT32 a = K_GetUnderwaterTurnAdjust(player); INT32 adj = 0; @@ -1967,6 +1968,24 @@ static void P_3dMovement(player_t *player) player->mo->momx += totalthrust.x; player->mo->momy += totalthrust.y; + // Releasing a drift while on the Top translates all your + // momentum (and even then some) into whichever direction + // you're facing + if (onground && player->curshield == KSHIELD_TOP && (K_GetKartButtons(player) & BT_DRIFT) != BT_DRIFT && (player->oldcmd.buttons & BT_DRIFT)) + { + const fixed_t gmin = FRACUNIT/4; + const fixed_t gmax = 5*FRACUNIT/2; + + const fixed_t grindfactor = (gmax - gmin) / GARDENTOP_MAXGRINDTIME; + const fixed_t grindscale = gmin + (player->topdriftheld * grindfactor); + + const fixed_t speed = R_PointToDist2(0, 0, player->mo->momx, player->mo->momy); + + P_InstaThrust(player->mo, player->mo->angle, FixedMul(speed, grindscale)); + + player->topdriftheld = 0;/* reset after release */ + } + if (!onground) { const fixed_t airspeedcap = (50*mapobjectscale); From c5b132e8db3800d3dbaf2cff513300d960598351 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 28 Sep 2022 18:28:13 -0700 Subject: [PATCH 43/63] Fix -Wsign-compare --- src/k_terrain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_terrain.c b/src/k_terrain.c index 01b029b92..cd420e37a 100644 --- a/src/k_terrain.c +++ b/src/k_terrain.c @@ -1082,7 +1082,7 @@ void K_UpdateTerrainOverlay(mobj_t *mo) fixed_t speedDiv = FRACUNIT + FixedMul(FixedDiv(speed, maxSpeed), o->speed); tic_t animSpeed = max(FixedDiv(mo->state->tics, speedDiv), 1); - mo->tics = min(mo->tics, animSpeed); + mo->tics = min((tic_t)mo->tics, animSpeed); } } From 36a40d097149c8bd20d6e77546c2b50b8422b9b3 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 28 Sep 2022 21:23:49 -0700 Subject: [PATCH 44/63] Refactor weapon pref into one place --- src/d_netcmd.c | 59 +++++++++++++++++++++++++++++++++++--------------- src/d_netcmd.h | 4 +++- src/g_demo.c | 22 ++----------------- src/g_game.c | 8 +++---- 4 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index dcc351fb9..db78bd18f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1731,40 +1731,65 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) #endif } -void SendWeaponPref(UINT8 n) +enum { + WP_KICKSTARTACCEL = 1<<0, + WP_SHRINKME = 1<<1, +}; + +void WeaponPref_Send(UINT8 ssplayer) { - UINT8 buf[1]; + UINT8 prefs = 0; - buf[0] = 0; + if (cv_kickstartaccel[ssplayer].value) + prefs |= WP_KICKSTARTACCEL; - if (cv_kickstartaccel[n].value) - buf[0] |= 1; + if (cv_shrinkme[ssplayer].value) + prefs |= WP_SHRINKME; - if (cv_shrinkme[n].value) - buf[0] |= 2; - - SendNetXCmdForPlayer(n, XD_WEAPONPREF, buf, 1); + SendNetXCmdForPlayer(ssplayer, XD_WEAPONPREF, &prefs, 1); } -static void Got_WeaponPref(UINT8 **cp,INT32 playernum) +void WeaponPref_Save(UINT8 **cp, INT32 playernum) { + player_t *player = &players[playernum]; + + UINT8 prefs = 0; + + if (player->pflags & PF_KICKSTARTACCEL) + prefs |= WP_KICKSTARTACCEL; + + if (player->pflags & PF_SHRINKME) + prefs |= WP_SHRINKME; + + WRITEUINT8(*cp, prefs); +} + +void WeaponPref_Parse(UINT8 **cp, INT32 playernum) +{ + player_t *player = &players[playernum]; + UINT8 prefs = READUINT8(*cp); - players[playernum].pflags &= ~(PF_KICKSTARTACCEL|PF_SHRINKME); + player->pflags &= ~(PF_KICKSTARTACCEL|PF_SHRINKME); - if (prefs & 1) - players[playernum].pflags |= PF_KICKSTARTACCEL; + if (prefs & WP_KICKSTARTACCEL) + player->pflags |= PF_KICKSTARTACCEL; - if (prefs & 2) - players[playernum].pflags |= PF_SHRINKME; + if (prefs & WP_SHRINKME) + player->pflags |= PF_SHRINKME; if (leveltime < 2) { // BAD HACK: No other place I tried to slot this in // made it work for the host when they initally host, // so this will have to do. - K_UpdateShrinkCheat(&players[playernum]); + K_UpdateShrinkCheat(player); } +} + +static void Got_WeaponPref(UINT8 **cp,INT32 playernum) +{ + WeaponPref_Parse(cp, playernum); // SEE ALSO g_demo.c demo_extradata[playernum] |= DXD_WEAPONPREF; @@ -1952,7 +1977,7 @@ void D_SendPlayerConfig(UINT8 n) UINT8 *p = buf; SendNameAndColor(n); - SendWeaponPref(n); + WeaponPref_Send(n); if (pr != NULL) { diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 0114c726f..0f6b50ad8 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -230,7 +230,9 @@ void D_RegisterServerCommands(void); void D_RegisterClientCommands(void); void CleanupPlayerName(INT32 playernum, const char *newname); boolean EnsurePlayerNameIsGood(char *name, INT32 playernum); -void SendWeaponPref(UINT8 n); +void WeaponPref_Send(UINT8 ssplayer); +void WeaponPref_Save(UINT8 **cp, INT32 playernum); +void WeaponPref_Parse(UINT8 **cp, INT32 playernum); void D_SendPlayerConfig(UINT8 n); void Command_ExitGame_f(void); void Command_Retry_f(void); diff --git a/src/g_demo.c b/src/g_demo.c index bc1f86cc5..c025ff95d 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -364,20 +364,7 @@ void G_ReadDemoExtraData(void) } if (extradata & DXD_WEAPONPREF) { - i = READUINT8(demo_p); - players[p].pflags &= ~(PF_KICKSTARTACCEL|PF_SHRINKME); - if (i & 1) - players[p].pflags |= PF_KICKSTARTACCEL; - if (i & 2) - players[p].pflags |= PF_SHRINKME; - - if (leveltime < 2) - { - // BAD HACK: No other place I tried to slot this in - // made it work for the host when they initally host, - // so this will have to do. - K_UpdateShrinkCheat(&players[p]); - } + WeaponPref_Parse(&demo_p, p); //CONS_Printf("weaponpref is %d for player %d\n", i, p); } @@ -492,12 +479,7 @@ void G_WriteDemoExtraData(void) } if (demo_extradata[i] & DXD_WEAPONPREF) { - UINT8 prefs = 0; - if (players[i].pflags & PF_KICKSTARTACCEL) - prefs |= 1; - if (players[i].pflags & PF_SHRINKME) - prefs |= 2; - WRITEUINT8(demo_p, prefs); + WeaponPref_Save(&demo_p, i); } } diff --git a/src/g_game.c b/src/g_game.c index 181aa0697..57a25adf7 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1303,22 +1303,22 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n) static void weaponPrefChange(void) { - SendWeaponPref(0); + WeaponPref_Send(0); } static void weaponPrefChange2(void) { - SendWeaponPref(1); + WeaponPref_Send(1); } static void weaponPrefChange3(void) { - SendWeaponPref(2); + WeaponPref_Send(2); } static void weaponPrefChange4(void) { - SendWeaponPref(3); + WeaponPref_Send(3); } // From 048e7e807c6e8948af32d6a1b93a95612d5bc26a Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Sep 2022 01:37:51 -0700 Subject: [PATCH 45/63] Remove macro to disable noclip camera --- src/doomdef.h | 4 - src/p_map.c | 4 - src/p_user.c | 208 -------------------------------------------------- 3 files changed, 216 deletions(-) diff --git a/src/doomdef.h b/src/doomdef.h index 6997d7951..63318ef5e 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -691,10 +691,6 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; #undef UPDATE_ALERT #endif -/// - SRB2Kart options - -/// Camera always has noclip. -#define NOCLIPCAM - /// Other karma comeback modes //#define OTHERKARMAMODES diff --git a/src/p_map.c b/src/p_map.c index 62baa23e6..6f3f5ad13 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2354,11 +2354,7 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) fixed_t tryx = thiscam->x; fixed_t tryy = thiscam->y; -#ifndef NOCLIPCAM - if ((players[displayplayers[i]].cheats & PC_NOCLIP) || (leveltime < introtime)) // Noclipping player camera noclips too!! -#else if (!(players[displayplayers[i]].pflags & PF_NOCONTEST)) // Time Over should not clip through walls -#endif { floatok = true; thiscam->floorz = thiscam->z; diff --git a/src/p_user.c b/src/p_user.c index 5261b84cb..b1c35a839 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3068,10 +3068,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall mobj_t *mo; fixed_t f1, f2; fixed_t speed; -#ifndef NOCLIPCAM - boolean cameranoclip; - subsector_t *newsubsec; -#endif fixed_t playerScale = FixedDiv(player->mo->scale, mapobjectscale); fixed_t scaleDiff = playerScale - FRACUNIT; @@ -3129,12 +3125,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall return true; } -#ifndef NOCLIPCAM - cameranoclip = ((player->cheats & PC_NOCLIP) - || (mo->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)) // Noclipping player camera noclips too!! - || (leveltime < introtime)); // Kart intro cam -#endif - if ((player->pflags & PF_NOCONTEST) && (gametyperules & GTR_CIRCUIT)) // 1 for momentum keep, 2 for turnaround timeover = (player->karthud[khud_timeovercam] > 2*TICRATE ? 2 : 1); else @@ -3377,204 +3367,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall z = mo->z + pviewheight + distz; } -#ifndef NOCLIPCAM // Disable all z-clipping for noclip cam - // move camera down to move under lower ceilings - newsubsec = R_PointInSubsectorOrNull(((mo->x>>FRACBITS) + (thiscam->x>>FRACBITS))<<(FRACBITS-1), ((mo->y>>FRACBITS) + (thiscam->y>>FRACBITS))<<(FRACBITS-1)); - - if (!newsubsec) - newsubsec = thiscam->subsector; - - if (newsubsec) - { - fixed_t myfloorz, myceilingz; - fixed_t midz = thiscam->z + (thiscam->z - mo->z)/2; - fixed_t midx = ((mo->x>>FRACBITS) + (thiscam->x>>FRACBITS))<<(FRACBITS-1); - fixed_t midy = ((mo->y>>FRACBITS) + (thiscam->y>>FRACBITS))<<(FRACBITS-1); - - // Cameras use the heightsec's heights rather then the actual sector heights. - // If you can see through it, why not move the camera through it too? - if (newsubsec->sector->camsec >= 0) - { - myfloorz = sectors[newsubsec->sector->camsec].floorheight; - myceilingz = sectors[newsubsec->sector->camsec].ceilingheight; - } - else if (newsubsec->sector->heightsec >= 0) - { - myfloorz = sectors[newsubsec->sector->heightsec].floorheight; - myceilingz = sectors[newsubsec->sector->heightsec].ceilingheight; - } - else - { - myfloorz = P_CameraGetFloorZ(thiscam, newsubsec->sector, midx, midy, NULL); - myceilingz = P_CameraGetCeilingZ(thiscam, newsubsec->sector, midx, midy, NULL); - } - - // Check list of fake floors and see if floorz/ceilingz need to be altered. - if (newsubsec->sector->ffloors) - { - ffloor_t *rover; - fixed_t delta1, delta2; - INT32 thingtop = midz + thiscam->height; - - for (rover = newsubsec->sector->ffloors; rover; rover = rover->next) - { - fixed_t topheight, bottomheight; - if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERALL) || GETSECSPECIAL(rover->master->frontsector->special, 4) == 12) - continue; - - topheight = P_CameraGetFOFTopZ(thiscam, newsubsec->sector, rover, midx, midy, NULL); - bottomheight = P_CameraGetFOFBottomZ(thiscam, newsubsec->sector, rover, midx, midy, NULL); - - delta1 = midz - (bottomheight - + ((topheight - bottomheight)/2)); - delta2 = thingtop - (bottomheight - + ((topheight - bottomheight)/2)); - if (topheight > myfloorz && abs(delta1) < abs(delta2)) - myfloorz = topheight; - if (bottomheight < myceilingz && abs(delta1) >= abs(delta2)) - myceilingz = bottomheight; - } - } - - // Check polyobjects and see if floorz/ceilingz need to be altered - { - INT32 xl, xh, yl, yh, bx, by; - validcount++; - - xl = (unsigned)(tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; - - BMBOUNDFIX(xl, xh, yl, yh); - - for (by = yl; by <= yh; by++) - for (bx = xl; bx <= xh; bx++) - { - INT32 offset; - polymaplink_t *plink; // haleyjd 02/22/06 - - if (bx < 0 || by < 0 || bx >= bmapwidth || by >= bmapheight) - continue; - - offset = by*bmapwidth + bx; - - // haleyjd 02/22/06: consider polyobject lines - plink = polyblocklinks[offset]; - - while (plink) - { - polyobj_t *po = plink->po; - - if (po->validcount != validcount) // if polyobj hasn't been checked - { - sector_t *polysec; - fixed_t delta1, delta2, thingtop; - fixed_t polytop, polybottom; - - po->validcount = validcount; - - if (!P_PointInsidePolyobj(po, x, y) || !(po->flags & POF_SOLID)) - { - plink = (polymaplink_t *)(plink->link.next); - continue; - } - - // We're inside it! Yess... - polysec = po->lines[0]->backsector; - - if (GETSECSPECIAL(polysec->special, 4) == 12) - { // Camera noclip polyobj. - plink = (polymaplink_t *)(plink->link.next); - continue; - } - - if (po->flags & POF_CLIPPLANES) - { - polytop = polysec->ceilingheight; - polybottom = polysec->floorheight; - } - else - { - polytop = INT32_MAX; - polybottom = INT32_MIN; - } - - thingtop = midz + thiscam->height; - delta1 = midz - (polybottom + ((polytop - polybottom)/2)); - delta2 = thingtop - (polybottom + ((polytop - polybottom)/2)); - - if (polytop > myfloorz && abs(delta1) < abs(delta2)) - myfloorz = polytop; - - if (polybottom < myceilingz && abs(delta1) >= abs(delta2)) - myceilingz = polybottom; - } - plink = (polymaplink_t *)(plink->link.next); - } - } - } - - // crushed camera - if (myceilingz <= myfloorz + thiscam->height && !resetcalled && !cameranoclip) - { - P_ResetCamera(player, thiscam); - return true; - } - - // camera fit? - if (myceilingz != myfloorz - && myceilingz - thiscam->height < z) - { -/* // no fit - if (!resetcalled && !cameranoclip) - { - P_ResetCamera(player, thiscam); - return true; - } -*/ - z = myceilingz - thiscam->height-FixedMul(11*FRACUNIT, mo->scale); - // is the camera fit is there own sector - } - - // Make the camera a tad smarter with 3d floors - if (newsubsec->sector->ffloors && !cameranoclip) - { - ffloor_t *rover; - - for (rover = newsubsec->sector->ffloors; rover; rover = rover->next) - { - fixed_t topheight, bottomheight; - if ((rover->flags & FF_BLOCKOTHERS) && (rover->flags & FF_RENDERALL) && (rover->flags & FF_EXISTS) && GETSECSPECIAL(rover->master->frontsector->special, 4) == 12) - { - topheight = P_CameraGetFOFTopZ(thiscam, newsubsec->sector, rover, midx, midy, NULL); - bottomheight = P_CameraGetFOFBottomZ(thiscam, newsubsec->sector, rover, midx, midy, NULL); - - if (bottomheight - thiscam->height < z - && midz < bottomheight) - z = bottomheight - thiscam->height-FixedMul(11*FRACUNIT, mo->scale); - - else if (topheight + thiscam->height > z - && midz > topheight) - z = topheight; - - if ((mo->z >= topheight && midz < bottomheight) - || ((mo->z < bottomheight && mo->z+mo->height < topheight) && midz >= topheight)) - { - // Can't see - if (!resetcalled) - P_ResetCamera(player, thiscam); - return true; - } - } - } - } - } - - if (thiscam->z < thiscam->floorz && !cameranoclip) - thiscam->z = thiscam->floorz; -#endif // NOCLIPCAM - // point viewed by the camera // this point is just 64 unit forward the player dist = 64*cameraScale; From 0444e704131cd74556240b238ad7de313b7c7db7 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Sep 2022 02:23:07 -0700 Subject: [PATCH 46/63] Rearrange player cheat flags PC_GODMODE -> PF_GODMODE PC_NOCLIP -> MF_NOCLIP --- src/command.c | 9 --------- src/d_player.h | 15 ++++----------- src/deh_tables.c | 5 +++-- src/g_game.c | 10 ---------- src/m_cheat.c | 13 ++++--------- src/p_inter.c | 2 +- src/p_mobj.c | 4 ++-- 7 files changed, 14 insertions(+), 44 deletions(-) diff --git a/src/command.c b/src/command.c index 0015bcf1c..d1355a923 100644 --- a/src/command.c +++ b/src/command.c @@ -1891,7 +1891,6 @@ void CV_CheatsChanged(void) else { consvar_t *cvar; - UINT8 i; // Set everything back to default. for (cvar = consvar_vars; cvar; cvar = cvar->next) @@ -1900,14 +1899,6 @@ void CV_CheatsChanged(void) // Reset any other cheat command effects here, as well. cv_debug = 0; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - - players[i].cheats = 0; - } } } diff --git a/src/d_player.h b/src/d_player.h index f2943dd18..debfb6675 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -58,14 +58,15 @@ typedef enum // typedef enum { - // free: 1<<0 to 1<<2 + PF_GODMODE = 1<<0, // Immortal. No lightsnake from pits either + + // free: 1<<1 and 1<<2 // Look back VFX has been spawned // TODO: Is there a better way to track this? PF_GAINAX = 1<<3, - // Accessibility and cheats - PF_KICKSTARTACCEL = 1<<4, // Is accelerate in kickstart mode? + PF_KICKSTARTACCEL = 1<<4, // Accessibility feature: Is accelerate in kickstart mode? // 1<<5 free // 1<<6 free @@ -105,13 +106,6 @@ typedef enum // up to 1<<31 is free } pflags_t; -typedef enum -{ - PC_GODMODE = 1, - PC_NOCLIP = 1<<1, - // up to 1<<31 is free -} pcheats_t; - typedef enum { // Are animation frames playing? @@ -372,7 +366,6 @@ typedef struct player_s // Bit flags. // See pflags_t, above. pflags_t pflags; - pcheats_t cheats; // playing animation. panim_t panim; diff --git a/src/deh_tables.c b/src/deh_tables.c index a0084ec85..084f347ac 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5708,8 +5708,9 @@ const char *const MAPTHINGFLAG_LIST[4] = { }; const char *const PLAYERFLAG_LIST[] = { - // free: 1<<0 to 1<<2 (name un-matchable) - "\x01", + "GODMODE", + + // free: 1<<1 and 1<<2 (name un-matchable) "\x01", "\x01", diff --git a/src/g_game.c b/src/g_game.c index 181aa0697..f3c807ed8 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2218,7 +2218,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) UINT32 followitem; INT32 pflags; - INT32 cheats; UINT8 ctfteam; @@ -2298,7 +2297,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) botrival = players[player].botvars.rival; pflags = (players[player].pflags & (PF_WANTSTOJOIN|PF_KICKSTARTACCEL|PF_SHRINKME|PF_SHRINKACTIVE)); - cheats = 0; // SRB2kart if (betweenmaps || leveltime < introtime) @@ -2373,10 +2371,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) pflags |= (players[player].pflags & (PF_STASIS|PF_ELIMINATED|PF_NOCONTEST|PF_FAULT|PF_LOSTLIFE)); } - // As long as we're not in multiplayer, carry over cheatcodes from map to map - if (!(netgame || multiplayer)) - cheats = players[player].cheats; - if (!betweenmaps) { // Obliterate follower from existence (if valid memory) @@ -2392,7 +2386,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->roundscore = roundscore; p->lives = lives; p->pflags = pflags; - p->cheats = cheats; p->ctfteam = ctfteam; p->jointime = jointime; p->splitscreenindex = splitscreenindex; @@ -4783,9 +4776,6 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr players[i].playerstate = PST_REBORN; memset(&players[i].respawn, 0, sizeof (players[i].respawn)); - // Clear cheatcodes too, just in case. - players[i].cheats = 0; - players[i].roundscore = 0; if (resetplayer && !(multiplayer && demo.playback)) // SRB2Kart diff --git a/src/m_cheat.c b/src/m_cheat.c index 98043cd2d..5c9c0015e 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -262,13 +262,8 @@ void Command_CheatNoClip_f(void) if (!plyr->mo || P_MobjWasRemoved(plyr->mo)) return; - plyr->cheats ^= PC_NOCLIP; - CONS_Printf(M_GetText("No Clipping %s\n"), plyr->cheats & PC_NOCLIP ? M_GetText("On") : M_GetText("Off")); - - if (plyr->cheats & PC_NOCLIP) - plyr->mo->flags |= MF_NOCLIP; - else - plyr->mo->flags &= ~MF_NOCLIP; + plyr->mo->flags ^= MF_NOCLIP; + CONS_Printf(M_GetText("No Clipping %s\n"), plyr->mo->flags & MF_NOCLIP ? M_GetText("On") : M_GetText("Off")); } void Command_CheatGod_f(void) @@ -280,8 +275,8 @@ void Command_CheatGod_f(void) REQUIRE_SINGLEPLAYER; // TODO: make multiplayer compatible plyr = &players[consoleplayer]; - plyr->cheats ^= PC_GODMODE; - CONS_Printf(M_GetText("Cheese Mode %s\n"), plyr->cheats & PC_GODMODE ? M_GetText("On") : M_GetText("Off")); + plyr->pflags ^= PF_GODMODE; + CONS_Printf(M_GetText("Cheese Mode %s\n"), plyr->pflags & PF_GODMODE ? M_GetText("On") : M_GetText("Off")); } void Command_Scale_f(void) diff --git a/src/p_inter.c b/src/p_inter.c index 19f03c664..97171f201 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1874,7 +1874,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (player) // Player is the target { - if (player->cheats & PC_GODMODE) + if (player->pflags & PF_GODMODE) return false; if (!force) diff --git a/src/p_mobj.c b/src/p_mobj.c index 9b08f0e75..add104e5d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2082,7 +2082,7 @@ boolean P_CheckDeathPitCollide(mobj_t *mo) I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); - if (mo->player && mo->player->cheats & PC_GODMODE) + if (mo->player && mo->player->pflags & PF_GODMODE) return false; if (((mo->z <= mo->subsector->sector->floorheight @@ -3620,7 +3620,7 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled player->karthud[khud_timeovercam] = (2*TICRATE)+1; } - if (!resetcalled && !(player->cheats & PC_NOCLIP || leveltime < introtime) && !P_CheckSight(&dummy, player->mo)) // TODO: "P_CheckCameraSight" instead. + if (!resetcalled && !(player->mo->flags & MF_NOCLIP || leveltime < introtime) && !P_CheckSight(&dummy, player->mo)) // TODO: "P_CheckCameraSight" instead. { P_ResetCamera(player, thiscam); } From e30232e1031661db756cb74d78714c4bc16b623c Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Sep 2022 03:16:11 -0700 Subject: [PATCH 47/63] Kill last of MF2_TWOD -- toggletwod, line action 432 --- src/d_netcmd.c | 1 - src/deh_tables.c | 2 +- src/m_cheat.c | 12 ------------ src/m_cheat.h | 1 - src/p_mobj.h | 2 +- src/p_spec.c | 10 ---------- src/p_telept.c | 2 +- 7 files changed, 3 insertions(+), 27 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index dcc351fb9..1d43a8bda 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1094,7 +1094,6 @@ void D_RegisterClientCommands(void) COM_AddCommand("rteleport", Command_RTeleport_f); COM_AddCommand("skynum", Command_Skynum_f); COM_AddCommand("weather", Command_Weather_f); - COM_AddCommand("toggletwod", Command_Toggletwod_f); #ifdef _DEBUG COM_AddCommand("causecfail", Command_CauseCfail_f); #endif diff --git a/src/deh_tables.c b/src/deh_tables.c index a0084ec85..be283371e 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5649,7 +5649,7 @@ const char *const MOBJFLAG_LIST[] = { // \tMF2_(\S+).*// (.+) --> \t"\1", // \2 const char *const MOBJFLAG2_LIST[] = { "AXIS", // It's a NiGHTS axis! (For faster checking) - "TWOD", // Moves like it's in a 2D level + "\x01", // free: 1<<1 (name un-matchable) "DONTRESPAWN", // Don't respawn this object! "\x01", // free: 1<<3 (name un-matchable) "AUTOMATIC", // Thrown ring has automatic properties diff --git a/src/m_cheat.c b/src/m_cheat.c index 98043cd2d..a17e33d4b 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -651,18 +651,6 @@ void Command_Weather_f(void) P_SwitchWeather(atoi(COM_Argv(1))); } -void Command_Toggletwod_f(void) -{ - player_t *p = &players[consoleplayer]; - - REQUIRE_CHEATS; - REQUIRE_INLEVEL; - REQUIRE_SINGLEPLAYER; // TODO: make multiplayer compatible - - if (p->mo) - p->mo->flags2 ^= MF2_TWOD; -} - #ifdef _DEBUG // You never thought you needed this, did you? >=D // Yes, this has the specific purpose of completely screwing you up diff --git a/src/m_cheat.h b/src/m_cheat.h index ec1a129cf..2f82c71ec 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -56,7 +56,6 @@ void Command_Teleport_f(void); void Command_RTeleport_f(void); void Command_Skynum_f(void); void Command_Weather_f(void); -void Command_Toggletwod_f(void); #ifdef _DEBUG void Command_CauseCfail_f(void); #endif diff --git a/src/p_mobj.h b/src/p_mobj.h index 4cdacea6d..34329107b 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -169,7 +169,7 @@ typedef enum typedef enum { MF2_AXIS = 1, // It's a NiGHTS axis! (For faster checking) - MF2_TWOD = 1<<1, // Moves like it's in a 2D level + // free: 1<<1 MF2_DONTRESPAWN = 1<<2, // Don't respawn this object! // free: 1<<3 MF2_AUTOMATIC = 1<<4, // Thrown ring has automatic properties diff --git a/src/p_spec.c b/src/p_spec.c index b8c103f70..cd5d922fb 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2836,16 +2836,6 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) EV_DoCrush(line, crushBothOnce); break; - case 432: // Enable 2D Mode (Disable if noclimb) - if (mo && mo->player) - { - if (line->flags & ML_NOCLIMB) - mo->flags2 &= ~MF2_TWOD; - else - mo->flags2 |= MF2_TWOD; - } - break; - case 433: // Flip gravity (Flop gravity if noclimb) Works on pushables, too! if (line->flags & ML_NOCLIMB) mo->flags2 &= ~MF2_OBJECTFLIP; diff --git a/src/p_telept.c b/src/p_telept.c index 59774dd76..530830ad3 100644 --- a/src/p_telept.c +++ b/src/p_telept.c @@ -35,7 +35,7 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, INT32 starpostnum, tic_t starposttime, angle_t starpostangle, fixed_t starpostscale, angle_t drawangle, INT32 flags2) { - const INT32 takeflags2 = MF2_TWOD|MF2_OBJECTFLIP; + const INT32 takeflags2 = MF2_OBJECTFLIP; UINT8 i; (void)starposttime; From 64263583775b98bb6dea2c34e4ccfc2fbf29edb7 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Sep 2022 02:24:55 -0700 Subject: [PATCH 48/63] Let some cheat commands work online noclip god scale gravflip hurtme --- src/command.c | 1 + src/d_netcmd.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++- src/d_netcmd.h | 3 ++ src/m_cheat.c | 33 ++---------- src/m_cheat.h | 10 ++++ 5 files changed, 152 insertions(+), 29 deletions(-) diff --git a/src/command.c b/src/command.c index d1355a923..6358858cb 100644 --- a/src/command.c +++ b/src/command.c @@ -37,6 +37,7 @@ #include "r_data.h" // Color_cons_t #include "r_skins.h" #include "m_random.h" +#include "p_local.h" // P_ResetPlayerCheats //======== // protos. diff --git a/src/d_netcmd.c b/src/d_netcmd.c index dcc351fb9..652a41290 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -96,6 +96,7 @@ static void Got_DiscordInfo(UINT8 **cp, INT32 playernum); static void Got_ScheduleTaskcmd(UINT8 **cp, INT32 playernum); static void Got_ScheduleClearcmd(UINT8 **cp, INT32 playernum); static void Got_Automatecmd(UINT8 **cp, INT32 playernum); +static void Got_Cheat(UINT8 **cp, INT32 playernum); static void PointLimit_OnChange(void); static void TimeLimit_OnChange(void); @@ -625,7 +626,8 @@ const char *netxcmdnames[MAXNETXCMD - 1] = "PLAYSOUND", // XD_PLAYSOUND "SCHEDULETASK", // XD_SCHEDULETASK "SCHEDULECLEAR", // XD_SCHEDULECLEAR - "AUTOMATE" // XD_AUTOMATE + "AUTOMATE", // XD_AUTOMATE + "CHEAT", // XD_CHEAT }; // ========================================================================= @@ -678,6 +680,8 @@ void D_RegisterServerCommands(void) RegisterNetXCmd(XD_SCHEDULECLEAR, Got_ScheduleClearcmd); RegisterNetXCmd(XD_AUTOMATE, Got_Automatecmd); + RegisterNetXCmd(XD_CHEAT, Got_Cheat); + // Remote Administration COM_AddCommand("password", Command_Changepassword_f); COM_AddCommand("login", Command_Login_f); // useful in dedicated to kick off remote admin @@ -1970,6 +1974,42 @@ void D_SendPlayerConfig(UINT8 n) SendNetXCmdForPlayer(n, XD_POWERLEVEL, buf, p-buf); } +void D_Cheat(INT32 playernum, INT32 cheat, ...) +{ + va_list ap; + + UINT8 buf[64]; + UINT8 *p = buf; + + if (!CV_CheatsEnabled()) + { + CONS_Printf("This cannot be used without cheats enabled.\n"); + return; + } + + WRITEUINT8(p, playernum); + WRITEUINT8(p, cheat); + + va_start(ap, cheat); +#define COPY(writemacro, type) writemacro (p, va_arg(ap, type)) + + switch (cheat) + { + case CHEAT_SCALE: + COPY(WRITEFIXED, fixed_t); + break; + + case CHEAT_HURT: + COPY(WRITEINT32, INT32); + break; + } + +#undef COPY + va_end(ap); + + SendNetXCmd(XD_CHEAT, buf, p - buf); +} + // Only works for displayplayer, sorry! static void Command_ResetCamera_f(void) { @@ -5409,6 +5449,98 @@ static void Got_Automatecmd(UINT8 **cp, INT32 playernum) } } +static void Got_Cheat(UINT8 **cp, INT32 playernum) +{ + UINT8 targetPlayer = READUINT8(*cp); + cheat_t cheat = READUINT8(*cp); + + player_t *player; + + if (cheat >= NUMBER_OF_CHEATS || !CV_CheatsEnabled() || targetPlayer >= MAXPLAYERS || + playernode[targetPlayer] != playernode[playernum]) + { + CONS_Alert(CONS_WARNING, + M_GetText ("Illegal cheat command received from %s\n"), + player_names[playernum]); + return; + } + + player = &players[targetPlayer]; + + switch (cheat) + { + case CHEAT_NOCLIP: { + const char *status = "on"; + + if (!P_MobjWasRemoved(player->mo)) + { + player->mo->flags ^= MF_NOCLIP; + + if (!(player->mo->flags & MF_NOCLIP)) + { + status = "off"; + } + } + + CV_CheaterWarning(targetPlayer, va("noclip %s", status)); + break; + } + + case CHEAT_GOD: { + const char *status = (player->pflags & PF_GODMODE) ? "off" : "on"; + + player->pflags ^= PF_GODMODE; + + CV_CheaterWarning(targetPlayer, va("GOD MODE %s", status)); + break; + } + + case CHEAT_SCALE: { + const fixed_t smin = FRACUNIT/100; + const fixed_t smax = 100*FRACUNIT; + + fixed_t s = READFIXED(*cp); + float f; + + s = min(max(smin, s), smax); + f = FIXED_TO_FLOAT(s); + + if (!P_MobjWasRemoved(player->mo)) + { + player->mo->destscale = s; + } + + CV_CheaterWarning(targetPlayer, va("scale = %d%s", (int)f, M_Ftrim(FIXED_TO_FLOAT(s)))); + break; + } + + case CHEAT_FLIP: { + if (!P_MobjWasRemoved(player->mo)) + { + player->mo->flags2 ^= MF2_OBJECTFLIP; + } + + CV_CheaterWarning(targetPlayer, "invert gravity"); + break; + } + + case CHEAT_HURT: { + INT32 damage = READINT32(*cp); + + if (!P_MobjWasRemoved(player->mo)) + { + P_DamageMobj(player->mo, NULL, NULL, damage, DMG_NORMAL); + } + + CV_CheaterWarning(targetPlayer, va("%d damage to me", damage)); + break; + } + + case NUMBER_OF_CHEATS: + break; + } +} + /** Prints the number of displayplayers[0]. * * \todo Possibly remove this; it was useful for debugging at one point. diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 0114c726f..48c658ae3 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -179,6 +179,7 @@ typedef enum XD_SCHEDULETASK, // 36 XD_SCHEDULECLEAR, // 37 XD_AUTOMATE, // 38 + XD_CHEAT, // 39 MAXNETXCMD } netxcmd_t; @@ -278,6 +279,8 @@ void Automate_Clear(void); extern UINT32 livestudioaudience_timer; void LiveStudioAudience(void); +void D_Cheat(INT32 playernum, INT32 cheat, ...); + // used for the player setup menu UINT8 CanChangeSkin(INT32 playernum); diff --git a/src/m_cheat.c b/src/m_cheat.c index 5c9c0015e..a7c183b98 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -251,32 +251,18 @@ boolean cht_Responder(event_t *ev) // command that can be typed at the console! void Command_CheatNoClip_f(void) { - player_t *plyr; - REQUIRE_CHEATS; REQUIRE_INLEVEL; - REQUIRE_SINGLEPLAYER; // TODO: make netplay compatible - plyr = &players[consoleplayer]; - - if (!plyr->mo || P_MobjWasRemoved(plyr->mo)) - return; - - plyr->mo->flags ^= MF_NOCLIP; - CONS_Printf(M_GetText("No Clipping %s\n"), plyr->mo->flags & MF_NOCLIP ? M_GetText("On") : M_GetText("Off")); + D_Cheat(consoleplayer, CHEAT_NOCLIP); } void Command_CheatGod_f(void) { - player_t *plyr; - REQUIRE_CHEATS; REQUIRE_INLEVEL; - REQUIRE_SINGLEPLAYER; // TODO: make multiplayer compatible - plyr = &players[consoleplayer]; - plyr->pflags ^= PF_GODMODE; - CONS_Printf(M_GetText("Cheese Mode %s\n"), plyr->pflags & PF_GODMODE ? M_GetText("On") : M_GetText("Off")); + D_Cheat(consoleplayer, CHEAT_GOD); } void Command_Scale_f(void) @@ -286,7 +272,6 @@ void Command_Scale_f(void) REQUIRE_CHEATS; REQUIRE_INLEVEL; - REQUIRE_SINGLEPLAYER; // TODO: make multiplayer compatible if (scale < FRACUNIT/100 || scale > 100*FRACUNIT) //COM_Argv(1) will return a null string if they did not give a paramater, so... { @@ -294,29 +279,21 @@ void Command_Scale_f(void) return; } - if (!players[consoleplayer].mo) - return; - - players[consoleplayer].mo->destscale = scale; - - CONS_Printf(M_GetText("Scale set to %s\n"), COM_Argv(1)); + D_Cheat(consoleplayer, CHEAT_SCALE, scale); } void Command_Gravflip_f(void) { REQUIRE_CHEATS; REQUIRE_INLEVEL; - REQUIRE_SINGLEPLAYER; // TODO: make multiplayer compatible - if (players[consoleplayer].mo) - players[consoleplayer].mo->flags2 ^= MF2_OBJECTFLIP; + D_Cheat(consoleplayer, CHEAT_FLIP); } void Command_Hurtme_f(void) { REQUIRE_CHEATS; REQUIRE_INLEVEL; - REQUIRE_SINGLEPLAYER; // TODO: make multiplayer compatible if (COM_Argc() < 2) { @@ -324,7 +301,7 @@ void Command_Hurtme_f(void) return; } - P_DamageMobj(players[consoleplayer].mo, NULL, NULL, atoi(COM_Argv(1)), DMG_NORMAL); + D_Cheat(consoleplayer, CHEAT_HURT, atoi(COM_Argv(1))); } void Command_RTeleport_f(void) diff --git a/src/m_cheat.h b/src/m_cheat.h index ec1a129cf..080fe9997 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -19,6 +19,16 @@ #include "p_mobj.h" #include "command.h" +typedef enum { + CHEAT_NOCLIP, + CHEAT_GOD, + CHEAT_SCALE, + CHEAT_FLIP, + CHEAT_HURT, + + NUMBER_OF_CHEATS +} cheat_t; + boolean cht_Responder(event_t *ev); void cht_Init(void); From 57a3c4109c25178bf6b1ed99f229b8c8f8b0ea6b Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Sep 2022 02:39:19 -0700 Subject: [PATCH 49/63] Reset player cheat effects when disabling cheats cvar --- src/command.c | 2 ++ src/p_local.h | 2 ++ src/p_user.c | 24 ++++++++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/command.c b/src/command.c index 6358858cb..75e8fc06a 100644 --- a/src/command.c +++ b/src/command.c @@ -1900,6 +1900,8 @@ void CV_CheatsChanged(void) // Reset any other cheat command effects here, as well. cv_debug = 0; + + P_ResetPlayerCheats(); } } diff --git a/src/p_local.h b/src/p_local.h index 5fc73f1a2..4f9fa9c23 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -195,6 +195,8 @@ void P_PlayerAfterThink(player_t *player); void P_DoPlayerExit(player_t *player); void P_DoTimeOver(player_t *player); +void P_ResetPlayerCheats(void); + void P_InstaThrust(mobj_t *mo, angle_t angle, fixed_t move); fixed_t P_ReturnThrustX(mobj_t *mo, angle_t angle, fixed_t move); fixed_t P_ReturnThrustY(mobj_t *mo, angle_t angle, fixed_t move); diff --git a/src/p_user.c b/src/p_user.c index b1c35a839..a02b8e223 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4452,3 +4452,27 @@ boolean P_PlayerFullbright(player_t *player) { return (player->invincibilitytimer > 0); } + +void P_ResetPlayerCheats(void) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *player = &players[i]; + mobj_t *thing = player->mo; + + if (!playeringame[i]) + continue; + + player->pflags &= ~(PF_GODMODE); + + if (P_MobjWasRemoved(thing)) + continue; + + thing->flags &= ~(MF_NOCLIP); + + thing->destscale = mapobjectscale; + P_SetScale(thing, thing->destscale); + } +} From db92d9068e81d253845ab0598cf7875e0b2cc8d2 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Sep 2022 04:50:55 -0700 Subject: [PATCH 50/63] Netsync setrings and setlives - setrings no longer subtracts totalrings - removed INFLIVES --- src/d_netcmd.c | 29 +++++++++++++++++++++++++++++ src/d_player.h | 3 --- src/deh_tables.c | 3 --- src/m_cheat.c | 23 ++--------------------- src/m_cheat.h | 2 ++ 5 files changed, 33 insertions(+), 27 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 652a41290..e95df4d75 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1995,6 +1995,13 @@ void D_Cheat(INT32 playernum, INT32 cheat, ...) switch (cheat) { + case CHEAT_RINGS: + case CHEAT_LIVES: + // If you're confused why 'int' instead of + // 'SINT8', search online: 'default argument promotions' + COPY(WRITESINT8, int); + break; + case CHEAT_SCALE: COPY(WRITEFIXED, fixed_t); break; @@ -5495,6 +5502,28 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum) break; } + case CHEAT_RINGS: { + SINT8 rings = READSINT8(*cp); + + // P_GivePlayerRings does value clamping + player->rings = 0; + P_GivePlayerRings(player, rings); + + CV_CheaterWarning(targetPlayer, va("rings = %d", rings)); + break; + } + + case CHEAT_LIVES: { + SINT8 lives = READSINT8(*cp); + + // P_GivePlayerLives does value clamping + player->lives = 0; + P_GivePlayerLives(player, lives); + + CV_CheaterWarning(targetPlayer, va("lives = %d", lives)); + break; + } + case CHEAT_SCALE: { const fixed_t smin = FRACUNIT/100; const fixed_t smax = 100*FRACUNIT; diff --git a/src/d_player.h b/src/d_player.h index debfb6675..28d126b55 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -602,7 +602,4 @@ typedef struct player_s #endif } player_t; -// Value for infinite lives -#define INFLIVES 0x7F - #endif diff --git a/src/deh_tables.c b/src/deh_tables.c index 084f347ac..fdd7d184f 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -6347,9 +6347,6 @@ struct int_const_s const INT_CONST[] = { {"PA_DRIFT",PA_DRIFT}, {"PA_HURT",PA_HURT}, - // Value for infinite lives - {"INFLIVES",INFLIVES}, - // Got Flags, for player->gotflag! // Used to be MF_ for some stupid reason, now they're GF_ to stop them looking like mobjflags {"GF_REDFLAG",GF_REDFLAG}, diff --git a/src/m_cheat.c b/src/m_cheat.c index a7c183b98..ff82ce556 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -748,13 +748,7 @@ void Command_Setrings_f(void) REQUIRE_CHEATS; REQUIRE_INLEVEL; - if (COM_Argc() > 1) - { - // P_GivePlayerRings does value clamping - players[consoleplayer].rings = 0; - P_GivePlayerRings(&players[consoleplayer], atoi(COM_Argv(1))); - players[consoleplayer].totalring -= atoi(COM_Argv(1)); //undo totalring addition done in P_GivePlayerRings - } + D_Cheat(consoleplayer, CHEAT_RINGS, atoi(COM_Argv(1))); } void Command_Setlives_f(void) @@ -762,20 +756,7 @@ void Command_Setlives_f(void) REQUIRE_CHEATS; REQUIRE_INLEVEL; - if (COM_Argc() > 1) - { - SINT8 lives = atoi(COM_Argv(1)); - if (lives == -1) - { - players[consoleplayer].lives = INFLIVES; // infinity! - } - else - { - // P_GivePlayerLives does value clamping - players[consoleplayer].lives = 0; - P_GivePlayerLives(&players[consoleplayer], atoi(COM_Argv(1))); - } - } + D_Cheat(consoleplayer, CHEAT_LIVES, atoi(COM_Argv(1))); } // diff --git a/src/m_cheat.h b/src/m_cheat.h index 080fe9997..e12366b0f 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -22,6 +22,8 @@ typedef enum { CHEAT_NOCLIP, CHEAT_GOD, + CHEAT_RINGS, + CHEAT_LIVES, CHEAT_SCALE, CHEAT_FLIP, CHEAT_HURT, From 63af0882314efe2a62cd3f3935bb9ceee08c0c82 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Sep 2022 04:55:39 -0700 Subject: [PATCH 51/63] Let skynum work online I see no reason why it shouldn't. --- src/m_cheat.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/m_cheat.c b/src/m_cheat.c index ff82ce556..70758b864 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -591,7 +591,6 @@ void Command_Skynum_f(void) { REQUIRE_CHEATS; REQUIRE_INLEVEL; - REQUIRE_SINGLEPLAYER; // TODO: make multiplayer compatible if (COM_Argc() != 2) { From 0024332f34adfbaea543f44fa5ebe62b902aeb09 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Sep 2022 06:10:53 -0700 Subject: [PATCH 52/63] Let relativeteleport work online Requires all x, y, z arguments. Floats supported. Old: rteleport -x 1 -y 2 -z 3 New: rteleport 1.1 2.2 3.3 --- src/d_netcmd.c | 39 ++++++++++++++++++++++++++++++++++ src/m_cheat.c | 57 +++++++------------------------------------------- src/m_cheat.h | 1 + 3 files changed, 47 insertions(+), 50 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index e95df4d75..1efae4c43 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2009,6 +2009,12 @@ void D_Cheat(INT32 playernum, INT32 cheat, ...) case CHEAT_HURT: COPY(WRITEINT32, INT32); break; + + case CHEAT_RELATIVE_TELEPORT: + COPY(WRITEFIXED, fixed_t); + COPY(WRITEFIXED, fixed_t); + COPY(WRITEFIXED, fixed_t); + break; } #undef COPY @@ -5565,6 +5571,39 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum) break; } + case CHEAT_RELATIVE_TELEPORT: { + fixed_t x = READFIXED(*cp); + fixed_t y = READFIXED(*cp); + fixed_t z = READFIXED(*cp); + + float f[3] = { + FIXED_TO_FLOAT(x), + FIXED_TO_FLOAT(y), + FIXED_TO_FLOAT(z), + }; + char t[3][9]; + + if (!P_MobjWasRemoved(player->mo)) + { + P_MapStart(); + P_SetOrigin(player->mo, + player->mo->x + x, + player->mo->y + y, + player->mo->z + z); + P_MapEnd(); + + S_StartSound(player->mo, sfx_mixup); + } + + strlcpy(t[0], M_Ftrim(f[0]), sizeof t[0]); + strlcpy(t[1], M_Ftrim(f[1]), sizeof t[1]); + strlcpy(t[2], M_Ftrim(f[2]), sizeof t[2]); + + CV_CheaterWarning(targetPlayer, va("relative teleport by %d%s, %d%s, %d%s", + (int)f[0], t[0], (int)f[1], t[1], (int)f[2], t[2])); + break; + } + case NUMBER_OF_CHEATS: break; } diff --git a/src/m_cheat.c b/src/m_cheat.c index 70758b864..21e5645fb 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -306,64 +306,21 @@ void Command_Hurtme_f(void) void Command_RTeleport_f(void) { - fixed_t intx, inty, intz; - size_t i; - player_t *p = &players[consoleplayer]; - subsector_t *ss; + float x = atof(COM_Argv(1)); + float y = atof(COM_Argv(2)); + float z = atof(COM_Argv(3)); REQUIRE_CHEATS; REQUIRE_INLEVEL; - REQUIRE_SINGLEPLAYER; // TODO: make multiplayer compatible - if (COM_Argc() < 3 || COM_Argc() > 7) + if (COM_Argc() != 4) { - CONS_Printf(M_GetText("rteleport -x -y -z : relative teleport to a location\n")); + CONS_Printf(M_GetText("rteleport : relative teleport to a location\n")); return; } - if (!p->mo) - return; - - i = COM_CheckParm("-x"); - if (i) - intx = atoi(COM_Argv(i + 1)); - else - intx = 0; - - i = COM_CheckParm("-y"); - if (i) - inty = atoi(COM_Argv(i + 1)); - else - inty = 0; - - ss = R_PointInSubsectorOrNull(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT); - if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height) - { - CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n")); - return; - } - i = COM_CheckParm("-z"); - if (i) - { - intz = atoi(COM_Argv(i + 1)); - intz <<= FRACBITS; - intz += p->mo->z; - if (intz < ss->sector->floorheight) - intz = ss->sector->floorheight; - if (intz > ss->sector->ceilingheight - p->mo->height) - intz = ss->sector->ceilingheight - p->mo->height; - } - else - intz = p->mo->z; - - CONS_Printf(M_GetText("Teleporting by %d, %d, %d...\n"), intx, inty, FixedInt((intz-p->mo->z))); - - P_MapStart(); - if (!P_SetOrigin(p->mo, p->mo->x+intx*FRACUNIT, p->mo->y+inty*FRACUNIT, intz)) - CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n")); - else - S_StartSound(p->mo, sfx_mixup); - P_MapEnd(); + D_Cheat(consoleplayer, CHEAT_RELATIVE_TELEPORT, + FLOAT_TO_FIXED(x), FLOAT_TO_FIXED(y), FLOAT_TO_FIXED(z)); } void Command_Teleport_f(void) diff --git a/src/m_cheat.h b/src/m_cheat.h index e12366b0f..40ff3fe00 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -27,6 +27,7 @@ typedef enum { CHEAT_SCALE, CHEAT_FLIP, CHEAT_HURT, + CHEAT_RELATIVE_TELEPORT, NUMBER_OF_CHEATS } cheat_t; From 23408e7d3bcaf837660a349498076d1a628b510e Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Sep 2022 03:53:30 -0700 Subject: [PATCH 53/63] Let savecheckpoint work online, work at all Actually respawns you at this location! :smiley: Uses object Z position instead of floor height. --- src/d_netcmd.c | 21 +++++++++++++++++++++ src/d_player.h | 1 + src/k_respawn.c | 8 +++++++- src/m_cheat.c | 12 ++++++------ src/m_cheat.h | 1 + src/p_saveg.c | 2 ++ 6 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index e95df4d75..fb0db9c37 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1995,6 +1995,12 @@ void D_Cheat(INT32 playernum, INT32 cheat, ...) switch (cheat) { + case CHEAT_SAVECHECKPOINT: + COPY(WRITEFIXED, fixed_t); // x + COPY(WRITEFIXED, fixed_t); // y + COPY(WRITEFIXED, fixed_t); // z + break; + case CHEAT_RINGS: case CHEAT_LIVES: // If you're confused why 'int' instead of @@ -5502,6 +5508,21 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum) break; } + case CHEAT_SAVECHECKPOINT: { + fixed_t x = READFIXED(*cp); + fixed_t y = READFIXED(*cp); + fixed_t z = READFIXED(*cp); + + player->respawn.pointx = x; + player->respawn.pointy = y; + player->respawn.pointz = z; + player->respawn.manual = true; + + CV_CheaterWarning(targetPlayer, va("temporary checkpoint created at %d, %d, %d", + x / FRACUNIT, y / FRACUNIT, z / FRACUNIT)); + break; + } + case CHEAT_RINGS: { SINT8 rings = READSINT8(*cp); diff --git a/src/d_player.h b/src/d_player.h index 28d126b55..406069c16 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -296,6 +296,7 @@ typedef struct respawnvars_s UINT32 distanceleft; // How far along the course to respawn you tic_t dropdash; // Drop Dash charge timer boolean truedeath; // Your soul has left your body + boolean manual; // Respawn coords were manually set, please respawn exactly there } respawnvars_t; // player_t struct for all bot variables diff --git a/src/k_respawn.c b/src/k_respawn.c index 94bb04e18..227cf221f 100644 --- a/src/k_respawn.c +++ b/src/k_respawn.c @@ -157,7 +157,13 @@ void K_DoIngameRespawn(player_t *player) P_ResetPlayer(player); // Set up respawn position if invalid - if (player->respawn.wp != NULL && leveltime >= starttime) + if (player->respawn.manual == true) + { + player->respawn.distanceleft = 0; + player->respawn.pointz += K_RespawnOffset(player, player->respawn.flip); + player->respawn.manual = false; // one respawn only! + } + else if (player->respawn.wp != NULL && leveltime >= starttime) { const UINT32 dist = RESPAWN_DIST + (player->airtime * 48); player->respawn.distanceleft = (dist * mapobjectscale) / FRACUNIT; diff --git a/src/m_cheat.c b/src/m_cheat.c index 70758b864..a324dfda1 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -686,15 +686,15 @@ void Command_Dumplua_f(void) void Command_Savecheckpoint_f(void) { + mobj_t *thing = players[consoleplayer].mo; + REQUIRE_CHEATS; REQUIRE_INLEVEL; - REQUIRE_SINGLEPLAYER; // TODO: make multiplayer compatible - players[consoleplayer].respawn.pointx = players[consoleplayer].mo->x; - players[consoleplayer].respawn.pointy = players[consoleplayer].mo->y; - players[consoleplayer].respawn.pointz = players[consoleplayer].mo->floorz; - - CONS_Printf(M_GetText("Temporary checkpoint created at %d, %d, %d\n"), players[consoleplayer].respawn.pointx, players[consoleplayer].respawn.pointy, players[consoleplayer].respawn.pointz); + if (!P_MobjWasRemoved(thing)) + { + D_Cheat(consoleplayer, CHEAT_SAVECHECKPOINT, thing->x, thing->y, thing->z); + } } // Like M_GetAllEmeralds() but for console devmode junkies. diff --git a/src/m_cheat.h b/src/m_cheat.h index e12366b0f..0fe483d99 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -22,6 +22,7 @@ typedef enum { CHEAT_NOCLIP, CHEAT_GOD, + CHEAT_SAVECHECKPOINT, CHEAT_RINGS, CHEAT_LIVES, CHEAT_SCALE, diff --git a/src/p_saveg.c b/src/p_saveg.c index 233056f21..a6a987909 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -394,6 +394,7 @@ static void P_NetArchivePlayers(void) WRITEUINT32(save_p, players[i].respawn.distanceleft); WRITEUINT32(save_p, players[i].respawn.dropdash); WRITEUINT8(save_p, players[i].respawn.truedeath); + WRITEUINT8(save_p, players[i].respawn.manual); // botvars_t WRITEUINT8(save_p, players[i].botvars.difficulty); @@ -691,6 +692,7 @@ static void P_NetUnArchivePlayers(void) players[i].respawn.distanceleft = READUINT32(save_p); players[i].respawn.dropdash = READUINT32(save_p); players[i].respawn.truedeath = READUINT8(save_p); + players[i].respawn.manual = READUINT8(save_p); // botvars_t players[i].botvars.difficulty = READUINT8(save_p); From 13a17fa0f855cdf0a0771a21a1e5b3bb037430e2 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Sep 2022 07:44:50 -0700 Subject: [PATCH 54/63] Disable checkpoint saved by savecheckpoint when disabling cheats What a mouthful. --- src/p_user.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_user.c b/src/p_user.c index a02b8e223..28371486a 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4466,6 +4466,7 @@ void P_ResetPlayerCheats(void) continue; player->pflags &= ~(PF_GODMODE); + player->respawn.manual = false; if (P_MobjWasRemoved(thing)) continue; From 80d9637dda9eabfbbfe7ca468b36444725bd43f2 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 29 Sep 2022 12:19:45 -0400 Subject: [PATCH 55/63] devmode cheat online --- src/am_map.c | 4 +-- src/command.c | 2 +- src/console.c | 4 +-- src/d_clisrv.c | 2 +- src/d_main.c | 2 +- src/d_netcmd.c | 17 +++++++--- src/doomdef.h | 46 +++++++++++++++---------- src/f_finale.c | 2 +- src/g_game.c | 4 +-- src/k_menufunc.c | 6 ++-- src/lua_blockmaplib.c | 8 ++--- src/lua_hooklib.c | 2 +- src/m_cheat.c | 79 +++++++++++++++++++++++++++++++++++++------ src/m_cheat.h | 4 +++ src/p_enemy.c | 22 ++++++------ src/p_mobj.c | 4 +-- src/p_saveg.c | 4 +++ src/r_main.c | 34 ++----------------- src/st_stuff.c | 8 ++--- 19 files changed, 156 insertions(+), 98 deletions(-) diff --git a/src/am_map.c b/src/am_map.c index 04806de94..1bfb145c4 100644 --- a/src/am_map.c +++ b/src/am_map.c @@ -454,7 +454,7 @@ boolean AM_Responder(event_t *ev) { INT32 rc = false; - if (devparm || cv_debug) // only automap in Debug Tails 01-19-2001 + if (devparm || cht_debug) // only automap in Debug Tails 01-19-2001 { if (!automapactive) { @@ -625,7 +625,7 @@ static inline void AM_doFollowPlayer(void) */ void AM_Ticker(void) { - if (!cv_debug) + if (!cht_debug) AM_Stop(); if (dedicated || !automapactive) diff --git a/src/command.c b/src/command.c index 75e8fc06a..a66522186 100644 --- a/src/command.c +++ b/src/command.c @@ -1899,7 +1899,7 @@ void CV_CheatsChanged(void) CV_SetCVar(cvar, cvar->defaultvalue, false); // Reset any other cheat command effects here, as well. - cv_debug = 0; + cht_debug = 0; P_ResetPlayerCheats(); } diff --git a/src/console.c b/src/console.c index 08d04e318..ede2f633a 100644 --- a/src/console.c +++ b/src/console.c @@ -1521,12 +1521,12 @@ void CONS_Alert(alerttype_t level, const char *fmt, ...) CONS_Printf("%s", txt); } -void CONS_Debug(INT32 debugflags, const char *fmt, ...) +void CONS_Debug(UINT32 debugflags, const char *fmt, ...) { va_list argptr; static char *txt = NULL; - if ((cv_debug & debugflags) != debugflags) + if ((cht_debug & debugflags) != debugflags) return; if (txt == NULL) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 0613ba13d..602482aed 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -266,7 +266,7 @@ void SendNetXCmdForPlayer(UINT8 playerid, netxcmd_t id, const void *param, size_ { if (localtextcmd[playerid][0]+2+nparam > MAXTEXTCMD) { - // for future reference: if (cv_debug) != debug disabled. + // for future reference: if (cht_debug) != debug disabled. CONS_Alert(CONS_ERROR, M_GetText("NetXCmd buffer full, cannot add netcmd %d! (size: %d, needed: %s)\n"), id, localtextcmd[playerid][0], sizeu1(nparam)); return; } diff --git a/src/d_main.c b/src/d_main.c index 82cf8fd5a..e9ec23790 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -962,7 +962,7 @@ void D_StartTitle(void) splitscreen = 0; SplitScreen_OnChange(); - cv_debug = 0; + cht_debug = 0; emeralds = 0; memset(&luabanks, 0, sizeof(luabanks)); lastmaploaded = 0; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index e95df4d75..4d6efc73e 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -326,8 +326,6 @@ consvar_t cv_splitdevice = CVAR_INIT ("splitdevice", "Off", CV_SAVE, CV_OnOff, N consvar_t cv_skipmapcheck = CVAR_INIT ("skipmapcheck", "Off", CV_SAVE, CV_OnOff, NULL); -INT32 cv_debug; - consvar_t cv_usemouse = CVAR_INIT ("use_mouse", "Off", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse); consvar_t cv_usejoystick[MAXSPLITSCREENPLAYERS] = { @@ -2009,6 +2007,10 @@ void D_Cheat(INT32 playernum, INT32 cheat, ...) case CHEAT_HURT: COPY(WRITEINT32, INT32); break; + + case CHEAT_DEVMODE: + COPY(WRITEUINT32, UINT32); + break; } #undef COPY @@ -2852,7 +2854,7 @@ static void Command_Map_f(void) newresetplayers = false; // if not forcing and gametypes is the same // don't use a gametype the map doesn't support - if (cv_debug || option_force || cv_skipmapcheck.value) + if (cht_debug || option_force || cv_skipmapcheck.value) { fromlevelselect = false; // The player wants us to trek on anyway. Do so. } @@ -5565,6 +5567,13 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum) break; } + case CHEAT_DEVMODE: { + UINT32 flags = READUINT32(*cp); + cht_debug = flags; + CV_CheaterWarning(targetPlayer, va("devmode %08x", flags)); + break; + } + case NUMBER_OF_CHEATS: break; } @@ -5625,7 +5634,7 @@ void Command_ExitGame_f(void) splitscreen = 0; SplitScreen_OnChange(); - cv_debug = 0; + cht_debug = 0; emeralds = 0; memset(&luabanks, 0, sizeof(luabanks)); diff --git a/src/doomdef.h b/src/doomdef.h index 63318ef5e..26460b922 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -480,7 +480,7 @@ typedef enum void CONS_Printf(const char *fmt, ...) FUNCPRINTF; void CONS_Alert(alerttype_t level, const char *fmt, ...) FUNCDEBUG; -void CONS_Debug(INT32 debugflags, const char *fmt, ...) FUNCDEBUG; +void CONS_Debug(UINT32 debugflags, const char *fmt, ...) FUNCDEBUG; // For help debugging functions. #define POTENTIALLYUNUSED CONS_Alert(CONS_WARNING, "(%s:%d) Unused code appears to be used.\n", __FILE__, __LINE__) @@ -517,23 +517,35 @@ char *sizeu5(size_t num); extern int VERSION; extern int SUBVERSION; extern boolean devparm; // development mode (-debug) -// d_netcmd.c -extern INT32 cv_debug; -#define DBG_BASIC 0x0001 -#define DBG_DETAILED 0x0002 -#define DBG_PLAYER 0x0004 -#define DBG_RENDER 0x0008 -#define DBG_NIGHTSBASIC 0x0010 -#define DBG_NIGHTS 0x0020 -#define DBG_POLYOBJ 0x0040 -#define DBG_GAMELOGIC 0x0080 -#define DBG_NETPLAY 0x0100 -#define DBG_MEMORY 0x0200 -#define DBG_SETUP 0x0400 -#define DBG_LUA 0x0800 -#define DBG_RANDOMIZER 0x1000 -#define DBG_VIEWMORPH 0x2000 +// m_cheat.c +extern UINT32 cht_debug; + +typedef enum +{ + DBG_NONE = 0x00000000, + DBG_BASIC = 0x00000001, + DBG_DETAILED = 0x00000002, + DBG_PLAYER = 0x00000004, + DBG_RENDER = 0x00000008, + //DBG_NIGHTSBASIC = 0x00000010, // free + //DBG_NIGHTS = 0x00000020, // free + DBG_POLYOBJ = 0x00000040, + DBG_GAMELOGIC = 0x00000080, + DBG_NETPLAY = 0x00000100, + DBG_MEMORY = 0x00000200, + DBG_SETUP = 0x00000400, + DBG_LUA = 0x00000800, + DBG_RNG = 0x00001000, +} debugFlags_t; + +struct debugFlagNames_s +{ + const char *str; + debugFlags_t flag; +}; + +extern struct debugFlagNames_s const debug_flag_names[]; // ======================= // Misc stuff for later... diff --git a/src/f_finale.c b/src/f_finale.c index 005a4c6a1..0cc5ef5ea 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -866,7 +866,7 @@ boolean F_CreditResponder(event_t *event) return false; } - /*if (!(timesBeaten) && !(netgame || multiplayer) && !cv_debug) + /*if (!(timesBeaten) && !(netgame || multiplayer) && !cht_debug) return false;*/ if (key != KEY_ESCAPE && key != KEY_ENTER && key != KEY_BACKSPACE) diff --git a/src/g_game.c b/src/g_game.c index f3c807ed8..a0202082e 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4589,7 +4589,7 @@ void G_SaveGame(UINT32 slot, INT16 mapnum) gameaction = ga_nothing; - if (cv_debug && saved) + if (cht_debug && saved) CONS_Printf(M_GetText("Game saved.\n")); else if (!saved) CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, (marathonmode ? liveeventbackup : savegamename)); @@ -4691,7 +4691,7 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) } cleanup: - if (cv_debug && saved) + if (cht_debug && saved) CONS_Printf(M_GetText("Game saved.\n")); else if (!saved) CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, (marathonmode ? liveeventbackup : savegamename)); diff --git a/src/k_menufunc.c b/src/k_menufunc.c index e143d5670..1f015a907 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -2016,7 +2016,7 @@ void M_QuitResponse(INT32 ch) if (ch == MA_YES) { - if (!(netgame || cv_debug)) + if (!(netgame || cht_debug)) { mrand = M_RandomKey(sizeof(quitsounds) / sizeof(INT32)); if (quitsounds[mrand]) @@ -3577,7 +3577,7 @@ void M_LevelSelectHandler(INT32 choice) strncpy(connectedservername, cv_servername.string, MAXSERVERNAME); // Still need to reset devmode - cv_debug = 0; + cht_debug = 0; if (demo.playback) G_StopDemo(); @@ -3686,7 +3686,7 @@ void M_StartTimeAttack(INT32 choice) } // Still need to reset devmode - cv_debug = 0; + cht_debug = 0; emeralds = 0; if (demo.playback) diff --git a/src/lua_blockmaplib.c b/src/lua_blockmaplib.c index 1949d56bb..efb14a9c3 100644 --- a/src/lua_blockmaplib.c +++ b/src/lua_blockmaplib.c @@ -51,7 +51,7 @@ static UINT8 lib_searchBlockmap_Objects(lua_State *L, INT32 x, INT32 y, mobj_t * LUA_PushUserdata(L, thing, META_MOBJ); LUA_PushUserdata(L, mobj, META_MOBJ); if (lua_pcall(gL, 2, 1, 0)) { - if (!blockfuncerror || cv_debug & DBG_LUA) + if (!blockfuncerror || cht_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); blockfuncerror = true; @@ -112,7 +112,7 @@ static UINT8 lib_searchBlockmap_Lines(lua_State *L, INT32 x, INT32 y, mobj_t *th LUA_PushUserdata(L, thing, META_MOBJ); LUA_PushUserdata(L, po->lines[i], META_LINE); if (lua_pcall(gL, 2, 1, 0)) { - if (!blockfuncerror || cv_debug & DBG_LUA) + if (!blockfuncerror || cht_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); blockfuncerror = true; @@ -149,7 +149,7 @@ static UINT8 lib_searchBlockmap_Lines(lua_State *L, INT32 x, INT32 y, mobj_t *th LUA_PushUserdata(L, thing, META_MOBJ); LUA_PushUserdata(L, ld, META_LINE); if (lua_pcall(gL, 2, 1, 0)) { - if (!blockfuncerror || cv_debug & DBG_LUA) + if (!blockfuncerror || cht_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); blockfuncerror = true; @@ -195,7 +195,7 @@ static UINT8 lib_searchBlockmap_PolyObjs(lua_State *L, INT32 x, INT32 y, mobj_t LUA_PushUserdata(L, thing, META_MOBJ); LUA_PushUserdata(L, po, META_POLYOBJ); if (lua_pcall(gL, 2, 1, 0)) { - if (!blockfuncerror || cv_debug & DBG_LUA) + if (!blockfuncerror || cht_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); blockfuncerror = true; diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 8d47b7389..b797f669c 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -411,7 +411,7 @@ static int call_single_hook_no_copy(Hook_State *hook) else { /* print the error message once */ - if (cv_debug & DBG_LUA || !in_bit_array(hooksErrored, hook->id)) + if (cht_debug & DBG_LUA || !in_bit_array(hooksErrored, hook->id)) { CONS_Alert(CONS_WARNING, "%s\n", lua_tostring(gL, -1)); set_bit_array(hooksErrored, hook->id); diff --git a/src/m_cheat.c b/src/m_cheat.c index 70758b864..4b065f121 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -38,6 +38,8 @@ #include "lua_script.h" #include "lua_hook.h" +#include "fastcmp.h" + // // CHEAT SEQUENCE PACKAGE // @@ -111,7 +113,7 @@ static UINT8 cheatf_devmode(void) for (i = 0; i < MAXUNLOCKABLES; i++) unlockables[i].unlocked = true; devparm = true; - cv_debug |= 0x8000; + cht_debug |= 0x8000; // Refresh secrets menu existing. M_ClearMenus(true); @@ -720,24 +722,81 @@ void Command_Resetemeralds_f(void) } */ +// +// Devmode +// + +UINT32 cht_debug; + +struct debugFlagNames_s const debug_flag_names[] = +{ + {"None", DBG_NONE}, + {"Basic", DBG_BASIC}, + {"Detailed", DBG_DETAILED}, + {"Player", DBG_PLAYER}, + {"Render", DBG_RENDER}, + {"Renderer", DBG_RENDER}, // alt name + {"Polyobj", DBG_POLYOBJ}, + {"GameLogic", DBG_GAMELOGIC}, + {"Game", DBG_GAMELOGIC}, // alt name + {"Netplay", DBG_NETPLAY}, + {"Memory", DBG_MEMORY}, + {"Setup", DBG_SETUP}, + {"Lua", DBG_LUA}, + {"RNG", DBG_RNG}, + {"Randomizer", DBG_RNG}, // alt name + {NULL, 0} +}; + void Command_Devmode_f(void) { + size_t argc = 0; + REQUIRE_CHEATS; - REQUIRE_SINGLEPLAYER; // TODO: make multiplayer compatible - if (COM_Argc() > 1) + argc = COM_Argc(); + if (argc > 1) { - const char *arg = COM_Argv(1); + UINT32 flags = 0; + size_t i; - if (arg[0] && arg[0] == '0' && - arg[1] && arg[1] == 'x') // Use hexadecimal! - cv_debug = axtoi(arg+2); - else - cv_debug = atoi(arg); + for (i = 1; i < argc; i++) + { + const char *arg = COM_Argv(i); + size_t j; + + // Try it as a string + for (j = 0; debug_flag_names[j].str; j++) + { + if (stricmp(arg, debug_flag_names[j].str) == 0) + { + break; + } + } + + if (debug_flag_names[j].str) + { + flags |= debug_flag_names[j].flag; + continue; + } + + // Try it as a number + if (arg[0] && arg[0] == '0' && + arg[1] && arg[1] == 'x') // Use hexadecimal! + { + flags |= axtoi(arg+2); + } + else + { + flags |= atoi(arg); + } + } + + D_Cheat(consoleplayer, CHEAT_DEVMODE, flags); } else { - CONS_Printf(M_GetText("devmode : enable debugging tools and info, prepend with 0x to use hexadecimal\n")); + CONS_Printf(M_GetText("devmode : Enable debugging info. Prepend with 0x to use hexadecimal\n")); return; } } diff --git a/src/m_cheat.h b/src/m_cheat.h index e12366b0f..35dec646f 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -27,10 +27,14 @@ typedef enum { CHEAT_SCALE, CHEAT_FLIP, CHEAT_HURT, + CHEAT_DEVMODE, NUMBER_OF_CHEATS } cheat_t; +// +// Cheat sequences +// boolean cht_Responder(event_t *ev); void cht_Init(void); diff --git a/src/p_enemy.c b/src/p_enemy.c index 60632cca7..55ea6de81 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -8216,7 +8216,7 @@ void A_OrbitNights(mobj_t* actor) if (!actor->target) { - if (cv_debug && !(actor->target && actor->target->player)) + if (cht_debug && !(actor->target && actor->target->player)) CONS_Printf("ERROR: Powerup has no target!\n"); return; } @@ -8286,7 +8286,7 @@ void A_SetObjectState(mobj_t *actor) if ((!locvar2 && !actor->target) || (locvar2 && !actor->tracer)) { - if (cv_debug) + if (cht_debug) CONS_Printf("A_SetObjectState: No target to change state!\n"); return; } @@ -8377,7 +8377,7 @@ void A_KnockBack(mobj_t *actor) if (!target) { - if(cv_debug) + if(cht_debug) CONS_Printf("A_KnockBack: No target!\n"); return; } @@ -8441,7 +8441,7 @@ void A_RingDrain(mobj_t *actor) if (!actor->target || !actor->target->player) { - if(cv_debug) + if(cht_debug) CONS_Printf("A_RingDrain: No player targeted!\n"); return; } @@ -8645,7 +8645,7 @@ void A_Custom3DRotate(mobj_t *actor) if (hspeed==0 && vspeed==0) { - if (cv_debug) + if (cht_debug) CONS_Printf("Error: A_Custom3DRotate: Object has no speed.\n"); return; } @@ -9080,7 +9080,7 @@ void A_SetCustomValue(mobj_t *actor) if (LUA_CallAction(A_SETCUSTOMVALUE, actor)) return; - if (cv_debug) + if (cht_debug) CONS_Printf("Init custom value is %d\n", actor->cusval); if (locvar1 == 0 && locvar2 == 4) @@ -9100,7 +9100,7 @@ void A_SetCustomValue(mobj_t *actor) else // replace actor->cusval = locvar1; - if(cv_debug) + if(cht_debug) CONS_Printf("New custom value is %d\n", actor->cusval); } @@ -9467,7 +9467,7 @@ void A_SetScale(mobj_t *actor) if (locvar1 <= 0) { - if(cv_debug) + if(cht_debug) CONS_Printf("A_SetScale: Valid scale not specified!\n"); return; } @@ -9481,7 +9481,7 @@ void A_SetScale(mobj_t *actor) if (!target) { - if(cv_debug) + if(cht_debug) CONS_Printf("A_SetScale: No target!\n"); return; } @@ -9522,7 +9522,7 @@ void A_RemoteDamage(mobj_t *actor) if (!target) { - if(cv_debug) + if(cht_debug) CONS_Printf("A_RemoteDamage: No target!\n"); return; } @@ -13149,7 +13149,7 @@ void A_ItemPop(mobj_t *actor) if (!(actor->target && actor->target->player)) { - if (cv_debug && !(actor->target && actor->target->player)) + if (cht_debug && !(actor->target && actor->target->player)) CONS_Printf("ERROR: Powerup has no target!\n"); return; } diff --git a/src/p_mobj.c b/src/p_mobj.c index add104e5d..f7910b89a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -4464,7 +4464,7 @@ mobj_t *P_GetClosestAxis(mobj_t *source) } if (closestaxis == NULL) - CONS_Debug(DBG_NIGHTS, "ERROR: No axis points found!\n"); + CONS_Alert(CONS_ERROR, "No axis points found!\n"); return closestaxis; } @@ -4536,7 +4536,7 @@ void P_SpawnHoopOfSomething(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT if (!axis) { - CONS_Debug(DBG_NIGHTS, "You forgot to put axis points in the map!\n"); + CONS_Alert(CONS_WARNING, "You forgot to put axis points in the map!\n"); return; } diff --git a/src/p_saveg.c b/src/p_saveg.c index 233056f21..4af2dedfd 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4599,6 +4599,8 @@ static void P_NetArchiveMisc(boolean resending) WRITEINT16(save_p, task->timer); WRITESTRING(save_p, task->command); } + + WRITEUINT32(save_p, cht_debug); } static inline boolean P_NetUnArchiveMisc(boolean reloading) @@ -4762,6 +4764,8 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) Schedule_Add(basetime, timer, command); } + cht_debug = READUINT32(save_p); + return true; } diff --git a/src/r_main.c b/src/r_main.c index 58c65427d..3e79f9871 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -915,39 +915,9 @@ void R_ApplyViewMorph(int s) end = width * height; -#if 0 - if (cv_debug & DBG_VIEWMORPH) + for (p = 0; p < end; p++) { - UINT8 border = 32; - UINT8 grid = 160; - INT32 ws = vid.width / 4; - INT32 hs = vid.width * (vid.height / 4); - - memcpy(tmpscr, srcscr, vid.width*vid.height); - for (p = 0; p < vid.width; p++) - { - tmpscr[viewmorph.scrmap[p]] = border; - tmpscr[viewmorph.scrmap[p + hs]] = grid; - tmpscr[viewmorph.scrmap[p + hs*2]] = grid; - tmpscr[viewmorph.scrmap[p + hs*3]] = grid; - tmpscr[viewmorph.scrmap[end - 1 - p]] = border; - } - for (p = vid.width; p < end; p += vid.width) - { - tmpscr[viewmorph.scrmap[p]] = border; - tmpscr[viewmorph.scrmap[p + ws]] = grid; - tmpscr[viewmorph.scrmap[p + ws*2]] = grid; - tmpscr[viewmorph.scrmap[p + ws*3]] = grid; - tmpscr[viewmorph.scrmap[end - 1 - p]] = border; - } - } - else -#endif - { - for (p = 0; p < end; p++) - { - tmpscr[p] = srcscr[viewmorph[s].scrmap[p]]; - } + tmpscr[p] = srcscr[viewmorph[s].scrmap[p]]; } VID_BlitLinearScreen(tmpscr, srcscr, diff --git a/src/st_stuff.c b/src/st_stuff.c index 138c0e64b..d46da54b5 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -364,7 +364,7 @@ static void ST_drawDebugInfo(void) if (!stplyr->mo) return; - if (cv_debug & DBG_BASIC) + if (cht_debug & DBG_BASIC) { const fixed_t d = AngleFixed(stplyr->mo->angle); V_DrawRightAlignedString(320, 168, V_MONOSPACE, va("X: %6d", stplyr->mo->x>>FRACBITS)); @@ -375,7 +375,7 @@ static void ST_drawDebugInfo(void) height = 152; } - if (cv_debug & DBG_DETAILED) + if (cht_debug & DBG_DETAILED) { //V_DrawRightAlignedString(320, height - 104, V_MONOSPACE, va("SHIELD: %5x", stplyr->powers[pw_shield])); V_DrawRightAlignedString(320, height - 96, V_MONOSPACE, va("SCALE: %5d%%", (stplyr->mo->scale*100)/FRACUNIT)); @@ -404,7 +404,7 @@ static void ST_drawDebugInfo(void) height -= 120; } - if (cv_debug & DBG_RANDOMIZER) // randomizer testing + if (cht_debug & DBG_RNG) // randomizer testing { // TODO: this only accounts for the undefined class, // which should be phased out as much as possible anyway. @@ -421,7 +421,7 @@ static void ST_drawDebugInfo(void) height -= 32; } - if (cv_debug & DBG_MEMORY) + if (cht_debug & DBG_MEMORY) V_DrawRightAlignedString(320, height, V_MONOSPACE, va("Heap used: %7sKB", sizeu1(Z_TagsUsage(0, INT32_MAX)>>10))); } From c65628e2d06383ad6a00084992a58cd32cc5c7ad Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 29 Sep 2022 12:22:15 -0400 Subject: [PATCH 56/63] Don't pad flags in the warning --- src/d_netcmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 4d6efc73e..2b67cb709 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -5570,7 +5570,7 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum) case CHEAT_DEVMODE: { UINT32 flags = READUINT32(*cp); cht_debug = flags; - CV_CheaterWarning(targetPlayer, va("devmode %08x", flags)); + CV_CheaterWarning(targetPlayer, va("devmode %x", flags)); break; } From cc7ceff30e535fadcdd2c0f588e0dd3d0b48babf Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Sep 2022 09:35:04 -0700 Subject: [PATCH 57/63] Clamp Top float modulation --- src/objects/gardentop.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/objects/gardentop.c b/src/objects/gardentop.c index 38154636f..3d55e03d1 100644 --- a/src/objects/gardentop.c +++ b/src/objects/gardentop.c @@ -256,7 +256,8 @@ modulate (mobj_t *top) if (top_float(top) > 0) { - top_float(top) -= hover_step; + top_float(top) = max(0, + top_float(top) - hover_step); } else if (P_IsObjectOnGround(top)) { @@ -276,7 +277,8 @@ modulate (mobj_t *top) if (top_float(top) < max_hover) { - top_float(top) += hover_step; + top_float(top) = min(max_hover, + top_float(top) + hover_step); } else { From 8529e8b95edb1e09980d12a322623402863bfc48 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Sep 2022 10:02:28 -0700 Subject: [PATCH 58/63] Make Garden Top backwards throw leap consistent across player scales --- src/k_kart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index df403b881..552f73b16 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10744,8 +10744,8 @@ void K_MoveKartPlayer(player_t *player, boolean onground) mobj_t *top = Obj_GardenTopDestroy(player); // Fly off the Top at high speed - P_Thrust(player->mo, K_MomentumAngle(player->mo), 80 * player->mo->scale); - P_SetObjectMomZ(player->mo, player->mo->height / 2, true); + P_Thrust(player->mo, K_MomentumAngle(player->mo), 80 * mapobjectscale); + P_SetObjectMomZ(player->mo, player->mo->info->height / 8, true); top->momx = player->mo->momx; top->momy = player->mo->momy; From aeda564145e2f9e818b290f0c4406e3defe64a8b Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Sep 2022 12:35:02 -0700 Subject: [PATCH 59/63] Fix typo FUCK blame cf02646229 --- src/p_mobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 1fe6af87a..803393b7c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9491,7 +9491,7 @@ void P_MobjThinker(mobj_t *mobj) return; // Destroy items sector special - if (P_CanDeleteKartItems(mobj->type)) + if (P_CanDeleteKartItem(mobj->type)) { if (mobj->health > 0 && P_MobjTouchingSectorSpecial(mobj, 4, 7, true)) { From d176aefd88166457b2409931d3d637e27bc3af60 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Sep 2022 12:55:07 -0700 Subject: [PATCH 60/63] Compare git commit when joining netgames in DEVELOP builds --- src/d_clisrv.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/d_clisrv.h | 4 ++++ src/d_main.c | 22 ++++++++++++++++++++++ src/doomdef.h | 11 +++++++++++ 4 files changed, 77 insertions(+) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 0613ba13d..a5a8e126b 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -895,8 +895,15 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) netbuffer->packettype = PT_SERVERINFO; netbuffer->u.serverinfo._255 = 255; netbuffer->u.serverinfo.packetversion = PACKETVERSION; + +#ifdef DEVELOP + memcpy(netbuffer->u.serverinfo.commit, + comprevision_abbrev_bin, GIT_SHA_ABBREV); +#else netbuffer->u.serverinfo.version = VERSION; netbuffer->u.serverinfo.subversion = SUBVERSION; +#endif + strncpy(netbuffer->u.serverinfo.application, SRB2APPLICATION, sizeof netbuffer->u.serverinfo.application); // return back the time value so client can compute their ping @@ -1404,11 +1411,13 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node) if (info->packetversion != PACKETVERSION) return;/* old new packet format */ +#ifndef DEVELOP if (info->version != VERSION) return; // Not same version. if (info->subversion != SUBVERSION) return; // Close, but no cigar. +#endif if (strcmp(info->application, SRB2APPLICATION)) return;/* that's a different mod */ @@ -1681,6 +1690,35 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent) if (client) { +#ifdef DEVELOP + // Commits do not match? Do not connect! + if (memcmp(serverlist[i].info.commit, + comprevision_abbrev_bin, + GIT_SHA_ABBREV)) + { + char theirs[GIT_SHA_ABBREV * 2 + 1]; + UINT8 n; + + for (n = 0; n < GIT_SHA_ABBREV; ++n) + { + sprintf(&theirs[n * 2], "%02hhx", + serverlist[i].info.commit[n]); + } + + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + + M_StartMessage(va( + "Your EXE differs from the server.\n" + " Yours: %.*s\n" + "Theirs: %s\n\n" + "Press ESC\n", + GIT_SHA_ABBREV * 2, comprevision, theirs), NULL, MM_NOTHING); + return false; + } +#endif + #ifdef HAVE_CURL if (serverlist[i].info.httpsource[0]) strncpy(http_source, serverlist[i].info.httpsource, MAX_MIRROR_LENGTH); @@ -2014,8 +2052,10 @@ static void CL_ConnectToServer(void) gametypestr[sizeof serverlist[i].info.gametypename - 1] = '\0'; CON_LogMessage(va(M_GetText("Gametype: %s\n"), gametypestr)); +#ifndef DEVELOP CON_LogMessage(va(M_GetText("Version: %d.%d\n"), serverlist[i].info.version, serverlist[i].info.subversion)); +#endif } SL_ClearServerList(servernode); diff --git a/src/d_clisrv.h b/src/d_clisrv.h index fabbd01f5..a7f56b78f 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -266,8 +266,12 @@ typedef struct UINT8 _255; UINT8 packetversion; char application[MAXAPPLICATION]; +#ifdef DEVELOP + UINT8 commit[GIT_SHA_ABBREV]; +#else UINT8 version; UINT8 subversion; +#endif UINT8 numberofplayer; UINT8 maxplayer; UINT8 refusereason; // 0: joinable, 1: joins disabled, 2: full diff --git a/src/d_main.c b/src/d_main.c index 82cf8fd5a..1586e96fa 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -96,6 +96,10 @@ int VERSION; int SUBVERSION; +#ifdef DEVELOP +UINT8 comprevision_abbrev_bin[GIT_SHA_ABBREV]; +#endif + #ifdef HAVE_DISCORDRPC #include "discord.h" #endif @@ -1170,6 +1174,20 @@ static void IdentifyVersion(void) #endif } +#ifdef DEVELOP +static void +D_AbbrevCommit (void) +{ + UINT8 i; + + for (i = 0; i < GIT_SHA_ABBREV; ++i) + { + sscanf(&comprevision[i * 2], "%2hhx", + &comprevision_abbrev_bin[i]); + } +} +#endif + static void D_ConvertVersionNumbers (void) { @@ -1194,6 +1212,10 @@ void D_SRB2Main(void) /* break the version string into version numbers, for netplay */ D_ConvertVersionNumbers(); +#ifdef DEVELOP + D_AbbrevCommit(); +#endif + // Print GPL notice for our console users (Linux) CONS_Printf( "\n\nDr. Robotnik's Ring Racers\n" diff --git a/src/doomdef.h b/src/doomdef.h index 6997d7951..9cd7bb1d9 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -516,6 +516,17 @@ char *sizeu5(size_t num); // d_main.c extern int VERSION; extern int SUBVERSION; + +#ifdef DEVELOP +// 4 bytes handles 8 characters of a git object SHA. At +// around 20k commits, we only need 6 characters for a unique +// abbreviation. Maybe in another 20k commits, more than 8 +// characters will be required! =P +// P.S. 8 is also what comptime generates +#define GIT_SHA_ABBREV (4) +extern UINT8 comprevision_abbrev_bin[GIT_SHA_ABBREV]; +#endif + extern boolean devparm; // development mode (-debug) // d_netcmd.c extern INT32 cv_debug; From 495c58e53f38015754aca178d1b9ad5aff6970d9 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Sep 2022 14:03:29 -0700 Subject: [PATCH 61/63] Add V_STRINGDANCE -- dancing letters They do a wiggle~ --- src/v_video.c | 39 ++++++++++++++++++++++++++++++++++++--- src/v_video.h | 5 +++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/v_video.c b/src/v_video.c index 8ed5ed53f..0e85bf2fa 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -36,6 +36,7 @@ // SRB2Kart #include "k_hud.h" +#include "i_time.h" // Each screen is [vid.width*vid.height]; UINT8 *screens[5]; @@ -1636,6 +1637,14 @@ UINT8 *V_GetStringColormap(INT32 colorflags) #endif } +INT32 V_DanceYOffset(INT32 counter) +{ + const INT32 duration = 16; + const INT32 step = (I_GetTime() + counter) % duration; + + return abs(step - (duration / 2)) - (duration / 4); +} + // Writes a single character (draw WHITE if bit 7 set) // void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed) @@ -2044,9 +2053,13 @@ void V_DrawStringScaled( boolean uppercase; boolean notcolored; + boolean dance; + boolean nodanceoverride; + INT32 dancecounter; + fixed_t cx, cy; - fixed_t cxoff; + fixed_t cxoff, cyoff; fixed_t cw; INT32 spacing; @@ -2057,6 +2070,14 @@ void V_DrawStringScaled( uppercase = !( flags & V_ALLOWLOWERCASE ); flags &= ~(V_FLIP);/* These two (V_ALLOWLOWERCASE) share a bit. */ + dance = (flags & V_STRINGDANCE) != 0; + nodanceoverride = !dance; + dancecounter = 0; + + /* Some of these flags get overloaded in this function so + don't pass them on. */ + flags &= ~(V_PARAMMASK); + if (colormap == NULL) { colormap = V_GetStringColormap(( flags & V_CHARCOLORMASK )); @@ -2247,8 +2268,9 @@ void V_DrawStringScaled( cx = x; cy = y; + cyoff = 0; - for (; ( c = *s ); ++s) + for (; ( c = *s ); ++s, ++dancecounter) { switch (c) { @@ -2267,18 +2289,29 @@ void V_DrawStringScaled( ( ( c & 0x7f )<< V_CHARCOLORSHIFT )& V_CHARCOLORMASK); } + if (nodanceoverride) + { + dance = false; + } + } + else if (c == V_STRINGDANCE) + { + dance = true; } else if (cx < right) { if (uppercase) c = toupper(c); + if (dance) + cyoff = V_DanceYOffset(dancecounter) * FRACUNIT; + c -= font->start; if (c >= 0 && c < font->size && font->font[c]) { cw = SHORT (font->font[c]->width) * dupx; cxoff = (*dim_fn)(scale, chw, hchw, dupx, &cw); - V_DrawFixedPatch(cx + cxoff, cy, scale, + V_DrawFixedPatch(cx + cxoff, cy + cyoff, scale, flags, font->font[c], colormap); cx += cw; } diff --git a/src/v_video.h b/src/v_video.h index 9564bca15..35be68b2f 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -84,6 +84,9 @@ void V_CubeApply(RGBA_t *input); // Bottom 8 bits are used for parameter (screen or character) #define V_PARAMMASK 0x000000FF +// strings/characters only +#define V_STRINGDANCE 0x00000002 + // flags hacked in scrn (not supported by all functions (see src)) // patch scaling uses bits 9 and 10 #define V_SCALEPATCHSHIFT 8 @@ -220,6 +223,8 @@ void V_DrawPromptBack(INT32 boxheight, INT32 color); #define V__IntegerStringWidth( scale,option,font,string ) \ (V_StringScaledWidth(scale,FRACUNIT,FRACUNIT,option,font,string) / FRACUNIT) +INT32 V_DanceYOffset(INT32 counter); + // draw a single character void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed); // draw a single character, but for the chat From 62b2718261b23075f276367697b7a2bbdba790ae Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Sep 2022 15:18:41 -0700 Subject: [PATCH 62/63] Print on the title screen and in console if there are uncommitted changes --- src/Makefile | 8 ++++++++ src/comptime.c | 7 +++++++ src/d_netcmd.c | 3 +++ src/doomdef.h | 1 + src/f_finale.c | 2 ++ 5 files changed, 21 insertions(+) diff --git a/src/Makefile b/src/Makefile index 2367553ed..3c621001d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -195,6 +195,14 @@ passthru_opts:= # separate suffix with an underscore exesuffix:=$(call _,$(EXESUFFIX)) +# If there are uncommitted changes +# -uno: disregard untracked files +# Warning: this can only be accurate for comptime.c since +# that file is always recompiled! +ifneq ($(shell git status --porcelain -uno),) +opts+=-DCOMPVERSION_UNCOMMITTED +endif + include Makefile.d/platform.mk include Makefile.d/features.mk include Makefile.d/versions.mk diff --git a/src/comptime.c b/src/comptime.c index 398eda074..81b5ec7d6 100644 --- a/src/comptime.c +++ b/src/comptime.c @@ -15,6 +15,13 @@ const char *comprevision = SRB2_COMP_REVISION; #elif (defined(COMPVERSION)) #include "comptime.h" +const int compuncommitted = +#if (defined(COMPVERSION_UNCOMMITTED)) +1; +#else +0; +#endif + #else const char *compbranch = "Unknown"; const char *comprevision = "illegal"; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 58a17204b..8ecad7285 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -4756,6 +4756,9 @@ static void Command_Version_f(void) CONS_Printf("\x87" "DEVELOP " "\x80"); #endif + if (compuncommitted) + CONS_Printf("\x85" "! UNCOMMITTED CHANGES ! " "\x80"); + CONS_Printf("\n"); } diff --git a/src/doomdef.h b/src/doomdef.h index 6997d7951..30c53c5c8 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -613,6 +613,7 @@ UINT32 quickncasehash (const char *p, size_t n) // Compile date and time and revision. extern const char *compdate, *comptime, *comprevision, *compbranch; +extern int compuncommitted; // Disabled code and code under testing // None of these that are disabled in the normal build are guaranteed to work perfectly diff --git a/src/f_finale.c b/src/f_finale.c index 005a4c6a1..7b5651535 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2006,6 +2006,8 @@ void F_TitleScreenDrawer(void) #else // Regular build addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, va("%s", VERSIONSTRING)); #endif + if (compuncommitted) + addtext(V_REDMAP|V_STRINGDANCE, "! UNCOMMITTED CHANGES !"); } #undef addtext } From bc0fc9b05a23c6cf6e82778c003115caa2d5ed53 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 30 Sep 2022 05:49:26 -0700 Subject: [PATCH 63/63] Readd version and subversion to serverinfo Add commit field after those two so packet is identical up to that point and DEVELOP builds mismatch version online. blame d176aefd8 --- src/d_clisrv.c | 10 +++------- src/d_clisrv.h | 5 ++--- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index a5a8e126b..a6f18b1ab 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -896,12 +896,12 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) netbuffer->u.serverinfo._255 = 255; netbuffer->u.serverinfo.packetversion = PACKETVERSION; + netbuffer->u.serverinfo.version = VERSION; + netbuffer->u.serverinfo.subversion = SUBVERSION; + #ifdef DEVELOP memcpy(netbuffer->u.serverinfo.commit, comprevision_abbrev_bin, GIT_SHA_ABBREV); -#else - netbuffer->u.serverinfo.version = VERSION; - netbuffer->u.serverinfo.subversion = SUBVERSION; #endif strncpy(netbuffer->u.serverinfo.application, SRB2APPLICATION, @@ -1411,13 +1411,11 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node) if (info->packetversion != PACKETVERSION) return;/* old new packet format */ -#ifndef DEVELOP if (info->version != VERSION) return; // Not same version. if (info->subversion != SUBVERSION) return; // Close, but no cigar. -#endif if (strcmp(info->application, SRB2APPLICATION)) return;/* that's a different mod */ @@ -2052,10 +2050,8 @@ static void CL_ConnectToServer(void) gametypestr[sizeof serverlist[i].info.gametypename - 1] = '\0'; CON_LogMessage(va(M_GetText("Gametype: %s\n"), gametypestr)); -#ifndef DEVELOP CON_LogMessage(va(M_GetText("Version: %d.%d\n"), serverlist[i].info.version, serverlist[i].info.subversion)); -#endif } SL_ClearServerList(servernode); diff --git a/src/d_clisrv.h b/src/d_clisrv.h index a7f56b78f..354e62486 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -266,11 +266,10 @@ typedef struct UINT8 _255; UINT8 packetversion; char application[MAXAPPLICATION]; -#ifdef DEVELOP - UINT8 commit[GIT_SHA_ABBREV]; -#else UINT8 version; UINT8 subversion; +#ifdef DEVELOP + UINT8 commit[GIT_SHA_ABBREV]; #endif UINT8 numberofplayer; UINT8 maxplayer;