ARC9.PenTable = {
    [MAT_ANTLION]     = 1,
    [MAT_BLOODYFLESH] = 1,
    [MAT_CONCRETE]    = 1,
    [MAT_DIRT]        = 1,
    [MAT_EGGSHELL]    = 1,
    [MAT_FLESH]       = 1,
    [MAT_GRATE]       = 1,
    [MAT_ALIENFLESH]  = 1,
    [MAT_CLIP]        = 1,
    [MAT_SNOW]        = 1,
    [MAT_PLASTIC]     = 1,
    [MAT_METAL]       = 2,
    [MAT_SAND]        = 1,
    [MAT_FOLIAGE]     = 1,
    [MAT_COMPUTER]    = 1,
    [MAT_SLOSH]       = 1,
    [MAT_TILE]        = 1,
    [MAT_GRASS]       = 1,
    [MAT_VENT]        = 1,
    [MAT_WOOD]        = 0.5,
    [MAT_DEFAULT]     = 1,
    [MAT_GLASS]       = 0.25,
    [MAT_WARPSHIELD]  = 1,
}

ARC9.CosmeticCategories = {
    ["charm"] = true,
    ["camo"] = true,
    ["stickers"] = true,
}
ARC9.ShellSoundsTable = {
    ")arc9/casings/casing_556_1.wav",
    ")arc9/casings/casing_556_2.wav",
    ")arc9/casings/casing_556_3.wav",
    ")arc9/casings/casing_556_4.wav",
    ")arc9/casings/casing_556_1.wav",
    ")arc9/casings/casing_556_2.wav",
    ")arc9/casings/casing_556_3.wav",
    ")arc9/casings/casing_556_4.wav",
}

ARC9.Shell308SoundsTable = {
    ")arc9/casings/casing_308_1.wav",
    ")arc9/casings/casing_308_2.wav",
    ")arc9/casings/casing_308_3.wav",
    ")arc9/casings/casing_308_4.wav",
    ")arc9/casings/casing_308_1.wav",
    ")arc9/casings/casing_308_2.wav",
    ")arc9/casings/casing_308_3.wav",
    ")arc9/casings/casing_308_4.wav",
}

ARC9.PistolShellSoundsTable = {
    ")arc9/casings/casing_9mm_1.wav",
    ")arc9/casings/casing_9mm_2.wav",
    ")arc9/casings/casing_9mm_3.wav",
    ")arc9/casings/casing_9mm_4.wav",
    ")arc9/casings/casing_9mm_1.wav",
    ")arc9/casings/casing_9mm_2.wav",
    ")arc9/casings/casing_9mm_3.wav",
    ")arc9/casings/casing_9mm_4.wav"
}

ARC9.TinyShellSoundsTable = {
    ")arc9/casings/casing_22_1.wav",
    ")arc9/casings/casing_22_2.wav",
    ")arc9/casings/casing_22_3.wav",
    ")arc9/casings/casing_22_4.wav",
    ")arc9/casings/casing_22_1.wav",
    ")arc9/casings/casing_22_2.wav",
    ")arc9/casings/casing_22_3.wav",
    ")arc9/casings/casing_22_4.wav"
}

ARC9.ShotgunShellSoundsTable = {
    ")arc9/casings/casing_12ga_1.wav",
    ")arc9/casings/casing_12ga_2.wav",
    ")arc9/casings/casing_12ga_3.wav",
    ")arc9/casings/casing_12ga_4.wav",
    ")arc9/casings/casing_12ga_1.wav",
    ")arc9/casings/casing_12ga_2.wav",
    ")arc9/casings/casing_12ga_3.wav",
    ")arc9/casings/casing_12ga_4.wav"
}

ARC9.RicochetSounds = {
    ")arc9/fx/ricochet_01.wav",
	")arc9/fx/ricochet_02.wav",
	")arc9/fx/ricochet_03.wav",
	")arc9/fx/ricochet_04.wav",
	")arc9/fx/ricochet_05.wav",
	")arc9/fx/ricochet_06.wav",
	")arc9/fx/ricochet_07.wav",
	")arc9/fx/ricochet_08.wav",
	")arc9/fx/ricochet_09.wav",
	")arc9/fx/ricochet_10.wav",
	")arc9/fx/ricochet_11.wav",
	")arc9/fx/ricochet_12.wav",
	")arc9/fx/ricochet_13.wav",
	")arc9/fx/ricochet_14.wav",
	")arc9/fx/ricochet_15.wav"
 }

