
Key RequiredUniversal

-- main module
-- by COOlInkKid
-- universal script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
-- Weapons module
local WeaponModule = {}
WeaponModule.__index = WeaponModule
-- Configuration
local WEAPON_CONFIGS = {
["AssaultRifle"] = {
Damage = 25,
FireRate = 0.15, -- секунд между выстрелами
MagazineSize = 30,
ReloadTime = 2.5,
MaxAmmo = 180,
Spread = 3, -- градусы
Range = 500
},
["Pistol"] = {
Damage = 35,
FireRate = 0.4,
MagazineSize = 12,
ReloadTime = 1.8,
MaxAmmo = 60,
Spread = 2,
Range = 300
}
}
function WeaponModule.new(weaponType, owner)
local self = setmetatable({}, WeaponModule)
self.WeaponType = weaponType
self.Owner = owner
self.Config = WEAPON_CONFIGS[weaponType] or WEAPON_CONFIGS["AssaultRifle"]
-- Unknown
self.CurrentAmmo = self.Config.MagazineSize
self.TotalAmmo = self.Config.MaxAmmo
self.IsReloading = false
self.CanFire = true
self.Equipped = false
return self
end
function WeaponModule:Fire(mousePosition)
if not self.CanFire or self.IsReloading or self.CurrentAmmo <= 0 then
return
end
self.CanFire = false
self.CurrentAmmo -= 1
-- visual effects
self:PlayFireEffects()
-- Logic hit
local hitResult = self:CalculateHit(mousePosition)
if hitResult and hitResult.Instance then
self:ProcessHit(hitResult)
end
-- sound fire
self:PlaySound("Fire")
-- Automatic reload
if self.CurrentAmmo <= 0 then
self:StartReload()
else
-- fireRate wait
task.wait(self.Config.FireRate)
self.CanFire = true
end
end
function WeaponModule:CalculateHit(mousePosition)
local character = self.Owner.Character
if not character then return end
local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
if not humanoidRootPart then return end
-- spread
local spread = math.rad(self.Config.Spread)
local direction = (mousePosition - humanoidRootPart.Position).Unit
direction = direction + Vector3.new(
(math.random() - 0.5) * spread,
(math.random() - 0.5) * spread,
(math.random() - 0.5) * spread
)
-- result raycast
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {character}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local raycastResult = workspace:Raycast(
humanoidRootPart.Position,
direction * self.Config.Range,
raycastParams
)
return raycastResult
end
function WeaponModule:ProcessHit(hitResult)
local hitPart = hitResult.Instance
local humanoid = hitPart.Parent:FindFirstChildOfClass("Humanoid")
if humanoid then
-- damage
humanoid:TakeDamage(self.Config.Damage)
-- effects
self:CreateHitEffect(hitResult.Position)
-- unknown
self:ShowHitMarker()
end
end
function WeaponModule:StartReload()
if self.IsReloading or self.CurrentAmmo == self.Config.MagazineSize then
return
end
local ammoNeeded = self.Config.MagazineSize - self.CurrentAmmo
if self.TotalAmmo <= 0 or ammoNeeded <= 0 then
return
end
self.IsReloading = true
self.CanFire = false
-- sounds reload
self:PlaySound("Reload")
-- Visualisation
self:ShowReloadIndicator()
task.wait(self.Config.ReloadTime)
-- unknown
local ammoToReload = math.min(ammoNeeded, self.TotalAmmo)
self.CurrentAmmo += ammoToReload
self.TotalAmmo -= ammoToReload
self.IsReloading = false
self.CanFire = true
-- Update UI
self:UpdateAmmoUI()
end
function WeaponModule:PlayFireEffects()
-- logic effects
-- Мuzzle flash, trassers
end
function WeaponModule:CreateHitEffect(position)
local hitEffect = Instance.new("Part")
hitEffect.Size = Vector3.new(0.2, 0.2, 0.2)
hitEffect.Position = position
hitEffect.Material = Enum.Material.Neon
hitEffect.Color = Color3.fromRGB(255, 50, 50)
hitEffect.Anchored = true
hitEffect.CanCollide = false
hitEffect.Parent = workspace
game.Debris:AddItem(hitEffect, 0.5)
end
function WeaponModule:ShowHitMarker()
-- logic update UI
end
function WeaponModule:ShowReloadIndicator()
-- logic indicators
end
function WeaponModule:UpdateAmmoUI()
-- update system
end
function WeaponModule:PlaySound(soundType)
-- sound logic
end
-- Control system weapons
local WeaponController = {}
WeaponController.__index = WeaponController
function WeaponController.new(player)
local self = setmetatable({}, WeaponController)
self.Player = player
self.CurrentWeapon = nil
self.Weapons = {}
self:SetupInput()
return self
end
function WeaponController:SetupInput()
local playerGui = self.Player:WaitForChild("PlayerGui")
UserInputService.InputBegan:Connect(function(input, gameProcessed)
if gameProcessed then return end
if input.UserInputType == Enum.UserInputType.MouseButton1 then
self:OnMouseClick()
elseif input.KeyCode == Enum.KeyCode.R then
self:OnReloadKey()
elseif input.KeyCode == Enum.KeyCode.One then
self:SwitchWeapon("AssaultRifle")
elseif input.KeyCode == Enum.KeyCode.Two then
self:SwitchWeapon("Pistol")
end
end)
end
function WeaponController:OnMouseClick()
if self.CurrentWeapon then
local mouse = self.Player:GetMouse()
self.CurrentWeapon:Fire(mouse.Hit.Position)
end
end
function WeaponController:OnReloadKey()
if self.CurrentWeapon then
self.CurrentWeapon:StartReload()
end
end
function WeaponController:SwitchWeapon(weaponType)
if self.Weapons[weaponType] then
self.CurrentWeapon = self.Weapons[weaponType]
self:UpdateWeaponUI()
else
self:AddWeapon(weaponType)
end
end
function WeaponController:AddWeapon(weaponType)
local newWeapon = WeaponModule.new(weaponType, self.Player)
self.Weapons[weaponType] = newWeapon
self.CurrentWeapon = newWeapon
self:UpdateWeaponUI()
end
function WeaponController:UpdateWeaponUI()
-- update weapons system
end
-- Initialisation system
local function onPlayerAdded(player)
local controller = WeaponController.new(player)
-- unknown
task.wait(1)
controller:AddWeapon("AssaultRifle")
controller:AddWeapon("Pistol")
end
-- unknown
Players.PlayerAdded:Connect(onPlayerAdded)
for _, player in ipairs(Players:GetPlayers()) do
task.spawn(onPlayerAdded, player)
end
return WeaponModule



Warning! I haven't tested it and don't know if it works at all.