local meta = FindMetaTable('Player')

function SuR:VJ_LNR_CreateZombie(victim, inflictor)
    local findPos = victim:GetPos()
    local findMDL = victim:GetModel()

    timer.Simple(0.01, function()
        for _, v in pairs(ents.FindInSphere(findPos, 75)) do
            if v:GetClass() == "prop_ragdoll" and v:GetModel() == findMDL then
                v:Remove()
            end
        end
    end)

    local zombie = NULL
    local sndTbl = nil
    local oldModel = victim:GetModel()
    local oldSkin = victim:GetSkin()
    local oldMaterial = victim:GetMaterial()
    local oldColor = victim:GetColor()

    if victim.GetPlayerColor and victim:GetPlayerColor() then
        oldPlayerColor = victim:GetPlayerColor()
    else
        oldPlayerColor = false
    end

    local DefaultFootSteps = {"npc/metropolice/gear1.wav", "npc/metropolice/gear2.wav", "npc/metropolice/gear3.wav", "npc/metropolice/gear4.wav", "npc/metropolice/gear5.wav", "npc/metropolice/gear6.wav"}

    if victim.SoundTbl_FootStep and #victim.SoundTbl_FootStep > 0 then
        sndTbl = victim.SoundTbl_FootStep
    else
        if victim.IsVJBaseSNPC_Human and not VJ_PICK(victim.SoundTbl_FootStep) then
            sndTbl = DefaultFootSteps
        end
    end

    if victim:IsNPC() or victim:IsPlayer() then
        if inflictor.LNR_Walker or victim.LNR_Walker then
            victim.LNR_Infected = false
            victim.LNR_Drowner = false
            zombie = ents.Create("npc_vj_lnr_wal")

            if victim:IsPlayer() then
                zombie = ents.Create("npc_vj_lnr_wal_ply")
            end
        end

        if inflictor.LNR_Infected or victim.LNR_Infected then
            victim.LNR_Walker = false
            victim.LNR_Drowner = false
            zombie = ents.Create("npc_vj_lnr_inf")

            if victim:IsPlayer() then
                zombie = ents.Create("npc_vj_lnr_inf_ply")
            end
        end

        if inflictor.LNR_Drowner or victim.LNR_Drowner then
            victim.LNR_Walker = false
            victim.LNR_Infected = false
            zombie = ents.Create("npc_vj_lnr_drowned")

            if victim:IsPlayer() then
                zombie = ents.Create("npc_vj_lnr_drowned_ply")
            end
        end

        zombie:SetPos(victim:GetPos())
        zombie:SetAngles(victim:GetAngles())
        zombie:Spawn()
        undo.ReplaceEntity(victim, zombie)
        zombie:VJ_LNR_CreateBoneMerge(zombie, oldModel, oldSkin, oldColor, oldMaterial, oldPlayerColor, victim)
    end

    if sndTbl then
        zombie.SoundTbl_FootStep = sndTbl
    end

    -- This fixes an error that would pop up if an SNPC or entity infected more than one enemy at a time
    if zombie.IsVJBaseSNPC and zombie.CurrentPossibleEnemies == nil then
        zombie.CurrentPossibleEnemies = {}
    end

    if string.find(oldModel, "female") or string.find(oldModel, "alyx") or string.find(oldModel, "mossman") or string.find(oldModel, "chell") then
        if zombie.LNR_Walker then
            zombie:ZombieVoice_FemaleWal()
        elseif zombie.LNR_Infected then
            zombie:ZombieVoice_FemaleInf()
        elseif zombie.LNR_Drowner then
            zombie:ZombieVoice_FemaleDro()
        end
    end

    if string.find(oldModel, "police") then
        zombie:ZombieVoice_CP()
    elseif string.find(oldModel, "combine") or string.find(oldModel, "zombie_soldier") then
        zombie:ZombieVoice_Combine()
    end

    local DeathAnims = {ACT_SIGNAL1, ACT_SIGNAL2, ACT_SIGNAL3}

    local AnimTime = VJ_GetSequenceDuration(zombie, zombie:GetSequenceName(zombie:GetSequence()))
    zombie:VJ_ACT_PLAYACTIVITY(DeathAnims, true, 120, false)
    zombie.LNR_AllowedToStumble = false
    zombie.GodMode = true
    zombie.CanInvestigate = false
    zombie.HasPoseParameterLooking = false
    zombie.DisableFindEnemy = true
    zombie.DisableMakingSelfEnemyToNPCs = true
    zombie:AddFlags(FL_NOTARGET)
    zombie.MovementType = VJ_MOVETYPE_STATIONARY
    zombie.CanTurnWhileStationary = false
    zombie.HasSounds = false
    zombie.DisableSelectSchedule = true

    timer.Simple(math.random(GetConVar("VJ_LNR_ResurrectionTime1"):GetInt(), GetConVar("VJ_LNR_ResurrectionTime2"):GetInt()), function()
        if IsValid(zombie) then
            zombie.GodMode = false
            zombie.CanInvestigate = true
            zombie.DisableFindEnemy = false
            zombie.DisableMakingSelfEnemyToNPCs = false
            zombie:RemoveFlags(FL_NOTARGET)

            if GetConVar("vj_npc_sd_nosounds"):GetInt() == 0 then
                zombie.HasSounds = true
            end

            if zombie:GetActivity() == ACT_SIGNAL1 then
                zombie:VJ_ACT_PLAYACTIVITY("infectionrise", true, false, false)
                AnimTime = VJ_GetSequenceDuration(zombie, "infectionrise")
            elseif zombie:GetActivity() == ACT_SIGNAL2 then
                zombie:VJ_ACT_PLAYACTIVITY("slumprise_a", true, false, false)
                AnimTime = VJ_GetSequenceDuration(zombie, "slumprise_a")

                if zombie:GetActivity() == ACT_SIGNAL2 and math.random(1, 3) == 1 then
                    zombie:VJ_ACT_PLAYACTIVITY("slumprise_a2", true, false, false)
                    AnimTime = VJ_GetSequenceDuration(zombie, "slumprise_a2")
                end
            elseif zombie:GetActivity() == ACT_SIGNAL3 then
                zombie:VJ_ACT_PLAYACTIVITY("infectionrise2", true, false, false)
                AnimTime = VJ_GetSequenceDuration(zombie, "infectionrise2")
            end

            if GetConVar("vj_npc_noidleparticle"):GetInt() == 0 and GetConVar("VJ_LNR_Eyes"):GetInt() == 1 then
                for i = 1, 2 do
                    local att = i == 2 and "eye1" or "eye2"
                    local EyeGlow = ents.Create("env_sprite")
                    EyeGlow:SetKeyValue("model", "vj_base/sprites/vj_glow1.vmt")
                    EyeGlow:SetKeyValue("scale", "0.02")
                    EyeGlow:SetKeyValue("rendermode", "5")

                    if zombie:GetClass() == "npc_vj_lnr_inf" or zombie:GetClass() == "npc_vj_lnr_inf_ply" then
                        EyeGlow:SetKeyValue("rendercolor", "255 0 0")
                    end

                    if zombie:GetClass() == "npc_vj_lnr_drowned" or zombie:GetClass() == "npc_vj_lnr_drowned_ply" then
                        EyeGlow:SetKeyValue("rendercolor", "0 255 255 255")
                    end

                    if zombie:GetClass() == "npc_vj_lnr_wal" or zombie:GetClass() == "npc_vj_lnr_wal_ply" then
                        EyeGlow:SetKeyValue("rendercolor", "255 255 0 255")
                    end

                    EyeGlow:SetKeyValue("spawnflags", "1")
                    EyeGlow:SetParent(zombie)
                    EyeGlow:Fire("SetParentAttachment", att, 0)
                    EyeGlow:Spawn()
                    EyeGlow:Activate()
                    zombie:DeleteOnRemove(EyeGlow)
                end
            end

            timer.Simple(AnimTime, function()
                if IsValid(zombie) then
                    zombie.HasPoseParameterLooking = true
                    zombie:DoChangeMovementType(VJ_MOVETYPE_GROUND)

                    if zombie:GetClass() == "npc_vj_lnr_drowned" or zombie:GetClass() == "npc_vj_lnr_drowned_ply" then
                        zombie:DoChangeMovementType(VJ_MOVETYPE_AQUATIC)
                    end

                    zombie.LNR_AllowedToStumble = true
                    zombie.DisableSelectSchedule = false
                end
            end)
        end
    end)

    if victim.IsVJBaseSNPC then
        victim.HasDeathRagdoll = false
        victim.HasDeathAnimation = false
    end

    if victim:IsPlayer() then
        if IsValid(victim:GetRagdollEntity()) then
            SafeRemoveEntity(victim:GetRagdollEntity())
        end
    end

    if victim:IsNPC() then
        SafeRemoveEntity(victim)
    end

    if IsValid(victim:GetActiveWeapon()) then
        SafeRemoveEntity(victim:GetActiveWeapon())
    end
end

function meta:SuR_MakeZombie()
    if self:Alive() then
        self:Kill()
        if math.random(1,2) == 1 then
            self.LNR_Infected = true
        else
            self.LNR_Walker = true
        end
        SuR:VJ_LNR_CreateZombie(self, self)
        if SuR.Config.Versus_Mode then
            timer.Simple(0, function() self:SetTeam(2) end)
        end
    end
    SuR:StopInfection(self)
end

function meta:SuR_SelfRevive()
    if !self:IsDowned() or self:GetNWFloat('SelfRevive') <= 0 or self:GetSVAnim() != "" or self:IsFlagSet(FL_FROZEN) then return end

    if self:LookupAttachment("anim_attachment_LH") > 0 then
        local att = self:GetAttachment(self:LookupAttachment("anim_attachment_LH"))
        local ent = ents.Create("base_anim")
        ent:SetModel("models/props_c17/TrapPropeller_Lever.mdl")
        ent:Spawn()
        ent:SetPos(att.Pos)
        ent:SetAngles(att.Ang)
        ent:SetParent(self, self:LookupAttachment("anim_attachment_LH"))
        ent:SetLocalAngles(Angle(0,0,90))
        ent:SetLocalPos(Vector(0,0,-4))
        SafeRemoveEntityDelayed(ent, 8)
    end

    self:SetSVAnimation("sur_selfrevive", true, true, true)
    self:ConCommand("-forward")
    timer.Remove("PlayerDowned"..self:EntIndex())
    timer.Simple(1, function()
        if !IsValid(self) or !self:Alive() then return end
        self:EmitSound("surrounded/player/syringe.mp3", 60, math.random(90,110))
        self:ScreenFade(SCREENFADE.IN, Color(20,200,20,100), 0.5, 0)
    end)
    timer.Simple(8, function()
        if !IsValid(self) or !self:Alive() or self:IsFlagSet(FL_FROZEN) or !self:IsDowned() then return end
        self:SuR_Revive(false, true)
        self:SetNWFloat('SelfRevive', self:GetNWFloat('SelfRevive')-1)
    end)
