local meta = FindMetaTable('Player')

function meta:GetPlayerClass()
    return self:GetNWString("PlayerClass", "survivor")
end

function meta:GetLevel()
    return self:GetNWFloat("PlayerLevel", 1), self:GetNWFloat("PlayerXP", 0)
end

function meta:GetLevelState()
    local lvl = self:GetLevel()
    if self:IsZombie() or !self:Alive() then
        return 0
    end
    if lvl >= 21 then
        return 5
    elseif lvl >= 16 then
        return 4
    elseif lvl >= 11 then
        return 3
    elseif lvl >= 6 then
        return 2
    else
        return 1
    end
end

function meta:GetXPToLevel(without)
    local start_xp = SuR.Config.Start_Level_XP
    local lvl_mult = SuR.Config.Level_Progress_Mult
    local lvl, cur_xp = self:GetLevel()
    local formula = start_xp+(lvl*lvl_mult)
    --formula = start_xp*lvl_mult^(lvl-1)
    local need_xp = math.max(formula-cur_xp, 0)
    if without then
        need_xp = math.max(formula, 0)
    end

    return need_xp
end

function meta:IsSurvivor()
    return self:Team() == 1
end

function meta:IsZombie()
    return self:Team() == 2
end

function meta:IsDowned()
    return self:GetNWBool('SuR_Downed', false)
end

function meta:IsStunned(isidle)
	return not isidle and string.match(self:GetSVAnim(), "sur_fall_") or isidle and string.match(self:GetSVAnim(), "sur_fall_idle")
end

function meta:IsLockedAbilities()
    return self:IsDowned() or self:IsStunned() or self:WaterLevel() >= 2 or self:GetNWBool('SVAnimStopCutscene') or self:GetNWBool('SVAnimStopMoving') or IsValid(self:GetNWEntity('ReviveTarget')) or self:IsZombie()
end

function meta:GetSVAnim()
    return self:GetNWString('SVAnim', '')
end

function SuR:TransferModelData(base, model)
	local ent1Model = base:GetModel()
	local ent1Skin = base:GetSkin()
	local ent1BodyGroups = base:GetNumBodyGroups()
	model:SetModel(ent1Model)
	model:SetSkin(ent1Skin)
	for i = 0, ent1BodyGroups - 1 do
		model:SetBodygroup(i, base:GetBodygroup(i))
	end
end

function SuR:TransferBones(base, ragdoll, client)
    if client and CLIENT then return end
	if !IsValid(base) or !IsValid(ragdoll) then return end
	if client then
		net.Start("SuR.BecomeRagdoll")
		net.WriteEntity(ragdoll)
		net.Broadcast()
        SafeRemoveEntityDelayed(base, 0.1)
	else
		for i = 0, ragdoll:GetPhysicsObjectCount() - 1 do
			local bone = ragdoll:GetPhysicsObjectNum( i )
			if ( IsValid( bone ) ) then
				local pos, ang = base:GetBonePosition( ragdoll:TranslatePhysBoneToBone( i ) )
				if ( pos ) then bone:SetPos( pos ) end
				if ( ang ) then bone:SetAngles( ang ) end
				bone:SetVelocity(-bone:GetVelocity())
			end
		end
	end
end

