
-- this hud took long and i add a hint of sonic and the fallen star type sheet credit goes to DarkEdgyHope aka Rivaledgyhope for 
-- this amazing script ik i am such a goat gng!

local MENU_OPTIONS = {
    "CARRY MODE",
    "STOMP MOVEMENT",
    "BOOST SOUNDS",
    "BOOST BUTTON", 
    "WHITE", "RED", "BLUE", "CYAN", "MAGENTA", "YELLOW", "ORANGE", "GREEN", 
    "PURPLE", "PINK", "BROWN", "GOLD", "SILVER", "SKY", "CYLOOP", "MINT", 
    "LAVENDER", "CRIMSON", "SAPPHIRE", "EMERALD", "TEAL", "BRONZE", "COPPER", 
    "RUBY", "AQUA", "VIOLET", "AETHER", "COBALT", "PEPPER", "NEON", "JET", 
    "APRICOT", "FLAME", "PASTEL"
}


local BOX_W = 170
local BOX_H = 190 
local ANIMATION_SPEED_TICS = 6
local smooth_stamina_cache = {}
local patches = {}
local boost_button_flags = {
    [0] = BT_CUSTOM1,
    [1] = BT_CUSTOM2,
    [2] = BT_CUSTOM3,
    [3] = BT_FIRENORMAL
}
	


rawset(_G, "carry_enabled", true)
rawset(_G, "stomp_enabled", true)
rawset(_G, "boost_sound_mode", 1) -- 1 = GENERATIONS, 2 = SONIC RUSH, 3 = FRONTIERS
rawset(_G, "boost_button_mode", 1) -- 0 = CUSTOM1, 1 = CUSTOM2, 2 = CUSTOM3,4 = FIRENORMAL

addHook("PlayerThink", function(player)
    if not (player and player.valid and player.mo and player.mo.valid) then return end
    local chosen_button_flag = BT_CUSTOM2
    if _G["boost_button_mode"] ~= nil and boost_button_flags[_G["boost_button_mode"]] ~= nil then
        chosen_button_flag = boost_button_flags[_G["boost_button_mode"]]
    end
    if player.bstcooldown == nil then player.bstcooldown = 0 end
    if player.bstcooldown > 0 then player.bstcooldown = $ - 1 end
    if player.mo.shadowform_stamina >= 1 then
        if player.speed >= player.runspeed  
        and (player.cmd.buttons & chosen_button_flag) 
        and (player.bstcooldown == 0)
        and not (player.pflags & PF_FULLSTASIS)
        and not (player.pflags & PF_STARTDASH)
        and not (player.pflags & PF_FINISHED)
        and not (player.pflags & PF_SPINNING)
        and not (player.pflags & PF_THOKKED)
        and player.playerstate ~= PST_DEAD
        and not P_PlayerInPain(player) then
         player.bvfxing = true
         player.charflags = $ | SF_RUNONWATER
		 player.charflags = $ | SF_CANBUSTWALLS
		 player.bstframe = true
        else if player.powers[pw_carry] == 3888
		 and (player.cmd.buttons & chosen_button_flag) 
        and (player.bstcooldown == 0)
        and not (player.pflags & PF_FULLSTASIS)
        and not (player.pflags & PF_STARTDASH)
        and not (player.pflags & PF_FINISHED)
        and not (player.pflags & PF_SPINNING)
        and not (player.pflags & PF_THOKKED)
        and player.playerstate ~= PST_DEAD
        and not P_PlayerInPain(player) 
		 player.bvfxing = true
		 player.charflags = $ | SF_RUNONWATER
		 player.charflags = $ | SF_CANBUSTWALLS
		 player.bstframe = true
		 else
            player.bvfxing = false
            player.charflags = $ & ~SF_RUNONWATER
            player.charflags = $ & ~SF_CANBUSTWALLS
            if player.bstframe == true then
                player.bstframe = false
                player.bstcooldown = 15
            end
			end
		end
	 end
end)

addHook("PostThinkFrame", function()
    for player in players.iterate do
        if not (player and player.valid) then continue end
        if player.bvfxing == true then
            if player.hashitwooshspeed == true then -- some stuff i left behind
                player.camerascale = FRACUNIT * 2 
            else
                player.camerascale = FRACUNIT * 3 / 2
            end
        else
            player.camerascale = FRACUNIT
        end
    end
end)


local function HandleMenuHorizontalScrolling(player)
    if player.menu_cursor == 36 then
        if player.cmd.sidemove > 0 then
            _G["boost_button_mode"] = $ + 1
            if _G["boost_button_mode"] > 3 then _G["boost_button_mode"] = 0 end
            player.menu_debounce = 6
			if player==consoleplayer
            S_StartSound(player.mo, sfx_onee)
			end
        elseif player.cmd.sidemove < 0 then
            _G["boost_button_mode"] = $ - 1
            if _G["boost_button_mode"] < 0 then _G["boost_button_mode"] = 3 end
            player.menu_debounce = 6
			if player==consoleplayer
            S_StartSound(player.mo, sfx_onee)
			end
        end
    end
end


addHook("PlayerSpawn", function(player)
    player.menu_open = false
    player.menu_cursor = 1
    player.menu_debounce = 0
    player.menu_anim_timer = 0 
    player.menu_smooth_scroll = 1 * FRACUNIT 
    player.saved_stage_music = "NONE"
    player.neon_impact_flare = 0 
    if player.mo and player.mo.valid then
        player.mo.boost_menu_audio_state = "IDLE"
    end
end)

addHook("PlayerThink", function(player)
    if player.chosenbvfxcolor == nil and player.mo and player.mo.valid then
        player.chosenbvfxcolor = player.mo.color
    end
end)