ARC9.PresetPath = "arc9_presets/"
ARC9.PresetIconFormat = "arc9.png"

ARC9.ATTsHaveBeenReloaded = false
ARC9.OverDraw = false

ARC9.LHIKHandBones = {
    "ValveBiped.Bip01_L_Wrist",
    "ValveBiped.Bip01_L_Ulna",
    "ValveBiped.Bip01_L_Hand",
    "ValveBiped.Bip01_L_Finger4",
    "ValveBiped.Bip01_L_Finger41",
    "ValveBiped.Bip01_L_Finger42",
    "ValveBiped.Bip01_L_Finger3",
    "ValveBiped.Bip01_L_Finger31",
    "ValveBiped.Bip01_L_Finger32",
    "ValveBiped.Bip01_L_Finger2",
    "ValveBiped.Bip01_L_Finger21",
    "ValveBiped.Bip01_L_Finger22",
    "ValveBiped.Bip01_L_Finger1",
    "ValveBiped.Bip01_L_Finger11",
    "ValveBiped.Bip01_L_Finger12",
    "ValveBiped.Bip01_L_Finger0",
    "ValveBiped.Bip01_L_Finger01",
    "ValveBiped.Bip01_L_Finger02"
}

ARC9.RHIKHandBones = {
    "ValveBiped.Bip01_R_Wrist",
    "ValveBiped.Bip01_R_Ulna",
    "ValveBiped.Bip01_R_Hand",
    "ValveBiped.Bip01_R_Finger4",
    "ValveBiped.Bip01_R_Finger41",
    "ValveBiped.Bip01_R_Finger42",
    "ValveBiped.Bip01_R_Finger3",
    "ValveBiped.Bip01_R_Finger31",
    "ValveBiped.Bip01_R_Finger32",
    "ValveBiped.Bip01_R_Finger2",
    "ValveBiped.Bip01_R_Finger21",
    "ValveBiped.Bip01_R_Finger22",
    "ValveBiped.Bip01_R_Finger1",
    "ValveBiped.Bip01_R_Finger11",
    "ValveBiped.Bip01_R_Finger12",
    "ValveBiped.Bip01_R_Finger0",
    "ValveBiped.Bip01_R_Finger01",
    "ValveBiped.Bip01_R_Finger02"
}

ARC9.TPIKBones = {
    //"ValveBiped.Bip01_L_Wrist",
    //"ValveBiped.Bip01_L_Ulna", --//better to not use these!
    "ValveBiped.Bip01_L_Hand",
    "ValveBiped.Bip01_L_Finger4",
    "ValveBiped.Bip01_L_Finger41",
    "ValveBiped.Bip01_L_Finger42",
    "ValveBiped.Bip01_L_Finger3",
    "ValveBiped.Bip01_L_Finger31",
    "ValveBiped.Bip01_L_Finger32",
    "ValveBiped.Bip01_L_Finger2",
    "ValveBiped.Bip01_L_Finger21",
    "ValveBiped.Bip01_L_Finger22",
    "ValveBiped.Bip01_L_Finger1",
    "ValveBiped.Bip01_L_Finger11",
    "ValveBiped.Bip01_L_Finger12",
    "ValveBiped.Bip01_L_Finger0",
    "ValveBiped.Bip01_L_Finger01",
    "ValveBiped.Bip01_L_Finger02",
    //"ValveBiped.Bip01_R_Wrist",
    //"ValveBiped.Bip01_R_Ulna", --//better to not use these!
    "ValveBiped.Bip01_R_Hand",
    "ValveBiped.Bip01_R_Finger4",
    "ValveBiped.Bip01_R_Finger41",
    "ValveBiped.Bip01_R_Finger42",
    "ValveBiped.Bip01_R_Finger3",
    "ValveBiped.Bip01_R_Finger31",
    "ValveBiped.Bip01_R_Finger32",
    "ValveBiped.Bip01_R_Finger2",
    "ValveBiped.Bip01_R_Finger21",
    "ValveBiped.Bip01_R_Finger22",
    "ValveBiped.Bip01_R_Finger1",
    "ValveBiped.Bip01_R_Finger11",
    "ValveBiped.Bip01_R_Finger12",
    "ValveBiped.Bip01_R_Finger0",
    "ValveBiped.Bip01_R_Finger01",
    "ValveBiped.Bip01_R_Finger02"
}

