How would I make guns automatic using this modular framework?

Heya There!!

I’m working on a modular framework and I’m wondering how I would make automatic guns fire by holding down Mouse1. How the system works is that whenever a player equips a tool (which is a gear, not a model), a module script gets the tools settings which is a module script inside of the tool.

Of course, the settings will include stuff like ammo, damage, and if its automatic or not. How would I go by detecting to see if the tool is automatic?

InputController (LocalScript)

--[[SERVICES]]--
local Players = game:GetService("Players")
local ContextActionService = game:GetService("ContextActionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

--[[FOLDERS]]--
local ClientModules = ReplicatedStorage:WaitForChild("ClientModules")
local RemoteEvents = ReplicatedStorage:WaitForChild("RemoteEvents")
local Weaponry = ReplicatedStorage:WaitForChild("Weaponry")

--[[MODULES]]--
local BaseGun = require(ReplicatedStorage.ClientModules.BaseGun)

--[[VARIABLES]]--
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local PlayerMouse = Player:GetMouse()

--[[CONTROLS]]--
Character.ChildAdded:Connect(function(Child)
	if Child:IsA("Tool") then
		BaseGun:Equip(Child)
		
		--//Functions
		local function Fire(actionName, inputState, inputObject)
			BaseGun:Fire(Character, Child:WaitForChild("Base"), PlayerMouse.Hit.Position)
		end
		
		--//Bind
		ContextActionService:BindAction("Fire",Fire,false,Enum.UserInputType.MouseButton1)
	end
end)

BaseGun (ModuleScript)

--[[SERVICES]]--
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Debris = game:GetService("Debris")

--[[FOLDERS]]--
local RemoteEvents = ReplicatedStorage:WaitForChild("RemoteEvents")

--[[MODULE]]--
local BaseGunModule = {}
BaseGunModule.__index = BaseGunModule

function BaseGunModule:Equip(Weapon)
	self.Settings = require(Weapon:WaitForChild("Settings"))
	
	--//Extra variables
	self.LastFire = 0
	self.AmmoRemember = self.Settings.AmmoHold
end

function BaseGunModule:Fire(Wielder, A, B)
	--//Firerate/Debounce
	local Now = os.clock()
	if Now - self.LastFire < self.Settings.Firerate then warn("On cooldown. Stop.") return end
	self.LastFire = Now
	
	--//Checking to see if the gun has enough ammo
	if self.Settings.AmmoHold >= 1 then
		--//Firing the gun
		self.Settings.AmmoHold -= 1

		local RaycastParam = RaycastParams.new()
		RaycastParam.FilterDescendantsInstances = {Wielder}
		RaycastParam.FilterType = Enum.RaycastFilterType.Exclude

		local Raycast = workspace:Raycast(A.Position, (B - A.Position).Unit * 5000, RaycastParam)
		local RaycastInstance = Raycast.Instance
		if RaycastInstance then
			--//Humanoid check & damage
			local Humanoid = RaycastInstance.Parent:FindFirstChildWhichIsA("Humanoid")
			if not Humanoid then
				--//The raycast didn't hit a humanoid.
				return
			end

			if Humanoid and Humanoid.Health >= 1 then
				Humanoid:TakeDamage(self.Settings.BaseDamage)
				RemoteEvents.Fire:FireServer(Humanoid, self.Settings.BaseDamage)
			end
			
			--//Raycasting
			self:Trace(A.Position, RaycastInstance.Position, B)
		else
			--//Raycasting if we didn't hit anything or hit a part.
			local EndPoint = A + (B - A.Position).Unit * 5000
			self:Trace(A, EndPoint)
		end
	else
		self:Reload()
	end
end

function BaseGunModule:Reload()
	--//Reloading the gun if we have enough ammo.
	if self.Settings.AmmoContain >= 1 then
		self.Settings.AmmoHold = self.AmmoRemember
		self.Settings.AmmoContain -= self.Settings.AmmoHold
	else
		warn("Find a refill station. You do not have any ammo remaining.")
	end
	
end

--//Tracing
function BaseGunModule:Trace(A, B, C)
	local Tracer = Instance.new("Part",workspace.Debris)
	local Distance = (A - B).Magnitude
	
	--//Customizing
	Tracer.Anchored = true
	Tracer.CanQuery = false
	Tracer.Material = Enum.Material.Neon
	Tracer.BrickColor = BrickColor.Yellow()
	Tracer.Size = Vector3.new(0.1, 0.1, Distance)
	Tracer.Transparency = 0.8
	Tracer.CastShadow = false
	
	--//Positioning
	Tracer.CFrame = CFrame.lookAt(A, C) * CFrame.new(0, 0, -Distance/2)
	Debris:AddItem(Tracer,0.05)
end

return BaseGunModule

Hello!

There’s tons of methods of achieving this, however the one I’d consider is to use ContextActionService and wait until the player lets go of MouseButton1, while it’s held you can and if the weapon is automatic you can use the Fire function from the module as I’m pretty sure it already has a debounce.

You would have to tinker a bit with how the function is handled and make it loop. Anyways hope this helps, let me know if you need further assistance!

Dont overcomplicate it.

Use a lot of if statements and dictionaries.

To store the data use attributes or use a modulescript with a dictionary data labeled gunId with a value regarding the properties you want. The gunId can be the name of the gun for easier recognition and organization.

I should’ve posted the settings module inside of the post. I’d also like you to know that the modular framework takes inspiration from EgoMoose’s FPS framework

(I know its quite barebones)

local WeaponSettings = {
	BaseDamage = 5,
	MinimumDamage = 15,
	MaxiumumDamage = 150,
	AmmoHold = 150,
	AmmoContain = 750,
	BulletSpread = 0.5,
	Firerate = 0.02,
	Automatic = true
}



return WeaponSettings