-- CONSTANTS local FULLCHARGE = 65 local CHARGEDIFF = 5 local AFTERTOUCH_FALLOFF = 3*FRACUNIT local AFTERTOUCH_FALLOFF_AIR = 1*FRACUNIT local TAKEDOWN_BONUS = 10 -- + Weight * 5 addHook("PlayerSpawn", function(player) -- START VARIABLES player.burnout = 0 player.boosting = false -- Boosting while Supercharged player.floatrings = 0 player.overRings = 0 -- "Extra Rings" player.growthTicks = 0 -- grow/shrink tick accumulator for ring rewards player.baildrop = 0 player.ringboost = 0 player.superring = player.superring or 0 player.pickuprings = player.pickuprings or 0 player.hudrings = 0 -- Crash Breaker debug/state player.cb_explode_tics = 0 player.cb_explode_radius = 0 player.cb_explode_tick = 0 player.cb_last_explode_tick = -1 player.cb_raw_excess = 0 player.cb_scale = FRACUNIT end) local function GetExplosionRadius(player) if not player or not player.mo then return 0 end local scale = player.mo.scale or FRACUNIT local base = scale*1024 local raw = base + scale * (((player.rings or 0)+20) + (player.overRings or 0) + (player.superring or 0)) * 256 player.cb_raw_excess = raw - base player.cb_scale = scale if player.boosting then return base+raw elseif raw <= base*4 then return raw else local excess = raw - base local gap = scale*(16384) -- 512 - base = -- Softcap: 100 + (gap * excess) / (excess + gap) local p = 2 local capped = base*4 + (gap * excess^p) / (excess^p + gap) return capped end end addHook("ThinkFrame", function(player) -- FRAME PER PLAYER (PLAYER THINK) for player in players.iterate do local did_explode = false local spinouttimer = player.spinouttimer or 0 local tumbleheight = player.tumbleheight or 0 local rings = player.rings or 0 local overRings = player.overRings or 0 local superring = player.superring or 0 local bailHeld = (player.cmd.buttons & BT_BAIL) ~= 0 local oldButtons = (player.oldcmd and player.oldcmd.buttons) or 0 local bailPressed = bailHeld and ((oldButtons & BT_BAIL) == 0) local lookbackHeld = (player.cmd.buttons & BT_LOOKBACK) ~= 0 local downHeld = (player.cmd.throwdir or 0) < 0 local forceExplode = bailPressed and (downHeld or lookbackHeld) if player.cb_explode_tics and player.cb_explode_tics > 0 then player.cb_explode_tics = $ - 1 end -- Ring Unlocker (pull extras into overRings, push back when below cap) if (rings + (player.pickuprings or 0)) >= 20 then player.overRings = $+1 player.rings = $-1 elseif overRings > 0 then if rings < 19 then player.rings = $+1 player.overRings = $-1 end end if (rings + overRings) < 127 then player.hudrings = rings + overRings else player.hudrings = 127 end -- Total rings for HUD display -- Refresh cached ring values after unlocker adjustments rings = player.rings or rings overRings = player.overRings or overRings superring = player.superring or superring -- Explosion -- Crash Breaker: only while already spinning/tumbling if (forceExplode) and bailPressed and (rings + overRings + superring > 1) then did_explode = true local radius = GetExplosionRadius(player) player.cb_explode_tics = 8 player.cb_explode_radius = radius player.cb_explode_tick = leveltime P_RadiusAttack(player.mo, player.mo, radius) K_SpawnMineExplosion(player.mo, 36, MT_BOOMEXPLODE) P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_SMOLDERING) player.ringburst = player.superring + player.floatrings + player.overRings + player.rings + 20 player.superring = 0 player.overRings = 0 player.floatrings = 0 if player.rings > 0 then player.rings = $-20 K_TumblePlayer(player, player.mo, player.mo, true) player.momz = 50*FRACUNIT K_SpawnSparkleTrail(player.mo) P_PlayerRingBurst(player, 20) end end -- Crash Breaker knockback/tumble (active for a few tics after explosion) if player.cb_explode_tics and player.cb_explode_tics > 0 and player.cb_explode_radius > 0 and player.mo and player.mo.valid then local radius = player.cb_explode_radius for victim in players.iterate do if victim ~= player and victim.mo and victim.mo.valid then if victim.cb_last_explode_tick ~= player.cb_explode_tick then local dist = P_AproxDistance(P_AproxDistance(victim.mo.x - player.mo.x, victim.mo.y - player.mo.y), victim.mo.z - player.mo.z) if dist <= radius then victim.cb_last_explode_tick = player.cb_explode_tick local angle = R_PointToAngle2(player.mo.x, player.mo.y, victim.mo.x, victim.mo.y) local knockback = max(0, FixedDiv(radius - dist, radius)) * 50 * FRACUNIT P_InstaThrust(victim.mo, angle, knockback) victim.mo.momz = $ + knockback / 2 K_TumblePlayer(victim, player.mo, player.mo, true) end end end end end -- Burnout activation (only if we did NOT just explode this tic) if (not did_explode) and spinouttimer <= 0 and tumbleheight <= 10 and overRings > ((FULLCHARGE - 20)+(-10+player.kartspeed*CHARGEDIFF)) and bailPressed then if player.speed < (10*FRACUNIT + (1000*FRACUNIT/(player.kartspeed*10+3))) then P_InstaThrust(player.mo, player.mo.angle, 10*FRACUNIT + (1000*FRACUNIT/(player.kartspeed*10+3))) -- Temp. Depcrecated from v1 end player.baildrop = $ + (player.overRings*2)*(player.kartspeed/2) if player.overRings > ((FULLCHARGE - 20)+(-10+player.kartspeed*CHARGEDIFF)) then player.overRings = $ - ((FULLCHARGE - 20)+(-10+player.kartspeed*CHARGEDIFF)) local sqrtInput = max(0, 5*((player.kartspeed)/(4))*(player.overRings-500)+1000) player.ringboost = $ + FixedSqrt(sqrtInput) -- print(sqrtInput .. " This works?") else player.ringboost = $ + player.overRings * 4 end if player.position == 1 then player.invincibilitytimer = 0 player.overRings = 0 elseif player.position > 4 then K_DoInvincibility(player, (1*(TICRATE/2))*player.kartweight+((1*player.position-4)*TICRATE)) end player.boosting = true end -- Burnout bonus if player.boosting then --- Drift Bonus --- if player.drift ~= 0 then player.floatrings = $ + 5 + (8-player.kartweight) end if player.driftboost > 0 then player.floatrings = $ + 8 + (8-player.kartweight) end --- Dash Panel Bonus --- if player.floorboost ~= 0 then player.superring = $ + 2 end --- WaveDash Bonus --- if player.wavedash > 0 then player.floatrings = $ + 2 + ((8-player.kartweight)/2) end if not P_IsObjectOnGround(player.mo) then player.floatrings = $ + player.speed*TICRATE/(50*FRACUNIT) player.floatrings = $ + abs(player.mo.momz)*TICRATE/(100*FRACUNIT) end --------------- Keep Boost --------------- local baildrop_val = player.baildrop or 0 local ringboost_val = player.ringboost or 0 local targetBoost = baildrop_val*(4+(player.kartspeed/4)) if ringboost_val < targetBoost and targetBoost < 30000 then player.ringboost = targetBoost elseif ringboost_val > 20000 then player.ringboost = 20000 end --------------- Bail Cancel --------------- if (player.cmd.buttons & BT_BRAKE) and P_IsObjectOnGround(player.mo) then player.burnout = 0 player.boosting = false player.ringboost = 0 player.baildrop = 0 player.stunned = 0 player.superring = $/8 player.invincibilitytimer = 0 end --------------- Bail Chain --------------- if player.baildrop < 2 then if player.superring > ((FULLCHARGE)+(-10+player.kartspeed*CHARGEDIFF)) then if bailHeld then player.baildrop = $ + player.superring * 4 player.ringboost = $ + player.superring * 5 else player.stunned = 0 S_StartSound(player.mo, sfx_supert) player.overRings = player.superring/2 player.superring = $/2 player.burnout = $ + 1 end end player.boosting = false player.burnout = 0 end ------ handleboost ------ player.handleboost = (FRACUNIT - 10000) + (player.ringboost * 2 ) player.weightboost = FRACUNIT ------------------------- -- end burnout --Sounds-- if player.superring > ((FULLCHARGE)+(-10+player.kartspeed*CHARGEDIFF)) and (leveltime%20) == 10 then S_StartSound(player.mo, sfx_s3kad) end elseif player.superring == 0 then player.burnout = 0 end -- of boosting --------------- Float to Whole rings --------------- if player.position > 3 and player.floatrings > TICRATE*2 then player.superring = $ + 1 player.overRings = $ + 1 player.floatrings = $ - (TICRATE*2) end if player.floatrings > TICRATE then player.superring = $ + 1 player.floatrings = $ - TICRATE end -- AfterTouch Mechanic if player.spinouttimer > 0 or player.wipeoutslow > 0 then if player.spinouttimer > 200 then --Prevent After touch to become OP from SPB. P_InstaThrust(player.mo, player.mo.angle, -10*FRACUNIT) end if player.spinouttimer < 100 then P_Thrust(player.mo, player.mo.angle, (player.spinouttimer/2)*player.cmd.throwdir+player.speed*player.cmd.throwdir*3/FRACUNIT) P_Thrust(player.mo, player.mo.angle+ANGLE_90, (player.spinouttimer/2)*player.cmd.turning+player.speed*player.cmd.turning*3/FRACUNIT) else P_Thrust(player.mo, player.mo.angle, (player.spinouttimer/30)*player.cmd.throwdir+player.speed*player.cmd.throwdir*3/FRACUNIT+player.cmd.throwdir) P_Thrust(player.mo, player.mo.angle+ANGLE_90, (player.spinouttimer/30)*player.cmd.turning+player.speed*player.cmd.turning*3/FRACUNIT+player.cmd.throwdir) end elseif player.tumbleheight != nil and player.tumbleheight > 10 then -- Aftertouch while Tumbling P_Thrust(player.mo, player.mo.angle, (player.speed+player.mo.momz)*player.cmd.throwdir*2/(FRACUNIT)) --Manouver Player based on their current speed/momentum [Forward / Backawards] P_Thrust(player.mo, player.mo.angle+ANGLE_90, (player.speed+player.mo.momz)*player.cmd.turning*2/(FRACUNIT)) -- [Left / Right] end -- End of AfterTouch -- Deathpit/pitblame reward logic (cringe) if player.pitblame and player.pitblame >= 0 then local attacker = players[player.pitblame+1] if attacker and attacker.valid then attacker.overRings = (attacker.superring or 0) + (TAKEDOWN_BONUS*2) end end if player.growshrinktimer > 0 and player.growshrinktimer < 16000 and player.numboosts >= 2 and P_IsObjectOnGround(player.mo) and (player.position >= 2 or player.boosting == true) then player.ringdelay = 0 player.growthTicks = $ + (player.numboosts*10)/4 if player.growthTicks >= 10 then player.growthTicks = 0 -- Reset accumulator player.growshrinktimer = $ + 2 -- Extend grow/shrink effect end player.floatrings = $ + max(player.numboosts-2, 0) end end end) -- In your ShouldDamage hook, modify it to detect explosion damage and apply knockback addHook("ShouldDamage", function(target, inflictor, source) if target.player then local attacker = (source and source.player) or (inflictor and inflictor.player) -- Check if this is explosion damage from a tumbling/spinning player if attacker and source and source.valid and attacker.cb_explode_tics and attacker.cb_explode_tics > 0 then -- Reward logic for crash breaker hit attacker.rings = 20 attacker.overRings = $ + 70 end -- Original reward logic if attacker then attacker.superring = $ + TAKEDOWN_BONUS+(attacker.kartweight*5) + 20 end end end) -- Physical fighting bonus. addHook("MobjCollide", function(mo1, mo2) local player1 = mo1.player local player2 = mo2.player if player1 and player2 then player1.floatrings = $ + player1.kartweight - player2.kartweight + 5 player2.floatrings = $ + player2.kartweight - player1.kartweight + 5 end end) local function HUDThing(v, p, c) -- HUD CODE -- Crash Breaker debug info if p.cb_explode_radius and p.cb_explode_radius > 0 then local radius_units = p.cb_explode_radius / FRACUNIT local active = (p.cb_explode_tics and p.cb_explode_tics > 0) and "YES" or "NO" local tics = (p.cb_explode_tics or 0) v.drawString(6, 188, "CB RADIUS: " .. radius_units .. " | ACTIVE: " .. active .. " | TICS: " .. tics, V_MONOSPACE | V_SNAPTOBOTTOM | V_SNAPTORIGHT | V_YELLOWMAP, "small") local raw_excess_units = (p.cb_raw_excess or 0) / FRACUNIT local scale_units = (p.cb_scale or FRACUNIT) / FRACUNIT v.drawString(6, 182, "CB RAW-BASE: " .. raw_excess_units .. " | SCALE: " .. scale_units, V_MONOSPACE | V_SNAPTOBOTTOM | V_SNAPTORIGHT | V_YELLOWMAP, "small") end if p.overRings != nil then if p.overRings >= 108 then v.drawString(6, 170, "+" .. (p.overRings-108 or 0), V_MONOSPACE | V_SNAPTOBOTTOM | V_SNAPTORIGHT | V_YELLOWMAP, "small") end end if (p.overRings or 0) > ((FULLCHARGE - 20)+(-10+p.kartspeed*CHARGEDIFF)) then v.drawString(100, 50, "SUPERCHARGED!", V_LOWSCALEPATCH, right) end --end -- SuperCharge >>>>>>>>>>>> --- BOOST BAR -- Boost Bar =========== -- Ensure rep is always a valid number local rep = 0 if p.boosting == true then rep = p.baildrop / 8 else if p.overRings ~= nil then rep = ((p.rings or 0) + (p.overRings or 0)) / 4 else rep = (p.rings or 0) / 4 end end rep = min(barlength, rep) local boostbar = "[" .. string.rep("|", rep) .. string.rep(" ", barlength - rep) .. "]" v.drawString(70, 70, " " .. boostbar, V_MONOSPACE | V_SNAPTOTOP | V_SNAPTORIGHT | V_YELLOWMAP, "small") if p.boosting == true then v.drawString(70, 70, " " .. boostbar, V_MONOSPACE | V_SNAPTOTOP | V_SNAPTORIGHT | V_ADD | V_80TRANS | V_SKYMAP, "small") end end hud.add(HUDThing)