mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-03-26 04:51:43 +00:00
Merge branch 'stun-balance' into 'master'
Stun adjustments for balance (resolves #1552) Closes #1552 See merge request kart-krew-dev/ring-racers-internal!2636
This commit is contained in:
commit
9c208d0236
9 changed files with 139 additions and 42 deletions
|
|
@ -740,7 +740,7 @@ struct player_t
|
|||
UINT8 tumbleBounces;
|
||||
UINT16 tumbleHeight; // In *mobjscaled* fracunits, or mfu, not raw fu
|
||||
UINT16 stunned; // Number of tics during which rings cannot be picked up
|
||||
UINT8 stunnedCombo; // Number of hits sustained while stunned, reduces consecutive stun penalties
|
||||
mobj_t *flybot; // One Flybot767 circling the player while stunned
|
||||
UINT8 justDI; // Turn-lockout timer to briefly prevent unintended turning after DI, resets when actionable or no input
|
||||
boolean flipDI; // Bananas flip the DI direction. Was a bug, but it made bananas much more interesting.
|
||||
|
||||
|
|
|
|||
83
src/k_kart.c
83
src/k_kart.c
|
|
@ -9738,23 +9738,12 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
&& P_IsObjectOnGround(player->mo)
|
||||
)
|
||||
{
|
||||
// MEGA FUCKING HACK BECAUSE P_SAVEG MOBJS ARE FULL
|
||||
// Would updating player_saveflags to 32 bits have any negative consequences?
|
||||
// For now, player->stunned 16th bit is a flag to determine whether the flybots were spawned
|
||||
|
||||
// timer counts down at triple speed while spindashing
|
||||
player->stunned = (player->stunned & 0x8000) | max(0, (player->stunned & 0x7FFF) - (player->spindash ? 3 : 1));
|
||||
player->stunned = max(0, player->stunned - (player->spindash ? 3 : 1));
|
||||
|
||||
// when timer reaches 0, reset the flag and stun combo counter
|
||||
if ((player->stunned & 0x7FFF) == 0)
|
||||
// if the flybots aren't spawned, spawn them now!
|
||||
if (player->stunned != 0 && P_MobjWasRemoved(player->flybot))
|
||||
{
|
||||
player->stunned = 0;
|
||||
player->stunnedCombo = 0;
|
||||
}
|
||||
// otherwise if the flybots aren't spawned, spawn them now!
|
||||
else if ((player->stunned & 0x8000) == 0)
|
||||
{
|
||||
player->stunned |= 0x8000;
|
||||
Obj_SpawnFlybotsForPlayer(player);
|
||||
}
|
||||
}
|
||||
|
|
@ -16313,4 +16302,70 @@ fixed_t K_TeamComebackMultiplier(player_t *player)
|
|||
return multiplier;
|
||||
}
|
||||
|
||||
void K_ApplyStun(player_t *player, mobj_t *inflictor, mobj_t *source, ATTRUNUSED INT32 damage, ATTRUNUSED UINT8 damagetype)
|
||||
{
|
||||
#define BASE_STUN_TICS_MIN (4 * TICRATE)
|
||||
#define BASE_STUN_TICS_MAX (10 * TICRATE)
|
||||
#define MAX_STUN_REDUCTION (FRACUNIT/2)
|
||||
#define STUN_REDUCTION_DISTANCE (20000)
|
||||
INT32 stunTics = 0;
|
||||
UINT8 numPlayers = 0;
|
||||
UINT8 i;
|
||||
|
||||
// calculate the number of players playing
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && !players[i].spectator)
|
||||
{
|
||||
numPlayers++;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate base stun tics
|
||||
stunTics = Easing_Linear((player->kartweight - 1) * FRACUNIT / 8, BASE_STUN_TICS_MAX, BASE_STUN_TICS_MIN);
|
||||
|
||||
// reduce stun in games with more than 8 players
|
||||
if (numPlayers > 8)
|
||||
{
|
||||
stunTics -= 6 * (numPlayers - 8);
|
||||
}
|
||||
|
||||
// 1/3 stun values in battle
|
||||
if (gametyperules & GTR_SPHERES)
|
||||
{
|
||||
stunTics /= 3;
|
||||
}
|
||||
|
||||
if (source && source->player)
|
||||
{
|
||||
// hits scored by players apply full stun
|
||||
;
|
||||
}
|
||||
else if (inflictor && (P_IsKartItem(inflictor->type) || P_IsKartFieldItem(inflictor->type)))
|
||||
{
|
||||
// items not thrown by a player apply half stun
|
||||
stunTics /= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// all other hazards apply 1/4 stun
|
||||
stunTics /= 4;
|
||||
}
|
||||
|
||||
UINT32 dist = K_GetItemRouletteDistance(player, D_NumPlayersInRace());
|
||||
if (dist > STUN_REDUCTION_DISTANCE)
|
||||
dist = STUN_REDUCTION_DISTANCE;
|
||||
|
||||
fixed_t distfactor = FixedDiv(dist, STUN_REDUCTION_DISTANCE); // 0-1 as you approach STUN_REDUCTION_DISTANCE
|
||||
fixed_t stunfactor = Easing_Linear(distfactor, FRACUNIT, MAX_STUN_REDUCTION);
|
||||
stunTics = FixedMul(stunTics*FRACUNIT, stunfactor)/FRACUNIT;
|
||||
|
||||
player->stunned = max(stunTics, 0);
|
||||
|
||||
#undef BASE_STUN_TICS_MIN
|
||||
#undef BASE_STUN_TICS_MAX
|
||||
#undef MAX_STUN_REDUCTION
|
||||
#undef STUN_REDUCTION_DISTANCE
|
||||
}
|
||||
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -340,6 +340,8 @@ boolean K_TryPickMeUp(mobj_t *m1, mobj_t *m2, boolean allowHostile);
|
|||
|
||||
fixed_t K_TeamComebackMultiplier(player_t *player);
|
||||
|
||||
void K_ApplyStun(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -440,6 +440,7 @@ void Obj_DestroyedKartParticleLanding(mobj_t *part);
|
|||
void Obj_SpawnFlybotsForPlayer(player_t *player);
|
||||
void Obj_FlybotThink(mobj_t *flybot);
|
||||
void Obj_FlybotDeath(mobj_t *flybot);
|
||||
void Obj_FlybotRemoved(mobj_t *flybot);
|
||||
|
||||
/* Pulley */
|
||||
void Obj_PulleyThink(mobj_t *root);
|
||||
|
|
|
|||
|
|
@ -262,8 +262,8 @@ static int player_get(lua_State *L)
|
|||
lua_pushinteger(L, plr->tumbleHeight);
|
||||
else if (fastcmp(field,"stunned"))
|
||||
lua_pushinteger(L, plr->stunned);
|
||||
else if (fastcmp(field,"stunnedcombo"))
|
||||
lua_pushinteger(L, plr->stunnedCombo);
|
||||
else if (fastcmp(field,"flybot"))
|
||||
LUA_PushUserdata(L, plr->flybot, META_MOBJ);
|
||||
else if (fastcmp(field,"justdi"))
|
||||
lua_pushinteger(L, plr->justDI);
|
||||
else if (fastcmp(field,"flipdi"))
|
||||
|
|
@ -896,8 +896,13 @@ static int player_set(lua_State *L)
|
|||
plr->tumbleHeight = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"stunned"))
|
||||
plr->stunned = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"stunnedcombo"))
|
||||
plr->stunnedCombo = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"flybot"))
|
||||
{
|
||||
mobj_t *mo = NULL;
|
||||
if (!lua_isnil(L, 3))
|
||||
mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
|
||||
P_SetTarget(&plr->flybot, mo);
|
||||
}
|
||||
else if (fastcmp(field,"justdi"))
|
||||
plr->justDI = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"flipdi"))
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ void Obj_SpawnFlybotsForPlayer(player_t *player)
|
|||
{
|
||||
UINT8 i;
|
||||
mobj_t *mo = player->mo;
|
||||
mobj_t *hprev = mo;
|
||||
fixed_t radius = mo->radius;
|
||||
|
||||
for (i = 0; i < FLYBOT_QUANTITY; i++)
|
||||
|
|
@ -61,6 +62,17 @@ void Obj_SpawnFlybotsForPlayer(player_t *player)
|
|||
flybot->movedir = flybot->old_angle = flybot->angle = angle + ANGLE_90;
|
||||
flybot->old_z = SetFlybotZ(flybot);
|
||||
flybot->renderflags |= (i * RF_DONTDRAW);
|
||||
|
||||
if (hprev->player)
|
||||
{
|
||||
P_SetTarget(&player->flybot, flybot);
|
||||
}
|
||||
else
|
||||
{
|
||||
P_SetTarget(&hprev->hnext, flybot);
|
||||
P_SetTarget(&flybot->hprev, hprev);
|
||||
}
|
||||
hprev = flybot;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -80,11 +92,18 @@ void Obj_FlybotThink(mobj_t *flybot)
|
|||
|
||||
if (mo->player)
|
||||
{
|
||||
if (((stunned = mo->player->stunned & 0x7FFF) == 0) || (mo->player->playerstate == PST_DEAD))
|
||||
if (((stunned = mo->player->stunned) == 0) || (mo->player->playerstate == PST_DEAD))
|
||||
{
|
||||
P_KillMobj(flybot, NULL, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// If player is spindashing, spin faster to hint that stun is going down faster
|
||||
else if (mo->player->spindash)
|
||||
{
|
||||
speed *= 2;
|
||||
flybot->movedir += FLYBOT_BOB_FREQUENCY*2;
|
||||
}
|
||||
}
|
||||
|
||||
flybot->frame = flybot->frame & ~FF_TRANSMASK;
|
||||
|
|
@ -120,6 +139,11 @@ void Obj_FlybotDeath(mobj_t *flybot)
|
|||
|
||||
if (!P_MobjWasRemoved(mo))
|
||||
{
|
||||
if (mo->player && (flybot == mo->player->flybot))
|
||||
{
|
||||
P_SetTarget(&mo->player->flybot, NULL);
|
||||
}
|
||||
|
||||
mom.x = mo->momx;
|
||||
mom.y = mo->momy;
|
||||
mom.z = mo->momz;
|
||||
|
|
@ -140,3 +164,12 @@ void Obj_FlybotDeath(mobj_t *flybot)
|
|||
angle += ANGLE_90;
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_FlybotRemoved(mobj_t *flybot)
|
||||
{
|
||||
mobj_t *mo = flybot->target;
|
||||
if (!P_MobjWasRemoved(mo) && mo->player && (flybot == mo->player->flybot))
|
||||
{
|
||||
P_SetTarget(&mo->player->flybot, NULL);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3041,7 +3041,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
UINT8 type = (damagetype & DMG_TYPEMASK);
|
||||
const boolean hardhit = (type == DMG_EXPLODE || type == DMG_KARMA || type == DMG_TUMBLE); // This damage type can do evil stuff like ALWAYS combo
|
||||
INT16 ringburst = 5;
|
||||
UINT16 stunTics = 0;
|
||||
|
||||
// Check if the player is allowed to be damaged!
|
||||
// If not, then spawn the instashield effect instead.
|
||||
|
|
@ -3488,26 +3487,11 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
}
|
||||
|
||||
// Apply stun!
|
||||
// Feel free to move these calculations higher up if different damage sources should apply variable stun in future
|
||||
#define MIN_STUNTICS (4 * TICRATE)
|
||||
#define MAX_STUNTICS (10 * TICRATE)
|
||||
stunTics = Easing_Linear((player->kartweight - 1) * FRACUNIT / 8, MAX_STUNTICS, MIN_STUNTICS);
|
||||
stunTics >>= player->stunnedCombo; // consecutive hits add half as much stun as the previous hit
|
||||
|
||||
// 1/3 base stun values in battle
|
||||
if (gametyperules & GTR_SPHERES)
|
||||
if (type != DMG_STING)
|
||||
{
|
||||
stunTics /= 3;
|
||||
K_ApplyStun(player, inflictor, source, damage, damagetype);
|
||||
}
|
||||
|
||||
if (player->stunnedCombo < UINT8_MAX)
|
||||
{
|
||||
player->stunnedCombo++;
|
||||
}
|
||||
player->stunned = (player->stunned & 0x8000) | min(0x7FFF, (player->stunned & 0x7FFF) + stunTics);
|
||||
#undef MIN_STUNTICS
|
||||
#undef MAX_STUNTICS
|
||||
|
||||
K_DefensiveOverdrive(target->player);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11855,6 +11855,11 @@ void P_RemoveMobj(mobj_t *mobj)
|
|||
Obj_UnlinkRocks(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_FLYBOT767:
|
||||
{
|
||||
Obj_FlybotRemoved(mobj);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -72,8 +72,7 @@ static savebuffer_t *current_savebuffer;
|
|||
#define ARCHIVEBLOCK_WAYPOINTS 0x7F46498F
|
||||
#define ARCHIVEBLOCK_RNG 0x7FAAB5BD
|
||||
|
||||
// Note: This cannot be bigger
|
||||
// than an UINT16 (for now)
|
||||
// Note: This cannot have more than 32 entries
|
||||
typedef enum
|
||||
{
|
||||
AWAYVIEW = 0x0001,
|
||||
|
|
@ -93,6 +92,7 @@ typedef enum
|
|||
BARRIER = 0x4000,
|
||||
BALLHOGRETICULE = 0x8000,
|
||||
STONESHOE = 0x10000,
|
||||
FLYBOT = 0x20000,
|
||||
} player_saveflags;
|
||||
|
||||
static inline void P_ArchivePlayer(savebuffer_t *save)
|
||||
|
|
@ -368,6 +368,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
if (players[i].stoneShoe)
|
||||
flags |= STONESHOE;
|
||||
|
||||
if (players[i].flybot)
|
||||
flags |= FLYBOT;
|
||||
|
||||
WRITEUINT32(save->p, flags);
|
||||
|
||||
if (flags & SKYBOXVIEW)
|
||||
|
|
@ -418,6 +421,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
if (flags & STONESHOE)
|
||||
WRITEUINT32(save->p, players[i].stoneShoe->mobjnum);
|
||||
|
||||
if (flags & FLYBOT)
|
||||
WRITEUINT32(save->p, players[i].flybot->mobjnum);
|
||||
|
||||
WRITEUINT32(save->p, (UINT32)players[i].followitem);
|
||||
|
||||
WRITEUINT32(save->p, players[i].charflags);
|
||||
|
|
@ -464,7 +470,6 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
WRITEUINT8(save->p, players[i].tumbleBounces);
|
||||
WRITEUINT16(save->p, players[i].tumbleHeight);
|
||||
WRITEUINT16(save->p, players[i].stunned);
|
||||
WRITEUINT8(save->p, players[i].stunnedCombo);
|
||||
|
||||
WRITEUINT8(save->p, players[i].justDI);
|
||||
WRITEUINT8(save->p, players[i].flipDI);
|
||||
|
|
@ -1073,6 +1078,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
if (flags & STONESHOE)
|
||||
players[i].stoneShoe = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
||||
if (flags & FLYBOT)
|
||||
players[i].flybot = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
||||
players[i].followitem = (mobjtype_t)READUINT32(save->p);
|
||||
|
||||
//SetPlayerSkinByNum(i, players[i].skin);
|
||||
|
|
@ -1120,7 +1128,6 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
players[i].tumbleBounces = READUINT8(save->p);
|
||||
players[i].tumbleHeight = READUINT16(save->p);
|
||||
players[i].stunned = READUINT16(save->p);
|
||||
players[i].stunnedCombo = READUINT8(save->p);
|
||||
|
||||
players[i].justDI = READUINT8(save->p);
|
||||
players[i].flipDI = (boolean)READUINT8(save->p);
|
||||
|
|
@ -6232,6 +6239,11 @@ static void P_RelinkPointers(void)
|
|||
if (!RelinkMobj(&players[i].stoneShoe))
|
||||
CONS_Debug(DBG_GAMELOGIC, "stoneShoe not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].flybot)
|
||||
{
|
||||
if (!RelinkMobj(&players[i].flybot))
|
||||
CONS_Debug(DBG_GAMELOGIC, "flybot not found on player %d\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue