include("shared.lua")

AddCSLuaFile("shared.lua")

function ENT:Initialize()
    self:SetModel("models/exfil/palfa.mdl")
    self:SetSolid(SOLID_VPHYSICS)
    self:PhysicsInit(SOLID_VPHYSICS)
    self:SetBodygroup(1, 1)
    self:SetBodygroup(2, 1)
    self.DeltaTime = 0
    self.PickingTime = 0
    self.MaxSpeed = 10000
    self.CurrentSpeed = 10000
    self.Mayday = false
    self.Heli = true
    
    local phys = self:GetPhysicsObject()
    phys:Wake()
    phys:EnableCollisions(false)

    if !istable(self.Points) or #self.Points < 5 then
        self:Remove()
        return
    end

    ---CREW MODELS---

    if self.Heli then
        local crew = ents.Create("base_anim")
        crew:SetModel("models/exfil/mw22_crew_pm.mdl")
        crew:SetPos(self:GetPos()+self:GetForward()*234+self:GetRight()*28+self:GetUp()*-172)
        crew:SetAngles(self:GetAngles())
        crew:Spawn()
        crew:SetParent(self)
        crew:ResetSequence("sit")
        crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Upperarm"), Angle(20, -60, 0), true)
        crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Forearm"), Angle(-45, 30, 0), true)
        crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Hand"), Angle(-140, 90, -30), true)
        crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Calf"), Angle(0, -55, 0), true)
        crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_L_Calf"), Angle(0, -55, 0), true)
        crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Foot"), Angle(0, 20, 0), true)
        crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_L_Foot"), Angle(0, 20, 0), true)
        self:DeleteOnRemove(crew)

        local crew = ents.Create("base_anim")
        crew:SetModel("models/exfil/mw22_crew_pm.mdl")
        crew:SetPos(self:GetPos()+self:GetForward()*234-self:GetRight()*28+self:GetUp()*-172)
        crew:SetAngles(self:GetAngles())
        crew:Spawn()
        crew:SetParent(self)
        crew:ResetSequence("sit")
        crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Upperarm"), Angle(20, -60, 0), true)
        crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Forearm"), Angle(-45, 30, 0), true)
        crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Hand"), Angle(-140, 90, -30), true)
        crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Calf"), Angle(0, -55, 0), true)
        crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_L_Calf"), Angle(0, -55, 0), true)
        crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Foot"), Angle(0, 20, 0), true)
        crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_L_Foot"), Angle(0, 20, 0), true)
        self:DeleteOnRemove(crew)
    else

    end

    -----------------

    self:SetPos(self.Points[1].pos)
    self:SetAngles(self.Points[1].ang)
    self.CurrentPoint = 2
end

