diff --git a/src/d_player.h b/src/d_player.h index 7f286400c..64547b348 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -1062,6 +1062,7 @@ struct player_t UINT8 ringboxdelay; // Delay until Ring Box auto-activates UINT8 ringboxaward; // Where did we stop? + UINT32 lastringboost; // What was our accumulated boost when locking the award? UINT8 amps; UINT8 amppickup; diff --git a/src/f_finale.c b/src/f_finale.c index e3a41e495..a53d5414a 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -923,13 +923,11 @@ void F_IntroTicker(void) S_StartSound(NULL, sfx_supflk); } - if (skiptype == 5) // Quick Thunderdome + if (skiptype == 5) // Quick Race Menu { ResetSkipSequences(); - CV_StealthSetValue(&cv_kartbot, 13); - CV_StealthSetValue(&cv_maxplayers, 8); - CV_StealthSetValue(&cv_thunderdome, 1); - D_MapChange(G_RandMap(TOL_RACE, UINT16_MAX-1, true, false, NULL), GT_RACE, (cv_kartencore.value == 1), true, 0, false, false); + M_StartControlPanel(); + currentMenu = &PLAY_RaceGamemodesDef; return; } @@ -1023,19 +1021,19 @@ static void AdvanceSkipSequences(UINT8 input) UINT8 s2cheat[] = {1, 1, 1}; UINT8 s3cheat[] = {2, 2, 2}; UINT8 s3kcheat[] = {3, 3, 3}; - UINT8 thundercheat[] = {4, 4, 4}; + UINT8 spincheat[] = {4, 4, 4}; #else UINT8 s2cheat[] = {1, 1, 1, 3, 3, 3, 1}; UINT8 s3cheat[] = {1, 1, 3, 3, 1, 1, 1, 1}; UINT8 s3kcheat[] = {4, 4, 4, 2, 2, 2, 1, 1, 1}; - UINT8 thundercheat[] = {2, 4, 2, 4, 3, 3, 1, 1}; + UINT8 spincheat[] = {1, 2, 3, 4, 3, 2, 1}; #endif UINT8 nicetry[] = {1, 1, 3, 3, 4, 2, 4, 2}; #define NUMCHEATSPLUSONE 5 - UINT8 *cheats[NUMCHEATSPLUSONE] = {s2cheat, s3cheat, s3kcheat, nicetry, thundercheat}; - UINT8 cheatlengths[NUMCHEATSPLUSONE] = {sizeof(s2cheat), sizeof(s3cheat), sizeof(s3kcheat), sizeof(nicetry), sizeof(thundercheat)}; + UINT8 *cheats[NUMCHEATSPLUSONE] = {s2cheat, s3cheat, s3kcheat, nicetry, spincheat}; + UINT8 cheatlengths[NUMCHEATSPLUSONE] = {sizeof(s2cheat), sizeof(s3cheat), sizeof(s3kcheat), sizeof(nicetry), sizeof(spincheat)}; for (UINT8 i = 0; i < NUMCHEATSPLUSONE; i++) // for each cheat... { diff --git a/src/k_kart.c b/src/k_kart.c index 6b3be07bb..5173fa3eb 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -292,7 +292,7 @@ void K_TimerInit(void) if (G_TimeAttackStart()) { - starttime = 15*TICRATE; // Longest permitted start. No half-laps in reverse. + starttime = 10*TICRATE; // Longest permitted start. No half-laps in reverse. // (Changed on finish line cross later, don't worry.) } @@ -9399,13 +9399,20 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) // extreme ringboost duration. Less aggressive for accel types, so they // retain more speed for small payouts. + // 2.4: Even if it IS paying out, if the duration gets extreme, + // start applying decay anyway! + UINT8 roller = TICRATE*2; roller += 4*(8-player->kartspeed); + // UINT16 oldringboost = player->ringboost; + if (player->superring == 0) player->ringboost -= max((player->ringboost / roller), 1); else - player->ringboost--; + player->ringboost -= min(K_GetFullKartRingPower(player, false) - 1, max(player->ringboost / 2 / roller, 1)); + + // CONS_Printf("%d - %d\n", player->ringboost, oldringboost - player->ringboost); } if (player->sneakertimer) @@ -9678,7 +9685,13 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->superring) { player->nextringaward++; - UINT8 ringrate = 3 - min(2, player->superring / 20); // Used to consume fat stacks of cash faster. + + UINT8 fastringscaler = (K_GetKartGameSpeedScalar(gamespeed) > FRACUNIT) ? 20 : 20; // If G3 / TA gets out of control, can speed up all ring box payout + + UINT32 existing = (player->lastringboost / K_GetFullKartRingPower(player, true)); // How many rings (effectively) do we have boost credit for right now? + + UINT8 ringrate = 3 - min(2, (player->superring + existing) / fastringscaler); // Used to consume fat stacks of cash faster. + if (player->nextringaward >= ringrate) { if (player->instaWhipCharge) @@ -11001,6 +11014,11 @@ INT32 K_GetKartRingPower(const player_t *player, boolean boosted) return max(ringPower / FRACUNIT, 1); } +INT32 K_GetFullKartRingPower(const player_t *player, boolean boosted) +{ + return 3 + K_GetKartRingPower(player, boosted); +} + // Returns false if this player being placed here causes them to collide with any other player // Used in g_game.c for match etc. respawning // This does not check along the z because the z is not correctly set for the spawnee at this point @@ -11680,6 +11698,12 @@ static void K_KartDrift(player_t *player, boolean onground) K_SpawnDriftSparks(player); } + // Magic numbers ahoy! Meant to allow purple drifts to progress past color transition. + if ((player->driftcharge + driftadditive) > (dsthree+(32*3)) && K_TimeAttackRules() && leveltime < starttime) + { + driftadditive = max(0, (dsthree+(32*3)) - player->driftcharge); + } + if ((player->driftcharge < dsone && player->driftcharge+driftadditive >= dsone) || (player->driftcharge < dstwo && player->driftcharge+driftadditive >= dstwo) || (player->driftcharge < dsthree && player->driftcharge+driftadditive >= dsthree)) @@ -13144,6 +13168,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->ringboxdelay--; if (player->ringboxdelay == 0) { + player->lastringboost = player->ringboost; UINT32 award = 5*player->ringboxaward + 10; if (!K_ThunderDome()) award = 3 * award / 2; @@ -13155,28 +13180,41 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } else if (modeattacking) { - // At high distance values, the power of Ring Box is mainly an extra source of speed, to be - // stacked with power items (or itself!) during the payout period. - // Low-dist Ring Box follows some special rules, to somewhat normalize the reward between stat - // blocks that respond to rings differently; here, variance in payout period counts for a lot! + // TA has: + // - no one to tether from + // - no player damage + // - no player bumps + // ...which nullifies a lot of designed advantages for accel types and high-weight racers. + // + // In addition, it's at Gear 3 Thunderdome speed, which can make it hard for heavies to + // take strong lines without brakedrifting. + // + // To try and help close this gap, we fudge Ring Box payouts to allow weaker characters + // better access to things that make them go fast, without changing core handling. UINT8 accel = 10-player->kartspeed; UINT8 weight = player->kartweight; - // Fixed point math can suck a dick. + // Relative stat power for bonus TA Ring Box awards. + // AP 1, WP 2 = weight is worth twice what accel is. + // 0 = stat not considered at all! + UINT8 accelPower = 0; + UINT8 weightPower = 4; - if (accel > weight) - { - accel *= 10; - weight *= 3; - } - else - { - accel *= 3; - weight *= 10; - } + UINT8 total = accelPower*accel + weightPower*weight; + UINT8 maxtotal = accelPower*9 + weightPower*9; - award = (110 + accel + weight) * award / 120; + // Scale from base payout at 9/1 to max payout at 1/9. + award = Easing_InCubic(FRACUNIT*total/maxtotal, 13*award/10, 18*award/10); + + // And, because we don't have to give a damn about sandbagging, up the stakes the longer we progress! + if (gametyperules & GTR_CIRCUIT) + { + UINT8 maxgrade = 10; + UINT8 margin = min(player->gradingpointnum, maxgrade); + + award = Easing_Linear(FRACUNIT * margin / maxgrade, award, 2*award); + } } else { @@ -13187,6 +13225,19 @@ void K_MoveKartPlayer(player_t *player, boolean onground) award = award * (behindMulti + 10) / 10; } + // Felt kinda arbitrary, replaced with G3+ fast payout. Sealed away for later...? + + /* + // Stacked Ring Box is good. REALLY good. "Uncapped speed that feeds into itself" good. + // Keep highly unusual values under control, using the following core rule: + // If we already have more boost than we're about to be awarded, STOP!!! + UINT32 existing = (player->ringboost / K_GetFullKartRingPower(player, true)); // How many rings (effectively) do we have boost credit for right now? + UINT32 reduction = 8*existing/10; // Take an arbitrary percentage of those rings, and... + fixed_t reductionfactor = FixedDiv(FRACUNIT*reduction, FRACUNIT*award); // ...get a ratio to compare our potential award against it. 0 = no existing boost, 1+ = existing boost comparable to our award. + reductionfactor = min(reductionfactor, FRACUNIT); // Cap for easing function, and... + award = Easing_Linear(reductionfactor, award, award/4); // ...ease between unmodified and minimum award. + */ + K_AwardPlayerRings(player, award, true); player->ringboxaward = 0; } diff --git a/src/k_kart.h b/src/k_kart.h index 502bf7d45..00b0e44c3 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -201,6 +201,7 @@ void K_RepairOrbitChain(mobj_t *orbit); void K_CalculateBananaSlope(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player); mobj_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range); INT32 K_GetKartRingPower(const player_t *player, boolean boosted); +INT32 K_GetFullKartRingPower(const player_t *player, boolean boosted); boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y); INT16 K_UpdateSteeringValue(INT16 inputSteering, INT16 destSteering); INT16 K_GetKartTurnValue(const player_t *player, INT16 turnvalue); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index d706ac381..62eca4611 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -288,6 +288,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->ringboxdelay); else if (fastcmp(field,"ringboxaward")) lua_pushinteger(L, plr->ringboxaward); + else if (fastcmp(field,"lastringboost")) + lua_pushinteger(L, plr->lastringboost); else if (fastcmp(field,"amps")) lua_pushinteger(L, plr->amps); else if (fastcmp(field,"amppickup")) @@ -898,6 +900,8 @@ static int player_set(lua_State *L) plr->ringboxdelay = luaL_checkinteger(L, 3); else if (fastcmp(field,"ringboxaward")) plr->ringboxaward = luaL_checkinteger(L, 3); + else if (fastcmp(field,"lastringboost")) + plr->lastringboost = luaL_checkinteger(L, 3); else if (fastcmp(field,"amps")) plr->amps = luaL_checkinteger(L, 3); else if (fastcmp(field,"amppickup")) diff --git a/src/p_enemy.c b/src/p_enemy.c index 8c7ec2ce1..270c20aea 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3519,7 +3519,7 @@ void A_AttractChase(mobj_t *actor) angle_t offset = FixedAngle(18<target->player->ringboost += K_GetKartRingPower(actor->target->player, true) + 3; + actor->target->player->ringboost += K_GetFullKartRingPower(actor->target->player, true); S_ReducedVFXSoundAtVolume(actor->target, sfx_s1b5, actor->target->player->ringvolume, NULL); @@ -3575,7 +3575,7 @@ void A_AttractChase(mobj_t *actor) if (actor->extravalue1 >= 16) { if (!P_GivePlayerRings(actor->target->player, 1)) // returns 0 if addition failed - actor->target->player->ringboost += K_GetKartRingPower(actor->target->player, true) + 3; + actor->target->player->ringboost += K_GetFullKartRingPower(actor->target->player, true); if (actor->cvmem) // caching S_StartSound(actor->target, sfx_s1c5); diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 224342b0c..9f11fbb70 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -658,6 +658,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].ringboxdelay); WRITEUINT8(save->p, players[i].ringboxaward); + WRITEUINT32(save->p, players[i].lastringboost); WRITEUINT8(save->p, players[i].amps); WRITEUINT8(save->p, players[i].amppickup); @@ -1294,6 +1295,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].ringboxdelay = READUINT8(save->p); players[i].ringboxaward = READUINT8(save->p); + players[i].lastringboost = READUINT32(save->p); players[i].amps =READUINT8(save->p); players[i].amppickup =READUINT8(save->p);