local FRACUNIT = FRACUNIT
local cd_mode = CV_FindVar("cd_mode")
local k_boostpower = k_boostpower
local k_accelboost = k_accelboost

local otrx_mul = CV_RegisterVar({
    name = "otrx_mul",
    defaultvalue = "1.0", -- I recommend you reduce this if you have BLib set up with a lot of non-vanilla boosts.
    flags = CV_NETVAR|CV_FLOAT|CV_SHOWMODIF,
    possiblevalue = CV_Unsigned
})

local function OpenTricks_PrepModifiers(player, speed, accel, multspeed, multaccel)
  local multiplier = otrx_mul.value
  local raw_speed = speed
  local raw_accel = accel
  
  if multspeed 
    raw_speed = FixedMul($ - FRACUNIT, multiplier) + FRACUNIT -- so augment doesn't slow us with reduced host multi
  else
    raw_speed = FixedMul($, multiplier)
  end
  
  if multaccel
    raw_accel = FixedMul($ - FRACUNIT, multiplier) + FRACUNIT
  else
    raw_accel = FixedMul($, multiplier)
  end
  
  if chaosdrives and cd_mode and cd_mode.value >= 2 and not chaosdrives.blib
    local sp = player.kartspeed -- raw speed before Chaos Drives
    local ac = 9 - player.kartspeed -- likewise
  
    local spcd = sp -- modified speed after Chaos Drives
    local accd = ac -- likewise
  
    cd_speed = min($ + player.cd_run, 10) - player.cd_safeHandicap
    cd_accel = min($ + player.cd_swim, 10) - player.cd_safeHandicap
    
    local trueaccel = 32 + (4 * ac)
    local desiredaccel = 32 + (4 *cd_accel)
    local acceldiff = FixedDiv(desiredaccel, trueaccel)
    local g_cc = 56320 + (12288 * gamespeed)
    local shiftby = 14
    local truespeed = FixedMul((150 + sp*3)<<shiftby, g_cc)
    local desiredspeed = FixedMul((150 + cd_speed*3)<<shiftby, g_cc)
    local speeddiff = FixedDiv(desiredspeed, truespeed)
    
    raw_speed = FixedMul($, speeddiff) + (speeddiff-FRACUNIT) -- even though I literally copy-pasted it from my own code
    raw_accel = FixedMul($, acceldiff) + (acceldiff-FRACUNIT) -- something feels deeply wrong about this math
  end
  
  if multspeed 
    if multaccel --both multipliers
      return 0, 0, FixedMul(raw_speed, player.kartstuff[k_boostpower]), FixedMul(raw_accel, player.kartstuff[k_accelboost])
    else -- speed multiplier
      return 0, raw_accel, FixedMul(raw_speed, player.kartstuff[k_boostpower]), FRACUNIT
    end
  elseif multaccel -- accel multiplier
    return 0, 0, FRACUNIT, FixedMul(raw_accel, player.kartstuff[k_accelboost])
  else -- both additive
    return raw_speed, raw_accel, FRACUNIT, FRACUNIT
  end
end

local function OpenTricks_DoPassiveSpeed(player, amount, multiply, blib_name, stack, stackvfx, chain)
  local spa, aca, spm, acm = OpenTricks_PrepModifiers(player, amount, 0, multiply, false)
  if BLib
    BLib.SetBoost(player, blib_name, spa, nil, spm - FRACUNIT, stack, stackvfx, chain)
  else
    player.kartstuff[k_boostpower] = FixedMul($, spm) + spa
  end
end

local function OpenTricks_DoPassiveAccel(player, amount, multiply, blib_name, stack, stackvfx, chain)
  local spa, aca, spm, acm = OpenTricks_PrepModifiers(player, 0, amount, false, multiply)
  if BLib
    BLib.SetBoost(player, blib_name, nil, aca, nil, stack, stackvfx, chain) -- no accel multiplication
  else
    player.kartstuff[k_accelboost] = FixedMul($, acm) + aca
  end
end

local function OpenTricks_DoPassiveBoost(player, speed_amount, speed_multiply, accel_amount, accel_multiply, blib_name, stack, stackvfx, chain)
  local spa, aca, spm, acm = OpenTricks_PrepModifiers(player, speed_amount, accel_amount, speed_multiply, accel_multiply)
  if BLib
    BLib.SetBoost(player, blib_name, spa, aca, spm - FRACUNIT, stack, stackvfx, chain) -- no accel multiplication
  else
    player.kartstuff[k_boostpower] = FixedMul($, spm) + spa
	player.kartstuff[k_accelboost] = FixedMul($, acm) + aca
  end
end

local function OpenTricks_StopBoost(player, blib_name)
  if BLib -- non-BLib servers don't really have to do anything yet.
    BLib.SetBoost(player, blib_name)
  end
end

local function OpenTricks_AutoMiniBoost(player, table)
  if table.mini > 0
    OpenTricks_DoPassiveBoost(player, (FRACUNIT / 4), false, (FRACUNIT * 3), false, "OpenTricks_GenericBoost", true, true, false)
    table.mini = max(0, $ - 1)
  else
    OpenTricks_StopBoost(player, "OpenTricks_GenericBoost")
  end
end

rawset(_G, "OpenTricks_DoPassiveSpeed", OpenTricks_DoPassiveSpeed)
rawset(_G, "OpenTricks_DoPassiveAccel", OpenTricks_DoPassiveAccel)
rawset(_G, "OpenTricks_DoPassiveBoost", OpenTricks_DoPassiveBoost)
rawset(_G, "OpenTricks_StopBoost", OpenTricks_StopBoost)
rawset(_G, "OpenTricks_AutoMiniBoost", OpenTricks_AutoMiniBoost)