function WeaponsSystem.onWeaponAdded(L)local c=WeaponsSystem.getWeaponForInstance(L)if not c then WeaponsSystem.createWeaponForInstance(L)end end function WeaponsSystem.onWeaponRemoved(L)local c=WeaponsSystem.getWeaponForInstance(L)if c then c:onDestroyed()end WeaponsSystem.knownWeapons[L]=nil end function WeaponsSystem.getRemoteEvent(L)if not WeaponsSystem.networkFolder then return end local c=WeaponsSystem.remoteEvents[L]if IsServer then if not c then warn("\078\111 \082\101\109\111\116\101\069\118\101\110\116 \110\097\109\101\100 ",L)return nil end return c else if not c then c=WeaponsSystem.networkFolder:WaitForChild(L,math.huge)end return c end end function WeaponsSystem.getRemoteFunction(L)if not WeaponsSystem.networkFolder then return end local c=WeaponsSystem.remoteFunctions[L]if IsServer then if not c then warn("\078\111 \082\101\109\111\116\101\070\117\110\099\116\105\111\110 \110\097\109\101\100 ",L)return nil end return c else if not c then c=WeaponsSystem.networkFolder:WaitForChild(L,math.huge)end return c end end function WeaponsSystem.setWeaponEquipped(L,c)assert(not IsServer,"\087\101\097\112\111\110\115\083\121\115\116\101\109\046\115\101\116\087\101\097\112\111\110\069\113\117\105\112\112\101\100 \115\104\111\117\108\100 \111\110\108\121 \098\101 \099\097\108\108\101\100 \111\110 \116\104\101 \099\108\105\101\110\116\046")if not L then return end local U=WeaponsSystem.currentWeapon local M=false local r=false if U==L then if not c then WeaponsSystem.currentWeapon=nil M=false r=true else r=false end else if c then WeaponsSystem.currentWeapon=L M=true r=true end end if WeaponsSystem.camera then WeaponsSystem.camera:resetZoomFactor()WeaponsSystem.camera:setHasScope(false)if WeaponsSystem.currentWeapon then WeaponsSystem.camera:setZoomFactor(WeaponsSystem.currentWeapon:getConfigValue("\090\111\111\109\070\097\099\116\111\114",1.1))WeaponsSystem.camera:setHasScope(WeaponsSystem.currentWeapon:getConfigValue("\072\097\115\083\099\111\112\101",false))end end if WeaponsSystem.gui then WeaponsSystem.gui:setEnabled(M)if WeaponsSystem.currentWeapon then WeaponsSystem.gui:setCrosshairWeaponScale(WeaponsSystem.currentWeapon:getConfigValue("\067\114\111\115\115\104\097\105\114\083\099\097\108\101",1))else WeaponsSystem.gui:setCrosshairWeaponScale(1)end end if r then WeaponsSystem.CurrentWeaponChanged:Fire(L.instance,U and U.instance)end end function WeaponsSystem.getHumanoid(L)while L and L~=workspace do if L:IsA("\077\111\100\101\108")and(L.PrimaryPart and L.PrimaryPart.Name=="\072\117\109\097\110\111\105\100\082\111\111\116\080\097\114\116")then return L:FindFirstChildOfClass("\072\117\109\097\110\111\105\100")end L=L.Parent end end function WeaponsSystem.getPlayerFromHumanoid(L)for c,U in ipairs(Players:GetPlayers())do if U.Character and L:IsDescendantOf(U.Character)then return U end end end local function L(L,c,U,M,r,W,A)if c:IsA("\072\117\109\097\110\111\105\100")then c:TakeDamage(U)end end function WeaponsSystem.doDamage(c,U,M,r,W,A)if not c or ancestorHasTag(c,"\087\101\097\112\111\110\115\083\121\115\116\101\109\073\103\110\111\114\101")then return end if IsServer then if c:IsA("\072\117\109\097\110\111\105\100")and(r:IsA("\080\108\097\121\101\114")and r.Character)then local L=r.Character:FindFirstChildOfClass("\072\117\109\097\110\111\105\100")local U=Players:GetPlayerFromCharacter(c.Parent)if L and(c~=L and U)then WeaponData:FireClient(U,"\072\105\116\066\121\079\116\104\101\114\080\108\097\121\101\114",r.Character.HumanoidRootPart.CFrame.Position)end end local q=_damageCallback or L q(WeaponsSystem,c,U,M,r,W,A)end end local function c(L)return 0 end function WeaponsSystem.getTeam(L)local U=_getTeamCallback or c return U(L)end function WeaponsSystem.playersOnDifferentTeams(L,c)if L==c or L==nil or c==nil then return true end local U=WeaponsSystem.getTeam(L)local M=WeaponsSystem.getTeam(c)return U==0 or U~=M end return WeaponsSystem


function WeaponsSystem.onWeaponAdded(weaponInstance)
	local weapon = WeaponsSystem.getWeaponForInstance(weaponInstance)
	if not weapon then
		WeaponsSystem.createWeaponForInstance(weaponInstance)
	end
end

function WeaponsSystem.onWeaponRemoved(weaponInstance)
	local weapon = WeaponsSystem.getWeaponForInstance(weaponInstance)
	if weapon then
		weapon:onDestroyed()
	end
	WeaponsSystem.knownWeapons[weaponInstance] = nil