COM_AddCommand("bvfx", function(player, colorName)
    if not (player and player.valid) then return end
    if not colorName then
        CONS_Printf(player, "Usage: bvfx <colorname> or bvfx default")
        return
    end
    local newColor = _G["SKINCOLOR_" .. colorName:upper()]
    if newColor ~= nil then
        player.chosenbvfxcolor = newColor
        CONS_Printf(player, "Your personal bvfx color set to: " .. colorName:upper())
    else
        CONS_Printf(player, "Error: " .. colorName .. " is not a valid color!")
    end
end)



rawset(_G, "BoostVfx", function(player)
    if not (player and player.valid and player.mo and player.mo.valid) then return end
    local vfxColor = player.chosenbvfxcolor or player.mo.color
    local fast = P_SpawnMobj(player.mo.x + (P_RandomRange(-50,50) * player.mo.scale), player.mo.y + (P_RandomRange(-50,50) * player.mo.scale), player.mo.z + (player.mo.height/2) + (P_RandomRange(-20,20) * player.mo.scale), MT_SMOKE)
    if fast and fast.valid then
        fast.state = S_BOOSTPARTICLE
        fast.angle = player.drawangle
        fast.momx = player.mo.momx/2
        fast.momy = player.mo.momy/2
        fast.momz = player.mo.momz/2
        fast.colorized = true
        fast.blendmode = AST_ADD
        fast.scale = player.mo.scale
        fast.frame = $|FF_FULLBRIGHT|FF_TRANS40
        fast.tics = 20
        fast.color = vfxColor
    end
    local fast2 = P_SpawnMobj(player.mo.x + (P_RandomRange(-50,50) * player.mo.scale), player.mo.y + (P_RandomRange(-50,50) * player.mo.scale), player.mo.z + (player.mo.height/2) + (P_RandomRange(-20,20) * player.mo.scale), MT_SMOKE)
    if fast2 and fast2.valid then
        fast2.state = S_BOOSTPARTICLE
        fast2.angle = player.drawangle
        fast2.momx = player.mo.momx/2
        fast2.momy = player.mo.momy/2
        fast2.momz = player.mo.momz/2
        fast2.colorized = true
        fast2.blendmode = AST_ADD
        fast2.scale = player.mo.scale
        fast2.frame = $|FF_FULLBRIGHT|FF_TRANS40
        fast2.tics = 20
        fast2.color = vfxColor
    end
    local trail = P_SpawnGhostMobj(player.mo)
    if trail and trail.valid then
        trail.tics = 3
        trail.blendmode = AST_ADD
        trail.frame = $|FF_FULLBRIGHT
        P_MoveOrigin(trail, player.mo.x, player.mo.y, player.mo.z)
        trail.color = vfxColor
    end    local adventurerip2 = P_SpawnMobjFromMobj(player.mo, player.mo.momx/2, player.mo.momy/2 , player.mo.momz, MT_THOK)  
    if adventurerip2 and adventurerip2.valid then
        adventurerip2.colorized = true
        adventurerip2.blendmode = AST_ADD
        adventurerip2.sprite = SPR_TMPE
        adventurerip2.frame = (leveltime*2 % 4) | FF_TRANS60
        adventurerip2.tics = 5
        adventurerip2.tracer = player.mo
        adventurerip2.destscale = FRACUNIT/3
        adventurerip2.scale = FRACUNIT
        adventurerip2.rollangle = player.mo.rollangle + FixedMul(player.mo.momz, sin(player.mo.angle - (player.mo.momx + player.mo.momy)))
        adventurerip2.angle = player.drawangle
        adventurerip2.color = vfxColor
    end
    local sparkle = P_SpawnMobj(player.mo.x+P_RandomRange(-20, 20)*player.mo.scale, player.mo.y+P_RandomRange(-30, 30)*player.mo.scale, player.mo.z+P_RandomRange(-30, 0)*player.mo.scale+player.mo.height, MT_WATERZAP)
    if sparkle and sparkle.valid then
        sparkle.flags2 = $|MF2_OBJECTFLIP
        sparkle.colorized = true
        sparkle.state = S_BOOST_SPARK
        sparkle.scale = FRACUNIT/3
        sparkle.destscale = -2
        sparkle.blendmode = AST_ADD
        sparkle.tics = 20
        sparkle.color = vfxColor
    end
    local sparkle2 = P_SpawnMobj(player.mo.x+P_RandomRange(-20, 20)*player.mo.scale, player.mo.y+P_RandomRange(-50, 50)*player.mo.scale, player.mo.z+P_RandomRange(-30, 0)*player.mo.scale+player.mo.height, MT_WATERZAP)
    if sparkle2 and sparkle2.valid then
        sparkle2.flags2 = $|MF2_OBJECTFLIP
        sparkle2.colorized = true
        sparkle2.destscale = FRACUNIT*3/2
        sparkle2.blendmode = AST_ADD
        sparkle2.tics = 25
        sparkle2.color = vfxColor
    end
end)

local function draw_custom_num(v, nums, x, y, scale, flags, colormap)
    if not v then return false end
    nums = tostring(nums or 0)
    local chars = {}
    local charX = 0
    local totalWidth = 0
    local i = 1
    while i <= nums:len() do
        local width = 0
        local currentChar = nums:sub(i, i)
        local patchName = "NUBM" .. currentChar
        if patches[patchName] == nil then
            local success, result = pcall(function() return v.cachePatch(patchName) end)
            if success and result and result.valid then
                if result.width == 8 and result.height == 8 then
                    patches[patchName] = false
                else
                    patches[patchName] = result
                end
            else
                patches[patchName] = false
            end
        end
        local patch = patches[patchName]
        if not patch then return false end
        width = FixedMul(patch.width - 1, scale)
        table.insert(chars, {
            patch = patch,
            x = charX
        })
        charX = $ + width
        totalWidth = $ + width
        i = $ + 1
    end
    for i = 1, #chars do
        if chars[i] and chars[i].patch then
            local currentPatch = chars[i].patch
            v.drawScaled(x * FRACUNIT + chars[i].x - totalWidth / 2, y * FRACUNIT - (currentPatch.height * scale) / 2, scale, currentPatch, flags, colormap)
        end
    end
    return true
