175 lines
5.0 KiB
Plaintext
175 lines
5.0 KiB
Plaintext
local script = script.Parent.Pieces.PieceScript
|
|
|
|
if not script.Parent:FindFirstChild("Roots") then game.ServerStorage.Roots.Parent = script.Parent end
|
|
local roots = {}
|
|
for _,root in pairs(script.Parent.Roots:GetChildren()) do
|
|
if root.Name == "Root" then
|
|
root.Anchored = true
|
|
root.Transparency = 1
|
|
root.CanCollide = false
|
|
table.insert(roots,root)
|
|
end
|
|
end
|
|
-- piece: {"X,Y,Z,NX,NY,NZ,A,B...} marking each property it has
|
|
local pieces = {}
|
|
for _,piece in pairs(script.Parent:GetChildren()) do
|
|
if piece:IsA("Model") then
|
|
-- Set of 'characteristics' this has, equivalent to (unary?) branches in lhmes14c
|
|
local characteristics = {}
|
|
|
|
local position = piece:GetPivot().Position
|
|
local closest_root
|
|
local closest = 32
|
|
for _,root in pairs(roots) do
|
|
local distance = (root.Position - position).Magnitude
|
|
if distance < closest then
|
|
closest = distance
|
|
closest_root = root
|
|
end
|
|
end
|
|
|
|
if closest_root then
|
|
closest_root.Parent = piece
|
|
piece.PrimaryPart = closest_root
|
|
end
|
|
|
|
-- Make sure there is a PrimaryPart
|
|
if not piece.PrimaryPart then
|
|
piece.PrimaryPart = piece:FindFirstChildWhichIsA("BasePart")
|
|
end
|
|
if not piece.PrimaryPart then
|
|
warn(string.format("Piece: '%s' has no viable PrimaryPart (empty), please provide one.",piece.Name))
|
|
continue
|
|
end
|
|
|
|
-- Weld all Parts together
|
|
piece.PrimaryPart.Anchored = true
|
|
local template_weld = Instance.new("WeldConstraint")
|
|
template_weld.Part0 = piece.PrimaryPart
|
|
for _,item in pairs(piece:GetChildren()) do
|
|
if item:IsA("BasePart") and item ~= piece.PrimaryPart then
|
|
local weld = template_weld:Clone()
|
|
weld.Parent = piece
|
|
weld.Part1 = item
|
|
end
|
|
end
|
|
|
|
-- Populate characteristics
|
|
for literal in string.gmatch(piece.Name,"[^%.]+") do
|
|
local value,class = string.match(literal,"^(!?)(.*)")
|
|
characteristics[class] = #value == 0
|
|
end
|
|
|
|
piece.Parent = game.ServerStorage
|
|
--piece:ScaleTo()
|
|
table.insert(pieces,{characteristics = characteristics,piece = piece})
|
|
end
|
|
end
|
|
-- Compute whether variants are viable and actually copy/rotate them as options
|
|
local rotator = {
|
|
["X"] = "Z",
|
|
["Z"] = "NX",
|
|
["NX"] = "NZ",
|
|
["NZ"] = "X"
|
|
}
|
|
local function alreadyExists(match)
|
|
for _,piece in pairs(pieces) do
|
|
local success = true
|
|
for class,value in pairs(match) do
|
|
if piece.characteristics[class] ~= value then success = false break end
|
|
end
|
|
if success then return true end
|
|
end
|
|
end
|
|
local function rotateClass(class)
|
|
return rotator[class] or class
|
|
end
|
|
local new_pieces = {}
|
|
for _,piece in pairs(pieces) do -- This isn't very optimised, but it runs at the start of the program, this is ok.
|
|
local r90 = {}
|
|
local r180 = {}
|
|
local r270 = {}
|
|
for class,value in pairs(piece.characteristics) do
|
|
local c90 = rotateClass(class)
|
|
local c180 = rotateClass(c90)
|
|
local c270 = rotateClass(c180)
|
|
r90[c90] = value
|
|
r180[c180] = value
|
|
r270[c270] = value
|
|
end
|
|
local function pieceFactory(angle,characteristics)
|
|
if not alreadyExists(characteristics) then
|
|
local new_piece = piece.piece:Clone()
|
|
new_piece.Name = "V."..new_piece.Name
|
|
new_piece:PivotTo(new_piece:GetPivot() * CFrame.Angles(0,math.rad(angle),0))
|
|
table.insert(new_pieces,{piece = new_piece,characteristics = characteristics})
|
|
end
|
|
end
|
|
pieceFactory(270,r90)
|
|
pieceFactory(180,r180)
|
|
pieceFactory(90,r270)
|
|
end
|
|
for _,piece in pairs(pieces) do table.insert(new_pieces,piece) end
|
|
pieces = new_pieces
|
|
|
|
--[[local city = function(x,y,z)
|
|
return (math.noise(x*0.16,y*0.16,z*0.16) - (y * 0.05) + 0.2) > 0
|
|
end]]
|
|
|
|
local scale = 4
|
|
local template_part = Instance.new("Part")
|
|
template_part.Anchored = true
|
|
template_part.Name = "PieceTemplate"
|
|
template_part.CanCollide = false
|
|
template_part.Transparency = 0.5
|
|
template_part.Size = Vector3.one * scale
|
|
|
|
local function block(x,y,z,f,city)
|
|
local X = city(x+f,y,z)
|
|
local Y = city(x,y+f,z)
|
|
local Z = city(x,y,z+f)
|
|
local NX = city(x-f,y,z)
|
|
local NY = city(x,y-f,z)
|
|
local NZ = city(x,y,z-f)
|
|
local match = { -- The matching characteristics table for the hypothetical piece in this place
|
|
X = X,
|
|
Y = Y,
|
|
Z = Z,
|
|
NX = NX,
|
|
NY = NY,
|
|
NZ = NZ
|
|
}
|
|
if X and Y and Z and NX and NY and NZ then return false end
|
|
local greatest_rank = 0 -- The amount of matching characteristics for the best matching piece
|
|
local greatest = template_part -- The physical piece
|
|
for _,piece in pairs(pieces) do -- Look through every known piece
|
|
local rank = 0
|
|
for class,value in pairs(match) do -- Assimilate a rank of the characteristics it shares with this hypothetical one
|
|
local this = piece.characteristics[class]
|
|
if value == this then rank = rank + 1 elseif this ~= nil then rank = rank - 1 end -- If it's greatest, make it so
|
|
end
|
|
if rank > greatest_rank or (rank == greatest_rank and (math.random(1,10) > 3)) then
|
|
greatest = piece.piece
|
|
greatest_rank = rank
|
|
end
|
|
end
|
|
greatest = greatest:Clone()
|
|
greatest.Parent = game.Workspace -- Position it
|
|
greatest:PivotTo(greatest:GetPivot().Rotation + Vector3.new(x,y,z))
|
|
return true
|
|
end
|
|
|
|
--[[local function gen()
|
|
for x = 1,20 do
|
|
for y = 1,15 do
|
|
for z = 1,20 do
|
|
if city(x,y,z) then
|
|
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end]]
|
|
|
|
return {block=block}
|