Merge pull request 'Hardcoded Stacking and Chaining' (#33) from stackingmaybe into blankart-dev

Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/33
This commit is contained in:
NepDisk 2025-03-26 18:30:19 +00:00
commit f338eec51a
21 changed files with 840 additions and 109 deletions

View file

@ -74,6 +74,7 @@ static char * COM_Purge (char *text, int *lenp);
CV_PossibleValue_t CV_OnOff[] = {{0, "Off"}, {1, "On"}, {0, NULL}};
CV_PossibleValue_t CV_YesNo[] = {{0, "No"}, {1, "Yes"}, {0, NULL}};
CV_PossibleValue_t CV_Signed[] = {{-999999999, "MIN"}, {999999999, "MAX"}, {0, NULL}};
CV_PossibleValue_t CV_Unsigned[] = {{0, "MIN"}, {999999999, "MAX"}, {0, NULL}};
CV_PossibleValue_t CV_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}};

View file

@ -170,6 +170,7 @@ struct consvar_t //NULL, NULL, 0, NULL, NULL |, 0, NULL, NULL, 0, 0, NULL
extern CV_PossibleValue_t CV_OnOff[];
extern CV_PossibleValue_t CV_YesNo[];
extern CV_PossibleValue_t CV_Signed[];
extern CV_PossibleValue_t CV_Unsigned[];
extern CV_PossibleValue_t CV_Natural[];

View file