end

addHook("PlayerSpawn", function(player)
    player.menu_open = false
    player.menu_cursor = 1
    player.menu_debounce = 0
    player.menu_anim_timer = 0 
    player.menu_smooth_scroll = 1 * FRACUNIT 
    player.saved_stage_music = "NONE"
    player.neon_impact_flare = 0 
    if player.mo and player.mo.valid then
        player.mo.boost_menu_audio_state = "IDLE"
    end
end)

addHook("PlayerThink", function(player)
    if player.chosenbvfxcolor == nil and player.mo and player.mo.valid then
        player.chosenbvfxcolor = player.mo.color
    end
end)

addHook("PlayerThink", function(player)
    if not (player and player.valid and player.mo and player.mo.valid) then return end
    local mo = player.mo
    if player.menu_debounce == nil then player.menu_debounce = 0 end
    if player.neon_impact_flare == nil then player.neon_impact_flare = 0 end
    if player.menu_open == nil then player.menu_open = false end
    if player.menu_anim_timer == nil then player.menu_anim_timer = 0 end
    if player.menu_cursor == nil then player.menu_cursor = 1 end
    if player.menu_smooth_scroll == nil then player.menu_smooth_scroll = 1 * FRACUNIT end
    if player.saved_stage_music == nil then player.saved_stage_music = "NONE" end
    if player.menu_debounce > 0 then player.menu_debounce = $ - 1 end
    if player.neon_impact_flare > 0 then player.neon_impact_flare = $ - 1 end 
    if (player.cmd.buttons & BT_CUSTOM3) and player.menu_debounce == 0 then
        if player.menu_open == false and player.speed > 0 then return end -- this shit is hard to deal gng
        player.menu_open = not player.menu_open
        player.menu_debounce = 12
        player.neon_impact_flare = 8 
        S_StartSound(mo, sfx_menu1)
        
        if player.menu_open then
            local currentSong = S_MusicName()
            if currentSong ~= "SFPASE" and currentSong ~= "MENR" then player.saved_stage_music = currentSong end
            if not player.menu_music_locked then S_ChangeMusic("MENR", true, player) player.menu_music_locked = true end
        else
            if player.menu_music_locked then
                local trackToRestore = (player.saved_stage_music ~= "NONE") and player.saved_stage_music or mapheaderinfo[G_LegacyMapName(gamemap)].music
                S_ChangeMusic(trackToRestore, true, player)
                player.menu_music_locked = false
            end
        end
    end
    if player.menu_open then
        if player.menu_anim_timer < ANIMATION_SPEED_TICS then player.menu_anim_timer = $ + 1 end
    else
        if player.menu_anim_timer > 0 then player.menu_anim_timer = $ - 1 end
    end
    if not player.menu_open and player.menu_anim_timer == 0 then return end

    if player.menu_open and player.menu_anim_timer == ANIMATION_SPEED_TICS then
        if (player.cmd.forwardmove > 25) and player.menu_debounce == 0 then
            player.menu_cursor = $ - 1
            if player.menu_cursor < 1 then player.menu_cursor = #MENU_OPTIONS player.menu_smooth_scroll = (#MENU_OPTIONS + 1) * FRACUNIT end
            player.menu_debounce = 6
            player.neon_impact_flare = 4 
            S_StartSound(mo, sfx_roll)
        elseif (player.cmd.forwardmove < -25) and player.menu_debounce == 0 then
            player.menu_cursor = $ + 1
            if player.menu_cursor > #MENU_OPTIONS then player.menu_cursor = 1 player.menu_smooth_scroll = 0 end
            player.menu_debounce = 6
            player.neon_impact_flare = 4 
            S_StartSound(mo, sfx_roll)
        end
        local diff = (player.menu_cursor * FRACUNIT) - player.menu_smooth_scroll
        player.menu_smooth_scroll = $ + (diff / 3)
    end
    if player.menu_open and player.menu_anim_timer == ANIMATION_SPEED_TICS then
        if player.menu_debounce == 0 then
            if player.menu_cursor == 4 then
                if (player.cmd.sidemove > 25) or (player.cmd.buttons & BT_SPIN) then
                    _G["boost_button_mode"] = $ + 1
                    if _G["boost_button_mode"] > 3 then _G["boost_button_mode"] = 0 end
                    player.menu_debounce = 6
                    player.neon_impact_flare = 4
                    S_StartSound(mo, sfx_onee)
                elseif (player.cmd.sidemove < -25) then
                    _G["boost_button_mode"] = $ - 1
                    if _G["boost_button_mode"] < 0 then _G["boost_button_mode"] = 3 end
                    player.menu_debounce = 6
                    player.neon_impact_flare = 4
                    S_StartSound(mo, sfx_onee)
                end
            end
        end
        if (player.cmd.buttons & BT_JUMP) and player.menu_debounce == 0 then
            player.menu_debounce = 12
            player.neon_impact_flare = 6 
            if player.menu_cursor == 1 then
                _G["carry_enabled"] = not _G["carry_enabled"]
                if _G["carry_enabled"] == true then S_StartSound(mo, sfx_onee) else S_StartSound(mo, sfx_one) end
            elseif player.menu_cursor == 2 then
                _G["stomp_enabled"] = not _G["stomp_enabled"]
                S_StartSound(mo, sfx_onee)
            elseif player.menu_cursor == 3 then
                _G["boost_sound_mode"] = $ + 1
                if _G["boost_sound_mode"] > 4 then _G["boost_sound_mode"] = 1 end
                S_StartSound(mo, sfx_onee)
            elseif player.menu_cursor == 4 then
                _G["boost_button_mode"] = $ + 1
                if _G["boost_button_mode"] > 3 then _G["boost_button_mode"] = 0 end
                S_StartSound(mo, sfx_onee)
            else
                local colorStringName = MENU_OPTIONS[player.menu_cursor]
                local targetColorObj = _G["SKINCOLOR_" .. colorStringName]
                if targetColorObj ~= nil then player.chosenbvfxcolor = targetColorObj S_StartSound(mo, sfx_onee) end
            end
        end
    end
    if player.menu_open then
        player.cmd.forwardmove = 0 player.cmd.sidemove = 0 player.cmd.buttons = 0
        mo.momx = 0 mo.momy = 0 if mo.momz > 0 then mo.momz = 0 end 
    end
end)



