File size: 4,797 Bytes
0712d5f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | -- src/ServerScriptService/NPCManager.server.lua
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
local NPCConfig = require(ReplicatedStorage:WaitForChild("Shared"):WaitForChild("NPCConfig"))
local DialogueEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("DialogueEvent")
local ShopEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("ShopEvent")
local npcFolder = Instance.new("Folder")
npcFolder.Name = "NPCs"
npcFolder.Parent = workspace
local function createNPCModel(npcId, npcData)
local model = Instance.new("Model")
model.Name = npcId
-- Create humanoid R6-style body parts
local torso = Instance.new("Part")
torso.Name = "HumanoidRootPart"
torso.Size = Vector3.new(2, 2, 1)
torso.Position = npcData.Position
torso.Anchored = true
torso.Color = npcData.BodyColors.TorsoColor
torso.Material = Enum.Material.SmoothPlastic
torso.Parent = model
local head = Instance.new("Part")
head.Name = "Head"
head.Shape = Enum.PartType.Ball
head.Size = Vector3.new(1.6, 1.6, 1.6)
head.Position = npcData.Position + Vector3.new(0, 1.8, 0)
head.Anchored = true
head.Color = npcData.BodyColors.HeadColor
head.Material = Enum.Material.SmoothPlastic
head.Parent = model
-- Face decal
local face = Instance.new("Decal")
face.Face = Enum.NormalId.Front
face.Texture = "rbxasset://textures/face.png"
face.Parent = head
-- Left Arm
local leftArm = Instance.new("Part")
leftArm.Name = "LeftArm"
leftArm.Size = Vector3.new(1, 2, 1)
leftArm.Position = npcData.Position + Vector3.new(-1.5, 0, 0)
leftArm.Anchored = true
leftArm.Color = npcData.BodyColors.LeftArmColor
leftArm.Material = Enum.Material.SmoothPlastic
leftArm.Parent = model
-- Right Arm
local rightArm = Instance.new("Part")
rightArm.Name = "RightArm"
rightArm.Size = Vector3.new(1, 2, 1)
rightArm.Position = npcData.Position + Vector3.new(1.5, 0, 0)
rightArm.Anchored = true
rightArm.Color = npcData.BodyColors.RightArmColor
rightArm.Material = Enum.Material.SmoothPlastic
rightArm.Parent = model
-- Left Leg
local leftLeg = Instance.new("Part")
leftLeg.Name = "LeftLeg"
leftLeg.Size = Vector3.new(1, 2, 1)
leftLeg.Position = npcData.Position + Vector3.new(-0.5, -2, 0)
leftLeg.Anchored = true
leftLeg.Color = npcData.BodyColors.LeftLegColor
leftLeg.Material = Enum.Material.SmoothPlastic
leftLeg.Parent = model
-- Right Leg
local rightLeg = Instance.new("Part")
rightLeg.Name = "RightLeg"
rightLeg.Size = Vector3.new(1, 2, 1)
rightLeg.Position = npcData.Position + Vector3.new(0.5, -2, 0)
rightLeg.Anchored = true
rightLeg.Color = npcData.BodyColors.RightLegColor
rightLeg.Material = Enum.Material.SmoothPlastic
rightLeg.Parent = model
model.PrimaryPart = torso
-- Nameplate
local billboard = Instance.new("BillboardGui")
billboard.Size = UDim2.new(0, 200, 0, 50)
billboard.StudsOffset = Vector3.new(0, 3.5, 0)
billboard.AlwaysOnTop = true
billboard.Parent = head
local nameLabel = Instance.new("TextLabel")
nameLabel.Size = UDim2.new(1, 0, 1, 0)
nameLabel.BackgroundTransparency = 1
nameLabel.Text = npcData.DisplayName
nameLabel.TextColor3 = Color3.new(1, 1, 0.7)
nameLabel.TextScaled = true
nameLabel.Font = Enum.Font.GothamBold
nameLabel.TextStrokeTransparency = 0.5
nameLabel.Parent = billboard
-- ProximityPrompt for interaction
local prompt = Instance.new("ProximityPrompt")
prompt.ActionText = "Talk"
prompt.ObjectText = npcData.DisplayName
prompt.MaxActivationDistance = 10
prompt.HoldDuration = 0
prompt.Parent = torso
-- Track dialogue state per player
local dialogueIndex = {} -- [userId] = current line index
prompt.Triggered:Connect(function(player)
if not dialogueIndex[player.UserId] then
dialogueIndex[player.UserId] = 1
end
local lineIndex = dialogueIndex[player.UserId]
local dialogue = npcData.Dialogue
if lineIndex <= #dialogue then
DialogueEvent:FireClient(player, npcData.DisplayName, dialogue[lineIndex], lineIndex < #dialogue)
dialogueIndex[player.UserId] = lineIndex + 1
else
-- Reset dialogue
dialogueIndex[player.UserId] = 1
DialogueEvent:FireClient(player, npcData.DisplayName, dialogue[1], #dialogue > 1)
-- If shopkeeper, open shop UI
if npcData.Role == "Shopkeeper" then
ShopEvent:FireClient(player, "OpenShop")
end
end
end)
CollectionService:AddTag(model, "NPC")
model.Parent = npcFolder
return model
end
-- Spawn all NPCs
task.spawn(function()
task.wait(2) -- Wait for world structures
for npcId, npcData in pairs(NPCConfig.NPCs) do
createNPCModel(npcId, npcData)
end
print("All NPCs spawned")
end)
|