Files
ClaudeCode-Roblox-Studio-MCP/examples/fps-game/part5_client.lua
Admin a66533206f Add FPS game example, auto-connect plugin, and Python injection tools
- Updated RobloxMCPPlugin with HTTP polling (auto-enables HttpService)
- Added 20-weapon FPS game example (CoD-style)
- Added Python studio-inject.py for command bar injection via Win32 API
- Added auto-connect setup scripts (VBS + PowerShell)
- Updated MCP server with all FPS game tools

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 16:57:35 +04:00

372 lines
12 KiB
Lua

-- ═══════════════════════════════════════════════════════════════════
-- MINI CALL OF DUTY - FPS Game Setup (Part 5: Weapon Client Script)
-- ═══════════════════════════════════════════════════════════════════
local SG = game:GetService("StarterGui")
-- Get the HUD that was already created in Part 4
local hudGui = SG:FindFirstChild("FPS_HUD")
-- Add the weapon controller LocalScript
local weaponScript = Instance.new("LocalScript")
weaponScript.Name = "WeaponController"
weaponScript.Parent = hudGui
weaponScript.Source = [[
local Players = game:GetService("Players")
local RS = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local UIS = game:GetService("UserInputService")
local Events = RS:WaitForChild("Events")
local Shared = RS:WaitForChild("Shared")
local WeaponData = require(Shared:WaitForChild("WeaponData"))
local player = Players.LocalPlayer
local camera = workspace.CurrentCamera
local mouse = player:GetMouse()
-- Weapon state
local currentWeapon = "M4A1"
local weapon = WeaponData[currentWeapon]
local ammo = weapon.magSize
local reserveAmmo = weapon.maxAmmo
local isReloading = false
local lastShot = 0
local isADS = false
local isSprinting = false
local isFiring = false
local recoilX = 0
local recoilY = 0
-- UI references
local scriptParent = script.Parent
local crosshair = scriptParent:WaitForChild("Crosshair")
local hitMarker = scriptParent:WaitForChild("HitMarker")
local weaponPanel = scriptParent:WaitForChild("WeaponPanel")
local ammoLabel = weaponPanel:WaitForChild("AmmoLabel")
local weaponLabel = weaponPanel:WaitForChild("WeaponName")
local reserveLabel = weaponPanel:WaitForChild("ReserveLabel")
local reloadBar = scriptParent:WaitForChild("ReloadBar")
local reloadFill = reloadBar:WaitForChild("Fill")
local scoreLabel = scriptParent:WaitForChild("ScoreFrame"):WaitForChild("ScoreLabel")
local damageVignette = scriptParent:WaitForChild("DamageVignette")
local kills = 0
local deaths = 0
local function updateHUD()
if ammoLabel then
ammoLabel.Text = ammo .. " / " .. reserveAmmo
if ammo <= math.floor(weapon.magSize * 0.25) then
ammoLabel.TextColor3 = Color3.fromRGB(255, 80, 80)
else
ammoLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
end
end
if weaponLabel then
weaponLabel.Text = weapon.displayName:upper()
end
if reserveLabel then
reserveLabel.Text = isReloading and "RELOADING..." or ""
end
if scoreLabel then
scoreLabel.Text = "KILLS: " .. kills .. " | DEATHS: " .. deaths
end
end
local function shoot()
if isReloading then return end
if ammo <= 0 then
-- Auto reload
if reserveAmmo > 0 then
-- Play empty click sound via visual feedback
end
return
end
if tick() - lastShot < weapon.fireRate then return end
lastShot = tick()
ammo = ammo - 1
-- Recoil
recoilX = recoilX + (math.random() - 0.5) * weapon.recoil.x
recoilY = weapon.recoil.y * 0.3
camera.CFrame = camera.CFrame * CFrame.Angles(
math.rad(-recoilY),
math.rad(recoilX * 0.1),
0
)
-- Spread
local spreadAmount = isADS and weapon.spread.ads or weapon.spread.hip
local spread = Vector3.new(
(math.random() - 0.5) * spreadAmount * 0.01,
(math.random() - 0.5) * spreadAmount * 0.01,
0
)
-- Raycast
local rayDirection = (camera.CFrame.LookVector + spread) * weapon.range
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local char = player.Character
if char then raycastParams.FilterDescendantsInstances = {char} end
local result = workspace:Raycast(camera.CFrame.Position, rayDirection, raycastParams)
-- Muzzle flash
local flash = Instance.new("Part")
flash.Size = Vector3.new(0.3, 0.3, 0.3)
flash.Shape = Enum.PartType.Ball
flash.Color = Color3.fromRGB(255, 200, 50)
flash.Material = Enum.Material.Neon
flash.Anchored = true
flash.CanCollide = false
flash.Position = camera.CFrame.Position + camera.CFrame.LookVector * 3
flash.Parent = workspace
game:GetService("Debris"):AddItem(flash, 0.04)
if result then
-- Bullet trail
local trail = Instance.new("Part")
local trailLen = (camera.CFrame.Position - result.Position).Magnitude
trail.Size = Vector3.new(0.08, 0.08, trailLen)
trail.CFrame = CFrame.new(camera.CFrame.Position, result.Position)
* CFrame.new(0, 0, -trailLen / 2)
trail.Anchored = true
trail.CanCollide = false
trail.Color = Color3.fromRGB(255, 220, 100)
trail.Material = Enum.Material.Neon
trail.Transparency = 0.4
trail.Parent = workspace
game:GetService("Debris"):AddItem(trail, 0.06)
-- Impact spark
local spark = Instance.new("Part")
spark.Size = Vector3.new(0.4, 0.4, 0.4)
spark.Shape = Enum.PartType.Ball
spark.Color = Color3.fromRGB(255, 180, 50)
spark.Material = Enum.Material.Neon
spark.Anchored = true
spark.CanCollide = false
spark.Position = result.Position
spark.Parent = workspace
game:GetService("Debris"):AddItem(spark, 0.12)
-- Smoke puff at impact
local smoke = Instance.new("Part")
smoke.Size = Vector3.new(1, 1, 1)
smoke.Shape = Enum.PartType.Ball
smoke.Color = Color3.fromRGB(120, 120, 110)
smoke.Transparency = 0.5
smoke.Anchored = true
smoke.CanCollide = false
smoke.Position = result.Position
smoke.Parent = workspace
game:GetService("Debris"):AddItem(smoke, 0.3)
-- Send to server
Events:WaitForChild("ShootEvent"):FireServer({
origin = camera.CFrame.Position,
direction = rayDirection,
hit = result.Instance,
hitPos = result.Position,
normal = result.Normal,
weapon = currentWeapon,
})
else
-- Shot into air - just trail to max range
local endPoint = camera.CFrame.Position + rayDirection
local trail = Instance.new("Part")
local trailLen = weapon.range
trail.Size = Vector3.new(0.06, 0.06, trailLen)
trail.CFrame = CFrame.new(camera.CFrame.Position, endPoint)
* CFrame.new(0, 0, -trailLen / 2)
trail.Anchored = true
trail.CanCollide = false
trail.Color = Color3.fromRGB(255, 220, 100)
trail.Material = Enum.Material.Neon
trail.Transparency = 0.5
trail.Parent = workspace
game:GetService("Debris"):AddItem(trail, 0.04)
end
-- Auto reload when empty
if ammo <= 0 and reserveAmmo > 0 then
task.delay(0.3, function() reload() end)
end
updateHUD()
end
local function reload()
if isReloading then return end
if ammo >= weapon.magSize then return end
if reserveAmmo <= 0 then return end
isReloading = true
reloadBar.Visible = true
local startTime = tick()
local conn
conn = RunService.RenderStepped:Connect(function()
local elapsed = tick() - startTime
local pct = math.clamp(elapsed / weapon.reloadTime, 0, 1)
reloadFill.Size = UDim2.new(pct * 200, 0, 1, 0)
if pct >= 1 then
conn:Disconnect()
local needed = weapon.magSize - ammo
local toLoad = math.min(needed, reserveAmmo)
ammo = ammo + toLoad
reserveAmmo = reserveAmmo - toLoad
isReloading = false
reloadBar.Visible = false
reloadFill.Size = UDim2.new(0, 0, 1, 0)
updateHUD()
end
end)
updateHUD()
end
-- Input handling
UIS.InputBegan:Connect(function(input, processed)
if processed then return end
if input.UserInputType == Enum.UserInputType.MouseButton2 then
isADS = true
if isSprinting then isSprinting = false end
end
if input.UserInputType == Enum.UserInputType.MouseButton1 then
isFiring = true
if not weapon.automatic then shoot() end
if isSprinting then isSprinting = false end
end
if input.KeyCode == Enum.KeyCode.LeftShift then
if not isADS then isSprinting = true end
end
if input.KeyCode == Enum.KeyCode.LeftControl then
local c = player.Character
if c then
local h = c:FindFirstChildOfClass("Humanoid")
if h then h.WalkSpeed = 8 end
end
end
if input.KeyCode == Enum.KeyCode.R then reload() end
-- Weapon switch
if input.KeyCode == Enum.KeyCode.One then currentWeapon = "M4A1"
elseif input.KeyCode == Enum.KeyCode.Two then currentWeapon = "AK47"
elseif input.KeyCode == Enum.KeyCode.Three then currentWeapon = "Sniper"
elseif input.KeyCode == Enum.KeyCode.Four then currentWeapon = "Shotgun" end
if input.KeyCode >= Enum.KeyCode.One and input.KeyCode <= Enum.KeyCode.Four then
weapon = WeaponData[currentWeapon]
ammo = weapon.magSize
reserveAmmo = weapon.maxAmmo
isReloading = false
reloadBar.Visible = false
updateHUD()
end
end)
UIS.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton2 then isADS = false end
if input.UserInputType == Enum.UserInputType.MouseButton1 then isFiring = false end
if input.KeyCode == Enum.KeyCode.LeftShift then isSprinting = false end
if input.KeyCode == Enum.KeyCode.LeftControl then
local c = player.Character
if c then
local h = c:FindFirstChildOfClass("Humanoid")
if h then h.WalkSpeed = 20 end
end
end
end)
-- Track kills/deaths from events
Events:WaitForChild("KillEvent").OnClientEvent:Connect(function(data)
if data.killer == player.Name then
kills = kills + 1
end
if data.victim == player.Name then
deaths = deaths + 1
end
updateHUD()
end)
-- Main loop
RunService.RenderStepped:Connect(function()
-- Camera FOV for ADS
local targetFOV = isADS and weapon.adsFOV or 70
camera.FieldOfView = camera.FieldOfView + (targetFOV - camera.FieldOfView) * 0.2
-- Sprint speed
local c = player.Character
if c then
local h = c:FindFirstChildOfClass("Humanoid")
if h and h.MoveDirection.Magnitude > 0 then
if isSprinting then
h.WalkSpeed = 30
elseif not UIS:IsKeyDown(Enum.KeyCode.LeftControl) then
h.WalkSpeed = 20
end
end
end
-- Auto-fire for automatic weapons
if isFiring and weapon.automatic then shoot() end
-- Recoil recovery
recoilX = recoilX * 0.9
recoilY = recoilY * 0.85
-- Crosshair spread
local spreadPx = isADS and 2 or (isSprinting and 15 or 6)
if isFiring then spreadPx = spreadPx + 4 end
for _, child in ipairs(crosshair:GetChildren()) do
if child.Name == "Top" then child.Position = UDim2.new(0, 9, 0, 9 - spreadPx)
elseif child.Name == "Bottom" then child.Position = UDim2.new(0, 9, 0, 9 + spreadPx)
elseif child.Name == "Left" then child.Position = UDim2.new(0, 9 - spreadPx, 0, 9)
elseif child.Name == "Right" then child.Position = UDim2.new(0, 9 + spreadPx, 0, 9)
end
end
end)
-- First person lock
UIS.MouseIconEnabled = false
player.CameraMode = Enum.CameraMode.LockFirstPerson
player.CharacterAdded:Connect(function()
ammo = weapon.magSize
reserveAmmo = weapon.maxAmmo
kills = 0
deaths = 0
isReloading = false
reloadBar.Visible = false
updateHUD()
end)
updateHUD()
print("═══════════════════════════════════════════")
print(" MINI CALL OF DUTY - LOADED!")
print(" Controls:")
print(" WASD = Move")
print(" LMB = Shoot")
print(" RMB = Aim Down Sights")
print(" Shift = Sprint")
print(" Ctrl = Crouch")
print(" R = Reload")
print(" 1-4 = Switch Weapon")
print(" Weapons: M4A1(1), AK-47(2), AWP Sniper(3), SPAS-12(4)")
print("═══════════════════════════════════════════")
]]
print("[CoD FPS] Part 5/5 complete: Weapon controller script created.")
print("═══════════════════════════════════════════")
print(" ALL PARTS COMPLETE! Press PLAY in Studio to start.")
print("═══════════════════════════════════════════")