addHook("HUD", function(v, p)
    if not (p and p.valid) then return end
    local ANIMATION_SPEED_TICS = 6
    local a = p.menu_anim_timer or 0
    if p.menu_open == true then hud.disable("score") hud.disable("time") hud.disable("rings")
    else hud.enable("score") hud.enable("time") hud.enable("rings") end
    if a == 0 then return end
    v.disableVanillaHUD = true
    local sW, sH, cC, aC = v.width()/FRACUNIT, v.height()/FRACUNIT, p.menu_cursor or 1, 151
    if p.menu_open then
        v.drawFill(0, 0, sW, sH, 31|V_SNAPTOTOP|V_90TRANS)
        local mH = 16 local sHut = (mH * a) / ANIMATION_SPEED_TICS
        v.drawFill(0, 0, sW, sHut, 31|V_SNAPTOTOP) v.drawFill(0, sH-sHut, sW, sHut, 31|V_SNAPTOTOP)
        v.drawFill(0, sHut-1, sW, 1, aC|V_SNAPTOTOP|V_50TRANS) v.drawFill(0, sH-sHut, sW, 1, aC|V_SNAPTOTOP)
    end
    if a == ANIMATION_SPEED_TICS then
        local sS, sF, sC = (leveltime/2)%max(1, sH), leveltime%max(1, sH), max(1, sH-36)
        for sx = 10, sW, 35 do
            local dY1, dY2 = (sx*4+sS)%sC+16, (sx*2+sF)%sC+16
            v.drawFill(sx, dY1, 1, 3, aC|V_SNAPTOTOP|V_70TRANS) v.drawFill(sx+15, dY2, 1, 2, 31|V_SNAPTOTOP|V_60TRANS)
        end
        local fX = (sW - (leveltime*3 % (sW+60)))
        if fX > 10 and fX < sW-10 then v.drawFill(fX, sH/4, 3, 2, aC|V_SNAPTOTOP|V_50TRANS) v.drawFill(fX+10, sH*3/4, 2, 2, 0|V_SNAPTOTOP|V_70TRANS) end
    end
    local targetY = 104 - (BOX_H / 2)
    local cY = targetY local bW, bH = 0, 0 local isCrtFlashing = false
    if a <= 2 then bW = (BOX_W * a) / 2 bH = 2 cY = targetY + (BOX_H / 2) - 1 isCrtFlashing = true
    else bW = BOX_W local verticalProgress = a - 2 bH = (BOX_H * verticalProgress) / (ANIMATION_SPEED_TICS - 2) cY = targetY + (BOX_H / 2) - (bH / 2) end
    local crtShakeX = 0
    if a > 0 and a < ANIMATION_SPEED_TICS then local shakeMagnitude = max(1, 4 - a) crtShakeX = ((leveltime % 2 == 0) and 1 or -1) * shakeMagnitude end
    local cX = 160 - (bW / 2) + crtShakeX local dI, pO = p.neon_impact_flare or 0, (leveltime%16 < 8) and 1 or 0 local tF = 3 + pO + dI
    if dI > 0 then v.drawFill(cX-(tF+(dI*2)), cY-(tF+(dI*2)), bW+((tF+(dI*2))*2), bH+((tF+(dI*2))*2), aC|V_SNAPTOTOP|V_80TRANS) end
    v.drawFill(cX-tF, cY-tF, bW+(tF*2), bH+(tF*2), aC|V_SNAPTOTOP|V_70TRANS)
    local crtBgColor = 29|V_SNAPTOTOP|V_20TRANS
    if isCrtFlashing then crtBgColor = (leveltime % 2 == 0) and (0|V_SNAPTOTOP) or (159|V_SNAPTOTOP)
    elseif a < ANIMATION_SPEED_TICS then crtBgColor = 159|V_SNAPTOTOP|V_30TRANS end
    v.drawFill(cX, cY, bW, bH, crtBgColor)
    if isCrtFlashing and bW > 0 then
        local noiseColors = {0, 31, 159, 29}
        for nx = 0, bW, 4 do local noiseColorIndex = ((leveltime + nx) % 4) + 1 v.drawFill(cX + nx, cY, min(4, bW - nx), 2, noiseColors[noiseColorIndex]|V_SNAPTOTOP|V_70TRANS) end
    end
    if p.menu_open then
        local aS = 8 + (dI/2)
        v.drawFill(cX-tF-4, cY-tF-4, aS, 1, aC|V_SNAPTOTOP) v.drawFill(cX-tF-4, cY-tF-4, 1, aS, aC|V_SNAPTOTOP)
        v.drawFill(cX+bW+tF+4-aS, cY-tF-4, aS, 1, aC|V_SNAPTOTOP) v.drawFill(cX+bW+tF+3, cY-tF-4, 1, aS, aC|V_SNAPTOTOP)
        v.drawFill(cX-tF-4, cY+bH+tF+3, aS, 1, aC|V_SNAPTOTOP) v.drawFill(cX-tF-4, cY+bH+tF+4-aS, 1, aS, aC|V_SNAPTOTOP)
        v.drawFill(cX+bW+tF+4-aS, cY+bH+tF+3, aS, 1, aC|V_SNAPTOTOP) v.drawFill(cX+bW+tF+3, cY+bH+tF+4-aS, 1, aS, aC|V_SNAPTOTOP)
    end
    if a == ANIMATION_SPEED_TICS then
        local slowScrollX = (leveltime) % 24 local slowScrollY = (leveltime) % 24
        local pulseSize = 10 + ((sin(leveltime * (ANG1 * 3)) * 3) / FRACUNIT)
        local cycleWave = (sin(leveltime * (ANG1 * 4)) * 3) / FRACUNIT local globalFade = 30 + cycleWave
        for bx = -24, bW + 24, 24 do
            for by = -24, bH + 24, 24 do
                local finalBoxX = cX + bx - slowScrollX local finalBoxY = cY + 22 + by - slowScrollY
                if finalBoxX >= cX + 4 and finalBoxX + pulseSize <= cX + bW - 4 then
                    if finalBoxY >= cY + 20 and finalBoxY + pulseSize <= cY + bH - 14 then
                        local alternateStyle = (((bx + (leveltime & ~23)) / 24) + ((by + (leveltime & ~23)) / 24)) % 2 == 0
                        local baseAlpha = alternateStyle and V_70TRANS or V_80TRANS
                        if globalFade > 31 then baseAlpha = alternateStyle and V_80TRANS or V_90TRANS
                        elseif globalFade < 29 then baseAlpha = alternateStyle and V_60TRANS or V_70TRANS end
                        v.drawFill(finalBoxX, finalBoxY, pulseSize, pulseSize, 31|V_SNAPTOTOP|baseAlpha) v.drawFill(finalBoxX + 1, finalBoxY + 1, pulseSize - 2, pulseSize - 2, 29|V_SNAPTOTOP|V_70TRANS)
                    end
                end
            end
        end
    end
local sS, vW = p.menu_smooth_scroll or (1*FRACUNIT), 4 local tI, sI = #MENU_OPTIONS, (sS/FRACUNIT)-(vW/2)
        local eI = sI + vW if sI < 1 then sI = 1 end if eI > tI then eI = tI end
        if a == ANIMATION_SPEED_TICS then
            local spkoffset = (leveltime / 4) % 8
            for zy = cY + spkoffset, cY + bH - 8, 8 do
                local distancefromtop = zy - cY
                local dynamicw = 4 + (distancefromtop / 24)
                if dynamicw > 12 then dynamicw = 12 end
                local w1 = dynamicw
                local w2 = (dynamicw * 3) / 4
                local w3 = dynamicw / 2
                local w4 = dynamicw / 4
                v.drawFill(cX - w1, zy + 0, w1, 1, aC|V_50TRANS|V_SNAPTOTOP|V_PERPLAYER)
                v.drawFill(cX - w2, zy + 1, w2, 1, aC|V_50TRANS|V_SNAPTOTOP|V_PERPLAYER)
                v.drawFill(cX - w3, zy + 2, w3, 1, aC|V_50TRANS|V_SNAPTOTOP|V_PERPLAYER)
                v.drawFill(cX - w4, zy + 3, w4, 1, aC|V_50TRANS|V_SNAPTOTOP|V_PERPLAYER)
                v.drawFill(cX - w4, zy + 4, w4, 1, aC|V_50TRANS|V_SNAPTOTOP|V_PERPLAYER)
                v.drawFill(cX - w3, zy + 5, w3, 1, aC|V_50TRANS|V_SNAPTOTOP|V_PERPLAYER)
                v.drawFill(cX - w2, zy + 6, w2, 1, aC|V_50TRANS|V_SNAPTOTOP|V_PERPLAYER)
                v.drawFill(cX - w1, zy + 7, w1, 1, aC|V_50TRANS|V_SNAPTOTOP|V_PERPLAYER)
                local rx = cX + bW
                v.drawFill(rx, zy + 0, w1, 1, aC|V_50TRANS|V_SNAPTOTOP|V_PERPLAYER)
                v.drawFill(rx, zy + 1, w2, 1, aC|V_50TRANS|V_SNAPTOTOP|V_PERPLAYER)
                v.drawFill(rx, zy + 2, w3, 1, aC|V_50TRANS|V_SNAPTOTOP|V_PERPLAYER)
                v.drawFill(rx, zy + 3, w4, 1, aC|V_50TRANS|V_SNAPTOTOP|V_PERPLAYER)
                v.drawFill(rx, zy + 4, w4, 1, aC|V_50TRANS|V_SNAPTOTOP|V_PERPLAYER)
                v.drawFill(rx, zy + 5, w3, 1, aC|V_50TRANS|V_SNAPTOTOP|V_PERPLAYER)
                v.drawFill(rx, zy + 6, w2, 1, aC|V_50TRANS|V_SNAPTOTOP|V_PERPLAYER)
                v.drawFill(rx, zy + 7, w1, 1, aC|V_50TRANS|V_SNAPTOTOP|V_PERPLAYER)
                local seed = (zy / 8)
                if seed % 2 == 0 then continue end
                local p_lifecycle = ((leveltime / 2) + (seed * 5)) % 24
                local p_trans = (p_lifecycle > 18) and V_80TRANS or ((p_lifecycle > 12) and V_70TRANS or V_50TRANS)
                local p_offset_x = p_lifecycle * 1
                local p_offset_y = 3 + (sin(p_lifecycle * ANG1 * 15) / (FRACUNIT / 4))
                local rotation_frame = (leveltime / 6) % 4
                local r_px = rx + w1 + p_offset_x
                local l_px = cX - w1 - p_offset_x - 2
                local py = zy + p_offset_y
                if rotation_frame == 0 then
                    v.drawFill(r_px, py, 2, 1, aC | p_trans | V_SNAPTOTOP | V_PERPLAYER)
                    v.drawFill(r_px, py + 1, 1, 1, aC | p_trans | V_SNAPTOTOP | V_PERPLAYER)
                    v.drawFill(l_px, py, 2, 1, aC | p_trans | V_SNAPTOTOP | V_PERPLAYER)
                    v.drawFill(l_px, py + 1, 1, 1, aC | p_trans | V_SNAPTOTOP | V_PERPLAYER)
                elseif rotation_frame == 1 then
                    v.drawFill(r_px + 1, py, 1, 1, aC | p_trans | V_SNAPTOTOP | V_PERPLAYER)
                    v.drawFill(r_px, py + 1, 2, 1, aC | p_trans | V_SNAPTOTOP | V_PERPLAYER)
                    v.drawFill(l_px + 1, py, 1, 1, aC | p_trans | V_SNAPTOTOP | V_PERPLAYER)
                    v.drawFill(l_px, py + 1, 2, 1, aC | p_trans | V_SNAPTOTOP | V_PERPLAYER)
                elseif rotation_frame == 2 then
                    v.drawFill(r_px, py, 1, 1, aC | p_trans | V_SNAPTOTOP | V_PERPLAYER)
                    v.drawFill(r_px, py + 1, 2, 1, aC | p_trans | V_SNAPTOTOP | V_PERPLAYER)
                    v.drawFill(l_px, py, 1, 1, aC | p_trans | V_SNAPTOTOP | V_PERPLAYER)
                    v.drawFill(l_px, py + 1, 2, 1, aC | p_trans | V_SNAPTOTOP | V_PERPLAYER)
                else
                    v.drawFill(r_px, py, 2, 1, aC | p_trans | V_SNAPTOTOP | V_PERPLAYER)
                    v.drawFill(r_px + 1, py + 1, 1, 1, aC | p_trans | V_SNAPTOTOP | V_PERPLAYER)
                    v.drawFill(l_px, py, 2, 1, aC | p_trans | V_SNAPTOTOP | V_PERPLAYER)
                    v.drawFill(l_px + 1, py + 1, 1, 1, aC | p_trans | V_SNAPTOTOP | V_PERPLAYER)
                end
            end
        end
    if not isCrtFlashing then
        local scanlineY = cY + 20 + ((leveltime * 2) % (bH - 36))
        if a == ANIMATION_SPEED_TICS then
            local windScroll = (leveltime * 4) % bW local starScroll = (leveltime * 2) % bW
            for row = 1, 14 do
                local tracerX = cX + bW - ((windScroll + (row * 23)) % bW) local tracerY = cY + 20 + (row * 11) local tracerW = 10 + (row % 4 * 6)
                if tracerY < cY + bH - 14 and tracerX >= cX + 4 and tracerX + tracerW <= cX + bW - 4 then
                    local altLineColor = (row % 2 == 0) and (aC|V_SNAPTOTOP|V_60TRANS) or (31|V_SNAPTOTOP|V_80TRANS)
                    v.drawFill(tracerX, tracerY, tracerW, 1, altLineColor)
                end
                local starX = cX + bW - ((starScroll + (row * 43) + 17) % bW) local starY = cY + 24 + ((row * 13) % (bH - 42))
                if starY < cY + bH - 14 and starX >= cX + 4 and starX < cX + bW - 4 then
                    local flashPhase = (leveltime + row) % 12
                    local starColor = (flashPhase < 4) and (0|V_SNAPTOTOP) or ((flashPhase < 8) and (135|V_SNAPTOTOP|V_20TRANS) or (159|V_SNAPTOTOP|V_50TRANS))
                    v.drawFill(starX, starY, 1, 1, starColor)
                    if row < 14 then
                        local nextStarX = cX + bW - ((starScroll + ((row + 1) * 43) + 17) % bW) local nextStarY = cY + 24 + (((row + 1) * 13) % (bH - 42))
                        if nextStarY < cY + bH - 14 and nextStarX >= cX + 4 and nextStarX < cX + bW - 4 then
                            local midX = (starX + nextStarX) / 2 v.drawFill(midX, (starY + nextStarY) / 2, 1, 1, 135|V_SNAPTOTOP|V_90TRANS)
                        end
                    end
                end
            end
            local textScanY = cY + 20 + (leveltime % (bH - 36))
            if textScanY >= cY + 22 and textScanY <= cY + bH - 24 then
                v.drawString(161, textScanY - 3, "Subscribe to rivaledgyhope!", V_SNAPTOTOP|V_80TRANS, "thin-center")
                v.drawString(160, textScanY - 4, "Subscribe to rivaledgyhope!", V_SNAPTOTOP|V_PURPLEMAP, "thin-center")
            end
        end
        v.drawFill(cX, cY, bW, 18, 159|V_SNAPTOTOP) v.drawFill(cX, cY, bW, 1, 135|V_SNAPTOTOP)
        v.drawFill(cX, cY+bH-1, bW, 1, 135|V_SNAPTOTOP) v.drawFill(cX, cY, 1, bH, 135|V_SNAPTOTOP)
        v.drawFill(cX+bW-1, cY, 1, bH, 135|V_SNAPTOTOP) v.drawString(160, cY+5, "BOOST SETTINGS", V_YELLOWMAP, "thin-center")
        if p.mo and p.mo.valid then
            local sP = v.getSprite2Patch(p.mo.skin, SPR2_SIGN, false, A, 0, 0)
            if sP then
                local sB, bS, dR = sin(leveltime*ANG10)*5, (cY+68)*FRACUNIT, 0
                if p.menu_smooth_scroll ~= nil then dR = FixedMul(((cC*FRACUNIT)-p.menu_smooth_scroll)/18, ANG1) end
                local bM, cM = FRACUNIT+(cos(leveltime*(ANG10/2))/50), v.getColormap(TC_DEFAULT, p.mo.color)
                if a < ANIMATION_SPEED_TICS then local cS = FixedMul((a*FRACUNIT)/ANIMATION_SPEED_TICS, bM) v.drawStretched(160*FRACUNIT, bS+sB, cS, cS, sP, V_SNAPTOTOP, cM, dR)
                else v.drawStretched(160*FRACUNIT, bS+sB, bM, bM, sP, V_SNAPTOTOP, cM, dR) end
            end
        end
        local sS, vW = p.menu_smooth_scroll or (1*FRACUNIT), 4 local tI, sI = #MENU_OPTIONS, (sS/FRACUNIT)-(vW/2)
        local eI = sI + vW if sI < 1 then sI = 1 end if eI > tI then eI = tI end
        local sL, sC = {"GENERATIONS", "SONIC RUSH", "FRONTIERS", "FARD"}, {V_YELLOWMAP, V_MAGENTAMAP, V_CYANMAP, V_GREENMAP}
        local bN, bC = {"BT_CUSTOM1", "BT_CUSTOM2", "BT_CUSTOM3", "FIRENORMAL"}, {V_SKYMAP, V_YELLOWMAP, V_PURPLEMAP, V_REDMAP}
        for i = sI, eI do
            local lY = cY + 144 + (((i*FRACUNIT)-sS) * 11 / FRACUNIT)
            if lY > (cY+115) and lY < (cY+bH-16) then
                if i == cC and a == ANIMATION_SPEED_TICS then
                    if i == 1 then v.drawString(160, lY, "[ BOOST STYLE: "..(_G["carry_enabled"] and "CARRY" or "BATTLE!").." ]", _G["carry_enabled"] and V_GREENMAP or V_YELLOWMAP, "thin-center")
                    elseif i == 2 then v.drawString(160, lY, "[ STOMP MOVE: "..(_G["stomp_enabled"] and "ACTIVE" or "MUTED!").." ]", _G["stomp_enabled"] and V_GREENMAP or V_REDMAP, "thin-center")
                    elseif i == 3 then local sM = _G["boost_sound_mode"] or 1 v.drawString(160, lY, "[ SOUNDS: "..sL[sM].." ]", sC[sM], "thin-center")
                    elseif i == 4 then local bM = _G["boost_button_mode"] or 0 if bM > 3 then bM = 0 end v.drawString(160, lY, "[ BUTTON: "..bN[bM+1].." ]", bC[bM+1], "thin-center")
                    else v.drawString(160, lY, "[ "..MENU_OPTIONS[i].." ]", (leveltime%10 < 5) and V_YELLOWMAP or 0, "thin-center") end
                else
                    if i == 1 then v.drawString(160, lY, "BOOST STYLE: "..(_G["carry_enabled"] and "CARRY" or "BATTLE!"), V_GRAYMAP|(_G["carry_enabled"] and V_GREENMAP or V_YELLOWMAP), "thin-center")
                    elseif i == 2 then v.drawString(160, lY, "STOMP MOVE: "..(_G["stomp_enabled"] and "ACTIVE" or "MUTED!"), V_GRAYMAP|(_G["stomp_enabled"] and V_GREENMAP or V_REDMAP), "thin-center")
                    elseif i == 3 then
                        local sM = _G["boost_sound_mode"] or 1
						local col = (sC and sC[sM]) and sC[sM] or V_YELLOWMAP
						v.drawString(160, lY, "BOOST SOUNDS: "..(sL[sM] or "UNKNOWN"), V_GRAYMAP|col, "thin-center")
						elseif i == 4 then local bM = _G["boost_button_mode"] or 0 if bM > 3 then bM = 0 end
						v.drawString(160, lY, "BOOST BUTTON: "..bN[bM+1], V_GRAYMAP|bC[bM+1], "thin-center")
						else v.drawString(160, lY, MENU_OPTIONS[i], V_GRAYMAP, "thin-center") end
end
end
end
v.drawFill(cX, cY+bH-12, bW, 12, 159|V_SNAPTOTOP) v.drawString(160, cY+bH-10, "W/S: NAVIGATE  *  SPACE: EQUIP", V_WHITERESMAP, "thin-center")
end
end)


