local meta = FindMetaTable("Entity")

local function visiblity(ent, ent2)
    local tr = util.TraceLine( {
        start = ent:EyePos(),
        endpos = ent2:WorldSpaceCenter(),
        filter = ent,
        mask = MASK_SOLID_BRUSHONLY
    })
    print(!tr.Hit , tr.Entity, ent, ent2)
    return !tr.Hit
end

function meta:RewriteLNR(isspecial)
    self.TimeOverDeath = 60
    self.RewriteDoorThing = true
    self:SetCustomCollisionCheck(true)

    self.DefaultMeleeDistance = {self.MeleeAttackDistance, self.MeleeAttackDamageDistance}

    if self:GetClass() == "npc_vj_lnr_hazmat" then return end

    function self:CustomOnThink()
        if self.Zombie_CustomOnThink then
            self:Zombie_CustomOnThink()
        end

        local en = self:GetEnemy()
        if IsValid(en) then
            local height = math.abs(en:GetPos().z-self:GetPos().z)
            if height > 24 then
                self.MeleeAttackDistance = 128
                self.MeleeAttackDamageDistance = 128
            else
                self.MeleeAttackDistance = self.DefaultMeleeDistance[1]
                self.MeleeAttackDamageDistance = self.DefaultMeleeDistance[2]
            end
        end

        if self.LNR_Crawler or self.LNR_Crippled or self.Dead or self.DeathAnimationCodeRan or self.Flinching or self:GetSequence() == self:LookupSequence("nz_spawn_climbout_fast") or self:GetSequence() == self:LookupSequence("nz_spawn_jump") or self:GetSequence() == self:LookupSequence("shove_forward_01") or self:GetSequence() == self:LookupSequence("infectionrise") or self:GetSequence() == self:LookupSequence("infectionrise2") or self:GetSequence() == self:LookupSequence("slumprise_a") or self:GetSequence() == self:LookupSequence("slumprise_a2") then
            self.LNR_DoorToBreak = NULL

            return
        end

        local acti = ACT_OPEN_DOOR
        if !VJ_AnimationExists(self, ACT_OPEN_DOOR) then
            acti = self.AnimTbl_MeleeAttack[1]
        end

        if acti then
            if not IsValid(self.LNR_DoorToBreak) then
                if (not self.VJ_IsBeingControlled) or (self.VJ_IsBeingControlled and self.VJ_TheController:KeyDown(IN_DUCK)) then
                    for _, v in pairs(ents.FindInSphere(self:GetPos(), 48)) do
                        if ( v:GetClass() == "prop_door_rotating" or v:GetClass() == "func_door_rotating" or v:GetClass() == "func_door" or v:GetClass() == "sur_barricade" ) then
                            self.LNR_DoorToBreak = v
                            break
                        end
                    end
                end
            else
                if self.PlayingAttackAnimation then
                    self.LNR_DoorToBreak = NULL

                    return
                end

                if self:GetActivity() ~= ACT_OPEN_DOOR then
                    local ang = self:GetAngles()
                    self:SetAngles(Angle(ang.x, (self.LNR_DoorToBreak:GetPos() - self:GetPos()):Angle().y, ang.z))
                    self:VJ_ACT_PLAYACTIVITY(ACT_OPEN_DOOR, true, false, false)
                    self:SetState(VJ_STATE_ONLY_ANIMATION)
                end
            end
        end

        if not IsValid(self.LNR_DoorToBreak) then
            self:SetState()
        end
    end
end