ARC9.LHIKBones = {
    "ValveBiped.Bip01_L_UpperArm",
    "ValveBiped.Bip01_L_Forearm",
    "ValveBiped.Bip01_L_Wrist",
    "ValveBiped.Bip01_L_Ulna",
    "ValveBiped.Bip01_L_Hand",
    "ValveBiped.Bip01_L_Finger4",
    "ValveBiped.Bip01_L_Finger41",
    "ValveBiped.Bip01_L_Finger42",
    "ValveBiped.Bip01_L_Finger3",
    "ValveBiped.Bip01_L_Finger31",
    "ValveBiped.Bip01_L_Finger32",
    "ValveBiped.Bip01_L_Finger2",
    "ValveBiped.Bip01_L_Finger21",
    "ValveBiped.Bip01_L_Finger22",
    "ValveBiped.Bip01_L_Finger1",
    "ValveBiped.Bip01_L_Finger11",
    "ValveBiped.Bip01_L_Finger12",
    "ValveBiped.Bip01_L_Finger0",
    "ValveBiped.Bip01_L_Finger01",
    "ValveBiped.Bip01_L_Finger02"
}

ARC9.RHIKBones = {
    "ValveBiped.Bip01_R_UpperArm",
    "ValveBiped.Bip01_R_Forearm",
    "ValveBiped.Bip01_R_Wrist",
    "ValveBiped.Bip01_R_Ulna",
    "ValveBiped.Bip01_R_Hand",
    "ValveBiped.Bip01_R_Finger4",
    "ValveBiped.Bip01_R_Finger41",
    "ValveBiped.Bip01_R_Finger42",
    "ValveBiped.Bip01_R_Finger3",
    "ValveBiped.Bip01_R_Finger31",
    "ValveBiped.Bip01_R_Finger32",
    "ValveBiped.Bip01_R_Finger2",
    "ValveBiped.Bip01_R_Finger21",
    "ValveBiped.Bip01_R_Finger22",
    "ValveBiped.Bip01_R_Finger1",
    "ValveBiped.Bip01_R_Finger11",
    "ValveBiped.Bip01_R_Finger12",
    "ValveBiped.Bip01_R_Finger0",
    "ValveBiped.Bip01_R_Finger01",
    "ValveBiped.Bip01_R_Finger02"
}

ARC9.CancelMultipliers = {
    [1] = {
        [HITGROUP_HEAD]     = 2,
        [HITGROUP_CHEST]    = 1,
        [HITGROUP_STOMACH]  = 1,
        [HITGROUP_LEFTARM]  = 0.25,
        [HITGROUP_RIGHTARM] = 0.25,
        [HITGROUP_LEFTLEG]  = 0.25,
        [HITGROUP_RIGHTLEG] = 0.25,
        [HITGROUP_GEAR]     = 1,
        [HITGROUP_GENERIC]  = 1,
    },
    ["terrortown"] = {
        [HITGROUP_HEAD]     = 1, -- TTT headshot damage is per weapon, there is no global multiplier.
        [HITGROUP_CHEST]    = 1,
        [HITGROUP_STOMACH]  = 1,
        [HITGROUP_LEFTARM]  = 0.55,
        [HITGROUP_RIGHTARM] = 0.55,
        [HITGROUP_LEFTLEG]  = 0.55,
        [HITGROUP_RIGHTLEG] = 0.55,
        [HITGROUP_GEAR]     = 1,
        [HITGROUP_GENERIC]  = 1,
    },
}

-- 0.0254 is only applicable to model scale, since actual map scaling is based on 1 foot = 16 units.
-- Not changing this in case some other addon is using the constant as stat
ARC9.HUToM = 0.0254