end

function meta:SuR_Down()
    if self.ExecutingTarget then return end
    if self:GetInfection() >= 0.5 then
        self:SuR_MakeZombie()
        return
    end
    self:SetSVAnimation("sur_helpup_trials_follower_drophigh", true, true, true)
    self:SetNWBool('SuR_Downed', true)
    self:SetNWVector('CutsceneAddPos', self:GetUp()*-32)
    self:SetHealth(50)
    self:GodEnable()
    self:SetActiveWeapon(nil)
    self:SetNoTarget(true)
    self:SetDSP(14)
    self:PlayVoiceLine("downed")
    self:DropButtons()
    SuR:MessageOnClient(4, self)
    SuR:ShowTips("revive")

    local delay = 65
    if SuR:CurrentFighters() < 1 and self:GetNWFloat('SelfRevive') <= 0 or SuR.ActiveMutator == 3 then
        delay = 3
    elseif SuR.Current_Wave >= 15 then
        delay = 15
    elseif SuR.Current_Wave >= 10 then
        delay = 20
    elseif SuR.Current_Wave >= 6 then
        delay = 25
    elseif SuR.Current_Wave >= 3 then
        delay = 30
    end

    timer.Create("PlayerDowned2"..self:EntIndex(), delay, 1, function()
        if !IsValid(self) then return end

        self:SetNoTarget(false)
        self:GodDisable()
    end)
    timer.Create("PlayerDowned"..self:EntIndex(), SuR.Config.Bleedout_Time, 1, function()
        if !IsValid(self) then return end

        self:DropButtons()
        self:SetSVAnimation("sur_downed_trials_bleedout", true, true, true)
        timer.Simple(3, function()
            if !IsValid(self) or !self:IsDowned() then return end
            self:SuR_Revive(true)
        end)
    end)

    local wep = self:GetActiveWeapon()
    if IsValid(wep) then
        self.PreDownedWeapon = wep:GetClass()
    end
