if SERVER then
	AddCSLuaFile()
end

SWEP.PrintName = "Fäuste"
SWEP.Author = "Modern Gaming & GMod"
SWEP.Purpose = "Fäuste, die ausschließlich zur Selbstverteidigung zu verwenden, sind."
SWEP.Instructions = "Linkslick & Rechtsklick, um Fausthiebe auszuteilen.\nNachladen zum Rausholen oder Einstecken der Fäuste.\n3 hintereinanderfolgende Treffer, lösen einen Combo-Schlag aus."
SWEP.Spawnable = true
SWEP.UseHands = true
SWEP.DrawAmmo = false
SWEP.DrawCrosshair = false
SWEP.ViewModel = Model("models/weapons/c_arms.mdl")
SWEP.WorldModel	= ""
SWEP.ViewModelFOV = 52
SWEP.Slot = 0
SWEP.SlotPos = 5
SWEP.Primary.ClipSize = -1
SWEP.Primary.DefaultClip = -1
SWEP.Primary.Automatic = true
SWEP.Primary.Ammo = "none"
SWEP.Secondary.ClipSize	= -1
SWEP.Secondary.DefaultClip = -1
SWEP.Secondary.Automatic = true
SWEP.Secondary.Ammo = "none"
SWEP.Normal = "normal"
SWEP.HoldType = "fist"
SWEP.Fists = true

local SwingSound = Sound("weapons/slam/throw.wav")
local HitSound = Sound("Flesh.ImpactHard")

function SWEP:SetupDataTables()
	self:NetworkVar("Bool", 0, "Raised")
	self:NetworkVar("Int", 0, "Combo")
	self:NetworkVar("Float", 0, "NextMeleeAttack")
	self:NetworkVar("Float", 1, "NextPushAttack")
	self:NetworkVar("Float", 2, "NextIdle")
	self:NetworkVar("Float", 3, "NextRaise")
	self:NetworkVar("Float", 4, "HideTime")
	self:NetworkVar("Float", 5, "NextPossiblePush")
end

function SWEP:PreDrawViewModel(vm)
	if self:GetRaised() then
		if self:GetHideTime() > CurTime() then
			return true
		end
	elseif self:GetHideTime() <= CurTime() then
		return true
	end
end

function SWEP:DrawHUD()
	local owner = self.Owner
	if owner:InVehicle() and !owner:GetAllowWeaponsInVehicle() then return end
	if !self:GetRaised() then
		local scrw, scrh = ScrW() / 2, ScrH() - 110
		draw.SimpleTextOutlined("Deine Fäuste sind in deinen Taschen.", "mg_instructions", scrw, scrh, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 1, color_black)
		draw.SimpleTextOutlined("Drücke R, um sie herauszuholen!", "mg_instructions2", scrw, scrh + 25, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 1, color_black)
		local tr = self:PlayerTrace(owner, true, true)
		local ent = tr.Entity
		if IsValid(ent) and (ent:IsPlayer() or ent:IsNPC()) then
			if self:GetHideTime() > CurTime() or self:GetNextPushAttack() > CurTime() then return end
			if self:GetNextPossiblePush() < CurTime() then
				draw.SimpleTextOutlined("[Linksklick / Rechtsklick] Wegschubsen", "mg_instructions", scrw, ScrH() / 2, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 1, color_black)
			else
				draw.SimpleTextOutlined("[Linksklick / Rechtsklick] Cooldown ("..string.ToMinutesSeconds(self:GetNextPossiblePush() - CurTime())..")", "mg_instructions", scrw, ScrH() / 2, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 1, color_black)
			end
		end
	end
end

function SWEP:Initialize()
	self:SetHoldType(self.Normal)
end

function SWEP:Deploy()
	self:SetNextRaise(CurTime() + 0.1)
	self:SetRaised(false)
	self:SetHoldType(self.Normal)
	self:SetNextMeleeAttack(0)
	self:SetNextPushAttack(0)
	self:SendWeaponAnim(ACT_VM_DEPLOY)
	if SERVER then
		self:SetCombo(0)
	end
	return true
end

function SWEP:UpdateNextIdle()
	local vm = self.Owner:GetViewModel()
	if IsValid(vm) then
		self:SetNextIdle(CurTime() + vm:SequenceDuration() / vm:GetPlaybackRate())
	end
end