end

function WeaponsSystem.getRemoteEvent(name)
	if not WeaponsSystem.networkFolder then
		return
	end

	local remoteEvent = WeaponsSystem.remoteEvents[name]
	if IsServer then
		if not remoteEvent then
			warn("No RemoteEvent named ", name)
			return nil
		end

		return remoteEvent
	else
		if not remoteEvent then
			remoteEvent = WeaponsSystem.networkFolder:WaitForChild(name, math.huge)
		end

		return remoteEvent
	end
end

function WeaponsSystem.getRemoteFunction(name)
	if not WeaponsSystem.networkFolder then
		return
	end

	local remoteFunc = WeaponsSystem.remoteFunctions[name]
	if IsServer then
		if not remoteFunc then
			warn("No RemoteFunction named ", name)
			return nil
		end

		return remoteFunc
	else
		if not remoteFunc then
			remoteFunc = WeaponsSystem.networkFolder:WaitForChild(name, math.huge)
		end

		return remoteFunc
	end
end

function WeaponsSystem.setWeaponEquipped(weapon, equipped)
	assert(not IsServer, "WeaponsSystem.setWeaponEquipped should only be called on the client.")
	if not weapon then
		return
	end

	local lastWeapon = WeaponsSystem.currentWeapon
	local hasWeapon = false
	local weaponChanged = false

	if lastWeapon == weapon then
		if not equipped then
			WeaponsSystem.currentWeapon = nil
			hasWeapon = false
			weaponChanged = true
		else
			weaponChanged = false
		end
	else
		if equipped then
			WeaponsSystem.currentWeapon = weapon
			hasWeapon = true
			weaponChanged = true
		end
	end

	if WeaponsSystem.camera then
		WeaponsSystem.camera:resetZoomFactor()
		WeaponsSystem.camera:setHasScope(false)

		if WeaponsSystem.currentWeapon then
			WeaponsSystem.camera:setZoomFactor(WeaponsSystem.currentWeapon:getConfigValue("ZoomFactor", 1.1))
			WeaponsSystem.camera:setHasScope(WeaponsSystem.currentWeapon:getConfigValue("HasScope", false))
		end
	end

	if WeaponsSystem.gui then
		WeaponsSystem.gui:setEnabled(hasWeapon)

		if WeaponsSystem.currentWeapon then
			WeaponsSystem.gui:setCrosshairWeaponScale(WeaponsSystem.currentWeapon:getConfigValue("CrosshairScale", 1))
		else
			WeaponsSystem.gui:setCrosshairWeaponScale(1)
		end
	end

	if weaponChanged then
		WeaponsSystem.CurrentWeaponChanged:Fire(weapon.instance, lastWeapon and lastWeapon.instance)
	end
end

function WeaponsSystem.getHumanoid(part)
	while part and part ~= workspace do
		if part:IsA("Model") and part.PrimaryPart and part.PrimaryPart.Name == "HumanoidRootPart" then
			return part:FindFirstChildOfClass("Humanoid")
		end

		part = part.Parent
	end
end

function WeaponsSystem.getPlayerFromHumanoid(humanoid)
	for _, player in ipairs(Players:GetPlayers()) do
		if player.Character and humanoid:IsDescendantOf(player.Character) then
			return player
		end
	end
end

local function _defaultDamageCallback(system, target, amount, damageType, dealer, hitInfo, damageData)
	if target:IsA("Humanoid") then
		target:TakeDamage(amount)
	end
end

function WeaponsSystem.doDamage(target, amount, damageType, dealer, hitInfo, damageData)
	if not target or ancestorHasTag(target, "WeaponsSystemIgnore") then
		return
	end
	if IsServer then
		if target:IsA("Humanoid") and dealer:IsA("Player") and dealer.Character then
			local dealerHumanoid = dealer.Character:FindFirstChildOfClass("Humanoid")
			local targetPlayer = Players:GetPlayerFromCharacter(target.Parent)
			if dealerHumanoid and target ~= dealerHumanoid and targetPlayer then
				-- Trigger the damage indicator
				WeaponData:FireClient(targetPlayer, "HitByOtherPlayer", dealer.Character.HumanoidRootPart.CFrame.Position)
			end
		end

		-- NOTE:  damageData is a more or less free-form parameter that can be used for passing information from the code that is dealing damage about the cause.
		-- .The most obvious usage is extracting icons from the various weapon types (in which case a weapon instance would likely be passed in)
		-- ..The default weapons pass in that data
		local handler = _damageCallback or _defaultDamageCallback
		handler(WeaponsSystem, target, amount, damageType, dealer, hitInfo, damageData)
	end
end

local function _defaultGetTeamCallback(player)
	return 0
end

function WeaponsSystem.getTeam(player)
	local handler = _getTeamCallback or _defaultGetTeamCallback
	return handler(player)
end

function WeaponsSystem.playersOnDifferentTeams(player1, player2)
	if player1 == player2 or player1 == nil or player2 == nil then
		-- This allows players to damage themselves and NPC's
		return true
	end

	local player1Team = WeaponsSystem.getTeam(player1)
	local player2Team = WeaponsSystem.getTeam(player2)
	return player1Team == 0 or player1Team ~= player2Team
end

return WeaponsSystem
