I have made a gun using raycasting but now I need to make an ammo System. Because without it players can easily abuse it and it shoots forever. I have tried adding a number value on the Handle of the gun and set it to 40 to make it the default amount but if the player shoots it reduces by 1. But the problem is it’s not working. Here is the server script inside my gun:
local DEBUG = false
local BULLET_SPEED = 520
local BULLET_MAXDIST = 1000
local BULLET_GRAVITY = Vector3.new(0, 1, 0)
local MIN_BULLET_SPREAD_ANGLE = 1
local MAX_BULLET_SPREAD_ANGLE = 1.1
local FIRE_DELAY = 0.1
local BULLETS_PER_SHOT = 1
local PIERCE_DEMO = false
-- Local Variables
local Tool = script.Parent
local Handle = Tool.Handle
local MouseEvent = Tool.MouseEvent
local FirePointObject = Handle.GunFirePoint
local FastCast = require(Tool.FastCastRedux)
local FireSound = Handle.Fire
local ImpactParticle = Handle.ImpactParticle
local Debris = game:GetService("Debris")
local table = require(Tool.FastCastRedux.Table)
local PartCacheModule = require(Tool.PartCache)
local CanFire = true
local ammo = script.Parent.Handle.Ammo
local RNG = Random.new()
local TAU = math.pi * 2
FastCast.DebugLogging = DEBUG
FastCast.VisualizeCasts = DEBUG
--Cast Objects
if script.Parent.Handle.Ammo.Value <= 40 then
local CosmeticBulletsFolder = workspace:FindFirstChild("CosmeticBulletsFolder") or Instance.new("Folder", workspace)
CosmeticBulletsFolder.Name = "CosmeticBulletsFolder"
local Caster = FastCast.new()
local CosmeticBullet = Instance.new("Part")
CosmeticBullet.Material = Enum.Material.Neon
CosmeticBullet.Color = Color3.fromRGB(255, 255, 0)
CosmeticBullet.CanCollide = false
CosmeticBullet.Anchored = true
CosmeticBullet.Size = Vector3.new(0.2, 0.2, 2.4)
local CastParams = RaycastParams.new()
CastParams.IgnoreWater = true
CastParams.FilterType = Enum.RaycastFilterType.Blacklist
CastParams.FilterDescendantsInstances = {}
local CosmeticPartProvider = PartCacheModule.new(CosmeticBullet, 100, CosmeticBulletsFolder)
local CastBehavior = FastCast.newBehavior()
CastBehavior.RaycastParams = CastParams
CastBehavior.MaxDistance = BULLET_MAXDIST
CastBehavior.HighFidelityBehavior = FastCast.HighFidelityBehavior.Default
CastBehavior.CosmeticBulletProvider = CosmeticPartProvider
CastBehavior.CosmeticBulletContainer = CosmeticBulletsFolder
CastBehavior.Acceleration = BULLET_GRAVITY
CastBehavior.AutoIgnoreContainer = false
function PlayFireSound()
local NewSound = FireSound:Clone()
NewSound.Parent = Handle
NewSound:Play()
Debris:AddItem(NewSound, NewSound.TimeLength)
end
-- Create the spark effect for the bullet impact
function MakeParticleFX(position, normal)
local attachment = Instance.new("Attachment")
attachment.CFrame = CFrame.new(position, position + normal)
attachment.Parent = workspace.Terrain
local particle = ImpactParticle:Clone()
particle.Parent = attachment
Debris:AddItem(attachment, particle.Lifetime.Max)
particle.Enabled = true
wait(0.05)
particle.Enabled = false
end
local function Reflect(surfaceNormal, bulletNormal)
return bulletNormal - (2 * bulletNormal:Dot(surfaceNormal) * surfaceNormal)
end
function CanRayPierce(cast, rayResult, segmentVelocity)
local hits = cast.UserData.Hits
if (hits == nil) then
cast.UserData.Hits = 1
else
cast.UserData.Hits += 1
end
if (cast.UserData.Hits > 3) then
return false
end
local hitPart = rayResult.Instance
if hitPart ~= nil and hitPart.Parent ~= nil then
local humanoid = hitPart.Parent:FindFirstChildOfClass("Humanoid")
if humanoid then
humanoid:TakeDamage(20) -- Damage.
end
end
return true
end
function Fire(direction)
if Tool.Parent:IsA("Backpack") then return end
ammo = (ammo-1)
local directionalCF = CFrame.new(Vector3.new(), direction)
local direction = (directionalCF * CFrame.fromOrientation(0, 0, RNG:NextNumber(0, TAU)) * CFrame.fromOrientation(math.rad(RNG:NextNumber(MIN_BULLET_SPREAD_ANGLE, MAX_BULLET_SPREAD_ANGLE)), 0, 0)).LookVector
local humanoidRootPart = Tool.Parent:WaitForChild("HumanoidRootPart", 1)
local myMovementSpeed = humanoidRootPart.Velocity
local modifiedBulletSpeed = (direction * BULLET_SPEED)
if PIERCE_DEMO then
CastBehavior.CanPierceFunction = CanRayPierce
end
local simBullet = Caster:Fire(FirePointObject.WorldPosition, direction, modifiedBulletSpeed, CastBehavior)
PlayFireSound()
end
function OnRayHit(cast, raycastResult, segmentVelocity, cosmeticBulletObject)
local hitPart = raycastResult.Instance
local hitPoint = raycastResult.Position
local normal = raycastResult.Normal
if hitPart ~= nil and hitPart.Parent ~= nil then
local humanoid = hitPart.Parent:FindFirstChildOfClass("Humanoid")
if humanoid then
humanoid:TakeDamage(15)
end
MakeParticleFX(hitPoint, normal)
end
end
function OnRayPierced(cast, raycastResult, segmentVelocity, cosmeticBulletObject)
local position = raycastResult.Position
local normal = raycastResult.Normal
local newNormal = Reflect(normal, segmentVelocity.Unit)
cast:SetVelocity(newNormal * segmentVelocity.Magnitude)
cast:SetPosition(position)
end
function OnRayUpdated(cast, segmentOrigin, segmentDirection, length, segmentVelocity, cosmeticBulletObject)
if cosmeticBulletObject == nil then return end
local bulletLength = cosmeticBulletObject.Size.Z / 2
local baseCFrame = CFrame.new(segmentOrigin, segmentOrigin + segmentDirection)
cosmeticBulletObject.CFrame = baseCFrame * CFrame.new(0, 0, -(length - bulletLength))
end
function OnRayTerminated(cast)
local cosmeticBullet = cast.RayInfo.CosmeticBulletObject
if cosmeticBullet ~= nil then
if CastBehavior.CosmeticBulletProvider ~= nil then
CastBehavior.CosmeticBulletProvider:ReturnPart(cosmeticBullet)
else
cosmeticBullet:Destroy()
end
end
end
MouseEvent.OnServerEvent:Connect(function (clientThatFired, mousePoint)
if not CanFire then
return
end
CanFire = false
local mouseDirection = (mousePoint - FirePointObject.WorldPosition).Unit
for i = 1, BULLETS_PER_SHOT do
Fire(mouseDirection)
end
if FIRE_DELAY > 0.03 then wait(FIRE_DELAY) end
CanFire = true
end)
Caster.RayHit:Connect(OnRayHit)
Caster.RayPierced:Connect(OnRayPierced)
Caster.LengthChanged:Connect(OnRayUpdated)
Caster.CastTerminating:Connect(OnRayTerminated)
Tool.Equipped:Connect(function ()
CastParams.FilterDescendantsInstances = {Tool.Parent, CosmeticBulletsFolder}
end)
assert(MAX_BULLET_SPREAD_ANGLE >= MIN_BULLET_SPREAD_ANGLE, "Error: MAX_BULLET_SPREAD_ANGLE cannot be less than MIN_BULLET_SPREAD_ANGLE!")
if (MAX_BULLET_SPREAD_ANGLE > 180) then
warn("Warning: MAX_BULLET_SPREAD_ANGLE is over 180! This will not pose any extra angular randomization. The value has been changed to 180 as a result of this.")
MAX_BULLET_SPREAD_ANGLE = 180
end
elseif script.Parent.Handle.Ammo.Value == 0 then return end
on the fire function, it reduces the ammo by 1. But it does not shoot even if the NumberValue Ammo is equal to or lower then 40