btw i did not use ai, comment above .new() is for autocompletion, so i know what to put in args
module (oop-ish)
local Weapon = {}
Weapon.__index = Weapon
Weapon.weaponRegistry = {}
export type Weapon = typeof(setmetatable({} :: {
template: Tool,
name: string,
damage: number,
hitSpeed: number,
speedModifier: number
}, Weapon))
--[[
Constructs a new instance of class Weapon
template: Dummy Tool to use as a base
name: Unique identifier for the weapon
damage: Damage dealt per hit
hitSpeed: Time (in seconds) between each hit
speedModifier: Walkspeed multiplier when held
]]--
function Weapon.new(cfg: {any}): Weapon
local self = setmetatable({}, Weapon)
self.template = cfg.template or error("arsenal.Weapon.new() -> templatel set")
self.name = cfg.name or error("arsenal.Weapon.new() -> No name set")
self.damage = cfg.damage or error("arsenal.Weapon.new() -> No damage set")
self.hitSpeed = cfg.hitSpeed or error("arsenal.Weapon.new() -> No hitSpeed set")
self.speedModifier = cfg.speedModifier or 1
return self
end
function Weapon:init(): ()
local tool: Tool = self.template:Clone()
tool.Activated:Connect(function()
print("activated")
end)
Weapon.weaponRegistry[self] = tool
end
return Weapon
server script that uses this (below)
local Weapon = require(game.ReplicatedStorage.Weapon)
game.Players.PlayerAdded:Connect(function(plr)
plr.CharacterAdded:Connect(function(char)
for _, kid in char:GetDescendants() do
if kid:IsA("BasePart") then
kid.CollisionGroup = "Player"
end
end
end)
end)
Weapon.new({
template = game.ServerStorage.Dummies.Katana,
name = "Katana",
damage = 7,
hitSpeed = 0.3,
speedModifier = 1.12
}):init()
for wep: Weapon.Weapon, tool: Tool in Weapon.weaponRegistry do
tool:Clone().Parent = game.StarterPack
end

it's simple, crude, but extremely effective and very beginner-friendly compared to metatable inheritence if you never used metatables before.