hook.Add("AcceptInput", "SuR_RewriteInput", function( self, name, activator, caller, data )
    if self.RewriteDoorThing and self.IsZombie and name == "break_door" then
        if IsValid(self.LNR_DoorToBreak) then
            VJ_CreateSound(self, self.SoundTbl_BeforeMeleeAttack, self.BeforeMeleeAttackSoundLevel, self:VJ_DecideSoundPitch(self.BeforeMeleeAttackSoundPitch.a, self.BeforeMeleeAttackSoundPitch.b))
            VJ_EmitSound(self, "physics/wood/wood_panel_impact_hard1.wav", 75, 100)
            local doorDmg = self.MeleeAttackDamage
            local door = self.LNR_DoorToBreak

            if door.health == nil then
                door.health = 200 - doorDmg
            elseif door.health <= 0 then
                VJ_EmitSound(self, self.SoundTbl_MeleeAttackMiss, self.MeleeAttackMissSoundLevel, self:VJ_DecideSoundPitch(self.MeleeAttackMissSoundPitch.a, self.MeleeAttackMissSoundPitch.b))

                return
            else
                door.health = door.health - doorDmg
            end

            if door:GetClass() == "prop_door_rotating" and door.health <= 0 then
                door:EmitSound("physics/wood/wood_furniture_break" .. math.random(1, 2) .. ".wav", 75, 100)
                door:EmitSound("ambient/materials/door_hit1.wav", 75, 100)
                ParticleEffect("door_pound_core", door:GetPos(), door:GetAngles(), nil)
                ParticleEffect("door_explosion_chunks", door:GetPos(), door:GetAngles(), nil)
                door:Remove()
                local doorgib = ents.Create("prop_physics")
                doorgib:SetPos(door:GetPos())
                doorgib:SetAngles(door:GetAngles())
                doorgib:SetModel(door:GetModel())
                doorgib:SetSkin(door:GetSkin())
                doorgib:SetBodygroup(1, door:GetBodygroup(1))
                doorgib:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
                doorgib:SetSolid(SOLID_NONE)
                doorgib:Spawn()
                doorgib:GetPhysicsObject():ApplyForceCenter(self:GetForward() * 5000)
                SafeRemoveEntityDelayed(doorgib, 30)
            elseif door.health <= 0 then
                door:EmitSound("physics/wood/wood_furniture_break" .. math.random(1, 2) .. ".wav", 75, 100)
                ParticleEffect("door_pound_core", door:GetPos(), door:GetAngles(), nil)
                ParticleEffect("door_explosion_chunks", door:GetPos(), door:GetAngles(), nil)
                door:Remove()
                local doorgibs = ents.Create("prop_dynamic")
                doorgibs:SetPos(door:GetPos())
                doorgibs:SetAngles(door:GetAngles())
                doorgibs:SetModel("models/props_c17/FurnitureDresser001a.mdl")
                doorgibs:Spawn()
                doorgibs:TakeDamage(9999)
                doorgibs:Fire("break")
            end
        end
        return true
    end
end)

local function PushApart(npc1, npc2)
    local pos1 = npc1:GetPos()
    local pos2 = npc2:GetPos()
    if pos1:DistToSqr(pos2) > 10000 then return end
    local dir = (pos1 - pos2):GetNormalized()
    local pushForce = 50
    local npc1allow = npc1:GetClass() != "npc_vj_lnr_hazmat" and !npc1:IsPlayer()
    local npc2allow = npc2:GetClass() != "npc_vj_lnr_hazmat" and !npc2:IsPlayer()

    if npc1allow then
        npc1:SetVelocity(dir * pushForce)
    end
    if npc2allow then
        npc2:SetVelocity(-dir * pushForce)
    end
end

hook.Add("ShouldCollide", "SuR_NoCollision", function(ent1, ent2)
    if ent1 == ent2 then return false end

    local allow1 = ent1:IsNPC() and ent1.IsZombie or ent1:IsPlayer() and ent1:IsZombie()
    local allow2 = ent2:IsNPC() and ent2.IsZombie or ent2:IsPlayer() and ent2:IsZombie()
    if allow1 and allow2 then
        PushApart(ent1, ent2)
        return false
    end

    local allow1 = ent1:IsNPC() and ent1.IsHuman or ent1:IsPlayer() and ent1:IsSurvivor()
    local allow2 = ent2:IsNPC() and ent2.IsHuman or ent2:IsPlayer() and ent2:IsSurvivor()
    if allow1 and allow2 then
        PushApart(ent1, ent2)
        return false
    end
end)