@ -151,6 +151,8 @@ static void KartEncore_OnChange(void);
static void KartComeback_OnChange(void);
static void KartEliminateLast_OnChange(void);
static void KartRings_OnChange(void);
static void KartStacking_OnChange(void);
static void KartChaining_OnChange(void);
static void KartItemBreaker_OnChange(void);
static void Schedule_OnChange(void);
@ -436,22 +438,57 @@ static CV_PossibleValue_t kartbot_cons_t[] = {
};
consvar_t cv_kartbot = CVAR_INIT ("kartbot", "0", CV_NETVAR, kartbot_cons_t, NULL);
consvar_t cv_karteliminatelast = CVAR_INIT ("karteliminatelast", "Yes", CV_NETVAR|CV_CHEAT|CV_CALL, CV_YesNo, KartEliminateLast_OnChange);
consvar_t cv_karteliminatelast = CVAR_INIT ("karteliminatelast", "Yes", CV_NETVAR|CV_CALL, CV_YesNo, KartEliminateLast_OnChange);
// Toggles for new features
consvar_t cv_kartrings = CVAR_INIT ("kartrings", "No", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_YesNo, KartRings_OnChange);
consvar_t cv_kartrings = CVAR_INIT ("kartrings", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, KartRings_OnChange);
// Stacking related
consvar_t cv_kartstacking = CVAR_INIT ("kartstacking", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, KartStacking_OnChange);
consvar_t cv_kartstacking_calc_arg_offset = CVAR_INIT ("kartstacking_calcargoffset", "0.32", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_maxvanillaboost = CVAR_INIT ("kartstacking_maxvanillaboost", "0.375", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_speedboostdropoff = CVAR_INIT ("kartstacking_speedboostdropoff", "0.01", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_speedboostdropoff_brake = CVAR_INIT ("kartstacking_speedboostdropoff_brake", "0.05", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
// Vanilla Stacking boosts.
consvar_t cv_kartstacking_sneaker_easyspeedboost = CVAR_INIT ("vanillaboost_sneaker_easyspeedboost", "0.8317", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_sneaker_normalspeedboost = CVAR_INIT ("vanillaboost_sneaker_normalspeedboost", "0.5", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_sneaker_hardspeedboost = CVAR_INIT ("vanillaboost_sneaker_hardspeedboost", "0.2756", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_sneaker_accelboost = CVAR_INIT ("vanillaboost_sneaker_accelboost", "8.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_sneaker_maxgrade = CVAR_INIT ("vanillaboost_sneaker_maxgrade", "3", CV_NETVAR|CV_CHEAT, CV_Natural, NULL);
consvar_t cv_kartstacking_invincibility_speedboost = CVAR_INIT ("vanillaboost_invincibility_speedboost", "0.375", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_invincibility_accelboost = CVAR_INIT ("vanillaboost_invincibility_accelboost", "3.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_grow_speedboost = CVAR_INIT ("vanillaboost_grow_speedboost", "0.2", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_grow_accelboost = CVAR_INIT ("vanillaboost_grow_accelboost", "0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_flame_speedval = CVAR_INIT ("vanillaboost_flame_speedval", "0.80", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_flame_accelboost = CVAR_INIT ("vanillaboost_flame_accelboost", "3.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_start_speedboost = CVAR_INIT ("vanillaboost_start_speedboost", "0.25", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_start_accelboost = CVAR_INIT ("vanillaboost_start_accelboost", "6.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_drift_speedboost = CVAR_INIT ("vanillaboost_drift_speedboost", "0.25", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_drift_accelboost = CVAR_INIT ("vanillaboost_drift_accelboost", "4.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_ring_speedboost = CVAR_INIT ("vanillaboost_ring_speedboost", "0.2", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_ring_accelboost = CVAR_INIT ("vanillaboost_ring_accelboost", "4.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartchaining = CVAR_INIT ("kartchaining", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, KartChaining_OnChange);
consvar_t cv_kartchainingoffroad = CVAR_INIT ("kartchaining_chainoffroad", "No", CV_NETVAR, CV_YesNo, NULL);
consvar_t cv_kartitembreaker = CVAR_INIT ("kartitembreaker", "No", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_YesNo, KartItemBreaker_OnChange);
consvar_t cv_kartwalltransfer = CVAR_INIT ("BG_forcewalltransfer", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_kartusepwrlv = CVAR_INIT ("kartusepwrlv", "Yes", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL);
consvar_t cv_kartusepwrlv = CVAR_INIT ("kartusepwrlv", "Yes", CV_NETVAR, CV_YesNo, NULL);
consvar_t cv_kartpurpledrift = CVAR_INIT ("kartpurpledrift", "No", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL);
consvar_t cv_kartpurpledrift = CVAR_INIT ("kartpurpledrift", "No", CV_NETVAR, CV_YesNo, NULL);
consvar_t cv_kartbumpspark = CVAR_INIT ("kartbumpspark", "No", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL);
consvar_t cv_kartbumpspark = CVAR_INIT ("kartbumpspark", "No", CV_NETVAR, CV_YesNo, NULL);
consvar_t cv_kartbumpspring = CVAR_INIT ("kartbumpspring", "No", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL);
consvar_t cv_kartbumpspring = CVAR_INIT ("kartbumpspring", "No", CV_NETVAR, CV_YesNo, NULL);
static CV_PossibleValue_t kartdebugitem_cons_t[] =
{
@ -6941,16 +6978,82 @@ static void KartRings_OnChange(void)
return;
}
if (cv_kartrings.value)
if (!K_RingsActive() && cv_kartrings.value)
{
CONS_Printf(M_GetText("Rings will be turned \"On\" Next Round.\n"));
}
else
else if (K_RingsActive() && !cv_kartrings.value)
{
CONS_Printf(M_GetText("Rings will be turned \"Off\" Next Round.\n"));
}
}
static void KartStacking_OnChange(void)
{
if (K_CanChangeRules() == false)
{
return;
}
if (!stackingactive && cv_kartstacking.value)
{
if (leveltime < starttime)
{
stackingactive = true;
CONS_Printf(M_GetText("Boost Stacking has been turned \"On\".\n"));
}
else
{
CONS_Printf(M_GetText("Boost Stacking will be turned \"On\" next round.\n"));
}
}
else if (stackingactive && !cv_kartstacking.value)
{
if (leveltime < starttime)
{
stackingactive = false;
CONS_Printf(M_GetText("Boost Stacking has been turned \"Off\".\n"));
}
else
{
CONS_Printf(M_GetText("Boost Stacking will be turned \"Off\" next round.\n"));
}
}
}
static void KartChaining_OnChange(void)
{
if (K_CanChangeRules() == false)
{
return;
}
if (!chainingactive && cv_kartchaining.value)
{
if (leveltime < starttime)
{
chainingactive = true;
CONS_Printf(M_GetText("Boost Chaining has been turned \"On\".\n"));
}
else
{
CONS_Printf(M_GetText("Boost Chaining will be turned \"On\" Next Round.\n"));
}
}
else if (chainingactive && !cv_kartstacking.value)
{
if (leveltime < starttime)
{
chainingactive = false;
CONS_Printf(M_GetText("Boost Chaining has been turned \"Off\".\n"));
}
else
{
CONS_Printf(M_GetText("Boost Chaining will be turned \"Off\" next round.\n"));
}
}
}
static void KartItemBreaker_OnChange(void)
{
if (K_CanChangeRules() == false)
@ -6958,11 +7061,16 @@ static void KartItemBreaker_OnChange(void)
return;
}
if (cv_kartitembreaker.value)
if (!multiplayer)
{
return;
}
if (!itembreaker && cv_kartitembreaker.value)
{
CONS_Printf(M_GetText("Singleplayer Item Breaker will be turned \"On\" Next Round.\n"));
}
else
else if (itembreaker && !cv_kartitembreaker.value)
{
CONS_Printf(M_GetText("Singleplayer Item Breaker will be turned \"Off\" Next Round.\n"));
}

View file

@ -96,6 +96,40 @@ extern consvar_t cv_kartbot;
extern consvar_t cv_karteliminatelast;
extern consvar_t cv_kartusepwrlv;
extern consvar_t cv_kartrings;
extern consvar_t cv_kartstacking;
extern consvar_t cv_kartstacking_calc_arg_offset;
extern consvar_t cv_kartstacking_maxvanillaboost;
extern consvar_t cv_kartstacking_speedboostdropoff;
extern consvar_t cv_kartstacking_speedboostdropoff_brake;
extern consvar_t cv_kartstacking_sneaker_easyspeedboost;
extern consvar_t cv_kartstacking_sneaker_normalspeedboost;
extern consvar_t cv_kartstacking_sneaker_hardspeedboost;
extern consvar_t cv_kartstacking_sneaker_accelboost;
extern consvar_t cv_kartstacking_sneaker_maxgrade;
extern consvar_t cv_kartstacking_invincibility_speedboost;
extern consvar_t cv_kartstacking_invincibility_accelboost;
extern consvar_t cv_kartstacking_flame_speedval;
extern consvar_t cv_kartstacking_flame_accelboost;
extern consvar_t cv_kartstacking_grow_speedboost;
extern consvar_t cv_kartstacking_grow_accelboost;
extern consvar_t cv_kartstacking_start_speedboost;
extern consvar_t cv_kartstacking_start_accelboost;
extern consvar_t cv_kartstacking_drift_speedboost;
extern consvar_t cv_kartstacking_drift_accelboost;
extern consvar_t cv_kartstacking_ring_speedboost;
extern consvar_t cv_kartstacking_ring_accelboost;
extern consvar_t cv_kartchaining;
extern consvar_t cv_kartchainingoffroad;
extern consvar_t cv_kartitembreaker;
extern consvar_t cv_kartwalltransfer;
extern consvar_t cv_kartpurpledrift;

View file

@ -452,6 +452,13 @@ struct sonicloopvars_t
sonicloopcamvars_t camera;
};
struct boostinfo_t {
fixed_t stackspeedboost;
fixed_t nonstackspeedboost;
fixed_t accelboost;
UINT8 grade;
};
// ========================================================================
// PLAYER STRUCTURE
// ========================================================================
@ -581,6 +588,9 @@ struct player_t
fixed_t speedboost; // Boost value smoothing for max speed
fixed_t accelboost; // Boost value smoothing for acceleration
angle_t boostangle; // angle set when not spun out OR boosted to determine what direction you should keep going at if you're spun out and boosted.
boostinfo_t boostinfo; // Stores values used for setting speed and accel boosts.
UINT8 numsneakers; // Number of stacked sneakers
UINT8 numboosts; // Number of Boosts stacking this frame
UINT8 tripwireState; // see tripwirestate_t
UINT8 tripwirePass; // see tripwirepass_t
@ -622,7 +632,9 @@ struct player_t
SINT8 stolentimer; // you are being stolen from
UINT16 sneakertimer; // Duration of a Sneaker Boost (from Sneakers or level boosters)
UINT16 realsneakertimer;// Duration of a Sneaker Boosts acutal time that doesn't get chained.(used for chainoffroad and tripwires)
UINT8 floorboost; // (0 to 3) - Prevents Sneaker sounds for a brief duration when triggered by a floor panel
UINT16 chaintimer; // Stores current chain timer length.
UINT8 boostcharge; // Charge during race start

View file

@ -1058,6 +1058,8 @@ _(TUMBLECOIN)
_(KARMAFIREWORK)
_(GAINAX)
_(BOOSTSTACK)
_(FOLLOWER)
_(FOLLOWERBUBBLE_FRONT)
_(FOLLOWERBUBBLE_BACK)

View file

@ -1054,6 +1054,9 @@ _(kdtrg1)
_(kdtrg2)
_(kdtrg3)
// Chaining Sound
_(bstchn)
// Shout message sound effect
_(sysmsg)

View file

@ -715,6 +715,8 @@ _(WTRU) // Water Trail Underlay
_(GCHA) // follower: generic chao
_(CHEZ) // follower: cheese
_(BSSS) // Stacking effect
_(TRCK)
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later

View file

@ -4200,6 +4200,8 @@ _(GAINAX_HUGE)
_(GAINAX_MID1)
_(GAINAX_MID2)
_(BOOSTSTACK)
_(WAYPOINTORB)
_(WAYPOINTSPLAT)
_(EGOORB)

View file

@ -49,6 +49,12 @@
#include "k_follower.h"
#include "k_grandprix.h"
consvar_t cv_kartstacking_colorflame = CVAR_INIT ("kartstacking_colorflame", "On", 0, CV_OnOff, NULL);
consvar_t cv_kartstacking_sneakerstacksound = CVAR_INIT ("kartstacking_sneakerstacksound", "On", 0, CV_OnOff, NULL);
consvar_t cv_kartchainingsound = CVAR_INIT ("kartchaining_chainsound", "On", 0, CV_OnOff, NULL);
consvar_t cv_kartdriftsounds = CVAR_INIT ("kartdriftsounds", "On", 0, CV_OnOff, NULL);
consvar_t cv_kartdriftefx = CVAR_INIT ("kartdriftefx", "On", 0, CV_OnOff, NULL);
// SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H:
// gamespeed is cc (0 for easy, 1 for normal, 2 for hard)
// franticitems is Frantic Mode items, bool
@ -253,6 +259,44 @@ void K_RegisterKartStuff(void)
CV_RegisterVar(&cv_lessflicker);
CV_RegisterVar(&cv_kartrings);
// Stacking
CV_RegisterVar(&cv_kartstacking);
CV_RegisterVar(&cv_kartstacking_calc_arg_offset);
CV_RegisterVar(&cv_kartstacking_speedboostdropoff);
CV_RegisterVar(&cv_kartstacking_speedboostdropoff_brake);
CV_RegisterVar(&cv_kartstacking_colorflame);
CV_RegisterVar(&cv_kartstacking_sneakerstacksound);
// Vanilla Boosts
CV_RegisterVar(&cv_kartstacking_sneaker_easyspeedboost);
CV_RegisterVar(&cv_kartstacking_sneaker_normalspeedboost);
CV_RegisterVar(&cv_kartstacking_sneaker_hardspeedboost);
CV_RegisterVar(&cv_kartstacking_sneaker_accelboost);
CV_RegisterVar(&cv_kartstacking_sneaker_maxgrade);
CV_RegisterVar(&cv_kartstacking_invincibility_speedboost);
CV_RegisterVar(&cv_kartstacking_invincibility_accelboost);
CV_RegisterVar(&cv_kartstacking_grow_speedboost);
CV_RegisterVar(&cv_kartstacking_grow_accelboost);
CV_RegisterVar(&cv_kartstacking_flame_speedval);
CV_RegisterVar(&cv_kartstacking_flame_accelboost);
CV_RegisterVar(&cv_kartstacking_start_speedboost);
CV_RegisterVar(&cv_kartstacking_start_accelboost);
CV_RegisterVar(&cv_kartstacking_drift_speedboost);
CV_RegisterVar(&cv_kartstacking_drift_accelboost);
CV_RegisterVar(&cv_kartstacking_ring_speedboost);
CV_RegisterVar(&cv_kartstacking_ring_accelboost);
CV_RegisterVar(&cv_kartchaining);
CV_RegisterVar(&cv_kartchainingoffroad);
CV_RegisterVar(&cv_kartchainingsound);
CV_RegisterVar(&cv_kartitembreaker);
CV_RegisterVar(&cv_newspeedometer);
@ -265,6 +309,10 @@ void K_RegisterKartStuff(void)
CV_RegisterVar(&cv_kartbumpspark);
CV_RegisterVar(&cv_kartbumpspring);
CV_RegisterVar(&cv_kartdriftsounds);
CV_RegisterVar(&cv_kartdriftefx);
}
//}
@ -2299,6 +2347,17 @@ void K_SpawnInvincibilitySpeedLines(mobj_t *mo)
fast->destscale = 6*((mo->player->invincibilitytimer/TICRATE)*FRACUNIT)/8;
}
static void K_SpawnStackingEffect(player_t *player)
{
// Thanks to 1ndev for code used for booststack->scale and boosttack->frame! (taken and modified from BoostStack)
mobj_t *booststack = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BOOSTSTACK);
P_SetTarget(&booststack->target, player->mo);
P_SetScale(booststack, FixedMul(FRACUNIT + FixedMul(2*FRACUNIT - FRACUNIT, FixedDiv(min(player->numboosts,4)*FRACUNIT, 4*FRACUNIT)), mapobjectscale));
booststack->angle = player->mo->angle + ANGLE_90;
booststack->color = player->mo->color;
}
void K_SpawnBumpEffect(mobj_t *mo)
{
mobj_t *fx = P_SpawnMobj(mo->x, mo->y, mo->z, MT_BUMP);
@ -3057,7 +3116,9 @@ void K_MomentumToFacing(player_t *player)
boolean K_ApplyOffroad(player_t *player)
{
if (player->invincibilitytimer || player->hyudorotimer || player->sneakertimer)
boolean sneakertimer = CANTCHAINOFFROAD ? (player->sneakertimer && player->realsneakertimer) : player->sneakertimer;
if (player->invincibilitytimer || player->hyudorotimer || sneakertimer)
return false;
return true;
}
@ -3097,7 +3158,7 @@ tripwirepass_t K_TripwirePassConditions(player_t *player)
{
if (
player->invincibilitytimer ||
player->sneakertimer
(player->sneakertimer && player->realsneakertimer)
)
return TRIPWIRE_BLASTER;
@ -3289,22 +3350,54 @@ static inline fixed_t K_GetSneakerBoostSpeed(void)
switch (gamespeed)
{
case 0:
return 53740+768;
return EASYSNEAKERSPEEDBOOST;
break;
case 2:
return 17294+768;
return HARDSNEAKERSPEEDBOOST;
break;
default:
return 32768;
return NORMALSNEAKERSPEEDBOOST;
break;
}
}
static fixed_t diminish(fixed_t speedboost)
{
return FixedSqrt(speedboost + CALC_ARG_OFFSET) - CALC_RET_OFFSET;
}
void K_DoBoost(player_t *player, fixed_t speedboost, fixed_t accelboost, boolean stack, boolean visible)
{
if (stack && stackingactive)
{
player->boostinfo.stackspeedboost += speedboost;
}
player->boostinfo.nonstackspeedboost = max(player->boostinfo.nonstackspeedboost, speedboost);
player->boostinfo.accelboost = max(player->boostinfo.accelboost, accelboost);
if (visible)
{
player->boostinfo.grade = CLAMP(player->boostinfo.grade+1, 0, stackingactive ? UINT8_MAX : 1);
}
}
void K_ClearBoost(player_t *player)
{
player->boostinfo.stackspeedboost = 0;
player->boostinfo.nonstackspeedboost = 0;
player->boostinfo.accelboost = 0;
player->boostinfo.grade = 0;
}
// sets boostpower, speedboost and accelboost to whatever we need it to be
static void K_GetKartBoostPower(player_t *player)
{
fixed_t boostpower = FRACUNIT;
fixed_t speedboost = 0, accelboost = 0;
fixed_t finalspeedboost = 0;
fixed_t finalaccelboost = 0;
UINT8 finalgrade = 0;
fixed_t prevspeedboost = player->speedboost;
if (player->spinouttimer && player->wipeoutslow == 1) // Slow down after you've been bumped
{
@ -3330,26 +3423,26 @@ static void K_GetKartBoostPower(player_t *player)
S_StartSound(player->mo, sfx_cdfm70);
}
#define ADDBOOST(s,a) { \
speedboost = max(speedboost,s); \
accelboost = max(accelboost,a); \
}
if (player->sneakertimer) // Sneaker
{
UINT8 i;
fixed_t sneakerspeedboost = K_GetSneakerBoostSpeed();
ADDBOOST(sneakerspeedboost, 8*FRACUNIT); // + ???% top speed, + 800% acceleration
UINT8 numsneakers = player->numsneakers ? player->numsneakers : 1;
for (i = 0; i < numsneakers; i++)
{
K_DoBoost(player, sneakerspeedboost, SNEAKERACCELBOOST, true, true); // + ???% top speed, + 800% acceleration
}
}
if (player->invincibilitytimer) // Invincibility
{
ADDBOOST(3*FRACUNIT/8, 3*FRACUNIT); // + 37.5% top speed, + 300% acceleration
K_DoBoost(player, INVINSPEEDBOOST, INVINACCELBOOST, false, false); // + 37.5% top speed, + 300% acceleration
}
if (player->growshrinktimer > 0) // Grow
{
ADDBOOST(FRACUNIT/5, 0); // + 20% top speed, + 0% acceleration
K_DoBoost(player, GROWSPEEDBOOST, GROWACCELBOOST, false, false); // + 20% top speed, + 0% acceleration
}
if (player->flamestore) // Flame Shield dash
@ -3357,49 +3450,81 @@ static void K_GetKartBoostPower(player_t *player)
fixed_t dash = K_FlameShieldDashVar(player->flamedash);
fixed_t intermediate = 0;
fixed_t boost = 0;
fixed_t val = 52428; // Rim idea: diminish starts around 1.2x sneaker speed and plateaus around 1.4-1.5x
fixed_t accel = 3*FRACUNIT;
fixed_t val = FLAMESPEEDVAL; // Rim idea: diminish starts around 1.2x sneaker speed and plateaus around 1.4-1.5x
intermediate = FixedDiv(FixedMul(val, FRACUNIT*-1/2) - FRACUNIT/4,-val+FRACUNIT/2);
boost = FixedMul(val,(FRACUNIT-FixedDiv(FRACUNIT,(dash+intermediate))));
ADDBOOST(boost, accel);
K_DoBoost(player, boost, FLAMEACCELBOOST, false, false);
}
if (player->startboost) // Startup Boost
{
ADDBOOST(FRACUNIT/4, 6*FRACUNIT); // + 25% top speed, + 300% acceleration
K_DoBoost(player, STARTSPEEDBOOST, STARTACCELBOOST, true, true); // + 25% top speed, + 600% acceleration
}
if (player->driftboost) // Drift Boost
{
ADDBOOST(FRACUNIT/4, 4*FRACUNIT); // + 25% top speed, + 400% acceleration
K_DoBoost(player, DRIFTSPEEDBOOST, DRIFTACCELBOOST, true, true); // + 25% top speed, + 400% acceleration
}
if (player->ringboost) // Ring Boost
{
ADDBOOST(FRACUNIT/5, 4*FRACUNIT); // + 20% top speed, + 400% acceleration
K_DoBoost(player, RINGSPEEDBOOST, RINGACCELBOOST, true, true); // + 20% top speed, + 400% acceleration
}
// This should always remain the last boost stack before tethering
// This should always remain the last boost
if (player->botvars.rubberband > FRACUNIT && K_PlayerUsesBotMovement(player) == true)
{
ADDBOOST(player->botvars.rubberband - FRACUNIT, 0);
K_DoBoost(player, player->botvars.rubberband - FRACUNIT, 0, false, false);
}
player->boostpower = boostpower;
// Combine nonstack and stacking boosts here.
finalspeedboost = max(player->boostinfo.nonstackspeedboost, diminish(player->boostinfo.stackspeedboost));
finalaccelboost = player->boostinfo.accelboost;
finalgrade = player->boostinfo.grade;
// value smoothing
if (speedboost > player->speedboost)
if (stackingactive)
{
player->speedboost = speedboost;
if (player->offroad && K_ApplyOffroad(player))
{
player->speedboost = max(finalspeedboost, player->speedboost)/2;
player->accelboost = max(finalaccelboost, player->accelboost)/2;
}
else if (finalspeedboost >= prevspeedboost)
{
player->speedboost = max(player->speedboost, finalspeedboost);
player->accelboost = max(finalaccelboost, player->accelboost);
}
else if ((player->aizdriftstrat && abs((player->drift) < 5)) || (K_GetKartButtons(player) & BT_BRAKE))
{
player->speedboost = max(prevspeedboost - SPEEDBOOSTDROPOFF_BRAKE, min(player->speedboost, MAXVANILLABOOST));
player->accelboost = max(finalaccelboost, player->accelboost);
}
else
{
player->speedboost += (speedboost - player->speedboost) / (TICRATE/2);
player->speedboost = prevspeedboost - SPEEDBOOSTDROPOFF;
player->accelboost = max(finalaccelboost, player->accelboost);
}
}
else
{
if (finalspeedboost > player->speedboost)
{
player->speedboost = finalspeedboost;
}
else
{
player->speedboost += (finalspeedboost - player->speedboost) / (TICRATE/2);
}
}
player->accelboost = accelboost;
player->accelboost = finalaccelboost;
player->numboosts = finalgrade;
K_ClearBoost(player);
}
// Returns value based on being Grown or Shrunk otherwise returns FRACUNIT
@ -5128,22 +5253,27 @@ static void K_DoHyudoroSteal(player_t *player)
}
}
void K_DoSneaker(player_t *player, INT32 type)
// Handle these else where to reduce code duplication between panels and sneakers
static void K_SneakerPanelStackSound(player_t *player)
{
const fixed_t intendedboost = K_GetSneakerBoostSpeed();
const sfxenum_t normalsfx = sfx_cdfm01;
const sfxenum_t smallsfx = sfx_cdfm40;
sfxenum_t sfx = normalsfx;
if (player->floorboost == 0 || player->floorboost == 3)
if ((player->numsneakers > 0) && stackingactive)
{
S_StopSoundByID(player->mo, sfx_cdfm01);
S_StartSound(player->mo, sfx_cdfm01);
K_SpawnDashDustRelease(player);
if (intendedboost > player->speedboost)
player->karthud[khud_destboostcam] = FixedMul(FRACUNIT, FixedDiv((intendedboost - player->speedboost), intendedboost));
// Use a less annoying sound when stacking sneakers.
sfx = smallsfx;
}
if (player->sneakertimer == 0)
S_StopSoundByID(player->mo, normalsfx);
S_StopSoundByID(player->mo, smallsfx);
S_StartSound(player->mo, sfx);
}
static void K_SneakerPanelEffect(player_t *player, INT32 type)
{
if (!player->sneakertimer)
{
if (type == 2)
{
@ -5172,6 +5302,22 @@ void K_DoSneaker(player_t *player, INT32 type)
K_FlipFromObject(overlay, player->mo);
}
}
}
void K_DoSneaker(player_t *player, INT32 type)
{
const fixed_t intendedboost = K_GetSneakerBoostSpeed();
if (player->floorboost == 0 || player->floorboost == 3)
{
K_SneakerPanelStackSound(player);
K_SpawnDashDustRelease(player);
if (intendedboost > player->speedboost)
player->karthud[khud_destboostcam] = FixedMul(FRACUNIT, FixedDiv((intendedboost - player->speedboost), intendedboost));
}
K_SneakerPanelEffect(player, type);
if (type != 0)
{
@ -5179,6 +5325,12 @@ void K_DoSneaker(player_t *player, INT32 type)
}
player->sneakertimer = sneakertime;
player->realsneakertimer = sneakertime;
if (player->sneakertimer && (player->floorboost == 0 || player->floorboost == 3))
{
player->numsneakers = CLAMP(player->numsneakers+1, 0, stackingactive ? MAXSNEAKERSTACK : 1);
}
// set angle for spun out players:
player->boostangle = player->mo->angle;
@ -5190,25 +5342,22 @@ void K_DoWaterRunPanel(player_t *player)
if (player->floorboost == 0 || player->floorboost == 3)
{
S_StopSoundByID(player->mo, sfx_cdfm01);
S_StopSoundByID(player->mo, sfx_kc3c);
S_StartSound(player->mo, sfx_cdfm01);
S_StartSound(player->mo, sfx_kc3c);
K_SneakerPanelStackSound(player);
K_SpawnDashDustRelease(player);
if (intendedboost > player->speedboost)
player->karthud[khud_destboostcam] = FixedMul(FRACUNIT, FixedDiv((intendedboost - player->speedboost), intendedboost));
}
if (player->sneakertimer == 0)
{
mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BOOSTFLAME);
P_SetTarget(&overlay->target, player->mo);
P_SetScale(overlay, (overlay->destscale = player->mo->scale));
K_FlipFromObject(overlay, player->mo);
}
K_SneakerPanelEffect(player, 0);
player->sneakertimer = TICRATE*2;
player->realsneakertimer = TICRATE*2;
if (player->sneakertimer && (player->floorboost == 0 || player->floorboost == 3))
{
player->numsneakers = CLAMP(player->numsneakers+1, 0, stackingactive ? MAXSNEAKERSTACK : 1);
}
player->mo->flags2 |= MF2_WATERRUN;
// set angle for spun out players:
@ -6854,6 +7003,7 @@ static void K_RaceStart(player_t *player)
player->startboost = 0;
K_DoSneaker(player, 0);
player->sneakertimer = 70; // PERFECT BOOST!!
player->realsneakertimer = 70;
if (!player->floorboost || player->floorboost == 3) // Let everyone hear this one
S_StartSound(player->mo, sfx_s25f);
@ -6922,6 +7072,118 @@ static void K_TireGreaseEffect(player_t *player)
S_StartSound(player->mo, sfx_screec);
}
boolean K_BoostChain(player_t *player, INT32 timer, boolean chainsound)
{
if (!chainingactive)
{
// You can't chain why bother?
return false;
}
if (timer > player->chaintimer)
{
// Just what I needed! - Toad
if (cv_kartchainingsound.value && chainsound && player->chaintimer && player->sneakertimer)
{
if (player->mo)
{
// Chain Sound!
S_StartSound(player->mo, sfx_bstchn);
}
}
player->chaintimer = timer;
}
if (player->chaintimer)
{
// You can continue chaining!
return true;
}
// Aw shucks, time to drop the chain....
return false;
}
INT32 K_ChainOrDeincrementTime(player_t *player, INT32 timer, INT32 deincrement, boolean chainsound)
{
timer -= deincrement;
if (K_BoostChain(player, timer, chainsound))
{
// Its time to chain.
return max(1, timer);
}
// Continue to drain the timer as normal.
return timer;
}
// Get the tic inverse sum using kartspeed, kartweight and your number of boosts.
static INT32 ticinversesum(UINT8 kartspeed, UINT8 kartweight, UINT8 grade)
{
return (TICRATE / kartspeed) + (TICRATE / CLAMP(kartweight, 1, 5)) + grade;
}
// Get the maximum required stacks needed for the ringnerf based on kartspeed and kartweight
static INT32 statrangemap(UINT8 kartspeed, UINT8 kartweight)
{
INT32 scaledsw = (9 - kartspeed) + (9 - kartweight);
fixed_t scaled_input = (scaledsw)*FRACUNIT/16;
// Scale the result to be within range [2, 4]
fixed_t result = 4*FRACUNIT - (FixedMul(scaled_input, 2*FRACUNIT));
// Stay within range please!
if (result < 2*FRACUNIT)
result = 2*FRACUNIT;
if (result > 4*FRACUNIT)
result = 4*FRACUNIT;
result = result >> FRACBITS;
return result;
}
static void K_HandleRingDeincrement(player_t *player, boolean chainnerf)
{
// Aggressively reduce extreme ringboost duration.
// Less aggressive for accel types.
UINT8 roller = TICRATE;
UINT16 finalringtimer;
roller += 4*(8-player->kartspeed);
finalringtimer = max((player->ringboost / roller), 1);
if (chainnerf)
{
UINT8 requiredgrade = statrangemap(player->kartspeed, player->kartweight);
if (player->numboosts >= requiredgrade)
{
INT32 insum = ticinversesum(player->kartspeed, player->kartweight, player->numboosts);
INT32 subring = (player->ringboost*2)/insum;
if (player->kartspeed == 1)
{
// fuck off chao you aren't chaining an entire race.
subring = (player->ringboost*4)/insum;
}
finalringtimer += subring;
}
if (player->ringboost - finalringtimer > player->chaintimer)
{
// Cap this to prevent displacement between chaintimer and ringtimer.
player->chaintimer = min(player->ringboost, (TICRATE - TICRATE/4));
}
}
player->ringboost = max(player->chaintimer ? 1: 0, player->ringboost - finalringtimer);
}
/** \brief Decreases various kart timers and powers per frame. Called in P_PlayerThink in p_user.c
\param player player object passed from P_PlayerThink
@ -6931,8 +7193,6 @@ static void K_TireGreaseEffect(player_t *player)
*/
void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
{
const boolean onground = P_IsObjectOnGround(player->mo);
/* reset sprite offsets :) */
player->mo->sprxoff = 0;
player->mo->spryoff = 0;
@ -6996,25 +7256,11 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
}
}
/*if (gametype == GT_RACE && player->rings <= 0 && (K_RingsActive() == true)) // spawn ring debt indicator
// Stacking Effect
if (stackingactive && player->numboosts > 1)
{
mobj_t *debtflag = P_SpawnMobj(player->mo->x + player->mo->momx, player->mo->y + player->mo->momy,
player->mo->z + P_GetMobjZMovement(player->mo) + player->mo->height + (24*player->mo->scale), MT_THOK);
P_SetMobjState(debtflag, S_RINGDEBT);
P_SetScale(debtflag, (debtflag->destscale = player->mo->scale));
K_MatchGenericExtraFlags(debtflag, player->mo);
debtflag->frame += (leveltime % 4);
if ((leveltime/12) & 1)
debtflag->frame += 4;
debtflag->color = player->skincolor;
debtflag->fuse = 2;
debtflag->renderflags = K_GetPlayerDontDrawFlag(player);
}*/
K_SpawnStackingEffect(player);
}
}
if (player->itemtype == KITEM_NONE)
@ -7111,19 +7357,22 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
player->ringboost = 0;
else if (player->ringboost)
{
// Aggressively reduce extreme ringboost duration.
// Less aggressive for accel types.
UINT8 roller = TICRATE;
roller += 4*(8-player->kartspeed);
player->ringboost -= max((player->ringboost / roller), 1);
K_HandleRingDeincrement(player, chainingactive);
}
if (player->sneakertimer)
{
player->sneakertimer--;
player->sneakertimer = K_ChainOrDeincrementTime(player, player->sneakertimer, 1, false);
if (player->sneakertimer <= 0)
{
player->mo->flags2 &= ~MF2_WATERRUN;
player->numsneakers = 0;
}
}
if (player->realsneakertimer)
player->realsneakertimer--;
if (player->sneakertimer && player->wipeoutslow > 0 && player->wipeoutslow < wipeoutslowtime+1)
player->wipeoutslow = wipeoutslowtime+1;
@ -7131,17 +7380,11 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (player->floorboost > 0)
player->floorboost--;
if (player->sneakertimer == 0)
{
// No more waterrunning for you pal!
player->mo->flags2 &= ~MF2_WATERRUN;
}
if (player->driftboost)
player->driftboost--;
player->driftboost = K_ChainOrDeincrementTime(player, player->driftboost, 1, true);
if (player->startboost > 0)
player->startboost--;
player->startboost = K_ChainOrDeincrementTime(player, player->startboost, 1, false);
if (player->invincibilitytimer)
player->invincibilitytimer--;
@ -7240,7 +7483,10 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
player->outruntime--;
if (player->tiregrease > 0)
player->tiregrease--;;
player->tiregrease--;
if (player->chaintimer)
player->chaintimer--;
if (player->itemblink && player->itemblink-- <= 0)
{
@ -8616,7 +8862,14 @@ INT32 K_GetKartDriftSparkValueForStage(player_t *player, UINT8 stage)
static void K_SpawnDriftEFX(player_t *player,SINT8 level)
{
if (!cv_kartdriftefx.value)
{
// Not wanted sorry!
return;
}
mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BOOSTFLAME);
P_SetMobjState(overlay, S_DRIFTBOOSTFLAME);
P_SetTarget(&overlay->target, player->mo);
P_SetScale(overlay, (overlay->destscale = player->mo->scale));
K_FlipFromObject(overlay, player->mo);
@ -8672,8 +8925,11 @@ static void K_KartDrift(player_t *player, boolean onground)
{
if (player->driftboost < 50)
player->driftboost = 50;
S_StartSound(player->mo, sfx_s23c);
if (cv_kartdriftsounds.value)
S_StartSound(player->mo, sfx_kc5b);
S_StartSound(player->mo, sfx_s23c);
K_SpawnDriftEFX(player, 2);
player->driftcharge = 0;
}
@ -8683,9 +8939,16 @@ static void K_KartDrift(player_t *player, boolean onground)
{
if (player->driftboost < 80)
player->driftboost = 80;
if (cv_kartdriftsounds.value)
{
S_StartSound(player->mo, sfx_kc5b);
S_StartSound(player->mo, sfx_kc3c);
S_StartSound(player->mo, sfx_s3k47);
}
else
{
S_StartSound(player->mo, sfx_s23c);
}
K_SpawnDriftEFX(player, 3);
player->driftcharge = 0;
}
@ -8695,8 +8958,16 @@ static void K_KartDrift(player_t *player, boolean onground)
{
if (player->driftboost < 125)
player->driftboost = 125;
if (cv_kartdriftsounds.value)
{
S_StartSound(player->mo, sfx_kc5b);
S_StartSound(player->mo, sfx_kc4d);
}
else
{
S_StartSound(player->mo, sfx_s23c);
}
K_SpawnDriftEFX(player, 4);
player->driftcharge = 0;
}
@ -10350,6 +10621,28 @@ boolean K_RingsActive(void)
return true;
}
boolean K_StackingActive(void)
{
if (stackingactive)
{
// Booststacking is enabled!
return true;
}
return false;
}
boolean K_ChainingActive(void)
{
if (chainingactive)
{
// Boostchaining is enabled!
return true;
}
return false;
}
boolean K_UsingLegacyCheckpoints(void)
{
if (numbosswaypoints > 0)

View file

@ -14,6 +14,12 @@
extern "C" {
#endif
extern consvar_t cv_kartstacking_colorflame;
extern consvar_t cv_kartstacking_sneakerstacksound;
extern consvar_t cv_kartchainingsound;
extern consvar_t cv_kartdriftsounds;
extern consvar_t cv_kartdriftefx;
#define KART_FULLTURN 800
/*
@ -31,6 +37,35 @@ Make sure this matches the actual number of states
#define FLAMESTOREMAX TICRATE*2
// Precalculated constants for stacked boost diminishing
// *Somewhat* matches old calc but doesn't use arrays, which makes it faster and more memory efficent
#define CALC_ARG_OFFSET cv_kartstacking_calc_arg_offset.value
#define CALC_RET_OFFSET FixedSqrt(CALC_ARG_OFFSET)
#define MAXVANILLABOOST cv_kartstacking_maxvanillaboost.value
#define SPEEDBOOSTDROPOFF cv_kartstacking_speedboostdropoff.value
#define SPEEDBOOSTDROPOFF_BRAKE cv_kartstacking_speedboostdropoff_brake.value
// Vanilla Boosts
#define EASYSNEAKERSPEEDBOOST cv_kartstacking_sneaker_easyspeedboost.value
#define NORMALSNEAKERSPEEDBOOST cv_kartstacking_sneaker_normalspeedboost.value
#define HARDSNEAKERSPEEDBOOST cv_kartstacking_sneaker_hardspeedboost.value
#define SNEAKERACCELBOOST cv_kartstacking_sneaker_accelboost.value
#define MAXSNEAKERSTACK cv_kartstacking_sneaker_maxgrade.value
#define INVINSPEEDBOOST cv_kartstacking_invincibility_speedboost.value
#define INVINACCELBOOST cv_kartstacking_invincibility_accelboost.value
#define GROWSPEEDBOOST cv_kartstacking_grow_speedboost.value
#define GROWACCELBOOST cv_kartstacking_grow_accelboost.value
#define FLAMESPEEDVAL cv_kartstacking_flame_speedval.value
#define FLAMEACCELBOOST cv_kartstacking_flame_accelboost.value
#define STARTSPEEDBOOST cv_kartstacking_start_speedboost.value
#define STARTACCELBOOST cv_kartstacking_start_accelboost.value
#define DRIFTSPEEDBOOST cv_kartstacking_drift_speedboost.value
#define DRIFTACCELBOOST cv_kartstacking_drift_accelboost.value
#define RINGSPEEDBOOST cv_kartstacking_ring_speedboost.value
#define RINGACCELBOOST cv_kartstacking_ring_accelboost.value
#define CANTCHAINOFFROAD (cv_kartchaining.value && !cv_kartchainingoffroad.value)
// Used for respawning checks.
typedef struct respawnresult_s
@ -192,10 +227,17 @@ void K_UnsetItemOut(player_t *player);
boolean K_SafeRespawnPosition(mobj_t * mo);
boolean K_RingsActive(void);
boolean K_StackingActive(void);
boolean K_ChainingActive(void);
boolean K_BoostChain(player_t *player, INT32 timer, boolean chainsound);
INT32 K_ChainOrDeincrementTime(player_t *player, INT32 timer, INT32 deincrement, boolean chainsound);
boolean K_UsingLegacyCheckpoints(void);
void K_UpdateMobjItemOverlay(mobj_t *part, SINT8 itemType, UINT8 itemCount);
void K_DoBoost(player_t *player, fixed_t speedboost, fixed_t accelboost, boolean stack, boolean visible);
void K_ClearBoost(player_t *player);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -3958,7 +3958,7 @@ static int lib_kSetIndirectItemCountdown(lua_State *L)
return 0;
}
// Sets the item cooldown before another shrink / SPB can be rolled
// Sets the item cooldown before another hyudoro can be rolled
static int lib_kSetHyuCountdown(lua_State *L)
{
tic_t c = (tic_t)luaL_checkinteger(L, 1);
@ -3985,6 +3985,20 @@ static int lib_kRingsActive(lua_State *L)
return 1;
}
// Checks if Stacking is active.
static int lib_kStackingActive(lua_State *L)
{
lua_pushboolean(L, K_StackingActive());
return 1;
}
// Checks if Chaining is active.
static int lib_kChainingActive(lua_State *L)
{
lua_pushboolean(L, K_ChainingActive());
return 1;
}
// Checks if current map is using legacy boss3 bassed checkpoints. Useful for map compat.
static int lib_kUsingLegacyCheckpoints(lua_State *L)
{
@ -3992,6 +4006,59 @@ static int lib_kUsingLegacyCheckpoints(lua_State *L)
return 1;
}
static int lib_kDoBoost(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
fixed_t speedboost = luaL_checkfixed(L, 2);
fixed_t accelboost = luaL_checkfixed(L, 3);
boolean stacking = lua_optboolean(L, 4);
boolean visible = lua_isnoneornil(L, 5) ? true : luaL_checkboolean(L, 5);
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_DoBoost(player, speedboost, accelboost, stacking, visible);
return 0;
}
static int lib_kClearBoost(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_ClearBoost(player);
return 0;
}
static int lib_kBoostChain(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INT32 timer = luaL_checkinteger(L, 2);
INT32 chainsound = lua_optboolean(L, 3);
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_BoostChain(player, timer, chainsound));
return 1;
}
static int lib_kChainOrDeincrementTime(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INT32 timer = luaL_checkinteger(L, 2);
INT32 deincrement = luaL_checkinteger(L, 3);
INT32 chainsound = lua_optboolean(L, 4);
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushinteger(L, K_ChainOrDeincrementTime(player, timer, deincrement, chainsound));
return 1;
}
static int lib_getTimeMicros(lua_State *L)
{
lua_pushinteger(L, I_GetPreciseTime() / (I_GetPrecisePrecision() / 1000000));
@ -4286,12 +4353,19 @@ static luaL_Reg lib[] = {
{"K_SetExitCountdown",lib_kSetExitCountdown},
{"K_SetIndirectItemCooldown",lib_kSetIndirectItemCountdown},
{"K_SetHyudoroCooldown",lib_kSetHyuCountdown},
{"K_SafeRespawnPosition", lib_kSafeRespawnPosition},
{"K_SafeRespawnPosition",lib_kSafeRespawnPosition},
{"K_GetCollideAngle",lib_kGetCollideAngle},
{"K_RingsActive",lib_kRingsActive},
{"K_StackingActive",lib_kStackingActive},
{"K_ChainingActive",lib_kChainingActive},
{"K_UsingLegacyCheckpoints",lib_kUsingLegacyCheckpoints},
{"K_DoBoost",lib_kDoBoost},
{"K_ClearBoost",lib_kClearBoost},
{"K_BoostChain",lib_kBoostChain},
{"K_ChainOrDeincrementTime",lib_kChainOrDeincrementTime},
// k_boss
{"K_InitBossHealthBar", lib_kInitBossHealthBar},

View file

@ -590,6 +590,8 @@ int LUA_ConsoleLib(lua_State *L)
lua_setglobal(L, "CV_YesNo");
lua_pushlightuserdata(L, CV_Unsigned);
lua_setglobal(L, "CV_Unsigned");
lua_pushlightuserdata(L, CV_Signed);
lua_setglobal(L, "CV_Signed");
lua_pushlightuserdata(L, CV_Natural);
lua_setglobal(L, "CV_Natural");

View file

@ -229,6 +229,9 @@ enum player_e
player_speedboost,
player_accelboost,
player_boostangle,
player_boostinfo,
player_numsneakers,
player_numboosts,
player_tripwireState,
player_tripwirePass,
player_tripwireLeniency,
@ -260,7 +263,9 @@ enum player_e
player_stealingtimer,
player_stolentimer,
player_sneakertimer,
player_realsneakertimer,
player_floorboost,
player_chaintimer,
player_growshrinktimer,
player_growcancel,
player_squishedtimer,
@ -398,6 +403,9 @@ static const char *const player_opt[] = {
"speedboost",
"accelboost",
"boostangle",
"boostinfo",
"numsneakers",
"numboosts",
"tripwireState",
"tripwirePass",
"tripwireLeniency",
@ -429,7 +437,9 @@ static const char *const player_opt[] = {
"stealingtimer",
"stolentimer",
"sneakertimer",
"realsneakertimer",
"floorboost",
"chaintimer",
"growshrinktimer",
"growcancel",
"squishedtimer",
@ -699,6 +709,15 @@ static int player_get(lua_State *L)
case player_boostangle:
lua_pushangle(L, plr->boostangle);
break;
case player_boostinfo:
luaL_error(L, "Don't directly read boostinfo. Use speedboost, accelboost and numboosts instead,\n");
break;
case player_numsneakers:
lua_pushinteger(L, plr->numsneakers);
break;
case player_numboosts:
lua_pushinteger(L, plr->numboosts);
break;
case player_tripwireState:
lua_pushinteger(L, plr->tripwireState);
break;
@ -792,9 +811,15 @@ static int player_get(lua_State *L)
case player_sneakertimer:
lua_pushinteger(L, plr->sneakertimer);
break;
case player_realsneakertimer:
lua_pushinteger(L, plr->realsneakertimer);
break;
case player_floorboost:
lua_pushinteger(L, plr->floorboost);
break;
case player_chaintimer:
lua_pushinteger(L, plr->chaintimer);
break;
case player_growshrinktimer:
lua_pushinteger(L, plr->growshrinktimer);
break;
@ -1281,6 +1306,15 @@ static int player_set(lua_State *L)
case player_boostangle:
plr->boostangle = luaL_checkangle(L, 3);
break;
case player_boostinfo:
NOSET;
break;
case player_numsneakers:
plr->numsneakers = luaL_checkinteger(L, 3);
break;
case player_numboosts:
plr->numboosts = luaL_checkinteger(L, 3);
break;
case player_tripwireState:
plr->tripwireState = luaL_checkinteger(L, 3);
break;
@ -1374,9 +1408,15 @@ static int player_set(lua_State *L)
case player_sneakertimer:
plr->sneakertimer = luaL_checkinteger(L, 3);
break;
case player_realsneakertimer:
plr->realsneakertimer = luaL_checkinteger(L, 3);
break;
case player_floorboost:
plr->floorboost = luaL_checkinteger(L, 3);
break;
case player_chaintimer:
plr->chaintimer = luaL_checkinteger(L, 3);
break;
case player_growshrinktimer:
plr->growshrinktimer = luaL_checkinteger(L, 3);
break;

View file

@ -360,6 +360,15 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word,"battleprisons")) {
lua_pushinteger(L, itembreaker);
return 1;
} else if (fastcmp(word,"ringsactive")) {
lua_pushinteger(L, ringsactive);
return 1;
} else if (fastcmp(word,"stackingactive")) {
lua_pushinteger(L, stackingactive);
return 1;
} else if (fastcmp(word,"chainingactive")) {
lua_pushinteger(L, chainingactive);
return 1;
} else if (fastcmp(word,"hyubgone")) {
lua_pushinteger(L, hyubgone);
return 1;
@ -481,6 +490,12 @@ int LUA_WriteGlobals(lua_State *L, const char *word)
introtime = (tic_t)luaL_checkinteger(L, 2);
else if (fastcmp(word,"itembreaker"))
itembreaker = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"battleprisons"))
itembreaker = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"chainingactive"))
stackingactive = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"chainingactive"))
chainingactive = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"gamespeed"))
gamespeed = (UINT8)luaL_checkinteger(L, 2);
else if (fastcmp(word,"nummapboxes"))

View file

@ -3583,6 +3583,9 @@ void A_AttractChase(mobj_t *actor)
actor->target->player->ringboost += K_GetKartRingPower(actor->target->player, true) + 3;
S_StartSoundAtVolume(actor->target, sfx_s1b5, actor->target->player->ringvolume);
if (actor->target->player->ringboost > (4*TICRATE + TICRATE/2))
actor->target->player->ringboost = (4*TICRATE + TICRATE/2);
actor->target->player->ringvolume -= RINGVOLUMEUSEPENALTY;
P_KillMobj(actor, actor->target, actor->target, DMG_NORMAL);
@ -3607,6 +3610,9 @@ void A_AttractChase(mobj_t *actor)
if (!P_GivePlayerRings(actor->target->player, 1)) // returns 0 if addition failed
actor->target->player->ringboost += K_GetKartRingPower(actor->target->player, true) + 3;
if (actor->target->player->ringboost > (4*TICRATE + TICRATE/2))
actor->target->player->ringboost = (4*TICRATE + TICRATE/2);
if (actor->cvmem) // caching
S_StartSound(actor->target, sfx_s1c5);
else

View file

@ -7070,7 +7070,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
return false;
}
{
player_t *p = NULL;
if (mobj->target->target && mobj->target->target->player)
@ -7080,12 +7079,16 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
mobj->angle = mobj->extravalue1 && p ? p->drawangle : mobj->target->angle;
P_MoveOrigin(mobj, mobj->target->x + P_ReturnThrustX(mobj, mobj->angle+ANGLE_180, mobj->target->radius),
mobj->target->y + P_ReturnThrustY(mobj, mobj->angle+ANGLE_180, mobj->target->radius), mobj->target->z);
mobj->target->y + P_ReturnThrustY(mobj, mobj->angle+ANGLE_180, mobj->target->radius), mobj->target->z+5*mapobjectscale);
K_FlipFromObject(mobj, mobj->target);
P_SetScale(mobj, mobj->target->scale);
mobj->roll = mobj->target->roll;
mobj->pitch = mobj->target->pitch;
mobj->sloperoll = mobj->target->sloperoll;
mobj->slopepitch = mobj->target->slopepitch;
if (p)
{
if (mobj->extravalue1)
@ -7120,6 +7123,38 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
}
else
{
if (stackingactive && cv_kartstacking_colorflame.value)
{
switch(p->numsneakers)
{
case 0:
case 1:
mobj->colorized = false;
break;
case 2:
mobj->colorized = true;
mobj->color = SKINCOLOR_BLUEBERRY;
break;
case 3:
mobj->colorized = true;
mobj->color = SKINCOLOR_PURPLE;
break;
case 4:
mobj->colorized = true;
mobj->color = SKINCOLOR_MOONSLAM;
break;
case 5:
mobj->colorized = true;
mobj->color = SKINCOLOR_WHITE;
break;
default:
mobj->colorized = true;
mobj->color = SKINCOLOR_WHITE;
break;
}
}
if (p->sneakertimer > mobj->movecount)
P_SetMobjState(mobj, S_BOOSTFLAME);
mobj->movecount = p->sneakertimer;
@ -7129,7 +7164,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
if (mobj->extravalue1)
{
if (leveltime % 2 == 1)
{
mobj->frame |= FF_TRANS60;
@ -7143,7 +7177,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
{
mobj->color = K_RainbowColor(leveltime);
}
}
if (mobj->state == &states[S_BOOSTSMOKESPAWNER])
@ -7307,6 +7340,28 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
}
break;
case MT_BOOSTSTACK:
{
if (!mobj->target || P_MobjWasRemoved(mobj->target) || !mobj->target->health || (mobj->target->player && !mobj->target->player->numboosts))
{
P_RemoveMobj(mobj);
return false;
}
mobj->roll = mobj->target->roll;
mobj->pitch = mobj->target->pitch;
mobj->sloperoll = mobj->target->sloperoll;
mobj->slopepitch = mobj->target->slopepitch;
// Thx Indev! (taken and modified from BoostStack)
P_MoveOrigin(mobj, mobj->target->x + FixedMul(cos(mobj->target->angle), FixedMul(30*FRACUNIT, mapobjectscale)), mobj->target->y + FixedMul(sin(mobj->target->angle), FixedMul(30*FRACUNIT, mapobjectscale)), mobj->target->z);
K_FlipFromObject(mobj, mobj->target);
// Leveltime based animation
mobj->frame = states[S_BOOSTSTACK].frame + (leveltime / 3) % 5;
break;
}
case MT_THUNDERSHIELD:
{
if (!mobj->target || !mobj->target->health || !mobj->target->player

View file

@ -578,6 +578,8 @@ extern UINT16 emeraldspawndelay;
extern INT32 numstarposts;
extern INT32 numbosswaypoints;
extern boolean ringsactive;
extern boolean stackingactive;
extern boolean chainingactive;
extern UINT16 bossdisabled;
extern boolean stoppedclock;

View file

@ -272,6 +272,14 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITEFIXED(save->p, players[i].speedboost);
WRITEFIXED(save->p, players[i].accelboost);
WRITEANGLE(save->p, players[i].boostangle);
WRITEUINT8(save->p, players[i].numsneakers);
WRITEUINT8(save->p, players[i].numboosts);
// boostinfo_t
WRITEFIXED(save->p, players[i].boostinfo.stackspeedboost);
WRITEFIXED(save->p, players[i].boostinfo.nonstackspeedboost);
WRITEFIXED(save->p, players[i].boostinfo.accelboost);
WRITEUINT8(save->p, players[i].boostinfo.grade);
WRITEUINT8(save->p, players[i].tripwireState);
WRITEUINT8(save->p, players[i].tripwirePass);
@ -310,7 +318,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITESINT8(save->p, players[i].stealingtimer);
WRITEUINT16(save->p, players[i].sneakertimer);
WRITEUINT16(save->p, players[i].realsneakertimer);
WRITEUINT8(save->p, players[i].floorboost);
WRITEUINT16(save->p, players[i].chaintimer);
WRITEUINT8(save->p, players[i].boostcharge);
@ -576,6 +586,14 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].speedboost = READFIXED(save->p);
players[i].accelboost = READFIXED(save->p);
players[i].boostangle = READANGLE(save->p);
players[i].numsneakers = READUINT8(save->p);
players[i].numboosts = READUINT8(save->p);
// boostinfo_t
players[i].boostinfo.stackspeedboost = READFIXED(save->p);
players[i].boostinfo.nonstackspeedboost = READFIXED(save->p);
players[i].boostinfo.accelboost = READFIXED(save->p);
players[i].boostinfo.grade = READUINT8(save->p);
players[i].tripwireState = READUINT8(save->p);
players[i].tripwirePass = READUINT8(save->p);
@ -614,7 +632,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].stealingtimer = READSINT8(save->p);
players[i].sneakertimer = READUINT16(save->p);
players[i].realsneakertimer = READUINT16(save->p);
players[i].floorboost = READUINT8(save->p);
players[i].chaintimer = READUINT16(save->p);
players[i].boostcharge = READUINT8(save->p);
@ -5067,6 +5087,8 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending)
WRITEINT16(save->p, lastmap);
WRITEUINT16(save->p, bossdisabled);
WRITEUINT8(save->p, ringsactive);
WRITEUINT8(save->p, stackingactive);
WRITEUINT8(save->p, chainingactive);
for (i = 0; i < 4; i++)
{
@ -5236,6 +5258,8 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool
lastmap = READINT16(save->p);
bossdisabled = READUINT16(save->p);
ringsactive = READUINT8(save->p);
stackingactive = READUINT8(save->p);
chainingactive = READUINT8(save->p);
for (i = 0; i < 4; i++)
{

View file

@ -142,7 +142,9 @@ line_t *spawnlines;
side_t *spawnsides;
INT32 numstarposts;
INT32 numbosswaypoints;
boolean ringsactive;
boolean ringsactive = false;
boolean stackingactive = false;
boolean chainingactive = false;
UINT16 bossdisabled;
boolean stoppedclock;
boolean levelloading;
@ -7883,6 +7885,16 @@ static void P_InitLevelSettings(boolean reloadinggamestate)
else
ringsactive = false;
if (cv_kartstacking.value)
stackingactive = true;
else
stackingactive = false;
if (cv_kartchaining.value)
chainingactive = true;
else
chainingactive = false;
// emerald hunt
hunt1 = hunt2 = hunt3 = NULL;

View file

@ -43,6 +43,7 @@ TYPEDEF (discordRequest_t);
// d_player.h
TYPEDEF (botvars_t);
TYPEDEF (boostinfo_t);
TYPEDEF (player_t);
TYPEDEF (sonicloopcamvars_t);
TYPEDEF (sonicloopvars_t);