Directional Influence

Pretty much just copy+pasted from Snap the Sentinel!!
- Hold left/right to adjust the momentum angle after hitlag, up to 22.5 degrees. (Only angle can be adjusted, so you can't adjust your speed, only your direction.)
- It's relative to your angle, so sometimes you need to use forward/back, or even diagonals (forward/back throws now store full analog data for this to work)
- Bananas flip DI direction, to make them not baby easy mode
- Tumble has x3 DI (so angle adjustments of 67.5!!), and hitlag on each bounce to allow even more control.
This commit is contained in:
Sally Coolatta 2022-05-20 01:45:16 -04:00
parent ee21b2493a
commit 56c23339be
15 changed files with 215 additions and 44 deletions

View file

@ -4143,7 +4143,8 @@ static void HandlePacketFromAwayNode(SINT8 node)
static boolean CheckForSpeedHacks(UINT8 p)
{
if (netcmds[maketic%BACKUPTICS][p].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][p].forwardmove < -MAXPLMOVE
|| netcmds[maketic%BACKUPTICS][p].turning > KART_FULLTURN || netcmds[maketic%BACKUPTICS][p].turning < -KART_FULLTURN)
|| netcmds[maketic%BACKUPTICS][p].turning > KART_FULLTURN || netcmds[maketic%BACKUPTICS][p].turning < -KART_FULLTURN
|| netcmds[maketic%BACKUPTICS][p].throwdir > KART_FULLTURN || netcmds[maketic%BACKUPTICS][p].throwdir < -KART_FULLTURN)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), playernode[p]);
//D_Clearticcmd(k);

View file

@ -402,6 +402,8 @@ typedef struct player_s
UINT8 justbumped; // Prevent players from endlessly bumping into each other
UINT8 tumbleBounces;
UINT16 tumbleHeight; // In *mobjscaled* fracunits, or mfu, not raw fu
boolean justDI; // Directional Influence ended, true until letting go of turn
boolean flipDI; // Bananas flip the DI direction. Was a bug, but it made bananas much more interesting.
SINT8 drift; // (-5 to 5) - Drifting Left or Right, plus a bigger counter = sharper turn
fixed_t driftcharge; // Charge your drift so you can release a burst of speed

View file

