-- Grappling hook stand-alone system
-- By JetBoom

GrapTimers = {}

function CreateGrapArrow(userid, arrowtype)
	if not _PlayerInfo(userid, "alive") or not _PlayerInfo(userid, "connected") then return end
	local Bolt = _EntCreate( "physics_prop" )
	_EntPrecacheModel( "models/mixerman3d/other/arrow.mdl" )
	if Bolt > 0 then
		_EntSetModel(Bolt, "models/mixerman3d/other/arrow.mdl")
		_EntSetPos(Bolt, vecAdd(_PlayerGetShootPos(userid), vecMul(_PlayerGetShootAng( userid ),vector3(30,30,30))))
		_EntSetAng(Bolt, _PlayerGetShootAng(userid))
		_EntSetOwner(Bolt, userid)
		_EntSetAng(Bolt, _PlayerGetShootAng(userid))
		_EntSpawn(Bolt)
		_phys.ApplyForceCenter(Bolt, vecMul(_PlayerGetShootAng(userid), vector3(250000, 250000, 250000)))
		_EntEmitSound(Bolt, "weapons/crossbow/bolt_fly4.wav")
		_EntitySetPhysicsAttacker(Bolt, userid)
		_EntSetMaterial(Bolt, "gmod/shiny")
		_EntSetName(Bolt, "rope"..userid)
		GrapTimers[Bolt] = AddTimer(0.05, 120, GrapCheckHit, Bolt, userid)
	end
end

function RemoveGrapArrow(prop)
	HaltTimer(GrapTimers[prop])
	_EntRemove(prop)
end

function GrapCheckHit(prop, userid)
	if not _EntExists(prop) or _EntGetName(prop) ~= "rope"..userid or prop <= 0 then HaltTimer(GrapTimers[prop]) return end
	_TraceLine(_EntGetPos(prop), _EntGetForwardVector(prop), 81, prop)
	if _TraceHit() then
		GrapProcessHit(0, prop, userid)
		return
	end
	local tab = _EntitiesFindInSphere(_EntGetPos(prop), 30)
	for i=1, table.getn(tab) do
		if tab[i] ~= userid and tab[i] ~= prop and ValidTarget(tab[i]) then
			GrapProcessHit(tab[i], prop, userid)
			return
		end
	end
end

function ValidTarget(ent)
	local nam = _EntGetType(ent)
	if string.find(nam, "physics") or nam == "player" then
		return true
	end
	return false
end

function GrapProcessHit(targ, prop, userid)
	if _EntGetType(prop) ~= "prop_physics" or prop <= 0 then HaltTimer(GrapTimers[prop]) return end
	HaltTimer(GrapTimers[prop])
	_phys.EnableMotion(prop, false)
	AddTimer(0.05, 0, DoGrapHook, userid, prop)
end

function IsInRadius(a, b, dist)
	return math.abs(vecLength(vecSub(_EntGetPos(a),_EntGetPos(b)))) <= dist
end

function DoGrapHook(userid, prop)
	if _EntGetType(prop) ~= "prop_physics" or not _PlayerInfo(userid, "alive") then HaltTimer(GrapTimers[prop]) return end
	if _EntGetType(_PlayerGetActiveWeapon(userid)) ~= "weapon_grapplinghook" then _EntRemove(prop) HaltTimer(GrapTimers[prop]) return end
	if _EntGetType(prop) == "prop_physics" then
		if _PlayerIsKeyDown(userid, IN_ATTACK2) then
			_EntSetVelocity(userid, vecAdd(_EntGetVelocity(userid), vecMul(vecNormalize(vecSub(_EntGetPos(prop), _EntGetPos(userid))),vector3(75,75,75))))
		end
	else
		if not IsInRadius(userid, prop, 128) then
			_EntSetVelocity(userid, vecAdd(_EntGetVelocity(userid), vecMul(vecNormalize(vecSub(_EntGetPos(prop), _EntGetPos(userid))),vector3(75,75,75))))
		end
	end
	_EffectInit()
	_EffectSetEnt(userid)
	if prop <= _MaxPlayers() then
		_EffectSetStart(_PlayerGetShootPos(prop))
	else
		_EffectSetOrigin(_EntGetPos(prop))
	end
	if userid <= _MaxPlayers() then
		_EffectSetStart(_PlayerGetShootPos(userid))
	else
		_EffectSetStart(_EntGetPos(userid))
	end
	_EffectSetScale(4)
	_EffectSetMagnitude(0.3)
	_EffectSetRadius(70)
	_EffectDispatch("FadingLineTeamSolid")
end
