Files
ClaudeCode-Roblox-Studio-MCP/roblox-fps-complete.lua
Gemini AI 2065361e57 Add GTA city builder + background injection API for Roblox Studio
- inject_gta_city.py: Full GTA-style city with 20 buildings, roads, cars,
  street lights, traffic lights, trees, 15 human enemies with varied
  skin/clothing, and 10 COD weapons with visible gun models
- inject_bg.py: Background injection using SendMessage/PostMessage Win32 API
- inject_bg2.py: PostMessage approach targeting main window for WPF apps
- inject_cod_final.py: Working COD game injection (7-step sequential)
- cod_inject.py: Combined COD game builder with proper Studio launch
- roblox-fps-p1-p6: Split Lua scripts for multi-part injection

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

1315 lines
51 KiB
Lua

-- ═══════════════════════════════════════════════════════════════
-- MINI CALL OF DUTY - COMPLETE GAME (Single Injection)
-- 20 Weapons | Enemy AI | Full HUD | Urban Map
-- ═══════════════════════════════════════════════════════════════
-- ── CLEAN SLATE ──
for _, v in pairs({"GameServer", "FPS_HUD", "WeaponClient", "WeaponController", "PlayerSetup"}) do
local s = game.ServerScriptService:FindFirstChild(v)
if s then s:Destroy() end
local g = game.StarterGui:FindFirstChild(v)
if g then g:Destroy() end
local p = game.StarterPlayer.StarterPlayerScripts:FindFirstChild(v)
if p then p:Destroy() end
end
local shared = game.ReplicatedStorage:FindFirstChild("Shared")
if shared then shared:Destroy() end
local events = game.ReplicatedStorage:FindFirstChild("Events")
if events then events:Destroy() end
-- Clean workspace
for _, v in pairs(workspace:GetChildren()) do
if v:IsA("Model") or v:IsA("Part") or v:IsA("Folder") then
if v.Name ~= "Camera" and v.Name ~= "Terrain" then
v:Destroy()
end
end
end
wait(0.5)
-- ═══════════════════════════════════════════════════════════════
-- PART 1: MAP
-- ═══════════════════════════════════════════════════════════════
-- Ground
local ground = Instance.new("Part", workspace)
ground.Name = "Ground"
ground.Size = Vector3.new(400, 2, 400)
ground.Position = Vector3.new(0, -1, 0)
ground.Anchored = true
ground.BrickColor = BrickColor.new("Dark stone grey")
ground.Material = Enum.Material.Concrete
-- Boundary walls
local wallData = {
{n="NorthWall",s={400,20,2},p={0,10,-200}},
{n="SouthWall",s={400,20,2},p={0,10,200}},
{n="EastWall",s={2,20,400},p={200,10,0}},
{n="WestWall",s={2,20,400},p={-200,10,0}},
}
for _,w in ipairs(wallData) do
local wall = Instance.new("Part", workspace)
wall.Name = w.n
wall.Size = Vector3.new(unpack(w.s))
wall.Position = Vector3.new(unpack(w.p))
wall.Anchored = true
wall.BrickColor = BrickColor.new("Dark stone grey")
wall.Material = Enum.Material.Concrete
wall.Transparency = 0.3
end
-- Buildings
local buildings = {
{n="Building_Alpha",s={30,20,25},p={-60,10,-80},c="Medium stone grey"},
{n="Building_Bravo",s={25,18,30},p={70,9,-60},c="Brown"},
{n="Building_Charlie",s={35,22,20},p={-40,11,70},c="Dark stone grey"},
{n="Building_Delta",s={20,16,35},p={80,8,80},c="Medium stone grey"},
{n="Building_Echo",s={28,24,28},p={0,12,-150},c="Brown"},
}
for _,b in ipairs(buildings) do
local bld = Instance.new("Model", workspace)
bld.Name = b.n
-- Main structure
local main = Instance.new("Part", bld)
main.Name = "Main"
main.Size = Vector3.new(unpack(b.s))
main.Position = Vector3.new(unpack(b.p))
main.Anchored = true
main.BrickColor = BrickColor.new(b.c)
main.Material = Enum.Material.Brick
end
-- Cover objects (sandbags, crates, barrels)
local coverPositions = {
{-20,1,0},{20,1,0},{0,1,-30},{0,1,30},
{-50,1,20},{50,1,-20},{-30,1,-50},{30,1,50},
{-80,1,0},{80,1,0},{0,1,-80},{0,1,80},
{-10,1,-120},{10,1,120},{-100,1,-40},{100,1,40},
{-60,1,40},{60,1,-40},{-40,1,-120},{40,1,120},
{110,1,0},{-110,1,0},{0,1,110},{0,1,-110},
}
for i,cp in ipairs(coverPositions) do
if i % 3 == 0 then
-- Barrel
local barrel = Instance.new("Part", workspace)
barrel.Name = "Barrel_"..i
barrel.Size = Vector3.new(3, 4, 3)
barrel.Position = Vector3.new(cp[1], cp[2]+2, cp[3])
barrel.Anchored = true
barrel.BrickColor = BrickColor.new("Reddish brown")
barrel.Material = Enum.Material.Metal
barrel.Shape = Enum.PartType.Cylinder
barrel.Orientation = Vector3.new(0, 0, 90)
elseif i % 3 == 1 then
-- Crate
local crate = Instance.new("Part", workspace)
crate.Name = "Crate_"..i
crate.Size = Vector3.new(5, 5, 5)
crate.Position = Vector3.new(cp[1], cp[2]+2.5, cp[3])
crate.Anchored = true
crate.BrickColor = BrickColor.new("Brown")
crate.Material = Enum.Material.Wood
else
-- Sandbag
local sandbag = Instance.new("Part", workspace)
sandbag.Name = "Sandbag_"..i
sandbag.Size = Vector3.new(8, 3, 3)
sandbag.Position = Vector3.new(cp[1], cp[2]+1.5, cp[3])
sandbag.Anchored = true
sandbag.BrickColor = BrickColor.new("Brick yellow")
sandbag.Material = Enum.Material.Sand
end
end
-- Watchtowers
local towers = {{-120,0,-120},{120,0,-120},{-120,0,120},{120,0,120}}
for i,tp in ipairs(towers) do
local tower = Instance.new("Model", workspace)
tower.Name = "Watchtower_"..i
-- Base
local base = Instance.new("Part", tower)
base.Size = Vector3.new(6, 1, 6)
base.Position = Vector3.new(tp[1], 0.5, tp[3])
base.Anchored = true
base.BrickColor = BrickColor.new("Dark stone grey")
base.Material = Enum.Material.Metal
-- Legs
for _,off in ipairs({{-2,0,-2},{2,0,-2},{-2,0,2},{2,0,2}}) do
local leg = Instance.new("Part", tower)
leg.Size = Vector3.new(1, 15, 1)
leg.Position = Vector3.new(tp[1]+off[1], 7.5, tp[3]+off[2])
leg.Anchored = true
leg.BrickColor = BrickColor.new("Dark stone grey")
leg.Material = Enum.Material.Metal
end
-- Platform
local plat = Instance.new("Part", tower)
plat.Size = Vector3.new(8, 1, 8)
plat.Position = Vector3.new(tp[1], 15, tp[3])
plat.Anchored = true
plat.BrickColor = BrickColor.new("Brown")
plat.Material = Enum.Material.Wood
end
-- Spawn points
for _,sp in ipairs({{0,3,170},{-30,3,170},{30,3,170}}) do
local spPart = Instance.new("SpawnLocation", workspace)
spPart.Size = Vector3.new(6, 1, 6)
spPart.Position = Vector3.new(unpack(sp))
spPart.Anchored = true
spPart.CanCollide = false
spPart.Transparency = 1
spPart.Name = "SpawnPoint"
end
-- Lighting
local lighting = game:GetService("Lighting")
lighting.ClockTime = 17.5
lighting.Brightness = 0.5
lighting.FogEnd = 500
lighting.FogStart = 200
lighting.Ambient = Color3.fromRGB(100, 100, 120)
lighting.OutdoorAmbient = Color3.fromRGB(80, 80, 100)
local bloom = Instance.new("BloomEffect", lighting)
bloom.Intensity = 0.3
bloom.Size = 24
bloom.Threshold = 1
local cc = Instance.new("ColorCorrectionEffect", lighting)
cc.Contrast = 0.1
cc.Saturation = 0.1
cc.TintColor = Color3.fromRGB(255, 240, 220)
wait(0.3)
-- ═══════════════════════════════════════════════════════════════
-- PART 2: SHARED DATA (ReplicatedStorage)
-- ═══════════════════════════════════════════════════════════════
local shared = Instance.new("Folder", game.ReplicatedStorage)
shared.Name = "Shared"
-- RemoteEvents
local events = Instance.new("Folder", game.ReplicatedStorage)
events.Name = "Events"
Instance.new("RemoteEvent", events).Name = "HitEvent"
Instance.new("RemoteEvent", events).Name = "KillEvent"
Instance.new("RemoteEvent", events).Name = "DamageEvent"
Instance.new("RemoteEvent", events).Name = "WeaponSwitchEvent"
Instance.new("RemoteEvent", events).Name = "ReloadEvent"
Instance.new("RemoteEvent", events).Name = "PlayerDiedEvent"
Instance.new("RemoteEvent", events).Name = "EnemyKilledEvent"
Instance.new("RemoteEvent", events).Name = "HitMarkerEvent"
-- WeaponData ModuleScript with 20 WEAPONS
local wd = Instance.new("ModuleScript", shared)
wd.Name = "WeaponData"
wd.Source = [[
local WeaponData = {
-- ASSAULT RIFLES
{Name="M4A1 Carbine", Category="Assault Rifle", Key=Enum.KeyCode.One, Damage=25, HeadMulti=2.5, FireRate=0.1, MagSize=30, ReloadTime=2.2, Spread=0.02, ADS_Spread=0.008, Recoil=0.3, Range=300, Auto=true, AmmoType="5.56x45mm"},
{Name="AK-47", Category="Assault Rifle", Key=Enum.KeyCode.Two, Damage=28, HeadMulti=2.5, FireRate=0.12, MagSize=30, ReloadTime=2.5, Spread=0.03, ADS_Spread=0.012, Recoil=0.45, Range=280, Auto=true, AmmoType="7.62x39mm"},
{Name="FN SCAR-H", Category="Assault Rifle", Key=Enum.KeyCode.Three, Damage=33, HeadMulti=2.5, FireRate=0.11, MagSize=20, ReloadTime=2.6, Spread=0.025, ADS_Spread=0.01, Recoil=0.4, Range=320, Auto=true, AmmoType="7.62x51mm"},
{Name="M16A4", Category="Assault Rifle", Key=Enum.KeyCode.Four, Damage=30, HeadMulti=2.8, FireRate=0.075, MagSize=30, ReloadTime=2.3, Spread=0.015, ADS_Spread=0.005, Recoil=0.35, Range=350, Auto=false, BurstCount=3, AmmoType="5.56x45mm"},
{Name="FAMAS F1", Category="Assault Rifle", Key=Enum.KeyCode.Five, Damage=24, HeadMulti=2.5, FireRate=0.065, MagSize=25, ReloadTime=2.1, Spread=0.025, ADS_Spread=0.01, Recoil=0.35, Range=270, Auto=true, AmmoType="5.56x45mm"},
{Name="HK G36C", Category="Assault Rifle", Key=Enum.KeyCode.Six, Damage=26, HeadMulti=2.5, FireRate=0.09, MagSize=30, ReloadTime=2.2, Spread=0.02, ADS_Spread=0.008, Recoil=0.3, Range=300, Auto=true, AmmoType="5.56x45mm"},
-- SMGS
{Name="MP5A4", Category="SMG", Key=Enum.KeyCode.Seven, Damage=20, HeadMulti=2, FireRate=0.08, MagSize=30, ReloadTime=1.8, Spread=0.035, ADS_Spread=0.015, Recoil=0.15, Range=150, Auto=true, AmmoType="9x19mm"},
{Name="FN P90", Category="SMG", Key=Enum.KeyCode.Eight, Damage=21, HeadMulti=2, FireRate=0.065, MagSize=50, ReloadTime=2.5, Spread=0.04, ADS_Spread=0.018, Recoil=0.18, Range=140, Auto=true, AmmoType="5.7x28mm"},
{Name="HK MP7A2", Category="SMG", Key=Enum.KeyCode.Nine, Damage=19, HeadMulti=2, FireRate=0.07, MagSize=40, ReloadTime=2.0, Spread=0.03, ADS_Spread=0.012, Recoil=0.12, Range=130, Auto=true, AmmoType="4.6x30mm"},
{Name="UMP-45", Category="SMG", Key=Enum.KeyCode.Zero, Damage=23, HeadMulti=2, FireRate=0.11, MagSize=25, ReloadTime=2.0, Spread=0.04, ADS_Spread=0.018, Recoil=0.22, Range=160, Auto=true, AmmoType=".45 ACP"},
-- SNIPERS
{Name="AWP", Category="Sniper", Key=Enum.KeyCode.Q, Damage=95, HeadMulti=3, FireRate=1.4, MagSize=10, ReloadTime=3.5, Spread=0.001, ADS_Spread=0, Recoil=2.0, Range=800, Auto=false, ScopeZoom=8, AmmoType=".338 Lapua"},
{Name="Barrett M82", Category="Sniper", Key=Enum.KeyCode.E, Damage=150, HeadMulti=3, FireRate=1.8, MagSize=5, ReloadTime=4.0, Spread=0.002, ADS_Spread=0.001, Recoil=3.5, Range=1000, Auto=false, ScopeZoom=10, AmmoType=".50 BMG"},
{Name="SVD Dragunov", Category="Sniper", Key=Enum.KeyCode.T, Damage=55, HeadMulti=2.8, FireRate=0.5, MagSize=10, ReloadTime=3.0, Spread=0.005, ADS_Spread=0.002, Recoil=1.2, Range=600, Auto=false, ScopeZoom=4, AmmoType="7.62x54mm"},
-- SHOTGUNS
{Name="SPAS-12", Category="Shotgun", Key=Enum.KeyCode.Z, Damage=15, HeadMulti=1.5, FireRate=0.9, MagSize=8, ReloadTime=3.5, Spread=0.1, ADS_Spread=0.08, Recoil=1.5, Range=40, Auto=false, Pellets=8, AmmoType="12 Gauge"},
{Name="Remington 870", Category="Shotgun", Key=Enum.KeyCode.X, Damage=18, HeadMulti=1.5, FireRate=1.0, MagSize=6, ReloadTime=3.0, Spread=0.12, ADS_Spread=0.09, Recoil=1.8, Range=35, Auto=false, Pellets=6, AmmoType="12 Gauge"},
-- LMGS
{Name="M249 SAW", Category="LMG", Key=Enum.KeyCode.C, Damage=28, HeadMulti=2, FireRate=0.08, MagSize=100, ReloadTime=5.5, Spread=0.05, ADS_Spread=0.025, Recoil=0.5, Range=350, Auto=true, AmmoType="5.56x45mm"},
{Name="M134 Minigun", Category="LMG", Key=Enum.KeyCode.V, Damage=18, HeadMulti=1.8, FireRate=0.04, MagSize=200, ReloadTime=8.0, Spread=0.07, ADS_Spread=0.04, Recoil=0.35, Range=250, Auto=true, AmmoType="7.62x51mm"},
-- PISTOLS
{Name="Desert Eagle", Category="Pistol", Key=Enum.KeyCode.B, Damage=45, HeadMulti=3, FireRate=0.3, MagSize=7, ReloadTime=1.8, Spread=0.03, ADS_Spread=0.015, Recoil=0.8, Range=100, Auto=false, AmmoType=".50 AE"},
{Name="Glock 18C", Category="Pistol", Key=Enum.KeyCode.N, Damage=18, HeadMulti=2, FireRate=0.05, MagSize=20, ReloadTime=1.5, Spread=0.04, ADS_Spread=0.02, Recoil=0.15, Range=60, Auto=true, AmmoType="9x19mm"},
-- LAUNCHER
{Name="RPG-7", Category="Launcher", Key=Enum.KeyCode.G, Damage=200, HeadMulti=1, FireRate=2.0, MagSize=1, ReloadTime=4.5, Spread=0.01, ADS_Spread=0.005, Recoil=3.0, Range=200, Auto=false, Explosive=true, BlastRadius=20, AmmoType="PG-7VL"},
}
return WeaponData
]]
-- ═══════════════════════════════════════════════════════════════
-- PART 3: GAME SERVER (ServerScriptService)
-- ═══════════════════════════════════════════════════════════════
local gs = Instance.new("Script", game.ServerScriptService)
gs.Name = "GameServer"
gs.Source = [[
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
local Events = ReplicatedStorage:WaitForChild("Events")
local HitEvent = Events:WaitForChild("HitEvent")
local KillEvent = Events:WaitForChild("KillEvent")
local DamageEvent = Events:WaitForChild("DamageEvent")
local PlayerDiedEvent = Events:WaitForChild("PlayerDiedEvent")
local EnemyKilledEvent = Events:WaitForChild("EnemyKilledEvent")
local HitMarkerEvent = Events:WaitForChild("HitMarkerEvent")
-- Player management
Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
local humanoid = character:WaitForChild("Humanoid")
humanoid.MaxHealth = 100
humanoid.Health = 100
humanoid.WalkSpeed = 18
-- Spawn loadout
humanoid.Died:Connect(function()
PlayerDiedEvent:FireClient(player, player.Name)
task.delay(4, function()
if player and player.Character and player.Character:FindFirstChild("Humanoid") then
player.Character:FindFirstChild("Humanoid").Health = 0
end
player:LoadCharacter()
end)
end)
end)
end)
-- Hit detection from clients
HitEvent.OnServerEvent:Connect(function(player, hitPart, damage, isHeadshot, weaponName)
if hitPart and hitPart.Parent and hitPart.Parent:FindFirstChild("Humanoid") then
local target = hitPart.Parent
local hum = target:FindFirstChild("Humanoid")
if hum and hum.Health > 0 then
local dmg = isHeadshot and damage * 2.5 or damage
hum:TakeDamage(dmg)
HitMarkerEvent:FireClient(player, isHeadshot)
-- Notify target they took damage
local targetPlayer = Players:GetPlayerFromCharacter(target)
if targetPlayer and targetPlayer ~= player then
DamageEvent:FireClient(targetPlayer, dmg)
end
if hum.Health <= 0 then
KillEvent:FireClient(player, "Enemy")
player.leaderstats.Kills.Value = player.leaderstats.Kills.Value + 1
end
end
end
end)
-- Enemy hit detection
EnemyKilledEvent.OnServerEvent:Connect(function(player, enemyName)
if player and player:FindFirstChild("leaderstats") then
player.leaderstats.Kills.Value = player.leaderstats.Kills.Value + 1
end
end)
-- Leaderstats
Players.PlayerAdded:Connect(function(player)
local ls = Instance.new("Folder", player)
ls.Name = "leaderstats"
local kills = Instance.new("IntValue", ls)
kills.Name = "Kills"
kills.Value = 0
local deaths = Instance.new("IntValue", ls)
deaths.Name = "Deaths"
deaths.Value = 0
player.CharacterAdded:Connect(function(char)
local hum = char:WaitForChild("Humanoid")
hum.Died:Connect(function()
deaths.Value = deaths.Value + 1
end)
end)
end)
-- ═══════ ENEMY AI SYSTEM ═══════
local MAX_ENEMIES = 10
local ENEMY_SPawns = {
Vector3.new(-150, 3, -150), Vector3.new(150, 3, -150),
Vector3.new(-150, 3, 150), Vector3.new(150, 3, 150),
Vector3.new(0, 3, -150), Vector3.new(0, 3, 150),
Vector3.new(-150, 3, 0), Vector3.new(150, 3, 0),
Vector3.new(-100, 3, -100), Vector3.new(100, 3, 100),
}
local enemies = {}
local patrolPoints = {
Vector3.new(-60, 3, -80), Vector3.new(70, 3, -60),
Vector3.new(-40, 3, 70), Vector3.new(80, 3, 80),
Vector3.new(0, 3, -150), Vector3.new(-120, 3, -120),
Vector3.new(120, 3, -120), Vector3.new(-120, 3, 120),
Vector3.new(120, 3, 120), Vector3.new(0, 3, 0),
}
local function createEnemy(spawnPos)
local enemy = Instance.new("Model", Workspace)
enemy.Name = "EnemySoldier"
-- Body
local torso = Instance.new("Part", enemy)
torso.Name = "Torso"
torso.Size = Vector3.new(3, 3, 2)
torso.Position = spawnPos
torso.BrickColor = BrickColor.new("Dark green")
torso.Material = Enum.Material.Plastic
-- Head
local head = Instance.new("Part", enemy)
head.Name = "Head"
head.Size = Vector3.new(2, 2, 2)
head.Position = spawnPos + Vector3.new(0, 2.5, 0)
head.BrickColor = BrickColor.new("Medium stone grey")
head.Material = Enum.Material.Plastic
-- Legs
local ll = Instance.new("Part", enemy)
ll.Name = "Left Leg"
ll.Size = Vector3.new(1, 3, 1)
ll.Position = spawnPos + Vector3.new(-0.75, -2.5, 0)
ll.BrickColor = BrickColor.new("Dark green")
ll.Parent = enemy
local rl = Instance.new("Part", enemy)
rl.Name = "Right Leg"
rl.Size = Vector3.new(1, 3, 1)
rl.Position = spawnPos + Vector3.new(0.75, -2.5, 0)
rl.BrickColor = BrickColor.new("Dark green")
rl.Parent = enemy
-- Weld everything
local hum = Instance.new("Humanoid", enemy)
hum.MaxHealth = 100
hum.Health = 100
hum.WalkSpeed = 12
local rootPart = Instance.new("Part", enemy)
rootPart.Name = "HumanoidRootPart"
rootPart.Size = Vector3.new(2, 2, 1)
rootPart.Position = spawnPos
rootPart.Transparency = 1
rootPart.CanCollide = false
local function weld(part0, part1)
local w = Instance.new("Weld", part0)
w.Part0 = part0
w.Part1 = part1
end
weld(rootPart, torso)
weld(torso, head)
weld(torso, ll)
weld(torso, rl)
-- AI state
local state = {
model = enemy,
hum = hum,
status = "patrol",
targetPoint = patrolPoints[math.random(#patrolPoints)],
lastShot = 0,
detectRange = 60,
attackRange = 45,
}
-- Patrol behavior
local function patrolLoop()
while enemy.Parent and hum.Health > 0 do
task.wait(0.5)
if state.status == "patrol" then
local root = enemy:FindFirstChild("HumanoidRootPart")
if root then
hum:MoveTo(state.targetPoint)
if (root.Position - state.targetPoint).Magnitude < 5 then
state.targetPoint = patrolPoints[math.random(#patrolPoints)]
end
end
end
end
end
-- Detection loop
local function detectLoop()
while enemy.Parent and hum.Health > 0 do
task.wait(0.3)
local root = enemy:FindFirstChild("HumanoidRootPart")
if not root then continue end
for _, player in ipairs(Players:GetPlayers()) do
if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
local pRoot = player.Character.HumanoidRootPart
local dist = (pRoot.Position - root.Position).Magnitude
if dist < state.detectRange then
state.status = "chase"
hum:MoveTo(pRoot.Position)
if dist < state.attackRange and tick() - state.lastShot > 1.5 then
state.lastShot = tick()
-- Damage player
local pHum = player.Character:FindFirstChild("Humanoid")
if pHum and pHum.Health > 0 then
pHum:TakeDamage(8 + math.random(7))
DamageEvent:FireClient(player, 10)
end
end
elseif dist > state.detectRange * 1.5 then
state.status = "patrol"
end
end
end
end
end
-- Death handler
hum.Died:Connect(function()
for _, p in ipairs(Players:GetPlayers()) do
local char = p.Character
if char and char:FindFirstChild("HumanoidRootPart") then
local dist = (enemy:FindFirstChild("HumanoidRootPart") and enemy.HumanoidRootPart.Position or Vector3.zero) - char.HumanoidRootPart.Position
if dist.Magnitude < 80 then
EnemyKilledEvent:FireClient(p, enemy.Name)
end
end
end
task.delay(8, function()
if enemy and enemy.Parent then enemy:Destroy() end
end)
-- Respawn new enemy
task.delay(12, function()
if #Workspace:GetChildren() - 10 < MAX_ENEMIES then
local sp = ENEMY_SPawns[math.random(#ENEMY_SPawns)]
createEnemy(sp)
end
end)
end)
coroutine.wrap(patrolLoop)()
coroutine.wrap(detectLoop)()
return state
end
-- Spawn initial enemies
for i = 1, MAX_ENEMIES do
task.delay(i * 0.5, function()
createEnemy(ENEMY_SPawns[i])
end)
end
print("[GameServer] 20-Weapon FPS Game loaded!")
]]
-- ═══════════════════════════════════════════════════════════════
-- PART 4: HUD (StarterGui)
-- ═══════════════════════════════════════════════════════════════
local hud = Instance.new("ScreenGui", game.StarterGui)
hud.Name = "FPS_HUD"
hud.ResetOnSpawn = false
hud.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
-- Crosshair
local cross = Instance.new("Frame", hud)
cross.Name = "Crosshair"
cross.Size = UDim2.new(0, 20, 0, 2)
cross.Position = UDim2.new(0.5, -10, 0.5, -1)
cross.BackgroundColor3 = Color3.new(1, 1, 1)
cross.BorderSizePixel = 0
local crossV = Instance.new("Frame", hud)
crossV.Name = "CrosshairV"
crossV.Size = UDim2.new(0, 2, 0, 20)
crossV.Position = UDim2.new(0.5, -1, 0.5, -10)
crossV.BackgroundColor3 = Color3.new(1, 1, 1)
crossV.BorderSizePixel = 0
-- Hit Marker
local hm = Instance.new("Frame", hud)
hm.Name = "HitMarker"
hm.Size = UDim2.new(0, 30, 0, 30)
hm.Position = UDim2.new(0.5, -15, 0.5, -15)
hm.BackgroundTransparency = 1
hm.Visible = false
local hm1 = Instance.new("Frame", hm)
hm1.Size = UDim2.new(0, 15, 0, 3)
hm1.Position = UDim2.new(0, 15, 0, 0)
hm1.Rotation = 45
hm1.BackgroundColor3 = Color3.new(1, 1, 1)
hm1.BorderSizePixel = 0
local hm2 = Instance.new("Frame", hm)
hm2.Size = UDim2.new(0, 15, 0, 3)
hm2.Position = UDim2.new(0, 0, 0, 15)
hm2.Rotation = 45
hm2.BackgroundColor3 = Color3.new(1, 1, 1)
hm2.BorderSizePixel = 0
-- Health Bar (bottom left)
local hbFrame = Instance.new("Frame", hud)
hbFrame.Name = "HealthFrame"
hbFrame.Size = UDim2.new(0, 250, 0, 30)
hbFrame.Position = UDim2.new(0, 20, 1, -60)
hbFrame.BackgroundColor3 = Color3.fromRGB(30, 30, 30)
hbFrame.BorderSizePixel = 0
hbFrame.BackgroundTransparency = 0.3
local hbFill = Instance.new("Frame", hbFrame)
hbFill.Name = "HealthFill"
hbFill.Size = UDim2.new(1, 0, 1, 0)
hbFill.BackgroundColor3 = Color3.fromRGB(0, 200, 0)
hbFill.BorderSizePixel = 0
local hbText = Instance.new("TextLabel", hbFrame)
hbText.Name = "HealthText"
hbText.Size = UDim2.new(1, 0, 1, 0)
hbText.BackgroundTransparency = 1
hbText.TextColor3 = Color3.new(1, 1, 1)
hbText.TextStrokeTransparency = 0.5
hbText.Font = Enum.Font.GothamBold
hbText.TextSize = 16
hbText.Text = "100 HP"
-- Ammo display (bottom right)
local ammoFrame = Instance.new("Frame", hud)
ammoFrame.Name = "AmmoFrame"
ammoFrame.Size = UDim2.new(0, 200, 0, 60)
ammoFrame.Position = UDim2.new(1, -220, 1, -80)
ammoFrame.BackgroundTransparency = 1
local ammoText = Instance.new("TextLabel", ammoFrame)
ammoText.Name = "AmmoText"
ammoText.Size = UDim2.new(1, 0, 0.6, 0)
ammoText.Position = UDim2.new(0, 0, 0, 0)
ammoText.BackgroundTransparency = 1
ammoText.TextColor3 = Color3.new(1, 1, 1)
ammoText.TextStrokeTransparency = 0.5
ammoText.Font = Enum.Font.GothamBold
ammoText.TextSize = 28
ammoText.TextXAlignment = Enum.TextXAlignment.Right
ammoText.Text = "30 / 30"
local weaponName = Instance.new("TextLabel", ammoFrame)
weaponName.Name = "WeaponName"
weaponName.Size = UDim2.new(1, 0, 0.4, 0)
weaponName.Position = UDim2.new(0, 0, 0.6, 0)
weaponName.BackgroundTransparency = 1
weaponName.TextColor3 = Color3.fromRGB(200, 200, 200)
weaponName.TextStrokeTransparency = 0.7
weaponName.Font = Enum.Font.Gotham
weaponName.TextSize = 14
weaponName.TextXAlignment = Enum.TextXAlignment.Right
weaponName.Text = "M4A1 Carbine"
-- Reload bar
local reloadBar = Instance.new("Frame", hud)
reloadBar.Name = "ReloadBar"
reloadBar.Size = UDim2.new(0, 200, 0, 6)
reloadBar.Position = UDim2.new(0.5, -100, 1, -120)
reloadBar.BackgroundColor3 = Color3.fromRGB(60, 60, 60)
reloadBar.BorderSizePixel = 0
reloadBar.Visible = false
reloadBar.BackgroundTransparency = 0.3
local reloadFill = Instance.new("Frame", reloadBar)
reloadFill.Name = "Fill"
reloadFill.Size = UDim2.new(0, 0, 1, 0)
reloadFill.BackgroundColor3 = Color3.fromRGB(255, 200, 0)
reloadFill.BorderSizePixel = 0
local reloadText = Instance.new("TextLabel", hud)
reloadText.Name = "ReloadText"
reloadText.Size = UDim2.new(0, 200, 0, 20)
reloadText.Position = UDim2.new(0.5, -100, 1, -140)
reloadText.BackgroundTransparency = 1
reloadText.TextColor3 = Color3.fromRGB(255, 200, 0)
reloadText.Font = Enum.Font.GothamBold
reloadText.TextSize = 14
reloadText.Text = "RELOADING..."
reloadText.Visible = false
-- Kill Feed (top right)
local kf = Instance.new("Frame", hud)
kf.Name = "KillFeed"
kf.Size = UDim2.new(0, 250, 0, 200)
kf.Position = UDim2.new(1, -260, 0, 10)
kf.BackgroundTransparency = 1
local kfLayout = Instance.new("UIListLayout", kf)
kfLayout.SortOrder = Enum.SortOrder.LayoutOrder
kfLayout.Padding = UDim.new(0, 4)
kfLayout.VerticalAlignment = Enum.VerticalAlignment.Top
-- Score display (top center)
local scoreFrame = Instance.new("Frame", hud)
scoreFrame.Name = "ScoreFrame"
scoreFrame.Size = UDim2.new(0, 200, 0, 40)
scoreFrame.Position = UDim2.new(0.5, -100, 0, 10)
scoreFrame.BackgroundColor3 = Color3.fromRGB(20, 20, 20)
scoreFrame.BackgroundTransparency = 0.5
scoreFrame.BorderSizePixel = 0
local scoreText = Instance.new("TextLabel", scoreFrame)
scoreText.Name = "ScoreText"
scoreText.Size = UDim2.new(1, 0, 1, 0)
scoreText.BackgroundTransparency = 1
scoreText.TextColor3 = Color3.new(1, 1, 1)
scoreText.Font = Enum.Font.GothamBold
scoreText.TextSize = 20
scoreText.Text = "KILLS: 0"
-- Streak banner (center)
local streak = Instance.new("TextLabel", hud)
streak.Name = "StreakBanner"
streak.Size = UDim2.new(0, 400, 0, 60)
streak.Position = UDim2.new(0.5, -200, 0.3, 0)
streak.BackgroundTransparency = 1
streak.TextColor3 = Color3.fromRGB(255, 50, 50)
streak.Font = Enum.Font.GothamBold
streak.TextSize = 36
streak.TextStrokeTransparency = 0.3
streak.Text = ""
streak.Visible = false
-- Damage Vignette
local vignette = Instance.new("ImageLabel", hud)
vignette.Name = "DamageVignette"
vignette.Size = UDim2.new(1, 0, 1, 0)
vignette.Position = UDim2.new(0, 0, 0, 0)
vignette.BackgroundTransparency = 1
vignette.ImageTransparency = 1
vignette.Image = "rbxassetid://1489679531"
vignette.ImageColor3 = Color3.new(1, 0, 0)
vignette.ScaleType = Enum.ScaleType.Slice
vignette.SliceCenter = Rect.new(0.4, 0.4, 0.6, 0.6)
-- Minimap (top left)
local minimap = Instance.new("Frame", hud)
minimap.Name = "Minimap"
minimap.Size = UDim2.new(0, 150, 0, 150)
minimap.Position = UDim2.new(0, 10, 0, 10)
minimap.BackgroundColor3 = Color3.fromRGB(20, 20, 30)
minimap.BorderSizePixel = 2
minimap.BorderColor3 = Color3.fromRGB(100, 100, 100)
local mapIcon = Instance.new("Frame", minimap)
mapIcon.Name = "PlayerDot"
mapIcon.Size = UDim2.new(0, 6, 0, 6)
mapIcon.Position = UDim2.new(0.5, -3, 0.5, -3)
mapIcon.BackgroundColor3 = Color3.fromRGB(0, 150, 255)
mapIcon.BorderSizePixel = 0
mapIcon.Shape = Enum.UIRectShape.Circle
-- Weapon list (bottom center)
local weaponList = Instance.new("Frame", hud)
weaponList.Name = "WeaponList"
weaponList.Size = UDim2.new(0, 500, 0, 25)
weaponList.Position = UDim2.new(0.5, -250, 1, -25)
weaponList.BackgroundColor3 = Color3.fromRGB(15, 15, 15)
weaponList.BackgroundTransparency = 0.5
weaponList.BorderSizePixel = 0
-- ═══════════════════════════════════════════════════════════════
-- PART 5: PLAYER SETUP (StarterPlayerScripts)
-- ═══════════════════════════════════════════════════════════════
local ps = Instance.new("LocalScript", game.StarterPlayer.StarterPlayerScripts)
ps.Name = "PlayerSetup"
ps.Source = [[
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local player = Players.LocalPlayer
local camera = workspace.CurrentCamera
player.CharacterAdded:Connect(function(character)
local humanoid = character:WaitForChild("Humanoid")
local rootPart = character:WaitForChild("HumanoidRootPart")
-- First person camera
RunService.RenderStepped:Connect(function()
if humanoid.Health > 0 then
camera.CameraType = Enum.CameraType.LockFirstPerson
local head = character:FindFirstChild("Head")
if head then
camera.CFrame = head.CFrame
end
end
end)
-- Sprint / Crouch
local sprinting = false
local crouching = false
UserInputService.InputBegan:Connect(function(input, gpe)
if gpe then return end
if input.KeyCode == Enum.KeyCode.LeftShift then
sprinting = true
humanoid.WalkSpeed = 28
elseif input.KeyCode == Enum.KeyCode.LeftControl then
crouching = true
humanoid.WalkSpeed = 8
end
end)
UserInputService.InputEnded:Connect(function(input)
if input.KeyCode == Enum.KeyCode.LeftShift then
sprinting = false
humanoid.WalkSpeed = crouching and 8 or 18
elseif input.KeyCode == Enum.KeyCode.LeftControl then
crouching = false
humanoid.WalkSpeed = sprinting and 28 or 18
end
end)
end)
-- Kill Feed listener
local Events = ReplicatedStorage:WaitForChild("Events")
local KillEvent = Events:WaitForChild("KillEvent")
local DamageEvent = Events:WaitForChild("DamageEvent")
local HitMarkerEvent = Events:WaitForChild("HitMarkerEvent")
KillEvent.OnClientEvent:Connect(function(killer)
local hud = player:WaitForChild("PlayerGui"):WaitForChild("FPS_HUD")
local kf = hud:FindFirstChild("KillFeed")
local entry = Instance.new("TextLabel", kf)
entry.Size = UDim2.new(1, 0, 0, 20)
entry.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
entry.BackgroundTransparency = 0.5
entry.TextColor3 = Color3.new(1, 1, 1)
entry.Font = Enum.Font.GothamBold
entry.TextSize = 13
entry.Text = player.Name .. " eliminated " .. (killer or "Enemy")
entry.TextXAlignment = Enum.TextXAlignment.Right
game:GetService("Debris"):AddItem(entry, 5)
end)
-- Damage vignette
DamageEvent.OnClientEvent:Connect(function(dmg)
local hud = player:WaitForChild("PlayerGui"):WaitForChild("FPS_HUD")
local vig = hud:FindFirstChild("DamageVignette")
if vig then
vig.ImageTransparency = 0.3
local t = TweenService:Create(vig, TweenInfo.new(0.8), {ImageTransparency = 1})
t:Play()
end
end)
-- Hit marker flash
HitMarkerEvent.OnClientEvent:Connect(function(isHeadshot)
local hud = player:WaitForChild("PlayerGui"):WaitForChild("FPS_HUD")
local hm = hud:FindFirstChild("HitMarker")
if hm then
hm.Visible = true
if isHeadshot then
for _, c in pairs(hm:GetChildren()) do
c.BackgroundColor3 = Color3.fromRGB(255, 50, 50)
end
else
for _, c in pairs(hm:GetChildren()) do
c.BackgroundColor3 = Color3.new(1, 1, 1)
end
end
task.delay(0.15, function()
hm.Visible = false
end)
end
end)
-- Minimap updater
RunService.RenderStepped:Connect(function()
local hud = player.PlayerGui:FindFirstChild("FPS_HUD")
if not hud then return end
local minimap = hud:FindFirstChild("Minimap")
if not minimap then return end
local character = player.Character
if not character or not character:FindFirstChild("HumanoidRootPart") then return end
local pos = character.HumanoidRootPart.Position
local mapSize = 400
local mmSize = 150
-- Clear old enemy dots
for _, c in pairs(minimap:GetChildren()) do
if c.Name == "EnemyDot" then c:Destroy() end
end
-- Player dot
local dot = minimap:FindFirstChild("PlayerDot")
if dot then
local rx = (pos.X / mapSize + 0.5) * mmSize
local rz = (pos.Z / mapSize + 0.5) * mmSize
dot.Position = UDim2.new(0, rx - 3, 0, rz - 3)
end
-- Enemy dots
for _, obj in pairs(workspace:GetChildren()) do
if obj:IsA("Model") and obj.Name == "EnemySoldier" and obj:FindFirstChild("HumanoidRootPart") then
local epos = obj.HumanoidRootPart.Position
local dist = (epos - pos).Magnitude
if dist < 100 then
local ex = (epos.X / mapSize + 0.5) * mmSize
local ez = (epos.Z / mapSize + 0.5) * mmSize
local eDot = Instance.new("Frame", minimap)
eDot.Name = "EnemyDot"
eDot.Size = UDim2.new(0, 4, 0, 4)
eDot.Position = UDim2.new(0, ex - 2, 0, ez - 2)
eDot.BackgroundColor3 = Color3.new(1, 0, 0)
eDot.BorderSizePixel = 0
eDot.Shape = Enum.UIRectShape.Circle
end
end
end
-- Health bar update
local char = player.Character
if char and char:FindFirstChild("Humanoid") then
local h = char.Humanoid
local hFrame = hud:FindFirstChild("HealthFrame")
if hFrame then
local fill = hFrame:FindFirstChild("HealthFill")
local txt = hFrame:FindFirstChild("HealthText")
if fill then
fill.Size = UDim2.new(h.Health / h.MaxHealth, 0, 1, 0)
if h.Health > 60 then fill.BackgroundColor3 = Color3.fromRGB(0, 200, 0)
elseif h.Health > 30 then fill.BackgroundColor3 = Color3.fromRGB(255, 200, 0)
else fill.BackgroundColor3 = Color3.fromRGB(255, 0, 0) end
end
if txt then txt.Text = math.floor(h.Health) .. " HP" end
end
end
end)
print("[PlayerSetup] Loaded!")
]]
-- ═══════════════════════════════════════════════════════════════
-- PART 6: WEAPON CONTROLLER (StarterPlayerScripts) - 20 WEAPONS
-- ═══════════════════════════════════════════════════════════════
local wc = Instance.new("LocalScript", game.StarterPlayer.StarterPlayerScripts)
wc.Name = "WeaponController"
wc.Source = [[
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local Debris = game:GetService("Debris")
local player = Players.LocalPlayer
local camera = workspace.CurrentCamera
local mouse = player:GetMouse()
local Events = ReplicatedStorage:WaitForChild("Events")
local HitEvent = Events:WaitForChild("HitEvent")
local KillEvent = Events:WaitForChild("KillEvent")
local WeaponSwitchEvent = Events:WaitForChild("WeaponSwitchEvent")
local WeaponData = require(ReplicatedStorage:WaitForChild("Shared"):WaitForChild("WeaponData"))
-- State
local currentIndex = 1
local currentAmmo = {}
local isReloading = false
local isADS = false
local canShoot = true
local recoilOffset = 0
local spreadOffset = 0
local lastShotTime = 0
local kills = 0
local killStreak = 0
local lastKillTime = 0
-- Initialize ammo for all weapons
for i, w in ipairs(WeaponData) do
currentAmmo[i] = w.MagSize
end
-- Key map
local keyMap = {}
for i, w in ipairs(WeaponData) do
keyMap[w.Key] = i
end
-- ═══════ WEAPON SWITCHING ═══════
local function switchWeapon(index)
if index < 1 or index > #WeaponData or isReloading then return end
currentIndex = index
local w = WeaponData[currentIndex]
-- Update HUD
local hud = player.PlayerGui:FindFirstChild("FPS_HUD")
if hud then
local ammoText = hud:FindFirstChild("AmmoFrame"):FindFirstChild("AmmoText")
local wnText = hud:FindFirstChild("AmmoFrame"):FindFirstChild("WeaponName")
if ammoText then ammoText.Text = currentAmmo[currentIndex] .. " / " .. w.MagSize end
if wnText then wnText.Text = w.Name end
end
isADS = false
camera.FieldOfView = 70
recoilOffset = 0
spreadOffset = 0
end
UserInputService.InputBegan:Connect(function(input, gpe)
if gpe then return end
-- Weapon keys
if keyMap[input.KeyCode] then
switchWeapon(keyMap[input.KeyCode])
end
-- ADS (Right mouse button)
if input.UserInputType == Enum.UserInputType.MouseButton2 then
local w = WeaponData[currentIndex]
if w.ScopeZoom then
isADS = true
camera.FieldOfView = 70 / w.ScopeZoom
elseif isADS == false then
isADS = true
local t = TweenService:Create(camera, TweenInfo.new(0.15), {FieldOfView = 45})
t:Play()
end
end
-- Reload
if input.KeyCode == Enum.KeyCode.R and not isReloading then
local w = WeaponData[currentIndex]
if currentAmmo[currentIndex] < w.MagSize then
isReloading = true
canShoot = false
local hud = player.PlayerGui:FindFirstChild("FPS_HUD")
if hud then
hud.ReloadBar.Visible = true
hud.ReloadText.Visible = true
end
-- Animate reload bar
local bar = hud and hud:FindFirstChild("ReloadBar")
local fill = bar and bar:FindFirstChild("Fill")
if fill then
fill.Size = UDim2.new(0, 0, 1, 0)
local rt = TweenService:Create(fill, TweenInfo.new(w.ReloadTime), {Size = UDim2.new(1, 0, 1, 0)})
rt:Play()
end
task.delay(w.ReloadTime, function()
currentAmmo[currentIndex] = w.MagSize
isReloading = false
canShoot = true
if hud then
hud.ReloadBar.Visible = false
hud.ReloadText.Visible = false
local ammoText = hud:FindFirstChild("AmmoFrame"):FindFirstChild("AmmoText")
if ammoText then ammoText.Text = currentAmmo[currentIndex] .. " / " .. w.MagSize end
end
end)
end
end
end)
UserInputService.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton2 then
isADS = false
local t = TweenService:Create(camera, TweenInfo.new(0.15), {FieldOfView = 70})
t:Play()
end
end)
-- ═══════ SHOOTING ═══════
local function shoot()
local w = WeaponData[currentIndex]
if not canShoot or isReloading then return end
if currentAmmo[currentIndex] <= 0 then return end
currentAmmo[currentIndex] = currentAmmo[currentIndex] - 1
-- Update ammo HUD
local hud = player.PlayerGui:FindFirstChild("FPS_HUD")
if hud then
local ammoText = hud:FindFirstChild("AmmoFrame"):FindFirstChild("AmmoText")
if ammoText then ammoText.Text = currentAmmo[currentIndex] .. " / " .. w.MagSize end
end
-- Raycast
local character = player.Character
if not character or not character:FindFirstChild("Head") then return end
local head = character.Head
local spread = isADS and w.ADS_Spread or w.Spread
spread = spread + spreadOffset
local rayOrigin = head.Position
local rayDir = (mouse.Hit.Position - rayOrigin).Unit
-- Add spread
rayDir = rayDir + Vector3.new(
(math.random() - 0.5) * spread,
(math.random() - 0.5) * spread,
(math.random() - 0.5) * spread
)
rayDir = rayDir.Unit
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Exclude
rayParams.FilterDescendantsInstances = {character}
-- Shotgun pellets
local pellets = w.Pellets or 1
for p = 1, pellets do
local pDir = rayDir
if pellets > 1 then
pDir = pDir + Vector3.new(
(math.random() - 0.5) * w.Spread * 2,
(math.random() - 0.5) * w.Spread * 2,
(math.random() - 0.5) * w.Spread * 2
)
pDir = pDir.Unit
end
local result = workspace:Raycast(rayOrigin, pDir * w.Range, rayParams)
if result then
local hitPart = result.Instance
local isHeadshot = hitPart.Name == "Head"
-- Bullet trail
local trail = Instance.new("Part", workspace)
trail.Size = Vector3.new(0.1, 0.1, (result.Position - rayOrigin).Magnitude)
trail.CFrame = CFrame.lookAt(rayOrigin, result.Position) * CFrame.new(0, 0, -trail.Size.Z / 2)
trail.Anchored = true
trail.CanCollide = false
trail.BrickColor = BrickColor.new("Bright yellow")
trail.Material = Enum.Material.Neon
trail.Transparency = 0.3
Debris:AddItem(trail, 0.15)
-- Impact spark
local spark = Instance.new("Part", workspace)
spark.Size = Vector3.new(0.5, 0.5, 0.5)
spark.Position = result.Position
spark.Anchored = true
spark.CanCollide = false
spark.BrickColor = BrickColor.new("Bright orange")
spark.Material = Enum.Material.Neon
Debris:AddItem(spark, 0.1)
-- Check if enemy
if hitPart.Parent and hitPart.Parent:FindFirstChild("Humanoid") then
local hum = hitPart.Parent:FindFirstChild("Humanoid")
if hum and hum.Health > 0 then
local dmg = isHeadshot and w.Damage * w.HeadMulti or w.Damage
if w.Explosive then
dmg = w.Damage
-- Explosion
local explosion = Instance.new("Explosion", workspace)
explosion.Position = result.Position
explosion.BlastRadius = w.BlastRadius or 20
explosion.BlastPressure = 500000
end
HitEvent:FireServer(hitPart, dmg, isHeadshot, w.Name)
if hum.Health <= 0 then
kills = kills + 1
killStreak = killStreak + 1
lastKillTime = tick()
-- Update score
if hud then
local st = hud:FindFirstChild("ScoreFrame"):FindFirstChild("ScoreText")
if st then st.Text = "KILLS: " .. kills end
-- Kill streak banner
local banner = hud:FindFirstChild("StreakBanner")
if banner then
local streaks = {
{2, "DOUBLE KILL!"},
{3, "TRIPLE KILL!"},
{5, "KILLING SPREE!"},
{7, "UNSTOPPABLE!"},
{10, "GODLIKE!"},
}
for _, s in ipairs(streaks) do
if killStreak == s[1] then
banner.Text = s[2]
banner.Visible = true
task.delay(2, function()
banner.Visible = false
end)
break
end
end
end
end
KillEvent:FireServer("EnemySoldier")
end
end
end
end
end
-- Recoil
recoilOffset = math.min(recoilOffset + w.Recoil, w.Recoil * 5)
spreadOffset = math.min(spreadOffset + w.Spread * 0.5, w.Spread * 3)
-- Auto reload when empty
if currentAmmo[currentIndex] <= 0 then
task.delay(0.3, function()
if currentAmmo[currentIndex] <= 0 and not isReloading then
-- Trigger reload
isReloading = true
canShoot = false
local ww = WeaponData[currentIndex]
if hud then
hud.ReloadBar.Visible = true
hud.ReloadText.Visible = true
end
local fill = hud and hud:FindFirstChild("ReloadBar") and hud.ReloadBar:FindFirstChild("Fill")
if fill then
fill.Size = UDim2.new(0, 0, 1, 0)
TweenService:Create(fill, TweenInfo.new(ww.ReloadTime), {Size = UDim2.new(1, 0, 1, 0)}):Play()
end
task.delay(ww.ReloadTime, function()
currentAmmo[currentIndex] = ww.MagSize
isReloading = false
canShoot = true
if hud then
hud.ReloadBar.Visible = false
hud.ReloadText.Visible = false
local at = hud:FindFirstChild("AmmoFrame"):FindFirstChild("AmmoText")
if at then at.Text = currentAmmo[currentIndex] .. " / " .. ww.MagSize end
end
end)
end
end)
end
end
-- ═══════ FIRE RATE CONTROL ═══════
local holdingMouse = false
UserInputService.InputBegan:Connect(function(input, gpe)
if gpe then return end
if input.UserInputType == Enum.UserInputType.MouseButton1 then
holdingMouse = true
local w = WeaponData[currentIndex]
if w.Auto then
-- Auto fire loop
task.spawn(function()
while holdingMouse and canShoot do
shoot()
task.wait(w.FireRate)
end
end)
else
-- Semi-auto / burst
if w.BurstCount then
for b = 1, w.BurstCount do
shoot()
task.wait(w.FireRate)
end
else
shoot()
end
end
end
end)
UserInputService.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
holdingMouse = false
end
end)
-- ═══════ RECOIL / SPREAD DECAY ═══════
RunService.RenderStepped:Connect(function()
recoilOffset = math.max(recoilOffset - 0.15, 0)
spreadOffset = math.max(spreadOffset - 0.01, 0)
-- Crosshair spread visual
local hud = player.PlayerGui:FindFirstChild("FPS_HUD")
if hud then
local w = WeaponData[currentIndex]
local baseSpread = isADS and w.ADS_Spread or w.Spread
local totalSpread = baseSpread + spreadOffset
local offset = math.floor(totalSpread * 300)
local ch = hud:FindFirstChild("Crosshair")
local cv = hud:FindFirstChild("CrosshairV")
if ch then ch.Position = UDim2.new(0.5, -10 - offset, 0.5, -1) end
if cv then cv.Position = UDim2.new(0.5, -1, 0.5, -10 - offset) end
end
-- Kill streak decay
if tick() - lastKillTime > 5 and killStreak > 0 then
killStreak = 0
end
end)
-- Initialize first weapon display
switchWeapon(1)
print("[WeaponController] 20 weapons loaded!")
]]
-- ═══════════════════════════════════════════════════════════════
-- WEAPON LIST HUD (keys display)
-- ═══════════════════════════════════════════════════════════════
local weaponListFrame = hud:FindFirstChild("WeaponList")
if weaponListFrame then
local keyLabels = {
{key="1-6", label="ASSAULT RIFLES", color=Color3.fromRGB(100,150,255)},
{key="7-0", label="SMGS", color=Color3.fromRGB(100,255,100)},
{key="Q/E/T", label="SNIPERS", color=Color3.fromRGB(255,100,100)},
{key="Z/X", label="SHOTGUNS", color=Color3.fromRGB(255,200,50)},
{key="C/V", label="LMGS", color=Color3.fromRGB(200,100,255)},
{key="B/N/G", label="PISTOL/LAUNCHER", color=Color3.fromRGB(255,150,100)},
}
for i, kl in ipairs(keyLabels) do
local lbl = Instance.new("TextLabel", weaponListFrame)
lbl.Size = UDim2.new(1/#keyLabels, 0, 1, 0)
lbl.Position = UDim2.new((i-1)/#keyLabels, 0, 0, 0)
lbl.BackgroundColor3 = kl.color
lbl.BackgroundTransparency = 0.7
lbl.TextColor3 = Color3.new(1, 1, 1)
lbl.Font = Enum.Font.GothamBold
lbl.TextSize = 10
lbl.Text = "["..kl.key.."] "..kl.label
end
end
print("════════════════════════════════════════════")
print(" MINI CALL OF DUTY - 20 WEAPONS LOADED!")
print(" Press F5 (Play) to start the game")
print(" WASD=Move LMB=Shoot RMB=ADS")
print(" Shift=Sprint Ctrl=Crouch R=Reload")
print(" Keys 1-6 = Assault Rifles")
print(" Keys 7,8,9,0 = SMGs")
print(" Keys Q,E,T = Snipers")
print(" Keys Z,X = Shotguns")
print(" Keys C,V = LMGs")
print(" Keys B,N = Pistols")
print(" Key G = RPG-7 Launcher")
print("════════════════════════════════════════════")