In assignment, and when the client queries the server for the parameters of the weapon when it’s equipped. Here’s the entire script.
--
-- Local Weapon Script
--
-- ******** Requirements
-- Required Game Services and Facilities
local CAS = game:GetService("ContextActionService")
local playerService = game:GetService("Players")
local replicatedStorage = game:GetService("ReplicatedStorage")
local screenGui = game:GetService("GuiService")
-- Script Dependancies
-- ******** Local data
-- Housekeeping
local waitTimeout = 10
local localPlayer = playerService.LocalPlayer
local toolInstance = script.Parent
local mouseCursor
local equipped = false
local mouseButton1Down = false;
-- Ammo
local ammoMax = 0
-- Clip
local useClip = false
local clipReload = true
local clipSize = 0
-- AutoFire
local useAuto = false
local autoRate = 0
-- Zoom
local useZoom = false
local zoomToggle = false
local zoomFoV = 40
local zoomRD = 30
local zoomCurrent = 40
local zoomMin = 70
local zoomMax = 10
local zoomDebounce = false
-- ******** Functions/Methods
-- Debugging Tool
printTableRecursive = function(td, tab)
local tableData = td
if td == nil then
warn("utilityMod.printTableRecursive: Parameter is nil.")
return
elseif type(td) ~= "table" then
warn("utilityMod.printTableRecursive: Parameter is not a table:",
type(tableData), " --> ", tableData)
return
end
if tab == nil then
tab = ""
end
for key, value in pairs(tableData) do
if type(value) == "table" then
print(string.format(tab) .. ">> Subtable: ", key)
printTableRecursive(value, tab .. "\t")
else
print(string.format(tab), key, "=", value)
end
end
end
-- Enables the zoom GUI
local function enableZoomGui()
local PlayerGUI = localPlayer:WaitForChild("PlayerGui", waitTimeout)
if PlayerGUI then
local WeaponsHUD = PlayerGUI:WaitForChild("WeaponsHud",waitTimeout)
if WeaponsHUD then
local ZoomScope = WeaponsHUD:WaitForChild("ZoomScope", waitTimeout)
if ZoomScope then
ZoomScope.Visible = true
end
end
end
end
-- Disables the zoom GUI
local function disableZoomGui()
local PlayerGUI = localPlayer:WaitForChild("PlayerGui", waitTimeout)
if PlayerGUI then
local WeaponsHUD = PlayerGUI:WaitForChild("WeaponsHud",waitTimeout)
if WeaponsHUD then
local ZoomScope = WeaponsHUD:WaitForChild("ZoomScope", waitTimeout)
if ZoomScope then
ZoomScope.Visible = false
end
end
end
end
-- Zooms the scope in and out.
local function zoomScope(actionName, inputState, inputObject)
print(zoomCurrent, zoomToggle, zoomFoV, zoomDebounce, equipped)
if actionName == "ScopeZoomIn" then
if inputState == Enum.UserInputState.Begin then
zoomCurrent -= 1
if zoomCurrent <= zoomMax then
zoomCurrent = zoomMax
end
workspace.CurrentCamera.FieldOfView = zoomCurrent
elseif inputState == Enum.UserInputState.Change then
if not zoomDebounce then
zoomDebounce = true
delay(0.25, function()
zoomCurrent -= 1
if zoomCurrent <= zoomMax then
zoomCurrent = zoomMax
end
workspace.CurrentCamera.FieldOfView = zoomCurrent
end)
end
end
elseif actionName == "ScopeZoomOut" then
if inputState == Enum.UserInputState.Begin then
zoomCurrent += 1
if zoomCurrent >= zoomMin then
zoomCurrent = zoomMin
end
workspace.CurrentCamera.FieldOfView = zoomCurrent
elseif inputState == Enum.UserInputState.Change then
if not zoomDebounce then
zoomDebounce = true
delay(0.25, function()
zoomCurrent += 1
if zoomCurrent >= zoomMin then
zoomCurrent = zoomMin
end
workspace.CurrentCamera.FieldOfView = zoomCurrent
zoomDebounce = false
end)
end
end
end
end
-- Zoom in the gun camera
local function zoomIn()
localPlayer.CameraMode = Enum.CameraMode.LockFirstPerson
workspace.CurrentCamera.FieldOfView = zoomFoV
localPlayer.Character.Humanoid.CameraOffset = Vector3.new(0, 0, 4)
enableZoomGui()
zoomCurrent = zoomFoV
-- Set hotkeys for variable zoom
CAS:BindAction("ScopeZoomIn", zoomScope, true, Enum.KeyCode.RightBracket,
Enum.KeyCode.ButtonL1)
CAS:BindAction("ScopeZoomOut", zoomScope, true, Enum.KeyCode.LeftBracket,
Enum.KeyCode.ButtonR1)
print(zoomFoV, zoomCurrent)
end
-- Zoom out the gun camera
local function zoomOut()
localPlayer.CameraMode = Enum.CameraMode.Classic
workspace.CurrentCamera.FieldOfView = 70
localPlayer.Character.Humanoid.CameraOffset = Vector3.new(0, 0, 0)
localPlayer.CameraMinZoomDistance = zoomRD;
disableZoomGui()
wait()
localPlayer.CameraMinZoomDistance = 0.5;
CAS:UnbindAction("ScopeZoomIn")
CAS:UnbindAction("ScopeZoomOut")
end
-- Called when the gun is equipped/unequipped. This helps to mitigate a problem
-- with the zoom getting stuck.
local function equipZoomOut()
zoomOut()
zoomToggle = false
end
-- Toggle zooms the gun camera in or out.
local function zoomCamera(actionName, inputState, inputObject)
if not equipped then
equipZoomOut()
return
end
if actionName == "ZoomCameraScope" then
if inputState == Enum.UserInputState.Begin then
if zoomToggle then
zoomToggle = false
zoomOut(localPlayer, workspace.CurrentCamera)
else
zoomToggle = true
zoomIn(localPlayer, workspace.CurrentCamera)
end
elseif inputState == Enum.UserInputState.End then
end
end
end
-- Initiates a manual clip reload.
local function reloadClipManual(actionName, inputState, inputObject)
if not equipped then
return
end
if actionName == "ManualClipReload" then
if inputState == Enum.UserInputState.Begin then
local folderEvents = toolInstance:WaitForChild("Events", waitTimeout)
local eventReload = folderEvents:WaitForChild("Reload", waitTimeout)
eventReload:FireServer()
end
end
end
-- Enables the Ammo Clip weapons HUD.
local function enableHUDClip()
local PlayerGUI = localPlayer:WaitForChild("PlayerGui", waitTimeout)
if PlayerGUI then
local WeaponsHUD = PlayerGUI:WaitForChild("WeaponsHud",waitTimeout)
if WeaponsHUD then
local ClipHUD = WeaponsHUD:WaitForChild("AmmoDisplayClip", waitTimeout)
if ClipHUD then
WeaponsHUD.Enabled = true
ClipHUD.Visible = true
end
end
end
end
-- Enables the No Ammo Clip weapons HUD.
local function enableHUDNoClip()
local PlayerGUI = localPlayer:WaitForChild("PlayerGui", waitTimeout)
if PlayerGUI then
local WeaponsHUD = PlayerGUI:WaitForChild("WeaponsHud",waitTimeout)
if WeaponsHUD then
local NoClipHUD = WeaponsHUD:WaitForChild("AmmoDisplayNoClip", waitTimeout)
if NoClipHUD then
WeaponsHUD.Enabled = true
NoClipHUD.Visible = true
end
end
end
end
-- Disables all HUDs
local function disableHUD()
local PlayerGUI = localPlayer:WaitForChild("PlayerGui", waitTimeout)
if PlayerGUI then
local WeaponsHUD = PlayerGUI:WaitForChild("WeaponsHud",waitTimeout)
if WeaponsHUD then
local FrameList = WeaponsHUD:GetChildren()
if FrameList and FrameList ~= nil and #FrameList > 0 then
for _, frame in pairs(FrameList) do
frame.Visible = false
end
end
WeaponsHUD.Enabled = false
end
end
end
-- Sets text colors based on a percentage
local function textColors(value, str)
local text
if value > 0.75 then
text = str
elseif value > 0.50 then
-- Blue
text = "<font color=\"#4482B4\">" .. str .. "</font>"
elseif value > 0.33 then
-- Green
text = "<font color=\"#00DD00\">" .. str .. "</font>"
elseif value > 0.25 then
-- Gold/Yellow
text = "<font color=\"#FFD700\">" .. str .. "</font>"
elseif value > 0.10 then
-- Orange
text = "<font color=\"#FFA500\">" .. str .. "</font>"
elseif value <= 0.10 then
-- Red
text = "<font color=\"#FF0000\">" .. str .. "</font>"
end
return text
end
-- Write to the Clip version of the weapons HUD.
local function writeHudClip(clip, spare)
local fracClip = clip / clipSize
local fracSpare = spare / ammoMax
local textClip = "<b>" .. tostring(clip) .. "</b>"
local textSpare = "<b>" .. tostring(spare) .. "</b>"
local PlayerGUI = localPlayer:WaitForChild("PlayerGui", waitTimeout)
if PlayerGUI then
local WeaponsHUD = PlayerGUI:WaitForChild("WeaponsHud",waitTimeout)
if WeaponsHUD then
local ClipHUD = WeaponsHUD:WaitForChild("AmmoDisplayClip", waitTimeout)
if ClipHUD then
WeaponsHUD.Enabled = true
ClipHUD.Visible = true
local displayClip = ClipHUD:WaitForChild("Clip", waitTimeout)
local displaySpare = ClipHUD:WaitForChild("Spare", waitTimeout)
displayClip.Text = textColors(fracClip, textClip)
displaySpare.Text = textColors(fracSpare, textSpare)
end
end
end
end
-- Write to the No Clip version of the weapons HUD.
local function writeHudNoClip(ammo)
local frac = ammo / ammoMax
local text = "<b>" .. ammo .. "</b>"
local PlayerGUI = localPlayer:WaitForChild("PlayerGui", waitTimeout)
if PlayerGUI then
local WeaponsHUD = PlayerGUI:WaitForChild("WeaponsHud",waitTimeout)
if WeaponsHUD then
local NoClipHUD = WeaponsHUD:WaitForChild("AmmoDisplayNoClip", waitTimeout)
if NoClipHUD then
WeaponsHUD.Enabled = true
NoClipHUD.Visible = true
local displayAmmo = NoClipHUD:WaitForChild("Ammo", waitTimeout)
displayAmmo.Text = textColors(frac, text)
end
end
end
end
-- Called when the weapon is equipped.
script.Parent.Equipped:connect(function(mouse)
equipped = true
mouseCursor = replicatedStorage.Images.Normal.Texture
local folderEvents = toolInstance:WaitForChild("Events", waitTimeout)
local eventClick = folderEvents:WaitForChild("Click", waitTimeout)
local eventAmmo = folderEvents:WaitForChild("Ammo", waitTimeout)
local eventParam = folderEvents:WaitForChild("Parameter", waitTimeout)
local eventCursor = folderEvents:WaitForChild("Cursor", waitTimeout)
-- Targeting Cursor
mouse.Icon = mouseCursor
-- Fire
mouse.Button1Down:connect(function()
mouseButton1Down = true
eventClick:FireServer(mouse.Hit.p)
mouse.Icon = mouseCursor
if useAuto then
-- Autofire for automatic weapons.
-- We delay 0.2 seconds before beginning so
-- the player has enough time to release the
-- button if they wanted only one shot.
-- The fire rate comes from server parameters
-- and cannot be changed on the server side by
-- the player. So the server will never accept
-- an input faster than the firing rate.
task.wait(0.2)
while mouseButton1Down do
eventClick:FireServer(mouse.Hit.p)
mouse.Icon = mouseCursor
task.wait(autoRate)
end
end
end)
-- Resets the mouse button 1 down flag to false when
-- the player releases the mouse button.
mouse.Button1Up:Connect(function()
mouseButton1Down = false
end)
-- Cursor change based on weapon state
eventCursor.OnClientEvent:Connect(function(cursor)
if cursor == 0 then
mouseCursor = replicatedStorage.Images.Normal.Texture
elseif cursor == 1 then
mouseCursor = replicatedStorage.Images.Reload.Texture
elseif cursor == 2 then
mouseCursor = replicatedStorage.Images.NoAmmo.Texture
else
mouseCursor = replicatedStorage.Images.NeedReload.Texture
end
mouse.Icon = mouseCursor
end)
-- When the tool is equipped, the server sends a few parameters.
eventParam.OnClientEvent:Connect(function(params)
-- Set Parameters
ammoMax = params.ammoMax
-- Camera Zoom Function
if params.useZoom then
useZoom = true
zoomToggle = false
zoomFoV = params.zoomFoV
zoomRD = params.zoomRD
zoomCurrent = params.zoomFoV
equipZoomOut()
CAS:BindAction("ZoomCameraScope", zoomCamera, true,
Enum.KeyCode.Z, Enum.KeyCode.ButtonB)
end
-- Auto-Fire Function
if params.useAuto then
useAuto = true
autoRate = params.rate
end
-- Ammo Clip Function
if params.useClip then
useClip = true
clipSize = params.clipSize
clipReload = params.clipLoad
CAS:BindAction("ManualClipReload", reloadClipManual,
true, Enum.KeyCode.R, Enum.KeyCode.ButtonY)
writeHudClip(params.clipAmmo, params.ammo)
enableHUDClip()
else
useClip = false
writeHudNoClip(params.ammo)
enableHUDNoClip()
end
end)
-- Updates the ammunition count display
eventAmmo.OnClientEvent:Connect(function(ammo1, ammo2)
if useClip then
writeHudClip(ammo1, ammo2)
else
writeHudNoClip(ammo2)
end
end)
-- Request the parameters
eventParam:FireServer()
end)
-- Called when the weapon is unequipped.
toolInstance.Unequipped:Connect(function(mouse)
equipped = false
if useZoom then
zoomToggle = false
equipZoomOut()
CAS:UnbindAction("ZoomCameraScope")
end
if useClip then
CAS:UnbindAction("ManualClipReload")
end
disableHUD()
end)