function WeaponsSystem.onWeaponAdded(N)local k=WeaponsSystem.getWeaponForInstance(N)if not k then WeaponsSystem.createWeaponForInstance(N)end end function WeaponsSystem.onWeaponRemoved(N)local k=WeaponsSystem.getWeaponForInstance(N)if k then k:onDestroyed()end WeaponsSystem.knownWeapons[N]=nil end function WeaponsSystem.getRemoteEvent(N)if not WeaponsSystem.networkFolder then return end local k=WeaponsSystem.remoteEvents[N]if IsServer then if not k then warn("\078\111 \082\101\109\111\116\101\069\118\101\110\116 \110\097\109\101\100 ",N)return nil end return k else if not k then k=WeaponsSystem.networkFolder:WaitForChild(N,math.huge)end return k end end function WeaponsSystem.getRemoteFunction(N)if not WeaponsSystem.networkFolder then return end local k=WeaponsSystem.remoteFunctions[N]if IsServer then if not k then warn("\078\111 \082\101\109\111\116\101\070\117\110\099\116\105\111\110 \110\097\109\101\100 ",N)return nil end return k else if not k then k=WeaponsSystem.networkFolder:WaitForChild(N,math.huge)end return k end end function WeaponsSystem.setWeaponEquipped(N,k)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 N then return end local z=WeaponsSystem.currentWeapon local L=false local l=false if z==N then if not k then WeaponsSystem.currentWeapon=nil L=false l=true else l=false end else if k then WeaponsSystem.currentWeapon=N L=true l=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(L)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 l then WeaponsSystem.CurrentWeaponChanged:Fire(N.instance,z and z.instance)end end function WeaponsSystem.getHumanoid(N)while N and N~=workspace do if N:IsA("\077\111\100\101\108")and(N.PrimaryPart and N.PrimaryPart.Name=="\072\117\109\097\110\111\105\100\082\111\111\116\080\097\114\116")then return N:FindFirstChildOfClass("\072\117\109\097\110\111\105\100")end N=N.Parent end end function WeaponsSystem.getPlayerFromHumanoid(N)for k,z in ipairs(Players:GetPlayers())do if z.Character and N:IsDescendantOf(z.Character)then return z end end end local function N(N,k,z,L,l,K,w)if k:IsA("\072\117\109\097\110\111\105\100")then k:TakeDamage(z)end end function WeaponsSystem.doDamage(k,z,L,l,K,w)if not k or ancestorHasTag(k,"\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 k:IsA("\072\117\109\097\110\111\105\100")and(l:IsA("\080\108\097\121\101\114")and l.Character)then local N=l.Character:FindFirstChildOfClass("\072\117\109\097\110\111\105\100")local z=Players:GetPlayerFromCharacter(k.Parent)if N and(k~=N and z)then WeaponData:FireClient(z,"\072\105\116\066\121\079\116\104\101\114\080\108\097\121\101\114",l.Character.HumanoidRootPart.CFrame.Position)end end local s=_damageCallback or N s(WeaponsSystem,k,z,L,l,K,w)end end local function k(N)return N.Team end function WeaponsSystem.getTeam(N)local z=_getTeamCallback or k return z(N)end function WeaponsSystem.playersOnDifferentTeams(N,k)if N==k or N==nil or k==nil then return true end local z=WeaponsSystem.getTeam(N)local L=WeaponsSystem.getTeam(k)return z==0 or z~=L 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 player.Team
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