@ -30,13 +30,11 @@ typedef enum
BT_DRIFT = 1<<2, // Drift (direction is cmd->turning)
BT_BRAKE = 1<<3, // Brake
BT_ATTACK = 1<<4, // Use Item
BT_FORWARD = 1<<5, // Aim Item Forward
BT_BACKWARD = 1<<6, // Aim Item Backward
BT_LOOKBACK = 1<<7, // Look Backward
BT_LOOKBACK = 1<<5, // Look Backward
BT_EBRAKEMASK = (BT_ACCELERATE|BT_BRAKE),
// free: 1<<9 to 1<<12
// free: 1<<6 to 1<<12
// Lua garbage
BT_CUSTOM1 = 1<<13,
@ -65,6 +63,7 @@ typedef struct
{
SINT8 forwardmove; // -MAXPLMOVE to MAXPLMOVE (50)
INT16 turning; // Turn speed
INT16 throwdir; // Aiming direction
INT16 aiming; // vertical aiming, see G_BuildTicCmd
UINT16 buttons;
UINT8 latency; // Netgames: how many tics ago was this ticcmd generated from this player's end?

View file

@ -6549,8 +6549,6 @@ struct int_const_s const INT_CONST[] = {
{"BT_DRIFT",BT_DRIFT},
{"BT_BRAKE",BT_BRAKE},
{"BT_ATTACK",BT_ATTACK},
{"BT_FORWARD",BT_FORWARD},
{"BT_BACKWARD",BT_BACKWARD},
{"BT_CUSTOM1",BT_CUSTOM1}, // Lua customizable
{"BT_CUSTOM2",BT_CUSTOM2}, // Lua customizable
{"BT_CUSTOM3",BT_CUSTOM3}, // Lua customizable

View file

@ -128,13 +128,16 @@ demoghost *ghosts = NULL;
#define DEMO_SHRINKME 0x04
// For demos
#define ZT_FWD 0x01
#define ZT_SIDE 0x02
#define ZT_TURNING 0x04
#define ZT_BUTTONS 0x08
#define ZT_AIMING 0x10
#define ZT_LATENCY 0x20
#define ZT_FLAGS 0x40
#define ZT_FWD 0x01
#define ZT_SIDE 0x02
#define ZT_TURNING 0x04
#define ZT_THROWDIR 0x08
#define ZT_BUTTONS 0x10
#define ZT_AIMING 0x20
#define ZT_LATENCY 0x40
#define ZT_FLAGS 0x80
// OUT OF ZIPTICS...
#define DEMOMARKER 0x80 // demoend
UINT8 demo_extradata[MAXPLAYERS];
@ -524,6 +527,8 @@ void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
oldcmd[playernum].forwardmove = READSINT8(demo_p);
if (ziptic & ZT_TURNING)
oldcmd[playernum].turning = READINT16(demo_p);
if (ziptic & ZT_THROWDIR)
oldcmd[playernum].throwdir = READINT16(demo_p);
if (ziptic & ZT_BUTTONS)
oldcmd[playernum].buttons = READUINT16(demo_p);
if (ziptic & ZT_AIMING)
@ -567,6 +572,13 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
ziptic |= ZT_TURNING;
}
if (cmd->throwdir != oldcmd[playernum].throwdir)
{
WRITEINT16(demo_p,cmd->throwdir);
oldcmd[playernum].throwdir = cmd->throwdir;
ziptic |= ZT_THROWDIR;
}
if (cmd->buttons != oldcmd[playernum].buttons)
{
WRITEUINT16(demo_p,cmd->buttons);
@ -1128,6 +1140,8 @@ void G_GhostTicker(void)
g->p++;
if (ziptic & ZT_TURNING)
g->p += 2;
if (ziptic & ZT_THROWDIR)
g->p += 2;
if (ziptic & ZT_BUTTONS)
g->p += 2;
if (ziptic & ZT_AIMING)

View file

@ -1027,10 +1027,15 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
}
// But forward/backward IS used for aiming.
if (PlayerInputDown(ssplayer, gc_aimforward) || (joystickvector.yaxis < 0))
cmd->buttons |= BT_FORWARD;
if (PlayerInputDown(ssplayer, gc_aimbackward) || (joystickvector.yaxis > 0))
cmd->buttons |= BT_BACKWARD;
if (PlayerInputDown(ssplayer, gc_aimforward))
cmd->throwdir += KART_FULLTURN;
if (PlayerInputDown(ssplayer, gc_aimbackward))
cmd->throwdir -= KART_FULLTURN;
if (analogjoystickmove && joystickvector.yaxis != 0)
{
cmd->throwdir -= (joystickvector.yaxis * KART_FULLTURN) >> 10;
}
}
// fire with any button/key
@ -1160,6 +1165,11 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
else if (cmd->turning < -KART_FULLTURN)
cmd->turning = -KART_FULLTURN;
if (cmd->throwdir > KART_FULLTURN)
cmd->throwdir = KART_FULLTURN;
else if (cmd->throwdir < -KART_FULLTURN)
cmd->throwdir = -KART_FULLTURN;
// Reset away view if a command is given.
if ((cmd->forwardmove || cmd->buttons)
&& !r_splitscreen && displayplayers[0] != consoleplayer && ssplayer == 1)
@ -1183,6 +1193,7 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n)
{
dest[i].forwardmove = src[i].forwardmove;
dest[i].turning = (INT16)SHORT(src[i].turning);
dest[i].throwdir = (INT16)SHORT(src[i].throwdir);
dest[i].aiming = (INT16)SHORT(src[i].aiming);
dest[i].buttons = (UINT16)SHORT(src[i].buttons);
dest[i].latency = src[i].latency;

View file

@ -1008,10 +1008,10 @@ static void K_BotTrick(player_t *player, ticcmd_t *cmd, line_t *botController)
cmd->turning = -KART_FULLTURN;
break;
case 3:
cmd->buttons |= BT_FORWARD;
cmd->throwdir = KART_FULLTURN;
break;
case 4:
cmd->buttons |= BT_BACKWARD;
cmd->throwdir = -KART_FULLTURN;
break;
}
}

View file

@ -332,15 +332,7 @@ static boolean K_BotGenericPressItem(player_t *player, ticcmd_t *cmd, SINT8 dir)
return false;
}
if (dir == 1)
{
cmd->buttons |= BT_FORWARD;
}
else if (dir == -1)
{
cmd->buttons |= BT_BACKWARD;
}
cmd->throwdir = KART_FULLTURN * dir;
cmd->buttons |= BT_ATTACK;
player->botvars.itemconfirm = 0;
return true;

View file

@ -3312,6 +3312,13 @@ void K_AddHitLag(mobj_t *mo, INT32 tics, boolean fromDamage)
mo->hitlag += tics;
mo->hitlag = min(mo->hitlag, MAXHITLAGTICS);
if (mo->player != NULL)
{
// Reset each time. We want to explicitly set this for bananas afterwards,
// so make sure an old value doesn't possibly linger.
mo->player->flipDI = false;
}
if (fromDamage == true)
{
// Dunno if this should flat-out &~ the flag out too.
@ -3560,6 +3567,7 @@ static boolean K_LastTumbleBounceCondition(player_t *player)
static void K_HandleTumbleBounce(player_t *player)
{
fixed_t gravityadjust;
player->tumbleBounces++;
player->tumbleHeight = (player->tumbleHeight * ((player->tumbleHeight > 100) ? 3 : 4)) / 5;
player->pflags &= ~PF_TUMBLESOUND;
@ -3590,6 +3598,10 @@ static void K_HandleTumbleBounce(player_t *player)
}
}
// A bit of damage hitlag.
// This gives a window for DI!!
K_AddHitLag(player->mo, 6, true);
if (P_IsDisplayPlayer(player) && player->tumbleHeight >= 40)
P_StartQuake((player->tumbleHeight*3/2)<<FRACBITS, 6); // funny earthquakes for the FEEL
@ -8171,6 +8183,12 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue)
return 0;
}
if (player->justDI == true)
{
// No turning until you let go after DI-ing.
return 0;
}
currentSpeed = FixedHypot(player->mo->momx, player->mo->momy);
if ((currentSpeed <= 0) // Not moving
@ -10115,7 +10133,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
K_trickPanelTimingVisual(player, momz);
}
else if (player->throwdir == 1)
else if (cmd->throwdir > 0)
{
if (player->mo->momz * P_MobjFlip(player->mo) > 0)
{
@ -10130,7 +10148,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
K_trickPanelTimingVisual(player, momz);
}
else if (player->throwdir == -1)
else if (cmd->throwdir < 0)
{
boolean relative = true;
@ -10338,4 +10356,102 @@ boolean K_IsSPBInGame(void)
return false;
}
void K_HandleDirectionalInfluence(player_t *player)
{
fixed_t strength = FRACUNIT >> 1; // 1.0 == 45 degrees
ticcmd_t *cmd = NULL;
angle_t sideAngle = ANGLE_MAX;
INT16 inputX, inputY;
INT16 inputLen;
fixed_t diX, diY;
fixed_t diLen;
fixed_t diMul;
fixed_t dot, invDot;
fixed_t finalX, finalY;
fixed_t finalLen;
fixed_t speed;
if (player->playerstate != PST_LIVE || player->spectator)
{
// ded
return;
}
// DI attempted!!
player->justDI = true;
cmd = &player->cmd;
inputX = cmd->throwdir;
inputY = -cmd->turning;
if (player->flipDI == true)
{
// Bananas flip the DI direction.
// Otherwise, DIing bananas is a little brain-dead easy :p
inputX = -inputX;
inputY = -inputY;
}
if (inputX == 0 && inputY == 0)
{
// No DI input, no need to do anything else.
return;
}
inputLen = FixedHypot(inputX, inputY);
if (inputLen > KART_FULLTURN)
{
inputLen = KART_FULLTURN;
}
if (player->tumbleBounces > 0)
{
// Very strong DI for tumble.
strength *= 3;
}
sideAngle = player->mo->angle - ANGLE_90;
diX = FixedMul(inputX, FINECOSINE(player->mo->angle >> ANGLETOFINESHIFT)) + FixedMul(inputY, FINECOSINE(sideAngle >> ANGLETOFINESHIFT));
diY = FixedMul(inputX, FINESINE(player->mo->angle >> ANGLETOFINESHIFT)) + FixedMul(inputY, FINESINE(sideAngle >> ANGLETOFINESHIFT));
diLen = FixedHypot(diX, diY);
// Normalize
diMul = (KART_FULLTURN * FRACUNIT) / inputLen;
if (diLen > 0)
{
diX = FixedMul(diMul, FixedDiv(diX, diLen));
diY = FixedMul(diMul, FixedDiv(diY, diLen));
}
// Now that we got the DI direction, we can
// actually preform the velocity redirection.
speed = FixedHypot(player->mo->momx, player->mo->momy);
finalX = FixedDiv(player->mo->momx, speed);
finalY = FixedDiv(player->mo->momy, speed);
dot = FixedMul(diX, finalX) + FixedMul(diY, finalY);
invDot = FRACUNIT - abs(dot);
finalX += FixedMul(FixedMul(diX, invDot), strength);
finalY += FixedMul(FixedMul(diY, invDot), strength);
finalLen = FixedHypot(finalX, finalY);
if (finalLen > 0)
{
finalX = FixedDiv(finalX, finalLen);
finalY = FixedDiv(finalY, finalLen);
}
player->mo->momx = FixedMul(speed, finalX);
player->mo->momy = FixedMul(speed, finalY);
}
//}

View file

@ -143,6 +143,7 @@ UINT8 K_GetInvincibilityItemFrame(void);
UINT8 K_GetOrbinautItemFrame(UINT8 count);
boolean K_IsSPBInGame(void);
void K_KartEbrakeVisuals(player_t *p);
void K_HandleDirectionalInfluence(player_t *player);
// sound stuff for lua
void K_PlayAttackTaunt(mobj_t *source);

View file

@ -238,6 +238,10 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->tumbleBounces);
else if (fastcmp(field,"tumbleHeight"))
lua_pushinteger(L, plr->tumbleHeight);
else if (fastcmp(field,"justDI"))
lua_pushboolean(L, plr->justDI);
else if (fastcmp(field,"flipDI"))
lua_pushboolean(L, plr->flipDI);
else if (fastcmp(field,"drift"))
lua_pushinteger(L, plr->drift);
else if (fastcmp(field,"driftcharge"))
@ -584,6 +588,10 @@ static int player_set(lua_State *L)
plr->tumbleBounces = luaL_checkinteger(L, 3);
else if (fastcmp(field,"tumbleHeight"))
plr->tumbleHeight = luaL_checkinteger(L, 3);
else if (fastcmp(field,"justDI"))
plr->justDI = luaL_checkboolean(L, 3);
else if (fastcmp(field,"flipDI"))
plr->flipDI = luaL_checkboolean(L, 3);
else if (fastcmp(field,"drift"))
plr->drift = luaL_checkinteger(L, 3);
else if (fastcmp(field,"driftcharge"))
@ -891,6 +899,8 @@ static int ticcmd_get(lua_State *L)
lua_pushinteger(L, cmd->forwardmove);
else if (fastcmp(field,"turning"))
lua_pushinteger(L, cmd->turning);
else if (fastcmp(field,"throwdir"))
lua_pushinteger(L, cmd->throwdir);
else if (fastcmp(field,"aiming"))
lua_pushinteger(L, cmd->aiming);
else if (fastcmp(field,"buttons"))
@ -919,6 +929,8 @@ static int ticcmd_set(lua_State *L)
cmd->forwardmove = (SINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"turning"))
cmd->turning = (INT16)luaL_checkinteger(L, 3);
else if (fastcmp(field,"throwdir"))
cmd->throwdir = (INT16)luaL_checkinteger(L, 3);
else if (fastcmp(field,"aiming"))
cmd->aiming = (INT16)luaL_checkinteger(L, 3);
else if (fastcmp(field,"buttons"))

