Merge remote-tracking branch 'origin/next' into subvsdub

This commit is contained in:
yamamama 2025-11-30 17:44:53 -05:00
commit 55e98f05cd
16 changed files with 152 additions and 15 deletions

View file

@ -1395,6 +1395,33 @@ D_ConvertVersionNumbers (void)
#endif
}
const char *D_GetFancyBranchName(void)
{
if (!strcmp(compbranch, ""))
{
// \x8b = aqua highlight
return "\x8b" "detached HEAD" "\x80";
}
return compbranch;
}
static void Command_assert(void)
{
#if !defined(NDEBUG) || defined(PARANOIA)
CONS_Printf("Yes, assertions are enabled.\n");
#else
CONS_Printf("No, ssertions are NOT enabled.\n");
#endif
}
#ifdef DEVELOP
static void Command_crash(void)
{
I_Error("The game crashed on PURPOSE, because of the 'crash' command. (This is only enabled in DEVELOP builds.)");
}
#endif
//
// D_SRB2Main
//
@ -1560,6 +1587,11 @@ void D_SRB2Main(void)
// Do this up here so that WADs loaded through the command line can use ExecCfg
COM_Init();
COM_AddCommand("assert", Command_assert);
#ifdef DEVELOP
COM_AddCommand("crash", Command_crash);
#endif
// add any files specified on the command line with -file wadfile
// to the wad list
if (!((M_GetUrlProtocolArg() || M_CheckParm("-connect")) && !M_CheckParm("-server")))

View file

@ -59,6 +59,8 @@ extern boolean usehome; //Alam: which path?
extern const char *pandf; //Alam: how to path?
extern char srb2path[256]; //Alam: SRB2's Home
const char *D_GetFancyBranchName(void);
// the infinite loop of D_SRB2Loop() called from win_main for windows version
void D_SRB2Loop(void) FUNCNORETURN;

View file