if SERVER then
	util.AddNetworkString("MG_Fists_Push")
end

if CLIENT then
	net.Receive("MG_Fists_Push", function()
		local ply = net.ReadEntity()
		if !IsValid(ply) then return end
		ply:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_GMOD_GESTURE_MELEE_SHOVE_2HAND, true)
	end)
end

function SWEP:PrimaryAttack(right)
	local owner = self.Owner
	if !self:GetRaised() then
		if self:GetNextPushAttack() <= CurTime() and self:GetNextPossiblePush() <= CurTime() and self:GetHideTime() <= CurTime() then
			self:SetNextPrimaryFire(CurTime() + 1)
			self:SetNextSecondaryFire(CurTime() + 1)
			local tr = self:PlayerTrace(owner, true)
			local ent = tr.Entity
			if IsValid(ent) and (ent:IsPlayer() or ent:IsNPC()) then
				if !ent:OnGround() then return end
				if ent:IsPlayer() and ent:IsFrozen() then return end
				self:EmitSound(SwingSound)
				owner:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_GMOD_GESTURE_MELEE_SHOVE_2HAND, true)
				if SERVER then
					net.Start("MG_Fists_Push")
						net.WriteEntity(owner)
					net.SendOmit({owner})
				end
				self:SetNextPushAttack(CurTime() + 0.3)
			end
		end
		return
	end
	owner:SetAnimation(PLAYER_ATTACK1)
	local anim = "fists_left"
	if right then anim = "fists_right" end
	if (self:GetCombo() >= 2) then
		anim = "fists_uppercut"
	end
	local vm = owner:GetViewModel()
	if IsValid(vm) then
		vm:SendViewModelMatchingSequence(vm:LookupSequence(anim))
	end
	self:UpdateNextIdle()
	self:EmitSound(SwingSound)
	self:SetNextMeleeAttack(CurTime() + 0.2)
	self:SetNextPrimaryFire(CurTime() + 0.9)
	self:SetNextSecondaryFire(CurTime() + 0.9)
end

function SWEP:SecondaryAttack()
	self:PrimaryAttack(true)
end

function SWEP:PlayerTrace(owner, push, cl)
	if !cl then
		owner:LagCompensation(true)
	end
	local tr = util.TraceLine({
		start = owner:GetShootPos(),
		endpos = owner:GetShootPos() + owner:GetAimVector() * 48,
		filter = owner,
		mask = MASK_SHOT_HULL
	})
	if !IsValid(tr.Entity) and !push then 
		tr = util.TraceHull({
			start = owner:GetShootPos(),
			endpos = owner:GetShootPos() + owner:GetAimVector() * 48,
			filter = owner,
			mins = Vector(-10, -10, -8),
			maxs = Vector(10, 10, 8),
			mask = MASK_SHOT_HULL
		})
	end
	if !cl then
		owner:LagCompensation(false)
	end
	return tr
end

function SWEP:PushPlayer()
	local owner = self.Owner
	local tr = self:PlayerTrace(owner, true)
	if (tr.Hit and !(game.SinglePlayer() and CLIENT)) then
		self:EmitSound(HitSound)
	end
	if SERVER and IsValid(tr.Entity) then
		if tr.Entity:IsPlayer() or tr.Entity:IsNPC() then
			if !tr.Entity:OnGround() then return end
			if tr.Entity:IsPlayer() and tr.Entity:IsFrozen() then return end
			local pushvel = tr.Normal * 395
			pushvel.z = math.Clamp(pushvel.z, 50, 100)
			tr.Entity:SetVelocity(tr.Entity:GetVelocity() + pushvel)
			hook.Run("MG_Fists_Push", owner, tr.Entity)
			self:SetNextPrimaryFire(CurTime() + 1)
			self:SetNextSecondaryFire(CurTime() + 1)
			self:SetNextPossiblePush(CurTime() + 10)
		end
	end
end