addHook("PlayerThink", function(player)
    if not (player and player.valid and player.mo and player.mo.valid) then return end
    local mo = player.mo
    if player.menu_open == true then
        if not (player.menu_indicator and player.menu_indicator.valid) then
            player.menu_indicator = P_SpawnMobj(mo.x, mo.y, mo.z + mo.height + 16*FRACUNIT, MT_THOK)
            if player.menu_indicator and player.menu_indicator.valid then
                player.menu_indicator.target = mo
                player.menu_indicator.flags = $ | MF_NOCLIP | MF_NOCLIPHEIGHT
                player.menu_indicator.sprite = SPR_MTEX
            end
        end
        if player.menu_indicator and player.menu_indicator.valid then
            local bobFactor = sin(FixedAngle(leveltime * FRACUNIT * 6))
            local zOffset = mo.z + mo.height + FixedMul(20 * FRACUNIT + FixedMul(6 * FRACUNIT, bobFactor), mo.scale)
            P_MoveOrigin(player.menu_indicator, mo.x, mo.y, zOffset)
            player.menu_indicator.scale = mo.scale
            if player.chosenbvfxcolor ~= nil then
                player.menu_indicator.color = player.chosenbvfxcolor
            else
                player.menu_indicator.color = mo.color
            end
        end
    else
        if player.menu_indicator and player.menu_indicator.valid then
            P_RemoveMobj(player.menu_indicator)
            player.menu_indicator = nil
        end
    end
end)