@ -622,6 +622,14 @@ consvar_t cv_kartflame_fastfuel = CVAR_INIT ("kartflame_fastfuel", "Off", CV_NET
// we want this to be default now apparently
consvar_t cv_kartflame_offroadburn = CVAR_INIT ("kartflame_offroadburn", "On", CV_NETVAR, CV_OnOff, NULL);
// "Arrow Bullet": above a certain speed threshold, an aura in the shape of the Shrink arrow
// covers you, signaling protection from (most) items and players.
// Default threshold percentage is currently 166%.
consvar_t cv_kartaltshrink_arrowbullet = CVAR_INIT ("kart_altshrink_arrowbullet", "On", CV_NETVAR, CV_OnOff, NULL);
static CV_PossibleValue_t altshrink_arrowbullet_threshold_cons_t[] = {{0, "MIN"}, {2 * FRACUNIT, "MAX"}, {0, NULL}};
consvar_t cv_kartaltshrink_arrowbulletthres = CVAR_INIT ("kart_altshrink_arrowbullet_threshold", "1.66", CV_NETVAR|CV_FLOAT, altshrink_arrowbullet_threshold_cons_t, NULL);
static CV_PossibleValue_t kartairsquish_cons_t[] = {{1, "Squish"}, {2, "Flip-over"}, {0, "None"}, {0, NULL}};
consvar_t cv_kartairsquish = CVAR_INIT ("kartairsquish", "None", CV_NETVAR, kartairsquish_cons_t, NULL);
@ -5478,9 +5486,9 @@ static void Command_ListDoomednums_f(void)
static void Command_Version_f(void)
{
#ifdef DEVELOP
CONS_Printf("SRB2Kart %s-%s (%s %s)\n", compbranch, comprevision, compdate, comptime);
CONS_Printf("SRB2Kart %s-%s (%s %s)\n", D_GetFancyBranchName(), comprevision, compdate, comptime);
#else
CONS_Printf("SRB2Kart %s (%s %s %s %s) ", VERSIONSTRING, compdate, comptime, comprevision, compbranch);
CONS_Printf("SRB2Kart %s (%s %s %s %s) ", VERSIONSTRING, compdate, comptime, comprevision, D_GetFancyBranchName());
#endif
// Base library

View file

@ -190,6 +190,8 @@ extern consvar_t cv_kartbubble_defense_damagerate;
extern consvar_t cv_kartbubble_boost_allow;
extern consvar_t cv_kartflame_fastfuel;
extern consvar_t cv_kartflame_offroadburn;
extern consvar_t cv_kartaltshrink_arrowbullet;
extern consvar_t cv_kartaltshrink_arrowbulletthres;
extern consvar_t cv_kartairsquish;

View file

@ -4436,7 +4436,10 @@ boolean G_CheckDemoStatus(void)
if (demo.recording && (modeattacking || demo.savemode != DSM_NOTSAVING))
{
G_SaveDemo();
if (demobuf.p)
{
G_SaveDemo();
}
return true;
}

View file

@ -361,7 +361,7 @@ static FUINT HWR_CalcSlopeLight(FUINT lightnum, pslope_t *slope, const sector_t
{
INT16 finallight = lightnum;
if (slope != NULL && P_ApplyLightOffsetFine(lightnum, sector))
if (slope != NULL && sector != NULL && P_ApplyLightOffsetFine(lightnum, sector))
{
finallight += (fof ? -slope->hwLightOffset : slope->hwLightOffset);

View file

@ -794,6 +794,10 @@ boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2)
boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
{
// What the fuck is calling this with stale refs? Whatever, validation's cheap.
if (P_MobjWasRemoved(t1) || P_MobjWasRemoved(t2) || !t1->player || !t2->player)
return false;
const boolean flameT1 = ((t1->player->flamestore > 0) && (t1->player->flametimer > 0));
const boolean flameT2 = ((t2->player->flamestore > 0) && (t2->player->flametimer > 0));
const boolean hyudoroT1 = (t1->player->hyudorotimer > 0);
@ -852,6 +856,8 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
P_InstaThrust(t2, K_MomentumAngle(t2), K_Momentum2D(t2) / 3);
K_PlayPainSound(t2, NULL);
return true;
}
}
if (P_IsObjectOnGround(t1) && P_IsObjectOnGround(t2))
@ -895,6 +901,8 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
P_InstaThrust(t1, K_MomentumAngle(t1), K_Momentum2D(t1) / 3);
K_PlayPainSound(t1, NULL);
return true;
}
}
else if (P_IsObjectOnGround(t1) && P_IsObjectOnGround(t2))

View file

@ -2036,7 +2036,7 @@ static void K_drawBossHealthBar(void)
UINT8 i = 0, barstatus = 1, randlen = 0, darken = 0;
const INT32 startx = BASEVIDWIDTH - 23;
INT32 starty = BASEVIDHEIGHT - 25;
INT32 rolrand = 0;
INT32 rolrand = 0, randtemp = 0;
boolean randsign = false;
if (bossinfo.barlen <= 1)
@ -2082,7 +2082,9 @@ static void K_drawBossHealthBar(void)
barstatus = 2;
}
randlen = M_RandomKey(bossinfo.visualbar-(bossinfo.visualdiv/(2*FRACUNIT)))+1;
randtemp = bossinfo.visualbar-(bossinfo.visualdiv/(2*FRACUNIT));
if (randtemp > 0)
randlen = M_RandomKey(randtemp)+1;
randsign = M_RandomChance(FRACUNIT/2);
// Right wing.
@ -2097,7 +2099,9 @@ static void K_drawBossHealthBar(void)
randlen--;
if (!randlen)
{
randlen = M_RandomKey(bossinfo.visualbar-(bossinfo.visualdiv/(2*FRACUNIT)))+1;
randtemp = bossinfo.visualbar-(bossinfo.visualdiv/(2*FRACUNIT));
if (randtemp > 0)
randlen = M_RandomKey(randtemp)+1;
if (barstatus > 1)
{
rolrand = M_RandomKey(barstatus)+1;
@ -2661,10 +2665,11 @@ static void K_drawKartStatsnLives(void)
{
INT32 offsetx = 0;
INT32 offsety = 0;
boolean split = r_splitscreen == 1;
if (cv_lives_xoffset.value == 0 || cv_lives_yoffset.value == 0)
if ((cv_lives_xoffset.value == 0 && cv_lives_yoffset.value == 0) || split)
{
if ((cv_newspeedometer.value == 0 || cv_newspeedometer.value == 2) && !K_RingsActive())
if ((cv_newspeedometer.value == 0 || cv_newspeedometer.value == 2) && !K_RingsActive() && !split)
{
offsetx = 25;
offsety = 15;

View file

@ -406,6 +406,8 @@ void K_RegisterKartStuff(void)
CV_RegisterVar(&cv_kartbubble_boost_allow);
CV_RegisterVar(&cv_kartflame_fastfuel);
CV_RegisterVar(&cv_kartflame_offroadburn);
CV_RegisterVar(&cv_kartaltshrink_arrowbullet);
CV_RegisterVar(&cv_kartaltshrink_arrowbulletthres);
CV_RegisterVar(&cv_kartairsquish);
@ -830,6 +832,22 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean sol
return false;
}
const boolean mobj1_intercepting = ((mobj1->player) && (K_InterceptArrowBullet(mobj1->player)));
const boolean mobj2_intercepting = ((mobj2->player) && (K_InterceptArrowBullet(mobj2->player)));
// The other player is an Arrow Bullet, ignore them.
if (mobj1->player && K_AltShrinkArrowBulletCondition(mobj1->player) && (!mobj2_intercepting))
{
mobj1->player->justbumped = bumptime;
return false;
}
if (mobj2->player && K_AltShrinkArrowBulletCondition(mobj2->player) && (!mobj1_intercepting))
{
mobj2->player->justbumped = bumptime;
return false;
}
mass1 = K_GetMobjWeight(mobj1, mobj2);
if (solid == true && mass1 > 0)
@ -2176,7 +2194,8 @@ boolean K_TripwirePass(const player_t *player)
boolean K_PlayerCanPunt(const player_t *player)
{
return player->invincibilitytimer > 0 || player->growshrinktimer > 0 ||
(player->flamestore > 0 && K_GetShieldFromPlayer(player) == KSHIELD_FLAME);
(player->flamestore > 0 && K_GetShieldFromPlayer(player) == KSHIELD_FLAME) ||
K_AltShrinkArrowBulletCondition(player);
}
boolean K_ItemMobjAllowedtoWaterRun(mobj_t *item)
@ -7536,7 +7555,15 @@ void K_KartResetPlayerColor(player_t *player)
if (player->growshrinktimer) // Ditto, for grow/shrink
{
if (player->growshrinktimer % 5 == 0)
if (K_AltShrinkArrowBulletCondition(player))
{
// Arrow Bullet!
player->mo->colorized = true;
player->mo->color = SKINCOLOR_CREAMSICLE;
fullbright = true;
goto finalise;
}
else if (player->growshrinktimer % 5 == 0)
{
player->mo->colorized = true;
player->mo->color = player->growshrinktimer < 0 ? SKINCOLOR_CREAMSICLE : SKINCOLOR_PERIWINKLE;
@ -8911,6 +8938,14 @@ static boolean K_AltInvinSliptideCondition(player_t *player)
return (K_InvincibilityGradient(player->invincibilitytimer) > (FRACUNIT/2));
}
fixed_t K_GetSpeedPercentage(player_t *player)
{
if (!player)
return 0; // NULL player means there's no speeed to gather.
return (FixedDiv(player->speed, K_GetKartSpeed(player, false, false)));
}
// Sliptide conditions for Alt. Shrink
static boolean K_AltShrinkSliptideCondition(player_t *player)
{
@ -8926,6 +8961,28 @@ static boolean K_AltShrinkSliptideCondition(player_t *player)
return (speedPercent > (3 * FRACUNIT / 4));
}
// Conditions for putting the player in "arrow bullet" mode.
boolean K_AltShrinkArrowBulletCondition(player_t *player)
{
if (!cv_kartaltshrink_arrowbullet.value) // Not toggled on; we can't do anything
return false;
if (!player)
return false; // NULL player means there's no way we can BE an arrow bullet.
// Only if you're at or above the threshold percentage!
return (K_GetSpeedPercentage(player) >= cv_kartaltshrink_arrowbulletthres.value);
}
// This player intercepts an Arrow Bullet and causes damage.
boolean K_InterceptArrowBullet(player_t *player)
{
if (!player)
return false;
return ((player->invincibilitytimer && !K_IsKartItemAlternate(KITEM_INVINCIBILITY)) || (player->growshrinktimer > 0) || (player->flamestore));
}
static void K_HandleAirDriftDrag(player_t *player, boolean onground)
{
if (onground && player->airdriftspeed > 0)

View file

@ -264,6 +264,9 @@ fixed_t K_InvincibilityGradient(UINT16 time);
UINT16 K_GetInvincibilityTime(player_t *player);
fixed_t K_GetInvincibilitySpeed(UINT16 time);
fixed_t K_GetInvincibilityAccel(UINT16 time);
fixed_t K_GetSpeedPercentage(player_t *player);
boolean K_AltShrinkArrowBulletCondition(player_t *player);
boolean K_InterceptArrowBullet(player_t *player);
void K_ResetPogoSpring(player_t *player);
void K_DoInvincibility(player_t *player, tic_t time);
void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source);

View file

@ -2848,6 +2848,7 @@ texty -= 10*vid.dupy;\
#if defined(DEVELOP)
addtext(V_ALLOWLOWERCASE|V_GREENMAP|V_TRANSLUCENT, comprevision);
addtext(V_ALLOWLOWERCASE|V_YELLOWMAP|V_TRANSLUCENT, compbranch);
addtext(0, D_GetFancyBranchName());
V_DrawThinString(0, 0, V_ALLOWLOWERCASE|V_ORANGEMAP|V_TRANSLUCENT|V_SNAPTOTOP, va("%s", complast));
#else // Regular build
addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, va("%s", VERSIONSTRING));

View file

@ -2125,7 +2125,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
if (damagetype != DMG_SPECTATOR && target->player && target->player->spectator)
return false;
if (source && source->player && source->player->spectator)
if (!P_MobjWasRemoved(source) && source->player && source->player->spectator)
return false;
switch (target->type)
@ -2215,6 +2215,9 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
const boolean explosioncombo = type == DMG_EXPLODE // This damage type can do evil stuff like ALWAYS combo
&& player->bubbleboost == 0; // ...but popping a Bubble Shield protects you!
// An Arrow Bullet player ran into a player with a stronger power item. Damage them!
const boolean intercept = ((!P_MobjWasRemoved(inflictor)) && inflictor->player && K_InterceptArrowBullet(inflictor->player));
// Check if the player is allowed to be damaged!
// If not, then spawn the instashield effect instead.
if (!force)
@ -2253,6 +2256,13 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
return false;
}
// Alt. Shrink: Tank non-explosion hits, as long as you're in Arrow Bullet mode.
if ((explosioncombo == false) && (intercept == false) && (K_AltShrinkArrowBulletCondition(player)))
{
K_DoInstashield(player);
return false;
}
// Bubble Shield protects you from spinout, but not knockback
if (K_GetShieldFromPlayer(player) == KSHIELD_BUBBLE
&& explosioncombo == false && source != NULL && type != DMG_VOLTAGE

View file

@ -8893,6 +8893,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
HWR_ClearAllTextures();
#endif
G_FreeGhosts(); // ghosts are allocated with PU_LEVEL
Patch_FreeTag(PU_PATCH_LOWPRIORITY);
Patch_FreeTag(PU_PATCH_ROTATED);
Z_FreeTags(PU_LEVEL, PU_PURGELEVEL - 1);

View file

@ -4417,7 +4417,7 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha
if (waypointcap == NULL)
{
// No point in trying at all if no waypoints exist.
break;
return false;
}
TAG_ITER_SECTORS(args[0], secnum)

View file

@ -2315,6 +2315,11 @@ void P_MovePlayer(player_t *player)
K_SpawnSparkleTrail(player->mo);
}
if (K_AltShrinkArrowBulletCondition(player))
{
K_SpawnSparkleTrail(player->mo);
}
if (player->wipeoutslow > 1 && (leveltime & 1))
K_SpawnWipeoutTrail(player->mo, false);

View file

@ -2124,8 +2124,8 @@ FUNCIERROR void ATTRNORETURN I_Error(const char *error, ...)
W_Shutdown();
#if defined (PARANOIA) && defined (__CYGWIN__)
*(volatile INT32 *)0 = 4; //Alam: Debug!
#if defined (PARANOIA) || defined (DEVELOP)
*(INT32 *)0 = 4; //Alam: Debug!
#endif
exit(-1);