Merge pull request '[Enhancement] Generalize Null Drift Tilt' (#236) from karttilt into next

Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/236
This commit is contained in:
minenice55 2026-04-20 01:22:05 +02:00
commit f2a3b38f1e
7 changed files with 169 additions and 47 deletions

View file

@ -624,9 +624,11 @@ struct player_t
INT32 drift_wannaturn; // Turn values the game uses to determine the direction you want to drift.
INT32 nulldrift; // When you drift without accelerating, this value ticks up/down depending on your drift's angle.
INT32 nulldrifttilt; // Sliptide-like kart tilting! (Can be toggled off)
tic_t nulldrifttime;
fixed_t karttilt; // Generalized sliptide-like kart tilting as an angle_t (Can be toggled off by clients)
fixed_t karttiltmomentum; // angular velocity in rad/sec
// (Delay-drift) - Delay in tics before the final drift angle is determined.
// Potentially influenced by player lag.
tic_t driftdelay;

View file

@ -1851,6 +1851,7 @@ void K_KartMoveAnimation(player_t *player)
player->mo->rollingxoffset = 0;
player->mo->rollingyoffset = 0;
player->mo->spritexoffset = 0;
if (!lookback)
player->pflags &= ~PF_GAINAX;
@ -1976,12 +1977,10 @@ void K_KartMoveAnimation(player_t *player)
if (onground && drift)
{
INT16 reversejitter = 0;
INT16 nullrolloffset = 0;
if ((player->jitterlegacy) && (!skincompat))
{
// Make RR characters imitate legacy jitters.
reversejitter = ((player->driftelapsed & 1) * 2) * -intsign(drift);
player->mo->rollingxoffset = ((player->driftelapsed & 1) * 2) * -intsign(drift);
}
else
{
@ -1993,15 +1992,6 @@ void K_KartMoveAnimation(player_t *player)
else if (turndir == 1)
spr2 += 1; // Outwards drift
}
if (abs(player->nulldrifttilt) > 0)
{
//todo: a way for skins(?) to define the tyre offset
nullrolloffset = intsign(drift) * ((36 * FINESINE(abs(player->nulldrifttilt)>>ANGLETOFINESHIFT))/FRACUNIT);
player->mo->rollingyoffset = ((18 * FINESINE(abs(player->nulldrifttilt)>>ANGLETOFINESHIFT))/FRACUNIT);
}
player->mo->rollingxoffset = reversejitter - nullrolloffset;
}
else if (glanceofs)
spr2 += glanceofs+1;
@ -2037,6 +2027,12 @@ void K_KartMoveAnimation(player_t *player)
if (!player->glanceDir)
player->pflags &= ~PF_GAINAX;
if (player->karttilt)
{
//todo: a way for skins(?) to define the tyre offset
player->mo->rollingyoffset = -abs(FixedMul(2 * player->mo->radius, FINESINE(FixedAngle(abs(player->karttilt))>>ANGLETOFINESHIFT))/FRACUNIT);
}
// Update lastspeed value -- we use to display slow driving frames instead of fast driving when slowing down.
player->lastspeed = player->speed;
}
@ -4244,7 +4240,7 @@ static void K_SpawnDriftSparks(player_t *player)
for (i = 0; i < 2; i++)
{
fixed_t driftExtraScale = 0;
if (player->nulldrifttilt &&
if (player->karttilt &&
((player->drift < 0 && (i & 1)) || (player->drift > 0 && !(i & 1))))
{
// when tilting during a null-drift don't spawn the sparks for the front tyre
@ -7167,8 +7163,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
player->mo->sprxoff = 0;
player->mo->spryoff = 0;
player->mo->sprzoff = 0;
player->mo->spritexoffset = 0;
player->mo->spriteyoffset = 0;
player->mo->bakexoff = 0;
player->mo->bakeyoff = 0;
@ -9431,6 +9425,88 @@ static void K_HandleAirDriftDrag(player_t *player, boolean onground)
}
}
// no float-to-fixed here because this is in the deterministic path
#define FIXEDRADTODEG (3754879) //57.2958
#define PLAYERTILTCAP (90*FRACUNIT)
#define PLAYERTILTMOMENTUMCAP (4*M_PI_FIXED)
/// @brief simulates applying a torque by applying a force at an offset from the player's centre, is a purely visual effect
/// @param player player to apply angular momentum to
/// @param distance distance from player centre to apply torque to ("radius")
/// @param force linear force to apply to the player to turn into angular velocity, + is CCW
void K_AddTiltImpulse(player_t *player, fixed_t distance, fixed_t force)
{
fixed_t angularvelocity = FixedDiv(force, abs(distance));
player->karttiltmomentum += angularvelocity;
}
/// @brief adds angular velocity to the player's tilt, this is a purely visual effect
/// @param player player to apply angular momentum to
/// @param angularvelocity angular velocity in rad/sec to impart onto the player's sprite
void K_AddTiltMomentum(player_t *player, fixed_t angularvelocity)
{
player->karttiltmomentum += angularvelocity;
}
static void K_HandleKartTilt(player_t *player)
{
SINT8 startsign = intsign(player->karttilt);
fixed_t angulargravity;
fixed_t angaccelgravity;
if (player->karttilt == 0 && player->karttiltmomentum == 0)
{
return;
}
if (player->mo->eflags & MFE_UNDERWATER)
{
// angular drag
player->karttiltmomentum = FixedMul(player->karttiltmomentum, 92*FRACUNIT/100);
angulargravity = abs(player->mo->gravity) * (P_IsObjectOnGround(player->mo) ? 2 : 1);
}
else
{
// angular drag
player->karttiltmomentum = FixedMul(player->karttiltmomentum, 98*FRACUNIT/100);
angulargravity = abs(player->mo->gravity) * (P_IsObjectOnGround(player->mo) ? 8 : 3);
}
// O = (linear velocity) / (distance from CoM)
angaccelgravity = FixedDiv(angulargravity, abs(FixedMul(player->mo->radius, FINECOSINE(FixedAngle(player->karttilt)>>ANGLETOFINESHIFT))));
player->karttiltmomentum += angaccelgravity * -intsign(player->karttilt);
if (abs(player->karttiltmomentum) >= PLAYERTILTMOMENTUMCAP)
{
player->karttiltmomentum = PLAYERTILTMOMENTUMCAP * intsign(player->karttiltmomentum);
}
player->karttilt += FixedMul(player->karttiltmomentum, FIXEDRADTODEG)/TICRATE;
// CONS_Printf("angaccelgravity: %4.3f\n", FixedToFloat(angaccelgravity));
// CONS_Printf("tilt angle: %4.3f\n", FixedToFloat(player->karttilt));
// CONS_Printf("tilt angle momentum (deg/s): %4.3f\n", FixedToFloat(player->karttiltmomentum) * (M_PI/180.0));
if ((player->karttilt < 0 && startsign > 0) ||
(player->karttilt > 0 && startsign < 0))
{
player->karttilt = 0;
player->karttiltmomentum /= 2;
if (abs(player->karttiltmomentum) < FRACUNIT/3)
{
player->karttiltmomentum = 0;
}
}
else if (abs(player->karttilt) >= PLAYERTILTCAP)
{
player->karttiltmomentum = 0;
player->karttilt = CLAMP(player->karttilt, -PLAYERTILTCAP + 1, PLAYERTILTCAP - 1);
}
}
#undef FIXEDRADTODEG
#undef PLAYERTILTCAP
#undef PLAYERTILTMOMENTUMCAP
static void K_KartDrift(player_t *player, boolean onground)
{
fixed_t minspeed = (10 * player->mo->scale);
@ -9694,31 +9770,25 @@ static void K_KartDrift(player_t *player, boolean onground)
}
}
if (player->nulldrift)
{
if (player->nulldrifttime <= 3*TICRATE/4)
{
angle_t tilt;
fixed_t dot;
fixed_t angularvelocity;
vector2_t fwd = {P_ReturnThrustX(player->mo, player->mo->angle, FRACUNIT), P_ReturnThrustY(player->mo, player->mo->angle, FRACUNIT)};
vector2_t mov = {player->mo->momx, player->mo->momy};
FV2_Normalize(&fwd);
FV2_Normalize(&mov);
dot = FRACUNIT - abs(FV2_Dot(&fwd, &mov));
tilt = FixedAngle(FixedMul(AngleFixed(ANG20), dot));
dot = FixedMul(CLAMP(abs(player->speed), 0, 30*mapobjectscale), FRACUNIT - abs(FV2_Dot(&fwd, &mov)));
if ((angle_t)abs(player->nulldrifttilt) < tilt)
angularvelocity = FixedDiv(-dot * intsign(player->nulldrift),
abs(FixedMul(player->mo->height/2, FINECOSINE(FixedAngle(player->karttilt)>>ANGLETOFINESHIFT)))
);
angularvelocity = FixedMul(CLAMP(angularvelocity, -M_PI_FIXED, M_PI_FIXED), FINECOSINE(FixedAngle(2 * player->karttilt)>>ANGLETOFINESHIFT));
if (abs(player->karttiltmomentum) < abs(angularvelocity))
{
player->nulldrifttilt = (abs(player->nulldrifttilt) + tilt/10) * -player->nulldrift;
}
}
else if (player->nulldrifttilt)
{
player->nulldrifttilt -= (CLAMP(ANG20 - abs(player->nulldrifttilt), ANG1, abs(player->nulldrifttilt))/3) * intsign(player->nulldrifttilt);
if (abs(player->nulldrifttilt) < (ANGLE_11hh / 4))
{
player->nulldrifttilt = 0;
}
player->karttiltmomentum = angularvelocity;
}
// Increment nulldrift timer.
@ -9727,14 +9797,6 @@ static void K_KartDrift(player_t *player, boolean onground)
// Let's have some faith that the driftspark thinker will set this value again
player->nulldrift = 0;
}
else if (player->nulldrifttilt)
{
player->nulldrifttilt -= (CLAMP(ANG20 - abs(player->nulldrifttilt), ANG1, abs(player->nulldrifttilt))/3) * intsign(player->nulldrifttilt);
if (abs(player->nulldrifttilt) < (ANGLE_11hh / 4))
{
player->nulldrifttilt = 0;
}
}
if (!K_Sliptiding(player))
{
@ -11276,6 +11338,8 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
K_KartSlipdash(player, onground);
K_HandleKartTilt(player);
K_RecoveryDash(player);
// Quick Turning

View file

@ -431,6 +431,9 @@ void K_KillAirDrop(player_t *player, p_airdropflags_t airdropflags);
boolean K_NullDriftTiltEnabled(void);
void K_AddTiltMomentum(player_t *player, fixed_t angularvelocity);
void K_AddTiltImpulse(player_t *player, fixed_t distance, fixed_t force);
#define RECOVERYDASHADD (TICRATE/2)
//og val 2*TICRATE
#define RECOVERYDASHCHARGETIME (3*TICRATE/2)

View file

@ -4755,6 +4755,27 @@ static int lib_kMomentum3D(lua_State *L)
return 1;
}
static int lib_kAddTiltImpulse(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
fixed_t distance = luaL_checkinteger(L, 2);
fixed_t force = luaL_checkinteger(L, 3);
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_AddTiltImpulse(player, distance, force);
return 0;
}
static int lib_kAddTiltMomentum(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
fixed_t angularvelocity = luaL_checkinteger(L, 2);
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_AddTiltMomentum(player, angularvelocity);
return 0;
}
static int lib_kMissileOrKartItem(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
@ -5868,6 +5889,9 @@ static luaL_Reg lib[] = {
{"K_IsPlayerRingBurnt", lib_kIsPlayerRingBurnt},
{"K_GetKartRingPower", lib_kGetKartRingPower},
{"K_AddTiltImpulse", lib_kAddTiltImpulse},
{"K_AddTiltMomentum", lib_kAddTiltMomentum},
// kart stuff that's in other places for some reason
{"K_IsMissileOrKartItem", lib_kMissileOrKartItem},

View file

@ -467,7 +467,11 @@ static int lib_lenLocalplayers(lua_State *L)
X(recoverydash) \
X(tripwireunstuck) \
X(bumpunstuck) \
X(public_key)
X(public_key) \
X(nulldrift) \
X(nulldrifttime) \
X(karttilt) \
X(karttiltmomentum)
enum player_e
{
@ -1226,6 +1230,18 @@ static int player_get(lua_State *L)
case player_bumpunstuck:
lua_pushinteger(L, plr->bumpUnstuck);
break;
case player_nulldrift:
lua_pushinteger(L, plr->nulldrift);
break;
case player_nulldrifttime:
lua_pushinteger(L, plr->nulldrifttime);
break;
case player_karttilt:
lua_pushinteger(L, plr->karttilt);
break;
case player_karttiltmomentum:
lua_pushinteger(L, plr->karttiltmomentum);
break;
#ifdef HWRENDER
case player_fovadd:
lua_pushfixed(L, plr->fovadd);
@ -2004,6 +2020,18 @@ static int player_set(lua_State *L)
case player_bumpunstuck:
plr->bumpUnstuck = lua_tointeger(L, 3);
break;
case player_nulldrift:
plr->nulldrift = lua_tointeger(L, 3);
break;
case player_nulldrifttime:
plr->nulldrifttime = lua_tointeger(L, 3);
break;
case player_karttilt:
plr->karttilt = lua_tointeger(L, 3);
break;
case player_karttiltmomentum:
plr->karttiltmomentum = lua_tointeger(L, 3);
break;
#ifdef HWRENDER
case player_fovadd:
plr->fovadd = luaL_checkfixed(L, 3);

View file

@ -641,7 +641,8 @@ static void P_NetSyncPlayers(savebuffer_t *save)
SYNC(players[i].driftboost);
SYNC(players[i].airdriftspeed);
SYNC(players[i].nulldrift);
SYNC(players[i].nulldrifttilt);
SYNC(players[i].karttilt);
SYNC(players[i].karttiltmomentum);
SYNC(players[i].nulldrifttime);
SYNC(players[i].recoverydashcharge);

View file

@ -65,7 +65,7 @@ static angle_t R_PlayerSpriteRotation(player_t *player, player_t *viewPlayer, bo
angle_t viewingAngle = R_PointToAnglePlayer(viewPlayer, player->mo->x, player->mo->y);
angle_t angleDelta = (viewingAngle - player->mo->angle);
INT32 nulltilt = (K_NullDriftTiltEnabled()) ? player->nulldrifttilt : 0;
INT32 nulltilt = (K_NullDriftTiltEnabled()) ? FixedAngle(player->karttilt) : 0;
INT32 aiztilt = (cv_sliptidetilt.value) ? player->aizdrifttilt : 0;
boolean nullBeforeSlip = (abs(aiztilt) < abs(nulltilt));