-- 10 / 360 / 60 is incorrect, how'd you even get it?
-- MOA is 1/60 of a degree, 1 radian = 57.2958 degrees
-- Not changing this in case some other addon is using the constant as stat
ARC9.MOAToAcc = 10 / 360 / 60
ARC9.TrueMOAToAcc = 1 / 60 / 57.2958

ARC9.Version = "1.0"

ARC9.NADETHROWTYPE_NORMAL = 0
ARC9.NADETHROWTYPE_TOSS = 1
ARC9.NADETHROWTYPE_EXPLODEINHANDS = 2

ARC9.CHAN_AUTO = 0
ARC9.CHAN_WEAPON = 1
ARC9.CHAN_DISTANT = 136
ARC9.CHAN_LAYER = 137
ARC9.CHAN_INDOOR = 139
ARC9.CHAN_INDOORDISTANT = 144
ARC9.CHAN_INDOORLAYER = 6
ARC9.CHAN_FIDDLE = 6
ARC9.CHAN_TRIGGER = 141
ARC9.CHAN_MELEE = 142
ARC9.CHAN_BREATH = 143

--USE THESE ENUMS IN A SWEP'S LUA FOR HL2 WEAPON REPLACEMENTS
-- I.E.:    "SWEP.ARC9WeaponCategory = 1"     WILL REPLACE PISTOLS AND MAGNUM REVOLVERS

ARC9.WEAPON_PISTOL = 1
ARC9.WEAPON_SHOTGUN = 2
ARC9.WEAPON_SMG = 3
ARC9.WEAPON_AR = 4
ARC9.WEAPON_SNIPER = 5
ARC9.WEAPON_RPG = 6
ARC9.WEAPON_MELEE = 7
ARC9.WEAPON_FRAG = 8
ARC9.WEAPON_SPECIAL = 9
ARC9.WEAPON_MISC = 0

ARC9.IMPULSE_TOGGLEATTS = 40

ARC9.IN_CUSTOMIZE = IN_WEAPON1
ARC9.IN_MELEE = IN_BULLRUSH
ARC9.IN_UBGL = IN_WEAPON2
ARC9.IN_INSPECT = IN_CANCEL
ARC9.IN_SWITCHSIGHTS = IN_RUN
-- Official enums end at 2^24
-- IN flags is 32 bit!
-- We still have 7 free values!!!
-- Use them up!!!!!

-- Used in dmginfo:SetDamageCustom to denote pending AP damage
ARC9.DMG_CUST_AP = 4096

ARC9.HL2Replacements = {
    ["weapon_pistol"] = {ARC9.WEAPON_PISTOL},
    ["weapon_357"] = {ARC9.WEAPON_PISTOL, ARC9.WEAPON_SNIPER},
    ["weapon_smg1"] = {ARC9.WEAPON_SMG},
    ["weapon_ar2"] = {ARC9.WEAPON_AR},
    ["weapon_shotgun"] = {ARC9.WEAPON_SHOTGUN},
    ["weapon_crossbow"] = {ARC9.WEAPON_SNIPER},
    ["weapon_crowbar"] = {ARC9.WEAPON_MELEE},
    ["weapon_rpg"] = {ARC9.WEAPON_RPG},
    ["weapon_frag"] = {ARC9.WEAPON_FRAG},
    ["weapon_alyxgun"] = {ARC9.WEAPON_SPECIAL},
    ["weapon_annabelle"] = {ARC9.WEAPON_SPECIAL, ARC9.WEAPON_SHOTGUN}
}