function ENT:GetPlayersInHeli()
    local tab = {}
    for _, ent in pairs(ents.FindInSphere(self:GetPos(), 500)) do
        if ent:IsPlayer() and ent:IsSurvivor() then
            local tr = util.TraceLine({
                start = ent:GetPos()+Vector(0,0,4),
                entpos = ent:GetPos()-Vector(0,0,32),
                filter = ent,
            })
            if tr.Entity == self or ent:GetGroundEntity() == self then
                tab[#tab+1] = ent
            else
                continue
            end
        end
    end
    return tab
end

function ENT:Exfil()
    for _, ent in ipairs(self:GetPlayersInHeli()) do
        ent:GodEnable()
    end
    self.Skipping = false
    self.Exfilling = true
    self.DamageLine = CurTime()+10
    self.CurrentPoint = self.CurrentPoint+1

    local num = #self:GetPlayersInHeli()
    if num == 0 then
        SuR:PlaySoundOnClient("surrounded/other/pilot1/helinone_0"..math.random(1,3)..".mp3")
    elseif num == SuR:CurrentFighters(true) then
        SuR:PlaySoundOnClient("surrounded/other/pilot1/helileave_0"..math.random(1,3)..".mp3")
    else
        SuR:PlaySoundOnClient("surrounded/other/pilot1/helisome_0"..math.random(1,3)..".mp3")
    end

    timer.Simple(0.01, function()
        if !IsValid(self) then return end
        local phys = self:GetPhysicsObject()
        if !IsValid(phys) then return end
        phys:EnableMotion(true)
        phys:AddVelocity(Vector(0,0,1))
    end)
end

function ENT:Complete()
    self.Skipping = true
    if #self:GetPlayersInHeli() > 0 then
        SuR.ExfilSuccess = true
        for _, ply in ipairs(self:GetPlayersInHeli()) do
            ply.ExfilItems = {
                main = ply:GetNWString('MainWeapon'),
                sec = ply:GetNWString('SecWeapon'),
                melee = ply:GetNWString('MeleeWeapon'),
                extra = ply:GetNWString('OtherWeapon'),
                bandages = ply:GetNWFloat('Bandages'),
                sprays = ply:GetNWFloat('Sprays'),
            }
            ply:AddXP(SuR.Config.XP_Giving["evac_success"])
        end
    end
    for _, ply in ipairs(player.GetAll()) do
        if table.HasValue(self:GetPlayersInHeli(), ply) then
            ply:KillSilent()
            ply:ScreenFade(SCREENFADE.IN, color_black, 1, 1)
        else
            ply:SuR_MakeZombie()
        end
    end
    if IsValid(self.CallEnt) then
        self.CallEnt:SetNWBool('Ready', true)
    end
    hook.Call("SuR.ExfilFinished", nil, SuR.ExfilSuccess)
end

function ENT:KillNPC()
    for _, ent in pairs(ents.FindInSphere(self:GetPos(), 400)) do
        if ent:IsNPC() or ent:IsPlayer() and ent:IsZombie() then
            ent:TakeDamage(100)
            self:EmitSound("physics/metal/metal_barrel_impact_soft"..math.random(1,4)..".wav", 70, math.random(80,120))
            if not self.DamageLine or self.DamageLine < CurTime() then
                self.DamageLine = CurTime()+9
                SuR:PlaySoundOnClient("surrounded/other/pilot1/helihurt_0"..math.random(1,3)..".mp3")
            end
        end
    end
end

hook.Add("SuR.Helo_Exfil_Reached", "SuR_FixExfil", function(heli, point)
    if point == 2 then
        heli:GetPhysicsObject():EnableCollisions(true)
        heli.PickingTime = CurTime()+heli.WaitTime-4
        heli.DamageLine = CurTime()+12
        SuR:Countdown(heli.WaitTime)
        if heli.LastExfil then
            SuR:PlaySoundOnClient("surrounded/other/pilot1/gashurry"..math.random(1,4)..".mp3")
        else
            SuR:PlaySoundOnClient("surrounded/other/pilot1/helihere_0"..math.random(1,3)..".mp3")
        end

        timer.Create("HeliExfilVoice1"..heli:EntIndex(), 8, 1, function()
            if !IsValid(heli) then return end
            SuR:PlaySoundOnClient("surrounded/other/pilot1/heligather_0"..math.random(1,3)..".mp3")
        end)

        timer.Create("HeliExfil"..heli:EntIndex(), heli.WaitTime-4, 1, function()
            if !IsValid(heli) then return end
            if heli.Heli then
                heli:EmitSound("surrounded/vehicles/palfa/engine_start.wav")
            else
                heli:EmitSound("surrounded/vehicles/van/engine_start.wav")
            end

            timer.Simple(4, function()
                if !IsValid(heli) then return end
                heli:Exfil()
            end)
        end)
    elseif point == 4 then
        heli:Complete()
        heli:GetPhysicsObject():EnableCollisions(false)
    end
end)

function ENT:PhysicsCollide(col, data)
    if self.Mayday then
        self.Disabled = true
        if self.Heli then
            self:StopSound("surrounded/vehicles/palfa/engine_idle.wav")
        else
            self:StopSound("surrounded/vehicles/van/engine_idle.wav")
        end
    end

    local tar = col.HitEntity
    if self.CurrentPoint == 3 and tar:IsWorld() then
        local phys = self:GetPhysicsObject()
        if IsValid(phys) then
            phys:EnableMotion(false)
        end
    end
end

function ENT:Think()
    local phys = self:GetPhysicsObject()

    if self.Disabled then return end

    ---ROTOR PART---

    local bone = 63
    self:ManipulateBoneAngles(bone, self:GetManipulateBoneAngles(bone)+Angle(0,10,0))

    local bone = self:LookupBone("tag_tail_rotor_rot")
    self:ManipulateBoneAngles(bone, self:GetManipulateBoneAngles(bone)+Angle(0,10,0))

    ----------------

    ---MOVE PART---

    local point = self.Points[self.CurrentPoint]
    self.CurrentSpeed = math.min(self.CurrentSpeed+FrameTime()/0.01, self.MaxSpeed)

    if point.pos:Distance(self:GetPos()) < point.dist and (not point.wait or self.Skipping) then
        hook.Run("SuR.Helo_Exfil_Reached", self, self.CurrentPoint)
        timer.Simple(0.01, function()
            if !IsValid(phys) then return end
            phys:EnableMotion(true)
            phys:AddVelocity(Vector(0,0,1))
        end)
        self.CurrentPoint = self.CurrentPoint+1
        if self.CurrentPoint > #self.Points then
            self:Remove()
            return
        end
        self.Skipping = false
        self.CurrentSpeed = 0 
    end

    self:KillNPC()

    if phys:IsMotionEnabled() then
        if self.Mayday then
            local tab = {}
            tab.secondstoarrive = 1
            tab.pos = self:GetPos()-Vector(0,0,100)
            tab.angle = self:GetAngles()+Angle(0.01,90,0)
            tab.maxangular = 5000
            tab.maxangulardamp = 10000
            tab.maxspeed = 1000000
            tab.maxspeeddamp = 10000
            tab.dampfactor = 0.5
            tab.teleportdistance = 0
            tab.deltatime = CurTime()-self.DeltaTime
            phys:ComputeShadowControl(tab)
        else
            local tab = {}
            tab.secondstoarrive = point.sec
            tab.pos = point.pos
            tab.angle = self:GetAngles()
            tab.maxangular = 500
            tab.maxangulardamp = 10000
            tab.maxspeed = 1000000
            tab.maxspeeddamp = 10000
            tab.dampfactor = point.damp
            tab.teleportdistance = 0
            tab.deltatime = CurTime()-self.DeltaTime
            phys:ComputeShadowControl(tab)

            local tab = {}
            tab.secondstoarrive = point.sec/5
            if point.smoothrotate then
                tab.secondstoarrive = point.sec
            end
            tab.pos = self:GetPos()
            tab.angle = point.ang
            tab.maxangular = 5000
            tab.maxangulardamp = 10000
            tab.maxspeed = 0
            tab.maxspeeddamp = 0
            tab.dampfactor = point.damp
            tab.teleportdistance = 0
            tab.deltatime = CurTime()-self.DeltaTime
            phys:ComputeShadowControl(tab)

            local vel = phys:GetVelocity()
            vel.x = math.Clamp(vel.x, -self.CurrentSpeed, self.CurrentSpeed)
            vel.y = math.Clamp(vel.y, -self.CurrentSpeed, self.CurrentSpeed)
            vel.z = math.Clamp(vel.z, -self.CurrentSpeed, self.CurrentSpeed)
            phys:SetVelocity(vel)
        end
    end

    --------------

    self.DeltaTime = CurTime()
    self:NextThink(CurTime())
    return true
end