end

function meta:SuR_Revive(kill, nophase, other)
    self:SetNWBool('SuR_Downed', false)
    self:SetNWVector('CutsceneAddPos', Vector(0,0,0))
    self:SetHealth(30)
    self:SetDSP(0)
    self:SetNoTarget(false)
    self:GodDisable()
    self:DropButtons()
    timer.Remove("PlayerDowned"..self:EntIndex())
    timer.Remove("PlayerDowned2"..self:EntIndex())

    if kill then
        if self:Alive() then
            self:Kill()
        end
    else
        if other then
            self:SetSVAnimation("sur_helpup_trials_follower_success", true, true, true)
        else
            self:SetSVAnimation("sur_revive_stand", true, true, true)
            self:SetNoTarget(true)
            self:SetHealth(60)
            timer.Simple(5, function()
                if !IsValid(self) or self:IsDowned() then return end
                self:SetNoTarget(false)
            end)
        end
        if !nophase then
            self:PlayVoiceLine("thanks")
        end
        if isstring(self.PreDownedWeapon) then
            self:SelectWeapon(self.PreDownedWeapon)
        end
    end
    self.PreDownedWeapon = nil
end

hook.Add("Think", "SuR_ThinkRevive", function()
	local tab = player.GetAll()
	for i=1, #tab do
		local ply = tab[i]

		local tr = util.TraceLine({
			start = ply:EyePos(),
			endpos = ply:EyePos() + ply:GetAimVector() * 50,
			filter = ply,
			mask = MASK_SHOT_HULL
		})

        local ent = tr.Entity
        if !IsValid(ply:GetNWEntity('ReviveTarget')) and IsValid(ent) and ent:IsPlayer() and ent:IsDowned() and !ply:IsDowned() and ply:Alive() and ply:GetVelocity():Length() < 10 and ply:KeyDown(IN_USE) and ent:GetSVAnim() == "" then
            ply:SetNWEntity('ReviveTarget', ent)
            if ply:GetPlayerClass() == "medic" and ply:GetLevelState() >= 4 then
                ply.ReviveProgress = 1
            end
        elseif IsValid(ply:GetNWEntity('ReviveTarget')) then
            local ent = ply:GetNWEntity('ReviveTarget')
            if ply:KeyDown(IN_USE) and ent:IsDowned() and !ply:IsDowned() and ply:Alive() and ply:GetVelocity():Length() < 10 and ply:GetPos():Distance(ent:GetPos()) < 50 then
                if ply.ReviveProgress == 0 then
                    ply:SetSVAnimation("sur_helpup_trials_leader_try", false, true, true)     
                    ent:SetSVAnimation("sur_helpup_trials_follower_try", false, true, true)
                    ply:DropButtons()
                    ent:DropButtons()            
                end
                ent:SetEyeAngles(ply:GetAngles()+Angle(0,180,0))
                ply.ReviveProgress = ply.ReviveProgress + FrameTime()/select(2, ply:LookupSequence("sur_helpup_trials_leader_try"))
                if ply.ReviveProgress >= 1 then
                    ent:SuR_Revive(false, false, true)
                    ply:SetSVAnimation("sur_helpup_trials_leader_success", true, true, true)
                end
            else
                if ply:GetSVAnim() == "sur_helpup_trials_leader_try" then
                    ply:SetSVAnimation("sur_helpup_trials_leader_leave", true, true, true) 
                end
                if IsValid(ent) and ply:GetSVAnim() != "sur_helpup_trials_leader_success" then
                    ent:SetSVAnimation("sur_helpup_trials_follower_drophigh", true, true, true)
                end
                ply.ReviveProgress = 0
                ply:SetNWEntity('ReviveTarget', NULL)
            end
        else
            if ply:GetSVAnim() == "sur_helpup_trials_leader_try" then
                ply:SetSVAnimation("sur_helpup_trials_leader_leave", true, true, true)
            end
            ply:SetNWEntity('ReviveTarget', NULL)
            ply.ReviveProgress = 0
        end
	end
end)