function SWEP:DealDamage()
	local owner = self.Owner
	local anim = self:GetSequenceName(owner:GetViewModel():GetSequence())
	owner:LagCompensation(true)
	local tr = util.TraceLine({
		start = owner:GetShootPos(),
		endpos = owner:GetShootPos() + owner:GetAimVector() * 48,
		filter = owner,
		mask = MASK_SHOT_HULL
	})
	if !IsValid(tr.Entity) then 
		tr = util.TraceHull({
			start = owner:GetShootPos(),
			endpos = owner:GetShootPos() + owner:GetAimVector() * 48,
			filter = owner,
			mins = Vector(-10, -10, -8),
			maxs = Vector(10, 10, 8),
			mask = MASK_SHOT_HULL
		})
	end
	owner:LagCompensation(false)
	if (tr.Hit and !(game.SinglePlayer() and CLIENT)) then
		self:EmitSound(HitSound)
	end
	local hitplayer = false
	if SERVER and IsValid(tr.Entity) then
		if tr.Entity:IsPlayer() or tr.Entity:IsNPC() then
			hitplayer = true
		end
		local dmginfo = DamageInfo()
		local attacker = owner
		if !IsValid(attacker) then attacker = self end
		dmginfo:SetAttacker(attacker)
		dmginfo:SetInflictor(self)
		dmginfo:SetDamage(math.Rand(4, 6))
		if (anim == "fists_left") then
			dmginfo:SetDamageForce(owner:GetUp() * 4912 + owner:GetForward() * 9998)
		elseif (anim == "fists_right") then
			dmginfo:SetDamageForce(owner:GetUp() * -4912 + owner:GetForward() * 9989)
		elseif (anim == "fists_uppercut") then
			owner.ComboAttack = true
			dmginfo:SetDamageForce(owner:GetUp() * 5158 + owner:GetForward() * 10012)
			dmginfo:SetDamage(math.Rand(8, 10))
		end
		local pos = owner:GetShootPos()
		local dest = pos + (owner:GetAimVector() * 48)
		tr.Entity:DispatchTraceAttack(dmginfo, pos + (owner:GetAimVector() * 3), dest)
		owner.ComboAttack = nil
	end
	if IsValid(tr.Entity) then
		local phys = tr.Entity:GetPhysicsObject()
		if IsValid(phys) and phys:GetMass() < 250 then
			phys:ApplyForceOffset(owner:GetAimVector() * 160 * phys:GetMass(), tr.HitPos)
		end
	end
	if SERVER then
		if (hitplayer and anim != "fists_uppercut") then
			self:SetCombo(self:GetCombo() + 1)
		else
			self:SetCombo(0)
		end
	end
end

function SWEP:Reload()
	if self:GetNextRaise() > CurTime() or !self.Owner:KeyPressed(IN_RELOAD) or !IsFirstTimePredicted() then return end
	self:SetNextRaise(CurTime() + 1)
	self:SetRaised(!self:GetRaised())
	self:SetHoldType(self:GetRaised() and self.HoldType or self.Normal)
	local vm = self.Owner:GetViewModel()
	if self:GetRaised() then
		self:SetHideTime(CurTime() + 0.1)
		if IsValid(vm) then
			vm:SendViewModelMatchingSequence(vm:LookupSequence("fists_draw"))
		end
		self:UpdateNextIdle()
		self:SetNextPrimaryFire(CurTime() + 1)
		self:SetNextSecondaryFire(CurTime() + 1)
	else
		self:SetHideTime(CurTime() + 0.5)
		if IsValid(vm) then
			vm:SendViewModelMatchingSequence(vm:LookupSequence("fists_holster"))
		end
	end
	self:SetNextMeleeAttack(0)
	self:SetNextPushAttack(0)
	if SERVER then
		self:SetCombo(0)
	end
end

function SWEP:Think()
	local tb = self:GetTable()
	local dt = tb.dt
	if !dt then return end

	local curtime = CurTime()

	if !dt.Raised then
		local pushattack = dt.NextPushAttack
		if (pushattack > 0 and curtime > pushattack) then
			self:PushPlayer()
			dt.NextPushAttack = 0
		end
		return
	end

	local vm = self:GetOwner():GetViewModel()
	local idletime = self:GetNextIdle()

	if (vm:IsValid() and idletime > 0 and curtime > idletime) then
		vm:SendViewModelMatchingSequence(vm:LookupSequence("fists_idle_0"..math.random(1, 2)))
		self:UpdateNextIdle()
	end
	local meleetime = dt.NextMeleeAttack
	if (meleetime > 0 and curtime > meleetime) then
		self:DealDamage()
		self:SetNextMeleeAttack(0)
	end

	if (SERVER and curtime > self:GetNextPrimaryFire() + 0.1) then
		self:SetCombo(0)
	end
end