From 647ab66c2fc6f14b55f0085e85a530a408ae67fe Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Sun, 3 Mar 2024 00:46:21 -0700 Subject: [PATCH 01/33] WIP: low-ring conveyance fixups --- src/d_player.h | 1 + src/k_kart.c | 29 +++++++++++++++++++++++++++++ src/lua_playerlib.c | 4 ++++ src/p_enemy.c | 10 ++++++++++ src/p_saveg.c | 2 ++ 5 files changed, 46 insertions(+) diff --git a/src/d_player.h b/src/d_player.h index 098ed8bd1..ab30fc934 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -987,6 +987,7 @@ struct player_t INT16 incontrol; // -1 to -175 when spinning out or tumbling, 1 to 175 when not. Use to check for combo hits or emergency inputs. UINT16 progressivethrust; // When getting beat up in GTR_BUMPERS, speed up the longer you've been out of control. + UINT8 ringvisualwarning; boolean analoginput; // Has an input been recorded that requires analog usage? For input display. diff --git a/src/k_kart.c b/src/k_kart.c index 5c07f26f9..b4c0a5011 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8437,6 +8437,20 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) debtflag->color = player->skincolor; debtflag->fuse = 2; + + if (!(gametyperules & GTR_SPHERES)) + { + P_SetScale(debtflag, + Easing_InQuint( + min(FRACUNIT, FRACUNIT*player->ringvisualwarning/(TICRATE*3)), + debtflag->scale, + debtflag->scale*2 + ) + ); + if (player->ringvisualwarning <= 1) + debtflag->renderflags = K_GetPlayerDontDrawFlag(player); + } + } if (player->springstars && (leveltime & 1)) @@ -9013,6 +9027,21 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->incontrol++; } + if (player->rings <= 0) + { + if (player->ringvisualwarning > 1) + player->ringvisualwarning--; + } + else + { + player->ringvisualwarning = 0; + } + + if (player->ringvisualwarning == 0 && player->rings <= 0) + { + player->ringvisualwarning = 6*TICRATE/2; + } + player->incontrol = min(player->incontrol, 5*TICRATE); player->incontrol = max(player->incontrol, -5*TICRATE); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index e2cbffd0a..b323b3ca8 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -263,6 +263,8 @@ static int player_get(lua_State *L) lua_pushboolean(L, plr->incontrol); else if (fastcmp(field,"progressivethrust")) lua_pushboolean(L, plr->progressivethrust); + else if (fastcmp(field,"ringvisualwarning")) + lua_pushboolean(L, plr->ringvisualwarning); else if (fastcmp(field,"dotrickfx")) lua_pushboolean(L, plr->dotrickfx); else if (fastcmp(field,"bumperinflate")) @@ -801,6 +803,8 @@ static int player_set(lua_State *L) plr->incontrol = luaL_checkinteger(L, 3); else if (fastcmp(field,"progressivethrust")) plr->progressivethrust = luaL_checkboolean(L, 3); + else if (fastcmp(field,"ringvisualwarning")) + plr->ringvisualwarning = luaL_checkboolean(L, 3); else if (fastcmp(field,"analoginput")) plr->markedfordeath = luaL_checkboolean(L, 3); else if (fastcmp(field,"markedfordeath")) diff --git a/src/p_enemy.c b/src/p_enemy.c index 645ff3013..640f17fac 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3522,6 +3522,16 @@ void A_AttractChase(mobj_t *actor) S_ReducedVFXSoundAtVolume(actor->target, sfx_s1b5, actor->target->player->ringvolume, NULL); + if (actor->target->player->rings <= 10 && P_IsDisplayPlayer(actor->target->player)) + { + S_ReducedVFXSoundAtVolume(actor->target, sfx_gshab, + 255 - 10*actor->target->player->rings + , NULL); + + if (actor->target->player->rings == 0) + S_ReducedVFXSoundAtVolume(actor->target, sfx_gshad, 255, NULL); + } + actor->target->player->ringvolume -= RINGVOLUMEUSEPENALTY; sparkle = P_SpawnMobj(actor->target->x, actor->target->y, actor->target->z, MT_RINGSPARKS); diff --git a/src/p_saveg.c b/src/p_saveg.c index bc58064b7..c3bb62629 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -598,6 +598,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEINT16(save->p, players[i].incontrol); WRITEUINT16(save->p, players[i].progressivethrust); + WRITEUINT8(save->p, players[i].ringvisualwarning); WRITEUINT8(save->p, players[i].analoginput); @@ -1184,6 +1185,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].incontrol = READINT16(save->p); players[i].progressivethrust = READUINT16(save->p); + players[i].ringvisualwarning = READUINT8(save->p); players[i].analoginput = READUINT8(save->p); From eb4524fe1f3a42ced5b9dd1f25f0566749e72ee8 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Sun, 3 Mar 2024 01:07:36 -0700 Subject: [PATCH 02/33] Reduce <10 ring warning sound volume --- src/p_enemy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 640f17fac..b1dca873a 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3525,7 +3525,7 @@ void A_AttractChase(mobj_t *actor) if (actor->target->player->rings <= 10 && P_IsDisplayPlayer(actor->target->player)) { S_ReducedVFXSoundAtVolume(actor->target, sfx_gshab, - 255 - 10*actor->target->player->rings + 255 - 20*actor->target->player->rings , NULL); if (actor->target->player->rings == 0) From 8a1a688f006b4a4b93d54626f66464236cb85e3b Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Sun, 3 Mar 2024 16:53:55 -0700 Subject: [PATCH 03/33] Nudge low-ring volume again again --- src/p_enemy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index b1dca873a..9052ef63d 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3525,11 +3525,11 @@ void A_AttractChase(mobj_t *actor) if (actor->target->player->rings <= 10 && P_IsDisplayPlayer(actor->target->player)) { S_ReducedVFXSoundAtVolume(actor->target, sfx_gshab, - 255 - 20*actor->target->player->rings + 210 - 10*actor->target->player->rings , NULL); if (actor->target->player->rings == 0) - S_ReducedVFXSoundAtVolume(actor->target, sfx_gshad, 255, NULL); + S_ReducedVFXSoundAtVolume(actor->target, sfx_gshad, 127, NULL); } actor->target->player->ringvolume -= RINGVOLUMEUSEPENALTY; From 89c7e31c147ec09d8d31febf743aff4690688a3b Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 3 Mar 2024 17:27:06 -0800 Subject: [PATCH 04/33] R_DrawVisSprite: comment out GAME WOULD HAVE CRASHED warning This only meant anything to me --- src/r_things.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/r_things.cpp b/src/r_things.cpp index 2e948db57..8397c2998 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -1093,7 +1093,7 @@ static void R_DrawVisSprite(vissprite_t *vis) else { -#ifdef RANGECHECK +#if 0 if (vis->x1test && vis->x2test) { INT32 x1test = vis->x1test; @@ -1112,7 +1112,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) From 4cad56c38caec0db91a34388aed0bd4bf34133af Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 3 Mar 2024 17:31:04 -0800 Subject: [PATCH 05/33] P_CrossSubsector: do not I_Error on invalid subsector - IDK if return true is correct, but I've never seen this error before either --- src/p_sight.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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; From c6bdf4eae3a07cc8068ba18bf8f96300ddceffe6 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 3 Mar 2024 17:27:51 -0800 Subject: [PATCH 06/33] Remove RANGECHECK, replace with devmode prints - All code that would I_Error behind RANGECHECK, simply return - Add debug prints under devmode render --- src/CMakeLists.txt | 2 +- src/doomdef.h | 2 -- src/hardware/hw_main.c | 21 ++++++++++----------- src/p_polyobj.c | 36 ------------------------------------ src/r_bsp.cpp | 8 +++----- src/r_draw_column.cpp | 6 ------ src/r_things.cpp | 30 ++++++++++++++++-------------- src/v_video.cpp | 2 -- 8 files changed, 30 insertions(+), 77 deletions(-) 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/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/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/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/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 8397c2998..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) @@ -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_video.cpp b/src/v_video.cpp index 06991d0e5..694848d88 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; From df2e4f57fd2f883e092d2d820f7806c9bc82b17b Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 4 Mar 2024 22:11:19 -0800 Subject: [PATCH 07/33] Menus/Accessibility: add FOV option, 70 to 110 Adds FOV to profiles json --- src/cvars.cpp | 1 + src/k_menu.h | 1 + src/k_profiles.cpp | 7 +++++++ src/k_profiles.h | 5 ++++- src/menus/options-profiles-1.c | 2 ++ src/menus/options-profiles-edit-1.c | 3 +++ src/menus/options-profiles-edit-accessibility.cpp | 5 ++++- 7 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/cvars.cpp b/src/cvars.cpp index 521fefb27..97e407b10 100644 --- a/src/cvars.cpp +++ b/src/cvars.cpp @@ -951,6 +951,7 @@ void Dummymenuplayer_OnChange(void); consvar_t cv_dummymenuplayer = MenuDummy("dummymenuplayer", "P1").onchange(Dummymenuplayer_OnChange).values({{0, "NOPE"}, {1, "P1"}, {2, "P2"}, {3, "P3"}, {4, "P4"}}); consvar_t cv_dummyprofileautoroulette = MenuDummy("dummyprofileautoroulette", "Off").on_off(); +consvar_t cv_dummyprofilefov = MenuDummy("dummyprofilefov", "90").min_max(70, 110); consvar_t cv_dummyprofilelitesteer = MenuDummy("dummyprofilelitesteer", "On").on_off(); consvar_t cv_dummyprofilekickstart = MenuDummy("dummyprofilekickstart", "Off").on_off(); consvar_t cv_dummyprofilename = MenuDummy("dummyprofilename", ""); diff --git a/src/k_menu.h b/src/k_menu.h index ae093bf1c..2088a8470 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -1047,6 +1047,7 @@ extern consvar_t cv_dummyprofilekickstart; extern consvar_t cv_dummyprofileautoroulette; extern consvar_t cv_dummyprofilelitesteer; extern consvar_t cv_dummyprofilerumble; +extern consvar_t cv_dummyprofilefov; void M_ResetOptions(void); void M_InitOptions(INT32 choice); // necessary for multiplayer since there's some options we won't want to access diff --git a/src/k_profiles.cpp b/src/k_profiles.cpp index ccec96ad9..2e123c7e5 100644 --- a/src/k_profiles.cpp +++ b/src/k_profiles.cpp @@ -28,6 +28,8 @@ #include "k_color.h" #include "command.h" +extern "C" consvar_t cv_dummyprofilefov, cv_fov[MAXSPLITSCREENPLAYERS]; + CV_PossibleValue_t lastprofile_cons_t[] = {{-1, "MIN"}, {MAXPROFILES, "MAX"}, {0, NULL}}; // List of all the profiles. @@ -79,6 +81,7 @@ profile_t* PR_MakeProfile( newprofile->autoroulette = false; newprofile->litesteer = true; newprofile->rumble = true; + newprofile->fov = atoi(cv_dummyprofilefov.defaultvalue); // Copy from gamecontrol directly as we'll be setting controls up directly in the profile. memcpy(newprofile->controls, controlarray, sizeof(newprofile->controls)); @@ -98,6 +101,7 @@ profile_t* PR_MakeProfileFromPlayer(const char *prname, const char *pname, const newprofile->autoroulette = cv_autoroulette[pnum].value; newprofile->litesteer = cv_litesteer[pnum].value; newprofile->rumble = cv_rumble[pnum].value; + newprofile->fov = cv_fov[pnum].value / FRACUNIT; return newprofile; } @@ -292,6 +296,7 @@ void PR_SaveProfiles(void) jsonprof.preferences.autoroulette = cprof->autoroulette; jsonprof.preferences.litesteer = cprof->litesteer; jsonprof.preferences.rumble = cprof->rumble; + jsonprof.preferences.fov = cprof->fov; for (size_t j = 0; j < num_gamecontrols; j++) { @@ -456,6 +461,7 @@ void PR_LoadProfiles(void) newprof->autoroulette = jsprof.preferences.autoroulette; newprof->litesteer = jsprof.preferences.litesteer; newprof->rumble = jsprof.preferences.rumble; + newprof->fov = jsprof.preferences.fov; try { @@ -495,6 +501,7 @@ static void PR_ApplyProfile_Settings(profile_t *p, UINT8 playernum) CV_StealthSetValue(&cv_autoroulette[playernum], p->autoroulette); CV_StealthSetValue(&cv_litesteer[playernum], p->litesteer); CV_StealthSetValue(&cv_rumble[playernum], p->rumble); + CV_StealthSetValue(&cv_fov[playernum], p->fov); // set controls... G_ApplyControlScheme(playernum, p->controls); diff --git a/src/k_profiles.h b/src/k_profiles.h index 2fb5cf9fa..fe5f02567 100644 --- a/src/k_profiles.h +++ b/src/k_profiles.h @@ -47,6 +47,7 @@ struct ProfilePreferencesJson bool autoroulette; bool litesteer; bool rumble; + uint8_t fov; tm test; NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( @@ -54,7 +55,8 @@ struct ProfilePreferencesJson kickstartaccel, autoroulette, litesteer, - rumble + rumble, + fov ) }; @@ -153,6 +155,7 @@ struct profile_t boolean autoroulette; // cv_autoroulette boolean litesteer; // cv_litesteer boolean rumble; // cv_rumble + UINT8 fov; // cv_fov // Finally, control data itself INT32 controls[num_gamecontrols][MAXINPUTMAPPING]; // Lists of all the controls, defined the same way as default inputs in g_input.c diff --git a/src/menus/options-profiles-1.c b/src/menus/options-profiles-1.c index 7c82d12e5..8a81dadfb 100644 --- a/src/menus/options-profiles-1.c +++ b/src/menus/options-profiles-1.c @@ -93,6 +93,7 @@ void M_StartEditProfile(INT32 c) CV_StealthSetValue(&cv_dummyprofileautoroulette, optionsmenu.profile->autoroulette); CV_StealthSetValue(&cv_dummyprofilelitesteer, optionsmenu.profile->litesteer); CV_StealthSetValue(&cv_dummyprofilerumble, optionsmenu.profile->rumble); + CV_StealthSetValue(&cv_dummyprofilefov, optionsmenu.profile->fov); } else { @@ -102,6 +103,7 @@ void M_StartEditProfile(INT32 c) CV_StealthSetValue(&cv_dummyprofileautoroulette, 0); // off CV_StealthSetValue(&cv_dummyprofilelitesteer, 1); // on CV_StealthSetValue(&cv_dummyprofilerumble, 1); // on + CV_StealthSetValue(&cv_dummyprofilefov, 90); } // Setup greyout and stuff. diff --git a/src/menus/options-profiles-edit-1.c b/src/menus/options-profiles-edit-1.c index 9fe9997b3..65eca8819 100644 --- a/src/menus/options-profiles-edit-1.c +++ b/src/menus/options-profiles-edit-1.c @@ -90,15 +90,18 @@ static void M_ProfileEditApply(void) optionsmenu.profile->autoroulette = cv_dummyprofileautoroulette.value; optionsmenu.profile->litesteer = cv_dummyprofilelitesteer.value; optionsmenu.profile->rumble = cv_dummyprofilerumble.value; + optionsmenu.profile->fov = cv_dummyprofilefov.value; // If this profile is in-use by anyone, apply the changes immediately upon exiting. // Don't apply the profile itself as that would lead to issues mid-game. if (belongsto > -1 && belongsto < MAXSPLITSCREENPLAYERS) { + extern consvar_t cv_fov[MAXSPLITSCREENPLAYERS]; CV_SetValue(&cv_kickstartaccel[belongsto], cv_dummyprofilekickstart.value); CV_SetValue(&cv_autoroulette[belongsto], cv_dummyprofileautoroulette.value); CV_SetValue(&cv_litesteer[belongsto], cv_dummyprofilelitesteer.value); CV_SetValue(&cv_rumble[belongsto], cv_dummyprofilerumble.value); + CV_SetValue(&cv_fov[belongsto], cv_dummyprofilefov.value); } // Reapply player 1's real profile. diff --git a/src/menus/options-profiles-edit-accessibility.cpp b/src/menus/options-profiles-edit-accessibility.cpp index ca031279c..1c8d6ca88 100644 --- a/src/menus/options-profiles-edit-accessibility.cpp +++ b/src/menus/options-profiles-edit-accessibility.cpp @@ -102,6 +102,9 @@ menuitem_t OPTIONS_ProfileAccessibility[] = { {IT_STRING | IT_CVAR, "Lite Steer", "Hold DOWN on d-pad/keyboard for shallow turns.", NULL, {.cvar = &cv_dummyprofilelitesteer}, 0, 0}, + {IT_STRING | IT_CVAR, "Field of View", "Higher FOV lets you see more.", + NULL, {.cvar = &cv_dummyprofilefov}, 0, 0}, + {IT_SPACE | IT_NOTHING, NULL, NULL, NULL, {NULL}, 0, 0}, @@ -129,7 +132,7 @@ menu_t OPTIONS_ProfileAccessibilityDef = { &OPTIONS_EditProfileDef, 0, OPTIONS_ProfileAccessibility, - 145, 52, + 145, 41, SKINCOLOR_ULTRAMARINE, 0, MBF_DRAWBGWHILEPLAYING, "FILE", From e5059bfced59b586112ac190e9635ec6fd661887 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 5 Mar 2024 00:15:07 -0800 Subject: [PATCH 08/33] Menus/Accessibility: Input Display Yes/No -> On/Off --- src/cvars.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cvars.cpp b/src/cvars.cpp index 521fefb27..4a2fa9948 100644 --- a/src/cvars.cpp +++ b/src/cvars.cpp @@ -356,7 +356,7 @@ consvar_t cv_drawdist_precip = Player("drawdist_precip", "1024").values({ {0, "None"}, }); -consvar_t cv_drawinput = Player("drawinput", "No").yes_no(); +consvar_t cv_drawinput = Player("drawinput", "Off").on_off(); consvar_t cv_ffloorclip = Player("ffloorclip", "On").on_off(); consvar_t cv_fpscap = Player("fpscap", "Match refresh rate").values({ From e86ae4b22b052c19efca448fb91b62b109d1a18b Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 5 Mar 2024 02:56:34 -0800 Subject: [PATCH 09/33] G_AddGhost, G_GetStaffGhostBrief: fix bugged unlockables code This was causing the following crash: I_Error(): Ghost is not a record attack ghost DXD (ziptic = 1) --- src/g_demo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_demo.cpp b/src/g_demo.cpp index fbeb4d98d..444138b21 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -3591,7 +3591,7 @@ void G_AddGhost(savebuffer_t *buffer, const char *defdemoname) // Skip unlockables { UINT32 unlockables = READUINT32(p); - p += std::min(unlockables, MAXUNLOCKABLES); + p += unlockables; } p++; // mapmusrng @@ -3814,7 +3814,7 @@ staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer) // Skip unlockables { UINT32 unlockables = READUINT32(p); - p += std::min(unlockables, MAXUNLOCKABLES); + p += unlockables; } p++; // mapmusrng From f60309983a49a62002395c60614b476665e0b9f9 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 5 Mar 2024 03:11:05 -0800 Subject: [PATCH 10/33] Add debugprisoncd cheat (DEVELOP only) - Always drops a CD from Prison Eggs --- src/cvars.cpp | 4 ++++ src/m_cond.c | 26 ++++++++++++++++++++++++++ src/p_inter.c | 10 +++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/cvars.cpp b/src/cvars.cpp index 4a2fa9948..b9199f8bd 100644 --- a/src/cvars.cpp +++ b/src/cvars.cpp @@ -873,6 +873,10 @@ consvar_t cv_1pswap = PlayerCheat("1pswap", "1").min_max(1, MAXSPLITSCREENPLAYER consvar_t cv_debugfinishline = PlayerCheat("debugfinishline", "Off").on_off().description("Highlight finish lines, respawn lines, death pits and instakill planes with high contrast colors"); consvar_t cv_debughudtracker = PlayerCheat("debughudtracker", "Off").on_off().description("Highlight overlapping HUD tracker blocks"); +#ifdef DEVELOP + consvar_t cv_debugprisoncd = PlayerCheat("debugprisoncd", "Off").on_off().description("Always drop a CD from breaking Prisons"); +#endif + consvar_t cv_debugrank = PlayerCheat("debugrank", "Off").description("Show GP rank state on the HUD; optionally force a rank grade").values({ {0, "Off"}, {1, "On"}, diff --git a/src/m_cond.c b/src/m_cond.c index af30e415b..079da8238 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1019,6 +1019,32 @@ cacheprisoneggpickup: } //CONS_Printf("thisprisoneggpickup = %u (MAXCONDITIONSETS is %u)\n", gamedata->thisprisoneggpickup, MAXCONDITIONSETS); + +#ifdef DEVELOP + extern consvar_t cv_debugprisoncd; + // If all drops are collected, just force the first valid one. + if (cv_debugprisoncd.value && gamedata->thisprisoneggpickup_cached == NULL) + { + for (i = 0; gamedata->thisprisoneggpickup_cached == NULL && + i < gamedata->numprisoneggpickups; i++) + { + c = &conditionSets[gamedata->prisoneggpickups[i]]; + if (c->numconditions) + { + for (j = 0; j < c->numconditions; ++j) + { + cn = &c->condition[j]; + if (cn->type != UC_PRISONEGGCD) + continue; + + gamedata->thisprisoneggpickup = gamedata->prisoneggpickups[i]; + gamedata->thisprisoneggpickup_cached = cn; + break; + } + } + } + } +#endif } static void M_PrecacheLevelLocks(void) diff --git a/src/p_inter.c b/src/p_inter.c index 86a2a2094..270f8529c 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1198,13 +1198,21 @@ static void P_AddBrokenPrison(mobj_t *target, mobj_t *inflictor, mobj_t *source) secretextratime = TICRATE/2; } - if ( + +#ifdef DEVELOP + extern consvar_t cv_debugprisoncd; +#endif + if (( grandprixinfo.gp == true // Bonus Round && demo.playback == false // Not playback && netgame == false // game design + makes it easier to implement && gamedata->thisprisoneggpickup_cached != NULL && gamedata->prisoneggstothispickup == 0 && gamedata->thisprisoneggpickupgrabbed == false + ) +#ifdef DEVELOP + || (cv_debugprisoncd.value && gamedata->thisprisoneggpickup_cached != NULL) +#endif ) { // Will be 0 for the next level From 18654a8a7079c0dd26b2d83d876b1606f1b8fe93 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 5 Mar 2024 03:14:07 -0800 Subject: [PATCH 11/33] Extra effects for Prison Egg CD - The goal here is to make it more obvious if a CD drops, and make the CD more visible. - Rainbow sparkles scaled up by x3. - Play long "powering down" noise when a Prison with a CD inside is destroyed. - CD spawns after noise stops playing. - Spawn a twinkle (Gainax). - Flickers while "powering down" noise is playing. - Enlarges and disappears in sync with the "CD dropped" sound effect. - Darken the map while all of this is happening. --- src/deh_tables.c | 4 ++++ src/info.c | 4 ++++ src/info.h | 4 ++++ src/p_inter.c | 24 ++++++++++++++++++++++++ src/p_mobj.c | 10 ++++++++++ src/sounds.c | 2 +- 6 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index da0e50972..7a80db60b 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -506,6 +506,10 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi // Prison Egg Drops "S_PRISONEGGDROP_CD", + "S_PRISONEGGDROP_FLAREA1", + "S_PRISONEGGDROP_FLAREA2", + "S_PRISONEGGDROP_FLAREB1", + "S_PRISONEGGDROP_FLAREB2", // Bubble Source "S_BUBBLES1", diff --git a/src/info.c b/src/info.c index 8d8e72053..13250ba4f 100644 --- a/src/info.c +++ b/src/info.c @@ -1013,6 +1013,10 @@ state_t states[NUMSTATES] = // Prison Egg Drops {SPR_ALTM, 0|FF_PAPERSPRITE|FF_SEMIBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_PRISONEGGDROP_CD + {SPR_LENS, 14|FF_FULLBRIGHT|FF_ADD|FF_TRANS10, 1, {NULL}, 0, 0, S_PRISONEGGDROP_FLAREA2}, // S_PRISONEGGDROP_FLAREA1 + {SPR_NULL, 0, 1, {NULL}, 0, 0, S_PRISONEGGDROP_FLAREA1}, // S_PRISONEGGDROP_FLAREA2 + {SPR_LENS, 11|FF_FULLBRIGHT|FF_ADD|FF_TRANS10|FF_ANIMATE, 16, {NULL}, 7, 2, S_PRISONEGGDROP_FLAREB2}, // S_PRISONEGGDROP_FLAREB1 + {SPR_LENS, 19|FF_FULLBRIGHT|FF_ADD|FF_TRANS10|FF_ANIMATE, 6, {NULL}, 1, 2, S_NULL}, // S_PRISONEGGDROP_FLAREB2 // Bubble Source {SPR_BBLS, 0, 8, {A_BubbleSpawn}, 2048, 0, S_BUBBLES2}, // S_BUBBLES1 diff --git a/src/info.h b/src/info.h index fd062e658..3b26cfefc 100644 --- a/src/info.h +++ b/src/info.h @@ -1499,6 +1499,10 @@ typedef enum state // Prison Egg Drops S_PRISONEGGDROP_CD, + S_PRISONEGGDROP_FLAREA1, + S_PRISONEGGDROP_FLAREA2, + S_PRISONEGGDROP_FLAREB1, + S_PRISONEGGDROP_FLAREB2, // Bubble Source S_BUBBLES1, diff --git a/src/p_inter.c b/src/p_inter.c index 270f8529c..048034486 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1226,6 +1226,10 @@ static void P_AddBrokenPrison(mobj_t *target, mobj_t *inflictor, mobj_t *source) if (secretpickup) { + // Grab attention with a long sound effect. + target->hitlag += 56; + S_StartSound(target, sfx_s3k85); + secretpickup->hitlag = target->hitlag; secretpickup->z -= secretpickup->height/2; @@ -1252,6 +1256,26 @@ static void P_AddBrokenPrison(mobj_t *target, mobj_t *inflictor, mobj_t *source) secretpickup, secretpickup->angle, P_ReturnThrustX(secretpickup, launchangle, launchmomentum) ); + + mobj_t *flare = P_SpawnMobj( + target->x, target->y, + target->z + target->height/2, + MT_SPARK + ); + + if (flare) + { + // Will flicker in place until secretpickup exits hitlag. + flare->colorized = true; + flare->renderflags |= RF_ALWAYSONTOP; + P_InstaScale(flare, 4 * flare->scale); + P_SetTarget(&secretpickup->target, flare); + P_SetMobjStateNF(flare, S_PRISONEGGDROP_FLAREA1); + } + + // Darken the level for roughly how long it takes until the last sound effect stops playing. + g_darkness.start = leveltime; + g_darkness.end = leveltime + target->hitlag + TICRATE + DARKNESS_FADE_TIME; } } } diff --git a/src/p_mobj.c b/src/p_mobj.c index 7a3083a8d..ce279a0d4 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7499,6 +7499,10 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->z += P_MobjFlip(mobj); mobj->flags2 |= MF2_AMBUSH; + + // Finish flare animation. + if (mobj->target && !P_MobjWasRemoved(mobj->target)) + P_SetMobjStateNF(mobj->target, S_PRISONEGGDROP_FLAREB1); } if (teststate == S_PRISONEGGDROP_CD) @@ -7538,6 +7542,12 @@ static boolean P_MobjRegularThink(mobj_t *mobj) sparkle->color = M_RandomChance(FRACUNIT/2) ? SKINCOLOR_ULTRAMARINE : SKINCOLOR_MAGENTA; sparkle->momz += 8 * mobj->scale * P_MobjFlip(mobj); + sparkle->scale = 3 * sparkle->scale; + sparkle->scalespeed = abs(sparkle->scale - sparkle->destscale) / 16; + + // Colorize flare. + if (mobj->target && !P_MobjWasRemoved(mobj->target)) + mobj->target->color = sparkle->color; } } } diff --git a/src/sounds.c b/src/sounds.c index 14ccca9cb..e9c3eff9c 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -534,7 +534,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k82", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Burst"}, {"s3k83", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Collapsing"}, {"s3k84", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Powering up"}, - {"s3k85", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Powering down"}, + {"s3k85", false, 64, 24, -1, NULL, 0, -1, -1, LUMPERROR, "Powering down"}, {"s3k86", false, 128, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Alarm"}, {"s3k87", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bounce"}, {"s3k88", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Metallic squeak"}, From 1ba91ef853ec14d9e5096179831d35d7e6b787c8 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 5 Mar 2024 04:27:23 -0800 Subject: [PATCH 12/33] Respawn: only ignore finish lines when traveling back to first waypoint This fixes lightsnaking through a finish line on sprint maps not giving you a lap. - On circuit maps, lightsnake stops at the finish line waypoint (there's only one finish line) - On sprint maps, there are multiple finish lines but you can't have multiple finish line waypoints, therefore lightsnake goes right through - So we have to make sure the player can cross a finish line while in lightsnake to account for this - Because lightsnake sends you back to the respawn waypoint in a straight line, it may inadvertently cross a finish line and remove a lap - So here's the change: the player should no-clip through the finish line ONLY while traveling back to the first waypoint - Because after that, lightsnake follows the map's waypoints and is intentionally crossing sprint maps' finish lines --- src/p_spec.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/p_spec.c b/src/p_spec.c index ff68cc509..c4ca508ed 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1906,12 +1906,31 @@ void P_SwitchWeather(preciptype_t newWeather) P_SpawnPrecipitation(); } +static boolean K_IgnoreFinishLine(player_t *player) +{ + // Lightsnake travels to the first waypoint in a straight + // line (init). + // This has the potential to inadvertently cross a finish + // line and remove a lap (happened on Hardhat Havoc). + // After the first waypoint, lightsnake follows the + // waypoints in order so it's not an issue there. + if (player->respawn.state == RESPAWNST_MOVE && player->respawn.init == true) + return true; + + // If potential lap cheating has been detected, do not + // interact with the finish line at all. + if (player->bigwaypointgap) + return true; + + return false; +} + // Passed over the finish line forwards static void K_HandleLapIncrement(player_t *player) { if (player) { - if (player->respawn.state == RESPAWNST_MOVE || player->bigwaypointgap) + if (K_IgnoreFinishLine(player)) return; if (!G_TimeAttackStart() && leveltime < starttime && !(gametyperules & GTR_ROLLINGSTART)) { @@ -2184,7 +2203,7 @@ static void K_HandleLapDecrement(player_t *player) { if (player) { - if (player->respawn.state == RESPAWNST_MOVE || player->bigwaypointgap) + if (K_IgnoreFinishLine(player)) return; if ((player->cheatchecknum == 0) && (player->laps > 0)) { From 6023fa4825abefd851ec25a98c57bf2ca4c3899d Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 5 Mar 2024 14:48:09 -0600 Subject: [PATCH 13/33] Only record tumble time for machine local players --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 38f32762c..084b0c244 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8095,7 +8095,7 @@ void K_KartPlayerHUDUpdate(player_t *player) else player->karthud[khud_finish] = 0; - if (demo.playback == false && P_IsLocalPlayer(player) == true) + if (demo.playback == false && P_IsMachineLocalPlayer(player) == true) { if (player->tumbleBounces != 0 && gamedata->totaltumbletime != UINT32_MAX) { From 3386c70f9c73bec4883cf2853e2be4aeb5af6b93 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 5 Mar 2024 14:49:18 -0600 Subject: [PATCH 14/33] Record skin wins only for machine local players --- 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 7adfa49ea..13da816e4 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1314,7 +1314,7 @@ void P_DoPlayerExit(player_t *player, pflags_t flags) PR_SaveProfiles(); } - if (P_IsLocalPlayer(player) && player->skin < numskins) + if (P_IsMachineLocalPlayer(player) && player->skin < numskins) { skins[player->skin].records.wins++; } From fb3beef84cec5f8ac0fef0bea88c6992b9e8efa7 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 5 Mar 2024 14:49:51 -0600 Subject: [PATCH 15/33] Only do replay save btn for machine-local players --- 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 13da816e4..179a2792a 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1320,7 +1320,7 @@ void P_DoPlayerExit(player_t *player, pflags_t flags) } } - if (!demo.savebutton && P_IsLocalPlayer(player)) + if (!demo.savebutton && P_IsMachineLocalPlayer(player)) demo.savebutton = leveltime; } } From 2bfcfeb56037a1d18a8d13d23220b6167192cd2c Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 4 Mar 2024 16:54:36 +0000 Subject: [PATCH 16/33] Fix Skin unlocks at the beginning of replays - DXD_JOINDATA: Actually correctly write demo data - SetPlayerSkinByNum, bot skin iteration code: Use demo skinlist index instead of actual skin ID --- src/g_demo.cpp | 29 +++++++++++++++-------------- src/k_bot.cpp | 4 ++-- src/k_grandprix.c | 8 ++++---- src/r_skins.c | 9 ++++++--- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/g_demo.cpp b/src/g_demo.cpp index 444138b21..b471a0015 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -317,8 +317,8 @@ void G_ReadDemoExtraData(void) skinid = READUINT8(demobuf.p); if (skinid >= demo.numskins) skinid = 0; - SetPlayerSkinByNum(p, demo.skinlist[skinid].mapping); - demo.currentskinid[p] = skinid; + ghostext[p].skinid = demo.currentskinid[p] = skinid; + SetPlayerSkinByNum(p, skinid); players[p].kartspeed = ghostext[p].kartspeed = demo.skinlist[skinid].kartspeed; players[p].kartweight = ghostext[p].kartweight = demo.skinlist[skinid].kartweight; @@ -424,7 +424,7 @@ void G_WriteDemoExtraData(void) { for (j = 0; j < MAXAVAILABILITY; j++) { - WRITEUINT8(demobuf.p, players[i].availabilities[i]); + WRITEUINT8(demobuf.p, players[i].availabilities[j]); } WRITEUINT8(demobuf.p, (UINT8)players[i].bot); @@ -3354,12 +3354,9 @@ void G_DoPlayDemo(const char *defdemoname) // Skin - i = READUINT8(demobuf.p); - if (i >= demo.numskins) - i = 0; - SetPlayerSkinByNum(p, demo.skinlist[i].mapping); - demo.currentskinid[p] = ghostext[p].skinid = i; - + demo.currentskinid[p] = READUINT8(demobuf.p); + if (demo.currentskinid[p] >= demo.numskins) + demo.currentskinid[p] = 0; lastfakeskin[p] = READUINT8(demobuf.p); // Color @@ -3442,6 +3439,15 @@ void G_DoPlayDemo(const char *defdemoname) UINT8 j; p = slots[i]; + + for (j = 0; j < MAXAVAILABILITY; j++) + { + players[p].availabilities[j] = availabilities[p][j]; + } + + ghostext[p].skinid = demo.currentskinid[p]; + SetPlayerSkinByNum(p, demo.currentskinid[p]); + if (players[p].mo) { players[p].mo->color = players[p].skincolor; @@ -3457,11 +3463,6 @@ void G_DoPlayDemo(const char *defdemoname) players[p].kartweight = ghostext[p].kartweight = demo.skinlist[demo.currentskinid[p]].kartweight; players[p].charflags = ghostext[p].charflags = demo.skinlist[demo.currentskinid[p]].flags; players[p].lastfakeskin = lastfakeskin[p]; - - for (j = 0; j < MAXAVAILABILITY; j++) - { - players[p].availabilities[j] = availabilities[p][j]; - } } demo.deferstart = true; diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 66512be98..372200883 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -177,12 +177,12 @@ void K_UpdateMatchRaceBots(void) UINT8 numbots = 0; UINT8 numwaiting = 0; SINT8 wantedbots = 0; - UINT8 usableskins = 0; + UINT8 usableskins = 0, skincount = (demo.playback ? demo.numskins : numskins);; UINT8 grabskins[MAXSKINS+1]; UINT8 i; // Init usable bot skins list - for (i = 0; i < numskins; i++) + for (i = 0; i < skincount; i++) { grabskins[usableskins++] = i; } diff --git a/src/k_grandprix.c b/src/k_grandprix.c index 5b45c8176..92bd7b41b 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -133,7 +133,7 @@ void K_InitGrandPrixBots(void) UINT8 numplayers = 0; UINT8 competitors[MAXSPLITSCREENPLAYERS]; - UINT8 usableskins; + UINT8 usableskins, skincount = (demo.playback ? demo.numskins : numskins);; UINT8 grabskins[MAXSKINS+1]; UINT8 botskinlist[MAXPLAYERS]; @@ -146,7 +146,7 @@ void K_InitGrandPrixBots(void) memset(botskinlist, defaultbotskin, sizeof (botskinlist)); // Init usable bot skins list - for (usableskins = 0; usableskins < numskins; usableskins++) + for (usableskins = 0; usableskins < skincount; usableskins++) { grabskins[usableskins] = usableskins; } @@ -671,7 +671,7 @@ void K_RetireBots(void) const UINT8 defaultbotskin = R_BotDefaultSkin(); SINT8 newDifficulty; - UINT8 usableskins; + UINT8 usableskins, skincount = (demo.playback ? demo.numskins : numskins); UINT8 grabskins[MAXSKINS+1]; UINT8 i; @@ -687,7 +687,7 @@ void K_RetireBots(void) } // Init usable bot skins list - for (usableskins = 0; usableskins < numskins; usableskins++) + for (usableskins = 0; usableskins < skincount; usableskins++) { grabskins[usableskins] = usableskins; } diff --git a/src/r_skins.c b/src/r_skins.c index f67368daa..64dcfd1ec 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -226,7 +226,7 @@ UINT8 *R_GetSkinAvailabilities(boolean demolock, INT32 botforcecharacter) boolean R_SkinUsable(INT32 playernum, INT32 skinnum, boolean demoskins) { boolean needsunlocked = false; - boolean useplayerstruct = (Playing() && playernum != -1); + boolean useplayerstruct = ((Playing() || demo.playback) && playernum != -1); UINT16 i; INT32 skinid; @@ -357,6 +357,9 @@ engineclass_t R_GetEngineClass(SINT8 speed, SINT8 weight, skinflags_t flags) // Auxillary function that actually sets the skin static void SetSkin(player_t *player, INT32 skinnum) { + if (demo.playback) + skinnum = demo.skinlist[skinnum].mapping; + skin_t *skin = &skins[skinnum]; player->skin = skinnum; @@ -404,9 +407,9 @@ static void SetSkin(player_t *player, INT32 skinnum) // (If your mod locked them all, then you kinda stupid) static INT32 GetPlayerDefaultSkin(INT32 playernum) { - INT32 i; + INT32 i, skincount = (demo.playback ? demo.numskins : numskins); - for (i = 0; i < numskins; i++) + for (i = 0; i < skincount; i++) { if (R_SkinUsable(playernum, i, false)) { From 24b850a492ab40bf9efd4ad20bd34a40e2ab58f4 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 4 Mar 2024 16:56:07 +0000 Subject: [PATCH 17/33] LoadRecordGhosts: Use local unlock state, not consoleplayer availabilities (which might not be set yet) to determine whether a ghost should be visible --- src/p_setup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index f73355636..385e2ca3e 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -7851,7 +7851,7 @@ static void P_LoadRecordGhosts(void) if (sameGhosts) { INT32 skin = R_SkinAvailable(cv_skin[0].string); - if (skin < 0 || !R_SkinUsable(consoleplayer, skin, false)) + if (skin < 0 || !R_SkinUsable(-1, skin, false)) skin = 0; // use default skin add_ghosts(fmt::format("{}-{}{}", gpath, skins[skin].name, modeprefix), sameGhosts); } From 7f0df71558751d9b0f70f4d5e8bab8c5bcb4e3e3 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 4 Mar 2024 17:05:23 +0000 Subject: [PATCH 18/33] R_SkinAvailableEX - Most R_SkinAvailable calls should be returning index into demo.skinlist (same numerical value as when demo was recorded), for demo sync - A handful of general things permit exception for this - Expose `replaynumskins` (calculated as `(demo.playback ? demo.numskins : numskins)`) to Lua - There's *always* more that can be done for this, but this is the minimum spec that can at least be somewhat stable --- src/d_main.cpp | 2 +- src/d_netcmd.c | 2 +- src/f_finale.c | 4 ++-- src/g_demo.cpp | 6 ++++-- src/g_demo.h | 2 ++ src/g_gamedata.cpp | 4 ++-- src/hardware/hw_md2.c | 2 +- src/k_menudraw.c | 12 ++++++------ src/lua_baselib.c | 5 +++-- src/lua_hudlib.c | 8 +++++++- src/lua_mobjlib.c | 4 ++++ src/lua_script.c | 4 ++++ src/lua_skinlib.c | 2 +- src/m_cond.c | 6 +++--- src/menus/extras-challenges.c | 2 +- src/menus/main-goner.cpp | 2 +- src/menus/play-char-select.c | 4 ++-- src/p_saveg.c | 4 ++-- src/p_setup.cpp | 2 +- src/r_picformats.c | 2 +- src/r_skins.c | 34 ++++++++++++++++++++++++++++------ src/r_skins.h | 1 + 22 files changed, 78 insertions(+), 36 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 1ece00a2b..6fb28d624 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1946,7 +1946,7 @@ void D_SRB2Main(void) profile_t *pr = PR_GetProfile(cv_ttlprofilen.value); if (pr != NULL) { - INT32 importskin = R_SkinAvailable(pr->skinname); + INT32 importskin = R_SkinAvailableEx(pr->skinname, false); if (importskin != -1) { skins[importskin].records.wins = pr->wins; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 6d640d885..47d272caf 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -960,7 +960,7 @@ static void SendNameAndColor(const UINT8 n) // check if player has the skin loaded (cv_skin may have // the name of a skin that was available in the previous game) - cv_skin[n].value = R_SkinAvailable(cv_skin[n].string); + cv_skin[n].value = R_SkinAvailableEx(cv_skin[n].string, false); if ((cv_skin[n].value < 0) || !R_SkinUsable(playernum, cv_skin[n].value, false)) { CV_StealthSet(&cv_skin[n], DEFAULTSKIN); diff --git a/src/f_finale.c b/src/f_finale.c index 5de1d45dc..fff563921 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1345,12 +1345,12 @@ void F_TitleScreenDrawer(void) if (cache_gametrulystarted == true) { const char *eggName = "eggman"; - INT32 eggSkin = R_SkinAvailable(eggName); + INT32 eggSkin = R_SkinAvailableEx(eggName, false); skincolornum_t eggColor = SKINCOLOR_RED; UINT8 *eggColormap = NULL; const char *tailsName = "tails"; - INT32 tailsSkin = R_SkinAvailable(tailsName); + INT32 tailsSkin = R_SkinAvailableEx(tailsName, false); skincolornum_t tailsColor = SKINCOLOR_ORANGE; UINT8 *tailsColormap = NULL; diff --git a/src/g_demo.cpp b/src/g_demo.cpp index b471a0015..7c472ccba 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -2064,12 +2064,14 @@ static democharlist_t *G_LoadDemoSkins(savebuffer_t *info, UINT8 *worknumskins, return NULL; } - READMEM(info->p, skin, 16); + READMEM(info->p, skinlist[i].name, 16); + skinlist[i].name[16] = '\0'; + skinlist[i].namehash = quickncasehash(skinlist[i].name, SKINNAMESIZE); skinlist[i].kartspeed = READUINT8(info->p); skinlist[i].kartweight = READUINT8(info->p); skinlist[i].flags = READUINT32(info->p); - result = R_SkinAvailable(skin); + result = R_SkinAvailableEx(skin, false); if (result == -1) { if (!getclosest) diff --git a/src/g_demo.h b/src/g_demo.h index 91b2c7ee7..7a43d33c0 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -69,6 +69,8 @@ extern consvar_t cv_recordmultiplayerdemos, cv_netdemosyncquality; extern tic_t demostarttime; struct democharlist_t { + char name[17]; + UINT32 namehash; UINT8 mapping; // No, this isn't about levels. It maps to loaded character ID. UINT8 kartspeed; UINT8 kartweight; diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp index d522ce7ab..050f7341e 100644 --- a/src/g_gamedata.cpp +++ b/src/g_gamedata.cpp @@ -508,7 +508,7 @@ void srb2::load_ng_gamedata() for (auto& skinpair : js.skins) { - INT32 skin = R_SkinAvailable(skinpair.first.c_str()); + INT32 skin = R_SkinAvailableEx(skinpair.first.c_str(), false); skinrecord_t dummyrecord {}; dummyrecord.wins = skinpair.second.records.wins; @@ -683,7 +683,7 @@ void srb2::load_ng_gamedata() dummywindata[j].best_skin.id = MAXSKINS; dummywindata[j].best_skin.unloaded = nullptr; - int skinloaded = R_SkinAvailable(cuppair.second.records[j].bestskin.c_str()); + int skinloaded = R_SkinAvailableEx(cuppair.second.records[j].bestskin.c_str(), false); if (skinloaded >= 0) { dummywindata[j].best_skin.id = skinloaded; diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 3fdc221e9..9fabe59b0 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -570,7 +570,7 @@ void HWR_InitModels(void) addskinmodel: // add player model - s = R_SkinAvailable(skinname); + s = R_SkinAvailableEx(skinname, false); if (s != -1) { md2_playermodels[s].skin = s; diff --git a/src/k_menudraw.c b/src/k_menudraw.c index ea8a4b665..b7a7298df 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -345,7 +345,7 @@ UINT16 M_GetCvPlayerColor(UINT8 pnum) if (color != SKINCOLOR_NONE) return color; - INT32 skin = R_SkinAvailable(cv_skin[pnum].string); + INT32 skin = R_SkinAvailableEx(cv_skin[pnum].string, false); if (skin == -1) return SKINCOLOR_NONE; @@ -377,7 +377,7 @@ static void M_DrawMenuParty(void) // Despite the work put into it, can't use M_GetCvPlayerColor directly - we need to reference skin always. #define grab_skin_and_colormap(pnum) \ { \ - skin = R_SkinAvailable(cv_skin[pnum].string); \ + skin = R_SkinAvailableEx(cv_skin[pnum].string, false); \ color = cv_playercolor[pnum].value; \ if (skin == -1) \ skin = 0; \ @@ -2277,7 +2277,7 @@ void M_DrawProfileCard(INT32 x, INT32 y, boolean greyedout, profile_t *p) if (p != NULL && p->version) { truecol = p->color; - skinnum = R_SkinAvailable(p->skinname); + skinnum = R_SkinAvailableEx(p->skinname, false); strcpy(pname, p->profilename); } @@ -6516,7 +6516,7 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili INT32 skin = M_UnlockableFollowerNum(ref); if (skin != -1) { - INT32 psk = R_SkinAvailable(cv_skin[0].string); + INT32 psk = R_SkinAvailableEx(cv_skin[0].string, false); UINT16 col = K_GetEffectiveFollowerColor(followers[skin].defaultcolor, &followers[skin], cv_playercolor[0].value, (psk != -1) ? &skins[psk] : &skins[0]); colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE); pat = W_CachePatchName(followers[skin].icon, PU_CACHE); @@ -6775,7 +6775,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) } case SECRET_FOLLOWER: { - INT32 skin = R_SkinAvailable(cv_skin[0].string); + INT32 skin = R_SkinAvailableEx(cv_skin[0].string, false); INT32 fskin = M_UnlockableFollowerNum(ref); // Draw proximity reference for character @@ -6806,7 +6806,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) INT32 colorid = M_UnlockableColorNum(ref); if (colorid == SKINCOLOR_NONE) break; - INT32 skin = R_SkinAvailable(cv_skin[0].string); + INT32 skin = R_SkinAvailableEx(cv_skin[0].string, false); if (skin == -1) skin = 0; colormap = R_GetTranslationColormap(skin, colorid, GTC_MENUCACHE); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 71ad3fe75..c76888ce9 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2266,9 +2266,10 @@ static int lib_rSetPlayerSkin(lua_State *L) return luaL_error(L, "argument #2 not given (expected number or string)"); else if (lua_type(L, 2) == LUA_TNUMBER) // skin number { + INT32 skincount = (demo.playback ? demo.numskins : numskins); i = luaL_checkinteger(L, 2); - if (i < 0 || i >= numskins) - return luaL_error(L, "skin %d (argument #2) out of range (0 - %d)", i, numskins-1); + if (i < 0 || i >= skincount) + return luaL_error(L, "skin %d (argument #2) out of range (0 - %d)", i, skincount-1); } else // skin name { diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index c9c463d4a..862d1feef 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -378,7 +378,7 @@ static int libd_getSprite2Patch(lua_State *L) i = lua_tonumber(L, 1); if (i < 0 || i >= MAXSKINS) return luaL_error(L, "skin number %d out of range (0 - %d)", i, MAXSKINS-1); - if (i >= numskins) + if (i >= (demo.playback ? demo.numskins : numskins)) return 0; } else // find skin by name @@ -389,6 +389,9 @@ static int libd_getSprite2Patch(lua_State *L) return 0; } + if (demo.playback) + i = demo.skinlist[i].mapping; + lua_remove(L, 1); // remove skin now if (lua_isnumber(L, 1)) // sprite number given, e.g. SPR2_STIL @@ -1041,6 +1044,9 @@ static int libd_getColormap(lua_State *L) skinnum = i; } + if (demo.playback) + skinnum = demo.skinlist[skinnum].mapping; + // all was successful above, now we generate the colormap at last! colormap = R_GetTranslationColormap(skinnum, color, GTC_CACHE); diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 3ef2ff950..afe34b3bd 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -721,7 +721,11 @@ static int mobj_set(lua_State *L) if (skin != -1) { if (!mo->player || R_SkinUsable(mo->player-players, skin, false)) + { + if (demo.playback) + skin = demo.skinlist[skin].mapping; mo->skin = &skins[skin]; + } return 0; } diff --git a/src/lua_script.c b/src/lua_script.c index d47df24dc..ba3c54f44 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -16,6 +16,7 @@ #include "deh_lua.h" #include "z_zone.h" #include "w_wad.h" +#include "r_things.h" // numskins #include "p_setup.h" #include "r_state.h" #include "r_sky.h" @@ -371,6 +372,9 @@ int LUA_PushGlobals(lua_State *L, const char *word) } else if (fastcmp(word,"replayplayback")) { lua_pushboolean(L, demo.playback); return 1; + } else if (fastcmp(word,"replaynumskins")) { + lua_pushinteger(L, (demo.playback ? demo.numskins : numskins)); + return 1; } else if (fastcmp(word, "gamestate")) { lua_pushinteger(L, gamestate); return 1; diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c index 2950af461..3626a553a 100644 --- a/src/lua_skinlib.c +++ b/src/lua_skinlib.c @@ -196,7 +196,7 @@ static int lib_getSkin(lua_State *L) } // find skin by name - i = R_SkinAvailable(field); + i = R_SkinAvailableEx(field, false); if (i != -1) { LUA_PushUserdata(L, &skins[i], META_SKIN); diff --git a/src/m_cond.c b/src/m_cond.c index af30e415b..5789e8482 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1206,7 +1206,7 @@ void M_UpdateConditionSetsPending(void) case UCRP_ISCHARACTER: case UCRP_MAKERETIRE: { - cn->requirement = R_SkinAvailable(cn->stringvar); + cn->requirement = R_SkinAvailableEx(cn->stringvar, false); if (cn->requirement < 0) { @@ -2021,7 +2021,7 @@ static const char *M_GetConditionCharacter(INT32 skin, boolean directlyrequires) for (j = 0; j < SKINRIVALS; j++) { const char *rivalname = skins[i].rivals[j]; - INT32 rivalnum = R_SkinAvailable(rivalname); + INT32 rivalnum = R_SkinAvailableEx(rivalname, false); if (rivalnum != skin) continue; @@ -3504,7 +3504,7 @@ INT32 M_UnlockableSkinNum(unlockable_t *unlock) } // Get the skin from the string. - skinnum = R_SkinAvailable(unlock->stringVar); + skinnum = R_SkinAvailableEx(unlock->stringVar, false); if (skinnum != -1) { unlock->stringVarCache = skinnum; diff --git a/src/menus/extras-challenges.c b/src/menus/extras-challenges.c index ff169772e..b6b71957e 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -714,7 +714,7 @@ void M_ChallengesTick(void) INT32 fskin = M_UnlockableFollowerNum(ref); if (fskin != -1) { - INT32 psk = R_SkinAvailable(cv_skin[0].string); + INT32 psk = R_SkinAvailableEx(cv_skin[0].string, false); if (psk == -1) psk = 0; bombcolor = K_GetEffectiveFollowerColor(followers[fskin].defaultcolor, &followers[fskin], cv_playercolor[0].value, &skins[psk]); diff --git a/src/menus/main-goner.cpp b/src/menus/main-goner.cpp index 9331c9a9d..9085d517d 100644 --- a/src/menus/main-goner.cpp +++ b/src/menus/main-goner.cpp @@ -84,7 +84,7 @@ public: { if (!skinName.empty()) { - this->skinID = R_SkinAvailable(skinName.c_str()); + this->skinID = R_SkinAvailableEx(skinName.c_str(), false); } this->offset = offset; diff --git a/src/menus/play-char-select.c b/src/menus/play-char-select.c index 80352f312..aae204783 100644 --- a/src/menus/play-char-select.c +++ b/src/menus/play-char-select.c @@ -203,7 +203,7 @@ static INT16 M_GetMenuCategoryFromFollower(setup_player_t *p) static void M_SetupProfileGridPos(setup_player_t *p) { profile_t *pr = PR_GetProfile(p->profilen); - INT32 i = R_SkinAvailable(pr->skinname); + INT32 i = R_SkinAvailableEx(pr->skinname, false); INT32 alt = 0; // Hey it's my character's name! if (i == -1) @@ -247,7 +247,7 @@ static void M_SetupProfileGridPos(setup_player_t *p) static void M_SetupMidGameGridPos(setup_player_t *p, UINT8 num) { - INT32 i = R_SkinAvailable(cv_skin[num].zstring); + INT32 i = R_SkinAvailableEx(cv_skin[num].zstring, false); INT32 alt = 0; // Hey it's my character's name! if (i == -1) diff --git a/src/p_saveg.c b/src/p_saveg.c index 1720561e2..b6efe3530 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -150,7 +150,7 @@ static boolean P_UnArchivePlayer(savebuffer_t *save) INT32 skin; READSTRINGN(save->p, skinname, SKINNAMESIZE); - skin = R_SkinAvailable(skinname); + skin = R_SkinAvailableEx(skinname, false); if (skin == -1) { @@ -176,7 +176,7 @@ static boolean P_UnArchivePlayer(savebuffer_t *save) savedata.bots[pid].valid = true; READSTRINGN(save->p, skinname, SKINNAMESIZE); - skin = R_SkinAvailable(skinname); + skin = R_SkinAvailableEx(skinname, false); if (skin == -1) { diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 385e2ca3e..905470403 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -7850,7 +7850,7 @@ static void P_LoadRecordGhosts(void) if (sameGhosts) { - INT32 skin = R_SkinAvailable(cv_skin[0].string); + INT32 skin = R_SkinAvailableEx(cv_skin[0].string, false); if (skin < 0 || !R_SkinUsable(-1, skin, false)) skin = 0; // use default skin add_ghosts(fmt::format("{}-{}{}", gpath, skins[skin].name, modeprefix), sameGhosts); diff --git a/src/r_picformats.c b/src/r_picformats.c index 996662886..d87988583 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -1435,7 +1435,7 @@ static void R_ParseSpriteInfoSkin(struct ParseSpriteInfoState *parser) skinName[sprinfoTokenLength] = '\0'; strlwr(skinName); - skinnum = R_SkinAvailable(skinName); + skinnum = R_SkinAvailableEx(skinName, false); if (skinnum == -1) I_Error("Error parsing SPRTINFO lump: Unknown skin \"%s\"", skinName); diff --git a/src/r_skins.c b/src/r_skins.c index 64dcfd1ec..d98577c60 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -136,15 +136,17 @@ static void Sk_SetDefaultValue(skin_t *skin) } // Grab the default skin +#define DEFAULTBOTSKINNAME "eggrobo" UINT8 R_BotDefaultSkin(void) { static INT32 defaultbotskin = -1; + if (demo.playback) + return R_SkinAvailableEx(DEFAULTBOTSKINNAME, true); + if (defaultbotskin == -1) { - const char *defaultbotskinname = "eggrobo"; - - defaultbotskin = R_SkinAvailable(defaultbotskinname); + defaultbotskin = R_SkinAvailableEx(DEFAULTBOTSKINNAME, false); if (defaultbotskin == -1) { @@ -155,6 +157,7 @@ UINT8 R_BotDefaultSkin(void) return (UINT8)defaultbotskin; } +#undef DEFAULTBOTSKINNAME // // Initialize the basic skins @@ -318,10 +321,29 @@ UINT32 R_GetLocalRandomSkin(void) // returns true if the skin name is found (loaded from pwad) // warning return -1 if not found INT32 R_SkinAvailable(const char *name) +{ + return R_SkinAvailableEx(name, true); +} + +INT32 R_SkinAvailableEx(const char *name, boolean demoskins) { INT32 i; UINT32 hash = quickncasehash(name, SKINNAMESIZE); + if (demo.playback && demoskins) + { + for (i = 0; i < demo.numskins; i++) + { + if (demo.skinlist[i].namehash != hash) + continue; + + if (stricmp(demo.skinlist[i].name,name)!=0) + continue; + + return i; + } + } + for (i = 0; i < numskins; i++) { if (skins[i].namehash != hash) @@ -946,7 +968,7 @@ void R_AddSkins(UINT16 wadnum, boolean mainfile) // Others can't go in there because we don't want them to be patchable. if (!stricmp(stoken, "name")) { - INT32 skinnum = R_SkinAvailable(value); + INT32 skinnum = R_SkinAvailableEx(value, false); strlwr(value); if (skinnum == -1) STRBUFCPY(skin->name, value); @@ -961,7 +983,7 @@ void R_AddSkins(UINT16 wadnum, boolean mainfile) snprintf(value2, stringspace, "%s%d", value, numskins); value2[stringspace - 1] = '\0'; - if (R_SkinAvailable(value2) == -1) + if (R_SkinAvailableEx(value2, false) == -1) // I'm lazy so if NEW name is already used I leave the 'skin x' // default skin name set in Sk_SetDefaultValue STRBUFCPY(skin->name, value2); @@ -1141,7 +1163,7 @@ void R_PatchSkins(UINT16 wadnum, boolean mainfile) if (!stricmp(stoken, "name")) { strlwr(value); - skinnum = R_SkinAvailable(value); + skinnum = R_SkinAvailableEx(value, false); if (skinnum != -1) skin = &skins[skinnum]; else diff --git a/src/r_skins.h b/src/r_skins.h index 89f1c2b91..57b12825f 100644 --- a/src/r_skins.h +++ b/src/r_skins.h @@ -112,6 +112,7 @@ void R_PatchSkins(UINT16 wadnum, boolean mainfile); // Access INT32 R_SkinAvailable(const char *name); +INT32 R_SkinAvailableEx(const char *name, boolean demoskins); boolean R_SkinUsable(INT32 playernum, INT32 skinnum, boolean demoskins); UINT8 *R_GetSkinAvailabilities(boolean demolock, INT32 botforcecharacter); From 9b9c2cbcb6441748f53453e94ae34d267e16c9d4 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 4 Mar 2024 17:34:54 +0000 Subject: [PATCH 19/33] M_EndModeAttackRun: Fix recursivity issue that resulted in natural ends to replays losing track of restoreMenu --- src/menus/transient/pause-replay.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index 9c0c777a7..abb0e89cf 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -54,15 +54,22 @@ menu_t PAUSE_PlaybackMenuDef = { void M_EndModeAttackRun(void) { - G_CheckDemoStatus(); // Cancel recording + if (demo.playback) + { + G_CheckDemoStatus(); // Cancel recording + return; + } Command_ExitGame_f(); // Clear a bunch of state + if (!modeattacking) + return; + modeattacking = ATTACKING_NONE; // Kept until now because of Command_ExitGame_f if (demo.attract == DEMO_ATTRACT_TITLE) { - D_StartTitle(); + D_SetDeferredStartTitle(true); } else if (demo.attract == DEMO_ATTRACT_CREDITS) { From 96a6fe85f1088bc76763af07b389260c25d9aa96 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 5 Mar 2024 16:43:27 +0000 Subject: [PATCH 20/33] G_LoadDemoSkins: Actually pass the skin name to R_SkinAvailableEx, idiot Fixes the reported Emerl issue --- src/g_demo.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/g_demo.cpp b/src/g_demo.cpp index 7c472ccba..0610ddf5e 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -2033,7 +2033,6 @@ static void G_SaveDemoSkins(UINT8 **pp) static democharlist_t *G_LoadDemoSkins(savebuffer_t *info, UINT8 *worknumskins, boolean getclosest) { - char skin[17]; UINT8 i, byte, shif; democharlist_t *skinlist = NULL; @@ -2052,8 +2051,6 @@ static democharlist_t *G_LoadDemoSkins(savebuffer_t *info, UINT8 *worknumskins, I_Error("G_LoadDemoSkins: Insufficient memory to allocate list"); } - skin[16] = '\0'; - for (i = 0; i < (*worknumskins); i++) { INT32 result = -1; @@ -2071,7 +2068,7 @@ static democharlist_t *G_LoadDemoSkins(savebuffer_t *info, UINT8 *worknumskins, skinlist[i].kartweight = READUINT8(info->p); skinlist[i].flags = READUINT32(info->p); - result = R_SkinAvailableEx(skin, false); + result = R_SkinAvailableEx(skinlist[i].name, false); if (result == -1) { if (!getclosest) From c299831737f58d211377a139db4457836151b49e Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 4 Mar 2024 19:29:37 +0000 Subject: [PATCH 21/33] Fade out characters you haven't unlocked yet in Time Attack demos exclusively - Objects - Minimap All other HUD items need to be done manually, but the lives icon doesn't show up in time attack so this minimum should be fine --- src/k_hud.cpp | 12 ++++++---- src/r_skins.c | 11 ++++++++-- src/r_skins.h | 1 + src/r_spritefx.cpp | 7 ++++++ src/r_things.cpp | 55 +++++++++++++++++++++++++--------------------- 5 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 87d1095ec..5cdef51e4 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -88,6 +88,7 @@ patch_t *kp_facenum[MAXPLAYERS+1]; static patch_t *kp_facehighlight[8]; static patch_t *kp_nocontestminimap; +static patch_t *kp_unknownminimap; static patch_t *kp_spbminimap; static patch_t *kp_wouldyoustillcatchmeifiwereaworm; static patch_t *kp_catcherminimap; @@ -386,7 +387,7 @@ void K_LoadKartHUDGraphics(void) // Special minimap icons HU_UpdatePatch(&kp_nocontestminimap, "MINIDEAD"); - + HU_UpdatePatch(&kp_unknownminimap, "HUHMAP"); HU_UpdatePatch(&kp_spbminimap, "SPBMMAP"); HU_UpdatePatch(&kp_wouldyoustillcatchmeifiwereaworm, "MINIPROG"); @@ -4401,6 +4402,9 @@ static void K_drawKartMinimap(void) skin = ((skin_t*)g->mo->skin)-skins; else skin = 0; + + workingPic = R_CanShowSkinInDemo(skin) ? faceprefix[skin][FACE_MINIMAP] : kp_unknownminimap; + if (g->mo->color) { if (g->mo->colorized) @@ -4414,7 +4418,7 @@ static void K_drawKartMinimap(void) interpx = R_InterpolateFixed(g->mo->old_x, g->mo->x); interpy = R_InterpolateFixed(g->mo->old_y, g->mo->y); - K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, faceprefix[skin][FACE_MINIMAP], colormap); + K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, workingPic, colormap); g = g->next; } } @@ -4470,7 +4474,7 @@ static void K_drawKartMinimap(void) { skin = ((skin_t*)mobj->skin)-skins; - workingPic = faceprefix[skin][FACE_MINIMAP]; + workingPic = R_CanShowSkinInDemo(skin) ? faceprefix[skin][FACE_MINIMAP] : kp_unknownminimap; if (mobj->color) { @@ -4666,7 +4670,7 @@ static void K_drawKartMinimap(void) { skin = ((skin_t*)mobj->skin)-skins; - workingPic = faceprefix[skin][FACE_MINIMAP]; + workingPic = R_CanShowSkinInDemo(skin) ? faceprefix[skin][FACE_MINIMAP] : kp_unknownminimap; if (mobj->color) { diff --git a/src/r_skins.c b/src/r_skins.c index d98577c60..89e5ff159 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -229,7 +229,7 @@ UINT8 *R_GetSkinAvailabilities(boolean demolock, INT32 botforcecharacter) boolean R_SkinUsable(INT32 playernum, INT32 skinnum, boolean demoskins) { boolean needsunlocked = false; - boolean useplayerstruct = ((Playing() || demo.playback) && playernum != -1); + boolean useplayerstruct = ((Playing() || demo.playback) && playernum >= 0); UINT16 i; INT32 skinid; @@ -299,6 +299,13 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum, boolean demoskins) return (boolean)(gamedata->unlocked[i]); } +boolean R_CanShowSkinInDemo(INT32 skinnum) +{ + if (modeattacking == ATTACKING_NONE && !(demo.playback && demo.attract)) + return true; + return R_SkinUsable(-2, skinnum, false); +} + // Returns a random unlocked skin ID. UINT32 R_GetLocalRandomSkin(void) { @@ -307,7 +314,7 @@ UINT32 R_GetLocalRandomSkin(void) for (i = 0; i < numskins; i++) { - if (!R_SkinUsable(-1, i, false)) + if (!R_SkinUsable(-2, i, false)) continue; grabskins[usableskins++] = i; } diff --git a/src/r_skins.h b/src/r_skins.h index 57b12825f..03816d758 100644 --- a/src/r_skins.h +++ b/src/r_skins.h @@ -115,6 +115,7 @@ INT32 R_SkinAvailable(const char *name); INT32 R_SkinAvailableEx(const char *name, boolean demoskins); boolean R_SkinUsable(INT32 playernum, INT32 skinnum, boolean demoskins); UINT8 *R_GetSkinAvailabilities(boolean demolock, INT32 botforcecharacter); +boolean R_CanShowSkinInDemo(INT32 skinnum); // Setting void SetPlayerSkin(INT32 playernum,const char *skinname); diff --git a/src/r_spritefx.cpp b/src/r_spritefx.cpp index ae3edcf84..af34788ca 100644 --- a/src/r_spritefx.cpp +++ b/src/r_spritefx.cpp @@ -44,6 +44,13 @@ INT32 R_ThingLightLevel(mobj_t* thing) { lightlevel -= 255; } + + if (!R_CanShowSkinInDemo((skin_t*)thing->skin-skins) + && !thing->colorized + && !thing->hitlag) + { + lightlevel -= 128; + } } return lightlevel; diff --git a/src/r_things.cpp b/src/r_things.cpp index 52cb52521..a91eb128f 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -835,37 +835,42 @@ boolean R_ThingIsFlashing(mobj_t *thing) UINT8 *R_GetSpriteTranslation(vissprite_t *vis) { - if (!(vis->cut & SC_PRECIP) && - R_ThingIsFlashing(vis->mobj)) + if (vis->cut & SC_PRECIP) { - return R_GetTranslationColormap(TC_HITLAG, static_cast(0), GTC_CACHE); + // Simplified func, less safe properties to check + if (vis->mobj->color) + R_GetTranslationColormap(TC_DEFAULT, static_cast(vis->mobj->color), GTC_CACHE); + return NULL; } - /* - else if (R_SpriteIsFlashing(vis)) // Bosses "flash" + + size_t skinnum = TC_DEFAULT; + + if (vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player! { - if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized) - return R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); - else if (vis->mobj->type == MT_METALSONIC_BATTLE) - return R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE); - else - return R_GetTranslationColormap(TC_BOSS, 0, GTC_CACHE); - } - */ - else if (vis->mobj->color) - { - // New colormap stuff for skins Tails 06-07-2002 - if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized) - return R_GetTranslationColormap(TC_RAINBOW, static_cast(vis->mobj->color), GTC_CACHE); - else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player! + skinnum = (skin_t*)vis->mobj->skin-skins; + + // Hide not-yet-unlocked characters in replays from other people + if (!R_CanShowSkinInDemo(skinnum)) { - size_t skinnum = (skin_t*)vis->mobj->skin-skins; - return R_GetTranslationColormap((INT32)skinnum, static_cast(vis->mobj->color), GTC_CACHE); + skinnum = TC_BLINK; } - else // Use the defaults - return R_GetTranslationColormap(TC_DEFAULT, static_cast(vis->mobj->color), GTC_CACHE); } - else if (vis->mobj->sprite == SPR_PLAY) // Looks like a player, but doesn't have a color? Get rid of green sonic syndrome. - return R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_BLUE, GTC_CACHE); + + if (R_ThingIsFlashing(vis->mobj)) + { + if (skinnum != (size_t)TC_BLINK) + skinnum = TC_HITLAG; + + return R_GetTranslationColormap(skinnum, static_cast(0), GTC_CACHE); + } + + if (vis->mobj->color) + { + if (skinnum != (size_t)TC_BLINK && vis->mobj->colorized) + skinnum = TC_RAINBOW; + + return R_GetTranslationColormap(skinnum, static_cast(vis->mobj->color), GTC_CACHE); + } return NULL; } From 99e4975023ec26612eb88f489798a286093594f5 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 5 Mar 2024 15:00:22 -0700 Subject: [PATCH 22/33] Sting clarity --- src/k_hud.cpp | 14 +++++++++++++- src/k_kart.c | 5 +++++ src/sounds.c | 3 +++ src/sounds.h | 3 +++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 87d1095ec..e2b1d6794 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -2957,7 +2957,19 @@ static void K_drawRingCounter(boolean gametypeinfoshown) rn[0] = ((abs(stplyr->hudrings) / 10) % 10); rn[1] = (abs(stplyr->hudrings) % 10); - if (stplyr->hudrings <= 0 && (leveltime/5 & 1)) // In debt + if (stplyr->hudrings <= 0 && stplyr->ringvisualwarning > 1) + { + colorring = true; + if ((leveltime/2 & 1)) + { + ringmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_CRIMSON, GTC_CACHE); + } + else + { + ringmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_WHITE, GTC_CACHE); + } + } + else if (stplyr->hudrings <= 0 && (leveltime/5 & 1)) // In debt { ringmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_CRIMSON, GTC_CACHE); colorring = true; diff --git a/src/k_kart.c b/src/k_kart.c index 8f947d80d..df8fa9aeb 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4819,6 +4819,11 @@ void K_DebtStingPlayer(player_t *player, mobj_t *source) player->spinouttimer = length; player->wipeoutslow = min(length-1, wipeoutslowtime+1); + player->ringvisualwarning = TICRATE*2; + + if (P_IsDisplayPlayer(player)) + S_StartSoundAtVolume(NULL, sfx_sting0, 170); + P_SetPlayerMobjState(player->mo, S_KART_SPINOUT); } diff --git a/src/sounds.c b/src/sounds.c index 14ccca9cb..527e6b2ad 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1520,6 +1520,9 @@ sfxinfo_t S_sfx[NUMSFX] = {"tmxbdn", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Button down {"tmxbup", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Button up + // SMS + {"sting0", false, 64, 2, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Ring loss + // SRB2kart - Skin sounds {"kwin", false, 64, 96, -1, NULL, 0, SKSKWIN, -1, LUMPERROR, ""}, {"klose", false, 64, 96, -1, NULL, 0, SKSKLOSE, -1, LUMPERROR, ""}, diff --git a/src/sounds.h b/src/sounds.h index 532c844be..0aef7e7bc 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1596,6 +1596,9 @@ typedef enum sfx_tmxbdn, sfx_tmxbup, + // SMS + sfx_sting0, + // And LASTLY, Kart's skin sounds. sfx_kwin, sfx_klose, From a280ccb7de7bc90c5099077a0faaa1d06c84fd16 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 5 Mar 2024 16:00:00 -0700 Subject: [PATCH 23/33] Use old Ring Sting noise --- src/d_player.h | 1 + src/k_kart.c | 10 +++++++--- src/lua_playerlib.c | 4 ++++ src/p_saveg.c | 2 ++ src/sounds.c | 3 +++ src/sounds.h | 3 +++ 6 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index ab30fc934..a915ab22e 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -993,6 +993,7 @@ struct player_t boolean markedfordeath; boolean dotrickfx; + boolean stingfx; UINT8 bumperinflate; UINT8 ringboxdelay; // Delay until Ring Box auto-activates diff --git a/src/k_kart.c b/src/k_kart.c index a9db55a03..38146d30b 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4820,9 +4820,7 @@ void K_DebtStingPlayer(player_t *player, mobj_t *source) player->wipeoutslow = min(length-1, wipeoutslowtime+1); player->ringvisualwarning = TICRATE*2; - - if (P_IsDisplayPlayer(player)) - S_StartSoundAtVolume(NULL, sfx_sting0, 170); + player->stingfx = true; P_SetPlayerMobjState(player->mo, S_KART_SPINOUT); } @@ -8979,6 +8977,12 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->dotrickfx = false; } + if (player->stingfx && !player->mo->hitlag) + { + S_StartSound(player->mo, sfx_s226l); + player->stingfx = false; + } + // Don't screw up chain ring pickup/usage with instawhip charge. // If the button stays held, delay charge a bit. if (player->instaWhipChargeLockout) diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index b323b3ca8..81031d7b9 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -267,6 +267,8 @@ static int player_get(lua_State *L) lua_pushboolean(L, plr->ringvisualwarning); else if (fastcmp(field,"dotrickfx")) lua_pushboolean(L, plr->dotrickfx); + else if (fastcmp(field,"stingfx")) + lua_pushboolean(L, plr->stingfx); else if (fastcmp(field,"bumperinflate")) lua_pushboolean(L, plr->bumperinflate); else if (fastcmp(field,"ringboxdelay")) @@ -811,6 +813,8 @@ static int player_set(lua_State *L) plr->markedfordeath = luaL_checkboolean(L, 3); else if (fastcmp(field,"dotrickfx")) plr->dotrickfx = luaL_checkboolean(L, 3); + else if (fastcmp(field,"stingfx")) + plr->stingfx = luaL_checkboolean(L, 3); else if (fastcmp(field,"bumperinflate")) plr->bumperinflate = luaL_checkboolean(L, 3); else if (fastcmp(field,"ringboxdelay")) diff --git a/src/p_saveg.c b/src/p_saveg.c index dbbc95339..5c36f7a4d 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -604,6 +604,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].markedfordeath); WRITEUINT8(save->p, players[i].dotrickfx); + WRITEUINT8(save->p, players[i].stingfx); WRITEUINT8(save->p, players[i].bumperinflate); WRITEUINT8(save->p, players[i].ringboxdelay); @@ -1191,6 +1192,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].markedfordeath = READUINT8(save->p); players[i].dotrickfx = READUINT8(save->p); + players[i].stingfx = READUINT8(save->p); players[i].bumperinflate = READUINT8(save->p); players[i].ringboxdelay = READUINT8(save->p); diff --git a/src/sounds.c b/src/sounds.c index 527e6b2ad..537b382dc 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1523,6 +1523,9 @@ sfxinfo_t S_sfx[NUMSFX] = // SMS {"sting0", false, 64, 2, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Ring loss + // Patching up base sounds + {"s226l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // s2 spikes LOUD + // SRB2kart - Skin sounds {"kwin", false, 64, 96, -1, NULL, 0, SKSKWIN, -1, LUMPERROR, ""}, {"klose", false, 64, 96, -1, NULL, 0, SKSKLOSE, -1, LUMPERROR, ""}, diff --git a/src/sounds.h b/src/sounds.h index 0aef7e7bc..e48b39f88 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1599,6 +1599,9 @@ typedef enum // SMS sfx_sting0, + // Patch-up + sfx_s226l, + // And LASTLY, Kart's skin sounds. sfx_kwin, sfx_klose, From 136bb810e23133919fc2063d12da5de1da23767a Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 5 Mar 2024 16:15:41 -0700 Subject: [PATCH 24/33] Restore fucking thing --- src/k_kart.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/k_kart.c b/src/k_kart.c index 38146d30b..f3ffbd072 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4822,6 +4822,9 @@ void K_DebtStingPlayer(player_t *player, mobj_t *source) player->ringvisualwarning = TICRATE*2; player->stingfx = true; + if (P_IsDisplayPlayer(player)) + S_StartSound(NULL, sfx_sting0); + P_SetPlayerMobjState(player->mo, S_KART_SPINOUT); } From b458e28a5251c94a0fc0779598eaa6eb4d303d3c Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 5 Mar 2024 16:42:22 -0700 Subject: [PATCH 25/33] Transparent Ring Debt indicator for local player, if it's sticking around --- src/d_player.h | 2 +- src/k_kart.c | 52 +++++++++++++++++++++++++++----------------------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index a915ab22e..4630224dc 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -987,7 +987,7 @@ struct player_t INT16 incontrol; // -1 to -175 when spinning out or tumbling, 1 to 175 when not. Use to check for combo hits or emergency inputs. UINT16 progressivethrust; // When getting beat up in GTR_BUMPERS, speed up the longer you've been out of control. - UINT8 ringvisualwarning; + UINT8 ringvisualwarning; // Check with > 1, not >= 1! Set when put in debt, counts down and holds at 1 when still in debt. boolean analoginput; // Has an input been recorded that requires analog usage? For input display. diff --git a/src/k_kart.c b/src/k_kart.c index f3ffbd072..3d54d64b3 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8429,32 +8429,36 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) // Battle: spawn zero-bumpers indicator if ((gametyperules & GTR_SPHERES) ? player->mo->health <= 1 : player->rings <= 0) { - mobj_t *debtflag = P_SpawnMobj(player->mo->x + player->mo->momx, player->mo->y + player->mo->momy, - player->mo->z + P_GetMobjZMovement(player->mo) + player->mo->height + (24*player->mo->scale), MT_THOK); + UINT8 doubler; - P_SetMobjState(debtflag, S_RINGDEBT); - P_SetScale(debtflag, (debtflag->destscale = player->mo->scale)); - - K_MatchGenericExtraFlags(debtflag, player->mo); - debtflag->frame += (leveltime % 4); - - if ((leveltime/12) & 1) - debtflag->frame += 4; - - debtflag->color = player->skincolor; - debtflag->fuse = 2; - - if (!(gametyperules & GTR_SPHERES)) + // GROSS. In order to have a transparent version of this for a splitscreen local player, we actually need to spawn two! + for (doubler = 0; doubler < 2; doubler++) { - P_SetScale(debtflag, - Easing_InQuint( - min(FRACUNIT, FRACUNIT*player->ringvisualwarning/(TICRATE*3)), - debtflag->scale, - debtflag->scale*2 - ) - ); - if (player->ringvisualwarning <= 1) - debtflag->renderflags = K_GetPlayerDontDrawFlag(player); + mobj_t *debtflag = P_SpawnMobj(player->mo->x + player->mo->momx, player->mo->y + player->mo->momy, + player->mo->z + P_GetMobjZMovement(player->mo) + player->mo->height + (24*player->mo->scale), MT_THOK); + + P_SetMobjState(debtflag, S_RINGDEBT); + P_SetScale(debtflag, (debtflag->destscale = player->mo->scale)); + + K_MatchGenericExtraFlags(debtflag, player->mo); + debtflag->frame += (leveltime % 4); + + if ((leveltime/12) & 1) + debtflag->frame += 4; + + debtflag->color = player->skincolor; + debtflag->fuse = 2; + + if (doubler == 0) // Real copy. Draw for everyone but us. + { + debtflag->renderflags |= K_GetPlayerDontDrawFlag(player); + } + else if (doubler == 1) // Fake copy. Draw for only us, and go transparent after a bit. + { + debtflag->renderflags |= (RF_DONTDRAW & ~K_GetPlayerDontDrawFlag(player)); + if (player->ringvisualwarning <= 1 || gametyperules & GTR_SPHERES) + debtflag->renderflags |= RF_TRANS50; + } } } From 1bfd8fe66d9723b4548344c7e76606449d0182a6 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 5 Mar 2024 17:22:02 -0700 Subject: [PATCH 26/33] Use thintimer font for ring counter in 1P/2P --- src/k_hud.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index e2b1d6794..7245cb4c5 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -3080,16 +3080,24 @@ static void K_drawRingCounter(boolean gametypeinfoshown) V_DrawMappedPatch(LAPS_X+ringx+7, fy-5, V_HUDTRANS|V_SLIDEIN|splitflags|ringflip, kp_ring[ringanim_realframe], (colorring ? ringmap : NULL)); + // "Why fy-4? Why LAPS_X+29+1?" + // "use magic numbers" - jartha 2024-03-05 if (stplyr->hudrings < 0) // Draw the minus for ring debt { - V_DrawMappedPatch(LAPS_X+23, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_ringdebtminus, ringmap); - V_DrawMappedPatch(LAPS_X+29, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[rn[0]], ringmap); - V_DrawMappedPatch(LAPS_X+35, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[rn[1]], ringmap); + V_DrawMappedPatch(LAPS_X+23-1, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_ringdebtminus, ringmap); + using srb2::Draw; + Draw row = Draw(LAPS_X+29+0, fy-4).flags(V_HUDTRANS|V_SLIDEIN|splitflags).font(Draw::Font::kThinTimer).colormap(ringmap); + row.text("{:02}", abs(stplyr->hudrings)); + // V_DrawMappedPatch(LAPS_X+29, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[TALLNUM_FONT].font[rn[0]], ringmap); + // V_DrawMappedPatch(LAPS_X+35, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[TALLNUM_FONT].font[rn[1]], ringmap); } else { - V_DrawMappedPatch(LAPS_X+23, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[rn[0]], ringmap); - V_DrawMappedPatch(LAPS_X+29, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[rn[1]], ringmap); + using srb2::Draw; + Draw row = Draw(LAPS_X+23+3, fy-4).flags(V_HUDTRANS|V_SLIDEIN|splitflags).font(Draw::Font::kThinTimer).colormap(ringmap); + row.text("{:02}", abs(stplyr->hudrings)); + // V_DrawMappedPatch(LAPS_X+23, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[TALLNUM_FONT].font[rn[0]], ringmap); + // V_DrawMappedPatch(LAPS_X+29, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[TALLNUM_FONT].font[rn[1]], ringmap); } // SPB ring lock From 0bb4fa5960086cc60173748b00d4c872e8d4ee9f Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 5 Mar 2024 17:46:47 -0700 Subject: [PATCH 27/33] Lower SMS sting sound, again --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 3d54d64b3..a68293cf4 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4823,7 +4823,7 @@ void K_DebtStingPlayer(player_t *player, mobj_t *source) player->stingfx = true; if (P_IsDisplayPlayer(player)) - S_StartSound(NULL, sfx_sting0); + S_StartSoundAtVolume(NULL, sfx_sting0, 200); P_SetPlayerMobjState(player->mo, S_KART_SPINOUT); } From bea1cccdded7f8314d6c1d9e95fccf198794abc5 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 5 Mar 2024 16:16:05 -0800 Subject: [PATCH 28/33] Virtual Keyboard: rewrite keyboard-gamepad switching - Input handling is done straight in G_MapEventsToControls - If a keyboard event is received, switch off virtual keyboard - Removed the input lock while virtual keyboard is sliding away - If a gamepad event is received, and it is a change of at least half the full range, switch on virtual keyboard --- src/cvars.cpp | 1 + src/g_demo.cpp | 1 - src/g_input.c | 12 +++ src/k_menu.h | 3 +- src/k_menufunc.c | 13 +-- src/menus/transient/virtual-keyboard.c | 110 +++++++++---------------- 6 files changed, 55 insertions(+), 85 deletions(-) diff --git a/src/cvars.cpp b/src/cvars.cpp index 5737da301..320fe1d3b 100644 --- a/src/cvars.cpp +++ b/src/cvars.cpp @@ -890,6 +890,7 @@ consvar_t cv_debugrender_freezebsp = PlayerCheat("debugrender_freezebsp", "Off") consvar_t cv_debugrender_portal = PlayerCheat("debugrender_portal", "Off").on_off().description("Highlight visual portals in red"); consvar_t cv_debugrender_spriteclip = PlayerCheat("debugrender_spriteclip", "Off").on_off().description("Let sprites draw through walls"); consvar_t cv_debugrender_visplanes = PlayerCheat("debugrender_visplanes", "Off").on_off().description("Highlight the number of visplanes"); +consvar_t cv_debugvirtualkeyboard = PlayerCheat("debugvirtualkeyboard", "Off").on_off().description("Always show virtual keyboard instead of using real keyboard input."); consvar_t cv_devmode_screen = PlayerCheat("devmode_screen", "1").min_max(1, 4).description("Choose which splitscreen player devmode applies to"); consvar_t cv_drawpickups = PlayerCheat("drawpickups", "Yes").yes_no().description("Hide rings, spheres, item capsules, prison capsules (visual only)"); diff --git a/src/g_demo.cpp b/src/g_demo.cpp index 444138b21..cdd5aa8ca 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -4131,7 +4131,6 @@ boolean G_CheckDemoTitleEntry(void) demo.willsave = true; M_OpenVirtualKeyboard( - false, sizeof demo.titlename, [](const char* replace) -> const char* { diff --git a/src/g_input.c b/src/g_input.c index 279cae0f3..8c3d61a98 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -418,6 +418,12 @@ static INT32 AssignDeviceToFirstUnassignedPlayer(INT32 device) return -1; } +static void update_vkb_axis(INT32 axis) +{ + if (axis > JOYAXISRANGE/2) + M_SwitchVirtualKeyboard(true); +} + // // Remaps the inputs to game controls. // @@ -460,6 +466,8 @@ void G_MapEventsToControls(event_t *ev) case ev_keydown: if (ev->data1 < NUMINPUTS) { + M_MenuTypingInput(ev->data1); + if (ev->data2) // OS repeat? We handle that ourselves { break; @@ -556,11 +564,13 @@ void G_MapEventsToControls(event_t *ev) if (ev->data2 != INT32_MAX) { DeviceGameKeyDownArray[KEY_AXIS1 + (JOYANALOGS * 4) + (i * 2)] = max(0, ev->data2); + update_vkb_axis(max(0, ev->data2)); } if (ev->data3 != INT32_MAX) { DeviceGameKeyDownArray[KEY_AXIS1 + (JOYANALOGS * 4) + (i * 2) + 1] = max(0, ev->data3); + update_vkb_axis(max(0, ev->data3)); } } else @@ -592,6 +602,7 @@ void G_MapEventsToControls(event_t *ev) DeviceGameKeyDownArray[KEY_AXIS1 + (i * 4)] = 0; DeviceGameKeyDownArray[KEY_AXIS1 + (i * 4) + 1] = abs(ev->data2); } + update_vkb_axis(abs(ev->data2)); } if (ev->data3 != INT32_MAX) @@ -608,6 +619,7 @@ void G_MapEventsToControls(event_t *ev) DeviceGameKeyDownArray[KEY_AXIS1 + (i * 4) + 2] = 0; DeviceGameKeyDownArray[KEY_AXIS1 + (i * 4) + 3] = abs(ev->data3); } + update_vkb_axis(abs(ev->data3)); } } break; diff --git a/src/k_menu.h b/src/k_menu.h index 2088a8470..044559c06 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -686,9 +686,10 @@ void M_PlayMenuJam(void); boolean M_ConsiderSealedSwapAlert(void); -void M_OpenVirtualKeyboard(boolean gamepad, size_t cachelen, vkb_query_fn_t queryfn, menu_t *dummymenu); +void M_OpenVirtualKeyboard(size_t cachelen, vkb_query_fn_t queryfn, menu_t *dummymenu); void M_AbortVirtualKeyboard(void); void M_MenuTypingInput(INT32 key); +void M_SwitchVirtualKeyboard(boolean gamepad); void M_QuitResponse(INT32 ch); void M_QuitSRB2(INT32 choice); diff --git a/src/k_menufunc.c b/src/k_menufunc.c index dc86b141c..881b9b044 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -275,8 +275,6 @@ static boolean M_GamestateCanOpenMenu(void) // boolean M_Responder(event_t *ev) { - boolean menuKeyJustChanged = false; - if (dedicated || (demo.playback && demo.attract) || M_GamestateCanOpenMenu() == false) @@ -311,7 +309,6 @@ boolean M_Responder(event_t *ev) { // Record keyboard presses menuKey = ev->data1; - menuKeyJustChanged = true; } // Profiles: Control mapping. @@ -457,12 +454,6 @@ boolean M_Responder(event_t *ev) return false; } - // Typing for CV_IT_STRING - if (menuKeyJustChanged && menutyping.active && !menutyping.menutypingclose && menutyping.keyboardtyping) - { - M_ChangeStringCvar(menuKey); - } - // We're in the menu itself now. // M_Ticker will take care of the rest. return true; @@ -1097,7 +1088,7 @@ static void M_HandleMenuInput(void) // Typing for CV_IT_STRING if (menutyping.active) { - M_MenuTypingInput(thisMenuKey); + M_MenuTypingInput(-1); return; } @@ -1136,7 +1127,7 @@ static void M_HandleMenuInput(void) if (M_MenuConfirmPressed(pid)) { // If we entered this menu by pressing a menu Key, default to keyboard typing, otherwise use controller. - M_OpenVirtualKeyboard(thisMenuKey == -1, MAXSTRINGLENGTH, M_QueryCvarAction, NULL); + M_OpenVirtualKeyboard(MAXSTRINGLENGTH, M_QueryCvarAction, NULL); return; } else if (M_MenuExtraPressed(pid)) diff --git a/src/menus/transient/virtual-keyboard.c b/src/menus/transient/virtual-keyboard.c index 4204dce09..cb28ee157 100644 --- a/src/menus/transient/virtual-keyboard.c +++ b/src/menus/transient/virtual-keyboard.c @@ -196,18 +196,22 @@ void M_AbortVirtualKeyboard(void) M_GoBack(0); } -static boolean M_IsTypingKey(INT32 key) -{ - return key == KEY_BACKSPACE || key == KEY_ENTER - || key == KEY_ESCAPE || key == KEY_DEL - || key == KEY_LCTRL || key == KEY_RCTRL - || isprint(key); -} - void M_MenuTypingInput(INT32 key) { const UINT8 pid = 0; + // Determine when to check for keyboard inputs or controller inputs using menuKey, which is the key passed here as argument. + if (key > 0) + { + boolean gamepad = (key >= NUMKEYS); + M_SwitchVirtualKeyboard(gamepad); + if (gamepad) + return; + } + + if (!menutyping.active) + return; + // Fade-in if (menutyping.menutypingclose) @@ -233,6 +237,25 @@ void M_MenuTypingInput(INT32 key) menutyping.menutypingfade++; } + if (menutyping.menutypingfade >= 9) // either is visible + { + if (key == KEY_ENTER || key == KEY_ESCAPE) + { + M_CloseVirtualKeyboard(); + + M_SetMenuDelay(pid); + S_StartSound(NULL, sfx_s3k5b); + + return; + } + + if (menutyping.keyboardtyping) + { + M_ChangeStringCvar(key); + return; + } + } + if (menutyping.menutypingfade != destination) { // Don't allow typing until it's fully opened. @@ -240,68 +263,6 @@ void M_MenuTypingInput(INT32 key) } } - // Determine when to check for keyboard inputs or controller inputs using menuKey, which is the key passed here as argument. - if (!menutyping.keyboardtyping) // controller inputs - { - // we pressed a keyboard input that's not any of our buttons - if (key >= 0 && M_IsTypingKey(key) && menucmd[pid].dpad_lr == 0 && menucmd[pid].dpad_ud == 0 - && !(menucmd[pid].buttons & MBT_A) - && !(menucmd[pid].buttons & MBT_B) - && !(menucmd[pid].buttons & MBT_C) - && !(menucmd[pid].buttons & MBT_X) - && !(menucmd[pid].buttons & MBT_Y) - && !(menucmd[pid].buttons & MBT_Z) - && !(menucmd[pid].buttons & MBT_START)) - { - menutyping.keyboardtyping = true; - } - } - else // Keyboard inputs. - { - // On the flipside, if we're pressing any keyboard input, switch to controller inputs. - if (key >= 0 && !M_IsTypingKey(key) && ( - M_MenuButtonPressed(pid, MBT_A) - || M_MenuButtonPressed(pid, MBT_B) - || M_MenuButtonPressed(pid, MBT_C) - || M_MenuButtonPressed(pid, MBT_X) - || M_MenuButtonPressed(pid, MBT_Y) - || M_MenuButtonPressed(pid, MBT_Z) - || M_MenuButtonPressed(pid, MBT_START) - || (menucmd[pid].dpad_lr != 0 && menucmd[pid].prev_dpad_lr == 0) - || (menucmd[pid].dpad_ud != 0 && menucmd[pid].prev_dpad_ud != 0) - )) - { - /*CONS_Printf("key is %d, \ - %c%c%c-%c%c%c-%c-%c%c%c%c\n", - key, - M_MenuButtonPressed(pid, MBT_A) ? 'A' : ' ', - M_MenuButtonPressed(pid, MBT_B) ? 'B' : ' ', - M_MenuButtonPressed(pid, MBT_C) ? 'C' : ' ', - M_MenuButtonPressed(pid, MBT_X) ? 'X' : ' ', - M_MenuButtonPressed(pid, MBT_Y) ? 'Y' : ' ', - M_MenuButtonPressed(pid, MBT_Z) ? 'Z' : ' ', - M_MenuButtonPressed(pid, MBT_START) ? '+' : ' ', - menucmd[pid].dpad_lr < 0 ? '<' : ' ', - menucmd[pid].dpad_ud > 0 ? '^' : ' ', - menucmd[pid].dpad_ud < 0 ? 'v' : ' ', - menucmd[pid].dpad_lr > 0 ? '>' : ' ' - );*/ - menutyping.keyboardtyping = false; - return; - } - - // OTHERWISE, process keyboard inputs for typing! - if (key == KEY_ENTER || key == KEY_ESCAPE) - { - M_CloseVirtualKeyboard(); - - M_SetMenuDelay(pid); - S_StartSound(NULL, sfx_s3k5b); - - return; - } - } - if (menucmd[pid].delay == 0 && !menutyping.keyboardtyping) // We must check for this here because we bypass the normal delay check to allow for normal keyboard inputs { if (menucmd[pid].dpad_ud > 0) // down @@ -418,9 +379,8 @@ void M_MenuTypingInput(INT32 key) } } -void M_OpenVirtualKeyboard(boolean gamepad, size_t cachelen, vkb_query_fn_t queryfn, menu_t *dummymenu) +void M_OpenVirtualKeyboard(size_t cachelen, vkb_query_fn_t queryfn, menu_t *dummymenu) { - menutyping.keyboardtyping = !gamepad; menutyping.active = true; menutyping.menutypingclose = false; @@ -443,3 +403,9 @@ void M_OpenVirtualKeyboard(boolean gamepad, size_t cachelen, vkb_query_fn_t quer M_SetupNextMenu(dummymenu, true); } } + +void M_SwitchVirtualKeyboard(boolean gamepad) +{ + extern consvar_t cv_debugvirtualkeyboard; + menutyping.keyboardtyping = cv_debugvirtualkeyboard.value ? false : !gamepad; +} From ef4aab8d06bf718ac81f706a2fce32c21503ef2d Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 5 Mar 2024 12:35:02 -0800 Subject: [PATCH 29/33] M_AbortVirtualKeyboard: reset menutypingfade too If the menu is closed immediately after virtual keyboard begins closing, the keyboard would open instantly next time (no animation). --- src/menus/transient/virtual-keyboard.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/menus/transient/virtual-keyboard.c b/src/menus/transient/virtual-keyboard.c index 4204dce09..a3bf3c49d 100644 --- a/src/menus/transient/virtual-keyboard.c +++ b/src/menus/transient/virtual-keyboard.c @@ -190,6 +190,7 @@ void M_AbortVirtualKeyboard(void) return; menutyping.active = false; + menutyping.menutypingfade = 0; Z_Free(menutyping.cache); if (currentMenu == menutyping.dummymenu) From 0b3d1ac705990d80f030391f05b5d39d9ad0b349 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 5 Mar 2024 12:36:48 -0800 Subject: [PATCH 30/33] Menus: draw message box over virtual keyboard Message box has input priority, so it should have drawing priority too. --- src/k_menudraw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index ea8a4b665..0c1c7cb13 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -999,12 +999,12 @@ void M_Drawer(void) F_VersionDrawer(); } - // Draw message overlay when needed - M_DrawMenuMessage(); - // Draw typing overlay when needed, above all other menu elements. if (menutyping.active) M_DrawMenuTyping(); + + // Draw message overlay when needed + M_DrawMenuMessage(); } if (menuwipe) From 179597e70d781b07b7fb1d6c71ba9cfb4139367c Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 5 Mar 2024 12:44:22 -0800 Subject: [PATCH 31/33] Menus/Online: light redesign - Mostly hijacks the gamemode menu format (Local Play) - Host - Select gametype (Race, Battle) - Shortcuts to Gameplay Options and Server Options - Select map - Browser - Unchanged - Direct Join - Press A to enter an IP address - Press C to reconnect to the last joined server - Left/right cycles through the server history --- src/cvars.cpp | 1 + src/k_menu.h | 23 ++++- src/k_menudraw.c | 71 +++++++++++++--- src/menus/options-1.c | 24 ++++-- src/menus/play-local-race-difficulty.c | 2 +- src/menus/play-online-1.c | 112 +++++++++++++++++++++++-- src/menus/play-online-host.c | 38 +++++++-- src/menus/play-online-join-ip.c | 1 - 8 files changed, 237 insertions(+), 35 deletions(-) diff --git a/src/cvars.cpp b/src/cvars.cpp index 5737da301..25cb3f402 100644 --- a/src/cvars.cpp +++ b/src/cvars.cpp @@ -926,6 +926,7 @@ consvar_t cv_dummygpdifficulty = MenuDummy("dummygpdifficulty", "Normal").values consvar_t cv_dummygpencore = MenuDummy("dummygpencore", "Off").on_off(); consvar_t cv_dummyip = MenuDummy("dummyip", ""); +consvar_t cv_dummyipselect = MenuDummy("dummyipselect", "0").min_max(0, 2); extern CV_PossibleValue_t dummykartspeed_cons_t[]; consvar_t cv_dummykartspeed = MenuDummy("dummykartspeed", "Gear 2").values(dummykartspeed_cons_t); diff --git a/src/k_menu.h b/src/k_menu.h index 2088a8470..ec775a233 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -295,10 +295,26 @@ extern menu_t PLAY_MP_OptSelectDef; typedef enum { + mp_host = 0, + mp_browse, + mp_directjoin, + mp_back, +} mp_e; + +typedef enum +{ + mhost_gametype = 0, + mhost_gameplay_options, + mhost_server_options, + mhost_boxend, + mhost_mapselect = mhost_boxend, + mhost_back, + + // TODO, remove these (old code) mhost_sname = 0, mhost_public, mhost_maxp, - mhost_gametype, + //mhost_gametype, mhost_go, } mhost_e; @@ -1058,6 +1074,8 @@ void M_OptionsChangeBGColour(INT16 newcolour); // changes the background colour void M_VideoOptions(INT32 choice); void M_SoundOptions(INT32 choice); +void M_GameplayOptions(INT32 choice); +void M_ServerOptions(INT32 choice); void M_HandleItemToggles(INT32 choice); // For item toggling void M_EraseData(INT32 choice); // For data erasing @@ -1091,6 +1109,9 @@ void M_HandleVideoModes(INT32 ch); // data stuff void M_HandleProfileErase(INT32 choice); +// Draws "List via" at the bottom of the screen. +void M_DrawMasterServerReminder(void); + // Draws the EGGA CHANNEL background. void M_DrawEggaChannel(void); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 0c1c7cb13..d90fda389 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1222,6 +1222,38 @@ void M_DrawGenericMenu(void) static tic_t gm_flipStart; +static INT32 M_DrawRejoinIP(INT32 x, INT32 y, INT32 tx) +{ + extern consvar_t cv_dummyipselect; + char (*ip)[MAX_LOGIP] = joinedIPlist[cv_dummyipselect.value]; + if (!*ip[0]) + return 0; + + INT16 shift = 20; + x -= shift; + + INT16 j = 0; + for (j=0; j <= (GM_YOFFSET + 10) / 2; j++) + { + // Draw rectangles that look like the current selected item starting from the top of the actual selection graphic and going up to where it's supposed to go. + // With colour 169 (that's the index of the shade of black the plague colourization gives us. ...No I don't like using a magic number either. + V_DrawFill((x-1) + j, y + (2*j), 226, 2, 169); + } + + x += GM_XOFFSET + 14; + y += GM_YOFFSET; + + const char *text = ip[0]; + INT32 w = V_ThinStringWidth(text, 0); + INT32 f = highlightflags; + V_DrawMenuString(x - 10 - (skullAnimCounter/5), y, f, "\x1C"); // left arrow + V_DrawMenuString(x + w + 2+ (skullAnimCounter/5), y, f, "\x1D"); // right arrow + V_DrawThinString(x, y, f, text); + V_DrawRightAlignedThinString(BASEVIDWIDTH + 4 + tx, y, V_ORANGEMAP, "\xAC Rejoin"); + + return shift; +} + // // M_DrawKartGamemodeMenu // @@ -1266,10 +1298,19 @@ void M_DrawKartGamemodeMenu(void) } INT32 cx = x; + boolean selected = (i == itemOn && menutransition.tics == menutransition.dest); - if (i == itemOn && menutransition.tics == menutransition.dest) + if (selected) { - cx -= Easing_OutSine(M_DueFrac(gm_flipStart, GM_FLIPTIME), 0, GM_XOFFSET / 2); + fixed_t f = M_DueFrac(gm_flipStart, GM_FLIPTIME); + cx -= Easing_OutSine(f, 0, (GM_XOFFSET / 2)); + + // Direct Join + if (currentMenu == &PLAY_MP_OptSelectDef && i == mp_directjoin) + { + INT32 shift = M_DrawRejoinIP(cx, y, cx - x); + cx -= Easing_OutSine(f, 0, shift); + } } type = (currentMenu->menuitems[i].status & IT_DISPLAY); @@ -1281,7 +1322,7 @@ void M_DrawKartGamemodeMenu(void) { UINT8 *colormap = NULL; - if (i == itemOn && menutransition.tics == menutransition.dest) + if (selected) { colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_CACHE); } @@ -2550,7 +2591,7 @@ void M_DrawRaceDifficulty(void) for (i = 0; i < currentMenu->numitems; i++) { - if (i >= drace_boxend) + if (i >= currentMenu->extra1) { x = GM_STARTX + (GM_XOFFSET * 5 / 2); y = GM_STARTY + (GM_YOFFSET * 5 / 2); @@ -2615,7 +2656,7 @@ void M_DrawRaceDifficulty(void) { colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_CACHE); - if (i >= drace_boxend) + if (i >= currentMenu->extra1) { cx -= Easing_OutSine(M_DueFrac(gm_flipStart, GM_FLIPTIME), 0, GM_XOFFSET / 2); } @@ -2626,17 +2667,21 @@ void M_DrawRaceDifficulty(void) } - if (currentMenu->menuitems[i].status & IT_CVAR) + if (currentMenu->menuitems[i].status & (IT_CVAR | IT_ARROWS)) { INT32 fx = (cx - tx); INT32 centx = fx + (320-fx)/2 + (tx); // undo the menutransition movement to redo it here otherwise the text won't move at the same speed lole. - // implicitely we'll only take care of normal consvars - consvar_t *cv = currentMenu->menuitems[i].itemaction.cvar; + const char *val = currentMenu->menuitems[i].text; + if (currentMenu->menuitems[i].status & IT_CVAR) + { + consvar_t *cv = currentMenu->menuitems[i].itemaction.cvar; + val = cv->string; + } V_DrawFixedPatch(cx*FRACUNIT, y*FRACUNIT, FRACUNIT, 0, W_CachePatchName("MENUSHRT", PU_CACHE), colormap); - V_DrawCenteredGamemodeString(centx, y - 3, 0, colormap, cv->string); + V_DrawCenteredGamemodeString(centx, y - 3, 0, colormap, val); if (i == itemOn) { @@ -2656,7 +2701,7 @@ void M_DrawRaceDifficulty(void) x += GM_XOFFSET; y += GM_YOFFSET; - if (i < drace_boxend) + if (i < currentMenu->extra1) { y += 2; // extra spacing for Match Race options } @@ -3715,7 +3760,7 @@ void M_DrawTimeAttack(void) // NOTE: This is pretty rigid and only intended for use with the multiplayer options menu which has *3* choices. -static void M_DrawMasterServerReminder(void) +void M_DrawMasterServerReminder(void) { // Did you change the Server Browser address? Have a little reminder. @@ -3725,7 +3770,7 @@ static void M_DrawMasterServerReminder(void) else mservflags = warningflags; - INT32 y = BASEVIDHEIGHT - 24; + INT32 y = BASEVIDHEIGHT - 10; V_DrawFadeFill(0, y-1, BASEVIDWIDTH, 10+1, 0, 31, 5); V_DrawCenteredThinString(BASEVIDWIDTH/2, y, @@ -3785,7 +3830,7 @@ void M_DrawEggaChannel(void) patch_t *background = W_CachePatchName("M_EGGACH", PU_CACHE); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 25); - V_DrawFixedPatch(160<value][0]); + } +} + +static void find_ip(INT32 add) +{ + consvar_t *cv = ip_cvar(); + for (int i = 0; i < NUMLOGIP; ++i) + { + CV_AddValue(cv, add); + if (*joinedIPlist[cv->value][0]) + break; + } +} + +static void direct_join_routine(INT32 choice) +{ + consvar_t *cv = ip_cvar(); + INT32 index = cv->value; + + if (choice == 2) + ip_entry(); + else if (choice == -1) + { + const char *ip = joinedIPlist[index][0]; + if (*ip) + { + M_StartMessage("Direct Join", va("Connect to %s?", joinedIPlist[index][0]), + &confirm_ip_select, MM_YESNO, "Connect", "Back"); + } + } + else + find_ip(choice ? 1 : -1); +} + +// mp_e menuitem_t PLAY_MP_OptSelect[] = { {IT_STRING_CALL_NOTESTERS, "Host Game", "Start your own online game!", NULL, {.routine = M_PreMPHostInit}, 0, 0}, - {IT_STRING | IT_CALL, "Server Browser", "Search for game servers to play in.", + {IT_STRING | IT_CALL, "Browse", "Search for game servers to play in.", NULL, {.routine = M_PreMPRoomSelectInit}, 0, 0}, - {IT_STRING | IT_CALL, "Join by IP", "Join an online game by its IP address.", - NULL, {.routine = M_MPJoinIPInit}, 0, 0}, + {IT_STRING | IT_ARROWS, "Direct Join", "Join an online game by its IP address.", + NULL, {.routine = direct_join_routine}, 0, 0}, + + {IT_STRING | IT_CALL, "Back", NULL, NULL, {.routine = M_GoBack}, 0, 0}, }; #undef IT_STRING_CALL_NOTESTERS +static void draw_routine(void) +{ + M_DrawKartGamemodeMenu(); + M_DrawMasterServerReminder(); +} + +static boolean any_stored_ips(void) +{ + for (int i = 0; i < NUMLOGIP; ++i) + { + if (*joinedIPlist[i][0]) + return true; + } + return false; +} + +static void init_routine(void) +{ + menuitem_t *it = &PLAY_MP_OptSelect[mp_directjoin]; + CV_SetValue(ip_cvar(), 0); + if (any_stored_ips()) + { + it->status = IT_STRING | IT_ARROWS; + find_ip(1); + } + else + it->status = IT_STRING | IT_CALL; +} + +static boolean input_routine(INT32 key) +{ + uses_gamepad = (key == -1); + return false; +} menu_t PLAY_MP_OptSelectDef = { sizeof (PLAY_MP_OptSelect) / sizeof (menuitem_t), @@ -101,13 +199,13 @@ menu_t PLAY_MP_OptSelectDef = { 0, 0, 0, "NETMD2", - -1, 1, - M_DrawMPOptSelect, + 4, 5, + draw_routine, M_DrawEggaChannel, - M_MPOptSelectTick, NULL, + init_routine, NULL, - NULL + input_routine }; struct mpmenu_s mpmenu; diff --git a/src/menus/play-online-host.c b/src/menus/play-online-host.c index 3425c4884..3c6f344d6 100644 --- a/src/menus/play-online-host.c +++ b/src/menus/play-online-host.c @@ -6,9 +6,21 @@ #include "../z_zone.h" #include "../mserv.h" +static void draw_routine(void) +{ + M_DrawRaceDifficulty(); + M_DrawMasterServerReminder(); +} + +static void tick_routine(void) +{ + PLAY_MP_Host[mhost_gametype].text = gametypes[menugametype]->name; +} + // MULTIPLAYER HOST SCREEN -- see mhost_e menuitem_t PLAY_MP_Host[] = { +#if 0 //{IT_NOTHING | IT_KEYHANDLER, NULL, NULL, NULL, M_MPOptSelect, 0, 0}, {IT_STRING | IT_CVAR | IT_CV_STRING, "Server Name", "Display name for your game online. Other players will see this.", @@ -25,7 +37,21 @@ menuitem_t PLAY_MP_Host[] = {IT_STRING | IT_CALL, "GO", "Select a map with the currently selected gamemode", NULL, {.routine = M_MPSetupNetgameMapSelect}, 0, 0}, +#endif + {IT_STRING | IT_ARROWS, "Gametype", "Choose the type of play on your serer.", + NULL, {.routine = M_HandleHostMenuGametype}, 0, 0}, + {IT_STRING2 | IT_CALL, "Gameplay Options...", "Adjust settings pertaining to gameplay.", + NULL, {.routine = M_GameplayOptions}, 0, 0}, + + {IT_STRING2 | IT_CALL, "Server Options...", "Adjust settings pertaining to online play.", + NULL, {.routine = M_ServerOptions}, 0, 0}, + + {IT_STRING | IT_CALL, "Map Select", "Go on and select a level!", + NULL, {.routine = M_MPSetupNetgameMapSelect}, 0, 0}, + + {IT_STRING | IT_CALL, "Back", NULL, + NULL, {.routine = M_GoBack}, 0, 0}, }; menu_t PLAY_MP_HostDef = { @@ -34,13 +60,13 @@ menu_t PLAY_MP_HostDef = { 0, PLAY_MP_Host, 0, 0, - 0, 0, + mhost_boxend, 0, 0, "NETMD2", - -1, 1, // 1 frame transition.... This is really just because I don't want the black fade when we press esc, hehe - M_DrawMPHost, + 4, 5, + draw_routine, M_DrawEggaChannel, - M_MPOptSelectTick, // This handles the unfolding options + tick_routine, NULL, M_MPResetOpts, NULL @@ -66,8 +92,8 @@ void M_MPHostInit(INT32 choice) { (void)choice; mpmenu.modewinextend[0][0] = 1; - M_SetupNextMenu(&PLAY_MP_HostDef, true); - itemOn = mhost_go; + PLAY_MP_HostDef.lastOn = mhost_mapselect; + M_SetupNextMenu(&PLAY_MP_HostDef, false); Get_rules(); // There's one downside to doing it this way: diff --git a/src/menus/play-online-join-ip.c b/src/menus/play-online-join-ip.c index e7a839714..8f84a9c33 100644 --- a/src/menus/play-online-join-ip.c +++ b/src/menus/play-online-join-ip.c @@ -77,7 +77,6 @@ void M_JoinIP(const char *ipa) { if (*(ipa) == '\0') // Jack shit { - M_StartMessage("Online Play", "Please specify an address.\n", NULL, MM_NOTHING, NULL, NULL); return; } From 2aeb267febbc4e38d349a3c7716e1d51ed49862e Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 5 Mar 2024 12:49:07 -0800 Subject: [PATCH 32/33] Menus/Browser: fix wrong backgrounds being used in CORE / MODDED --- src/k_menudraw.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index d90fda389..5db14a87c 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -4164,6 +4164,13 @@ static void M_DrawServerCountAndHorizontalBar(void) void M_DrawMPServerBrowser(void) { + const char *header[3][2] = { + {"Server Browser", "BG_MPS1"}, + {"Core Servers", "BG_MPS1"}, + {"Modded Servers", "BG_MPS2"}, + }; + int mode = M_SecretUnlocked(SECRET_ADDONS, true) ? (mpmenu.room ? 2 : 1) : 0; + patch_t *text1 = W_CachePatchName("MENUBGT1", PU_CACHE); patch_t *text2 = W_CachePatchName("MENUBGT2", PU_CACHE); @@ -4183,7 +4190,7 @@ void M_DrawMPServerBrowser(void) UINT8 i; // background stuff - V_DrawFixedPatch(0, 0, FRACUNIT, 0, W_CachePatchName("BG_MPS3", PU_CACHE), NULL); + V_DrawFixedPatch(0, 0, FRACUNIT, 0, W_CachePatchName(header[mode][1], PU_CACHE), NULL); V_DrawFixedPatch(0, (BASEVIDHEIGHT + 16) * FRACUNIT, FRACUNIT, V_TRANSLUCENT, W_CachePatchName("MENUBG2", PU_CACHE), NULL); @@ -4257,12 +4264,7 @@ void M_DrawMPServerBrowser(void) V_DrawFill(0, 53, 320, 1, 31); V_DrawFill(0, 55, 320, 1, 31); - const char *headertext; - if (M_SecretUnlocked(SECRET_ADDONS, true)) - headertext = va("%s Servers", mpmenu.room ? "Modded" : "Core"); - else - headertext = "Server Browser"; - V_DrawCenteredGamemodeString(160, 2, 0, 0, headertext); + V_DrawCenteredGamemodeString(160, 2, 0, 0, header[mode][0]); // normal menu options M_DrawGenericMenu(); From 10d2bb45113a2c79bb69d5e2fe29552ff8865548 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 5 Mar 2024 22:03:13 -0700 Subject: [PATCH 33/33] Fix in-flight merge conflict re M_OpenVirtualKeyboard args --- src/menus/play-online-1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menus/play-online-1.c b/src/menus/play-online-1.c index 148c1afcc..2d3c57756 100644 --- a/src/menus/play-online-1.c +++ b/src/menus/play-online-1.c @@ -85,7 +85,7 @@ static boolean uses_gamepad; static void ip_entry(void) { - M_OpenVirtualKeyboard(uses_gamepad, MAXSTRINGLENGTH, query_ip, NULL); + M_OpenVirtualKeyboard(MAXSTRINGLENGTH, query_ip, NULL); } static consvar_t *ip_cvar(void)