addHook("PlayerThink", function(player)
    if (player.mo.vfx == nil)
	    player.mo.vfx = 0
	end
end)


addHook("PlayerThink", function(player)
	if player.mo and player.mo.valid
       if player.bvfxing == true
	   player.mo.vfx = $1 + 1 
end
end
end)

addHook("PlayerThink", function(player)
    if player.mo.vfx == 15
	player.mo.vfx = 2
	end
end)

addHook("PlayerThink", function(player)
    if player.bvfxing == false
	player.mo.vfx = 0
end
end)

addHook("PlayerThink", function(player)
if player.mo.vfx == 1
if not P_IsObjectOnGround(player.mo)
and not (player.weapondelay & 50)
P_SetObjectMomZ(player.mo, 5*FRACUNIT,true)
player.weapondelay = 50
end
end
end)

addHook("PlayerThink", function(player)
    if player.mo.vfx == 4
	local dashpart = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z + player.mo.height/2, MT_BOOSTVFX) 
	dashpart.angle = player.mo.angle + ANGLE_90
	dashpart.tics = 10
	dashpart. scalespeed= FRACUNIT / 3
	dashpart.destscale = FRACUNIT*2
	dashpart.colorized = true
	dashpart.blendmode = AST_ADD
	dashpart.momx = player.mo.momx/2
	dashpart.momy = player.mo.momy/2
	dashpart.momz = player.mo.momz/3
	dashpart.color = player.chosenbvfxcolor or player.mo.color
	end
