Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local ReplicatedStorage = game:GetService("ReplicatedStorage")
- local clock = require(ReplicatedStorage.TimeSyncManager)
- local NG = require(script.NameGenerator)
- local DecisionTree = require(script.NPCDecisionTree)
- local sin = math.sin
- local NPC_IdCount = 1
- local NPC_Count = 0
- local events = {}
- local folder = Instance.new("Folder")
- folder.Name = "NPC_Events"
- folder.Parent = ReplicatedStorage
- local function registerEvent(name)
- local NewNpcEvent = Instance.new("RemoteEvent")
- NewNpcEvent.Name = name
- NewNpcEvent.Parent = folder
- events[name] = NewNpcEvent
- return NewNpcEvent
- end
- registerEvent("NewNpc")
- registerEvent("WatchNpc")
- local npcFolder = Instance.new("Folder")
- npcFolder.Name = "NPCs"
- npcFolder.Parent = workspace
- local boidTemp = Instance.new("Part")
- boidTemp.Anchored = true
- boidTemp.CanCollide = false
- boidTemp.Size = Vector3.new(1,2,1)
- boidTemp.CFrame = CFrame.new(0,5,0)
- boidTemp.TopSurface = "Smooth"
- boidTemp.BottomSurface = "Smooth"
- boidTemp.Material = "SmoothPlastic"
- local boidProperties = Instance.new("Folder")
- boidProperties.Name = "Properties"
- boidProperties.Parent = boidTemp
- ---------------------------------------------------------------------------------------------------------------------------------
- -- / Private Methods /--
- ---------------------------------------------------------------------------------------------------------------------------------
- local function RunStatChanges(self)
- --print("A second has passed, updating for NPC_"..self.id)
- local s = self.stats
- s.stamina = s.stamina - .1
- s.thirst = s.thirst < 100 and s.thirst + .25 or 100
- s.hunger = s.hunger < 100 and s.hunger + .1 or 100
- local t, h = s.thirst, s.hunger
- if t > 85 or h > 85 then
- s.health = s.health - 1
- --s.walkSpeed = 12 -- slowdown when starving
- elseif h < 30 then
- s.health = s.health < 100 and s.health + .5 or 100
- end
- if s.health <= 0 then
- -- kill npc
- end
- if s.stamina <= 0 then
- s.stamina = 0
- --s.walkSpeed = 16
- else
- -- reset walkspeed?
- end
- --[[
- for stat, val in pairs(self.stats) do
- print(stat..": "..val)
- end]]
- end
- local function BeginUpdateCycle(self)
- local HB
- local t = 0 -- time passed tracker
- local logic = DecisionTree()
- logic:setObject(self)
- HB = game:GetService("RunService").Heartbeat:Connect(function(timePassed)
- logic:run()
- t = t + timePassed
- if t >= 1 then
- t = t - 1
- RunStatChanges(self)
- end
- end)
- return HB
- end
- local function newBoid(id)
- local b = boidTemp:Clone()
- b.Name = id
- b.Parent = npcFolder
- return b
- end
- local function initStats(stats)
- local function newItem(Type,Value)
- local obj = Instance.new(Type)
- obj.Value = Value
- obj.Parent = stats[2]
- end
- for stat, value in pairs(stats[1]) do
- local t = typeof(value)
- if t == "number" then
- newItem("NumberValue",value)
- elseif t == "boolean" then
- newItem("BoolValue",value)
- elseif t == "string" then
- newItem("StringValue",value)
- elseif t == "Instance" then
- newItem("ObjectValue",value)
- else
- warn("Illegal Type:",t,"for property:",stat)
- end
- end
- end
- ---------------------------------------------------------------------------------------------------------------------------------
- -- / Metatable Handling / --
- ---------------------------------------------------------------------------------------------------------------------------------
- local NPC = {npcs = {}}
- NPC.__index = NPC
- NPC.__tostring = function(t)
- return "NPC_"..t.id..":\t"..t.firstName.." "..t.lastName.."\n\tAge: "..t.age.."\n\tSex: "..(t.sex == 1 and "Male" or "Female")
- end
- function NPC:Init()
- print("Initialized Server Side")
- end
- local StatManager = {}
- StatManager.__index = function(t,k)
- return t[1][k:lower()]
- end
- StatManager.__newindex = function(t,k,v)
- k = k:lower()
- t[1][k] = v
- local prop = t[2]:FindFirstChild(k)
- if prop then
- prop.Value = v
- end
- end
- ---------------------------------------------------------------------------------------------------------------------------------
- -- / Constructors / --
- ---------------------------------------------------------------------------------------------------------------------------------
- function NPC.new()
- -- Prebuild setup for multi use data
- local s = math.random(1,2) -- sex: 1 is male, 2 is female
- -- put custom data here (you can erase anything in this table)
- local container = setmetatable({
- mom = nil,
- dad = nil,
- children = {},
- sex = s,
- firstName = NG.NewFirstName(s),
- lastName = NG.LastNames[math.random(#NG.LastNames)],
- age = math.random(18,64),
- home = nil,
- job = nil,
- }, NPC)
- container.__index = container
- container.__newindex = function(t,k,v)
- t:Set(k,v)
- end
- local b = newBoid(NPC_IdCount)
- local self = setmetatable({
- -- Core Data (Immutable)
- id = NPC_IdCount,
- boid = b,
- event = registerEvent("UpdateRegisterNPC_"..NPC_Count),
- -- Stat Data (represented as object values) (change however you like)
- stats = setmetatable({{
- health = 100,
- hunger = 0,
- thirst = 0,
- stamina = 100,
- walkspeed = 10
- },b.Properties},StatManager),
- -- properties to update to client
- watchList = {},
- }, container)
- -- Finalizations
- NPC_IdCount = NPC_IdCount + 1
- NPC_Count = NPC_Count + 1
- initStats(self.stats)
- NPC.npcs[self.boid] = self
- events.NewNpc:FireAllClients(self.event,self.boid)
- self.updateCycle = BeginUpdateCycle(self)
- return self
- end
- --[[
- function NPC.birth(mom,dad)
- local self = NPC.new()
- self.mom = mom
- self.dad = dad
- self.age = 0
- return self
- end]]
- function NPC:CreateOnClient(plr)
- events.NewNpc:FireClient(plr,self.event,self.boid)
- end
- ---------------------------------------------------------------------------------------------------------------------------------
- -- / Public Methods / -- (Dont mess with these)
- ---------------------------------------------------------------------------------------------------------------------------------
- function NPC:Destroy()
- NPC.npcs[self.boid] = nil
- -- tell clients to destroy their copy
- self.updateCycle:Disconnect()
- self.boid:Destroy()
- NPC_Count = NPC_Count - 1
- end
- -- Client manager for custom data
- function NPC:Set(property, newVal)
- end
- function NPC:Watch(plr,...)
- local props = type(...) == "table" and ... or {...}
- end
- function NPC:StopWatching(property)
- end
- function NPC:GetWalkSpeed()
- return self.stats.walkSpeed - self.age/40
- end
- function NPC:GoTo(pos)
- return self:MoveTo(pos)
- end
- function NPC:MoveTo(pos)
- local dist = (self.boid.Position - pos).magnitude
- local t = dist/self:GetWalkSpeed()
- local startTime = clock:GetTime()
- self.boid.CFrame = CFrame.new(pos)
- self.event:FireAllClients("MoveTo", pos, startTime, startTime+t)
- --print("time to complete:",t)
- wait(t-.05)
- return true
- end
- ---------------------------------------------------------------------------------------------------------------------------------
- -- / Custom Public Methods / -- (Put your custom methods here)
- ---------------------------------------------------------------------------------------------------------------------------------
- -- Optional
- -- Takes a string and sets the npcs name
- function NPC:SetName(newName)
- self.firstName = newName
- end
- -- Optional
- -- Ages the npc by one year
- function NPC:Age()
- self.age = self.age + 1
- return self.age
- end
- -- Module Close --
- return NPC
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement