From 56c23339be5c4a6276e8912b88fe116371bcb53f Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 20 May 2022 01:45:16 -0400 Subject: [PATCH] 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. --- src/d_clisrv.c | 3 +- src/d_player.h | 2 + src/d_ticcmd.h | 7 ++- src/deh_tables.c | 2 - src/g_demo.c | 28 ++++++++--- src/g_game.c | 19 +++++-- src/k_bot.c | 4 +- src/k_botitem.c | 10 +--- src/k_kart.c | 120 +++++++++++++++++++++++++++++++++++++++++++- src/k_kart.h | 1 + src/lua_playerlib.c | 12 +++++ src/p_inter.c | 6 +++ src/p_mobj.c | 5 ++ src/p_saveg.c | 6 +++ src/p_user.c | 34 ++++++++----- 15 files changed, 215 insertions(+), 44 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 7f6e6f287..21016d41c 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -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); diff --git a/src/d_player.h b/src/d_player.h index 60ca7c4bd..bd999641c 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -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 diff --git a/src/d_ticcmd.h b/src/d_ticcmd.h index 226c8f4d8..4b264a68a 100644 --- a/src/d_ticcmd.h +++ b/src/d_ticcmd.h @@ -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? diff --git a/src/deh_tables.c b/src/deh_tables.c index faa5010ad..a45e0ddab 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -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 diff --git a/src/g_demo.c b/src/g_demo.c index c53166e8e..db1e1db0f 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -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) diff --git a/src/g_game.c b/src/g_game.c index dd4723c91..411f85860 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -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; diff --git a/src/k_bot.c b/src/k_bot.c index 9e1212b1f..473ad5844 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -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; } } diff --git a/src/k_botitem.c b/src/k_botitem.c index 6f8e82034..4e509df0c 100644 --- a/src/k_botitem.c +++ b/src/k_botitem.c @@ -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; diff --git a/src/k_kart.c b/src/k_kart.c index 4edb34b5c..c8d3d4ef2 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -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)<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); +} + //} diff --git a/src/k_kart.h b/src/k_kart.h index d6ba0f720..89f176d29 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -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); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 3d05d9c15..506d6b96a 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -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")) diff --git a/src/p_inter.c b/src/p_inter.c index aceb8336c..9e98a8808 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -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; } } diff --git a/src/p_mobj.c b/src/p_mobj.c index c9f68b8f3..e21c2731e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -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; } diff --git a/src/p_saveg.c b/src/p_saveg.c index bebc5c161..84157decb 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -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); diff --git a/src/p_user.c b/src/p_user.c index 51016d80e..40cf52720 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -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