--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| 	Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]

if CLIENT then return end

function ArcCW.DoorBust(ent, vel)
    local cvar = ArcCW.ConVars["doorbust"]:GetInt()
    local t = ArcCW.ConVars["doorbust_time"]:GetFloat()
    if cvar == 0 or ent.ArcCW_DoorBusted then return end
    ent.ArcCW_DoorBusted = true

    local oldSpeed = ent:GetInternalVariable("m_flSpeed")
    ent:Fire("SetSpeed", tostring(oldSpeed * 5), 0)
    ent:Fire("Open", "", 0)
    ent:Fire("SetSpeed", oldSpeed, 0.3)

    if ent:GetPhysicsObject():IsValid() and cvar == 1 then

        -- Don't remove the door, that's a silly thing to do
        ent.ArcCW_DoorOldPos = ent:GetPos()
        ent:SetNoDraw(true)
        ent:SetNotSolid(true)

        -- Make a busted door prop and fling it
        local prop = ents.Create("prop_physics")
        prop:SetModel(ent:GetModel())
        prop:SetPos(ent:GetPos())
        prop:SetAngles(ent:GetAngles())
        prop:SetSkin(ent:GetSkin())
        prop:Spawn()
        prop:GetPhysicsObject():SetVelocity(vel)

        ent:SetPos(ent:GetPos() - Vector(0, 0, 10000))

        -- Make it not collide with players after a bit cause that's annoying
        timer.Create("ArcCW_DoorBust_" .. prop:EntIndex(), 2, 1, function()
            if IsValid(prop) then
                prop:SetCollisionGroup(COLLISION_GROUP_WEAPON)
            end
        end)

        -- Reset it after a while
        SafeRemoveEntityDelayed(prop, t)
        timer.Create("ArcCW_DoorBust_" .. ent:EntIndex(), t, 1, function()
            if IsValid(ent) then
                ent:SetNoDraw(false)
                ent:SetNotSolid(false)
                ent.ArcCW_DoorBusted = false
                ent:SetPos(ent.ArcCW_DoorOldPos)
                ent.ArcCW_DoorOldPos = nil
            end
        end)
    else
        timer.Create("ArcCW_DoorBust_" .. ent:EntIndex(), 0.5, 1, function()
            if IsValid(ent) then
                ent.ArcCW_DoorBusted = false
            end
        end)
    end
end

function ArcCW.TryBustDoor(ent, dmginfo)
    if ArcCW.ConVars["doorbust"]:GetInt() == 0 or !IsValid(ent) or !string.find(ent:GetClass(), "door") then return end
    local wep = IsValid(dmginfo:GetAttacker()) and ((dmginfo:GetInflictor():IsWeapon() and dmginfo:GetInflictor()) or dmginfo:GetAttacker():GetActiveWeapon())
    if !wep or !wep:IsWeapon() or !wep.ArcCW or !dmginfo:IsDamageType(DMG_BUCKSHOT) then return end
    if ent:GetNoDraw() or ent.ArcCW_NoBust or ent.ArcCW_DoorBusted then return end

    --- TTT may choose for some doors to not be openable by a crowbar, let's respect that
    if GAMEMODE.crowbar_unlocks and GAMEMODE.crowbar_unlocks[ent] != true then return end

    -- Magic number: 119.506 is the size of door01_left
    -- The bigger the door is, the harder it is to bust
    local threshold = ArcCW.ConVars["doorbust_threshold"]:GetInt() * math.pow((ent:OBBMaxs() - ent:OBBMins()):Length() / 119.506, 2)

    -- Because shotgun damage is done per pellet, we must count them together
    if ent.ArcCW_BustCurTime and (ent.ArcCW_BustCurTime + 0.1 < CurTime()) then
        ent.ArcCW_BustCurTime = nil
        ent.ArcCW_BustDamage = 0
    end
    if dmginfo:GetDamage() < (threshold - (ent.ArcCW_BustDamage or 0)) then
        ent.ArcCW_BustCurTime = ent.ArcCW_BustCurTime or CurTime()
        ent.ArcCW_BustDamage = (ent.ArcCW_BustDamage or 0) + dmginfo:GetDamage()
        return
    else
        ent.ArcCW_BustCurTime = nil
        ent.ArcCW_BustDamage = nil
    end
    ArcCW.DoorBust(ent, dmginfo:GetDamageForce() * 0.5)
    -- Double doors are usually linked to the same areaportal. We must destroy the second half of the double door no matter what
    for _, otherDoor in pairs(ents.FindInSphere(ent:GetPos(), 64)) do
        if ent != otherDoor and otherDoor:GetClass() == ent:GetClass() and !otherDoor:GetNoDraw() then
            ArcCW.DoorBust(otherDoor, dmginfo:GetDamageForce() * 0.5)
            break
        end
    end
end

hook.Add("PlayerUse", "ArcCW_DoorBust", function(ply, ent)
    if ent.ArcCW_DoorBusted then return false end
end)

-- This hook is not called on brush doors. Let's call this, uhh, intended behavior.
-- hook.Add("EntityTakeDamage", "ArcCW_DoorBust", ArcCW.TryBustDoor)