diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bf9fa2cfc..b47e248c9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -579,7 +579,7 @@ target_compile_definitions(SRB2SDL2 PRIVATE -DCMAKECONFIG) # Misc. build options from Makefiles if(SRB2_CONFIG_DEBUGMODE) - target_compile_definitions(SRB2SDL2 PRIVATE -DZDEBUG -DPARANOIA -DRANGECHECK -DPACKETDROP) + target_compile_definitions(SRB2SDL2 PRIVATE -DZDEBUG -DPARANOIA -DPACKETDROP) endif() if(SRB2_CONFIG_TESTERS) target_compile_definitions(SRB2SDL2 PRIVATE -DTESTERS) diff --git a/src/cvars.cpp b/src/cvars.cpp index 1aa0d9a0b..521fefb27 100644 --- a/src/cvars.cpp +++ b/src/cvars.cpp @@ -301,10 +301,7 @@ consvar_t cv_addons_search_case = Player("addons_search_case", "No").yes_no(); consvar_t cv_addons_search_type = Player("addons_search_type", "Anywhere").values({{0, "Start"}, {1, "Anywhere"}}); consvar_t cv_addons_showall = Player("addons_showall", "No").yes_no(); consvar_t cv_allowguests = Player("allowguests", "On").on_off(); - -void AltTitle_OnChange(void); -consvar_t cv_alttitle = Player("alttitle", "Off").flags(CV_NOSHOWHELP).on_off().onchange_noinit(AltTitle_OnChange); - +consvar_t cv_alttitle = Player("alttitle", "Off").on_off(); consvar_t cv_alwaysgrabmouse = GraphicsDriver("alwaysgrabmouse", "Off").on_off(); consvar_t cv_apng_delay = Player("apng_speed", "1x").values({ diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 9b0c1ff52..dbc95e065 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5920,9 +5920,9 @@ static void Local_Maketic(INT32 realtics) INT32 i; I_OsPolling(); // I_Getevent - D_ProcessEvents(); // menu responder, cons responder, - // game responder calls HU_Responder, AM_Responder, - // and G_MapEventsToControls + D_ProcessEvents(true); // menu responder, cons responder, + // game responder calls HU_Responder, AM_Responder, + // and G_MapEventsToControls if (!dedicated) rendergametic = gametic; diff --git a/src/d_main.cpp b/src/d_main.cpp index 19fd9c1db..1ece00a2b 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -264,7 +264,7 @@ void HandleGamepadDeviceEvents(event_t *ev) // D_ProcessEvents // Send all the events of the given timestamp down the responder chain // -void D_ProcessEvents(void) +void D_ProcessEvents(boolean callresponders) { event_t *ev; int i; @@ -298,6 +298,9 @@ void D_ProcessEvents(void) // update keys current state G_MapEventsToControls(ev); + if (!callresponders) + continue; // eat + // Menu input #ifdef HAVE_THREADS I_lock_mutex(&k_menu_mutex); diff --git a/src/d_main.h b/src/d_main.h index fdaa1bc1c..a47eec7a3 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -50,7 +50,7 @@ void D_PostEvent(const event_t *ev); void D_PostEvent_end(void); // delimiter for locking memory #endif -void D_ProcessEvents(void); +void D_ProcessEvents(boolean callresponders); const char *D_Home(void); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index fdda510dd..6d640d885 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -5195,19 +5195,6 @@ FUNCNORETURN static ATTRNORETURN void Command_Quit_f(void) I_Quit(); } -void AltTitle_OnChange(void) -{ - if (!cv_alttitle.value) - return; // it's fine. - - if (!M_SecretUnlocked(SECRET_ALTTITLE, true)) - { - CONS_Printf(M_GetText("You haven't earned this yet.\n")); - CV_StealthSetValue(&cv_alttitle, 0); - return; - } -} - void ItemFinder_OnChange(void) { if (!cv_itemfinder.value) diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 6316cb8b3..f97cd9bd8 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -110,7 +110,7 @@ typedef enum { } capsuletest_val_t; extern consvar_t cv_capsuletest; -extern consvar_t cv_alttitle, cv_itemfinder; +extern consvar_t cv_itemfinder; extern consvar_t cv_inttime, cv_advancemap; extern consvar_t cv_overtime; @@ -255,7 +255,6 @@ boolean IsPlayerAdmin(INT32 playernum); void SetAdminPlayer(INT32 playernum); void ClearAdminPlayers(void); void RemoveAdminPlayer(INT32 playernum); -void AltTitle_OnChange(void); void ItemFinder_OnChange(void); void D_SetPassword(const char *pw); diff --git a/src/doomdef.h b/src/doomdef.h index 14c879506..bdaeb556a 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -67,12 +67,10 @@ extern "C" { #if !defined (NDEBUG) #define PACKETDROP #define PARANOIA -//#define RANGECHECK #define ZDEBUG #endif // Uncheck this to compile debugging code -#define RANGECHECK //#ifndef PARANOIA //#define PARANOIA // do some tests that never fail but maybe // turn this on by make etc.. DEBUGMODE = 1 or use the Debug profile in the VC++ projects diff --git a/src/f_finale.c b/src/f_finale.c index 4ddd2db2b..5de1d45dc 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1145,13 +1145,8 @@ static void F_CacheTitleScreen(void) case TTMODE_RINGRACERS: { - if (!M_SecretUnlocked(SECRET_ALTTITLE, true)) - { - CV_StealthSetValue(&cv_alttitle, 0); - } - kts_bumper = W_CachePatchName( - (cv_alttitle.value ? "KTSJUMPR1" : "KTSBUMPR1"), + (M_UseAlternateTitleScreen() ? "KTSJUMPR1" : "KTSBUMPR1"), PU_PATCH_LOWPRIORITY); kts_eggman = W_CachePatchName("KTSEGG01", PU_PATCH_LOWPRIORITY); kts_tails = W_CachePatchName("KTSTAL01", PU_PATCH_LOWPRIORITY); diff --git a/src/f_wipe.cpp b/src/f_wipe.cpp index 664c2d11a..6c848cda1 100644 --- a/src/f_wipe.cpp +++ b/src/f_wipe.cpp @@ -494,11 +494,6 @@ void F_RunWipe(UINT8 wipemode, UINT8 wipetype, boolean drawMenu, const char *col WipeInAction = true; wipe_scr = screens[0]; - // FIXME: Wipes SUCK and drop input events for some reason, causing stuck gamepad inputs. - // It's better to ignore an intentional hold than to turn a tap into a phantom hold. - // (If you're removing this, remove the one after the inner loop too!) - G_ResetAllDeviceGameKeyDown(); - // lastwipetic should either be 0 or the tic we last wiped // on for fade-to-black for (;;) @@ -558,6 +553,12 @@ void F_RunWipe(UINT8 wipemode, UINT8 wipetype, boolean drawMenu, const char *col } I_OsPolling(); + // The event buffer is rather small so we need to + // process these events immediately, to make sure + // inputs don't get stuck (would happen a lot with + // some controllers that send a lot of analog + // events). + D_ProcessEvents(false); I_UpdateNoBlit(); if (drawMenu && rendermode != render_none) @@ -586,11 +587,6 @@ void F_RunWipe(UINT8 wipemode, UINT8 wipetype, boolean drawMenu, const char *col WipeInAction = false; - // FIXME: Wipes SUCK and drop input events for some reason, causing stuck gamepad inputs. - // It's better to ignore an intentional hold than to turn a tap into a phantom hold. - // (If you're removing this, remove the one before the inner loop too!) - G_ResetAllDeviceGameKeyDown(); - if (fcolor) { Z_Free(fcolor); diff --git a/src/g_demo.cpp b/src/g_demo.cpp index e727eacba..fbeb4d98d 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -3588,6 +3588,14 @@ void G_AddGhost(savebuffer_t *buffer, const char *defdemoname) if ((flags & DF_GRANDPRIX)) p += 3; + // Skip unlockables + { + UINT32 unlockables = READUINT32(p); + p += std::min(unlockables, MAXUNLOCKABLES); + } + + p++; // mapmusrng + if (*p == DEMOMARKER) { CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Replay is empty.\n"), defdemoname); @@ -3803,6 +3811,14 @@ staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer) if ((flags & DF_GRANDPRIX)) p += 3; + // Skip unlockables + { + UINT32 unlockables = READUINT32(p); + p += std::min(unlockables, MAXUNLOCKABLES); + } + + p++; // mapmusrng + // Assert first player is in and then read name if (READUINT8(p) != 0) goto fail; diff --git a/src/g_game.c b/src/g_game.c index 3ca13d642..69699b24f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1191,8 +1191,10 @@ void G_DoLoadLevelEx(boolean resetplayer, gamestate_t newstate) } // clear cmd building stuff - G_ResetAllDeviceGameKeyDown(); - G_ResetAllDeviceResponding(); + // We don't clear them anymore, so you can buffer inputs + // on map change / map restart. + //G_ResetAllDeviceGameKeyDown(); + //G_ResetAllDeviceResponding(); // clear hud messages remains (usually from game startup) CON_ClearHUD(); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 2beed6727..f81a4e2f4 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4740,10 +4740,11 @@ static void HWR_ProjectSprite(mobj_t *thing) tr_y = FIXED_TO_FLOAT(interp.y); // decide which patch to use for sprite relative to player -#ifdef RANGECHECK if ((unsigned)thing->sprite >= numsprites) - I_Error("HWR_ProjectSprite: invalid sprite number %i ", thing->sprite); -#endif + { + CONS_Debug(DBG_RENDER, "HWR_ProjectSprite: invalid sprite number %i\n", thing->sprite); + return; + } rot = thing->frame&FF_FRAMEMASK; @@ -5184,22 +5185,20 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) // decide which patch to use for sprite relative to player if ((unsigned)thing->sprite >= numsprites) -#ifdef RANGECHECK - I_Error("HWR_ProjectPrecipitationSprite: invalid sprite number %i ", + { + CONS_Debug(DBG_RENDER, "HWR_ProjectPrecipitationSprite: invalid sprite number %i\n", thing->sprite); -#else return; -#endif + } sprdef = &sprites[thing->sprite]; if ((size_t)(thing->frame&FF_FRAMEMASK) >= sprdef->numframes) -#ifdef RANGECHECK - I_Error("HWR_ProjectPrecipitationSprite: invalid sprite frame %i : %i for %s", + { + CONS_Debug(DBG_RENDER, "HWR_ProjectPrecipitationSprite: invalid sprite frame %i : %i for %s\n", thing->sprite, thing->frame, sprnames[thing->sprite]); -#else return; -#endif + } sprframe = &sprdef->spriteframes[ thing->frame & FF_FRAMEMASK]; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 7a4157def..61d925aba 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -319,6 +319,15 @@ void HU_Init(void) PR ("PRFN"); REG; + DIM ('0', 10); + DIG (2); + + PR ("ROLNUM"); + REG; + + PR ("RO4NUM"); + REG; + DIG (3); ADIM (KART); diff --git a/src/hu_stuff.h b/src/hu_stuff.h index 94130c7fb..487b06e1a 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -80,6 +80,8 @@ enum X (NIGHTSNUM), X (PINGNUM), X (PROFNUM), + X (ROLNUM), + X (RO4NUM), X (KART), X (TIMER), diff --git a/src/k_credits.cpp b/src/k_credits.cpp index 76037fd3b..266e163ea 100644 --- a/src/k_credits.cpp +++ b/src/k_credits.cpp @@ -1023,7 +1023,7 @@ static void F_DrawCreditsTitleDrop(void) 0, -BASEVIDHEIGHT * (FRACUNIT / 2), FRACUNIT, 0, static_cast(W_CachePatchName( - (cv_alttitle.value ? "KTSJUMPR1" : "KTSBUMPR1"), + (M_UseAlternateTitleScreen() ? "KTSJUMPR1" : "KTSBUMPR1"), PU_CACHE )), nullptr diff --git a/src/k_hud.cpp b/src/k_hud.cpp index e7b2f2c6b..87d1095ec 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -1371,6 +1371,7 @@ static void K_drawKartItem(void) // Set to 'no item' just in case. const UINT8 offset = ((r_splitscreen > 1) ? 1 : 0); patch_t *localpatch[3] = { kp_nodraw, kp_nodraw, kp_nodraw }; + UINT8 localamt[3] = {0, 0, 0}; patch_t *localbg = ((offset) ? kp_itembg[2] : kp_itembg[0]); patch_t *localinv = ((offset) ? kp_invincibility[((leveltime % (6*3)) / 3) + 7] : kp_invincibility[(leveltime % (7*3)) / 3]); INT32 fx = 0, fy = 0, fflags = 0; // final coords for hud and flags... @@ -1403,14 +1404,19 @@ static void K_drawKartItem(void) { case KITEM_INVINCIBILITY: localpatch[i] = localinv; + localamt[i] = amt; break; case KITEM_ORBINAUT: localpatch[i] = kp_orbinaut[(offset ? 4 : std::min(amt-1, 3))]; + if (amt > 4) + localamt[i] = amt; break; default: localpatch[i] = K_GetCachedItemPatch(item, offset); + if (item != KITEM_BALLHOG || amt != 5) + localamt[i] = amt; break; } } @@ -1586,25 +1592,35 @@ static void K_drawKartItem(void) V_SLIDEIN|fflags ); - V_DrawFixedPatch( - fx< 1) + { + using srb2::Draw; + Draw( + fx + rouletteCrop.x + FixedToFloat(rouletteSpace/2), + fy + rouletteCrop.y + FixedToFloat(rouletteOffset + y + rouletteSpace) - (r_splitscreen > 1 ? 15 : 33)) + .font(r_splitscreen > 1 ? Draw::Font::kRollingNum4P : Draw::Font::kRollingNum) + .align(Draw::Align::kCenter) + .flags(V_HUDTRANS|V_SLIDEIN|fflags) + .colormap(colormap) + .text("{}", localamt[i]); + } + }; + + draw_item(rouletteSpace, 0); + draw_item(-rouletteSpace, 2); if (stplyr->itemRoulette.active == true) { // Draw the item underneath the box. - V_DrawFixedPatch( - fx<realtime, - TIME_X, - TIME_Y, - V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP|V_SNAPTORIGHT, - 0); + { + bool ta = modeattacking && !demo.playback; + INT32 flags = V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP|V_SNAPTORIGHT; + K_drawKartTimestamp(stplyr->realtime, TIME_X, TIME_Y + (ta ? 2 : 0), flags, 0); + if (ta) + { + using srb2::Draw; + Draw(BASEVIDWIDTH - 19, 2) + .flags(flags | V_YELLOWMAP) + .align(Draw::Align::kRight) + .text("\xBE Restart"); + } + } islonesome = K_drawKartPositionFaces(); } @@ -5998,7 +6027,7 @@ void K_drawKartHUD(void) if (demo.attract == DEMO_ATTRACT_TITLE) // Draw logo on title screen demos { INT32 x = BASEVIDWIDTH - 8, y = BASEVIDHEIGHT-8, snapflags = V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_SLIDEIN; - patch_t *pat = static_cast(W_CachePatchName((cv_alttitle.value ? "MTSJUMPR1" : "MTSBUMPR1"), PU_CACHE)); + patch_t *pat = static_cast(W_CachePatchName((M_UseAlternateTitleScreen() ? "MTSJUMPR1" : "MTSBUMPR1"), PU_CACHE)); if (r_splitscreen == 3) { diff --git a/src/k_hud_track.cpp b/src/k_hud_track.cpp index 1ab870ea3..2f9c190e2 100644 --- a/src/k_hud_track.cpp +++ b/src/k_hud_track.cpp @@ -232,6 +232,8 @@ private: case MT_BATTLEUFO_SPAWNER: case MT_WAYPOINT: + case MT_BUBBLESHIELDTRAP: + case MT_GARDENTOP: return {}; default: @@ -341,11 +343,36 @@ bool is_object_tracking_target(const mobj_t* mobj) case MT_WAYPOINT: return cv_kartdebugwaypoints.value; + case MT_BUBBLESHIELDTRAP: + return mobj->tracer && !P_MobjWasRemoved(mobj->tracer) + && mobj->tracer->player && P_IsDisplayPlayer(mobj->tracer->player) + && mobj->tracer->player == &players[displayplayers[R_GetViewNumber()]]; + + case MT_GARDENTOP: + return mobj->tracer && !P_MobjWasRemoved(mobj->tracer) + && mobj->tracer->player && P_IsDisplayPlayer(mobj->tracer->player) + && mobj->tracer->player == &players[displayplayers[R_GetViewNumber()]] + && Obj_GardenTopPlayerNeedsHelp(mobj); + default: return false; } } +bool can_object_be_offscreen(const mobj_t* mobj) +{ + switch (mobj->type) + { + // You can see this, you fucking liar + case MT_GARDENTOP: + case MT_BUBBLESHIELDTRAP: + return false; + + default: + return true; + } +} + Visibility is_object_visible(const mobj_t* mobj) { switch (mobj->type) @@ -381,7 +408,7 @@ void K_DrawTargetTracking(const TargetTracking& target) const trackingResult_t& result = target.result; int32_t timer = 0; - if (result.onScreen == false) + if (can_object_be_offscreen(target.mobj) && result.onScreen == false) { // Off-screen, draw alongside the borders of the screen. // Probably the most complicated thing. @@ -578,7 +605,9 @@ void K_DrawTargetTracking(const TargetTracking& target) .align(Draw::Align::kCenter); }; - switch (target.mobj->type) // debug + srb2::Draw::Font splitfont = (r_splitscreen > 1) ? Draw::Font::kThin : Draw::Font::kMenu; + + switch (target.mobj->type) { case MT_BATTLEUFO_SPAWNER: debug().text("BUFO ID: {}", Obj_BattleUFOSpawnerID(target.mobj)); @@ -592,6 +621,21 @@ void K_DrawTargetTracking(const TargetTracking& target) } break; + case MT_BUBBLESHIELDTRAP: + Draw(FixedToFloat(result.x), FixedToFloat(result.y)) + .flags(V_SPLITSCREEN) + .font(Draw::Font::kMenu) + .align(Draw::Align::kCenter) + .text(((leveltime/3)%2) ? "\xB3 " : " \xB2"); + break; + + case MT_GARDENTOP: + Draw(FixedToFloat(result.x), FixedToFloat(result.y)) + .flags(V_SPLITSCREEN) + .font(splitfont) + .align(Draw::Align::kCenter) + .text("Try \xA7!"); + default: break; } diff --git a/src/k_menudraw.c b/src/k_menudraw.c index b0a125478..ea8a4b665 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -7014,7 +7014,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) { x = 8; y = BASEVIDHEIGHT-16; - V_DrawGamemodeString(x, y - 33, 0, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_MENUCACHE), cv_alttitle.string); + V_DrawGamemodeString(x, y - 33, 0, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_MENUCACHE), M_UseAlternateTitleScreen() ? "On" : "Off"); K_drawButtonAnim(x, y, 0, kp_button_a[1], challengesmenu.ticker); x += SHORT(kp_button_a[1][0]->width); @@ -8202,7 +8202,7 @@ void M_DrawWrongWarp(void) titleoffset += titlewidth; } - patch_t *bumper = W_CachePatchName((cv_alttitle.value ? "MTSJUMPR1" : "MTSBUMPR1"), PU_CACHE); + patch_t *bumper = W_CachePatchName((M_UseAlternateTitleScreen() ? "MTSJUMPR1" : "MTSBUMPR1"), PU_CACHE); V_DrawScaledPatch(x-(SHORT(bumper->width)), (BASEVIDHEIGHT-8)-(SHORT(bumper->height)), 0, bumper); } diff --git a/src/k_objects.h b/src/k_objects.h index fa708ae5c..93e6692d0 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -27,6 +27,7 @@ void Obj_GardenTopThink(mobj_t *top); void Obj_GardenTopSparkThink(mobj_t *spark); void Obj_GardenTopArrowThink(mobj_t *arrow); boolean Obj_GardenTopPlayerIsGrinding(const player_t *player); +boolean Obj_GardenTopPlayerNeedsHelp(const mobj_t *top); /* Shrink */ void Obj_PohbeeThinker(mobj_t *pohbee); diff --git a/src/m_cond.c b/src/m_cond.c index 4e35471ed..af30e415b 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -3758,3 +3758,9 @@ const char *M_GetEmblemPatch(emblem_t *em, boolean big) return pnamebuf; } + +boolean M_UseAlternateTitleScreen(void) +{ + extern consvar_t cv_alttitle; + return cv_alttitle.value && M_SecretUnlocked(SECRET_ALTTITLE, true); +} diff --git a/src/m_cond.h b/src/m_cond.h index 210a09767..3a549578f 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -494,6 +494,8 @@ UINT16 M_EmblemMapNum(emblem_t *emblem); #define M_Achieved(a) ((a) >= MAXCONDITIONSETS || gamedata->achieved[a]) +boolean M_UseAlternateTitleScreen(void); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/menus/extras-challenges.c b/src/menus/extras-challenges.c index e1df3066b..ff169772e 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -1027,11 +1027,13 @@ boolean M_ChallengesInputs(INT32 ch) { switch (unlockables[challengesmenu.currentunlock].type) { - case SECRET_ALTTITLE: + case SECRET_ALTTITLE: { + extern consvar_t cv_alttitle; CV_AddValue(&cv_alttitle, 1); S_StartSound(NULL, sfx_s3kc3s); M_SetMenuDelay(pid); break; + } default: break; } diff --git a/src/menus/options-server-1.c b/src/menus/options-server-1.c index bbd9a20e3..1a83b6af1 100644 --- a/src/menus/options-server-1.c +++ b/src/menus/options-server-1.c @@ -19,6 +19,22 @@ menuitem_t OPTIONS_Server[] = NULL, {.cvar = &cv_advertise}, 0, 0}, + {IT_HEADER, "Players...", NULL, + NULL, {NULL}, 0, 0}, + + {IT_STRING | IT_CVAR, "Maximum Players", "How many players can play at once.", + NULL, {.cvar = &cv_maxplayers}, 0, 0}, + + {IT_STRING | IT_CVAR, "Maximum Connections", "How many players & spectators can connect to the server.", + NULL, {.cvar = &cv_maxconnections}, 0, 0}, + + {IT_STRING | IT_CVAR, "CPU Difficulty", "Bots can fill unused slots. How strong should they be?", + NULL, {.cvar = &cv_kartbot}, 0, 0}, + + {IT_STRING | IT_CVAR, "Use PWR.LV", "Set whether players should be rated on their performance.", + NULL, {.cvar = &cv_kartusepwrlv}, 0, 0}, + + {IT_HEADER, "Progression...", NULL, NULL, {NULL}, 0, 0}, @@ -32,15 +48,9 @@ menuitem_t OPTIONS_Server[] = NULL, {.cvar = &cv_votetime}, 0, 0}, - {IT_HEADER, "Joining...", NULL, + {IT_HEADER, "Permissions...", NULL, NULL, {NULL}, 0, 0}, - {IT_STRING | IT_CVAR, "Maximum Players", "How many players can play at once.", - NULL, {.cvar = &cv_maxplayers}, 0, 0}, - - {IT_STRING | IT_CVAR, "Maximum Connections", "How many players & spectators can connect to the server.", - NULL, {.cvar = &cv_maxconnections}, 0, 0}, - {IT_STRING | IT_CVAR, "Allow Joining", "Sets whether players can connect to your server.", NULL, {.cvar = &cv_allownewplayer}, 0, 0}, @@ -60,8 +70,7 @@ menuitem_t OPTIONS_Server[] = {IT_STRING | IT_CVAR, "Chat Spam Protection", "Prevents too many message from a single player.", NULL, {.cvar = &cv_chatspamprotection}, 0, 0}, - - {IT_SPACE | IT_DYBIGSPACE, NULL, NULL, + {IT_HEADER, "Advanced...", NULL, NULL, {NULL}, 0, 0}, {IT_STRING | IT_SUBMENU, "Advanced...", "Advanced options. Be careful when messing with these!", diff --git a/src/menus/transient/level-select.c b/src/menus/transient/level-select.c index 46fb70342..9c8ab635b 100644 --- a/src/menus/transient/level-select.c +++ b/src/menus/transient/level-select.c @@ -747,7 +747,9 @@ void M_LevelSelected(INT16 add, boolean menuupdate) SV_StartSinglePlayerServer(levellist.newgametype, levellist.netgame); - CV_StealthSet(&cv_kartbot, cv_dummymatchbots.string); + if (!levellist.netgame) + CV_StealthSet(&cv_kartbot, cv_dummymatchbots.string); + CV_StealthSet(&cv_kartencore, (cv_dummygpencore.value == 1) ? "On" : "Auto"); CV_StealthSet(&cv_kartspeed, (cv_dummykartspeed.value == KARTSPEED_NORMAL) ? "Auto" : cv_dummykartspeed.string); diff --git a/src/objects/gardentop.c b/src/objects/gardentop.c index 143dca17f..c3b6b5e77 100644 --- a/src/objects/gardentop.c +++ b/src/objects/gardentop.c @@ -47,6 +47,8 @@ enum { #define top_waveangle(o) ((o)->movedir) /* wavepause will take mobjinfo reactiontime automatically */ #define top_wavepause(o) ((o)->reactiontime) +#define top_helpme(o) ((o)->cusval) +#define top_lifetime(o) ((o)->cvmem) #define spark_top(o) ((o)->target) #define spark_angle(o) ((o)->movedir) @@ -133,6 +135,8 @@ init_top top_float(top) = 0; top_sound(top) = sfx_None; top_waveangle(top) = 0; + top_helpme(top) = (mode == TOP_ANCHORED) ? 1 : 0; + top_lifetime(top) = 0; } static void @@ -191,6 +195,8 @@ spawn_grind_spark (mobj_t *top) player = get_rider_player(rider); } + top_helpme(top) = 0; + spark = P_SpawnMobjFromMobj( top, x, y, 0, MT_DRIFTSPARK); @@ -432,6 +438,8 @@ anchor_top (mobj_t *top) top->momy = 0; top->momz = rider->momz; + top_lifetime(top)++; + /* 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. */ @@ -687,3 +695,11 @@ Obj_GardenTopPlayerIsGrinding (const player_t *player) return top ? is_top_grinding(top) : false; } + +boolean +Obj_GardenTopPlayerNeedsHelp (const mobj_t *top) +{ + if (top && top_mode(top) != TOP_ANCHORED) + return false; + return top ? (top_helpme(top) || top_lifetime(top) < 3*TICRATE) : false; +} diff --git a/src/p_inter.c b/src/p_inter.c index 1889946e8..86a2a2094 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -634,6 +634,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_SetTarget(&special->tracer, toucher); toucher->flags |= MF_NOGRAVITY; toucher->momz = (8*toucher->scale) * P_MobjFlip(toucher); + + // Snap to the unfortunate player and quit moving laterally, or we can end up quite far away + special->momx = 0; + special->momy = 0; + special->x = toucher->x; + special->y = toucher->y; + special->z = toucher->z; + S_StartSound(toucher, sfx_s1b2); return; @@ -3114,8 +3122,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da source->player->invincibilityextensions++; source->player->invincibilitytimer += kinvextend; - // This has a scaling boost type now, don't let it get too crazy - source->player->invincibilitytimer = min(source->player->invincibilitytimer, 20*TICRATE); if (P_IsDisplayPlayer(source->player)) S_StartSound(NULL, sfx_gsha7); diff --git a/src/p_mobj.c b/src/p_mobj.c index a686fa609..7a3083a8d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5359,6 +5359,12 @@ static boolean P_IsTrackerType(INT32 type) case MT_WAYPOINT: // debug return true; + case MT_BUBBLESHIELDTRAP: // Mash prompt + return true; + + case MT_GARDENTOP: // Frey + return true; + default: return false; } diff --git a/src/p_polyobj.c b/src/p_polyobj.c index 021b8520e..62566c44d 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -1427,15 +1427,11 @@ void T_PolyObjRotate(polyrotate_t *th) polyobj_t *po = Polyobj_GetForNum(th->polyObjNum); if (!po) -#ifdef RANGECHECK - I_Error("T_PolyObjRotate: thinker has invalid id %d\n", th->polyObjNum); -#else { CONS_Debug(DBG_POLYOBJ, "T_PolyObjRotate: thinker with invalid id %d removed.\n", th->polyObjNum); P_RemoveThinker(&th->thinker); return; } -#endif // check for displacement due to override and reattach when possible if (po->thinker == NULL) @@ -1508,15 +1504,11 @@ void T_PolyObjMove(polymove_t *th) polyobj_t *po = Polyobj_GetForNum(th->polyObjNum); if (!po) -#ifdef RANGECHECK - I_Error("T_PolyObjMove: thinker has invalid id %d\n", th->polyObjNum); -#else { CONS_Debug(DBG_POLYOBJ, "T_PolyObjMove: thinker with invalid id %d removed.\n", th->polyObjNum); P_RemoveThinker(&th->thinker); return; } -#endif // check for displacement due to override and reattach when possible if (po->thinker == NULL) @@ -1598,15 +1590,11 @@ void T_PolyObjWaypoint(polywaypoint_t *th) fixed_t speed = th->speed; if (!po) -#ifdef RANGECHECK - I_Error("T_PolyObjWaypoint: thinker has invalid id %d\n", th->polyObjNum); -#else { CONS_Debug(DBG_POLYOBJ, "T_PolyObjWaypoint: thinker with invalid id %d removed.", th->polyObjNum); P_RemoveThinker(&th->thinker); return; } -#endif // check for displacement due to override and reattach when possible if (!po->thinker) @@ -1714,15 +1702,11 @@ void T_PolyDoorSlide(polyslidedoor_t *th) polyobj_t *po = Polyobj_GetForNum(th->polyObjNum); if (!po) -#ifdef RANGECHECK - I_Error("T_PolyDoorSlide: thinker has invalid id %d\n", th->polyObjNum); -#else { CONS_Debug(DBG_POLYOBJ, "T_PolyDoorSlide: thinker with invalid id %d removed.\n", th->polyObjNum); P_RemoveThinker(&th->thinker); return; } -#endif // check for displacement due to override and reattach when possible if (po->thinker == NULL) @@ -1819,15 +1803,11 @@ void T_PolyDoorSwing(polyswingdoor_t *th) polyobj_t *po = Polyobj_GetForNum(th->polyObjNum); if (!po) -#ifdef RANGECHECK - I_Error("T_PolyDoorSwing: thinker has invalid id %d\n", th->polyObjNum); -#else { CONS_Debug(DBG_POLYOBJ, "T_PolyDoorSwing: thinker with invalid id %d removed.\n", th->polyObjNum); P_RemoveThinker(&th->thinker); return; } -#endif // check for displacement due to override and reattach when possible if (po->thinker == NULL) @@ -1918,15 +1898,11 @@ void T_PolyObjDisplace(polydisplace_t *th) fixed_t dx, dy; if (!po) -#ifdef RANGECHECK - I_Error("T_PolyObjDisplace: thinker has invalid id %d\n", th->polyObjNum); -#else { CONS_Debug(DBG_POLYOBJ, "T_PolyObjDisplace: thinker with invalid id %d removed.\n", th->polyObjNum); P_RemoveThinker(&th->thinker); return; } -#endif // check for displacement due to override and reattach when possible if (po->thinker == NULL) @@ -1958,15 +1934,11 @@ void T_PolyObjRotDisplace(polyrotdisplace_t *th) fixed_t rotangle; if (!po) -#ifdef RANGECHECK - I_Error("T_PolyObjRotDisplace: thinker has invalid id %d\n", th->polyObjNum); -#else { CONS_Debug(DBG_POLYOBJ, "T_PolyObjRotDisplace: thinker with invalid id %d removed.\n", th->polyObjNum); P_RemoveThinker(&th->thinker); return; } -#endif // check for displacement due to override and reattach when possible if (po->thinker == NULL) @@ -2442,15 +2414,11 @@ void T_PolyObjFlag(polymove_t *th) size_t i; if (!po) -#ifdef RANGECHECK - I_Error("T_PolyObjFlag: thinker has invalid id %d\n", th->polyObjNum); -#else { CONS_Debug(DBG_POLYOBJ, "T_PolyObjFlag: thinker with invalid id %d removed.\n", th->polyObjNum); P_RemoveThinker(&th->thinker); return; } -#endif // check for displacement due to override and reattach when possible if (po->thinker == NULL) @@ -2549,15 +2517,11 @@ void T_PolyObjFade(polyfade_t *th) polyobj_t *po = Polyobj_GetForNum(th->polyObjNum); if (!po) -#ifdef RANGECHECK - I_Error("T_PolyObjFade: thinker has invalid id %d\n", th->polyObjNum); -#else { CONS_Debug(DBG_POLYOBJ, "T_PolyObjFade: thinker with invalid id %d removed.\n", th->polyObjNum); P_RemoveThinker(&th->thinker); return; } -#endif // check for displacement due to override and reattach when possible if (po->thinker == NULL) diff --git a/src/p_sight.c b/src/p_sight.c index e23fe13a5..c145ffbfd 100644 --- a/src/p_sight.c +++ b/src/p_sight.c @@ -469,10 +469,11 @@ static boolean P_CrossSubsector(size_t num, register los_t *los, register los_fu seg_t *seg; INT32 count; -#ifdef RANGECHECK if (num >= numsubsectors) - I_Error("P_CrossSubsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors)); -#endif + { + CONS_Debug(DBG_RENDER, "P_CrossSubsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors)); + return true; + } // haleyjd 02/23/06: this assignment should be after the above check seg = segs + subsectors[num].firstline; diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index 736037dac..6d5f93214 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -909,14 +909,12 @@ static void R_Subsector(size_t num) ZoneScoped; -#ifdef RANGECHECK - if (num >= numsubsectors) - I_Error("R_Subsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors)); -#endif - // subsectors added at run-time if (num >= numsubsectors) + { + CONS_Debug(DBG_RENDER, "R_Subsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors)); return; + } sub = &subsectors[num]; frontsector = sub->sector; diff --git a/src/r_draw_column.cpp b/src/r_draw_column.cpp index d9c1cf244..32656bf37 100644 --- a/src/r_draw_column.cpp +++ b/src/r_draw_column.cpp @@ -105,12 +105,10 @@ static void R_DrawColumnTemplate(drawcolumndata_t *dc) return; } -#ifdef RANGECHECK if ((unsigned)dc->x >= (unsigned)vid.width || dc->yl < 0 || dc->yh >= vid.height) { return; } -#endif if constexpr (Type & DrawColumnType::DC_LIGHTLIST) { @@ -341,10 +339,8 @@ void R_DrawFogColumn(drawcolumndata_t *dc) if (count < 0) return; -#ifdef RANGECHECK if ((unsigned)dc->x >= (unsigned)vid.width || dc->yl < 0 || dc->yh >= vid.height) return; -#endif // Framebuffer destination address. // Use ylookup LUT to avoid multiply with ScreenWidth. @@ -408,10 +404,8 @@ void R_DrawColumn_Flat(drawcolumndata_t *dc) if (count < 0) // Zero length, column does not exceed a pixel. return; -#ifdef RANGECHECK if ((unsigned)dc->x >= (unsigned)vid.width || dc->yl < 0 || dc->yh >= vid.height) return; -#endif // Framebuffer destination address. // Use ylookup LUT to avoid multiply with ScreenWidth. diff --git a/src/r_things.cpp b/src/r_things.cpp index 2e948db57..52cb52521 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -1073,9 +1073,7 @@ static void R_DrawVisSprite(vissprite_t *vis) } else if (vis->cut & SC_SHEAR) { -#ifdef RANGECHECK pwidth = patch->width; -#endif // Vertically sheared sprite for (dc.x = vis->x1; dc.x <= vis->x2; dc.x++, frac += vis->xiscale, dc.texturemid -= vis->shear.tan) @@ -1093,7 +1091,7 @@ static void R_DrawVisSprite(vissprite_t *vis) else { -#ifdef RANGECHECK +#if 0 if (vis->x1test && vis->x2test) { INT32 x1test = vis->x1test; @@ -1112,7 +1110,7 @@ static void R_DrawVisSprite(vissprite_t *vis) CONS_Printf("THE GAME WOULD HAVE CRASHED, %d (old) vs %d (new)\n", (x2test - x1test), (vis->x2 - vis->x1)); } } -#endif // RANGECHECK +#endif // Non-paper drawing loop for (dc.x = vis->x1; dc.x <= vis->x2; dc.x++, frac += vis->xiscale, sprtopscreen += vis->shear.tan) @@ -1191,10 +1189,11 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) { texturecolumn = frac>>FRACBITS; -#ifdef RANGECHECK if (texturecolumn < 0 || texturecolumn >= patch->width) - I_Error("R_DrawPrecipitationSpriteRange: bad texturecolumn"); -#endif + { + CONS_Debug(DBG_RENDER, "R_DrawPrecipitationSpriteRange: bad texturecolumn\n"); + break; + } column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn])); @@ -1832,10 +1831,11 @@ static void R_ProjectSprite(mobj_t *thing) sortscale = FixedDiv(projectiony[viewssnum], tz); // decide which patch to use for sprite relative to player -#ifdef RANGECHECK if ((size_t)(thing->sprite) >= numsprites) - I_Error("R_ProjectSprite: invalid sprite number %d ", thing->sprite); -#endif + { + CONS_Debug(DBG_RENDER, "R_ProjectSprite: invalid sprite number %d\n", thing->sprite); + return; + } frame = thing->frame&FF_FRAMEMASK; @@ -2634,19 +2634,21 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) yscale = FixedDiv(projectiony[viewssnum], tz); // decide which patch to use for sprite relative to player -#ifdef RANGECHECK if ((unsigned)thing->sprite >= numsprites) - I_Error("R_ProjectPrecipitationSprite: invalid sprite number %d ", + { + CONS_Debug(DBG_RENDER, "R_ProjectPrecipitationSprite: invalid sprite number %d\n", thing->sprite); -#endif + return; + } sprdef = &sprites[thing->sprite]; -#ifdef RANGECHECK if ((UINT8)(thing->frame&FF_FRAMEMASK) >= sprdef->numframes) - I_Error("R_ProjectPrecipitationSprite: invalid sprite frame %d : %d for %s", + { + CONS_Debug(DBG_RENDER, "R_ProjectPrecipitationSprite: invalid sprite frame %d : %d for %s\n", thing->sprite, thing->frame, sprnames[thing->sprite]); -#endif + return; + } sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK]; diff --git a/src/v_draw.cpp b/src/v_draw.cpp index e611b41a4..a668f98d0 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -308,6 +308,12 @@ int Draw::font_to_fontno(Font font) case Font::kMedium: return MED_FONT; + + case Font::kRollingNum: + return ROLNUM_FONT; + + case Font::kRollingNum4P: + return RO4NUM_FONT; } return TINY_FONT; diff --git a/src/v_draw.hpp b/src/v_draw.hpp index 2f6be5d25..8b0441537 100644 --- a/src/v_draw.hpp +++ b/src/v_draw.hpp @@ -41,6 +41,8 @@ public: kThinTimer, kMenu, kMedium, + kRollingNum, + kRollingNum4P, }; enum class Align diff --git a/src/v_video.cpp b/src/v_video.cpp index 06991d0e5..b37c1ad3c 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -987,10 +987,8 @@ void V_DrawBlock(INT32 x, INT32 y, INT32 scrn, INT32 width, INT32 height, const UINT8 *dest; const UINT8 *deststop; -#ifdef RANGECHECK if (x < 0 || x + width > vid.width || y < 0 || y + height > vid.height || (unsigned)scrn > 4) I_Error("Bad V_DrawBlock"); -#endif dest = screens[scrn] + y*vid.width + x; deststop = screens[scrn] + vid.rowbytes * vid.height; @@ -2342,6 +2340,12 @@ static void V_GetFontSpecification(int fontno, INT32 flags, fontspec_t *result) case PINGF_FONT: result->spacew = 3; break; + case ROLNUM_FONT: + result->spacew = 17; + break; + case RO4NUM_FONT: + result->spacew = 9; + break; } switch (fontno) @@ -2373,6 +2377,12 @@ static void V_GetFontSpecification(int fontno, INT32 flags, fontspec_t *result) case PINGF_FONT: result->lfh = 10; break; + case ROLNUM_FONT: + result->lfh = 33; + break; + case RO4NUM_FONT: + result->lfh = 15; + break; } switch (fontno) @@ -2432,6 +2442,8 @@ static void V_GetFontSpecification(int fontno, INT32 flags, fontspec_t *result) break; case OPPRF_FONT: case PINGF_FONT: + case ROLNUM_FONT: + case RO4NUM_FONT: if (result->chw) result->dim_fn = FixedCharacterDim; else