-- ═══════════════════════════════════════════════════════════════════ -- MINI CALL OF DUTY - FPS Game Setup (Part 3: Enemy AI + Server Handler) -- ═══════════════════════════════════════════════════════════════════ local SSS = game:GetService("ServerScriptService") local RS = game:GetService("ReplicatedStorage") -- ═══════════════════════════════════════════════════════════════ -- SERVER GAME HANDLER -- ═══════════════════════════════════════════════════════════════ local serverScript = Instance.new("Script") serverScript.Name = "GameServer" serverScript.Parent = SSS serverScript.Source = [[ local Players = game:GetService("Players") local RS = game:GetService("ReplicatedStorage") local Events = RS:WaitForChild("Events") local Shared = RS:WaitForChild("Shared") local WeaponData = require(Shared:WaitForChild("WeaponData")) local scores = {} local killFeed = {} -- Player setup Players.PlayerAdded:Connect(function(player) scores[player.UserId] = {kills = 0, deaths = 0, streak = 0} player.CharacterAdded:Connect(function(char) task.wait(0.5) local hum = char:WaitForChild("Humanoid") hum.MaxHealth = 100 hum.Health = 100 hum.WalkSpeed = 20 -- Give starter weapon visual local tool = Instance.new("Tool") tool.Name = "M4A1" tool.RequiresHandle = true tool.CanBeDropped = false local handle = Instance.new("Part") handle.Name = "Handle" handle.Size = Vector3.new(0.5, 0.5, 3) handle.Color = Color3.fromRGB(40, 40, 40) handle.Material = Enum.Material.SmoothPlastic handle.CanCollide = false handle.Anchored = false handle.Parent = tool tool.Parent = player.Backpack -- Gun body local barrel = Instance.new("Part") barrel.Name = "Barrel" barrel.Size = Vector3.new(0.2, 0.2, 2) barrel.Color = Color3.fromRGB(30, 30, 30) barrel.Material = Enum.Material.Metal barrel.CanCollide = false barrel.Anchored = false local weld = Instance.new("WeldConstraint") weld.Part0 = handle weld.Part1 = barrel weld.Parent = barrel barrel.CFrame = handle.CFrame * CFrame.new(0, 0.1, -2) barrel.Parent = tool -- Magazine local mag = Instance.new("Part") mag.Name = "Magazine" mag.Size = Vector3.new(0.3, 0.8, 0.4) mag.Color = Color3.fromRGB(35, 35, 35) mag.Material = Enum.Material.SmoothPlastic mag.CanCollide = false mag.Anchored = false local weld2 = Instance.new("WeldConstraint") weld2.Part0 = handle weld2.Part1 = mag weld2.Parent = mag mag.CFrame = handle.CFrame * CFrame.new(0, -0.5, -0.5) mag.Parent = tool -- Health regeneration task.spawn(function() while hum and hum.Health > 0 do task.wait(3) if hum.Health < hum.MaxHealth and hum.Health > 0 then hum.Health = math.min(hum.MaxHealth, hum.Health + 5) end end end) -- Death handler hum.Died:Connect(function() scores[player.UserId].deaths = scores[player.UserId].deaths + 1 scores[player.UserId].streak = 0 -- Respawn after 5 seconds task.delay(5, function() if player then player:LoadCharacter() end end) end) end) end) -- Handle hit events from clients Events:WaitForChild("ShootEvent").OnServerEvent:Connect(function(player, data) -- Validate the shot if not data or not data.hit then return end local hitObj = data.hit local weaponName = data.weapon or "M4A1" local weapon = WeaponData[weaponName] if not weapon then return end -- Check range local char = player.Character if not char then return end local dist = (data.hitPos - char.Head.Position).Magnitude if dist > weapon.range then return end -- Find the humanoid of what was hit local targetHum = nil local isHeadshot = false if hitObj:IsA("Model") then targetHum = hitObj:FindFirstChildOfClass("Humanoid") elseif hitObj.Parent and hitObj.Parent:IsA("Model") then targetHum = hitObj.Parent:FindFirstChildOfClass("Humanoid") elseif hitObj.Parent and hitObj.Parent.Parent and hitObj.Parent.Parent:IsA("Model") then targetHum = hitObj.Parent.Parent:FindFirstChildOfClass("Humanoid") end -- Check headshot if hitObj.Name == "Head" and targetHum then isHeadshot = true end -- Apply damage if targetHum then local dmg = weapon.damage if isHeadshot then dmg = dmg * weapon.headshotMult end targetHum:TakeDamage(dmg) -- Check if killed if targetHum.Health <= 0 then local victim = nil for _, p in ipairs(Players:GetPlayers()) do if p.Character and p.Character:FindFirstChildOfClass("Humanoid") == targetHum then victim = p break end end if victim then scores[player.UserId].kills = scores[player.UserId].kills + 1 scores[player.UserId].streak = scores[player.UserId].streak + 1 end -- Fire kill event Events:WaitForChild("KillEvent"):FireAllClients({ killer = player.Name, victim = victim and victim.Name or "Enemy", weapon = weaponName, headshot = isHeadshot, streak = scores[player.UserId].streak, }) end -- Fire damage indicator Events:WaitForChild("DamageEvent"):FireClient(player, { hit = true, headshot = isHeadshot, damage = dmg, }) end end) -- Game data request Events:WaitForChild("GetGameData").OnServerInvoke = function(player) return { scores = scores, killFeed = killFeed, } end -- Kill feed relay Events:WaitForChild("KillEvent").OnServerEvent:Connect(function(player, data) table.insert(killFeed, 1, data) if #killFeed > 5 then table.remove(killFeed) end end) -- ═══════════════════════════════════════════════════════════════ -- ENEMY AI SYSTEM -- ═══════════════════════════════════════════════════════════════ local enemySpawns = { Vector3.new(60, 2, 80), Vector3.new(-60, 2, 80), Vector3.new(70, 2, -80), Vector3.new(-70, 2, -80), Vector3.new(0, 2, 100), Vector3.new(0, 2, -80), Vector3.new(50, 2, 0), Vector3.new(-50, 2, 0), Vector3.new(-40, 2, 50), Vector3.new(40, 2, -50), Vector3.new(-80, 2, 30), Vector3.new(80, 2, -30), } local enemies = {} local MAX_ENEMIES = 10 local SPAWN_INTERVAL = 8 local function createEnemy(pos) local model = Instance.new("Model") model.Name = "Enemy_" .. tostring(#enemies + 1) -- Humanoid local hum = Instance.new("Humanoid") hum.MaxHealth = 80 hum.Health = 80 hum.WalkSpeed = 14 hum.Parent = model -- Head local head = Instance.new("Part") head.Name = "Head" head.Size = Vector3.new(1.5, 1.5, 1.5) head.Color = Color3.fromRGB(180, 140, 110) head.Material = Enum.Material.SmoothPlastic head.CanCollide = true head.Parent = model local headMesh = Instance.new("SpecialMesh") headMesh.MeshType = Enum.MeshType.Head headMesh.Scale = Vector3.new(1.25, 1.25, 1.25) headMesh.Parent = head -- Torso local torso = Instance.new("Part") torso.Name = "HumanoidRootPart" torso.Size = Vector3.new(2, 2, 1) torso.Color = Color3.fromRGB(60, 80, 40) -- Military green torso.Material = Enum.Material.SmoothPlastic torso.CanCollide = true torso.Parent = model -- Legs local lleg = Instance.new("Part") lleg.Name = "Left Leg" lleg.Size = Vector3.new(1, 2, 1) lleg.Color = Color3.fromRGB(50, 55, 45) lleg.Material = Enum.Material.SmoothPlastic lleg.Parent = model local rleg = Instance.new("Part") rleg.Name = "Right Leg" rleg.Size = Vector3.new(1, 2, 1) rleg.Color = Color3.fromRGB(50, 55, 45) rleg.Material = Enum.Material.SmoothPlastic rleg.Parent = model -- Arms local larm = Instance.new("Part") larm.Name = "Left Arm" larm.Size = Vector3.new(1, 2, 1) larm.Color = Color3.fromRGB(60, 80, 40) larm.Material = Enum.Material.SmoothPlastic larm.Parent = model local rarm = Instance.new("Part") rarm.Name = "Right Arm" rarm.Size = Vector3.new(1, 2, 1) rarm.Color = Color3.fromRGB(60, 80, 40) rarm.Material = Enum.Material.SmoothPlastic rarm.Parent = model -- Motor6D connections local function weld(part0, part1, c0, c1) local m = Instance.new("Motor6D") m.Part0 = part0 m.Part1 = part1 if c0 then m.C0 = c0 end if c1 then m.C1 = c1 end m.Parent = part0 end weld(torso, head, CFrame.new(0, 1.5, 0), CFrame.new(0, 0, 0)) weld(torso, larm, CFrame.new(-1.5, 0, 0), CFrame.new(0.5, 0, 0)) weld(torso, rarm, CFrame.new(1.5, 0, 0), CFrame.new(-0.5, 0, 0)) weld(torso, lleg, CFrame.new(-0.5, -2, 0), CFrame.new(0, 1, 0)) weld(torso, rleg, CFrame.new(0.5, -2, 0), CFrame.new(0, 1, 0)) -- Beret/hat local hat = Instance.new("Part") hat.Name = "Hat" hat.Size = Vector3.new(1.8, 0.5, 1.8) hat.Color = Color3.fromRGB(40, 50, 30) hat.Material = Enum.Material.SmoothPlastic hat.CanCollide = false hat.Parent = model local hatWeld = Instance.new("WeldConstraint") hatWeld.Part0 = head hatWeld.Part1 = hat hatWeld.Parent = hat hat.CFrame = head.CFrame * CFrame.new(0, 0.9, 0) -- Health bar above head local billboard = Instance.new("BillboardGui") billboard.Name = "HealthBar" billboard.Size = UDim2.new(3, 0, 0.4, 0) billboard.StudsOffset = Vector3.new(0, 3.5, 0) billboard.AlwaysOnTop = true billboard.Parent = head local bg = Instance.new("Frame") bg.Size = UDim2.new(1, 0, 1, 0) bg.BackgroundColor3 = Color3.fromRGB(40, 40, 40) bg.BorderSizePixel = 0 bg.Parent = billboard local fill = Instance.new("Frame") fill.Name = "Fill" fill.Size = UDim2.new(1, 0, 1, 0) fill.BackgroundColor3 = Color3.fromRGB(200, 30, 30) fill.BorderSizePixel = 0 fill.Parent = bg -- AI Script local aiScript = Instance.new("Script") aiScript.Source = [[ local humanoid = script.Parent:FindFirstChildOfClass("Humanoid") local rootPart = script.Parent:FindFirstChild("HumanoidRootPart") local head = script.Parent:FindFirstChild("Head") local healthFill = script.Parent:FindFirstChild("Head"):FindFirstChild("HealthBar"):FindFirstChild("Frame"):FindFirstChild("Fill") if not humanoid or not rootPart then return end local state = "patrol" local target = nil local lastShot = 0 local fireRate = 1.2 local damage = 12 local detectionRange = 80 local attackRange = 60 local patrolPoints = {} local currentPatrolIndex = 1 -- Generate patrol points for i = 1, 6 do local angle = math.rad(math.random(360)) local dist = math.random(15, 60) table.insert(patrolPoints, rootPart.Position + Vector3.new(math.cos(angle)*dist, 0, math.sin(angle)*dist)) end -- Find closest player local function findTarget() local closest = nil local closestDist = detectionRange for _, player in ipairs(game:GetService("Players"):GetPlayers()) do if player.Character then local hum = player.Character:FindFirstChildOfClass("Humanoid") if hum and hum.Health > 0 then local dist = (player.Character.Head.Position - rootPart.Position).Magnitude if dist < closestDist then closest = player closestDist = dist end end end end return closest, closestDist end -- Update health bar humanoid.HealthChanged:Connect(function(health) local pct = health / humanoid.MaxHealth healthFill.Size = UDim2.new(pct, 0, 1, 0) if pct < 0.3 then healthFill.BackgroundColor3 = Color3.fromRGB(200, 30, 30) else healthFill.BackgroundColor3 = Color3.fromRGB(200, 60, 30) end end) -- Main AI loop while humanoid and humanoid.Health > 0 do task.wait(0.3) target, _ = findTarget() if target and target.Character then local targetHum = target.Character:FindFirstChildOfClass("Humanoid") local targetHead = target.Character:FindFirstChild("Head") if targetHum and targetHum.Health > 0 and targetHead then local dist = (targetHead.Position - rootPart.Position).Magnitude -- Face target rootPart.CFrame = CFrame.new(rootPart.Position, Vector3.new(targetHead.Position.X, rootPart.Position.Y, targetHead.Position.Z)) if dist <= attackRange then state = "attack" -- Shoot at player if tick() - lastShot > fireRate then lastShot = tick() -- Raycast to player local direction = (targetHead.Position - head.Position).Unit local spread = Vector3.new(math.random()-0.5, math.random()-0.5, math.random()-0.5) * 2 local hitResult = workspace:Raycast(head.Position, (direction + spread) * attackRange) if hitResult then -- 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 = head.Position + direction * 2 flash.Parent = workspace game:GetService("Debris"):AddItem(flash, 0.08) -- Bullet trail local trail = Instance.new("Part") trail.Size = Vector3.new(0.1, 0.1, (head.Position - hitResult.Position).Magnitude) trail.CFrame = CFrame.new(head.Position, hitResult.Position) * CFrame.new(0, 0, -trail.Size.Z/2) trail.Anchored = true trail.CanCollide = false trail.Color = Color3.fromRGB(255, 200, 100) trail.Material = Enum.Material.Neon trail.Transparency = 0.3 trail.Parent = workspace game:GetService("Debris"):AddItem(trail, 0.1) -- Check if hit player local hitChar = hitResult.Instance if hitChar then local hitHum = nil if hitChar.Parent and hitChar.Parent:FindFirstChildOfClass("Humanoid") then hitHum = hitChar.Parent:FindFirstChildOfClass("Humanoid") elseif hitChar.Parent and hitChar.Parent.Parent and hitChar.Parent.Parent:FindFirstChildOfClass("Humanoid") then hitHum = hitChar.Parent.Parent:FindFirstChildOfClass("Humanoid") end if hitHum and hitHum ~= humanoid then hitHum:TakeDamage(damage) end end -- Impact effect local impact = Instance.new("Part") impact.Size = Vector3.new(0.5, 0.5, 0.5) impact.Shape = Enum.PartType.Ball impact.Color = Color3.fromRGB(255, 150, 50) impact.Material = Enum.Material.Neon impact.Anchored = true impact.CanCollide = false impact.Position = hitResult.Position impact.Parent = workspace game:GetService("Debris"):AddItem(impact, 0.15) end end else -- Move toward target state = "chase" humanoid:MoveTo(targetHead.Position) end end else -- Patrol state = "patrol" if #patrolPoints > 0 then humanoid:MoveTo(patrolPoints[currentPatrolIndex]) humanoid.MoveToFinished:Connect(function(reached) if reached then currentPatrolIndex = (currentPatrolIndex % #patrolPoints) + 1 end end) end end end -- Death effect local root = script.Parent:FindFirstChild("HumanoidRootPart") if root then for _, v in ipairs(script.Parent:GetDescendants()) do if v:IsA("BasePart") then v.Anchored = false v.BrickColor = BrickColor.new("Dark stone grey") local bf = Instance.new("BodyForce") bf.Force = Vector3.new(math.random(-50,50), 100, math.random(-50,50)) bf.Parent = v game:GetService("Debris"):AddItem(v, 3) end end end task.delay(3, function() if script.Parent then script.Parent:Destroy() end end) ]] aiScript.Parent = model -- Position local primary = torso model.PrimaryPart = primary primary.Position = pos head.Position = pos + Vector3.new(0, 2.5, 0) lleg.Position = pos + Vector3.new(-0.5, -1, 0) rleg.Position = pos + Vector3.new(0.5, -1, 0) larm.Position = pos + Vector3.new(-1.5, 0, 0) rarm.Position = pos + Vector3.new(1.5, 0, 0) model.Parent = workspace table.insert(enemies, model) return model end -- Enemy spawner loop task.spawn(function() task.wait(5) -- Initial delay while true do -- Remove dead enemies for i = #enemies, 1, -1 do if not enemies[i] or not enemies[i]:FindFirstChildOfClass("Humanoid") or enemies[i]:FindFirstChildOfClass("Humanoid").Health <= 0 then table.remove(enemies, i) end end -- Spawn new enemies if #enemies < MAX_ENEMIES then local pos = enemySpawns[math.random(#enemySpawns)] createEnemy(pos + Vector3.new(math.random(-5,5), 0, math.random(-5,5))) end task.wait(SPAWN_INTERVAL) end end) print("[GameServer] Enemy AI system active. Spawning " .. MAX_ENEMIES .. " enemies.") ]] print("[CoD FPS] Part 3/5 complete: Server handler + Enemy AI created.")