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

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
		local Player = Players:GetPlayerFromCharacter(target.Parent)
		if not Player and target.Health > 0 then
			target:TakeDamage(amount)
			-- Check if target is dead after applying damage
			if target.Health <= 0 and dealer and dealer.leaderstats and dealer.leaderstats.Kills then
				dealer.leaderstats.Kills.Value = dealer.leaderstats.Kills.Value + 1
			end
		end
	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