View file

@ -2095,6 +2095,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
player->instashield = 15;
K_SetHitLagForObjects(target, inflictor, laglength, true);
if (inflictor && !P_MobjWasRemoved(inflictor) && inflictor->type == MT_BANANA)
{
player->flipDI = true;
}
return true;
}
}

View file

@ -9150,6 +9150,11 @@ void P_MobjThinker(mobj_t *mobj)
mobj->spriteyscale = 5*FRACUNIT;
}
if (mobj->player != NULL && mobj->hitlag == 0 && (mobj->eflags & MFE_DAMAGEHITLAG))
{
K_HandleDirectionalInfluence(mobj->player);
}
return;
}

View file

@ -244,6 +244,9 @@ static void P_NetArchivePlayers(void)
WRITEUINT8(save_p, players[i].tumbleBounces);
WRITEUINT16(save_p, players[i].tumbleHeight);
WRITEUINT8(save_p, players[i].justDI);
WRITEUINT8(save_p, players[i].flipDI);
WRITESINT8(save_p, players[i].drift);
WRITEFIXED(save_p, players[i].driftcharge);
WRITEUINT8(save_p, players[i].driftboost);
@ -514,6 +517,9 @@ static void P_NetUnArchivePlayers(void)
players[i].tumbleBounces = READUINT8(save_p);
players[i].tumbleHeight = READUINT16(save_p);
players[i].justDI = (boolean)READUINT8(save_p);
players[i].flipDI = (boolean)READUINT8(save_p);
players[i].drift = READSINT8(save_p);
players[i].driftcharge = READFIXED(save_p);
players[i].driftboost = READUINT8(save_p);