end)

addHook("PlayerThink", function(player)
    if not (player and player.valid and player.mo and player.mo.valid) then return end
    if player.mo.vfx == 1 then
        P_StartQuake(10*FRACUNIT, TICRATE / 2)
		local adventureri = P_SpawnMobjFromMobj(player.mo, player.mo.momx*3/6, player.mo.momy*3/6 , player.mo.momz, MT_THOK)         
        adventureri.state = S_STRA1
		adventureri.destscale = FRACUNIT*2
		adventureri. scalespeed= FRACUNIT / 3
        adventureri.blendmode = AST_ADD
		adventureri.frame = $|FF_PAPERSPRITE
        adventureri.angle = player.drawangle + 180
        adventureri.color = player.chosenbvfxcolor or player.mo.color
        local soundMode = _G["boost_sound_mode"] or 1
        if soundMode == 1 then
            S_StartSound(player.mo, sfx_gener)
        elseif soundMode == 2 then
            S_StartSound(player.mo, sfx_rusher)
        elseif soundMode == 3 then
            S_StartSound(player.mo, sfx_fronti)
		elseif soundMode == 4 then
            S_StartSound(player.mo, sfx_fard)
        end
    end	
end)

	
addHook("PostThinkFrame", function()
    for player in players.iterate do
	if not (player and player.valid) then continue end
	if player.bvfxing == true then
	local vfxColor = player.chosenbvfxcolor or player.mo.color
	local dist = max(player.speed / (4*FRACUNIT), 1) 
	local labubu = P_SpawnMobjFromMobj(player.mo, player.mo.momx/dist, player.mo.momy/dist, player.mo.momz/dist, MT_THOK)
	labubu.sprite = SPR_BRHA
	labubu.frame = (leveltime/1)%4
	labubu.frame = $|FF_FULLBRIGHT
	labubu.tics = 1
	labubu.rollangle = player.mo.rollangle + FixedMul(player.mo.momz, sin(player.mo.angle - (player.mo.momx + player.mo.momy)))
	labubu.angle = player.drawangle
	labubu.scale = player.mo.scale
	labubu.blendmode = AST_ADD
	labubu.destscale = FRACUNIT*3/2
	labubu.scale = FRACUNIT*11/12
    labubu.color = vfxColor
	labubu.colorized = true
end
end
end)


local spawnticky = 4
addHook("PlayerThink", function(player)
    if not (player and player.mo and player.mo.valid) then return end
    if player.bvfxing == true 
    and P_IsObjectOnGround(player.mo) 
    and leveltime % spawnticky == 0 then
        local spawnZ = player.mo.z + (4 * player.mo.scale)
        local ring = P_SpawnMobj(player.mo.x, player.mo.y, spawnZ, MT_THOK)
        if ring and ring.valid then
            ring.colorized = true
            ring.blendmode = AST_ADD
            ring.scale = player.mo.scale
            ring.destscale = FixedMul(player.mo.scale, 3 * FRACUNIT)
            ring.scalespeed = FRACUNIT / 6
            ring.frame = $|FF_FULLBRIGHT|FF_TRANS20
            ring.tics = 6
			ring.state = S_GRNE1
			ring.color = player.chosenbvfxcolor or player.mo.color
            end
    end
end)