do
    local cvarDeveloper = GetConVar("developer")
    local cvarGetInt = FindMetaTable("ConVar").GetInt

    ARC9.DevCheckCached = false 

    local engineTickCount = engine.TickCount
    local ARC9DevCheckTick, ARC9DevCheckCached, ARC9DevCheckLast = 0, false, 0

    if CLIENT and not game.SinglePlayer() then
        local localPlayer

        local function initLocalPlayer()
            localPlayer = LocalPlayer()
        end

        hook.Add("InitPostEntity", "ARC9_CacheLocalPlayer", initLocalPlayer)

        -- for autorefresh
        if IsValid(LocalPlayer()) then
            initLocalPlayer()
        end

        local PlayerIsSuperAdmin = FindMetaTable("Player").IsSuperAdmin

        function ARC9.Dev(level)
            local now = engineTickCount()
    
            if ARC9DevCheckTick == now then return ARC9DevCheckCached end
    
            if (ARC9DevCheckLast or 0) > now then return ARC9DevCheckCached end
            ARC9DevCheckLast = now + 64 -- 64 ticks before next check
            
            local output = IsValid(localPlayer) and PlayerIsSuperAdmin(localPlayer) and cvarGetInt(cvarDeveloper) >= level

            ARC9DevCheckCached = output
            ARC9DevCheckTick = now
    
            return output
        end
    else
        function ARC9.Dev(level)
            local now = engineTickCount()
    
            if ARC9DevCheckTick == now then return ARC9DevCheckCached end
    
            if (ARC9DevCheckLast or 0) > now then return ARC9DevCheckCached end
            ARC9DevCheckLast = now + 64 -- 64 ticks before next check
            
            local output = cvarGetInt(cvarDeveloper) >= level
            
            ARC9DevCheckCached = output
            ARC9DevCheckTick = now
    
            return output
        end
    end
end

-- A cheaper, dirtier branchless implementation
function math.Approach(cur, target, inc)
    inc = math.abs(inc)

    -- if (cur < target) then
    --     return math.min(cur + inc, target)
    -- elseif (cur > target) then
    --     return math.max(cur - inc, target)
    -- end

    -- return target
    return ((cur < target) and math.min(cur + inc, target)) or ((cur > target) and math.max(cur - inc, target)) or target
end

function ARC9.IsPointOutOfBounds(vec)
    local v1, v2, v3 = vec:Unpack()

    if math.abs(v1) > 16384 or math.abs(v2) > 16384 or math.abs(v3) > 16384 then
        return true
    end
end

if CLIENT then
    function ARC9.FormatViewModelAttachment(vOrigin, bFrom) -- from wiki
        local view = render.GetViewSetup()

        local vEyePos = view.origin
        local aEyesRot = view.angles
        local vOffset = vOrigin - vEyePos
        local vForward = aEyesRot:Forward()

        local nViewX = math.tan( view.fovviewmodel_unscaled * math.pi / 360)

        if (nViewX == 0) then
            vForward:Mul(vForward:Dot(vOffset))
            vEyePos:Add(vForward)

            return vEyePos
        end

        local nWorldX = math.tan( view.fov_unscaled * math.pi / 360)

        if (nWorldX == 0) then
            vForward:Mul(vForward:Dot(vOffset))
            vEyePos:Add(vForward)

            return vEyePos
        end

        local vRight = aEyesRot:Right()
        local vUp = aEyesRot:Up()

        if (bFrom) then
            local nFactor = nWorldX / nViewX
            vRight:Mul(vRight:Dot(vOffset) * nFactor)
            vUp:Mul(vUp:Dot(vOffset) * nFactor)
        else
            local nFactor = nViewX / nWorldX
            vRight:Mul(vRight:Dot(vOffset) * nFactor)
            vUp:Mul(vUp:Dot(vOffset) * nFactor)
        end

        vForward:Mul(vForward:Dot(vOffset))

        vEyePos:Add(vRight)
        vEyePos:Add(vUp)
        vEyePos:Add(vForward)

        return vEyePos
    end
end


hook.Add("InitPostEntity", "ARC9_phystweak", function() -- stolen from tacrp
    if GetConVar("arc9_phystweak"):GetBool() then
        if !physenv or !physenv.GetPerformanceSettings then print("[ARC9] How the hell you don't have physenv???? wtf wrong with your game") return end
        local v = physenv.GetPerformanceSettings().MaxVelocity or 10000
        if v < 10000 then
            physenv.SetPerformanceSettings({MaxVelocity = 10000})
            print("[ARC9] Increasing MaxVelocity for projectiles to behave as intended! (" .. v .. "-> 10000)")
            print("[ARC9] Disable this behavior with 'arc9_phystweak 0'.")
        end
    end
end)