-- 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