function SuR:CurrentAliveEnemies()
    local tab = {}
    local tab2 = ents.FindByClass("*lnr*")
    for i=1,#tab2 do
        local ent = tab2[i]
        if not ent.IsZombie then continue end
        tab[#tab+1] = ent
    end
    return #tab
end

function SuR:CurrentFighters(downed)
    local tab = {}
    local tab2 = player.GetAll()
    for i=1,#tab2 do
        local ent = tab2[i]
        if not ent:Alive() or not downed and ent:IsDowned() and not ent.ExecutingTarget and ent:GetNWFloat('SelfRevive') <= 0 or ent:IsZombie() then continue end
        tab[#tab+1] = ent
    end
    return #tab
end

function SuR:CurrentPlayerZombies()
    local tab = {}
    local tab2 = player.GetAll()
    for i=1,#tab2 do
        local ent = tab2[i]
        if not ent:IsZombie() then continue end
        tab[#tab+1] = ent
    end
    return #tab
end

function SuR:PickRandomPlayer()
	local tab = {}
	local tab2 = player.GetAll()
	for i=1,#tab2 do
		local ply = tab2[i]
		if ply:Alive() and !ply:IsDowned() then
			table.insert(tab, ply)
		end
	end
	if #tab > 0 then
		return tab[math.random(1,#tab)]
	else
		return nil
	end
end

function SuR:CopyTable(source, to)
    to = {}
    for k, v in pairs(source) do
        to[k] = v
    end
end

function meta:GetInfection()
    return self:GetNWFloat('InfectionProgress', 0)
end

if SERVER then
    RunConsoleCommand("vj_npc_knowenemylocation", 1)
    RunConsoleCommand("vj_npc_itemdrops", 0) 
    RunConsoleCommand("vj_npc_sd_soundtrack", 1)
    RunConsoleCommand("mp_falldamage", 1)
    RunConsoleCommand("VJ_LNR_Infection", 0)
else
    RunConsoleCommand("cl_tfa_hud_enabled", 0)
    RunConsoleCommand("cl_tfa_hud_hitmarker_enabled", 0)
    RunConsoleCommand("cl_tfa_hud_crosshair_enable_custom", 0)
    RunConsoleCommand("cl_tfa_hud_keybindhints_enabled", 0)
    RunConsoleCommand("cl_tfa_ironsights_toggle", 0)
end

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

hook.Add("SetupMove", "SuR_Move", function(ply, mv, cmd)
    if SERVER then
        if SuR.ActiveMutator == 12 then
            mv:SetMaxSpeed(75)
            mv:SetMaxClientSpeed(75)
        end
    else
        if SuR.Data["Mutator"] == 12 then
            mv:SetMaxSpeed(75)
            mv:SetMaxClientSpeed(75)
        end
    end
	if ply:GetInfection() >= 0.8 or ply:Health() <= 15 then
		mv:SetMaxSpeed(60)
        mv:SetMaxClientSpeed(60)
	elseif ply:GetInfection() >= 0.4 or ply:Health() <= 30 then
		mv:SetMaxSpeed(90)
        mv:SetMaxClientSpeed(90)
	end
    if ply:GetNWBool('SVAnimStopMoving') then
        mv:SetMaxSpeed(1)
        mv:SetMaxClientSpeed(1)
    end
    if ply:IsDowned() then
        mv:SetMaxSpeed(20)
        mv:SetMaxClientSpeed(20)
    end
    if ply:IsZombie() and ply:Alive() then
        mv:SetSideSpeed(0)
    end
end)

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

game.AddParticles( "particles/antlion_gib_01.pcf" )
game.AddParticles( "particles/antlion_gib_02.pcf" )
game.AddParticles( "particles/advisor.pcf" )
game.AddParticles( "particles/Advisor_FX.pcf" )
game.AddParticles( "particles/aurora.pcf" )
game.AddParticles( "particles/aurora_sphere2.pcf" )
game.AddParticles( "particles/antlion_worker.pcf" )
game.AddParticles( "particles/buildingdamage.pcf" )
game.AddParticles( "particles/blob.pcf" )
game.AddParticles( "particles/bonfire.pcf" )
game.AddParticles( "particles/building_explosion.pcf" )
game.AddParticles( "particles/default.pcf" )
game.AddParticles( "particles/demo_paticle_light.pcf" )
game.AddParticles( "particles/devtest.pcf" )
game.AddParticles( "particles/door_explosion.pcf" )
game.AddParticles( "particles/dust_bombdrop.pcf" )
game.AddParticles( "particles/dust_rumble.pcf" )
game.AddParticles( "particles/explosion.pcf" )
game.AddParticles( "particles/electrical_fx.pcf" )
game.AddParticles( "particles/fire_ring.pcf" )
game.AddParticles( "particles/fireflow.pcf" )
game.AddParticles( "particles/flamethrowertest.pcf" )
game.AddParticles( "particles/grenade_fx.pcf" )
game.AddParticles( "particles/grub_blood.pcf" )
game.AddParticles( "particles/hunter_intro.pcf" )
game.AddParticles( "particles/hunter_projectile.pcf" )
game.AddParticles( "particles/hunter_shield_impact.pcf" )
game.AddParticles( "particles/hunter_flechette.pcf" )
game.AddParticles( "particles/choreo_dog_v_strider.pcf" )
game.AddParticles( "particles/choreo_launch.pcf" )
game.AddParticles( "particles/choreo_gman.pcf" )
game.AddParticles( "particles/choreo_extract.pcf" )
game.AddParticles( "particles/largefire.pcf" )
game.AddParticles( "particles/light_rays.pcf" )
game.AddParticles( "particles/magnusson_burner.pcf" )
game.AddParticles( "particles/rain.pcf" )
game.AddParticles( "particles/sand.pcf" )
game.AddParticles( "particles/skybox_smoke.pcf" )
game.AddParticles( "particles/stalactite.pcf" )
game.AddParticles( "particles/striderbuster.pcf" )
game.AddParticles( "particles/steampuff.pcf" )
game.AddParticles( "particles/test_grnalpha.pcf" )
game.AddParticles( "particles/test_noise.pcf" )
game.AddParticles( "particles/vehicle.pcf" )
game.AddParticles( "particles/vistasmokev1.pcf" )
game.AddParticles( "particles/Vortigaunt_FX.pcf" )
game.AddParticles( "particles/warpshield.pcf" )
game.AddParticles( "particles/water_leaks.pcf" )
game.AddParticles( "particles/waterfall.pcf" )
game.AddParticles( "particles/waterdrips.pcf" )
game.AddParticles( "particles/weapon_fx.pcf" )