View file

@ -2095,6 +2095,11 @@ void P_MovePlayer(player_t *player)
P_3dMovement(player);
if (cmd->turning == 0)
{
player->justDI = false;
}
// Kart frames
if (player->tumbleBounces > 0)
{
@ -4332,10 +4337,10 @@ void P_PlayerThink(player_t *player)
}
// Track airtime
if (P_IsObjectOnGround(player->mo))
if (P_IsObjectOnGround(player->mo)
&& !P_PlayerInPain(player)) // This isn't airtime, but it's control loss all the same.
{
if (!P_PlayerInPain(player))
player->airtime = 0;
player->airtime = 0;
}
else
{
@ -4347,17 +4352,20 @@ void P_PlayerThink(player_t *player)
// SRB2kart
// Save the dir the player is holding
// to allow items to be thrown forward or backward.
if (cmd->buttons & BT_FORWARD)
{
player->throwdir = 1;
}
else if (cmd->buttons & BT_BACKWARD)
{
player->throwdir = -1;
}
else
{
player->throwdir = 0;
const INT16 threshold = 0; //(KART_FULLTURN / 2);
if (cmd->throwdir > threshold)
{
player->throwdir = 1;
}
else if (cmd->throwdir < -threshold)
{
player->throwdir = -1;
}
else
{
player->throwdir = 0;
}
}
// Accessibility - kickstart your acceleration