From 3d6d2694b358f37511176253d4f0d56ae2c6dd3d Mon Sep 17 00:00:00 2001 From: SteelT Date: Sun, 16 Jul 2023 19:13:20 -0400 Subject: [PATCH 01/23] Fetch the server IP once Fixes ourIP being set on every map change Also catches a possible case where joining clients can sigfail in the window between map change and stun response --- src/d_clisrv.c | 54 +++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index d5023265f..e47e383dc 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -118,7 +118,7 @@ UINT32 playerpingtable[MAXPLAYERS]; //table of player latency values. #define GENTLEMANSMOOTHING (TICRATE) static tic_t reference_lag; -static UINT8 spike_time; +static UINT8 spike_time; static tic_t lowest_lag; boolean server_lagless; static CV_PossibleValue_t mindelay_cons_t[] = {{0, "MIN"}, {30, "MAX"}, {0, NULL}}; @@ -266,7 +266,7 @@ shouldsign_t ShouldSignChallenge(uint8_t *message) #ifndef SRB2_LITTLE_ENDIAN #error "FIXME: 64-bit timestamp field is not supported on Big Endian" #endif - + UINT64 then, now; UINT32 claimedIP, realIP; @@ -2280,7 +2280,7 @@ static void CL_ConnectToServer(void) { PR_ApplyProfile(cv_lastprofile[i].value, i); } - + // Slightly sucks that we have to duplicate these from d_main.c, but // the change to cv_lastprofile doesn't take in time for this codepath. if (M_CheckParm("-profile")) @@ -4029,7 +4029,7 @@ static void Got_AddBot(UINT8 **p, INT32 playernum) K_SetBot(newplayernum, skinnum, difficulty, style); } -static boolean SV_AddWaitingPlayers(SINT8 node, UINT8 *availabilities, +static boolean SV_AddWaitingPlayers(SINT8 node, UINT8 *availabilities, const char *name, uint8_t *key, UINT16 *pwr, const char *name2, uint8_t *key2, UINT16 *pwr2, const char *name3, uint8_t *key3, UINT16 *pwr3, @@ -4192,9 +4192,15 @@ boolean SV_SpawnServer(void) serverrunning = true; SV_ResetServer(); SV_GenContext(); - if (netgame && I_NetOpenSocket) + if (netgame) { - I_NetOpenSocket(); + if (I_NetOpenSocket) + { + I_NetOpenSocket(); + } + + ourIP = 0; + STUN_bind(GotOurIP); } // non dedicated server just connect to itself @@ -4203,9 +4209,7 @@ boolean SV_SpawnServer(void) else doomcom->numslots = 1; } - ourIP = 0; - if (netgame && server) - STUN_bind(GotOurIP); + // strictly speaking, i'm not convinced the following is necessary // but I'm not confident enough to remove it entirely in case it breaks something @@ -4438,19 +4442,19 @@ static void HandleConnect(SINT8 node) memcpy(lastReceivedKey[node][i], PR_GetLocalPlayerProfile(i)->public_key, sizeof(lastReceivedKey[node][i])); } else // Remote player, gotta check their signature. - { + { if (PR_IsKeyGuest(lastReceivedKey[node][i])) // IsSplitPlayerOnNodeGuest isn't appropriate here, they're not in-game yet! { if (!cv_allowguests.value) { SV_SendRefuse(node, M_GetText("The server doesn't allow GUESTs.\nCreate a profile to join!")); - return; + return; } sigcheck = 0; // Always succeeds. Yes, this is a success response. C R Y P T O } else - { + { sigcheck = crypto_eddsa_check(netbuffer->u.clientcfg.challengeResponse[i], lastReceivedKey[node][i], lastSentChallenge[node], CHALLENGELENGTH); } @@ -4473,7 +4477,7 @@ static void HandleConnect(SINT8 node) CONS_Alert(CONS_WARNING, "Joining player's pubkey matches existing player, stat updates will be nonsense!\n"); #else SV_SendRefuse(node, M_GetText("Duplicate pubkey already on server.\n(Did you share your profile?)")); - return; + return; #endif } } @@ -4491,7 +4495,7 @@ static void HandleConnect(SINT8 node) CONS_Alert(CONS_WARNING, "Players with same pubkey in the joning party, stat updates will be nonsense!\n"); #else SV_SendRefuse(node, M_GetText("Duplicate pubkey in local party.\n(How did you even do this?)")); - return; + return; #endif } } @@ -5013,7 +5017,7 @@ static void PT_Say(int node) return; } - stop_spamming[say.source] = 4; + stop_spamming[say.source] = 4; serverplayer_t *stats = SV_GetStatsByPlayerIndex(say.source); @@ -5044,7 +5048,7 @@ static char NodeToSplitPlayer(int node, int split) else if (split == 3) return nodetoplayer4[node]; return -1; -} +} /** Handles a packet received from a node that is in game * @@ -5073,7 +5077,7 @@ static void HandlePacketFromPlayer(SINT8 node) if (netconsole >= MAXPLAYERS) I_Error("bad table nodetoplayer: node %d player %d", doomcom->remotenode, netconsole); #endif - + #ifdef SIGNGAMETRAFFIC if (server) @@ -5097,10 +5101,10 @@ static void HandlePacketFromPlayer(SINT8 node) { if (crypto_eddsa_check(netbuffer->signature[splitnodes], players[targetplayer].public_key, message, doomcom->datalength - BASEPACKETSIZE)) { - CONS_Alert(CONS_ERROR, "SIGFAIL! Packet type %d from node %d player %d\nkey %s size %d netconsole %d\n", + CONS_Alert(CONS_ERROR, "SIGFAIL! Packet type %d from node %d player %d\nkey %s size %d netconsole %d\n", netbuffer->packettype, node, splitnodes, GetPrettyRRID(players[targetplayer].public_key, true), doomcom->datalength - BASEPACKETSIZE, netconsole); - + // Something scary can happen when multiple kicks that resolve to the same node are processed in quick succession. // Sometimes, a kick will still be left to process after the player's been disposed, and that causes the kick to resolve on the server instead! // This sucks, so we check for a stale/misfiring kick beforehand. @@ -5111,7 +5115,7 @@ static void HandlePacketFromPlayer(SINT8 node) return; } } - + } } } @@ -5635,7 +5639,7 @@ static void HandlePacketFromPlayer(SINT8 node) SendKick(targetplayer, KICK_MSG_SIGFAIL); break; } - else + else { memcpy(lastReceivedSignature[targetplayer], netbuffer->u.responseall.signature[responseplayer], sizeof(lastReceivedSignature[targetplayer])); } @@ -5987,7 +5991,7 @@ static void CL_SendClientCmd(void) lagDelay = reference_lag; } } - else + else { reference_lag = lagDelay; // Adjust quickly if the connection improves. spike_time = 0; @@ -6601,10 +6605,10 @@ static void KickUnverifiedPlayers(void) SendKick(i, KICK_MSG_SIGFAIL); } } - } + } } -// +// static void SendChallengeResults(void) { int i; @@ -7130,5 +7134,5 @@ void SendServerNotice(SINT8 target, char *message) { if (client) return; - DoSayCommand(message, target + 1, HU_PRIVNOTICE, servernode); + DoSayCommand(message, target + 1, HU_PRIVNOTICE, servernode); } From 45012dbd6ac4247285d207e073cdade7370d40ea Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 17 Jul 2023 13:51:48 +0100 Subject: [PATCH 02/23] Make sure MT_LOOPCENTERPOINT doesn't have an invalid stack-allocated spawnpoint pointer Fixes connecting to a server that's currently on a map with a loop. Also tidies P_SpawnItemRow, P_SpawnItemCircle to reduce the likelihood of this happening again, and possible crash with Lua-shortcircuited loop spawning --- src/p_mobj.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index ae19e7844..d927090fb 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13788,8 +13788,15 @@ static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 numi y + FixedMul(length, FINESINE(fineangle)), z, MT_LOOPCENTERPOINT); - if (!P_MobjWasRemoved(loopanchor)) - Obj_LinkLoopAnchor(loopanchor, loopcenter, mthing->args[0]); + if (P_MobjWasRemoved(loopanchor)) + { + // No recovery. + return; + } + + loopanchor->spawnpoint = NULL; + + Obj_LinkLoopAnchor(loopanchor, loopcenter, mthing->args[0]); } for (r = 0; r < numitems; r++) @@ -13809,15 +13816,15 @@ static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 numi if (!inclusive) mobj = P_SpawnMobjFromMapThing(&dummything, x, y, z, itemtype); - if (!mobj) + if (P_MobjWasRemoved(mobj)) continue; - if (isloopend) - { - Obj_InitLoopEndpoint(mobj, loopanchor); - } - mobj->spawnpoint = NULL; + + if (!isloopend) + continue; + + Obj_InitLoopEndpoint(mobj, loopanchor); } } @@ -13875,11 +13882,12 @@ static void P_SpawnItemCircle(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 n mobj = P_SpawnMobjFromMapThing(&dummything, x + v[0], y + v[1], z + v[2], itemtype); - if (!mobj) + if (P_MobjWasRemoved(mobj)) continue; - mobj->z -= mobj->height/2; mobj->spawnpoint = NULL; + + mobj->z -= mobj->height/2; } } From f8922c83c893a1da3583caec8023104fab5be77b Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 17 Jul 2023 13:53:13 +0100 Subject: [PATCH 03/23] MD2_TID: Don't pass a macro directly to P_SetThingTID This isn't currently the cause of any issue, but found this future footgun while researching the previous commit. Sometimes functions are turned into macros, which could potentially result in multiple save->p digestions if this was eventually turned into one. --- src/p_saveg.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/p_saveg.c b/src/p_saveg.c index 885b7b5c0..655e915ff 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4074,7 +4074,10 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker) if (diff2 & MD2_RENDERFLAGS) mobj->renderflags = READUINT32(save->p); if (diff2 & MD2_TID) - P_SetThingTID(mobj, READINT16(save->p)); + { + INT16 tid = READINT16(save->p); + P_SetThingTID(mobj, tid); + } if (diff2 & MD2_SPRITESCALE) { mobj->spritexscale = READFIXED(save->p); From a07a9e219195d75d0a7cd251dce6faa352430b86 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 17 Jul 2023 15:12:18 +0100 Subject: [PATCH 04/23] Don't use skincolor unlocks in situations where gamedata is inappropriate - Recieving a different client's XD_NAMEANDCOLOR - Loading profiles on game boot --- src/command.c | 2 +- src/d_netcmd.c | 10 +++++----- src/k_color.c | 6 +++--- src/k_color.h | 5 +++-- src/k_profiles.c | 8 ++++---- src/menus/play-char-select.c | 2 +- 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/command.c b/src/command.c index 7184ace42..1a6c74806 100644 --- a/src/command.c +++ b/src/command.c @@ -917,7 +917,7 @@ static void COM_Help_f(void) boolean follower = (cvar->PossibleValue == Followercolor_cons_t); for (i = SKINCOLOR_NONE; i < numskincolors; ++i) { - if (K_ColorUsable(i, follower) == true) + if (K_ColorUsable(i, follower, true) == true) { CONS_Printf(" %-3d : %s\n", i, skincolors[i].name); if (i == cvar->value) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 823099cf6..e6c36578d 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1497,9 +1497,9 @@ static void SendNameAndColor(const UINT8 n) UINT16 sendFollowerColor = cv_followercolor[n].value; // don't allow inaccessible colors - if (sendColor != SKINCOLOR_NONE && K_ColorUsable(sendColor, false) == false) + if (sendColor != SKINCOLOR_NONE && K_ColorUsable(sendColor, false, true) == false) { - if (player->skincolor && K_ColorUsable(player->skincolor, false) == true) + if (player->skincolor && K_ColorUsable(player->skincolor, false, true) == true) { // Use our previous color CV_StealthSetValue(&cv_playercolor[n], player->skincolor); @@ -1514,7 +1514,7 @@ static void SendNameAndColor(const UINT8 n) } // ditto for follower colour: - if (sendFollowerColor != SKINCOLOR_NONE && K_ColorUsable(sendFollowerColor, true) == false) + if (sendFollowerColor != SKINCOLOR_NONE && K_ColorUsable(sendFollowerColor, true, true) == false) { CV_StealthSet(&cv_followercolor[n], "Default"); // set it to "Default". I don't care about your stupidity! sendFollowerColor = cv_followercolor[n].value; @@ -1724,7 +1724,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) boolean kick = false; // don't allow inaccessible colors - if (K_ColorUsable(p->skincolor, false) == false) + if (K_ColorUsable(p->skincolor, false, false) == false) { kick = true; } @@ -6829,7 +6829,7 @@ static void Color_OnChange(const UINT8 p) I_Assert(p < MAXSPLITSCREENPLAYERS); UINT16 color = cv_playercolor[p].value; - boolean colorisgood = (color == SKINCOLOR_NONE || K_ColorUsable(color, false) == true); + boolean colorisgood = (color == SKINCOLOR_NONE || K_ColorUsable(color, false, true) == true); if (Playing() && splitscreen < p) { diff --git a/src/k_color.c b/src/k_color.c index 9078fc6bc..27d597f87 100644 --- a/src/k_color.c +++ b/src/k_color.c @@ -217,11 +217,11 @@ void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color) } /*-------------------------------------------------- - boolean K_ColorUsable(skincolornum_t color, boolean follower) + boolean K_ColorUsable(skincolornum_t color, boolean follower, boolean locked) See header file for description. --------------------------------------------------*/ -boolean K_ColorUsable(skincolornum_t color, boolean follower) +boolean K_ColorUsable(skincolornum_t color, boolean follower, boolean locked) { INT32 i = MAXUNLOCKABLES; @@ -237,7 +237,7 @@ boolean K_ColorUsable(skincolornum_t color, boolean follower) return false; } - if (demo.playback) + if (demo.playback || !locked) { // Simplifies things elsewhere... return true; diff --git a/src/k_color.h b/src/k_color.h index b835f9194..a66626f62 100644 --- a/src/k_color.h +++ b/src/k_color.h @@ -117,7 +117,7 @@ void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color); /*-------------------------------------------------- - boolean K_ColorUsable(skincolornum_t color, skin_t *skin, follower_t *follower); + boolean K_ColorUsable(skincolornum_t color, skin_t *skin, follower_t *follower, boolean locked); Determines whenever or not we meet the unlockable conditions to use a certain color. @@ -125,12 +125,13 @@ void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color); Input Arguments:- color - Color we want to use. follower - Set to include the special follower-only color options. + locked - use local player's unlocks. Return:- true if we can use it, otherwise false. --------------------------------------------------*/ -boolean K_ColorUsable(skincolornum_t color, boolean follower); +boolean K_ColorUsable(skincolornum_t color, boolean follower, boolean locked); #ifdef __cplusplus diff --git a/src/k_profiles.c b/src/k_profiles.c index 63dccc8b7..f0a0a8e89 100644 --- a/src/k_profiles.c +++ b/src/k_profiles.c @@ -373,7 +373,7 @@ void PR_LoadProfiles(void) ; // Valid, even outside the bounds } else if (profilesList[i]->color >= numskincolors - || K_ColorUsable(profilesList[i]->color, false) == false) + || K_ColorUsable(profilesList[i]->color, false, false) == false) { profilesList[i]->color = PROFILEDEFAULTCOLOR; } @@ -383,13 +383,13 @@ void PR_LoadProfiles(void) profilesList[i]->followercolor = READUINT16(save.p); if (profilesList[i]->followercolor == FOLLOWERCOLOR_MATCH - || profilesList[i]->followercolor == FOLLOWERCOLOR_OPPOSITE) + || profilesList[i]->followercolor == FOLLOWERCOLOR_OPPOSITE + || profilesList[i]->followercolor == SKINCOLOR_NONE) { ; // Valid, even outside the bounds } else if (profilesList[i]->followercolor >= numskincolors - || profilesList[i]->followercolor == SKINCOLOR_NONE - || K_ColorUsable(profilesList[i]->followercolor, true) == false) + || K_ColorUsable(profilesList[i]->followercolor, true, false) == false) { profilesList[i]->followercolor = PROFILEDEFAULTFOLLOWERCOLOR; } diff --git a/src/menus/play-char-select.c b/src/menus/play-char-select.c index 111c24ed8..257f0ad06 100644 --- a/src/menus/play-char-select.c +++ b/src/menus/play-char-select.c @@ -150,7 +150,7 @@ static void M_NewPlayerColors(setup_player_t *p) // Add all unlocked colors for (i = SKINCOLOR_NONE+1; i < numskincolors; i++) { - if (K_ColorUsable(i, follower) == true) + if (K_ColorUsable(i, follower, true) == true) { M_PushMenuColor(&p->colors, i); } From beebfd0d2f60fefd9d6584258208620cd1f8de27 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 18 Jul 2023 15:29:32 +0100 Subject: [PATCH 05/23] Ring Shooter: Only P_SetTarget if player is in game --- src/objects/ring-shooter.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/objects/ring-shooter.c b/src/objects/ring-shooter.c index 3150cf16f..c9812a6b8 100644 --- a/src/objects/ring-shooter.c +++ b/src/objects/ring-shooter.c @@ -63,8 +63,11 @@ static void RemoveRingShooterPointer(mobj_t *base) } // NULL the player's pointer. - player = &players[ rs_base_playerid(base) ]; - P_SetTarget(&player->ringShooter, NULL); + if (playeringame[ rs_base_playerid(base) ]) + { + player = &players[ rs_base_playerid(base) ]; + P_SetTarget(&player->ringShooter, NULL); + } // Remove our player ID rs_base_playerid(base) = -1; From e6619df2d49b3d59377b9c4379ac90ea596db0be Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 18 Jul 2023 15:45:49 +0100 Subject: [PATCH 06/23] Servant Hand: Refactor to use its own thinker Since it's already ticking for the sake of a fuse, make it handle its own movement/scaling as well. Spawning is still handled by the player thinker (and can be blocked by hitlag), but this permits it to disappear when a player dies/disconnects the server. --- src/k_kart.c | 2 +- src/k_objects.h | 3 +- src/objects/servant-hand.c | 81 ++++++++++++++++++++++---------------- src/p_mobj.c | 14 +++++-- 4 files changed, 62 insertions(+), 38 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 31ee0be8e..c1f793399 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8339,7 +8339,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) { K_KartEbrakeVisuals(player); - Obj_ServantHandHandling(player); + Obj_ServantHandSpawning(player); } if (K_GetKartButtons(player) & BT_BRAKE && diff --git a/src/k_objects.h b/src/k_objects.h index e00b4813f..5d063a68e 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -144,7 +144,8 @@ void Obj_GachaBomReboundThink(mobj_t *mobj); void Obj_SpawnGachaBomRebound(mobj_t *source, mobj_t *target); /* Servant Hand */ -void Obj_ServantHandHandling(player_t *player); +void Obj_ServantHandSpawning(player_t *player); +void Obj_ServantHandThink(mobj_t *hand); void Obj_PointPlayersToXY(fixed_t x, fixed_t y); /* Super Flicky Controller */ diff --git a/src/objects/servant-hand.c b/src/objects/servant-hand.c index 2b9cb7527..80c149cde 100644 --- a/src/objects/servant-hand.c +++ b/src/objects/servant-hand.c @@ -8,7 +8,7 @@ #include "../r_main.h" #include "../g_game.h" -void Obj_ServantHandHandling(player_t *player) +void Obj_ServantHandSpawning(player_t *player) { if (player->pflags & PF_WRONGWAY || player->pflags & PF_POINTME) { @@ -36,71 +36,86 @@ void Obj_ServantHandHandling(player_t *player) } } } - - if (player->hand) - { - player->hand->destscale = mapobjectscale; - } } else if (player->handtimer != 0) { player->handtimer--; } +} + +void Obj_ServantHandThink(mobj_t *hand) +{ + UINT8 handtimer = 0; + player_t *player = NULL; + + if (P_MobjWasRemoved(hand->target)) + { + P_RemoveMobj(hand); + return; + } + + if (hand->target->health && hand->target->player && hand->target->player->hand == hand) + { + player = hand->target->player; + handtimer = hand->target->player->handtimer; + } - if (player->hand) { const fixed_t handpokespeed = 4; - const fixed_t looping = handpokespeed - abs((player->hand->threshold % (handpokespeed*2)) - handpokespeed); + const fixed_t looping = handpokespeed - abs((hand->threshold % (handpokespeed*2)) - handpokespeed); fixed_t xoffs = 0, yoffs = 0; - player->hand->color = player->skincolor; - player->hand->angle = player->besthanddirection; - - if (player->hand->fuse != 0) + if (hand->fuse != 0) { ; } else if (looping != 0) { - xoffs = FixedMul(2 * looping * mapobjectscale, FINECOSINE(player->hand->angle >> ANGLETOFINESHIFT)), - yoffs = FixedMul(2 * looping * mapobjectscale, FINESINE(player->hand->angle >> ANGLETOFINESHIFT)), + xoffs = FixedMul(2 * looping * mapobjectscale, FINECOSINE(hand->angle >> ANGLETOFINESHIFT)), + yoffs = FixedMul(2 * looping * mapobjectscale, FINESINE(hand->angle >> ANGLETOFINESHIFT)), - player->hand->threshold++; + hand->threshold++; } - else if (player->handtimer == 0) + else if (handtimer == 0) { - player->hand->fuse = 8; + hand->fuse = 8; } else { - player->hand->threshold++; + hand->threshold++; } - if (player->hand->fuse != 0) + if (hand->fuse != 0) { - if ((player->hand->fuse > 4) ^ (player->handtimer < TICRATE/2)) + if ((hand->fuse > 4) ^ (handtimer < TICRATE/2)) { - player->hand->spritexscale = FRACUNIT/3; - player->hand->spriteyscale = 3*FRACUNIT; + hand->spritexscale = FRACUNIT/3; + hand->spriteyscale = 3*FRACUNIT; } else { - player->hand->spritexscale = 2*FRACUNIT; - player->hand->spriteyscale = FRACUNIT/2; + hand->spritexscale = 2*FRACUNIT; + hand->spriteyscale = FRACUNIT/2; } } - P_MoveOrigin(player->hand, - player->mo->x + xoffs, - player->mo->y + yoffs, - player->mo->z + player->mo->height + 30*mapobjectscale - ); - K_FlipFromObject(player->hand, player->mo); + if (player != NULL) + { + hand->color = player->skincolor; + hand->angle = player->besthanddirection; - player->hand->sprzoff = player->mo->sprzoff; + P_MoveOrigin(hand, + player->mo->x + xoffs, + player->mo->y + yoffs, + player->mo->z + player->mo->height + 30*mapobjectscale + ); + K_FlipFromObject(hand, player->mo); - player->hand->renderflags &= ~RF_DONTDRAW; - player->hand->renderflags |= (RF_DONTDRAW & ~K_GetPlayerDontDrawFlag(player)); + hand->sprzoff = player->mo->sprzoff; + + hand->renderflags &= ~RF_DONTDRAW; + hand->renderflags |= (RF_DONTDRAW & ~K_GetPlayerDontDrawFlag(player)); + } } } diff --git a/src/p_mobj.c b/src/p_mobj.c index d927090fb..103a1e452 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7380,6 +7380,13 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_MantaRingThink(mobj); break; } + case MT_SERVANTHAND: + { + Obj_ServantHandThink(mobj); + if (P_MobjWasRemoved(mobj)) + return false; + break; + } case MT_BALLHOG: { mobj_t *ghost = P_SpawnGhostMobj(mobj); @@ -9831,10 +9838,11 @@ static boolean P_FuseThink(mobj_t *mobj) } case MT_SERVANTHAND: { - if (!mobj->target - || P_MobjWasRemoved(mobj->target) + if (P_MobjWasRemoved(mobj->target) + || !mobj->target->health || !mobj->target->player - || mobj->target->player->handtimer == 0) + || mobj->target->player->handtimer == 0 + || mobj->target->player->hand != mobj) { P_RemoveMobj(mobj); return false; From ce08ac0f33df67761a7c17d9c55895520c76fa6c Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 18 Jul 2023 15:50:39 +0100 Subject: [PATCH 07/23] General tidy of mobj_t pointers on player_t struct - CL_ClearPlayer - Delete followmobj, stumbleIndicator, and sliptideZipIndicator - Wipe flickyAttacker and powerup.flickyController - G_PlayerReborn - Properly destroy the Follower and its bubble overlays, etc - Ensure ringShooter pointer is kept - Delete followmobj, stumbleIndicator, and sliptideZipIndicator - Wipe flickyAttacker and powerup.flickyController - P_PlayerThink - Ensure all invalid pointers are erased, even on hitlag frames --- src/d_clisrv.c | 34 +++++++++++++++++++++++++--------- src/g_game.c | 43 +++++++++++++++++++++++++++++-------------- src/k_kart.c | 12 ------------ src/p_user.c | 19 +++++++++++++++++++ 4 files changed, 73 insertions(+), 35 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index d5023265f..fc365a85b 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2775,20 +2775,36 @@ void CL_ClearPlayer(INT32 playernum) K_RemoveFollower(&players[playernum]); } - if (players[playernum].mo) - { - P_RemoveMobj(players[playernum].mo); - P_SetTarget(&players[playernum].mo, NULL); +#define PlayerPointerRemove(field) \ + if (field) \ + { \ + P_RemoveMobj(field); \ + P_SetTarget(&field, NULL); \ } + // These are mostly subservient to the player, and may not clean themselves up. + PlayerPointerRemove(players[playernum].mo); + PlayerPointerRemove(players[playernum].followmobj); + PlayerPointerRemove(players[playernum].stumbleIndicator); + PlayerPointerRemove(players[playernum].sliptideZipIndicator); + +#undef PlayerPointerRemove + + // These have thinkers of their own. + P_SetTarget(&players[playernum].whip, NULL); + P_SetTarget(&players[playernum].hand, NULL); + P_SetTarget(&players[playernum].hoverhyudoro, NULL); + P_SetTarget(&players[playernum].ringShooter, NULL); + + // TODO: Any better handling in store? + P_SetTarget(&players[playernum].flickyAttacker, NULL); + P_SetTarget(&players[playernum].powerup.flickyController, NULL); + + // These are camera items and possibly belong to multiple players. P_SetTarget(&players[playernum].skybox.viewpoint, NULL); P_SetTarget(&players[playernum].skybox.centerpoint, NULL); P_SetTarget(&players[playernum].awayview.mobj, NULL); - P_SetTarget(&players[playernum].followmobj, NULL); - P_SetTarget(&players[playernum].hoverhyudoro, NULL); - P_SetTarget(&players[playernum].stumbleIndicator, NULL); - P_SetTarget(&players[playernum].sliptideZipIndicator, NULL); - P_SetTarget(&players[playernum].ringShooter, NULL); + } // Handle parties. diff --git a/src/g_game.c b/src/g_game.c index 1280a8319..708479fbc 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2455,10 +2455,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) INT32 followerskin; UINT16 followercolor; - mobj_t *follower; // old follower, will probably be removed by the time we're dead but you never know. - mobj_t *hoverhyudoro; - mobj_t *skyboxviewpoint; - mobj_t *skyboxcenterpoint; + mobj_t *ringShooter, *hoverhyudoro; + mobj_t *skyboxviewpoint, *skyboxcenterpoint; INT32 charflags; UINT32 followitem; @@ -2677,22 +2675,40 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) if (!betweenmaps) { - follower = players[player].follower; - P_SetTarget(&players[player].follower, NULL); - P_SetTarget(&players[player].awayview.mobj, NULL); - P_SetTarget(&players[player].stumbleIndicator, NULL); + K_RemoveFollower(&players[player]); + +#define PlayerPointerRemove(field) \ + if (field) \ + { \ + P_RemoveMobj(field); \ + P_SetTarget(&field, NULL); \ + } + + // These are mostly subservient to the player, and may not clean themselves up. + PlayerPointerRemove(players[player].followmobj); + PlayerPointerRemove(players[player].stumbleIndicator); + PlayerPointerRemove(players[player].sliptideZipIndicator); + +#undef PlayerPointerRemove + + // These will erase themselves. P_SetTarget(&players[player].whip, NULL); P_SetTarget(&players[player].hand, NULL); - P_SetTarget(&players[player].ringShooter, NULL); - P_SetTarget(&players[player].followmobj, NULL); + // TODO: Any better handling in store? + P_SetTarget(&players[player].awayview.mobj, NULL); + P_SetTarget(&players[player].flickyAttacker, NULL); + P_SetTarget(&players[player].powerup.flickyController, NULL); + + // The following pointers are safe to set directly, because the end goal should be refcount consistency before and after remanifestation. + ringShooter = players[player].ringShooter; hoverhyudoro = players[player].hoverhyudoro; skyboxviewpoint = players[player].skybox.viewpoint; skyboxcenterpoint = players[player].skybox.centerpoint; } else { - follower = hoverhyudoro = NULL; + ringShooter = hoverhyudoro = NULL; skyboxviewpoint = skyboxcenterpoint = NULL; } @@ -2769,9 +2785,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) if (saveroundconditions) memcpy(&p->roundconditions, &roundconditions, sizeof (p->roundconditions)); - if (follower) - P_RemoveMobj(follower); - + // See above comment about refcount consistency. + p->ringShooter = ringShooter; p->hoverhyudoro = hoverhyudoro; p->skybox.viewpoint = skyboxviewpoint; p->skybox.centerpoint = skyboxcenterpoint; diff --git a/src/k_kart.c b/src/k_kart.c index c1f793399..4f570f3b5 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8065,9 +8065,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->guardCooldown) player->guardCooldown--; - - if (player->whip && P_MobjWasRemoved(player->whip)) - P_SetTarget(&player->whip, NULL); if (player->startboost > 0 && onground == true) { @@ -8326,15 +8323,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->tripwireState = TRIPSTATE_NONE; } - if (player->hand && P_MobjWasRemoved(player->hand)) - P_SetTarget(&player->hand, NULL); - - if (player->flickyAttacker && P_MobjWasRemoved(player->flickyAttacker)) - P_SetTarget(&player->flickyAttacker, NULL); - - if (player->powerup.flickyController && P_MobjWasRemoved(player->powerup.flickyController)) - P_SetTarget(&player->powerup.flickyController, NULL); - if (player->spectator == false) { K_KartEbrakeVisuals(player); diff --git a/src/p_user.c b/src/p_user.c index 74b5d6231..692eabdb0 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4249,6 +4249,25 @@ void P_PlayerThink(player_t *player) player->playerstate = PST_DEAD; } + // Erasing invalid player pointers + { +#define PlayerPointerErase(field) \ + if (field && P_MobjWasRemoved(field)) \ + P_SetTarget(&field, NULL); \ + + PlayerPointerErase(player->followmobj); + PlayerPointerErase(player->stumbleIndicator); + PlayerPointerErase(player->sliptideZipIndicator); + PlayerPointerErase(player->whip); + PlayerPointerErase(player->hand); + PlayerPointerErase(player->ringShooter); + PlayerPointerErase(player->hoverhyudoro); + PlayerPointerErase(player->flickyAttacker); + PlayerPointerErase(player->powerup.flickyController); + +#undef PlayerPointerErase + } + player->old_drawangle = player->drawangle; P_TickAltView(&player->awayview); From a812ef8809b1bb39a75f12f94dd70753cebd6494 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 18 Jul 2023 17:39:17 +0100 Subject: [PATCH 08/23] DMG_WHUMBLE There are two differences between Whumble and Stumble. - Stumble cannot be combo'd on upwards momentum, while whumble can. (Resolves #522) - Whumble takes bumpers, while stumble does not. - Removes the MT_INSTAWHIP hack. --- src/deh_tables.c | 1 + src/k_collide.cpp | 2 +- src/p_inter.c | 21 +++++++++++++-------- src/p_local.h | 1 + 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index edbb93eba..3be3edeb3 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -6550,6 +6550,7 @@ struct int_const_s const INT_CONST[] = { {"DMG_KARMA",DMG_KARMA}, {"DMG_VOLTAGE",DMG_VOLTAGE}, {"DMG_STUMBLE",DMG_STUMBLE}, + {"DMG_WHUMBLE",DMG_WHUMBLE}, //// Death types {"DMG_INSTAKILL",DMG_INSTAKILL}, {"DMG_DEATHPIT",DMG_DEATHPIT}, diff --git a/src/k_collide.cpp b/src/k_collide.cpp index 2f65d1536..4f920ea1e 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -888,7 +888,7 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim) // while still behaving as if it's a "real" hit. P_PlayRinglossSound(victim); P_PlayerRingBurst(victimPlayer, 5); - P_DamageMobj(victim, shield, attacker, 1, DMG_STUMBLE); // There's a special exception in P_DamageMobj for type==MT_INSTAWHIP + P_DamageMobj(victim, shield, attacker, 1, DMG_WHUMBLE); K_DropPowerUps(victimPlayer); diff --git a/src/p_inter.c b/src/p_inter.c index edc48a28b..6ff23128d 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2326,7 +2326,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da invincible = false; } - if (invincible && type != DMG_STUMBLE) + if (invincible && type != DMG_STUMBLE && type != DMG_WHUMBLE) { const INT32 oldHitlag = target->hitlag; const INT32 oldHitlagInflictor = inflictor ? inflictor->hitlag : 0; @@ -2384,7 +2384,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da { // Check if we should allow wombo combos (hard hits by default, inverted by the presence of DMG_WOMBO). - boolean allowcombo = ((hardhit || (type == DMG_STUMBLE)) == !(damagetype & DMG_WOMBO)); + boolean allowcombo = ((hardhit || (type == DMG_STUMBLE || type == DMG_WHUMBLE)) == !(damagetype & DMG_WOMBO)); // Tumble/stumble is a special case. if (type == DMG_TUMBLE) @@ -2393,11 +2393,16 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (player->tumbleBounces == 1 && (P_MobjFlip(target)*target->momz > 0)) allowcombo = false; } - else if (type == DMG_STUMBLE) + else if (type == DMG_STUMBLE || type == DMG_WHUMBLE) { // don't allow constant combo if (player->tumbleBounces == TUMBLEBOUNCES-1 && (P_MobjFlip(target)*target->momz > 0)) + { + if (type == DMG_STUMBLE) + return false; // No-sell strings of stumble + allowcombo = false; + } } if (allowcombo == false && (target->eflags & MFE_PAUSED)) @@ -2406,7 +2411,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } // DMG_EXPLODE excluded from flashtic checks to prevent dodging eggbox/SPB with weak spinout - if ((target->hitlag == 0 || allowcombo == false) && player->flashing > 0 && type != DMG_EXPLODE && type != DMG_STUMBLE) + if ((target->hitlag == 0 || allowcombo == false) && player->flashing > 0 && type != DMG_EXPLODE && type != DMG_STUMBLE && type != DMG_WHUMBLE) { // Post-hit invincibility K_DoInstashield(player); @@ -2434,9 +2439,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da damage = 0; } - // Instawhip breaks the rules and does "damaging stumble", - // but sting and stumble shouldn't be rewarding Battle hits otherwise. - if ((type == DMG_STING || type == DMG_STUMBLE) && !(inflictor && inflictor->type == MT_INSTAWHIP)) + // Sting and stumble shouldn't be rewarding Battle hits. + if (type == DMG_STING || type == DMG_STUMBLE) { damage = 0; } @@ -2532,6 +2536,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da ringburst = 0; break; case DMG_STUMBLE: + case DMG_WHUMBLE: K_StumblePlayer(player); ringburst = 0; break; @@ -2554,7 +2559,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da break; } - if (type != DMG_STUMBLE) + if (type != DMG_STUMBLE && type != DMG_WHUMBLE) { if (type != DMG_STING) player->flashing = K_GetKartFlashing(player); diff --git a/src/p_local.h b/src/p_local.h index 6b5846145..98168afe2 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -544,6 +544,7 @@ struct BasicFF_t #define DMG_KARMA 0x05 // Karma Bomb explosion -- works like DMG_EXPLODE, but steals half of their bumpers & deletes the rest #define DMG_VOLTAGE 0x06 #define DMG_STUMBLE 0x07 +#define DMG_WHUMBLE 0x08 //// Death types - cannot be combined with damage types #define DMG_INSTAKILL 0x80 #define DMG_DEATHPIT 0x81 From bfc8036e7e32f219648a8af2a822b594c8b2b3da Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 18 Jul 2023 17:53:54 +0100 Subject: [PATCH 09/23] Use display players for hearing/seeing horns, not local players Matches other local effects, and permits spectators (such as in tournaments) and replay watchers to see the honk. --- src/k_follower.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_follower.c b/src/k_follower.c index 511e81932..b1e4261b0 100644 --- a/src/k_follower.c +++ b/src/k_follower.c @@ -722,7 +722,7 @@ void K_FollowerHornTaunt(player_t *taunter, player_t *victim) || victim == NULL || taunter->followerskin < 0 || taunter->followerskin >= numfollowers - || (P_IsLocalPlayer(victim) == false && cv_karthorns.value != 2) + || (P_IsDisplayPlayer(victim) == false && cv_karthorns.value != 2) || P_MobjWasRemoved(taunter->mo) == true || P_MobjWasRemoved(taunter->follower) == true ) From 0b3ebb0686fcbb8ce312f12a73cc2e5aee827f4e Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 18 Jul 2023 18:00:51 +0100 Subject: [PATCH 10/23] Kickstart Accel indicator sound modifications - Play in replays/as spectator - Do not play for bot-controlled players (exiting, Podium, etc) --- src/p_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index 74b5d6231..c9a3e0357 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4302,7 +4302,7 @@ void P_PlayerThink(player_t *player) else if (player->kickstartaccel < ACCEL_KICKSTART) { player->kickstartaccel++; - if ((player->kickstartaccel == ACCEL_KICKSTART) && P_IsLocalPlayer(player)) + if ((player->kickstartaccel == ACCEL_KICKSTART) && !K_PlayerUsesBotMovement(player) && P_IsDisplayPlayer(player)) { S_StartSound(NULL, sfx_ding); } From 9b51c9c7fe54d7e14f0d95ab898f9b2a78e5fc4b Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 18 Jul 2023 19:52:14 +0100 Subject: [PATCH 11/23] V_GetHWConsBackColor: Fix for RR's console color list Also, don't be such a weenie that you say slurs in your code comments --- src/v_video.cpp | 58 ++++++++++++++----------------------------------- 1 file changed, 16 insertions(+), 42 deletions(-) diff --git a/src/v_video.cpp b/src/v_video.cpp index 5c06f45e8..c0efa5a9b 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1083,8 +1083,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) .done(); } -#ifdef HWRENDER -// This is now a function since it's otherwise repeated 2 times and honestly looks retarded: +// This is now a function, no use being such a weenie that you say a slur over it static UINT32 V_GetHWConsBackColor(void) { UINT32 hwcolor; @@ -1095,26 +1094,25 @@ static UINT32 V_GetHWConsBackColor(void) case 2: hwcolor = 0xdeb88700; break; // Sepia case 3: hwcolor = 0x40201000; break; // Brown case 4: hwcolor = 0xfa807200; break; // Pink - case 5: hwcolor = 0xff69b400; break; // Raspberry - case 6: hwcolor = 0xff000000; break; // Red - case 7: hwcolor = 0xffd68300; break; // Creamsicle - case 8: hwcolor = 0xff800000; break; // Orange - case 9: hwcolor = 0xdaa52000; break; // Gold - case 10: hwcolor = 0x80800000; break; // Yellow - case 11: hwcolor = 0x00ff0000; break; // Emerald - case 12: hwcolor = 0x00800000; break; // Green - case 13: hwcolor = 0x4080ff00; break; // Cyan - case 14: hwcolor = 0x4682b400; break; // Steel - case 15: hwcolor = 0x1e90ff00; break; // Periwinkle - case 16: hwcolor = 0x0000ff00; break; // Blue - case 17: hwcolor = 0xff00ff00; break; // Purple - case 18: hwcolor = 0xee82ee00; break; // Lavender + case 5: hwcolor = 0xff000000; break; // Red + case 6: hwcolor = 0xff800000; break; // Orange + case 7: hwcolor = 0xdaa52000; break; // Gold + case 8: hwcolor = 0xffdd0000; break; // Yellow + case 9: hwcolor = 0xc5e80000; break; // Peridot + case 10: hwcolor = 0x00800000; break; // Green + case 11: hwcolor = 0x15f2b000; break; // Aquamarine + case 12: hwcolor = 0x00ffff00; break; // Cyan + case 13: hwcolor = 0x4682b400; break; // Steel + case 14: hwcolor = 0x0000ff00; break; // Blue + case 15: hwcolor = 0x9844ff00; break; // Purple + case 16: hwcolor = 0xff00ff00; break; // Magenta + case 17: hwcolor = 0xee82ee00; break; // Lavender + case 18: hwcolor = 0xf570a500; break; // Rose // Default green default: hwcolor = 0x00800000; break; } return hwcolor; } -#endif // THANK YOU MPC!!! // and thanks toaster for cleaning it up. @@ -1674,31 +1672,7 @@ void V_DrawPromptBack(INT32 boxheight, INT32 color) if (color == INT32_MAX) color = cons_backcolor.value; - UINT32 hwcolor; - switch (color) - { - case 0: hwcolor = 0xffffff00; break; // White - case 1: hwcolor = 0x00000000; break; // Black // Note this is different from V_DrawFadeConsBack - case 2: hwcolor = 0xdeb88700; break; // Sepia - case 3: hwcolor = 0x40201000; break; // Brown - case 4: hwcolor = 0xfa807200; break; // Pink - case 5: hwcolor = 0xff69b400; break; // Raspberry - case 6: hwcolor = 0xff000000; break; // Red - case 7: hwcolor = 0xffd68300; break; // Creamsicle - case 8: hwcolor = 0xff800000; break; // Orange - case 9: hwcolor = 0xdaa52000; break; // Gold - case 10: hwcolor = 0x80800000; break; // Yellow - case 11: hwcolor = 0x00ff0000; break; // Emerald - case 12: hwcolor = 0x00800000; break; // Green - case 13: hwcolor = 0x4080ff00; break; // Cyan - case 14: hwcolor = 0x4682b400; break; // Steel - case 15: hwcolor = 0x1e90ff00; break; // Periwinkle - case 16: hwcolor = 0x0000ff00; break; // Blue - case 17: hwcolor = 0xff00ff00; break; // Purple - case 18: hwcolor = 0xee82ee00; break; // Lavender - // Default green - default: hwcolor = 0x00800000; break; - } + UINT32 hwcolor = V_GetHWConsBackColor(); #ifdef HWRENDER if (rendermode == render_opengl) From 24ab95ddde9074d91577a4c594b57350cc27437e Mon Sep 17 00:00:00 2001 From: Zwip-Zwap Zapony Date: Sun, 20 Nov 2022 11:50:01 +0100 Subject: [PATCH 12/23] Uncap console opening/closing animation --- src/console.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/console.c b/src/console.c index 3c5e0f9f2..ee6f8e672 100644 --- a/src/console.c +++ b/src/console.c @@ -614,33 +614,39 @@ static void CON_ChangeHeight(void) // static void CON_MoveConsole(void) { - fixed_t conspeed; + static fixed_t fracmovement = 0; Lock_state(); - conspeed = FixedDiv(cons_speed.value*vid.fdupy, FRACUNIT); - // instant if (!cons_speed.value) { con_curlines = con_destlines; + Unlock_state(); return; } - // up/down move to dest - if (con_curlines < con_destlines) + // Not instant - Increment fracmovement fractionally + fracmovement += FixedMul(cons_speed.value*vid.fdupy, renderdeltatics); + + if (con_curlines < con_destlines) // Move the console downwards { - con_curlines += FixedInt(conspeed); - if (con_curlines > con_destlines) - con_curlines = con_destlines; + con_curlines += FixedInt(fracmovement); // Move by fracmovement's integer value + if (con_curlines > con_destlines) // If we surpassed the destination... + con_curlines = con_destlines; // ...clamp to it! } - else if (con_curlines > con_destlines) + else // Move the console upwards { - con_curlines -= FixedInt(conspeed); + con_curlines -= FixedInt(fracmovement); if (con_curlines < con_destlines) con_curlines = con_destlines; + + if (con_destlines == 0) // If the console is being closed, not just moved up... + con_tick = 0; // ...don't show the blinking cursor } + fracmovement %= FRACUNIT; // Reset fracmovement's integer value, but keep the fraction + Unlock_state(); } @@ -759,10 +765,6 @@ void CON_Ticker(void) CON_ChangeHeight(); } - // console movement - if (con_destlines != con_curlines) - CON_MoveConsole(); - // clip the view, so that the part under the console is not drawn con_clipviewtop = -1; if (cons_backpic.value) // clip only when using an opaque background @@ -1875,6 +1877,10 @@ void CON_Drawer(void) CON_ClearHUD(); } + // console movement + if (con_curlines != con_destlines) + CON_MoveConsole(); + if (con_curlines > 0) CON_DrawConsole(); else if (CON_GamestateDrawHudLines() == true) From 4c08b7010ddc8dd45a1c3921fa8a9cb6a19e24f1 Mon Sep 17 00:00:00 2001 From: Zwip-Zwap Zapony Date: Sun, 20 Nov 2022 11:50:57 +0100 Subject: [PATCH 13/23] Make con_height adjustable on the fly --- src/console.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/console.c b/src/console.c index ee6f8e672..735fe1ba4 100644 --- a/src/console.c +++ b/src/console.c @@ -108,6 +108,7 @@ static void CON_RecalcSize(void); static void CON_ChangeHeight(void); static void CON_DrawBackpic(void); +static void CONS_height_Change(void); static void CONS_hudlines_Change(void); static void CONS_backcolor_Change(void); @@ -134,7 +135,7 @@ static CV_PossibleValue_t speed_cons_t[] = {{0, "MIN"}, {64, "MAX"}, {0, NULL}}; static consvar_t cons_speed = CVAR_INIT ("con_speed", "8", CV_SAVE, speed_cons_t, NULL); // percentage of screen height to use for console -static consvar_t cons_height = CVAR_INIT ("con_height", "50", CV_SAVE, CV_Unsigned, NULL); +static consvar_t cons_height = CVAR_INIT ("con_height", "50", CV_CALL|CV_SAVE, CV_Unsigned, CONS_height_Change); static CV_PossibleValue_t backpic_cons_t[] = {{0, "translucent"}, {1, "picture"}, {0, NULL}}; // whether to use console background picture, or translucent mode @@ -152,6 +153,18 @@ consvar_t cons_backcolor = CVAR_INIT ("con_backcolor", "Black", CV_CALL|CV_SAVE, static void CON_Print(char *msg); +// Change the console height on demand +// +static void CONS_height_Change(void) +{ + Lock_state(); + + if (con_destlines > 0 && !con_startup) // If the console is open (as in, not using "bind")... + CON_ChangeHeight(); // ...update its height now, not only when it's closed and re-opened + + Unlock_state(); +} + // // static void CONS_hudlines_Change(void) From c36d987be7da25f01ff31ac3eb444bb9f15bad9f Mon Sep 17 00:00:00 2001 From: Zwip-Zwap Zapony Date: Sun, 20 Nov 2022 11:51:40 +0100 Subject: [PATCH 14/23] Draw the input prompt while the console is moving --- src/console.c | 52 +++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/console.c b/src/console.c index 735fe1ba4..cdb0e0fc0 100644 --- a/src/console.c +++ b/src/console.c @@ -59,7 +59,7 @@ static boolean con_started = false; // console has been initialised static boolean con_forcepic = true; // at startup toggle console translucency when first off boolean con_recalc; // set true when screen size has changed -static tic_t con_tick; // console ticker for anim or blinking prompt cursor +static tic_t con_tick; // console ticker for blinking prompt cursor // con_scrollup should use time (currenttime - lasttime).. static boolean consoletoggle; // true when console key pushed, ticker will handle @@ -1814,41 +1814,41 @@ static void CON_DrawConsole(void) } // draw console text lines from top to bottom - if (con_curlines < minheight) - return; - - i = con_cy - con_scrollup; - - // skip the last empty line due to the cursor being at the start of a new line - i--; - - i -= (con_curlines - minheight) / charheight; - - if (rendermode == render_none) return; - - for (y = (con_curlines-minheight) % charheight; y <= con_curlines-minheight; y += charheight, i++) + if (con_curlines >= minheight) { - INT32 x; - size_t c; + i = con_cy - con_scrollup; - p = (UINT8 *)&con_buffer[((i > 0 ? i : 0)%con_totallines)*con_width]; + // skip the last empty line due to the cursor being at the start of a new line + i--; - for (c = 0, x = charwidth; c < con_width; c++, x += charwidth, p++) + i -= (con_curlines - minheight) / charheight; + + if (rendermode == render_none) return; + + for (y = (con_curlines-minheight) % charheight; y <= con_curlines-minheight; y += charheight, i++) { - while (*p & 0x80) + INT32 x; + size_t c; + + p = (UINT8 *)&con_buffer[((i > 0 ? i : 0)%con_totallines)*con_width]; + + for (c = 0, x = charwidth; c < con_width; c++, x += charwidth, p++) { - charflags = (*p & 0x7f) << V_CHARCOLORSHIFT; - p++; - c++; + while (*p & 0x80) + { + charflags = (*p & 0x7f) << V_CHARCOLORSHIFT; + p++; + c++; + } + if (c >= con_width) + break; + V_DrawCharacter(x, y, (INT32)(*p) | charflags | cv_constextsize.value | V_NOSCALESTART, true); } - if (c >= con_width) - break; - V_DrawCharacter(x, y, (INT32)(*p) | charflags | cv_constextsize.value | V_NOSCALESTART, true); } } // draw prompt if enough place (not while game startup) - if ((con_curlines == con_destlines) && (con_curlines >= minheight) && !con_startup) + if ((con_curlines >= (minheight-charheight)) && !con_startup) CON_DrawInput(); } From ea53197084dfd965eb4ffc4f8c1943b96479e097 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 18 Jul 2023 20:26:43 +0100 Subject: [PATCH 15/23] Fix off by 1 error in con_hudlines Originally written by Zwip-Zwap Zapony for the SRB2 repository as part of STJR/SRB2!1931, partially flattened to avoid waiting for the merger of the entire branch. - 0, not 1 as previously was the case, now shows zero lines. - Now inclusively capped between 0 and 20 lines in the cvar, rather than silently in the console code. --- src/console.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/console.c b/src/console.c index cdb0e0fc0..d8691df52 100644 --- a/src/console.c +++ b/src/console.c @@ -70,8 +70,8 @@ static INT32 con_curlines; // vid lines currently used by console INT32 con_clipviewtop; // (useless) -static INT32 con_hudlines; // number of console heads up message lines -static INT32 con_hudtime[MAXHUDLINES]; // remaining time of display for hud msg lines +static UINT8 con_hudlines; // number of console heads up message lines +static INT32 con_hudtime[MAXHUDLINES]; // remaining time of display for hud msg lines INT32 con_clearlines; // top screen lines to refresh when view reduced boolean con_hudupdate; // when messages scroll, we need a backgrnd refresh @@ -127,7 +127,8 @@ static char con_buffer[CON_BUFFERSIZE]; static consvar_t cons_msgtimeout = CVAR_INIT ("con_hudtime", "5", CV_SAVE, CV_Unsigned, NULL); // number of lines displayed on the HUD -static consvar_t cons_hudlines = CVAR_INIT ("con_hudlines", "5", CV_CALL|CV_SAVE, CV_Unsigned, CONS_hudlines_Change); +static CV_PossibleValue_t hudlines_cons_t[] = {{0, "MIN"}, {MAXHUDLINES, "MAX"}, {0, "None"}, {0, NULL}}; +static consvar_t cons_hudlines = CVAR_INIT ("con_hudlines", "5", CV_CALL|CV_SAVE, hudlines_cons_t, CONS_hudlines_Change); // number of lines console move per frame // (con_speed needs a limit, apparently) @@ -177,11 +178,6 @@ static void CONS_hudlines_Change(void) for (i = 0; i < con_hudlines; i++) con_hudtime[i] = 0; - if (cons_hudlines.value < 1) - cons_hudlines.value = 1; - else if (cons_hudlines.value > MAXHUDLINES) - cons_hudlines.value = MAXHUDLINES; - con_hudlines = cons_hudlines.value; Unlock_state(); @@ -799,9 +795,8 @@ void CON_Ticker(void) // make overlay messages disappear after a while for (i = 0; i < con_hudlines; i++) { - con_hudtime[i]--; - if (con_hudtime[i] < 0) - con_hudtime[i] = 0; + if (con_hudtime[i]) + con_hudtime[i]--; } Unlock_state(); @@ -1349,7 +1344,8 @@ boolean CON_Responder(event_t *ev) static void CON_Linefeed(void) { // set time for heads up messages - con_hudtime[con_cy%con_hudlines] = cons_msgtimeout.value*TICRATE; + if (con_hudlines) + con_hudtime[con_cy%con_hudlines] = cons_msgtimeout.value*TICRATE; con_cy++; con_cx = 0; @@ -1689,7 +1685,7 @@ static void CON_DrawHudlines(void) INT32 charwidth = 8 * con_scalefactor; INT32 charheight = 8 * con_scalefactor; - if (con_hudlines <= 0) + if (!con_hudlines) return; if (chat_on && OLDCHAT) @@ -1697,7 +1693,7 @@ static void CON_DrawHudlines(void) else y = 0; - for (i = con_cy - con_hudlines+1; i <= con_cy; i++) + for (i = con_cy - con_hudlines; i <= con_cy; i++) { size_t c; INT32 x; From 05b130b422c90990c3be301be44b102f8efa78e6 Mon Sep 17 00:00:00 2001 From: SteelT Date: Thu, 13 Jul 2023 01:02:15 -0400 Subject: [PATCH 16/23] Add CV_TrueFalse as possible value types for console variables This also adds support for using true/false as value aliases for On/Off, Yes/No or 1/0 # Conflicts: # src/command.c --- src/command.c | 13 ++++++++----- src/command.h | 1 + src/lua_consolelib.c | 4 +++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/command.c b/src/command.c index 7184ace42..2066fbff7 100644 --- a/src/command.c +++ b/src/command.c @@ -78,6 +78,7 @@ CV_PossibleValue_t CV_OnOff[] = {{0, "Off"}, {1, "On"}, {0, NULL}}; CV_PossibleValue_t CV_YesNo[] = {{0, "No"}, {1, "Yes"}, {0, NULL}}; CV_PossibleValue_t CV_Unsigned[] = {{0, "MIN"}, {999999999, "MAX"}, {0, NULL}}; CV_PossibleValue_t CV_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}}; +CV_PossibleValue_t CV_TrueFalse[] = {{0, "False"}, {1, "True"}, {0, NULL}}; // Cheats #ifdef DEVELOP @@ -909,9 +910,11 @@ static void COM_Help_f(void) { CONS_Printf(" Possible values:\n"); if (cvar->PossibleValue == CV_YesNo) - CONS_Printf(" Yes or No (On or Off, 1 or 0)\n"); + CONS_Printf(" Yes or No (On or Off, True or False, 1 or 0)\n"); else if (cvar->PossibleValue == CV_OnOff) - CONS_Printf(" On or Off (Yes or No, 1 or 0)\n"); + CONS_Printf(" On or Off (Yes or No, True or False, 1 or 0)\n"); + else if (cvar->PossibleValue == CV_TrueFalse) + CONS_Printf(" True or False (On or Off, Yes or No, 1 or 0)\n"); else if (cvar->PossibleValue == Color_cons_t || cvar->PossibleValue == Followercolor_cons_t) { boolean follower = (cvar->PossibleValue == Followercolor_cons_t); @@ -1565,12 +1568,12 @@ boolean CV_CompleteValue(consvar_t *var, const char **valstrp, INT32 *intval) goto found; } // Not found ... but wait, there's hope! - if (var->PossibleValue == CV_OnOff || var->PossibleValue == CV_YesNo) + if (var->PossibleValue == CV_OnOff || var->PossibleValue == CV_YesNo || var->PossibleValue == CV_TrueFalse) { overrideval = -1; - if (!stricmp(valstr, "on") || !stricmp(valstr, "yes")) + if (!stricmp(valstr, "on") || !stricmp(valstr, "yes") || !stricmp(valstr, "true")) overrideval = 1; - else if (!stricmp(valstr, "off") || !stricmp(valstr, "no")) + else if (!stricmp(valstr, "off") || !stricmp(valstr, "no") || !stricmp(valstr, "false")) overrideval = 0; if (overrideval != -1) diff --git a/src/command.h b/src/command.h index b3bae86a7..52e18f0fd 100644 --- a/src/command.h +++ b/src/command.h @@ -172,6 +172,7 @@ extern CV_PossibleValue_t CV_OnOff[]; extern CV_PossibleValue_t CV_YesNo[]; extern CV_PossibleValue_t CV_Unsigned[]; extern CV_PossibleValue_t CV_Natural[]; +extern CV_PossibleValue_t CV_TrueFalse[]; // SRB2kart // the KARTSPEED and KARTGP were previously defined here, but moved to doomstat to avoid circular dependencies diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 12a5f2ff3..965e9dd42 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -341,7 +341,7 @@ static int lib_cvRegisterVar(lua_State *L) } else if (i == 4 || (k && fasticmp(k, "PossibleValue"))) { if (lua_islightuserdata(L, 4)) { CV_PossibleValue_t *pv = lua_touserdata(L, 4); - if (pv == CV_OnOff || pv == CV_YesNo || pv == CV_Unsigned || pv == CV_Natural) + if (pv == CV_OnOff || pv == CV_YesNo || pv == CV_Unsigned || pv == CV_Natural || pv == CV_TrueFalse) cvar->PossibleValue = pv; else FIELDERROR("PossibleValue", "CV_PossibleValue_t expected, got unrecognised pointer") @@ -577,6 +577,8 @@ int LUA_ConsoleLib(lua_State *L) lua_setglobal(L, "CV_Unsigned"); lua_pushlightuserdata(L, CV_Natural); lua_setglobal(L, "CV_Natural"); + lua_pushlightuserdata(L, CV_TrueFalse); + lua_setglobal(L, "CV_TrueFalse"); // Set global functions lua_pushvalue(L, LUA_GLOBALSINDEX); From 02651d249c0faf943bcca447454234eb8ab257c7 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 18 Jul 2023 20:43:07 +0100 Subject: [PATCH 17/23] Set default value of `bots` to Off, not 0 --- 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 823099cf6..96fcdddd0 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -430,7 +430,7 @@ static CV_PossibleValue_t kartbot_cons_t[] = { {13,"Lv.MAX"}, {0, NULL} }; -consvar_t cv_kartbot = CVAR_INIT ("bots", "0", CV_NETVAR, kartbot_cons_t, NULL); +consvar_t cv_kartbot = CVAR_INIT ("bots", "Off", CV_NETVAR, kartbot_cons_t, NULL); consvar_t cv_karteliminatelast = CVAR_INIT ("eliminatelast", "Yes", CV_NETVAR|CV_CALL, CV_YesNo, KartEliminateLast_OnChange); From e2ee6e45d76ec4015c39e40cef2e19f172f0993a Mon Sep 17 00:00:00 2001 From: Zwip-Zwap Zapony Date: Sat, 4 Feb 2023 17:35:44 +0100 Subject: [PATCH 18/23] Limit con_hudtime to 24 hours Also rename cons_msgtimeout to cons_hudtime for consistency --- src/console.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/console.c b/src/console.c index d8691df52..eb7a1ccd9 100644 --- a/src/console.c +++ b/src/console.c @@ -70,8 +70,8 @@ static INT32 con_curlines; // vid lines currently used by console INT32 con_clipviewtop; // (useless) -static UINT8 con_hudlines; // number of console heads up message lines -static INT32 con_hudtime[MAXHUDLINES]; // remaining time of display for hud msg lines +static UINT8 con_hudlines; // number of console heads up message lines +static UINT32 con_hudtime[MAXHUDLINES]; // remaining time of display for hud msg lines INT32 con_clearlines; // top screen lines to refresh when view reduced boolean con_hudupdate; // when messages scroll, we need a backgrnd refresh @@ -124,7 +124,9 @@ static void CONS_backcolor_Change(void); static char con_buffer[CON_BUFFERSIZE]; // how many seconds the hud messages lasts on the screen -static consvar_t cons_msgtimeout = CVAR_INIT ("con_hudtime", "5", CV_SAVE, CV_Unsigned, NULL); +// CV_Unsigned can overflow when multiplied by TICRATE later, so let's use a 24-hour limit instead +static CV_PossibleValue_t hudtime_cons_t[] = {{0, "MIN"}, {86400, "MAX"}, {0, NULL}}; +static consvar_t cons_hudtime = CVAR_INIT ("con_hudtime", "5", CV_SAVE, hudtime_cons_t, NULL); // number of lines displayed on the HUD static CV_PossibleValue_t hudlines_cons_t[] = {{0, "MIN"}, {MAXHUDLINES, "MAX"}, {0, "None"}, {0, NULL}}; @@ -458,7 +460,7 @@ void CON_Init(void) Unlock_state(); - CV_RegisterVar(&cons_msgtimeout); + CV_RegisterVar(&cons_hudtime); CV_RegisterVar(&cons_hudlines); CV_RegisterVar(&cons_speed); CV_RegisterVar(&cons_height); @@ -1345,7 +1347,7 @@ static void CON_Linefeed(void) { // set time for heads up messages if (con_hudlines) - con_hudtime[con_cy%con_hudlines] = cons_msgtimeout.value*TICRATE; + con_hudtime[con_cy%con_hudlines] = cons_hudtime.value*TICRATE; con_cy++; con_cx = 0; From 6b5e3f650e033bff5961b8acb3837db688a3f0c7 Mon Sep 17 00:00:00 2001 From: Zwip-Zwap Zapony Date: Tue, 13 Jun 2023 14:02:19 +0200 Subject: [PATCH 19/23] Use 99999999 instead of 86400, make "MIN" 0 Nines might be more pleasing than an exact number for con_hudtime It'd be bad to make "MIN" in an old config suddenly start displaying lines for con_hudlines # Conflicts: # src/console.c --- src/console.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/console.c b/src/console.c index eb7a1ccd9..16fc3b8f9 100644 --- a/src/console.c +++ b/src/console.c @@ -124,12 +124,12 @@ static void CONS_backcolor_Change(void); static char con_buffer[CON_BUFFERSIZE]; // how many seconds the hud messages lasts on the screen -// CV_Unsigned can overflow when multiplied by TICRATE later, so let's use a 24-hour limit instead -static CV_PossibleValue_t hudtime_cons_t[] = {{0, "MIN"}, {86400, "MAX"}, {0, NULL}}; +// CV_Unsigned can overflow when multiplied by TICRATE later, so let's use a 3-year limit instead +static CV_PossibleValue_t hudtime_cons_t[] = {{0, "MIN"}, {99999999, "MAX"}, {0, NULL}}; static consvar_t cons_hudtime = CVAR_INIT ("con_hudtime", "5", CV_SAVE, hudtime_cons_t, NULL); // number of lines displayed on the HUD -static CV_PossibleValue_t hudlines_cons_t[] = {{0, "MIN"}, {MAXHUDLINES, "MAX"}, {0, "None"}, {0, NULL}}; +static CV_PossibleValue_t hudlines_cons_t[] = {{0, "MIN"}, {MAXHUDLINES, "MAX"}, {0, NULL}}; static consvar_t cons_hudlines = CVAR_INIT ("con_hudlines", "5", CV_CALL|CV_SAVE, hudlines_cons_t, CONS_hudlines_Change); // number of lines console move per frame From e3d0662c7d375e73a583d9e33a3ba324a4b194a1 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 19 Jul 2023 21:23:27 +0100 Subject: [PATCH 20/23] Remove even a mention of the slur that once sat here --- src/v_video.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/v_video.cpp b/src/v_video.cpp index c0efa5a9b..17519f894 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1083,7 +1083,6 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) .done(); } -// This is now a function, no use being such a weenie that you say a slur over it static UINT32 V_GetHWConsBackColor(void) { UINT32 hwcolor; From 55cda3dd5c40bbc85e25e7bf250930c89969d357 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 19 Jul 2023 22:29:02 +0100 Subject: [PATCH 21/23] Correctly flip minimap player icon dot in encore mode Resolves #582 --- src/k_hud.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index f60aff730..6c3a1d283 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -3994,8 +3994,6 @@ static void K_drawKartMinimap(void) if (doprogressionbar == false) { - angle_t ang = R_InterpolateAngle(mobj->old_angle, mobj->angle); - interpx = R_InterpolateFixed(mobj->old_x, mobj->x); interpy = R_InterpolateFixed(mobj->old_y, mobj->y); @@ -4010,6 +4008,10 @@ static void K_drawKartMinimap(void) if (!nocontest) { + angle_t ang = R_InterpolateAngle(mobj->old_angle, mobj->angle); + if (encoremode) + ang = ANGLE_180 - ang; + K_drawKartMinimapIcon( interpx, interpy, @@ -4198,8 +4200,6 @@ static void K_drawKartMinimap(void) if (doprogressionbar == false) { - angle_t ang = R_InterpolateAngle(mobj->old_angle, mobj->angle); - interpx = R_InterpolateFixed(mobj->old_x, mobj->x); interpy = R_InterpolateFixed(mobj->old_y, mobj->y); @@ -4214,6 +4214,10 @@ static void K_drawKartMinimap(void) if (!nocontest) { + angle_t ang = R_InterpolateAngle(mobj->old_angle, mobj->angle); + if (encoremode) + ang = ANGLE_180 - ang; + K_drawKartMinimapIcon( interpx, interpy, From dc4a25d823b1b4fd96b51ae8254e03cc7115f022 Mon Sep 17 00:00:00 2001 From: Lach Date: Thu, 20 Jul 2023 19:11:02 +1000 Subject: [PATCH 22/23] Add Dash Ring variables to net archive --- src/p_saveg.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/p_saveg.c b/src/p_saveg.c index 655e915ff..c3db1351f 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -185,7 +185,7 @@ static boolean P_UnArchivePlayer(savebuffer_t *save) savedata.bots[pid].score = READUINT32(save->p); } - return (pid == 0xFE); + return (pid == 0xFE); } static void P_NetArchivePlayers(savebuffer_t *save) @@ -500,6 +500,9 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].trickboostdecay); WRITEUINT8(save->p, players[i].trickboost); + WRITEUINT8(save->p, players[i].dashRingPullTics); + WRITEUINT8(save->p, players[i].dashRingPushTics); + WRITEUINT32(save->p, players[i].ebrakefor); WRITEUINT32(save->p, players[i].roundscore); @@ -918,6 +921,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].trickboostdecay = READUINT8(save->p); players[i].trickboost = READUINT8(save->p); + players[i].dashRingPullTics = READUINT8(save->p); + players[i].dashRingPushTics = READUINT8(save->p); + players[i].ebrakefor = READUINT32(save->p); players[i].roundscore = READUINT32(save->p); @@ -5665,7 +5671,7 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) } WRITEUINT8(save->p, encoremode); - + WRITEUINT8(save->p, mapmusrng); WRITEUINT32(save->p, leveltime); @@ -5836,7 +5842,7 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading) } encoremode = (boolean)READUINT8(save->p); - + mapmusrng = READUINT8(save->p); if (!P_LoadLevel(true, reloading)) From 255a10494a4caefe0efbcbebac9d4b2752dca7b0 Mon Sep 17 00:00:00 2001 From: Lach Date: Thu, 20 Jul 2023 19:15:20 +1000 Subject: [PATCH 23/23] Expose Dash Ring variables to Lua (and fix roundscore accessibility) --- src/lua_playerlib.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 282279a71..9e7253e97 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -409,8 +409,12 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->trickboostdecay); else if (fastcmp(field,"trickboost")) lua_pushinteger(L, plr->trickboost); + else if (fastcmp(field,"dashRingPullTics")) + lua_pushinteger(L, plr->dashRingPullTics); + else if (fastcmp(field,"dashRingPushTics")) + lua_pushinteger(L, plr->dashRingPushTics); else if (fastcmp(field,"roundscore")) - plr->roundscore = luaL_checkinteger(L, 3); + lua_pushinteger(L, plr->roundscore); else if (fastcmp(field,"emeralds")) lua_pushinteger(L, plr->emeralds); else if (fastcmp(field,"karmadelay")) @@ -730,7 +734,7 @@ static int player_set(lua_State *L) else if (fastcmp(field,"sliptideZipBoost")) plr->sliptideZipBoost = luaL_checkinteger(L, 3); else if (fastcmp(field,"instaShieldCooldown")) - plr->instaShieldCooldown = luaL_checkinteger(L, 3); + plr->instaShieldCooldown = luaL_checkinteger(L, 3); else if (fastcmp(field,"guardCooldown")) plr->guardCooldown = luaL_checkinteger(L, 3); /* @@ -813,8 +817,12 @@ static int player_set(lua_State *L) plr->trickboostdecay = luaL_checkinteger(L, 3); else if (fastcmp(field,"trickboost")) plr->trickboost = luaL_checkinteger(L, 3); + else if (fastcmp(field,"dashRingPullTics")) + plr->dashRingPullTics = luaL_checkinteger(L, 3); + else if (fastcmp(field,"dashRingPushTics")) + plr->dashRingPushTics = luaL_checkinteger(L, 3); else if (fastcmp(field,"roundscore")) - lua_pushinteger(L, plr->roundscore); + plr->roundscore = luaL_checkinteger(L, 3); else if (fastcmp(field,"emeralds")) plr->emeralds = luaL_checkinteger(L, 3); else if (fastcmp(field,"karmadelay"))