GEEKING
@@ -0,0 +1,570 @@
|
||||
-- Local function definitions
|
||||
local c = game.Workspace.Terrain
|
||||
local SetCell = c.SetCell
|
||||
local GetCell = c.GetCell
|
||||
local SetCells = c.SetCells
|
||||
local AutoWedge = c.AutowedgeCells
|
||||
|
||||
|
||||
-----------------
|
||||
--DEFAULT VALUES-
|
||||
-----------------
|
||||
loaded = false
|
||||
xpos = 0
|
||||
zpos = 0
|
||||
width = 512
|
||||
length = 512
|
||||
a = 30
|
||||
f = 8
|
||||
on = false
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--PLUGIN SETUP-
|
||||
---------------
|
||||
self = PluginManager():CreatePlugin()
|
||||
self.Deactivation:connect(function()
|
||||
Off()
|
||||
end)
|
||||
toolbar = self:CreateToolbar("Terrain")
|
||||
toolbarbutton = toolbar:CreateButton("", "Terrain Generator", "terrain.png")
|
||||
toolbarbutton.Click:connect(function()
|
||||
if on then
|
||||
Off()
|
||||
elseif loaded then
|
||||
On()
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
--FUNCTION DEFINITIONS-
|
||||
-----------------------
|
||||
|
||||
--makes a column of blocks from 1 up to height at location (x,z) in cluster c
|
||||
function coordHeight(x, z, height)
|
||||
SetCells(c, Region3int16.new(Vector3int16.new(x, 1, z), Vector3int16.new(x, height, z)), 1, 0, 0)
|
||||
end
|
||||
|
||||
--makes a heightmap for a layer of mountains (width x depth)
|
||||
--with a width frequency wf and depthfrequency df (width should be divisible by wf, depth should be divisible by df) (for unsquished results, width/wf = depth/df)
|
||||
--with a range of amplitudes between 0 and a
|
||||
function mountLayer(width, depth, wf, df, a)
|
||||
local heightmap = {}
|
||||
for i = 0, width-1 do
|
||||
heightmap[i] = {}
|
||||
for k = 0, depth-1 do
|
||||
heightmap[i][k] = 0
|
||||
end
|
||||
end
|
||||
math.randomseed(tick())
|
||||
local corners = {}
|
||||
for i = 0,wf do
|
||||
corners[i] = {}
|
||||
for k = 0, df do
|
||||
corners[i][k] = a*math.random()
|
||||
end
|
||||
end
|
||||
for i = 0, wf do
|
||||
corners[i][0] = 0
|
||||
corners[i][math.floor(df)] = 0
|
||||
end
|
||||
for k = 0, df do
|
||||
corners[0][k]=0
|
||||
corners[math.floor(wf)][k]=0
|
||||
end
|
||||
|
||||
for i = 0, width-(width/wf), width/wf do
|
||||
for k = 0, depth-(depth/df), depth/df do
|
||||
local c1 = corners[i/(width/wf)][k/(depth/df)]
|
||||
local c2 = corners[i/(width/wf)][(k+depth/df)/(depth/df)]
|
||||
local c3 = corners[(i+width/wf)/(width/wf)][k/(depth/df)]
|
||||
local c4 = corners[(i+width/wf)/(width/wf)][(k+depth/df)/(depth/df)]
|
||||
for x = i, i+(width/wf)-1 do
|
||||
for z = k, k+(depth/df)-1 do
|
||||
local avgc1c3 = (math.abs(x-i)*c3 + math.abs(x-(i+width/wf))*c1)/(width/wf)
|
||||
local avgc2c4 = (math.abs(x-i)*c4 + math.abs(x-(i+width/wf))*c2)/(width/wf)
|
||||
local avg = math.floor((math.abs(z-k)*avgc2c4 + math.abs(z-(k+depth/df))*avgc1c3)/(depth/df))
|
||||
if (avg > 100) then
|
||||
print(avg)
|
||||
avg = 1
|
||||
end
|
||||
heightmap[x][z]= avg
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return heightmap
|
||||
end
|
||||
|
||||
--makes a shell around block at coordinate x, z using heightmap
|
||||
function makeShell(x, z, heightmap, shellheightmap)
|
||||
local originalheight = heightmap[x][z]
|
||||
for i = x - 1, x + 1 do
|
||||
for k = z - 1, z + 1 do
|
||||
if shellheightmap[i][k] < originalheight then
|
||||
for h = originalheight, shellheightmap[i][k] - 2, -1 do
|
||||
if h > 0 then
|
||||
SetCell(c, i, h, k, 1, 0, 0)
|
||||
end
|
||||
end
|
||||
shellheightmap[i][k] = originalheight
|
||||
end
|
||||
end
|
||||
end
|
||||
return shellheightmap
|
||||
end
|
||||
|
||||
function setCamera()
|
||||
local currCamera = game.Workspace.CurrentCamera
|
||||
currCamera.CoordinateFrame = CFrame.new(0, 400, 1600)
|
||||
currCamera.Focus = CFrame.new(0, 255, 0)
|
||||
end
|
||||
|
||||
|
||||
function onGenerate()
|
||||
generate.BorderColor3 = Color3.new(0, 0, 0)
|
||||
generate.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
generate.BackgroundTransparency = 0.5
|
||||
frame.Visible = false
|
||||
toolbarbutton:SetActive(false)
|
||||
on = false
|
||||
if g:FindFirstChild("gload") == nil then
|
||||
gload = Instance.new("Frame", g)
|
||||
gload.Name = "gload"
|
||||
gload.Position = UDim2.new(0.4, 0, 0.025, 0)
|
||||
gload.Size = UDim2.new(0.2, 0, 0.05, 0)
|
||||
gload.BackgroundTransparency = 0.5
|
||||
gfill = Instance.new("Frame", gload)
|
||||
gfill.Name = "gfill"
|
||||
gfill.Position = UDim2.new(0, 0, 0, 0)
|
||||
gfill.Size = UDim2.new(0, 0, 1, 0)
|
||||
gfill.BackgroundColor3 = Color3.new(1, 0.25, 0)
|
||||
gfill.BackgroundTransparency = 0.5
|
||||
gloadstatus = Instance.new("TextLabel", gload)
|
||||
gloadstatus.Position = UDim2.new(0.4, 0, 0.4, 0)
|
||||
gloadstatus.Size = UDim2.new(0.2, 0, 0.2, 0)
|
||||
gloadstatus.Text = ""
|
||||
gloadstatus.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
gloadstatus.TextColor3 = Color3.new(1, 1, 1)
|
||||
gloadstatus.Font = Enum.Font.ArialBold
|
||||
gloadstatus.FontSize = Enum.FontSize.Size14
|
||||
gloadstatus.BorderColor3 = Color3.new(0, 0, 0)
|
||||
gloadstatus.BackgroundTransparency = 1
|
||||
else
|
||||
gload = g:FindFirstChild("gload")
|
||||
gfill = gload:FindFirstChild("gfill")
|
||||
gload.Visible = 1
|
||||
gfill.Visible = 1
|
||||
gfill.Size = UDim2.new(0, 0, 1, 0)
|
||||
gloadstatus.Text = ""
|
||||
end
|
||||
|
||||
--Generate Terrain
|
||||
-- offset terrain additionally by whatever the smallest cell is
|
||||
--xpos2 = xpos + game.Workspace.Terrain.MaxExtents.Min.X
|
||||
--zpos2 = zpos + game.Workspace.Terrain.MaxExtents.Min.Z
|
||||
xpos2 = xpos - width/2
|
||||
zpos2 = zpos - length/2
|
||||
|
||||
-- make sure we can see all the terrain
|
||||
if game.Workspace.CurrentCamera.CoordinateFrame.p.Y < 255 then
|
||||
setCamera()
|
||||
end
|
||||
|
||||
--make 3 layers of mountains (you can change the frequency and amplitude of each layer and add or remove layers as you see fit (but don't forget to add the new layers to the loop below)
|
||||
a1 = mountLayer(width, length, f*width/512, f*length/512, 3/5*a)
|
||||
a2 = mountLayer(width, length, 2*f*width/512, 2*f*length/512, 2/5*a)
|
||||
heightmap = {}
|
||||
for x = 0, width - 1 do
|
||||
heightmap[x + xpos2] = {}
|
||||
for z = 0, length - 1 do
|
||||
heightmap[x + xpos2][z + zpos2] = a1[x][z] + a2[x][z]
|
||||
end
|
||||
end
|
||||
shellheightmap = {}
|
||||
for x = 0, width - 1 do
|
||||
shellheightmap[x + xpos2] = {}
|
||||
for z = 0, length - 1 do
|
||||
shellheightmap[x + xpos2][z + zpos2] = heightmap[x + xpos2][z + zpos2]
|
||||
end
|
||||
end
|
||||
gprogress = 0
|
||||
gloadstatus.Text = "Generating Terrain Shape..."
|
||||
k = 1 + zpos2
|
||||
|
||||
local waitCount = 0
|
||||
|
||||
while k < length - 1 + zpos2 do
|
||||
for x = 1 + xpos2, width - 2 + xpos2 do
|
||||
coordHeight(x, k, heightmap[x][k])
|
||||
shellheightmap = makeShell(x, k, heightmap, shellheightmap)
|
||||
end
|
||||
k = k + 1
|
||||
gprogress = gprogress + 2/(length * 3)
|
||||
gfill.Size = UDim2.new(gprogress, 0, 1, 0)
|
||||
if waitCount > 5 then waitCount = 0 wait(0.01) else waitCount = waitCount + 1 end
|
||||
end
|
||||
gloadstatus.Text = "Smoothing Terrain..."
|
||||
k = 1 + zpos2
|
||||
waitCount = 0
|
||||
local maxHeight = -1
|
||||
local oldK = k
|
||||
while k < length - 1 + zpos2 do
|
||||
for x = 1 + xpos2, width - 2 + xpos2 do
|
||||
height = shellheightmap[x][k]
|
||||
if height == nil then
|
||||
height = -1
|
||||
end
|
||||
if height > maxHeight then
|
||||
maxHeight = height
|
||||
end
|
||||
end
|
||||
k = k + 1
|
||||
gprogress = gprogress + 1/(length * 3)
|
||||
gfill.Size = UDim2.new(gprogress, 0, 1, 0)
|
||||
if waitCount > 10 then
|
||||
waitCount = 0
|
||||
AutoWedge(c, Region3int16.new(Vector3int16.new(1 + xpos2, 0, oldK), Vector3int16.new(width - 2 + xpos2, maxHeight, k)))
|
||||
oldK = k+1
|
||||
maxHeight = -1
|
||||
wait()
|
||||
else waitCount = waitCount + 1 end
|
||||
if k == length - 2 + zpos2 then
|
||||
AutoWedge(c, Region3int16.new(Vector3int16.new(1 + xpos2, 0, oldK), Vector3int16.new(width - 2 + xpos2, maxHeight, k)))
|
||||
|
||||
gfill.Parent.Visible = false
|
||||
gfill.Visible = false
|
||||
end
|
||||
end
|
||||
|
||||
--Generate Terrain End
|
||||
end
|
||||
|
||||
function onReset()
|
||||
reset.BorderColor3 = Color3.new(0, 0, 0)
|
||||
reset.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
reset.BackgroundTransparency = 0.5
|
||||
frame.Visible = false
|
||||
toolbarbutton:SetActive(false)
|
||||
on = false
|
||||
|
||||
if g:FindFirstChild("rload") == nil then
|
||||
rload = Instance.new("Frame", g)
|
||||
rload.Name = "rload"
|
||||
rload.Position = UDim2.new(0.4, 0, 0.025, 0)
|
||||
rload.Size = UDim2.new(0.2, 0, 0.05, 0)
|
||||
rload.BackgroundTransparency = 0.5
|
||||
rfill = Instance.new("Frame", rload)
|
||||
rfill.Name = "rfill"
|
||||
rfill.Position = UDim2.new(0, 0, 0, 0)
|
||||
rfill.Size = UDim2.new(0, 0, 1, 0)
|
||||
rfill.BackgroundColor3 = Color3.new(1, 0.25, 0)
|
||||
rfill.BackgroundTransparency = 0.5
|
||||
else
|
||||
rload = g:FindFirstChild("rload")
|
||||
rfill = rload:FindFirstChild("rfill")
|
||||
rload.Visible = 1
|
||||
rfill.Visible = 1
|
||||
rfill.Size = UDim2.new(0, 0, 1, 0)
|
||||
end
|
||||
--Erase Terrain
|
||||
|
||||
local xMax = c.MaxExtents.Max.X
|
||||
local yMax = c.MaxExtents.Max.Y
|
||||
local zMax = c.MaxExtents.Max.Z
|
||||
|
||||
local xMin = c.MaxExtents.Min.X
|
||||
local yMin = c.MaxExtents.Min.Y
|
||||
local zMin = c.MaxExtents.Min.Z
|
||||
|
||||
|
||||
rprogress = 0
|
||||
|
||||
local waitCount = 0
|
||||
|
||||
z = zMax
|
||||
while z >= zMin do
|
||||
SetCells(c, Region3int16.new(Vector3int16.new(xMin, yMin, z), Vector3int16.new(xMax, yMax, z)), 0, 0, 0)
|
||||
z = z - 1
|
||||
|
||||
rprogress = rprogress + 1/(zMax - zMin + 1)
|
||||
rfill.Size = UDim2.new(rprogress, 0, 1, 0)
|
||||
if z == zMin then
|
||||
reset.BorderColor3 = Color3.new(0, 0, 0)
|
||||
rfill.Parent.Visible = false
|
||||
rfill.Visible = false
|
||||
end
|
||||
if waitCount > 5 then waitCount = 0 wait(0.001) else waitCount = waitCount + 1 end
|
||||
end
|
||||
|
||||
--Erase Terrain End
|
||||
end
|
||||
|
||||
function On()
|
||||
self:Activate(true)
|
||||
toolbarbutton:SetActive(true)
|
||||
frame.Visible = true
|
||||
for w = 0, 0.6, 0.1 do
|
||||
frame.Size = UDim2.new(w, 0, w + 0.2, 0)
|
||||
wait(0.0000001)
|
||||
end
|
||||
title.Text = "Terrain Generation"
|
||||
xposl.Text = "X-Offset: "..xpos
|
||||
zposl.Text = "Z-Offset: "..zpos
|
||||
widthl.Text = "Width: "..width
|
||||
lengthl.Text = "Length: "..length
|
||||
ampl.Text = "Amplitude: "..a
|
||||
freql.Text = "Frequency: "..f
|
||||
generate.Text = "Generate"
|
||||
reset.Text = "Reset"
|
||||
on = true
|
||||
end
|
||||
|
||||
function Off()
|
||||
toolbarbutton:SetActive(false)
|
||||
title.Text = ""
|
||||
xposl.Text = ""
|
||||
zposl.Text = ""
|
||||
widthl.Text = ""
|
||||
lengthl.Text = ""
|
||||
ampl.Text = ""
|
||||
freql.Text = ""
|
||||
generate.Text = ""
|
||||
reset.Text = ""
|
||||
for w = 0.6, 0, -0.1 do
|
||||
frame.Size = UDim2.new(w, 0, w + 0.2, 0)
|
||||
wait(0.0000001)
|
||||
end
|
||||
frame.Visible = false
|
||||
on = false
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
------
|
||||
--GUI-
|
||||
------
|
||||
|
||||
--load library for with sliders
|
||||
local RbxGui = LoadLibrary("RbxGui")
|
||||
|
||||
--screengui
|
||||
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
|
||||
--frame
|
||||
frame = Instance.new("Frame", g)
|
||||
frame.Size = UDim2.new(0.6, 0, 0.8, 0)
|
||||
frame.Position = UDim2.new(0.2, 0, 0.1, 0)
|
||||
frame.BackgroundTransparency = 0.5
|
||||
frame.Visible = false
|
||||
|
||||
--title
|
||||
title = Instance.new("TextLabel", frame)
|
||||
title.Position = UDim2.new(0.4, 0, 0.05, 0)
|
||||
title.Size = UDim2.new(0.2, 0, 0.05, 0)
|
||||
title.Text = ""
|
||||
title.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
title.TextColor3 = Color3.new(1, 1, 1)
|
||||
title.Font = Enum.Font.ArialBold
|
||||
title.FontSize = Enum.FontSize.Size24
|
||||
title.BorderColor3 = Color3.new(0, 0, 0)
|
||||
title.BackgroundTransparency = 1
|
||||
|
||||
--current xoffset display label
|
||||
xposl = Instance.new("TextLabel", frame)
|
||||
xposl.Position = UDim2.new(0.05, 0, 0.2, 0)
|
||||
xposl.Size = UDim2.new(0.1, 0, 0.05, 0)
|
||||
xposl.Text = ""
|
||||
xposl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
xposl.TextColor3 = Color3.new(1, 1, 1)
|
||||
xposl.Font = Enum.Font.ArialBold
|
||||
xposl.FontSize = Enum.FontSize.Size14
|
||||
xposl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
xposl.BackgroundTransparency = 1
|
||||
|
||||
--xoffset slider
|
||||
xposSliderGui, xposSliderPosition = RbxGui.CreateSlider(128, 0, UDim2.new(0.2, 0, 0.22, 0))
|
||||
xposSliderGui.Parent = frame
|
||||
xposBar = xposSliderGui:FindFirstChild("Bar")
|
||||
xposBar.Size = UDim2.new(0.75, 0, 0, 5)
|
||||
xposSliderPosition.Value = (xpos+252)/4 + 1
|
||||
xposSliderPosition.Changed:connect(function()
|
||||
xpos = (xposSliderPosition.Value - 1) * 4 - 252
|
||||
xposl.Text = "X-Offset: "..xpos
|
||||
end)
|
||||
|
||||
--current zoffset display label
|
||||
zposl = Instance.new("TextLabel", frame)
|
||||
zposl.Position = UDim2.new(0.05, 0, 0.3, 0)
|
||||
zposl.Size = UDim2.new(0.1, 0, 0.05, 0)
|
||||
zposl.Text = ""
|
||||
zposl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
zposl.TextColor3 = Color3.new(1, 1, 1)
|
||||
zposl.Font = Enum.Font.ArialBold
|
||||
zposl.FontSize = Enum.FontSize.Size14
|
||||
zposl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
zposl.BackgroundTransparency = 1
|
||||
|
||||
--zoffset slider
|
||||
zposSliderGui, zposSliderPosition = RbxGui.CreateSlider(128, 0, UDim2.new(0.2, 0, 0.32, 0))
|
||||
zposSliderGui.Parent = frame
|
||||
zposBar = zposSliderGui:FindFirstChild("Bar")
|
||||
zposBar.Size = UDim2.new(0.75, 0, 0, 5)
|
||||
zposSliderPosition.Value = (zpos+252)/4 + 1
|
||||
zposSliderPosition.Changed:connect(function()
|
||||
zpos = (zposSliderPosition.Value - 1) * 4 - 252
|
||||
zposl.Text = "Z-Offset: "..zpos
|
||||
end)
|
||||
|
||||
--current width display label
|
||||
widthl = Instance.new("TextLabel", frame)
|
||||
widthl.Position = UDim2.new(0.05, 0, 0.4, 0)
|
||||
widthl.Size = UDim2.new(0.1, 0, 0.05, 0)
|
||||
widthl.Text = ""
|
||||
widthl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
widthl.TextColor3 = Color3.new(1, 1, 1)
|
||||
widthl.Font = Enum.Font.ArialBold
|
||||
widthl.FontSize = Enum.FontSize.Size14
|
||||
widthl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
widthl.BackgroundTransparency = 1
|
||||
|
||||
--width slider
|
||||
widthSliderGui, widthSliderPosition = RbxGui.CreateSlider(4, 0, UDim2.new(0.2, 0, 0.42, 0))
|
||||
widthSliderGui.Parent = frame
|
||||
widthbar = widthSliderGui:FindFirstChild("Bar")
|
||||
widthbar.Size = UDim2.new(0.75, 0, 0, 5)
|
||||
widthSliderPosition.Value = 4
|
||||
widthSliderPosition.Changed:connect(function()
|
||||
width = math.pow(2, widthSliderPosition.Value + 5)
|
||||
widthl.Text = "Width: "..width
|
||||
end)
|
||||
|
||||
--current length display label
|
||||
lengthl = Instance.new("TextLabel", frame)
|
||||
lengthl.Position = UDim2.new(0.05, 0, 0.5, 0)
|
||||
lengthl.Size = UDim2.new(0.1, 0, 0.05, 0)
|
||||
lengthl.Text = ""
|
||||
lengthl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
lengthl.TextColor3 = Color3.new(1, 1, 1)
|
||||
lengthl.Font = Enum.Font.ArialBold
|
||||
lengthl.FontSize = Enum.FontSize.Size14
|
||||
lengthl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
lengthl.BackgroundTransparency = 1
|
||||
|
||||
--length slider
|
||||
lengthSliderGui, lengthSliderPosition = RbxGui.CreateSlider(4, 0, UDim2.new(0.2, 0, 0.52, 0))
|
||||
lengthSliderGui.Parent = frame
|
||||
lengthbar = lengthSliderGui:FindFirstChild("Bar")
|
||||
lengthbar.Size = UDim2.new(0.75, 0, 0, 5)
|
||||
lengthSliderPosition.Value = 4
|
||||
lengthSliderPosition.Changed:connect(function()
|
||||
length = math.pow(2, lengthSliderPosition.Value + 5)
|
||||
lengthl.Text = "Length: "..length
|
||||
end)
|
||||
|
||||
--current amplitude display label
|
||||
ampl = Instance.new("TextLabel", frame)
|
||||
ampl.Position = UDim2.new(0.05, 0, 0.6, 0)
|
||||
ampl.Size = UDim2.new(0.1, 0, 0.05, 0)
|
||||
ampl.Text = ""
|
||||
ampl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
ampl.TextColor3 = Color3.new(1, 1, 1)
|
||||
ampl.Font = Enum.Font.ArialBold
|
||||
ampl.FontSize = Enum.FontSize.Size14
|
||||
ampl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
ampl.BackgroundTransparency = 1
|
||||
|
||||
--amplitude slider
|
||||
ampSliderGui, ampSliderPosition = RbxGui.CreateSlider(62, 0, UDim2.new(0.2, 0, 0.62, 0))
|
||||
ampSliderGui.Parent = frame
|
||||
ampbar = ampSliderGui:FindFirstChild("Bar")
|
||||
ampbar.Size = UDim2.new(0.75, 0, 0, 5)
|
||||
ampSliderPosition.Value = a + 1
|
||||
ampSliderPosition.Changed:connect(function()
|
||||
a = ampSliderPosition.Value + 1
|
||||
ampl.Text = "Amplitude: "..a
|
||||
end)
|
||||
|
||||
--current frequency display label
|
||||
freql = Instance.new("TextLabel", frame)
|
||||
freql.Position = UDim2.new(0.05, 0, 0.7, 0)
|
||||
freql.Size = UDim2.new(0.1, 0, 0.05, 0)
|
||||
freql.Text = ""
|
||||
freql.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
freql.TextColor3 = Color3.new(1, 1, 1)
|
||||
freql.Font = Enum.Font.ArialBold
|
||||
freql.FontSize = Enum.FontSize.Size14
|
||||
freql.BorderColor3 = Color3.new(0, 0, 0)
|
||||
freql.BackgroundTransparency = 1
|
||||
|
||||
--frequency slider
|
||||
freqSliderGui, freqSliderPosition = RbxGui.CreateSlider(8, 0, UDim2.new(0.2, 0, 0.72, 0))
|
||||
freqSliderGui.Parent = frame
|
||||
freqbar = freqSliderGui:FindFirstChild("Bar")
|
||||
freqbar.Size = UDim2.new(0.75, 0, 0, 5)
|
||||
freqSliderPosition.Value = 4
|
||||
freqSliderPosition.Changed:connect(function()
|
||||
f = math.pow(2, freqSliderPosition.Value - 1)
|
||||
freql.Text = "Frequency: "..f
|
||||
end)
|
||||
|
||||
--generate button
|
||||
generate = Instance.new("TextButton", frame)
|
||||
generate.Position = UDim2.new(0.275, 0, 0.85, 0)
|
||||
generate.Size = UDim2.new(0.2, 0, 0.1, 0)
|
||||
generate.Text = ""
|
||||
generate.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
generate.TextColor3 = Color3.new(1, 1, 1)
|
||||
generate.Font = Enum.Font.ArialBold
|
||||
generate.FontSize = Enum.FontSize.Size14
|
||||
generate.BorderColor3 = Color3.new(0, 0, 0)
|
||||
generate.BackgroundTransparency = 0.5
|
||||
generate.MouseEnter:connect(function()
|
||||
generate.BorderColor3 = Color3.new(1, 1, 1)
|
||||
generate.BackgroundColor3 = Color3.new(0, 0, 0)
|
||||
generate.BackgroundTransparency = 0.2
|
||||
end)
|
||||
generate.MouseButton1Click:connect(onGenerate)
|
||||
generate.MouseLeave:connect(function()
|
||||
generate.BorderColor3 = Color3.new(0, 0, 0)
|
||||
generate.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
generate.BackgroundTransparency = 0.5
|
||||
end)
|
||||
|
||||
--reset button
|
||||
reset = Instance.new("TextButton", frame)
|
||||
reset.Position = UDim2.new(0.525, 0, 0.85, 0)
|
||||
reset.Size = UDim2.new(0.2, 0, 0.1, 0)
|
||||
reset.Text = ""
|
||||
reset.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
reset.TextColor3 = Color3.new(1, 1, 1)
|
||||
reset.Font = Enum.Font.ArialBold
|
||||
reset.FontSize = Enum.FontSize.Size14
|
||||
reset.BorderColor3 = Color3.new(0, 0, 0)
|
||||
reset.BackgroundTransparency = 0.5
|
||||
reset.MouseEnter:connect(function()
|
||||
reset.BorderColor3 = Color3.new(1, 1, 1)
|
||||
reset.BackgroundColor3 = Color3.new(0, 0, 0)
|
||||
reset.BackgroundTransparency = 0.2
|
||||
end)
|
||||
reset.MouseButton1Click:connect(onReset)
|
||||
reset.MouseLeave:connect(function()
|
||||
reset.BorderColor3 = Color3.new(0, 0, 0)
|
||||
reset.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
reset.BackgroundTransparency = 0.5
|
||||
end)
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------
|
||||
--SUCCESSFUL LOAD MESSAGE-
|
||||
--------------------------
|
||||
loaded = true
|
||||
print("Terrain Plugin Loaded")
|
||||
@@ -0,0 +1,240 @@
|
||||
-----------------
|
||||
--DEFAULT VALUES-
|
||||
-----------------
|
||||
loaded = false
|
||||
on = false
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--PLUGIN SETUP-
|
||||
---------------
|
||||
self = PluginManager():CreatePlugin()
|
||||
mouse = self:GetMouse()
|
||||
mouse.Button1Down:connect(function() onClicked(mouse) end)
|
||||
self.Deactivation:connect(function()
|
||||
Off()
|
||||
end)
|
||||
toolbar = self:CreateToolbar("Terrain")
|
||||
toolbarbutton = toolbar:CreateButton("", "Builder", "builder.png")
|
||||
toolbarbutton.Click:connect(function()
|
||||
if on then
|
||||
Off()
|
||||
elseif loaded then
|
||||
On()
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
-----------------------
|
||||
--FUNCTION DEFINITIONS-
|
||||
-----------------------
|
||||
function dist(x1, y1, x2, y2)
|
||||
return math.sqrt(math.pow(x2-x1, 2) + math.pow(y2-y1, 2))
|
||||
end
|
||||
|
||||
function dist3d(x1, y1, z1, x2, y2, z2)
|
||||
return math.sqrt(math.pow(dist(x1, y1, x2, y2), 2) + math.pow(z2-z1, 2))
|
||||
end
|
||||
|
||||
--converts the coordinate coord into a cluster coordinate where clusterlength is the length of the cluster in the same dimension as coord
|
||||
function clusterCoord(coord, clusterlength)
|
||||
return math.floor((coord + clusterlength/2)/4)
|
||||
end
|
||||
|
||||
--makes a wedge at location x, y, z
|
||||
--sets cell x, y, z to default material if parameter is provided, if not sets cell x, y, z to be whatever material it previously was
|
||||
--returns true if made a wedge, false if the cell remains a block
|
||||
function MakeWedge(x, y, z, defaultmaterial)
|
||||
local c = game.Workspace.Terrain
|
||||
--gather info about all the cells around x, y, z
|
||||
surroundings = {} --surroundings is a 3 x 3 x 3 array of the material of the cells adjacent to x, y, z
|
||||
for i = x - 1, x + 1 do
|
||||
surroundings[i] = {}
|
||||
for j = y - 1, y + 1 do
|
||||
surroundings[i][j] = {}
|
||||
for k = z - 1, z + 1 do
|
||||
local material, wedge, rotation = c:GetCell(i, j, k)
|
||||
surroundings[i][j][k] = material.Value
|
||||
end
|
||||
end
|
||||
end
|
||||
--make some useful arrays and counters
|
||||
local sides = {} --sides is an array of the material of the 4 adjacent sides
|
||||
sides[0] = surroundings[x - 1][y][z]
|
||||
sides[1] = surroundings[x][y][z + 1]
|
||||
sides[2] = surroundings[x + 1][y][z]
|
||||
sides[3] = surroundings[x][y][z - 1]
|
||||
local adjacentSides = 0
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 then
|
||||
adjacentSides = adjacentSides + 1
|
||||
end
|
||||
end
|
||||
local sidesAbove = {} --sides is an array of the material of the 4 adjacent sides 1 height above
|
||||
sidesAbove[0] = surroundings[x - 1][y + 1][z]
|
||||
sidesAbove[1] = surroundings[x][y + 1][z + 1]
|
||||
sidesAbove[2] = surroundings[x + 1][y + 1][z]
|
||||
sidesAbove[3] = surroundings[x][y + 1][z - 1]
|
||||
local adjacentSidesAbove = 0
|
||||
for n = 0, 3 do
|
||||
if sidesAbove[n] > 0 then
|
||||
adjacentSidesAbove = adjacentSidesAbove + 1
|
||||
end
|
||||
end
|
||||
local corners = {} --corners is an array of the material of the 4 adjacent corners
|
||||
corners[0] = surroundings[x - 1][y][z - 1]
|
||||
corners[1] = surroundings[x - 1][y][z + 1]
|
||||
corners[2] = surroundings[x + 1][y][z + 1]
|
||||
corners[3] = surroundings[x + 1][y][z - 1]
|
||||
local adjacentCorners = 0
|
||||
for n = 0, 3 do
|
||||
if corners[n] > 0 then
|
||||
adjacentCorners = adjacentCorners + 1
|
||||
end
|
||||
end
|
||||
local cornersAbove = {} --corners is an array of the material of the 4 adjacent corners 1 height above
|
||||
cornersAbove[0] = surroundings[x - 1][y + 1][z - 1]
|
||||
cornersAbove[1] = surroundings[x - 1][y + 1][z + 1]
|
||||
cornersAbove[2] = surroundings[x + 1][y + 1][z + 1]
|
||||
cornersAbove[3] = surroundings[x + 1][y + 1][z - 1]
|
||||
local adjacentCornersAbove = 0
|
||||
for n = 0, 3 do
|
||||
if cornersAbove[n] > 0 then
|
||||
adjacentCornersAbove = adjacentCornersAbove + 1
|
||||
end
|
||||
end
|
||||
--determine what type of wedge to make
|
||||
local material = nil
|
||||
local wedge = nil
|
||||
local rotation = nil
|
||||
if defaultmaterial then
|
||||
material = defaultmaterial
|
||||
else
|
||||
material, wedge, rotation = c:GetCell(x, y, z) --start with the existing material, wedge, and rotation
|
||||
end
|
||||
wedge = 0 --default wedge is a block
|
||||
rotation = 0 --default rotation is 0
|
||||
--type 1: 45 degree ramp //must not have a block on top and must have a block under, and be surrounded by 1 side; or 3 sides and the 2 corners between them
|
||||
if surroundings[x][y + 1][z] == 0 and surroundings[x][y - 1][z] > 0 then
|
||||
if adjacentSides == 1 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 then
|
||||
wedge = 1
|
||||
rotation = (n + 1) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
elseif adjacentSides == 3 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 and corners[(n + 1) % 4] > 0 and sides[(n + 1) % 4] > 0 and corners[(n + 2) % 4] > 0 and sides[(n + 2) % 4] > 0 then
|
||||
wedge = 1
|
||||
rotation = (n + 2) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 2: 45 degree corner //must not have a block on top and must have a block under, and be surrounded by 2 sides and the 1 corner between them; or 3 sides and 1 corner between 2 of them (facing towards that corner)
|
||||
if surroundings[x][y + 1][z] == 0 and surroundings[x][y - 1][z] > 0 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 and corners[(n + 1) % 4] > 0 and sides[(n + 1) % 4] > 0 and (adjacentSides == 2 or (adjacentSides == 3 and (corners[(n + 3) % 4] > 0 or (sides[(n + 2) % 4] > 0 and corners[(n + 2) % 4] > 0) or (sides[(n + 3) % 4] > 0 and corners[n] > 0)))) then
|
||||
wedge = 2
|
||||
rotation = (n + 2) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 3: 45 degree inverse corner //surrounded by three sides or 4 sides and 3 corners, with nothing above or else a block on top surrounded on 2 sides and the corner between them
|
||||
if adjacentSides == 3 and surroundings[x][y + 1][z] > 0 then
|
||||
if adjacentCorners > 1 then
|
||||
for n = 0, 3 do
|
||||
if (corners[n] == 0 or cornersAbove[n] == 0) and (sides[(n - 1) % 4] == 0 or sides[n] == 0) and (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] > 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] == 0) then
|
||||
wedge = 3
|
||||
rotation = (n + 3) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif adjacentSides == 4 and adjacentCorners == 3 then
|
||||
for n = 0, 3 do
|
||||
if corners[n] == 0 and (surroundings[x][y + 1][z] == 0 or (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] > 0 and cornersAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] == 0)) then
|
||||
wedge = 3
|
||||
rotation = (n + 3) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 4: half a cube, as if it were cut diagonally from front to back //surrounded by 2 sides
|
||||
if adjacentSides == 2 and adjacentCorners < 4 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] == 0 and sides[(n + 1) % 4] == 0 and (surroundings[x][y + 1][z] == 0 or (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] == 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] > 0)) then
|
||||
wedge = 4
|
||||
rotation = n
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function onClicked(mouse)
|
||||
if on then
|
||||
|
||||
c = game.Workspace.Terrain
|
||||
|
||||
local cellPos = c:WorldToCellPreferEmpty(Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
|
||||
local x = cellPos.x
|
||||
local y = cellPos.y
|
||||
local z = cellPos.z
|
||||
|
||||
c:SetCell(x, y, z, 1, 0, 0)
|
||||
for i = x - 1, x + 1 do
|
||||
for j = y - 1, y + 1 do
|
||||
for k = z - 1, z + 1 do
|
||||
MakeWedge(i, j, k)
|
||||
end
|
||||
end
|
||||
end
|
||||
print("Block built at: "..x..", "..y..", "..z)
|
||||
end
|
||||
end
|
||||
|
||||
function On()
|
||||
self:Activate(true)
|
||||
toolbarbutton:SetActive(true)
|
||||
on = true
|
||||
end
|
||||
|
||||
function Off()
|
||||
toolbarbutton:SetActive(false)
|
||||
on = false
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
------
|
||||
--GUI-
|
||||
------
|
||||
|
||||
--screengui
|
||||
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------
|
||||
--SUCCESSFUL LOAD MESSAGE-
|
||||
--------------------------
|
||||
loaded = true
|
||||
print("Builder Plugin Loaded")
|
||||
@@ -0,0 +1,234 @@
|
||||
-----------------
|
||||
--DEFAULT VALUES-
|
||||
-----------------
|
||||
loaded = false
|
||||
on = false
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--PLUGIN SETUP-
|
||||
---------------
|
||||
self = PluginManager():CreatePlugin()
|
||||
mouse = self:GetMouse()
|
||||
mouse.Button1Down:connect(function() onClicked(mouse) end)
|
||||
self.Deactivation:connect(function()
|
||||
Off()
|
||||
end)
|
||||
toolbar = self:CreateToolbar("Terrain")
|
||||
toolbarbutton = toolbar:CreateButton("", "Remover", "remover.png")
|
||||
toolbarbutton.Click:connect(function()
|
||||
if on then
|
||||
Off()
|
||||
elseif loaded then
|
||||
On()
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
--FUNCTION DEFINITIONS-
|
||||
-----------------------
|
||||
function dist(x1, y1, x2, y2)
|
||||
return math.sqrt(math.pow(x2-x1, 2) + math.pow(y2-y1, 2))
|
||||
end
|
||||
|
||||
function dist3d(x1, y1, z1, x2, y2, z2)
|
||||
return math.sqrt(math.pow(dist(x1, y1, x2, y2), 2) + math.pow(z2-z1, 2))
|
||||
end
|
||||
|
||||
--makes a wedge at location x, y, z
|
||||
--sets cell x, y, z to default material if parameter is provided, if not sets cell x, y, z to be whatever material it previously was
|
||||
--returns true if made a wedge, false if the cell remains a block
|
||||
function MakeWedge(x, y, z, defaultmaterial)
|
||||
local c = game.Workspace.Terrain
|
||||
--gather info about all the cells around x, y, z
|
||||
surroundings = {} --surroundings is a 3 x 3 x 3 array of the material of the cells adjacent to x, y, z
|
||||
for i = x - 1, x + 1 do
|
||||
surroundings[i] = {}
|
||||
for j = y - 1, y + 1 do
|
||||
surroundings[i][j] = {}
|
||||
for k = z - 1, z + 1 do
|
||||
local material, wedge, rotation = c:GetCell(i, j, k)
|
||||
surroundings[i][j][k] = material.Value
|
||||
end
|
||||
end
|
||||
end
|
||||
--make some useful arrays and counters
|
||||
local sides = {} --sides is an array of the material of the 4 adjacent sides
|
||||
sides[0] = surroundings[x - 1][y][z]
|
||||
sides[1] = surroundings[x][y][z + 1]
|
||||
sides[2] = surroundings[x + 1][y][z]
|
||||
sides[3] = surroundings[x][y][z - 1]
|
||||
local adjacentSides = 0
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 then
|
||||
adjacentSides = adjacentSides + 1
|
||||
end
|
||||
end
|
||||
local sidesAbove = {} --sides is an array of the material of the 4 adjacent sides 1 height above
|
||||
sidesAbove[0] = surroundings[x - 1][y + 1][z]
|
||||
sidesAbove[1] = surroundings[x][y + 1][z + 1]
|
||||
sidesAbove[2] = surroundings[x + 1][y + 1][z]
|
||||
sidesAbove[3] = surroundings[x][y + 1][z - 1]
|
||||
local adjacentSidesAbove = 0
|
||||
for n = 0, 3 do
|
||||
if sidesAbove[n] > 0 then
|
||||
adjacentSidesAbove = adjacentSidesAbove + 1
|
||||
end
|
||||
end
|
||||
local corners = {} --corners is an array of the material of the 4 adjacent corners
|
||||
corners[0] = surroundings[x - 1][y][z - 1]
|
||||
corners[1] = surroundings[x - 1][y][z + 1]
|
||||
corners[2] = surroundings[x + 1][y][z + 1]
|
||||
corners[3] = surroundings[x + 1][y][z - 1]
|
||||
local adjacentCorners = 0
|
||||
for n = 0, 3 do
|
||||
if corners[n] > 0 then
|
||||
adjacentCorners = adjacentCorners + 1
|
||||
end
|
||||
end
|
||||
local cornersAbove = {} --corners is an array of the material of the 4 adjacent corners 1 height above
|
||||
cornersAbove[0] = surroundings[x - 1][y + 1][z - 1]
|
||||
cornersAbove[1] = surroundings[x - 1][y + 1][z + 1]
|
||||
cornersAbove[2] = surroundings[x + 1][y + 1][z + 1]
|
||||
cornersAbove[3] = surroundings[x + 1][y + 1][z - 1]
|
||||
local adjacentCornersAbove = 0
|
||||
for n = 0, 3 do
|
||||
if cornersAbove[n] > 0 then
|
||||
adjacentCornersAbove = adjacentCornersAbove + 1
|
||||
end
|
||||
end
|
||||
--determine what type of wedge to make
|
||||
local material = nil
|
||||
local wedge = nil
|
||||
local rotation = nil
|
||||
if defaultmaterial then
|
||||
material = defaultmaterial
|
||||
else
|
||||
material, wedge, rotation = c:GetCell(x, y, z) --start with the existing material, wedge, and rotation
|
||||
end
|
||||
wedge = 0 --default wedge is a block
|
||||
rotation = 0 --default rotation is 0
|
||||
--type 1: 45 degree ramp //must not have a block on top and must have a block under, and be surrounded by 1 side; or 3 sides and the 2 corners between them
|
||||
if surroundings[x][y + 1][z] == 0 and surroundings[x][y - 1][z] > 0 then
|
||||
if adjacentSides == 1 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 then
|
||||
wedge = 1
|
||||
rotation = (n + 1) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
elseif adjacentSides == 3 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 and corners[(n + 1) % 4] > 0 and sides[(n + 1) % 4] > 0 and corners[(n + 2) % 4] > 0 and sides[(n + 2) % 4] > 0 then
|
||||
wedge = 1
|
||||
rotation = (n + 2) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 2: 45 degree corner //must not have a block on top and must have a block under, and be surrounded by 2 sides and the 1 corner between them; or 3 sides and 1 corner between 2 of them (facing towards that corner)
|
||||
if surroundings[x][y + 1][z] == 0 and surroundings[x][y - 1][z] > 0 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 and corners[(n + 1) % 4] > 0 and sides[(n + 1) % 4] > 0 and (adjacentSides == 2 or (adjacentSides == 3 and (corners[(n + 3) % 4] > 0 or (sides[(n + 2) % 4] > 0 and corners[(n + 2) % 4] > 0) or (sides[(n + 3) % 4] > 0 and corners[n] > 0)))) then
|
||||
wedge = 2
|
||||
rotation = (n + 2) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 3: 45 degree inverse corner //surrounded by three sides or 4 sides and 3 corners, with nothing above or else a block on top surrounded on 2 sides and the corner between them
|
||||
if adjacentSides == 3 and surroundings[x][y + 1][z] > 0 then
|
||||
if adjacentCorners > 1 then
|
||||
for n = 0, 3 do
|
||||
if (corners[n] == 0 or cornersAbove[n] == 0) and (sides[(n - 1) % 4] == 0 or sides[n] == 0) and (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] > 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] == 0) then
|
||||
wedge = 3
|
||||
rotation = (n + 3) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif adjacentSides == 4 and adjacentCorners == 3 then
|
||||
for n = 0, 3 do
|
||||
if corners[n] == 0 and (surroundings[x][y + 1][z] == 0 or (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] > 0 and cornersAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] == 0)) then
|
||||
wedge = 3
|
||||
rotation = (n + 3) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 4: half a cube, as if it were cut diagonally from front to back //surrounded by 2 sides
|
||||
if adjacentSides == 2 and adjacentCorners < 4 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] == 0 and sides[(n + 1) % 4] == 0 and (surroundings[x][y + 1][z] == 0 or (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] == 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] > 0)) then
|
||||
wedge = 4
|
||||
rotation = n
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return false
|
||||
end
|
||||
|
||||
function onClicked(mouse)
|
||||
if on then
|
||||
|
||||
c = game.Workspace.Terrain
|
||||
|
||||
local cellPos = c:WorldToCellPreferSolid(Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
|
||||
local x = cellPos.x
|
||||
local y = cellPos.y
|
||||
local z = cellPos.z
|
||||
|
||||
c:SetCell(x, y, z, 0, 0, 0)
|
||||
for i = x - 1, x + 1 do
|
||||
for j = y - 1, y + 1 do
|
||||
for k = z - 1, z + 1 do
|
||||
MakeWedge(i, j, k)
|
||||
end
|
||||
end
|
||||
end
|
||||
print("Block destroyed at: "..x..", "..y..", "..z)
|
||||
end
|
||||
end
|
||||
|
||||
function On()
|
||||
self:Activate(true)
|
||||
toolbarbutton:SetActive(true)
|
||||
on = true
|
||||
end
|
||||
|
||||
function Off()
|
||||
toolbarbutton:SetActive(false)
|
||||
on = false
|
||||
end
|
||||
|
||||
|
||||
|
||||
------
|
||||
--GUI-
|
||||
------
|
||||
|
||||
--screengui
|
||||
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------
|
||||
--SUCCESSFUL LOAD MESSAGE-
|
||||
--------------------------
|
||||
loaded = true
|
||||
print("Remover Plugin Loaded")
|
||||
@@ -0,0 +1,459 @@
|
||||
-----------------
|
||||
--DEFAULT VALUES-
|
||||
-----------------
|
||||
loaded = false
|
||||
on = false
|
||||
mousedown = false
|
||||
r = 0
|
||||
s = 1
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--PLUGIN SETUP-
|
||||
---------------
|
||||
self = PluginManager():CreatePlugin()
|
||||
self.Deactivation:connect(function()
|
||||
Off()
|
||||
end)
|
||||
|
||||
toolbar = self:CreateToolbar("Terrain")
|
||||
toolbarbutton = toolbar:CreateButton("", "Elevation Adjuster", "elevation.png")
|
||||
toolbarbutton.Click:connect(function()
|
||||
if on then
|
||||
Off()
|
||||
elseif loaded then
|
||||
On()
|
||||
end
|
||||
end)
|
||||
|
||||
mouse = self:GetMouse()
|
||||
mouse.Button1Down:connect(function()
|
||||
onClicked(mouse)
|
||||
end)
|
||||
mouse.Button1Up:connect(function() mousedown = false end)
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
--FUNCTION DEFINITIONS-
|
||||
-----------------------
|
||||
|
||||
--find height at coordinate x, z
|
||||
function findHeight(x, z)
|
||||
c = game.Workspace.Terrain
|
||||
h = 0
|
||||
material, wedge, rotation = c:GetCell(x, h + 1, z)
|
||||
while material.Value > 0 do
|
||||
h = h + 1
|
||||
material, wedge, rotation = c:GetCell(x, h + 1, z)
|
||||
end
|
||||
return h
|
||||
end
|
||||
|
||||
|
||||
--makes a shell around block at coordinate x, z using heightmap
|
||||
function makeShell(x, z, heightmap, shellheightmap)
|
||||
local c = game.Workspace.Terrain
|
||||
local originalheight = heightmap[x][z]
|
||||
for i = x - 1, x + 1 do
|
||||
for k = z - 1, z + 1 do
|
||||
if shellheightmap[i][k] < originalheight then
|
||||
for h = originalheight, shellheightmap[i][k] - 2, -1 do
|
||||
if h > 0 then
|
||||
c:SetCell(i, h, k, 1, 0, 0)
|
||||
end
|
||||
end
|
||||
shellheightmap[i][k] = originalheight
|
||||
end
|
||||
end
|
||||
end
|
||||
return shellheightmap
|
||||
end
|
||||
|
||||
|
||||
--makes a wedge at location x, y, z using info from heightmap instead of GetCell
|
||||
--sets cell x, y, z to default material if parameter is provided, if not sets cell x, y, z to be whatever material it previously was
|
||||
--returns true if made a wedge, false if the cell remains a block
|
||||
function MakeWedge(x, y, z, heightmap, defaultmaterial)
|
||||
local c = game.Workspace.Terrain
|
||||
--gather info about all the cells around x, y, z
|
||||
local surroundings = {} --surroundings is a 3 x 3 x 3 array of the cells adjacent to x, y, z (1 if a cell is there, 0 if not)
|
||||
for i = x - 1, x + 1 do
|
||||
surroundings[i] = {}
|
||||
for j = y - 1, y + 1 do
|
||||
surroundings[i][j] = {}
|
||||
for k = z - 1, z + 1 do
|
||||
heightmapi = heightmap[i]
|
||||
height = nil
|
||||
if heightmapi then
|
||||
height = heightmapi[k]
|
||||
end
|
||||
if height and height >= j then
|
||||
surroundings[i][j][k] = 1
|
||||
else
|
||||
surroundings[i][j][k] = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--make some useful arrays and counters
|
||||
local sides = {} --sides is an array of the material of the 4 adjacent sides
|
||||
sides[0] = surroundings[x - 1][y][z]
|
||||
sides[1] = surroundings[x][y][z + 1]
|
||||
sides[2] = surroundings[x + 1][y][z]
|
||||
sides[3] = surroundings[x][y][z - 1]
|
||||
local adjacentSides = 0
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 then
|
||||
adjacentSides = adjacentSides + 1
|
||||
end
|
||||
end
|
||||
local sidesAbove = {} --sides is an array of the material of the 4 adjacent sides 1 height above
|
||||
sidesAbove[0] = surroundings[x - 1][y + 1][z]
|
||||
sidesAbove[1] = surroundings[x][y + 1][z + 1]
|
||||
sidesAbove[2] = surroundings[x + 1][y + 1][z]
|
||||
sidesAbove[3] = surroundings[x][y + 1][z - 1]
|
||||
local adjacentSidesAbove = 0
|
||||
for n = 0, 3 do
|
||||
if sidesAbove[n] > 0 then
|
||||
adjacentSidesAbove = adjacentSidesAbove + 1
|
||||
end
|
||||
end
|
||||
local corners = {} --corners is an array of the material of the 4 adjacent corners
|
||||
corners[0] = surroundings[x - 1][y][z - 1]
|
||||
corners[1] = surroundings[x - 1][y][z + 1]
|
||||
corners[2] = surroundings[x + 1][y][z + 1]
|
||||
corners[3] = surroundings[x + 1][y][z - 1]
|
||||
local adjacentCorners = 0
|
||||
for n = 0, 3 do
|
||||
if corners[n] > 0 then
|
||||
adjacentCorners = adjacentCorners + 1
|
||||
end
|
||||
end
|
||||
local cornersAbove = {} --corners is an array of the material of the 4 adjacent corners 1 height above
|
||||
cornersAbove[0] = surroundings[x - 1][y + 1][z - 1]
|
||||
cornersAbove[1] = surroundings[x - 1][y + 1][z + 1]
|
||||
cornersAbove[2] = surroundings[x + 1][y + 1][z + 1]
|
||||
cornersAbove[3] = surroundings[x + 1][y + 1][z - 1]
|
||||
local adjacentCornersAbove = 0
|
||||
for n = 0, 3 do
|
||||
if cornersAbove[n] > 0 then
|
||||
adjacentCornersAbove = adjacentCornersAbove + 1
|
||||
end
|
||||
end
|
||||
--determine what type of wedge to make
|
||||
local material = nil
|
||||
local wedge = nil
|
||||
local rotation = nil
|
||||
if defaultmaterial then
|
||||
material = defaultmaterial
|
||||
else
|
||||
material, wedge, rotation = c:GetCell(x, y, z) --start with the existing material, wedge, and rotation
|
||||
end
|
||||
wedge = 0 --default wedge is a block
|
||||
rotation = 0 --default rotation is 0
|
||||
--type 1: 45 degree ramp //must not have a block on top and must have a block under, and be surrounded by 1 side; or 3 sides and the 2 corners between them
|
||||
if surroundings[x][y + 1][z] == 0 and surroundings[x][y - 1][z] > 0 then
|
||||
if adjacentSides == 1 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 then
|
||||
wedge = 1
|
||||
rotation = (n + 1) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
elseif adjacentSides == 3 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 and corners[(n + 1) % 4] > 0 and sides[(n + 1) % 4] > 0 and corners[(n + 2) % 4] > 0 and sides[(n + 2) % 4] > 0 then
|
||||
wedge = 1
|
||||
rotation = (n + 2) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 2: 45 degree corner //must not have a block on top and must have a block under, and be surrounded by 2 sides and the 1 corner between them; or 3 sides and 1 corner between 2 of them (facing towards that corner)
|
||||
if surroundings[x][y + 1][z] == 0 and surroundings[x][y - 1][z] > 0 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 and corners[(n + 1) % 4] > 0 and sides[(n + 1) % 4] > 0 and (adjacentSides == 2 or (adjacentSides == 3 and (corners[(n + 3) % 4] > 0 or (sides[(n + 2) % 4] > 0 and corners[(n + 2) % 4] > 0) or (sides[(n + 3) % 4] > 0 and corners[n] > 0)))) then
|
||||
wedge = 2
|
||||
rotation = (n + 2) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 3: 45 degree inverse corner //surrounded by three sides or 4 sides and 3 corners, with nothing above or else a block on top surrounded on 2 sides and the corner between them
|
||||
if adjacentSides == 3 and surroundings[x][y + 1][z] > 0 then
|
||||
if adjacentCorners > 1 then
|
||||
for n = 0, 3 do
|
||||
if (corners[n] == 0 or cornersAbove[n] == 0) and (sides[(n - 1) % 4] == 0 or sides[n] == 0) and (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] > 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] == 0) then
|
||||
wedge = 3
|
||||
rotation = (n + 3) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif adjacentSides == 4 and adjacentCorners == 3 then
|
||||
for n = 0, 3 do
|
||||
if corners[n] == 0 and (surroundings[x][y + 1][z] == 0 or (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] > 0 and cornersAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] == 0)) then
|
||||
wedge = 3
|
||||
rotation = (n + 3) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 4: half a cube, as if it were cut diagonally from front to back //surrounded by 2 sides
|
||||
if adjacentSides == 2 and adjacentCorners < 4 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] == 0 and sides[(n + 1) % 4] == 0 and (surroundings[x][y + 1][z] == 0 or (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] == 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] > 0)) then
|
||||
wedge = 4
|
||||
rotation = n
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
--elevates terrain at point (x, y, z) in cluster c
|
||||
--within radius r1 from x, z the elevation should become y + d
|
||||
--from radius r1 to r2 the elevation should be a gradient
|
||||
function elevate(x, y, z, r1, r2, d, range)
|
||||
local c = game.Workspace.Terrain
|
||||
|
||||
for i = x - (range + 2), x + (range + 2) do
|
||||
if oldheightmap[i] == nil then
|
||||
oldheightmap[i] = {}
|
||||
end
|
||||
for k = z - (range + 2), z + (range + 2) do
|
||||
if oldheightmap[i][k] == nil then
|
||||
oldheightmap[i][k] = findHeight(i, k)
|
||||
end
|
||||
|
||||
|
||||
--figure out the height to make coordinate (i, k)
|
||||
local distance = dist(i, k, x, z)
|
||||
if distance < r1 then
|
||||
height = y + d
|
||||
elseif distance < r2 then
|
||||
height = math.floor((y + d) * (1 - (distance - r1)/(r2 - r1)) + oldheightmap[i][k] * (distance - r1)/(r2 - r1))
|
||||
else
|
||||
height = oldheightmap[i][k]
|
||||
end
|
||||
if height == 0 then
|
||||
height = -1
|
||||
end
|
||||
|
||||
--heightmap[i][k] should be the current height of coordinate (i, k)
|
||||
if heightmap[i] == nil then
|
||||
heightmap[i] = {}
|
||||
end
|
||||
if heightmap[i][k] == nil then
|
||||
heightmap[i][k] = oldheightmap[i][k]
|
||||
end
|
||||
|
||||
--the height is either greater than or less than the current height
|
||||
if height > heightmap[i][k] then
|
||||
for h = heightmap[i][k] - 2, height do
|
||||
c:SetCell(i, h, k, 1, 0, 0)
|
||||
end
|
||||
heightmap[i][k] = height
|
||||
elseif height < heightmap[i][k] then
|
||||
for h = heightmap[i][k], height + 1, -1 do
|
||||
c:SetCell(i, h, k, 0, 0, 0)
|
||||
end
|
||||
heightmap[i][k] = height
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--copy heightmap into shellheightmap
|
||||
shellheightmap = {}
|
||||
for i = x - (range + 2), x + (range + 2) do
|
||||
if shellheightmap[i] == nil then
|
||||
shellheightmap[i] = {}
|
||||
end
|
||||
for k = z - (range + 2), z + (range + 2) do
|
||||
shellheightmap[i][k] = heightmap[i][k]
|
||||
end
|
||||
end
|
||||
--shell everything
|
||||
for i = x - range , x + range do
|
||||
for k = z - range, z + range do
|
||||
if shellheightmap[i][k] ~= oldheightmap[i][k] then
|
||||
shellheightmap = makeShell(i, k, heightmap, shellheightmap)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i = x - (range + 2), x + (range + 2) do
|
||||
for k = z - (range + 2), z + (range + 2) do
|
||||
heightmap[i][k] = shellheightmap[i][k]
|
||||
end
|
||||
end
|
||||
|
||||
for i = x - (range + 1), x + (range + 1) do
|
||||
for k = z - (range + 1), z + (range + 1) do
|
||||
local height = heightmap[i][k]
|
||||
if height == nil then
|
||||
height = -1
|
||||
end
|
||||
for h = height, 1, -1 do
|
||||
if not MakeWedge(i, h, k, heightmap, 1) then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function dist(x1, y1, x2, y2)
|
||||
return math.sqrt(math.pow(x2-x1, 2) + math.pow(y2-y1, 2))
|
||||
end
|
||||
|
||||
function dist3d(x1, y1, z1, x2, y2, z2)
|
||||
return math.sqrt(math.pow(dist(x1, z1, x2, z2), 2) + math.pow(math.abs(y2-y1)*100/d, 2))
|
||||
end
|
||||
|
||||
function onClicked(mouse)
|
||||
if on then
|
||||
|
||||
local c = game.Workspace.Terrain
|
||||
oldheightmap = {}
|
||||
heightmap = {}
|
||||
local cellPos = c:WorldToCellPreferSolid(Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
|
||||
local x = cellPos.X
|
||||
local y = cellPos.Y
|
||||
local z = cellPos.Z
|
||||
|
||||
mousedown = true
|
||||
local originalY = mouse.Y
|
||||
local prevY = originalY
|
||||
local d = 0
|
||||
local range = 0
|
||||
while mousedown == true do
|
||||
|
||||
if math.abs(mouse.Y - prevY) >= 5 then
|
||||
prevY = mouse.Y
|
||||
r2 = r + math.floor(50 * 1/s * math.abs(originalY - prevY)/mouse.ViewSizeY)
|
||||
if r2 > range then
|
||||
range = r2
|
||||
end
|
||||
d = math.floor(50 * (originalY - prevY)/mouse.ViewSizeY)
|
||||
elevate(x, y, z, r, r2, d, range)
|
||||
end
|
||||
wait(0)
|
||||
end
|
||||
print("Elevated at: "..x..", "..y..", "..z)
|
||||
end
|
||||
end
|
||||
|
||||
function On()
|
||||
self:Activate(true)
|
||||
toolbarbutton:SetActive(true)
|
||||
frame.Visible = true
|
||||
for w = 0, 0.3, 0.06 do
|
||||
frame.Size = UDim2.new(w, 0, w/2, 0)
|
||||
wait(0.0000001)
|
||||
end
|
||||
radl.Text = "Radius: "..r
|
||||
sfl.Text = "Slope: "..s
|
||||
on = true
|
||||
end
|
||||
|
||||
function Off()
|
||||
toolbarbutton:SetActive(false)
|
||||
radl.Text = ""
|
||||
sfl.Text = ""
|
||||
for w = 0.3, 0, -0.06 do
|
||||
frame.Size = UDim2.new(w, 0, w/2, 0)
|
||||
wait(0.0000001)
|
||||
end
|
||||
frame.Visible = false
|
||||
on = false
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
------
|
||||
--GUI-
|
||||
------
|
||||
|
||||
--load library for with sliders
|
||||
local RbxGui = LoadLibrary("RbxGui")
|
||||
|
||||
--screengui
|
||||
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
|
||||
--frame
|
||||
frame = Instance.new("Frame", g)
|
||||
frame.Position = UDim2.new(0.35, 0, 0.8, 0)
|
||||
frame.Size = UDim2.new(0.3, 0, 0.15, 0)
|
||||
frame.BackgroundTransparency = 0.5
|
||||
frame.Visible = false
|
||||
|
||||
--current radius display label
|
||||
radl = Instance.new("TextLabel", frame)
|
||||
radl.Position = UDim2.new(0.05, 0, 0.1, 0)
|
||||
radl.Size = UDim2.new(0.2, 0, 0.35, 0)
|
||||
radl.Text = ""
|
||||
radl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
radl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
radl.Font = Enum.Font.ArialBold
|
||||
radl.FontSize = Enum.FontSize.Size14
|
||||
radl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
radl.BackgroundTransparency = 1
|
||||
|
||||
--radius slider
|
||||
radSliderGui, radSliderPosition = RbxGui.CreateSlider(11, 0, UDim2.new(0.3, 0, 0.26, 0))
|
||||
radSliderGui.Parent = frame
|
||||
radBar = radSliderGui:FindFirstChild("Bar")
|
||||
radBar.Size = UDim2.new(0.65, 0, 0, 5)
|
||||
radSliderPosition.Value = r + 1
|
||||
radSliderPosition.Changed:connect(function()
|
||||
r = radSliderPosition.Value - 1
|
||||
radl.Text = "Radius: "..r
|
||||
end)
|
||||
|
||||
--current slope factor display label
|
||||
sfl = Instance.new("TextLabel", frame)
|
||||
sfl.Position = UDim2.new(0.05, 0, 0.55, 0)
|
||||
sfl.Size = UDim2.new(0.2, 0, 0.35, 0)
|
||||
sfl.Text = ""
|
||||
sfl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
sfl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
sfl.Font = Enum.Font.ArialBold
|
||||
sfl.FontSize = Enum.FontSize.Size14
|
||||
sfl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
sfl.BackgroundTransparency = 1
|
||||
|
||||
--slope factor slider
|
||||
sfSliderGui, sfSliderPosition = RbxGui.CreateSlider(16, 0, UDim2.new(0.3, 0, 0.71, 0))
|
||||
sfSliderGui.Parent = frame
|
||||
sfBar = sfSliderGui:FindFirstChild("Bar")
|
||||
sfBar.Size = UDim2.new(0.65, 0, 0, 5)
|
||||
sfSliderPosition.Value = s * 10 - 0.4
|
||||
sfSliderPosition.Changed:connect(function()
|
||||
s = sfSliderPosition.Value / 10 + 0.4
|
||||
sfl.Text = "Slope: "..s
|
||||
end)
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------
|
||||
--SUCCESSFUL LOAD MESSAGE-
|
||||
--------------------------
|
||||
loaded = true
|
||||
print("Elevation Plugin Loaded")
|
||||
@@ -0,0 +1,427 @@
|
||||
-----------------
|
||||
--DEFAULT VALUES-
|
||||
-----------------
|
||||
loaded = false
|
||||
on = false
|
||||
r = 5
|
||||
d = 0
|
||||
mousedown = false
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--PLUGIN SETUP-
|
||||
---------------
|
||||
self = PluginManager():CreatePlugin()
|
||||
self.Deactivation:connect(function()
|
||||
Off()
|
||||
end)
|
||||
|
||||
toolbar = self:CreateToolbar("Terrain")
|
||||
toolbarbutton = toolbar:CreateButton("", "Elevation Brush", "brush.png")
|
||||
toolbarbutton.Click:connect(function()
|
||||
if on then
|
||||
Off()
|
||||
elseif loaded then
|
||||
On()
|
||||
end
|
||||
end)
|
||||
|
||||
mouse = self:GetMouse()
|
||||
mouse.Button1Down:connect(function()
|
||||
onClicked(mouse)
|
||||
end)
|
||||
mouse.Button1Up:connect(function() mousedown = false end)
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
--FUNCTION DEFINITIONS-
|
||||
-----------------------
|
||||
|
||||
--makes a column of blocks from 1 up to height at location (x,z) in cluster c
|
||||
--if add is true, blocks below height will be added
|
||||
--if clear is true, blocks above height will be cleared
|
||||
function coordHeight(x, z, height, add, clear)
|
||||
c = game.Workspace.Terrain
|
||||
if add then
|
||||
for h = 1, height do
|
||||
c:SetCell(x, h, z, 1, 0, 0)
|
||||
end
|
||||
end
|
||||
if clear then
|
||||
ysize = c.MaxExtents.Max.Y
|
||||
for h = height + 1, ysize - 1 do
|
||||
c:SetCell(x, h, z, 0, 0, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--find height at coordinate x, z
|
||||
function getHeight(x, z)
|
||||
c = game.Workspace.Terrain
|
||||
h = 0
|
||||
material, wedge, rotation = c:GetCell(x, h + 1, z)
|
||||
while material.Value > 0 do
|
||||
h = h + 1
|
||||
material, wedge, rotation = c:GetCell(x, h + 1, z)
|
||||
end
|
||||
return h
|
||||
end
|
||||
|
||||
|
||||
function dist(x1, y1, x2, y2)
|
||||
return math.sqrt(math.pow(x2-x1, 2) + math.pow(y2-y1, 2))
|
||||
end
|
||||
|
||||
|
||||
function dist3d(x1, y1, z1, x2, y2, z2)
|
||||
return math.sqrt(math.pow(dist(x1, z1, x2, z2), 2) + math.pow(math.abs(y2-y1)*100/d, 2))
|
||||
end
|
||||
|
||||
|
||||
|
||||
--makes a wedge at location x, y, z using info from heightmap instead of GetCell
|
||||
--sets cell x, y, z to default material if parameter is provided, if not sets cell x, y, z to be whatever material it previously was
|
||||
--returns true if made a wedge, false if the cell remains a block
|
||||
function MakeWedge(x, y, z, heightmap, defaultmaterial)
|
||||
local c = game.Workspace.Terrain
|
||||
--gather info about all the cells around x, y, z
|
||||
local surroundings = {} --surroundings is a 3 x 3 x 3 array of the cells adjacent to x, y, z (1 if a cell is there, 0 if not)
|
||||
for i = x - 1, x + 1 do
|
||||
surroundings[i] = {}
|
||||
for j = y - 1, y + 1 do
|
||||
surroundings[i][j] = {}
|
||||
for k = z - 1, z + 1 do
|
||||
heightmapi = heightmap[i]
|
||||
height = nil
|
||||
if heightmapi then
|
||||
height = heightmapi[k]
|
||||
end
|
||||
if height and height >= j then
|
||||
surroundings[i][j][k] = 1
|
||||
else
|
||||
surroundings[i][j][k] = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--make some useful arrays and counters
|
||||
local sides = {} --sides is an array of the material of the 4 adjacent sides
|
||||
sides[0] = surroundings[x - 1][y][z]
|
||||
sides[1] = surroundings[x][y][z + 1]
|
||||
sides[2] = surroundings[x + 1][y][z]
|
||||
sides[3] = surroundings[x][y][z - 1]
|
||||
local adjacentSides = 0
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 then
|
||||
adjacentSides = adjacentSides + 1
|
||||
end
|
||||
end
|
||||
local sidesAbove = {} --sides is an array of the material of the 4 adjacent sides 1 height above
|
||||
sidesAbove[0] = surroundings[x - 1][y + 1][z]
|
||||
sidesAbove[1] = surroundings[x][y + 1][z + 1]
|
||||
sidesAbove[2] = surroundings[x + 1][y + 1][z]
|
||||
sidesAbove[3] = surroundings[x][y + 1][z - 1]
|
||||
local adjacentSidesAbove = 0
|
||||
for n = 0, 3 do
|
||||
if sidesAbove[n] > 0 then
|
||||
adjacentSidesAbove = adjacentSidesAbove + 1
|
||||
end
|
||||
end
|
||||
local corners = {} --corners is an array of the material of the 4 adjacent corners
|
||||
corners[0] = surroundings[x - 1][y][z - 1]
|
||||
corners[1] = surroundings[x - 1][y][z + 1]
|
||||
corners[2] = surroundings[x + 1][y][z + 1]
|
||||
corners[3] = surroundings[x + 1][y][z - 1]
|
||||
local adjacentCorners = 0
|
||||
for n = 0, 3 do
|
||||
if corners[n] > 0 then
|
||||
adjacentCorners = adjacentCorners + 1
|
||||
end
|
||||
end
|
||||
local cornersAbove = {} --corners is an array of the material of the 4 adjacent corners 1 height above
|
||||
cornersAbove[0] = surroundings[x - 1][y + 1][z - 1]
|
||||
cornersAbove[1] = surroundings[x - 1][y + 1][z + 1]
|
||||
cornersAbove[2] = surroundings[x + 1][y + 1][z + 1]
|
||||
cornersAbove[3] = surroundings[x + 1][y + 1][z - 1]
|
||||
local adjacentCornersAbove = 0
|
||||
for n = 0, 3 do
|
||||
if cornersAbove[n] > 0 then
|
||||
adjacentCornersAbove = adjacentCornersAbove + 1
|
||||
end
|
||||
end
|
||||
--determine what type of wedge to make
|
||||
local material = nil
|
||||
local wedge = nil
|
||||
local rotation = nil
|
||||
if defaultmaterial then
|
||||
material = defaultmaterial
|
||||
else
|
||||
material, wedge, rotation = c:GetCell(x, y, z) --start with the existing material, wedge, and rotation
|
||||
end
|
||||
wedge = 0 --default wedge is a block
|
||||
rotation = 0 --default rotation is 0
|
||||
--type 1: 45 degree ramp //must not have a block on top and must have a block under, and be surrounded by 1 side; or 3 sides and the 2 corners between them
|
||||
if surroundings[x][y + 1][z] == 0 and surroundings[x][y - 1][z] > 0 then
|
||||
if adjacentSides == 1 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 then
|
||||
wedge = 1
|
||||
rotation = (n + 1) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
elseif adjacentSides == 3 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 and corners[(n + 1) % 4] > 0 and sides[(n + 1) % 4] > 0 and corners[(n + 2) % 4] > 0 and sides[(n + 2) % 4] > 0 then
|
||||
wedge = 1
|
||||
rotation = (n + 2) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 2: 45 degree corner //must not have a block on top and must have a block under, and be surrounded by 2 sides and the 1 corner between them; or 3 sides and 1 corner between 2 of them (facing towards that corner)
|
||||
if surroundings[x][y + 1][z] == 0 and surroundings[x][y - 1][z] > 0 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 and corners[(n + 1) % 4] > 0 and sides[(n + 1) % 4] > 0 and (adjacentSides == 2 or (adjacentSides == 3 and (corners[(n + 3) % 4] > 0 or (sides[(n + 2) % 4] > 0 and corners[(n + 2) % 4] > 0) or (sides[(n + 3) % 4] > 0 and corners[n] > 0)))) then
|
||||
wedge = 2
|
||||
rotation = (n + 2) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 3: 45 degree inverse corner //surrounded by three sides or 4 sides and 3 corners, with nothing above or else a block on top surrounded on 2 sides and the corner between them
|
||||
if adjacentSides == 3 and surroundings[x][y + 1][z] > 0 then
|
||||
if adjacentCorners > 1 then
|
||||
for n = 0, 3 do
|
||||
if (corners[n] == 0 or cornersAbove[n] == 0) and (sides[(n - 1) % 4] == 0 or sides[n] == 0) and (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] > 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] == 0) then
|
||||
wedge = 3
|
||||
rotation = (n + 3) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif adjacentSides == 4 and adjacentCorners == 3 then
|
||||
for n = 0, 3 do
|
||||
if corners[n] == 0 and (surroundings[x][y + 1][z] == 0 or (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] > 0 and cornersAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] == 0)) then
|
||||
wedge = 3
|
||||
rotation = (n + 3) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 4: half a cube, as if it were cut diagonally from front to back //surrounded by 2 sides
|
||||
if adjacentSides == 2 and adjacentCorners < 4 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] == 0 and sides[(n + 1) % 4] == 0 and (surroundings[x][y + 1][z] == 0 or (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] == 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] > 0)) then
|
||||
wedge = 4
|
||||
rotation = n
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
--brushes terrain at point (x, y, z) in cluster c
|
||||
function brush(x, y, z, r, d)
|
||||
c = game.Workspace.Terrain
|
||||
|
||||
for i = x - (r + 3), x + (r + 3) do
|
||||
for k = z - (r + 3), z + (r + 3) do
|
||||
|
||||
if d >= 0 then
|
||||
inc = 1
|
||||
material = 1
|
||||
heightoffset = 0
|
||||
add = true
|
||||
else
|
||||
inc = -1
|
||||
material = 0
|
||||
heightoffset = 1
|
||||
add = false
|
||||
end
|
||||
|
||||
heightmapi = heightmap[i]
|
||||
if heightmapi then
|
||||
heightmapik = heightmapi[k]
|
||||
else
|
||||
heightmap[i] = {}
|
||||
end
|
||||
|
||||
if dist(x, z, i, k) < r then
|
||||
coordHeight(i, k, y + d, add, not add)
|
||||
end
|
||||
|
||||
heightmap[i][k] = getHeight(i, k)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
for ri = 0, r + 2 do
|
||||
i = x - ri
|
||||
for k = z - (r + 2), z + (r + 2) do
|
||||
height = heightmap[i][k]
|
||||
if height == nil then
|
||||
height = -1
|
||||
end
|
||||
for h = height, 0, -1 do
|
||||
if not MakeWedge(i, h, k, heightmap, 1) then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
i = x + ri
|
||||
for k = z - (r + 2), z + (r + 2) do
|
||||
height = heightmap[i][k]
|
||||
if height == nil then
|
||||
height = -1
|
||||
end
|
||||
for h = height, 0, -1 do
|
||||
if not MakeWedge(i, h, k, heightmap, 1) then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
wait(0)
|
||||
|
||||
end
|
||||
|
||||
|
||||
function onClicked(mouse)
|
||||
if on then
|
||||
|
||||
c = game.Workspace.Terrain
|
||||
heightmap = {}
|
||||
mousedown = true
|
||||
brushheight = nil
|
||||
while mousedown == true do
|
||||
local cellPos = c:WorldToCellPreferSolid(Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
|
||||
local x = cellPos.x
|
||||
local y = cellPos.y
|
||||
local z = cellPos.z
|
||||
|
||||
if brushheight == nil then
|
||||
brushheight = y
|
||||
end
|
||||
brush(x, brushheight, z, r, d)
|
||||
print("Brushed at: "..x..", "..brushheight..", "..z)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function On()
|
||||
self:Activate(true)
|
||||
toolbarbutton:SetActive(true)
|
||||
frame.Visible = true
|
||||
for w = 0, 0.3, 0.06 do
|
||||
frame.Size = UDim2.new(w, 0, w/2, 0)
|
||||
wait(0.0000001)
|
||||
end
|
||||
radl.Text = "Radius: "..r
|
||||
dfl.Text = "Height: "..d
|
||||
on = true
|
||||
end
|
||||
|
||||
function Off()
|
||||
toolbarbutton:SetActive(false)
|
||||
radl.Text = ""
|
||||
dfl.Text = ""
|
||||
for w = 0.3, 0, -0.06 do
|
||||
frame.Size = UDim2.new(w, 0, w/2, 0)
|
||||
wait(0.0000001)
|
||||
end
|
||||
frame.Visible = false
|
||||
on = false
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
------
|
||||
--GUI-
|
||||
------
|
||||
|
||||
--load library for with sliders
|
||||
local RbxGui = LoadLibrary("RbxGui")
|
||||
|
||||
--screengui
|
||||
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
|
||||
--frame
|
||||
frame = Instance.new("Frame", g)
|
||||
frame.Position = UDim2.new(0.35, 0, 0.8, 0)
|
||||
frame.Size = UDim2.new(0.3, 0, 0.15, 0)
|
||||
frame.BackgroundTransparency = 0.5
|
||||
frame.Visible = false
|
||||
|
||||
--current radius display label
|
||||
radl = Instance.new("TextLabel", frame)
|
||||
radl.Position = UDim2.new(0.05, 0, 0.1, 0)
|
||||
radl.Size = UDim2.new(0.2, 0, 0.35, 0)
|
||||
radl.Text = ""
|
||||
radl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
radl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
radl.Font = Enum.Font.ArialBold
|
||||
radl.FontSize = Enum.FontSize.Size14
|
||||
radl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
radl.BackgroundTransparency = 1
|
||||
|
||||
--radius slider
|
||||
radSliderGui, radSliderPosition = RbxGui.CreateSlider(5, 0, UDim2.new(0.3, 0, 0.26, 0))
|
||||
radSliderGui.Parent = frame
|
||||
radBar = radSliderGui:FindFirstChild("Bar")
|
||||
radBar.Size = UDim2.new(0.65, 0, 0, 5)
|
||||
radSliderPosition.Value = r - 1
|
||||
radSliderPosition.Changed:connect(function()
|
||||
r = radSliderPosition.Value + 1
|
||||
radl.Text = "Radius: "..r
|
||||
end)
|
||||
|
||||
--current depth factor display label
|
||||
dfl = Instance.new("TextLabel", frame)
|
||||
dfl.Position = UDim2.new(0.05, 0, 0.55, 0)
|
||||
dfl.Size = UDim2.new(0.2, 0, 0.35, 0)
|
||||
dfl.Text = ""
|
||||
dfl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
dfl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
dfl.Font = Enum.Font.ArialBold
|
||||
dfl.FontSize = Enum.FontSize.Size14
|
||||
dfl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
dfl.BackgroundTransparency = 1
|
||||
|
||||
--depth factor slider
|
||||
dfSliderGui, dfSliderPosition = RbxGui.CreateSlider(61, 0, UDim2.new(0.3, 0, 0.71, 0))
|
||||
dfSliderGui.Parent = frame
|
||||
dfBar = dfSliderGui:FindFirstChild("Bar")
|
||||
dfBar.Size = UDim2.new(0.65, 0, 0, 5)
|
||||
dfSliderPosition.Value = d + 31
|
||||
dfSliderPosition.Changed:connect(function()
|
||||
d = dfSliderPosition.Value - 31
|
||||
dfl.Text = "Height: "..d
|
||||
end)
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------
|
||||
--SUCCESSFUL LOAD MESSAGE-
|
||||
--------------------------
|
||||
loaded = true
|
||||
print("Elevation Plugin Loaded")
|
||||
@@ -0,0 +1,131 @@
|
||||
-----------------
|
||||
--DEFAULT VALUES-
|
||||
-----------------
|
||||
loaded = false
|
||||
on = false
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--PLUGIN SETUP-
|
||||
---------------
|
||||
self = PluginManager():CreatePlugin()
|
||||
mouse = self:GetMouse()
|
||||
mouse.Button1Down:connect(function() onClicked(mouse) end)
|
||||
self.Deactivation:connect(function()
|
||||
Off()
|
||||
end)
|
||||
toolbar = self:CreateToolbar("Terrain")
|
||||
toolbarbutton = toolbar:CreateButton("", "Plateau", "plateaus.png")
|
||||
toolbarbutton.Click:connect(function()
|
||||
if on then
|
||||
Off()
|
||||
elseif loaded then
|
||||
On()
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
--FUNCTION DEFINITIONS-
|
||||
-----------------------
|
||||
|
||||
--makes a plateau starting at point (x, y, z)
|
||||
function makePlateau(x, y, z)
|
||||
c = game.Workspace.Terrain
|
||||
q = {}
|
||||
index = 0
|
||||
q[index] = x
|
||||
q[index+1] = y
|
||||
q[index+2] = z
|
||||
insertindex = 3
|
||||
c:SetCell(q[index], q[index+1], q[index+2], 0, 0, 0)
|
||||
while q[index] do
|
||||
|
||||
insertindex = plateauHelper(insertindex, 0, 1, 0)
|
||||
insertindex = plateauHelper(insertindex, -1, 0, -1)
|
||||
insertindex = plateauHelper(insertindex, -1, 0, 0)
|
||||
insertindex = plateauHelper(insertindex, -1, 0, 1)
|
||||
insertindex = plateauHelper(insertindex, 0, 0, -1)
|
||||
insertindex = plateauHelper(insertindex, 0, 0, 1)
|
||||
insertindex = plateauHelper(insertindex, 1, 0, -1)
|
||||
insertindex = plateauHelper(insertindex, 1, 0, 0)
|
||||
insertindex = plateauHelper(insertindex, 1, 0, 1)
|
||||
|
||||
q[index] = nil
|
||||
q[index + 1] = nil
|
||||
q[index + 2] = nil
|
||||
index = index + 3
|
||||
if index % 1000 == 0 then
|
||||
wait()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function plateauHelper(insertindex, xoffset, yoffset, zoffset)
|
||||
material, wedge, rotation = c:GetCell(q[index] + xoffset, q[index+1] + yoffset, q[index+2] + zoffset)
|
||||
if material.Value > 0 then
|
||||
q[insertindex] = q[index] + xoffset
|
||||
q[insertindex+1] = q[index+1] + yoffset
|
||||
q[insertindex+2] = q[index+2] + zoffset
|
||||
c:SetCell(q[index] + xoffset, q[index+1] + yoffset, q[index+2] + zoffset, 0, 0, 0)
|
||||
insertindex = insertindex + 3
|
||||
end
|
||||
return insertindex
|
||||
end
|
||||
|
||||
|
||||
function dist(x1, y1, x2, y2)
|
||||
return math.sqrt(math.pow(x2-x1, 2) + math.pow(y2-y1, 2))
|
||||
end
|
||||
|
||||
function dist3d(x1, y1, z1, x2, y2, z2)
|
||||
return math.sqrt(math.pow(dist(x1, y1, x2, y2), 2) + math.pow(z2-z1, 2))
|
||||
end
|
||||
|
||||
function onClicked(mouse)
|
||||
if on then
|
||||
|
||||
c = game.Workspace.Terrain
|
||||
|
||||
local cellPos = c:WorldToCellPreferSolid(Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
|
||||
local x = cellPos.x
|
||||
local y = cellPos.y
|
||||
local z = cellPos.z
|
||||
|
||||
print("Plateau formed at: "..x..", "..y..", "..z)
|
||||
makePlateau(x, y, z)
|
||||
end
|
||||
end
|
||||
|
||||
function On()
|
||||
self:Activate(true)
|
||||
toolbarbutton:SetActive(true)
|
||||
on = true
|
||||
end
|
||||
|
||||
function Off()
|
||||
toolbarbutton:SetActive(false)
|
||||
on = false
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
------
|
||||
--GUI-
|
||||
------
|
||||
|
||||
--screengui
|
||||
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------
|
||||
--SUCCESSFUL LOAD MESSAGE-
|
||||
--------------------------
|
||||
loaded = true
|
||||
print("Plateaus Plugin Loaded")
|
||||
@@ -0,0 +1,386 @@
|
||||
-----------------
|
||||
--DEFAULT VALUES-
|
||||
-----------------
|
||||
loaded = false
|
||||
on = false
|
||||
r = 20
|
||||
d = 20
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--PLUGIN SETUP-
|
||||
---------------
|
||||
self = PluginManager():CreatePlugin()
|
||||
mouse = self:GetMouse()
|
||||
mouse.Button1Down:connect(function() onClicked(mouse) end)
|
||||
self.Deactivation:connect(function()
|
||||
Off()
|
||||
end)
|
||||
toolbar = self:CreateToolbar("Terrain")
|
||||
toolbarbutton = toolbar:CreateButton("", "Crater", "craters.png")
|
||||
toolbarbutton.Click:connect(function()
|
||||
if on then
|
||||
Off()
|
||||
elseif loaded then
|
||||
On()
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
--FUNCTION DEFINITIONS-
|
||||
-----------------------
|
||||
|
||||
--makes a wedge at location x, y, z using info from heightmap instead of GetCell
|
||||
--sets cell x, y, z to default material if parameter is provided, if not sets cell x, y, z to be whatever material it previously was
|
||||
--returns true if made a wedge, false if the cell remains a block
|
||||
function MakeWedge(x, y, z, heightmap, defaultmaterial)
|
||||
local c = game.Workspace.Terrain
|
||||
--gather info about all the cells around x, y, z
|
||||
|
||||
|
||||
local surroundings = {} --surroundings is a 3 x 3 x 3 array of the cells adjacent to x, y, z (1 if a cell is there, 0 if not)
|
||||
for i = x - 1, x + 1 do
|
||||
surroundings[i] = {}
|
||||
for j = y - 1, y + 1 do
|
||||
surroundings[i][j] = {}
|
||||
for k = z - 1, z + 1 do
|
||||
heightmapi = heightmap[i]
|
||||
height = nil
|
||||
if heightmapi then
|
||||
height = heightmapi[k]
|
||||
end
|
||||
if height then
|
||||
if height >= j then
|
||||
surroundings[i][j][k] = 1
|
||||
else
|
||||
surroundings[i][j][k] = 0
|
||||
end
|
||||
else -- need to get info from cell when our heightmap doesn't exist there! [otherwise, we can get holes through the terrain]
|
||||
local material, wedge, rotation = c:GetCell(i, j, k)
|
||||
surroundings[i][j][k] = material.Value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--make some useful arrays and counters
|
||||
local sides = {} --sides is an array of the material of the 4 adjacent sides
|
||||
sides[0] = surroundings[x - 1][y][z]
|
||||
sides[1] = surroundings[x][y][z + 1]
|
||||
sides[2] = surroundings[x + 1][y][z]
|
||||
sides[3] = surroundings[x][y][z - 1]
|
||||
local adjacentSides = 0
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 then
|
||||
adjacentSides = adjacentSides + 1
|
||||
end
|
||||
end
|
||||
local sidesAbove = {} --sides is an array of the material of the 4 adjacent sides 1 height above
|
||||
sidesAbove[0] = surroundings[x - 1][y + 1][z]
|
||||
sidesAbove[1] = surroundings[x][y + 1][z + 1]
|
||||
sidesAbove[2] = surroundings[x + 1][y + 1][z]
|
||||
sidesAbove[3] = surroundings[x][y + 1][z - 1]
|
||||
local adjacentSidesAbove = 0
|
||||
for n = 0, 3 do
|
||||
if sidesAbove[n] > 0 then
|
||||
adjacentSidesAbove = adjacentSidesAbove + 1
|
||||
end
|
||||
end
|
||||
local corners = {} --corners is an array of the material of the 4 adjacent corners
|
||||
corners[0] = surroundings[x - 1][y][z - 1]
|
||||
corners[1] = surroundings[x - 1][y][z + 1]
|
||||
corners[2] = surroundings[x + 1][y][z + 1]
|
||||
corners[3] = surroundings[x + 1][y][z - 1]
|
||||
local adjacentCorners = 0
|
||||
for n = 0, 3 do
|
||||
if corners[n] > 0 then
|
||||
adjacentCorners = adjacentCorners + 1
|
||||
end
|
||||
end
|
||||
local cornersAbove = {} --corners is an array of the material of the 4 adjacent corners 1 height above
|
||||
cornersAbove[0] = surroundings[x - 1][y + 1][z - 1]
|
||||
cornersAbove[1] = surroundings[x - 1][y + 1][z + 1]
|
||||
cornersAbove[2] = surroundings[x + 1][y + 1][z + 1]
|
||||
cornersAbove[3] = surroundings[x + 1][y + 1][z - 1]
|
||||
local adjacentCornersAbove = 0
|
||||
for n = 0, 3 do
|
||||
if cornersAbove[n] > 0 then
|
||||
adjacentCornersAbove = adjacentCornersAbove + 1
|
||||
end
|
||||
end
|
||||
--determine what type of wedge to make
|
||||
local material = nil
|
||||
local wedge = nil
|
||||
local rotation = nil
|
||||
if defaultmaterial then
|
||||
material = defaultmaterial
|
||||
else
|
||||
material, wedge, rotation = c:GetCell(x, y, z) --start with the existing material, wedge, and rotation
|
||||
end
|
||||
wedge = 0 --default wedge is a block
|
||||
rotation = 0 --default rotation is 0
|
||||
--type 1: 45 degree ramp //must not have a block on top and must have a block under, and be surrounded by 1 side; or 3 sides and the 2 corners between them
|
||||
if surroundings[x][y + 1][z] == 0 and surroundings[x][y - 1][z] > 0 then
|
||||
if adjacentSides == 1 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 then
|
||||
wedge = 1
|
||||
rotation = (n + 1) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
elseif adjacentSides == 3 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 and corners[(n + 1) % 4] > 0 and sides[(n + 1) % 4] > 0 and corners[(n + 2) % 4] > 0 and sides[(n + 2) % 4] > 0 then
|
||||
wedge = 1
|
||||
rotation = (n + 2) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 2: 45 degree corner //must not have a block on top and must have a block under, and be surrounded by 2 sides and the 1 corner between them; or 3 sides and 1 corner between 2 of them (facing towards that corner)
|
||||
if surroundings[x][y + 1][z] == 0 and surroundings[x][y - 1][z] > 0 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 and corners[(n + 1) % 4] > 0 and sides[(n + 1) % 4] > 0 and (adjacentSides == 2 or (adjacentSides == 3 and (corners[(n + 3) % 4] > 0 or (sides[(n + 2) % 4] > 0 and corners[(n + 2) % 4] > 0) or (sides[(n + 3) % 4] > 0 and corners[n] > 0)))) then
|
||||
wedge = 2
|
||||
rotation = (n + 2) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 3: 45 degree inverse corner //surrounded by three sides or 4 sides and 3 corners, with nothing above or else a block on top surrounded on 2 sides and the corner between them
|
||||
if adjacentSides == 3 and surroundings[x][y + 1][z] > 0 then
|
||||
if adjacentCorners > 1 then
|
||||
for n = 0, 3 do
|
||||
if (corners[n] == 0 or cornersAbove[n] == 0) and (sides[(n - 1) % 4] == 0 or sides[n] == 0) and (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] > 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] == 0) then
|
||||
wedge = 3
|
||||
rotation = (n + 3) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif adjacentSides == 4 and adjacentCorners == 3 then
|
||||
for n = 0, 3 do
|
||||
if corners[n] == 0 and (surroundings[x][y + 1][z] == 0 or (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] > 0 and cornersAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] == 0)) then
|
||||
wedge = 3
|
||||
rotation = (n + 3) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 4: half a cube, as if it were cut diagonally from front to back //surrounded by 2 sides
|
||||
if adjacentSides == 2 and adjacentCorners < 4 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] == 0 and sides[(n + 1) % 4] == 0 and (surroundings[x][y + 1][z] == 0 or (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] == 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] > 0)) then
|
||||
wedge = 4
|
||||
rotation = n
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
--makes a crater at point (x, y, z) in cluster c
|
||||
--d is the depth factor, a percent of the depth of a perfect sphere
|
||||
function makeCrater(x, y, z, r, d)
|
||||
c = game.Workspace.Terrain
|
||||
local heightmap = {}
|
||||
for i = x - (r + 1), x + (r + 1) do
|
||||
heightmap[i] = {}
|
||||
end
|
||||
|
||||
for j = 0, r + 1 do
|
||||
local cellschanged = false
|
||||
for i = x - (r + 1), x + (r + 1) do
|
||||
for k = z - (r + 1), z + (r + 1) do
|
||||
distance = math.sqrt(math.pow(dist(x, z, i, k), 2) + math.pow(y - (y - j*(100/d)), 2))
|
||||
if distance < r then
|
||||
c:SetCell(i, y + j, k, 0, 0, 0)
|
||||
c:SetCell(i, y - j, k, 0, 0, 0)
|
||||
cellschanged = true
|
||||
elseif heightmap[i] and heightmap[i][k] == nil then
|
||||
material, wedge, rotation = c:GetCell(i, y - j, k)
|
||||
if material.Value > 0 then
|
||||
heightmap[i][k] = y - j
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if cellschanged == false then
|
||||
break
|
||||
end
|
||||
wait(0)
|
||||
end
|
||||
|
||||
for ri = 0, r do
|
||||
wait(0)
|
||||
|
||||
i = x - ri
|
||||
for k = z - r, z + r do
|
||||
height = heightmap[i][k]
|
||||
if height == nil then
|
||||
height = -1
|
||||
end
|
||||
for h = height, 0, -1 do
|
||||
if not MakeWedge(i, h, k, heightmap, nil) then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
i = x + ri
|
||||
for k = z - r, z + r do
|
||||
height = heightmap[i][k]
|
||||
if height == nil then
|
||||
height = -1
|
||||
end
|
||||
for h = height, 0, -1 do
|
||||
if not MakeWedge(i, h, k, heightmap, nil) then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
function dist(x1, y1, x2, y2)
|
||||
return math.sqrt(math.pow(x2-x1, 2) + math.pow(y2-y1, 2))
|
||||
end
|
||||
|
||||
local debounce = false
|
||||
function onClicked(mouse)
|
||||
if on and not debounce then
|
||||
debounce = true
|
||||
c = game.Workspace.Terrain
|
||||
|
||||
local cellPos = c:WorldToCellPreferSolid(Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
|
||||
local x = cellPos.x
|
||||
local y = cellPos.y
|
||||
local z = cellPos.z
|
||||
|
||||
makeCrater(x, y, z, r, d)
|
||||
|
||||
print("Crater formed at: "..x..", "..y..", "..z)
|
||||
debounce = false
|
||||
end
|
||||
end
|
||||
|
||||
function On()
|
||||
self:Activate(true)
|
||||
toolbarbutton:SetActive(true)
|
||||
frame.Visible = true
|
||||
for w = 0, 0.3, 0.06 do
|
||||
frame.Size = UDim2.new(w, 0, w/2, 0)
|
||||
wait(0)
|
||||
end
|
||||
radl.Text = "Radius: "..r
|
||||
dfl.Text = "Depth: "..d.."%"
|
||||
on = true
|
||||
end
|
||||
|
||||
function Off()
|
||||
toolbarbutton:SetActive(false)
|
||||
radl.Text = ""
|
||||
dfl.Text = ""
|
||||
for w = 0.3, 0, -0.06 do
|
||||
frame.Size = UDim2.new(w, 0, w/2, 0)
|
||||
wait(0)
|
||||
end
|
||||
frame.Visible = false
|
||||
on = false
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
------
|
||||
--GUI-
|
||||
------
|
||||
|
||||
--load library for with sliders
|
||||
local RbxGui = LoadLibrary("RbxGui")
|
||||
|
||||
--screengui
|
||||
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
|
||||
--frame
|
||||
frame = Instance.new("Frame", g)
|
||||
frame.Position = UDim2.new(0.35, 0, 0.8, 0)
|
||||
frame.Size = UDim2.new(0.3, 0, 0.15, 0)
|
||||
frame.BackgroundTransparency = 0.5
|
||||
frame.Visible = false
|
||||
|
||||
--current radius display label
|
||||
radl = Instance.new("TextLabel", frame)
|
||||
radl.Position = UDim2.new(0.05, 0, 0.1, 0)
|
||||
radl.Size = UDim2.new(0.2, 0, 0.35, 0)
|
||||
radl.Text = ""
|
||||
radl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
radl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
radl.Font = Enum.Font.ArialBold
|
||||
radl.FontSize = Enum.FontSize.Size14
|
||||
radl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
radl.BackgroundTransparency = 1
|
||||
|
||||
--radius slider
|
||||
radSliderGui, radSliderPosition = RbxGui.CreateSlider(128, 0, UDim2.new(0.3, 0, 0.26, 0))
|
||||
radSliderGui.Parent = frame
|
||||
radBar = radSliderGui:FindFirstChild("Bar")
|
||||
radBar.Size = UDim2.new(0.65, 0, 0, 5)
|
||||
radSliderPosition.Value = r
|
||||
radSliderPosition.Changed:connect(function()
|
||||
r = radSliderPosition.Value
|
||||
radl.Text = "Radius: "..r
|
||||
end)
|
||||
|
||||
--current depth factor display label
|
||||
dfl = Instance.new("TextLabel", frame)
|
||||
dfl.Position = UDim2.new(0.05, 0, 0.55, 0)
|
||||
dfl.Size = UDim2.new(0.2, 0, 0.35, 0)
|
||||
dfl.Text = ""
|
||||
dfl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
dfl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
dfl.Font = Enum.Font.ArialBold
|
||||
dfl.FontSize = Enum.FontSize.Size14
|
||||
dfl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
dfl.BackgroundTransparency = 1
|
||||
|
||||
--depth factor slider
|
||||
dfSliderGui, dfSliderPosition = RbxGui.CreateSlider(100, 0, UDim2.new(0.3, 0, 0.71, 0))
|
||||
dfSliderGui.Parent = frame
|
||||
dfBar = dfSliderGui:FindFirstChild("Bar")
|
||||
dfBar.Size = UDim2.new(0.65, 0, 0, 5)
|
||||
dfSliderPosition.Value = d
|
||||
dfSliderPosition.Changed:connect(function()
|
||||
d = dfSliderPosition.Value
|
||||
dfl.Text = "Depth: "..d.."%"
|
||||
end)
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------
|
||||
--SUCCESSFUL LOAD MESSAGE-
|
||||
--------------------------
|
||||
loaded = true
|
||||
print("Craters Plugin Loaded")
|
||||
@@ -0,0 +1,383 @@
|
||||
-----------------
|
||||
--DEFAULT VALUES-
|
||||
-----------------
|
||||
loaded = false
|
||||
on = false
|
||||
r = 20
|
||||
d = 50
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--PLUGIN SETUP-
|
||||
---------------
|
||||
self = PluginManager():CreatePlugin()
|
||||
mouse = self:GetMouse()
|
||||
mouse.Button1Down:connect(function() onClicked(mouse) end)
|
||||
self.Deactivation:connect(function()
|
||||
Off()
|
||||
end)
|
||||
toolbar = self:CreateToolbar("Terrain")
|
||||
toolbarbutton = toolbar:CreateButton("", "Orb", "orbs.png")
|
||||
toolbarbutton.Click:connect(function()
|
||||
if on then
|
||||
Off()
|
||||
elseif loaded then
|
||||
On()
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
--FUNCTION DEFINITIONS-
|
||||
-----------------------
|
||||
|
||||
--find height at coordinate x, z
|
||||
function getHeight(x, z)
|
||||
c = game.Workspace.Terrain
|
||||
h = 0
|
||||
material, wedge, rotation = c:GetCell(x, h + 1, z)
|
||||
while material.Value > 0 do
|
||||
h = h + 1
|
||||
material, wedge, rotation = c:GetCell(x, h + 1, z)
|
||||
end
|
||||
return h
|
||||
end
|
||||
|
||||
--makes a wedge at location x, y, z using info from heightmap instead of GetCell
|
||||
--sets cell x, y, z to default material if parameter is provided, if not sets cell x, y, z to be whatever material it previously was
|
||||
--returns true if made a wedge, false if the cell remains a block
|
||||
function MakeWedge(x, y, z, heightmap, defaultmaterial)
|
||||
local c = game.Workspace.Terrain
|
||||
--gather info about all the cells around x, y, z
|
||||
local surroundings = {} --surroundings is a 3 x 3 x 3 array of the cells adjacent to x, y, z (1 if a cell is there, 0 if not)
|
||||
for i = x - 1, x + 1 do
|
||||
surroundings[i] = {}
|
||||
for j = y - 1, y + 1 do
|
||||
surroundings[i][j] = {}
|
||||
for k = z - 1, z + 1 do
|
||||
heightmapi = heightmap[i]
|
||||
height = nil
|
||||
if heightmapi then
|
||||
height = heightmapi[k]
|
||||
end
|
||||
if height and height >= j then
|
||||
surroundings[i][j][k] = 1
|
||||
else
|
||||
surroundings[i][j][k] = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--make some useful arrays and counters
|
||||
local sides = {} --sides is an array of the material of the 4 adjacent sides
|
||||
sides[0] = surroundings[x - 1][y][z]
|
||||
sides[1] = surroundings[x][y][z + 1]
|
||||
sides[2] = surroundings[x + 1][y][z]
|
||||
sides[3] = surroundings[x][y][z - 1]
|
||||
local adjacentSides = 0
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 then
|
||||
adjacentSides = adjacentSides + 1
|
||||
end
|
||||
end
|
||||
local sidesAbove = {} --sides is an array of the material of the 4 adjacent sides 1 height above
|
||||
sidesAbove[0] = surroundings[x - 1][y + 1][z]
|
||||
sidesAbove[1] = surroundings[x][y + 1][z + 1]
|
||||
sidesAbove[2] = surroundings[x + 1][y + 1][z]
|
||||
sidesAbove[3] = surroundings[x][y + 1][z - 1]
|
||||
local adjacentSidesAbove = 0
|
||||
for n = 0, 3 do
|
||||
if sidesAbove[n] > 0 then
|
||||
adjacentSidesAbove = adjacentSidesAbove + 1
|
||||
end
|
||||
end
|
||||
local corners = {} --corners is an array of the material of the 4 adjacent corners
|
||||
corners[0] = surroundings[x - 1][y][z - 1]
|
||||
corners[1] = surroundings[x - 1][y][z + 1]
|
||||
corners[2] = surroundings[x + 1][y][z + 1]
|
||||
corners[3] = surroundings[x + 1][y][z - 1]
|
||||
local adjacentCorners = 0
|
||||
for n = 0, 3 do
|
||||
if corners[n] > 0 then
|
||||
adjacentCorners = adjacentCorners + 1
|
||||
end
|
||||
end
|
||||
local cornersAbove = {} --corners is an array of the material of the 4 adjacent corners 1 height above
|
||||
cornersAbove[0] = surroundings[x - 1][y + 1][z - 1]
|
||||
cornersAbove[1] = surroundings[x - 1][y + 1][z + 1]
|
||||
cornersAbove[2] = surroundings[x + 1][y + 1][z + 1]
|
||||
cornersAbove[3] = surroundings[x + 1][y + 1][z - 1]
|
||||
local adjacentCornersAbove = 0
|
||||
for n = 0, 3 do
|
||||
if cornersAbove[n] > 0 then
|
||||
adjacentCornersAbove = adjacentCornersAbove + 1
|
||||
end
|
||||
end
|
||||
--determine what type of wedge to make
|
||||
local material = nil
|
||||
local wedge = nil
|
||||
local rotation = nil
|
||||
if defaultmaterial then
|
||||
material = defaultmaterial
|
||||
else
|
||||
material, wedge, rotation = c:GetCell(x, y, z) --start with the existing material, wedge, and rotation
|
||||
end
|
||||
wedge = 0 --default wedge is a block
|
||||
rotation = 0 --default rotation is 0
|
||||
--type 1: 45 degree ramp //must not have a block on top and must have a block under, and be surrounded by 1 side; or 3 sides and the 2 corners between them
|
||||
if surroundings[x][y + 1][z] == 0 and surroundings[x][y - 1][z] > 0 then
|
||||
if adjacentSides == 1 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 then
|
||||
wedge = 1
|
||||
rotation = (n + 1) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
elseif adjacentSides == 3 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 and corners[(n + 1) % 4] > 0 and sides[(n + 1) % 4] > 0 and corners[(n + 2) % 4] > 0 and sides[(n + 2) % 4] > 0 then
|
||||
wedge = 1
|
||||
rotation = (n + 2) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 2: 45 degree corner //must not have a block on top and must have a block under, and be surrounded by 2 sides and the 1 corner between them; or 3 sides and 1 corner between 2 of them (facing towards that corner)
|
||||
if surroundings[x][y + 1][z] == 0 and surroundings[x][y - 1][z] > 0 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] > 0 and corners[(n + 1) % 4] > 0 and sides[(n + 1) % 4] > 0 and (adjacentSides == 2 or (adjacentSides == 3 and (corners[(n + 3) % 4] > 0 or (sides[(n + 2) % 4] > 0 and corners[(n + 2) % 4] > 0) or (sides[(n + 3) % 4] > 0 and corners[n] > 0)))) then
|
||||
wedge = 2
|
||||
rotation = (n + 2) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 3: 45 degree inverse corner //surrounded by three sides or 4 sides and 3 corners, with nothing above or else a block on top surrounded on 2 sides and the corner between them
|
||||
if adjacentSides == 3 and surroundings[x][y + 1][z] > 0 then
|
||||
if adjacentCorners > 1 then
|
||||
for n = 0, 3 do
|
||||
if (corners[n] == 0 or cornersAbove[n] == 0) and (sides[(n - 1) % 4] == 0 or sides[n] == 0) and (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] > 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] == 0) then
|
||||
wedge = 3
|
||||
rotation = (n + 3) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif adjacentSides == 4 and adjacentCorners == 3 then
|
||||
for n = 0, 3 do
|
||||
if corners[n] == 0 and (surroundings[x][y + 1][z] == 0 or (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] > 0 and cornersAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] == 0)) then
|
||||
wedge = 3
|
||||
rotation = (n + 3) % 4
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
--type 4: half a cube, as if it were cut diagonally from front to back //surrounded by 2 sides
|
||||
if adjacentSides == 2 and adjacentCorners < 4 then
|
||||
for n = 0, 3 do
|
||||
if sides[n] == 0 and sides[(n + 1) % 4] == 0 and (surroundings[x][y + 1][z] == 0 or (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] == 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] > 0)) then
|
||||
wedge = 4
|
||||
rotation = n
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
c:SetCell(x, y, z, material, wedge, rotation)
|
||||
return false
|
||||
end
|
||||
|
||||
--makes an orb at point (x, y, z) in cluster c
|
||||
--d is the depth factor, a percent of the depth of a perfect sphere
|
||||
function makeBall(x, y, z, r, d)
|
||||
c = game.Workspace.Terrain
|
||||
local heightmap = {}
|
||||
for i = x - (r + 1), x + (r + 1) do
|
||||
heightmap[i] = {}
|
||||
end
|
||||
|
||||
for j = 0, r + 1 do
|
||||
local cellschanged = false
|
||||
for i = x - (r + 1), x + (r + 1) do
|
||||
for k = z - (r + 1), z + (r + 1) do
|
||||
distance = math.sqrt(math.pow(dist(x, z, i, k), 2) + math.pow(j*(100/d), 2))
|
||||
if distance < r then
|
||||
c:SetCell(i, y - j, k, 1, 0, 1)
|
||||
c:SetCell(i, y + j, k, 1, 0, 1)
|
||||
cellschanged = true
|
||||
heightmap[i][k] = y + j
|
||||
elseif heightmap[i][k] == nil then
|
||||
heightmap[i][k] = getHeight(i, k)
|
||||
end
|
||||
end
|
||||
end
|
||||
if cellschanged == false then
|
||||
break
|
||||
end
|
||||
wait(0)
|
||||
end
|
||||
|
||||
for ri = 0, r do
|
||||
wait(0)
|
||||
|
||||
i = x - ri
|
||||
for k = z - r, z + r do
|
||||
height = heightmap[i][k]
|
||||
if height == nil then
|
||||
height = -1
|
||||
end
|
||||
for h = height, 0, -1 do
|
||||
if not MakeWedge(i, h, k, heightmap) then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
i = x + ri
|
||||
for k = z - r, z + r do
|
||||
height = heightmap[i][k]
|
||||
if height == nil then
|
||||
height = -1
|
||||
end
|
||||
for h = height, 0, -1 do
|
||||
if not MakeWedge(i, h, k, heightmap) then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
function dist(x1, y1, x2, y2)
|
||||
return math.sqrt(math.pow(x2-x1, 2) + math.pow(y2-y1, 2))
|
||||
end
|
||||
|
||||
local debounce = false
|
||||
function onClicked(mouse)
|
||||
if on and not debounce then
|
||||
debounce = true
|
||||
c = game.Workspace.Terrain
|
||||
|
||||
local cellPos = c:WorldToCellPreferEmpty(Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
|
||||
local x = cellPos.x
|
||||
local y = cellPos.y
|
||||
local z = cellPos.z
|
||||
|
||||
makeBall(x, y, z, r, d)
|
||||
print("Orb created at: "..x..", "..y..", "..z)
|
||||
debounce = false
|
||||
end
|
||||
end
|
||||
|
||||
function On()
|
||||
self:Activate(true)
|
||||
toolbarbutton:SetActive(true)
|
||||
frame.Visible = true
|
||||
for w = 0, 0.3, 0.06 do
|
||||
frame.Size = UDim2.new(w, 0, w/2, 0)
|
||||
wait(0)
|
||||
end
|
||||
radl.Text = "Radius: "..r
|
||||
dfl.Text = "Height: "..d.."%"
|
||||
on = true
|
||||
end
|
||||
|
||||
function Off()
|
||||
toolbarbutton:SetActive(false)
|
||||
radl.Text = ""
|
||||
dfl.Text = ""
|
||||
for w = 0.3, 0, -0.06 do
|
||||
frame.Size = UDim2.new(w, 0, w/2, 0)
|
||||
wait(0)
|
||||
end
|
||||
frame.Visible = false
|
||||
on = false
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
------
|
||||
--GUI-
|
||||
------
|
||||
|
||||
--load library for with sliders
|
||||
local RbxGui = LoadLibrary("RbxGui")
|
||||
|
||||
--screengui
|
||||
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
|
||||
--frame
|
||||
frame = Instance.new("Frame", g)
|
||||
frame.Position = UDim2.new(0.35, 0, 0.8, 0)
|
||||
frame.Size = UDim2.new(0.3, 0, 0.15, 0)
|
||||
frame.BackgroundTransparency = 0.5
|
||||
frame.Visible = false
|
||||
|
||||
--current radius display label
|
||||
radl = Instance.new("TextLabel", frame)
|
||||
radl.Position = UDim2.new(0.05, 0, 0.1, 0)
|
||||
radl.Size = UDim2.new(0.2, 0, 0.35, 0)
|
||||
radl.Text = ""
|
||||
radl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
radl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
radl.Font = Enum.Font.ArialBold
|
||||
radl.FontSize = Enum.FontSize.Size14
|
||||
radl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
radl.BackgroundTransparency = 1
|
||||
|
||||
--radius slider
|
||||
radSliderGui, radSliderPosition = RbxGui.CreateSlider(128, 0, UDim2.new(0.3, 0, 0.26, 0))
|
||||
radSliderGui.Parent = frame
|
||||
radBar = radSliderGui:FindFirstChild("Bar")
|
||||
radBar.Size = UDim2.new(0.65, 0, 0, 5)
|
||||
radSliderPosition.Value = r
|
||||
radSliderPosition.Changed:connect(function()
|
||||
r = radSliderPosition.Value
|
||||
radl.Text = "Radius: "..r
|
||||
end)
|
||||
|
||||
--current depth factor display label
|
||||
dfl = Instance.new("TextLabel", frame)
|
||||
dfl.Position = UDim2.new(0.05, 0, 0.55, 0)
|
||||
dfl.Size = UDim2.new(0.2, 0, 0.35, 0)
|
||||
dfl.Text = ""
|
||||
dfl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
dfl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
dfl.Font = Enum.Font.ArialBold
|
||||
dfl.FontSize = Enum.FontSize.Size14
|
||||
dfl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
dfl.BackgroundTransparency = 1
|
||||
|
||||
--depth factor slider
|
||||
dfSliderGui, dfSliderPosition = RbxGui.CreateSlider(100, 0, UDim2.new(0.3, 0, 0.71, 0))
|
||||
dfSliderGui.Parent = frame
|
||||
dfBar = dfSliderGui:FindFirstChild("Bar")
|
||||
dfBar.Size = UDim2.new(0.65, 0, 0, 5)
|
||||
dfSliderPosition.Value = d
|
||||
dfSliderPosition.Changed:connect(function()
|
||||
d = dfSliderPosition.Value
|
||||
dfl.Text = "Height: "..d.."%"
|
||||
end)
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------
|
||||
--SUCCESSFUL LOAD MESSAGE-
|
||||
--------------------------
|
||||
loaded = true
|
||||
print("Orbs Plugin Loaded")
|
||||
@@ -0,0 +1,202 @@
|
||||
-----------------
|
||||
--DEFAULT VALUES-
|
||||
-----------------
|
||||
loaded = false
|
||||
x1 = 200
|
||||
y1 = 200
|
||||
x2 = 300
|
||||
y2 = 300
|
||||
h = 20
|
||||
on = false
|
||||
mode = 0
|
||||
|
||||
|
||||
---------------
|
||||
--PLUGIN SETUP-
|
||||
---------------
|
||||
self = PluginManager():CreatePlugin()
|
||||
mouse = self:GetMouse()
|
||||
mouse.Button1Down:connect(function() onClicked(mouse) end)
|
||||
self.Deactivation:connect(function()
|
||||
Off()
|
||||
end)
|
||||
toolbar = self:CreateToolbar("Terrain")
|
||||
toolbarbutton = toolbar:CreateButton("", "Roads: Click once to set the starting point and again to set the endpoint of the road.", "roads.png")
|
||||
toolbarbutton.Click:connect(function()
|
||||
if on then
|
||||
Off()
|
||||
elseif loaded then
|
||||
On()
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
--FUNCTION DEFINITIONS-
|
||||
-----------------------
|
||||
|
||||
--makes a column of blocks from 0 up to height at location (x,z) in cluster c
|
||||
function coordHeight(x, z, height)
|
||||
c = game.Workspace.Terrain
|
||||
for h = 1, height do
|
||||
c:SetCell(x, h, z, 1, 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
function coordCheck(x, z, height)
|
||||
c = game.Workspace.Terrain
|
||||
for h = height, 0, -1 do
|
||||
material, wedge, rotation = c:GetCell(x, h, z)
|
||||
if material.Value > 0 then
|
||||
return true
|
||||
elseif height == 0 then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function dist(x1, y1, x2, y2)
|
||||
return math.sqrt(math.pow(x2-x1, 2) + math.pow(y2-y1, 2))
|
||||
end
|
||||
|
||||
function dist3d(x1, y1, z1, x2, y2, z2)
|
||||
return math.sqrt(math.pow(dist(x1, y1, x2, y2), 2) + math.pow(z2-z1, 2))
|
||||
end
|
||||
|
||||
--create a path between coordinates (x1,z1) and (x2,z2) at height h in cluster c
|
||||
--a path is a road with height of 3 instead of 1, and it builds a bridge if there is no existing land under it
|
||||
--if you want path to come from x direction, make it start at the place
|
||||
--if you want it to come from z direction, make it end at the place
|
||||
--if p is true, turns on pillars, otherwise pillars are off
|
||||
function makePath(x1, z1, x2, z2, h, p)
|
||||
c = game.Workspace.Terrain
|
||||
if x2 < x1 then
|
||||
incx = -1
|
||||
n = 1
|
||||
else
|
||||
incx = 1
|
||||
n = -1
|
||||
end
|
||||
for x = x1, x2+n, incx do
|
||||
c:SetCell(x, h+1, z1, 0, 0, 0)
|
||||
c:SetCell(x, h+1, z1-1, 0, 0, 0)
|
||||
c:SetCell(x, h+1, z1+1, 0, 0, 0)
|
||||
c:SetCell(x, h+2, z1, 0, 0, 0)
|
||||
c:SetCell(x, h+2, z1-1, 0, 0, 0)
|
||||
c:SetCell(x, h+2, z1+1, 0, 0, 0)
|
||||
c:SetCell(x, h+3, z1, 0, 0, 0)
|
||||
c:SetCell(x, h+3, z1-1, 0, 0, 0)
|
||||
c:SetCell(x, h+3, z1+1, 0, 0, 0)
|
||||
c:SetCell(x, h, z1, 1, 0, 0)
|
||||
c:SetCell(x, h, z1-1, 1, 0, 0)
|
||||
c:SetCell(x, h, z1+1, 1, 0, 0)
|
||||
end
|
||||
if p then
|
||||
for x = x1, x2+n, 16*incx do
|
||||
if coordCheck(x, z1, h-1) then
|
||||
coordHeight(x, z1, h-1)
|
||||
end
|
||||
if coordCheck(x, z1-1, h-1) then
|
||||
coordHeight(x, z1-1, h-1)
|
||||
end
|
||||
if coordCheck(x, z1+1, h-1) then
|
||||
coordHeight(x, z1+1, h-1)
|
||||
end
|
||||
end
|
||||
end
|
||||
if z2 < z1 then
|
||||
incz = -1
|
||||
m = 1
|
||||
n = 2
|
||||
else
|
||||
incz = 1
|
||||
m = -1
|
||||
n = -2
|
||||
end
|
||||
for z = z1+m, z2+n, incz do
|
||||
c:SetCell(x2, h+1, z, 0, 0, 0)
|
||||
c:SetCell(x2-1, h+1, z, 0, 0, 0)
|
||||
c:SetCell(x2+1, h+1, z, 0, 0, 0)
|
||||
c:SetCell(x2, h+2, z, 0, 0, 0)
|
||||
c:SetCell(x2-1, h+2, z, 0, 0, 0)
|
||||
c:SetCell(x2+1, h+2, z, 0, 0, 0)
|
||||
c:SetCell(x2, h+3, z, 0, 0, 0)
|
||||
c:SetCell(x2-1, h+3, z, 0, 0, 0)
|
||||
c:SetCell(x2+1, h+3, z, 0, 0, 0)
|
||||
c:SetCell(x2, h, z, 1, 0, 0)
|
||||
c:SetCell(x2-1, h, z, 1, 0, 0)
|
||||
c:SetCell(x2+1, h, z, 1, 0, 0)
|
||||
end
|
||||
if p then
|
||||
for z = z1+m, z2+n, 16*incz do
|
||||
if coordCheck(x2, z, h-1) then
|
||||
coordHeight(x2, z, h-1)
|
||||
end
|
||||
if coordCheck(x2-1, z, h-1) then
|
||||
coordHeight(x2-1, z, h-1)
|
||||
end
|
||||
if coordCheck(x2+1, z, h-1) then
|
||||
coordHeight(x2+1, z, h-1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function onClicked (mouse)
|
||||
if on then
|
||||
|
||||
c = game.Workspace.Terrain
|
||||
|
||||
local cellPos = c:WorldToCellPreferSolid(Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
|
||||
local x = cellPos.x
|
||||
local y = cellPos.y
|
||||
local z = cellPos.z
|
||||
|
||||
if mode == 0 then
|
||||
x1 = x
|
||||
y1 = z
|
||||
h = y
|
||||
mode = 1
|
||||
elseif mode == 1 then
|
||||
x2 = x
|
||||
y2 = z
|
||||
makePath(x1, y1, x2, y2, h, true, c)
|
||||
mode = 0
|
||||
else
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function On()
|
||||
self:Activate(true)
|
||||
toolbarbutton:SetActive(true)
|
||||
mode = 0
|
||||
on = true
|
||||
end
|
||||
|
||||
function Off()
|
||||
toolbarbutton:SetActive(false)
|
||||
on = false
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
------
|
||||
--GUI-
|
||||
------
|
||||
|
||||
--screengui
|
||||
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------
|
||||
--SUCCESSFUL LOAD MESSAGE-
|
||||
--------------------------
|
||||
loaded = true
|
||||
print("Roads Plugin Loaded")
|
||||
@@ -0,0 +1,204 @@
|
||||
-----------------
|
||||
--DEFAULT VALUES-
|
||||
-----------------
|
||||
loaded = false
|
||||
on = false
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--PLUGIN SETUP-
|
||||
---------------
|
||||
self = PluginManager():CreatePlugin()
|
||||
mouse = self:GetMouse()
|
||||
mouse.Button1Down:connect(function() onClicked(mouse) end)
|
||||
self.Deactivation:connect(function()
|
||||
Off()
|
||||
end)
|
||||
toolbar = self:CreateToolbar("Terrain")
|
||||
toolbarbutton = toolbar:CreateButton("", "Tree", "trees.png")
|
||||
toolbarbutton.Click:connect(function()
|
||||
if on then
|
||||
Off()
|
||||
elseif loaded then
|
||||
On()
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
--FUNCTION DEFINITIONS-
|
||||
-----------------------
|
||||
|
||||
local Base = Instance.new("Part")
|
||||
Base.Name = "Trunk"
|
||||
Base.formFactor = "Custom"
|
||||
Base.TopSurface = 0
|
||||
Base.BottomSurface = 0
|
||||
Base.Anchored = false
|
||||
Base.BrickColor = BrickColor.new("Reddish brown")
|
||||
local Leaves = Base:Clone()
|
||||
Leaves.Name = "Leaves"
|
||||
Leaves.CanCollide = false
|
||||
Leaves.BrickColor = BrickColor.new("Dark green")
|
||||
local leafmesh = Instance.new("SpecialMesh")
|
||||
leafmesh.MeshType = "FileMesh"
|
||||
leafmesh.MeshId = "http://www.watrbx.wtf/asset/?id=1290033"
|
||||
leafmesh.TextureId = "http://www.watrbx.wtf/asset/?id=2861779"
|
||||
leafmesh.Parent = Leaves
|
||||
Instance.new("CylinderMesh",Base)
|
||||
|
||||
|
||||
-- get dot product of yz angles
|
||||
function dot(c1,c2)
|
||||
local m = CFrame.Angles(math.pi/2,0,0)
|
||||
return (c1*m).lookVector:Dot((c2*m).lookVector)
|
||||
end
|
||||
|
||||
-- multiplier for various sizes of foliage
|
||||
local leaf_mult = {
|
||||
Vector3.new(1.5,1.5,1.2);
|
||||
Vector3.new(1.5,1,1.5);
|
||||
Vector3.new(1.2,1.5,1.5);
|
||||
Vector3.new(1.5,1.5,1.5);
|
||||
}
|
||||
|
||||
function Welder(p0, p1)
|
||||
local w = Instance.new("Weld")
|
||||
w.Part0 = p0
|
||||
w.Part1 = p1
|
||||
local CJ = CFrame.new(p0.Position)
|
||||
w.C0 = p0.CFrame:inverse() * CJ
|
||||
w.C1 = p1.CFrame:inverse() * CJ
|
||||
w.Parent = p0
|
||||
end
|
||||
|
||||
function Branch(base,c)
|
||||
if c <= 0 then
|
||||
-- if the complexity has run out, generate some foliage
|
||||
local leaves = Leaves:Clone()
|
||||
local vol = base.Size.x+base.Size.y+base.Size.z -- determine size based on branch size
|
||||
leaves.Mesh.Scale = leaf_mult[math.random(1,#leaf_mult)]*math.random(vol/3*10,vol/3*12)/10
|
||||
leaves.Size = leaves.Mesh.Scale*0.75
|
||||
leaves.CFrame = base.CFrame * CFrame.new(0,base.Size.y/2,0) -- center foliage at top of branch
|
||||
leaves.Parent = base.Parent
|
||||
Welder(leaves, base)
|
||||
else
|
||||
-- otherwise, make some more branches
|
||||
local pos = base.CFrame*CFrame.new(0,base.Size/2,0)
|
||||
local height = base.Size.y
|
||||
local width = base.Size.x
|
||||
local nb = math.random(2,2) -- # of possible branches (2 seems to work fine for now)
|
||||
local r = math.random(45,135) -- rotation of branches on y axis
|
||||
|
||||
-- branch split angle difference
|
||||
-- the less complexity, the greater the possible angle
|
||||
-- minimum: 20-75; maximum: 40-80
|
||||
local da = math.random(20+55/c,40+40/c)
|
||||
|
||||
-- branch angle (overall angle of all branches)
|
||||
local ba = math.random(-da/3,da/3)
|
||||
|
||||
-- ba+da/2 shouldn't be near or greater than 90 degrees
|
||||
|
||||
for i=0,nb-1 do -- for each branch
|
||||
local branch = base:Clone()
|
||||
branch.Name = "Branch"
|
||||
local h = height*math.random(95,115)/100 -- height .95 to 1.15 of original
|
||||
|
||||
-- make new cframe
|
||||
-- move new to top of base, then apply branch angle (ba)
|
||||
local new = branch.CFrame * CFrame.new(0,height/2,0) * CFrame.Angles(0,0,math.rad(ba))
|
||||
-- next, rotate branch so that it faces away from others, also apply overall rotation (r)
|
||||
-- also, apply the split angle (da)
|
||||
-- finally, move branch upward by half it's size
|
||||
new = new * CFrame.Angles(0,i*(math.pi*2/nb)+r,math.rad(da/2)) * CFrame.new(0,h/2,0)
|
||||
|
||||
-- determine width by branch's final angle; greater the angle, smaller the width
|
||||
-- also shave off a bit of width for more dramatic change in size
|
||||
-- a frustum cone mesh would really help here
|
||||
local w = dot(new,branch.CFrame)*width*0.9
|
||||
|
||||
branch.Size = Vector3.new(w,h,w)
|
||||
branch.CFrame = new
|
||||
branch.Parent = base.Parent
|
||||
Welder(branch, base)
|
||||
|
||||
-- create the next set of branches with one less complexity
|
||||
Branch(branch,c-1)
|
||||
end
|
||||
end
|
||||
--wait() -- remove to generate faster
|
||||
end
|
||||
|
||||
-- Main Function ----------------
|
||||
function GenerateTree(location,complexity,width,height)
|
||||
--[[
|
||||
location: position tree will "sprout" out of
|
||||
complexity: # of times to branch out
|
||||
determines overall size and quality of tree
|
||||
produces between m^c+(m^(c+1)-1)/(m-1) parts,
|
||||
where c is complexity,
|
||||
and m is either the min or max # of possible branches
|
||||
(currently, both min and max are 2)
|
||||
width: initial x/z size of tree base
|
||||
determines overall thickness of tree
|
||||
height: initial y size of tree base
|
||||
contributes to sparseness of tree
|
||||
]]
|
||||
print("TreeGen - complexity: " .. complexity .. ", width: " .. width .. ", height: " .. height)
|
||||
local tree = Instance.new("Model")
|
||||
tree.Name = "Tree"
|
||||
tree.Parent = workspace
|
||||
local base = Base:Clone()
|
||||
base.Parent = tree
|
||||
base.Size = Vector3.new(width,height,width)
|
||||
-- move up by half its height, and rotate randomly
|
||||
base.CFrame = CFrame.new(location) * CFrame.new(0,height/2,0) * CFrame.Angles(0,math.rad(math.random(1,360)),0)
|
||||
leafmesh.VertexColor = Vector3.new((math.random() * .1) + .9, (math.random() * .4) + .6, 1)
|
||||
-- start branching
|
||||
Branch(base,complexity)
|
||||
return base
|
||||
end
|
||||
|
||||
|
||||
function onClicked(mouse)
|
||||
if on then
|
||||
local targetPart = mouse.Target
|
||||
local newTrunk = GenerateTree(mouse.Hit.p, math.random(3,6), math.random(2,4), math.random(5,10))
|
||||
|
||||
if targetPart and targetPart:IsA("Terrain") then Welder(newTrunk, targetPart) end -- make trees stick to terrain
|
||||
end
|
||||
end
|
||||
|
||||
function On()
|
||||
self:Activate(true)
|
||||
toolbarbutton:SetActive(true)
|
||||
on = true
|
||||
end
|
||||
|
||||
function Off()
|
||||
toolbarbutton:SetActive(false)
|
||||
on = false
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
------
|
||||
--GUI-
|
||||
------
|
||||
|
||||
--screengui
|
||||
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------
|
||||
--SUCCESSFUL LOAD MESSAGE-
|
||||
--------------------------
|
||||
loaded = true
|
||||
print("Tree Plugin Loaded")
|
||||
@@ -0,0 +1,836 @@
|
||||
-- Local function definitions
|
||||
local c = game.Workspace.Terrain
|
||||
local SetCell = c.SetCell
|
||||
local GetCell = c.GetCell
|
||||
local WorldToCellPreferSolid = c.WorldToCellPreferSolid
|
||||
local CellCornerToWorld = c.CellCornerToWorld
|
||||
local WorldToCell = c.WorldToCell
|
||||
local AutoWedge = c.AutowedgeCells
|
||||
|
||||
-----------------
|
||||
--DEFAULT VALUES-
|
||||
-----------------
|
||||
loaded = false
|
||||
on = false
|
||||
materialNames = {"Empty", "Grass", "Sand", "Granite", "Brick"}
|
||||
local currentMaterial = 1
|
||||
|
||||
local debounce = false
|
||||
local startCell = nil
|
||||
local endCell = nil
|
||||
local regionSelected = false
|
||||
local dragging = false
|
||||
local cloning = false
|
||||
local cloneHitCell = nil
|
||||
local boxSize = Vector3.new(0, 0, 0)
|
||||
|
||||
-- for region resizing
|
||||
local handles = Instance.new("Handles")
|
||||
local handlesWereDragged = false
|
||||
local dragStartX = 0
|
||||
local dragStartY = 0
|
||||
local dragStartZ = 0
|
||||
local dragEndX = 0
|
||||
local dragEndY = 0
|
||||
local dragEndZ = 0
|
||||
|
||||
|
||||
|
||||
local selectionBox = Instance.new("Part")
|
||||
selectionBox.Anchored = true
|
||||
selectionBox.CanCollide = false
|
||||
selectionBox.formFactor = "Custom"
|
||||
selectionBox.BottomSurface = "Smooth"
|
||||
selectionBox.TopSurface = "Smooth"
|
||||
selectionBox.BrickColor = BrickColor.new("Bright blue")
|
||||
selectionBox.Transparency = .7
|
||||
|
||||
local selectionLasso = Instance.new("SelectionBox")
|
||||
selectionLasso.Adornee = selectionBox
|
||||
|
||||
local cloneBox = Instance.new("Part")
|
||||
cloneBox.Anchored = true
|
||||
cloneBox.CanCollide = false
|
||||
cloneBox.formFactor = "Custom"
|
||||
cloneBox.BottomSurface = "Smooth"
|
||||
cloneBox.TopSurface = "Smooth"
|
||||
cloneBox.BrickColor = BrickColor.new("Deep orange")
|
||||
cloneBox.Transparency = .5
|
||||
|
||||
local cloneLasso = Instance.new("SelectionBox")
|
||||
cloneLasso.Color = BrickColor.new("Deep orange")
|
||||
cloneLasso.Adornee = cloneBox
|
||||
|
||||
|
||||
---------------
|
||||
--PLUGIN SETUP-
|
||||
---------------
|
||||
self = PluginManager():CreatePlugin()
|
||||
mouse = self:GetMouse()
|
||||
mouse.Button1Down:connect(function() mouseDown(mouse) end)
|
||||
mouse.Button1Up:connect(function() mouseUp(mouse) end)
|
||||
mouse.Move:connect(function() mouseMove(mouse) end)
|
||||
|
||||
self.Deactivation:connect(function()
|
||||
Off()
|
||||
end)
|
||||
toolbar = self:CreateToolbar("Terrain")
|
||||
toolbarbutton = toolbar:CreateButton("", "RegionEdit", "")
|
||||
toolbarbutton.Click:connect(function()
|
||||
if on then
|
||||
Off()
|
||||
elseif loaded then
|
||||
On()
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
--FUNCTION DEFINITIONS-
|
||||
-----------------------
|
||||
|
||||
function putCloneDown()
|
||||
startX = math.min(startCell.x, endCell.x)
|
||||
startY = math.min(startCell.y, endCell.y)
|
||||
startZ = math.min(startCell.z, endCell.z)
|
||||
|
||||
endX = math.max(startCell.x, endCell.x)
|
||||
endY = math.max(startCell.y, endCell.y)
|
||||
endZ = math.max(startCell.z, endCell.Z)
|
||||
|
||||
centerX = math.floor((startX + endX)/2)
|
||||
centerY = math.floor((startY + endY)/2)
|
||||
centerZ = math.floor((startZ + endZ)/2)
|
||||
|
||||
xOffset = cloneHitCell.x - centerX
|
||||
yOffset = cloneHitCell.y - centerY
|
||||
zOffset = cloneHitCell.z - centerZ
|
||||
|
||||
xStep = 1
|
||||
yStep = 1
|
||||
zStep = 1
|
||||
|
||||
if xOffset > 0 then
|
||||
-- go backwards on x axis
|
||||
tempVal = startX
|
||||
startX = endX
|
||||
endX = tempVal
|
||||
|
||||
xStep = -1
|
||||
end
|
||||
if yOffset > 0 then
|
||||
-- go backwards on y axis
|
||||
tempVal = startY
|
||||
startY = endY
|
||||
endY = tempVal
|
||||
|
||||
yStep = -1
|
||||
end
|
||||
if zOffset > 0 then
|
||||
-- go backwards on z axis
|
||||
tempVal = startZ
|
||||
startZ = endZ
|
||||
endZ = tempVal
|
||||
|
||||
zStep = -1
|
||||
end
|
||||
|
||||
local count = 0
|
||||
for x = startX, endX, xStep do
|
||||
for y = startY, endY, yStep do
|
||||
for z = startZ, endZ, zStep do
|
||||
local mat, typ, orient = GetCell(c, x, y, z)
|
||||
SetCell(c, x+xOffset, y+yOffset, z+zOffset, mat, typ, orient)
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
if count > 10000 then count = 0 wait() end
|
||||
end
|
||||
|
||||
-- switch the selected region to the new one :)
|
||||
startCell = Vector3.new(startX+xOffset, startY+yOffset, startZ+zOffset)
|
||||
endCell = Vector3.new(endX+xOffset, endY+yOffset, endZ+zOffset)
|
||||
|
||||
-- make the clone button look deselected now, if it's not
|
||||
if clone then
|
||||
clone.BorderColor3 = Color3.new(0, 0, 0)
|
||||
clone.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
clone.BackgroundTransparency = 0.5
|
||||
end
|
||||
end
|
||||
|
||||
function dragRegion(face, dist)
|
||||
startX = math.min(startCell.x, endCell.x)
|
||||
startY = math.min(startCell.y, endCell.y)
|
||||
startZ = math.min(startCell.z, endCell.z)
|
||||
|
||||
endX = math.max(startCell.x, endCell.x)
|
||||
endY = math.max(startCell.y, endCell.y)
|
||||
endZ = math.max(startCell.z, endCell.Z)
|
||||
|
||||
if face == Enum.NormalId.Front then
|
||||
dragStartZ = -math.floor(dist)
|
||||
elseif face == Enum.NormalId.Back then
|
||||
dragEndZ = math.floor(dist)
|
||||
elseif face == Enum.NormalId.Bottom then
|
||||
dragStartY = -math.floor(dist)
|
||||
elseif face == Enum.NormalId.Top then
|
||||
dragEndY = math.floor(dist)
|
||||
elseif face == Enum.NormalId.Left then
|
||||
dragStartX = -math.floor(dist)
|
||||
elseif face == Enum.NormalId.Right then
|
||||
dragEndX = math.floor(dist)
|
||||
else return end
|
||||
|
||||
-- update the box display
|
||||
local newStartX = math.min(startCell.x + dragStartX, endCell.x + dragEndX)
|
||||
local newStartY = math.min(startCell.y + dragStartY, endCell.y + dragEndY)
|
||||
local newStartZ = math.min(startCell.z + dragStartZ, endCell.z + dragEndZ)
|
||||
local newEndX = math.max(startCell.x + dragStartX, endCell.x + dragEndX)
|
||||
local newEndY = math.max(startCell.y + dragStartY, endCell.y + dragEndY)
|
||||
local newEndZ = math.max(startCell.z + dragStartZ, endCell.z + dragEndZ)
|
||||
|
||||
local boxStart = CellCornerToWorld(c, newStartX, newStartY, newStartZ)
|
||||
local boxEnd = CellCornerToWorld(c, newEndX + 1, newEndY + 1, newEndZ + 1)
|
||||
boxSize = boxEnd - boxStart
|
||||
local boxCenter = (boxEnd + boxStart)/2
|
||||
|
||||
selectionBox.Size = boxSize
|
||||
selectionBox.CFrame = CFrame.new(boxCenter)
|
||||
|
||||
handlesWereDragged = true
|
||||
end
|
||||
|
||||
|
||||
function mouseDown(mouse)
|
||||
if on and not debounce and mouse.Target then
|
||||
startCell = nil
|
||||
endCell = nil
|
||||
regionSelected = false
|
||||
handles.Visible = false
|
||||
selectionBox.Parent = nil
|
||||
selectionLasso.Visible = false
|
||||
|
||||
local tempCell = WorldToCellPreferSolid(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
|
||||
if GetCell(c, tempCell.x, tempCell.y, tempCell.z).Value == 0 then return end
|
||||
|
||||
dragging = true
|
||||
|
||||
startCell = tempCell
|
||||
elseif on and cloning and cloneHitCell and regionSelected then
|
||||
regionSelected = false
|
||||
handles.Visible = false
|
||||
print("Cloning")
|
||||
putCloneDown()
|
||||
|
||||
-- update selection box to new coords
|
||||
startX = math.min(startCell.x, endCell.x)
|
||||
startY = math.min(startCell.y, endCell.y)
|
||||
startZ = math.min(startCell.z, endCell.z)
|
||||
endX = math.max(startCell.x, endCell.x)
|
||||
endY = math.max(startCell.y, endCell.y)
|
||||
endZ = math.max(startCell.z, endCell.Z)
|
||||
local boxStart = CellCornerToWorld(c, startX, startY, startZ)
|
||||
local boxEnd = CellCornerToWorld(c, endX + 1, endY + 1, endZ + 1)
|
||||
boxSize = boxEnd - boxStart
|
||||
local boxCenter = (boxEnd + boxStart)/2
|
||||
selectionBox.Size = boxSize
|
||||
selectionBox.CFrame = CFrame.new(boxCenter)
|
||||
|
||||
--startCell = nil
|
||||
--endCell = nil
|
||||
--selectionLasso.Visible = false
|
||||
handles.Visible = true
|
||||
regionSelected = true
|
||||
cloneLasso.Visible = false
|
||||
cloning = false
|
||||
debounce = false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function mouseUp(mouse)
|
||||
dragging = false
|
||||
if not startCell or not endCell then return end
|
||||
if cloning then return end
|
||||
regionSelected = true
|
||||
print("Region Selected: "..startCell.x..", "..startCell.y..", "..startCell.z.." to "..endCell.x..", "..endCell.y..", "..endCell.z)
|
||||
|
||||
-- enforce ordering on startCell and endCell
|
||||
startX = math.min(startCell.x, endCell.x)
|
||||
startY = math.min(startCell.y, endCell.y)
|
||||
startZ = math.min(startCell.z, endCell.z)
|
||||
|
||||
endX = math.max(startCell.x, endCell.x)
|
||||
endY = math.max(startCell.y, endCell.y)
|
||||
endZ = math.max(startCell.z, endCell.Z)
|
||||
|
||||
startCell = Vector3.new(startX, startY, startZ)
|
||||
endCell = Vector3.new(endX, endY, endZ)
|
||||
|
||||
-- handle handle [lulz]
|
||||
handles.Visible = true
|
||||
|
||||
if handlesWereDragged then
|
||||
newStartX = math.min(startCell.x + dragStartX, endCell.x + dragEndX)
|
||||
newStartY = math.min(startCell.y + dragStartY, endCell.y + dragEndY)
|
||||
newStartZ = math.min(startCell.z + dragStartZ, endCell.z + dragEndZ)
|
||||
newEndX = math.max(startCell.x + dragStartX, endCell.x + dragEndX)
|
||||
newEndY = math.max(startCell.y + dragStartY, endCell.y + dragEndY)
|
||||
newEndZ = math.max(startCell.z + dragStartZ, endCell.z + dragEndZ)
|
||||
startCell = Vector3.new(newStartX, newStartY, newStartZ)
|
||||
endCell = Vector3.new(newEndX, newEndY, newEndZ)
|
||||
handlesWereDragged = false
|
||||
end
|
||||
|
||||
dragStartX = 0
|
||||
dragStartY = 0
|
||||
dragStartZ = 0
|
||||
dragEndX = 0
|
||||
dragEndY = 0
|
||||
dragEndZ = 0
|
||||
end
|
||||
|
||||
|
||||
function mouseMove(mouse)
|
||||
if on and cloning and regionSelected then
|
||||
cloneHitCell = WorldToCell(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
|
||||
|
||||
startX = math.min(startCell.x, endCell.x)
|
||||
startY = math.min(startCell.y, endCell.y)
|
||||
startZ = math.min(startCell.z, endCell.z)
|
||||
|
||||
endX = math.max(startCell.x, endCell.x)
|
||||
endY = math.max(startCell.y, endCell.y)
|
||||
endZ = math.max(startCell.z, endCell.Z)
|
||||
|
||||
centerX = math.floor((startX + endX)/2)
|
||||
centerY = math.floor((startY + endY)/2)
|
||||
centerZ = math.floor((startZ + endZ)/2)
|
||||
|
||||
xOffset = cloneHitCell.x - centerX
|
||||
yOffset = cloneHitCell.y - centerY
|
||||
zOffset = cloneHitCell.z - centerZ
|
||||
|
||||
cloneBox.CFrame = selectionBox.CFrame + 4 * Vector3.new(xOffset, yOffset, zOffset) -- since cells are 4x4x4
|
||||
cloneLasso.Visible = true
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
if not startCell or not dragging or debounce then return end
|
||||
|
||||
endCell = WorldToCellPreferSolid(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
|
||||
startX = math.min(startCell.x, endCell.x)
|
||||
startY = math.min(startCell.y, endCell.y)
|
||||
startZ = math.min(startCell.z, endCell.z)
|
||||
|
||||
endX = math.max(startCell.x, endCell.x)
|
||||
endY = math.max(startCell.y, endCell.y)
|
||||
endZ = math.max(startCell.z, endCell.Z)
|
||||
|
||||
local boxStart = CellCornerToWorld(c, startX, startY, startZ)
|
||||
local boxEnd = CellCornerToWorld(c, endX + 1, endY + 1, endZ + 1)
|
||||
boxSize = boxEnd - boxStart
|
||||
local boxCenter = (boxEnd + boxStart)/2
|
||||
|
||||
selectionBox.Size = boxSize
|
||||
selectionBox.CFrame = CFrame.new(boxCenter)
|
||||
--selectionBox.Parent = game.Workspace
|
||||
selectionLasso.Visible = true
|
||||
end
|
||||
|
||||
function onFill(newMaterial)
|
||||
if debounce then
|
||||
print("Cannot perform that operation until the previous one is complete.")
|
||||
return
|
||||
elseif not regionSelected then
|
||||
print("Please select a region first.")
|
||||
return
|
||||
else
|
||||
debounce = true
|
||||
print("Filling region.")
|
||||
startX = math.min(startCell.x, endCell.x)
|
||||
startY = math.min(startCell.y, endCell.y)
|
||||
startZ = math.min(startCell.z, endCell.z)
|
||||
|
||||
endX = math.max(startCell.x, endCell.x)
|
||||
endY = math.max(startCell.y, endCell.y)
|
||||
endZ = math.max(startCell.z, endCell.Z)
|
||||
|
||||
--c:SetCells(Region3int16.new(Vector3int16.new(startX, startY, startZ), Vector3int16.new(endX-startX, endY-startY, endZ-startZ)), newMaterial, 0, 0)
|
||||
local count = 0
|
||||
for x = startX, endX do
|
||||
for y = startY, endY do
|
||||
for z = startZ, endZ do
|
||||
SetCell(c, x, y, z, newMaterial, 0, 0)
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
if count > 10000 then count = 0 wait() end
|
||||
end
|
||||
|
||||
debounce = false
|
||||
end
|
||||
end
|
||||
|
||||
function onMaterialChange(newMaterial)
|
||||
if debounce then
|
||||
print("Cannot perform that operation until the previous one is complete.")
|
||||
return
|
||||
elseif not regionSelected then
|
||||
print("Please select a region first.")
|
||||
return
|
||||
elseif newMaterial == 0 then
|
||||
print("Cannot change material to Empty. Use Fill button to erase a region.")
|
||||
return
|
||||
else
|
||||
debounce = true
|
||||
print("Changing material of region.")
|
||||
startX = math.min(startCell.x, endCell.x)
|
||||
startY = math.min(startCell.y, endCell.y)
|
||||
startZ = math.min(startCell.z, endCell.z)
|
||||
|
||||
endX = math.max(startCell.x, endCell.x)
|
||||
endY = math.max(startCell.y, endCell.y)
|
||||
endZ = math.max(startCell.z, endCell.Z)
|
||||
|
||||
local count = 0
|
||||
for x = startX, endX do
|
||||
for y = startY, endY do
|
||||
for z = startZ, endZ do
|
||||
local mat, typ, orient = GetCell(c, x, y, z)
|
||||
if mat.Value > 0 then SetCell(c, x, y, z, newMaterial, typ, orient) end
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
if count > 10000 then count = 0 wait() end
|
||||
end
|
||||
|
||||
debounce = false
|
||||
end
|
||||
end
|
||||
|
||||
function onRotate()
|
||||
if debounce then
|
||||
print("Cannot perform that operation until the previous one is complete.")
|
||||
return
|
||||
elseif not regionSelected then
|
||||
print("Please select a region first.")
|
||||
return
|
||||
else
|
||||
debounce = true
|
||||
print("Rotating region.")
|
||||
startX = math.min(startCell.x, endCell.x)
|
||||
startY = math.min(startCell.y, endCell.y)
|
||||
startZ = math.min(startCell.z, endCell.z)
|
||||
|
||||
endX = math.max(startCell.x, endCell.x)
|
||||
endY = math.max(startCell.y, endCell.y)
|
||||
endZ = math.max(startCell.z, endCell.Z)
|
||||
|
||||
local xCenter = (startX+endX)/2
|
||||
local zCenter = (startZ+endZ)/2
|
||||
local xSize = (endX - startX)
|
||||
local zSize = (endZ - startZ)
|
||||
local xHalfSize = math.floor(xSize / 2)
|
||||
local zHalfSize = math.floor(zSize / 2)
|
||||
local newXCenter = math.floor(xCenter) - zHalfSize + zSize/2
|
||||
local newZCenter = math.floor(zCenter) - xHalfSize + xSize/2
|
||||
|
||||
for y = startY, endY do
|
||||
-- extract the y-slice
|
||||
|
||||
local cellTable = {}
|
||||
|
||||
|
||||
for x = startX, endX do
|
||||
xIndex = x - xCenter
|
||||
if (startX+endX)%2 == 1 then
|
||||
if xIndex > 0 then xIndex = math.ceil(xIndex)
|
||||
else xIndex = math.floor(xIndex) end
|
||||
end
|
||||
|
||||
cellTable[xIndex] = {}
|
||||
for z = startZ, endZ do
|
||||
local mat, typ, orient = GetCell(c, x, y, z)
|
||||
zIndex = z - zCenter
|
||||
if (startZ+endZ)%2 == 1 then
|
||||
if zIndex > 0 then zIndex = math.ceil(zIndex)
|
||||
else zIndex = math.floor(zIndex) end
|
||||
end
|
||||
|
||||
-- store in our table
|
||||
cellTable[xIndex][zIndex] = Vector3.new(mat.Value, typ.Value, orient.Value)
|
||||
|
||||
-- and clear the y-slice, so we don't get duplication errors
|
||||
SetCell(c, x, y, z, 0, 0, 0)
|
||||
end
|
||||
end
|
||||
wait()
|
||||
|
||||
-- put it back, rotated into the y-slice
|
||||
for x = math.floor(xCenter) - zHalfSize, math.floor(xCenter) - zHalfSize + zSize do
|
||||
for z = math.floor(zCenter) - xHalfSize, math.floor(zCenter) - xHalfSize + xSize do
|
||||
xIndex = x - newXCenter
|
||||
zIndex = z - newZCenter
|
||||
if zSize%2 == 1 then
|
||||
if xIndex > 0 then xIndex = math.ceil(xIndex)
|
||||
else xIndex = math.floor(xIndex) end
|
||||
end
|
||||
if xSize%2 == 1 then
|
||||
if zIndex > 0 then zIndex = math.ceil(zIndex)
|
||||
else zIndex = math.floor(zIndex) end
|
||||
end
|
||||
SetCell(c, x, y, z, cellTable[zIndex][-xIndex].x, cellTable[zIndex][-xIndex].y, (cellTable[zIndex][-xIndex].z + 3)%4)
|
||||
end
|
||||
end
|
||||
wait()
|
||||
end
|
||||
|
||||
-- update selection to follow rotation
|
||||
startCell = Vector3.new(math.floor(xCenter) - zHalfSize, startY, math.floor(zCenter) - xHalfSize)
|
||||
endCell = Vector3.new(math.floor(xCenter) - zHalfSize + zSize, endY, math.floor(zCenter) - xHalfSize + xSize)
|
||||
|
||||
local boxStart = CellCornerToWorld(c, startCell.X, startCell.Y, startCell.Z)
|
||||
local boxEnd = CellCornerToWorld(c, endCell.X + 1, endCell.Y + 1, endCell.Z + 1)
|
||||
boxSize = boxEnd - boxStart
|
||||
local boxCenter = (boxEnd + boxStart)/2
|
||||
|
||||
selectionBox.Size = boxSize
|
||||
selectionBox.CFrame = CFrame.new(boxCenter)
|
||||
selectionLasso.Visible = true
|
||||
debounce = false
|
||||
end
|
||||
end
|
||||
|
||||
function onAutoWedge()
|
||||
if debounce then
|
||||
print("Cannot perform that operation until the previous one is complete.")
|
||||
return
|
||||
elseif not regionSelected then
|
||||
print("Please select a region first.")
|
||||
return
|
||||
elseif newMaterial == 0 then
|
||||
print("Cannot change material to Empty. Use Fill button to erase a region.")
|
||||
return
|
||||
else
|
||||
debounce = true
|
||||
print("Smoothing region.")
|
||||
startX = math.min(startCell.x, endCell.x)
|
||||
startY = math.min(startCell.y, endCell.y)
|
||||
startZ = math.min(startCell.z, endCell.z)
|
||||
|
||||
endX = math.max(startCell.x, endCell.x)
|
||||
endY = math.max(startCell.y, endCell.y)
|
||||
endZ = math.max(startCell.z, endCell.Z)
|
||||
|
||||
local count = 0
|
||||
local numCellsInLayer = (endY - startY)*(endX - startX)
|
||||
for z = startZ, endZ do
|
||||
AutoWedge(c, Region3int16.new(Vector3int16.new(startX, startY, z), Vector3int16.new(endX, endY, z)))
|
||||
if count > 10000 then count = 0 wait() else count = count + numCellsInLayer end
|
||||
end
|
||||
|
||||
debounce = false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function onClone()
|
||||
if debounce then
|
||||
print("Cannot perform that operation until the previous one is complete.")
|
||||
return
|
||||
elseif not regionSelected then
|
||||
print("Please select a region first.")
|
||||
return
|
||||
else
|
||||
debounce = true
|
||||
cloneHitCell = nil
|
||||
cloning = true
|
||||
cloneBox.Size = boxSize
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function On()
|
||||
self:Activate(true)
|
||||
toolbarbutton:SetActive(true)
|
||||
|
||||
frame.Visible = true
|
||||
for w = 0, 0.2, 0.1 do
|
||||
frame.Size = UDim2.new(w, 0, w, 0)
|
||||
wait(0.0000001)
|
||||
end
|
||||
title.Text = "Region Editing"
|
||||
--freql.Text = materialString
|
||||
fill.Text = "Fill"
|
||||
matChange.Text = "Set Material"
|
||||
clone.Text = "Clone"
|
||||
autoWedge.Text = "Smooth"
|
||||
rotate.Text = "Rotate"
|
||||
|
||||
on = true
|
||||
end
|
||||
|
||||
function Off()
|
||||
selectionLasso.Visible = false
|
||||
cloneLasso.Visible = false
|
||||
startCell = nil
|
||||
endCell = nil
|
||||
regionSelected = false
|
||||
handles.Visible = false
|
||||
selectionBox.Parent = nil
|
||||
|
||||
-- reset variables
|
||||
currentMaterial = 1
|
||||
startCell = nil
|
||||
endCell = nil
|
||||
regionSelected = false
|
||||
dragging = false
|
||||
cloning = false
|
||||
cloneHitCell = nil
|
||||
boxSize = Vector3.new(0, 0, 0)
|
||||
debounce = false
|
||||
|
||||
-- for region resizing
|
||||
handlesWereDragged = false
|
||||
dragStartX = 0
|
||||
dragStartY = 0
|
||||
dragStartZ = 0
|
||||
dragEndX = 0
|
||||
dragEndY = 0
|
||||
dragEndZ = 0
|
||||
|
||||
toolbarbutton:SetActive(false)
|
||||
|
||||
title.Text = ""
|
||||
fill.Text = ""
|
||||
clone.Text = ""
|
||||
rotate.Text = ""
|
||||
matChange.Text = ""
|
||||
autoWedge.Text = ""
|
||||
for w = 0.2, 0, -0.1 do
|
||||
frame.Size = UDim2.new(w, 0, w, 0)
|
||||
wait(0.0000001)
|
||||
end
|
||||
frame.Visible = false
|
||||
on = false
|
||||
end
|
||||
|
||||
|
||||
function updateMaterialChoice(choice)
|
||||
if choice == "Grass" then
|
||||
currentMaterial = 1
|
||||
elseif choice == "Sand" then
|
||||
currentMaterial = 2
|
||||
elseif choice == "Empty" then
|
||||
currentMaterial = 0
|
||||
elseif choice == "Brick" then
|
||||
currentMaterial = 3
|
||||
elseif choice == "Granite" then
|
||||
currentMaterial = 4
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
------
|
||||
--GUI-
|
||||
------
|
||||
|
||||
--screengui
|
||||
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
selectionLasso.Visible = false
|
||||
selectionLasso.Parent = g
|
||||
cloneLasso.Visible = false
|
||||
cloneLasso.Parent = g
|
||||
handles.Visible = false
|
||||
handles.Adornee = selectionBox
|
||||
handles.Parent = g
|
||||
handles.MouseDrag:connect(dragRegion)
|
||||
|
||||
|
||||
--load library for with sliders
|
||||
local RbxGui = LoadLibrary("RbxGui")
|
||||
|
||||
--screengui
|
||||
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
|
||||
--frame
|
||||
frame = Instance.new("Frame", g)
|
||||
frame.Size = UDim2.new(0.2, 0, 0.2, 0)
|
||||
frame.Position = UDim2.new(0, 0, 0, 0)
|
||||
frame.BackgroundTransparency = 0.5
|
||||
frame.Visible = false
|
||||
|
||||
--title
|
||||
title = Instance.new("TextLabel", frame)
|
||||
title.Position = UDim2.new(0.4, 0, 0.05, 0)
|
||||
title.Size = UDim2.new(0.2, 0, 0.05, 0)
|
||||
title.Text = ""
|
||||
title.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
title.TextColor3 = Color3.new(1, 1, 1)
|
||||
title.Font = Enum.Font.ArialBold
|
||||
title.FontSize = Enum.FontSize.Size24
|
||||
title.BorderColor3 = Color3.new(0, 0, 0)
|
||||
title.BackgroundTransparency = 1
|
||||
|
||||
--[[current frequency display label
|
||||
freql = Instance.new("TextLabel", frame)
|
||||
freql.Position = UDim2.new(0.15, 0, 0.4, 0)
|
||||
freql.Size = UDim2.new(0.1, 0, 0.05, 0)
|
||||
freql.Text = ""
|
||||
freql.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
freql.TextColor3 = Color3.new(1, 1, 1)
|
||||
freql.Font = Enum.Font.ArialBold
|
||||
freql.FontSize = Enum.FontSize.Size14
|
||||
freql.BorderColor3 = Color3.new(0, 0, 0)
|
||||
freql.BackgroundTransparency = 1
|
||||
|
||||
--frequency slider
|
||||
freqSliderGui, freqSliderPosition = RbxGui.CreateSlider(3, 0, UDim2.new(0.2, 0, 0.72, 0))
|
||||
freqSliderGui.Parent = frame
|
||||
freqbar = freqSliderGui:FindFirstChild("Bar")
|
||||
freqbar.Size = UDim2.new(0.75, 0, 0, 5)
|
||||
freqSliderPosition.Value = 2
|
||||
freqSliderPosition.Changed:connect(function()
|
||||
f = freqSliderPosition.Value
|
||||
if (f == 1) then materialString = "Material: Empty"
|
||||
elseif (f == 2) then materialString = "Material: Grass"
|
||||
elseif (f == 3) then materialString = "Material: Sand"
|
||||
else materialString = "Material: Undefined" end
|
||||
freql.Text = materialString
|
||||
end)]]--
|
||||
|
||||
local materialSelect, externalMaterialSelectFunction = RbxGui.CreateDropDownMenu(materialNames, updateMaterialChoice)
|
||||
materialSelect.Name = "MaterialSelect"
|
||||
materialSelect.Position = UDim2.new(.05, 0, .2, 0)
|
||||
materialSelect.Size = UDim2.new(.6, 0, .3, 0)
|
||||
materialSelect.Parent = frame
|
||||
|
||||
|
||||
|
||||
--fill region button
|
||||
fill = Instance.new("TextButton", frame)
|
||||
fill.Position = UDim2.new(0.370, 0, 0.85, 0)
|
||||
fill.Size = UDim2.new(0.15, 0, 0.1, 0)
|
||||
fill.Text = ""
|
||||
fill.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
fill.TextColor3 = Color3.new(1, 1, 1)
|
||||
fill.Font = Enum.Font.ArialBold
|
||||
fill.FontSize = Enum.FontSize.Size14
|
||||
fill.BorderColor3 = Color3.new(0, 0, 0)
|
||||
fill.BackgroundTransparency = 0.5
|
||||
fill.MouseEnter:connect(function()
|
||||
fill.BorderColor3 = Color3.new(1, 1, 1)
|
||||
fill.BackgroundColor3 = Color3.new(0, 0, 0)
|
||||
fill.BackgroundTransparency = 0.2
|
||||
end)
|
||||
fill.MouseButton1Click:connect(function() onFill(currentMaterial) end)
|
||||
fill.MouseLeave:connect(function()
|
||||
fill.BorderColor3 = Color3.new(0, 0, 0)
|
||||
fill.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
fill.BackgroundTransparency = 0.5
|
||||
end)
|
||||
|
||||
matChange = Instance.new("TextButton", frame)
|
||||
matChange.Position = UDim2.new(0.025, 0, 0.85, 0)
|
||||
matChange.Size = UDim2.new(0.325, 0, 0.1, 0)
|
||||
matChange.Text = ""
|
||||
matChange.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
matChange.TextColor3 = Color3.new(1, 1, 1)
|
||||
matChange.Font = Enum.Font.ArialBold
|
||||
matChange.FontSize = Enum.FontSize.Size14
|
||||
matChange.BorderColor3 = Color3.new(0, 0, 0)
|
||||
matChange.BackgroundTransparency = 0.5
|
||||
matChange.MouseEnter:connect(function()
|
||||
matChange.BorderColor3 = Color3.new(1, 1, 1)
|
||||
matChange.BackgroundColor3 = Color3.new(0, 0, 0)
|
||||
matChange.BackgroundTransparency = 0.2
|
||||
end)
|
||||
matChange.MouseButton1Click:connect(function() onMaterialChange(currentMaterial) end)
|
||||
matChange.MouseLeave:connect(function()
|
||||
matChange.BorderColor3 = Color3.new(0, 0, 0)
|
||||
matChange.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
matChange.BackgroundTransparency = 0.5
|
||||
end)
|
||||
|
||||
|
||||
|
||||
--clone region button
|
||||
clone = Instance.new("TextButton", frame)
|
||||
clone.Position = UDim2.new(0.5325, 0, 0.85, 0)
|
||||
clone.Size = UDim2.new(0.2, 0, 0.1, 0)
|
||||
clone.Text = ""
|
||||
clone.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
clone.TextColor3 = Color3.new(1, 1, 1)
|
||||
clone.Font = Enum.Font.ArialBold
|
||||
clone.FontSize = Enum.FontSize.Size14
|
||||
clone.BorderColor3 = Color3.new(0, 0, 0)
|
||||
clone.BackgroundTransparency = 0.5
|
||||
clone.MouseEnter:connect(function()
|
||||
clone.BorderColor3 = Color3.new(1, 1, 1)
|
||||
clone.BackgroundColor3 = Color3.new(0, 0, 0)
|
||||
clone.BackgroundTransparency = 0.2
|
||||
end)
|
||||
clone.MouseButton1Click:connect(onClone)
|
||||
clone.MouseLeave:connect(function()
|
||||
clone.BorderColor3 = Color3.new(0, 0, 0)
|
||||
clone.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
clone.BackgroundTransparency = 0.5
|
||||
end)
|
||||
|
||||
--autowedge button
|
||||
autoWedge = Instance.new("TextButton", frame)
|
||||
autoWedge.Position = UDim2.new(0.75, 0, 0.85, 0)
|
||||
autoWedge.Size = UDim2.new(0.2, 0, 0.1, 0)
|
||||
autoWedge.Text = ""
|
||||
autoWedge.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
autoWedge.TextColor3 = Color3.new(1, 1, 1)
|
||||
autoWedge.Font = Enum.Font.ArialBold
|
||||
autoWedge.FontSize = Enum.FontSize.Size14
|
||||
autoWedge.BorderColor3 = Color3.new(0, 0, 0)
|
||||
autoWedge.BackgroundTransparency = 0.5
|
||||
autoWedge.MouseEnter:connect(function()
|
||||
autoWedge.BorderColor3 = Color3.new(1, 1, 1)
|
||||
autoWedge.BackgroundColor3 = Color3.new(0, 0, 0)
|
||||
autoWedge.BackgroundTransparency = 0.2
|
||||
end)
|
||||
autoWedge.MouseButton1Click:connect(onAutoWedge)
|
||||
autoWedge.MouseLeave:connect(function()
|
||||
autoWedge.BorderColor3 = Color3.new(0, 0, 0)
|
||||
autoWedge.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
autoWedge.BackgroundTransparency = 0.5
|
||||
end)
|
||||
|
||||
--rotate button
|
||||
rotate = Instance.new("TextButton", frame)
|
||||
rotate.Position = UDim2.new(0.75, 0, 0.45, 0)
|
||||
rotate.Size = UDim2.new(0.2, 0, 0.1, 0)
|
||||
rotate.Text = ""
|
||||
rotate.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
rotate.TextColor3 = Color3.new(1, 1, 1)
|
||||
rotate.Font = Enum.Font.ArialBold
|
||||
rotate.FontSize = Enum.FontSize.Size14
|
||||
rotate.BorderColor3 = Color3.new(0, 0, 0)
|
||||
rotate.BackgroundTransparency = 0.5
|
||||
rotate.MouseEnter:connect(function()
|
||||
rotate.BorderColor3 = Color3.new(1, 1, 1)
|
||||
rotate.BackgroundColor3 = Color3.new(0, 0, 0)
|
||||
rotate.BackgroundTransparency = 0.2
|
||||
end)
|
||||
rotate.MouseButton1Click:connect(onRotate)
|
||||
rotate.MouseLeave:connect(function()
|
||||
rotate.BorderColor3 = Color3.new(0, 0, 0)
|
||||
rotate.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
rotate.BackgroundTransparency = 0.5
|
||||
end)
|
||||
|
||||
--------------------------
|
||||
--SUCCESSFUL LOAD MESSAGE-
|
||||
--------------------------
|
||||
loaded = true
|
||||
print("Region Editing Plugin Loaded")
|
||||
@@ -0,0 +1,334 @@
|
||||
-----------------------------
|
||||
--LOCAL FUNCTION DEFINITIONS-
|
||||
-----------------------------
|
||||
local c = game.Workspace.Terrain
|
||||
local SetCell = c.SetCell
|
||||
local GetCell = c.GetCell
|
||||
local WorldToCellPreferSolid = c.WorldToCellPreferSolid
|
||||
|
||||
-----------------
|
||||
--DEFAULT VALUES-
|
||||
-----------------
|
||||
loaded = false
|
||||
on = false
|
||||
local materialToImageMap = {}
|
||||
local materialNames = {"Grass","Sand", "Brick", "Granite"}
|
||||
local currentMaterial = 1
|
||||
local changedDragging = 0
|
||||
|
||||
local debounce = false
|
||||
local dragging = false
|
||||
local r = 5
|
||||
|
||||
for i,v in pairs(materialNames) do
|
||||
materialToImageMap[v] = {}
|
||||
if v == "Grass" then
|
||||
materialToImageMap[v].Regular = "http://www.watrbx.wtf/asset/?id=56563112"
|
||||
elseif v == "Sand" then
|
||||
materialToImageMap[v].Regular = "http://www.watrbx.wtf/asset/?id=62356652"
|
||||
elseif v == "Brick" then
|
||||
materialToImageMap[v].Regular = "http://www.watrbx.wtf/asset/?id=65961537"
|
||||
materialToImageMap[v].Over = "http://www.watrbx.wtf/asset/?id=65961537"
|
||||
elseif v == "Granite" then
|
||||
materialToImageMap[v].Regular = "http://www.watrbx.wtf/asset/?id=65961588"
|
||||
materialToImageMap[v].Over = "http://www.watrbx.wtf/asset/?id=65961588"
|
||||
end
|
||||
end
|
||||
|
||||
for i,v in pairs(materialNames) do
|
||||
game:GetService("ContentProvider"):Preload(materialToImageMap[v].Regular)
|
||||
end
|
||||
|
||||
---------------
|
||||
--PLUGIN SETUP-
|
||||
---------------
|
||||
self = PluginManager():CreatePlugin()
|
||||
mouse = self:GetMouse()
|
||||
mouse.Button1Down:connect(function() mouseDown(mouse) end)
|
||||
mouse.Button1Up:connect(function() mouseUp(mouse) end)
|
||||
mouse.Move:connect(function() mouseMove(mouse) end)
|
||||
|
||||
self.Deactivation:connect(function()
|
||||
Off()
|
||||
end)
|
||||
toolbar = self:CreateToolbar("Terrain")
|
||||
toolbarbutton = toolbar:CreateButton("", "Material Brush", "materialBrush.png")
|
||||
toolbarbutton.Click:connect(function()
|
||||
if on then
|
||||
Off()
|
||||
elseif loaded then
|
||||
On()
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
--FUNCTION DEFINITIONS-
|
||||
-----------------------
|
||||
|
||||
function paint(mouse)
|
||||
if mouse and mouse.Hit and c and not debounce then
|
||||
debounce = true
|
||||
local count = 0
|
||||
local cellPos = WorldToCellPreferSolid(c, mouse.Hit.p)
|
||||
for x = cellPos.x - r, cellPos.x + r do
|
||||
for y = cellPos.y - r, cellPos.y + r do
|
||||
for z = cellPos.z - r, cellPos.z + r do
|
||||
local tempCellPos = Vector3.new(x, y, z)
|
||||
local distSq = (tempCellPos - cellPos):Dot(tempCellPos - cellPos)
|
||||
if (distSq < r*r) then
|
||||
local oldMaterial, oldType, oldOrientation = GetCell(c, x, y, z)
|
||||
if oldMaterial.Value > 0 then SetCell(c, x, y, z, currentMaterial, oldType, oldOrientation) end
|
||||
end
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
if count > 10000 then count = 0 wait() end
|
||||
end
|
||||
debounce = false
|
||||
end
|
||||
end
|
||||
|
||||
function mouseDown(mouse)
|
||||
changedDragging = tick()
|
||||
if on and mouse.Target == game.Workspace.Terrain then
|
||||
dragging = true
|
||||
tweeningFrame = true
|
||||
frame:TweenPosition(UDim2.new(0,-245,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.5,true,function()
|
||||
hintFrame.Visible = true
|
||||
tweeningFrame = false
|
||||
end)
|
||||
paint(mouse)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function mouseUp(mouse)
|
||||
dragging = false
|
||||
changedDragging = tick()
|
||||
delay(5,function()
|
||||
local timeDiff = (changedDragging + 5) - tick()
|
||||
if timeDiff < 0.2 then
|
||||
tweeningFrame = true
|
||||
hintFrame.Visible = false
|
||||
frame:TweenPosition(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.5,true,function()
|
||||
tweeningFrame = false
|
||||
end)
|
||||
end
|
||||
end)
|
||||
|
||||
end
|
||||
|
||||
|
||||
function mouseMove(mouse)
|
||||
if on and dragging then
|
||||
paint(mouse)
|
||||
end
|
||||
end
|
||||
|
||||
function On()
|
||||
self:Activate(true)
|
||||
toolbarbutton:SetActive(true)
|
||||
|
||||
local gui = game:GetService("CoreGui"):FindFirstChild("MaterialPainterGui",true)
|
||||
|
||||
frame.Position = UDim2.new(0,0,0,0)
|
||||
frame.Visible = true
|
||||
hintFrame.Visible = false
|
||||
halfFrame.Parent = gui
|
||||
title.Text = "Material Painter"
|
||||
radl.Text = "Radius: "..r
|
||||
|
||||
on = true
|
||||
end
|
||||
|
||||
function Off()
|
||||
toolbarbutton:SetActive(false)
|
||||
|
||||
title.Text = ""
|
||||
radl.Text = ""
|
||||
frame.Visible = false
|
||||
hintFrame.Visible = false
|
||||
halfFrame.Parent = nil
|
||||
on = false
|
||||
end
|
||||
|
||||
|
||||
function updateMaterialChoice(choice)
|
||||
if choice == "Grass" then
|
||||
currentMaterial = 1
|
||||
elseif choice == "Sand" then
|
||||
currentMaterial = 2
|
||||
elseif choice == "Erase" then
|
||||
currentMaterial = 0
|
||||
elseif choice == "Brick" then
|
||||
currentMaterial = 3
|
||||
elseif choice == "Granite" then
|
||||
currentMaterial = 4
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
------
|
||||
--GUI-
|
||||
------
|
||||
|
||||
--load library for with sliders
|
||||
local RbxGui = LoadLibrary("RbxGui")
|
||||
local tweeningFrame = false
|
||||
|
||||
--screengui
|
||||
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
g.Name = "MaterialPainterGui"
|
||||
|
||||
local selectedButton = nil
|
||||
|
||||
--frame
|
||||
frame = Instance.new("Frame", g)
|
||||
frame.Size = UDim2.new(0, 245, 0, 230)
|
||||
frame.Position = UDim2.new(0, 0, 0, 0)
|
||||
frame.BackgroundTransparency = 0.5
|
||||
frame.BorderSizePixel = 0
|
||||
frame.BackgroundColor3 = Color3.new(0,0,0)
|
||||
frame.Visible = false
|
||||
frame.Active = true
|
||||
|
||||
hintFrame = Instance.new("Frame",g)
|
||||
hintFrame.BackgroundTransparency = 0.5
|
||||
hintFrame.BackgroundColor3 = Color3.new(0,0,0)
|
||||
hintFrame.Size = UDim2.new(0,15,0,230)
|
||||
hintFrame.Visible = false
|
||||
|
||||
halfFrame = Instance.new("Frame",g)
|
||||
halfFrame.Name = "HalfFrame"
|
||||
halfFrame.Size = UDim2.new(0,123,0,230)
|
||||
halfFrame.BackgroundTransparency = 1
|
||||
halfFrame.MouseEnter:connect(function()
|
||||
if not dragging and frame.Position ~= UDim2.new(0, 0, 0, 0) and not tweeningFrame then
|
||||
tweeningFrame = true
|
||||
hintFrame.Visible = false
|
||||
frame:TweenPosition(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.2,true,function() tweeningFrame = false end)
|
||||
end
|
||||
end)
|
||||
|
||||
--title
|
||||
title = Instance.new("TextLabel", frame)
|
||||
title.Position = UDim2.new(0, 0, 0, 3)
|
||||
title.Size = UDim2.new(1, 0, 0, 24)
|
||||
title.Text = ""
|
||||
title.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
title.TextColor3 = Color3.new(1, 1, 1)
|
||||
title.Font = Enum.Font.ArialBold
|
||||
title.FontSize = Enum.FontSize.Size18
|
||||
title.BorderColor3 = Color3.new(0, 0, 0)
|
||||
title.BackgroundTransparency = 1
|
||||
|
||||
--current radius display label
|
||||
radl = Instance.new("TextLabel", frame)
|
||||
radl.Position = UDim2.new(0, 10, 1, -20)
|
||||
radl.Size = UDim2.new(0.2, 0, 0, 14)
|
||||
radl.Text = ""
|
||||
radl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
radl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
radl.Font = Enum.Font.Arial
|
||||
radl.FontSize = Enum.FontSize.Size14
|
||||
radl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
radl.BackgroundTransparency = 1
|
||||
|
||||
--radius slider
|
||||
radSliderGui, radSliderPosition = RbxGui.CreateSlider(10, 0, UDim2.new(0, 75, 1, -15))
|
||||
radSliderGui.Parent = frame
|
||||
radBar = radSliderGui:FindFirstChild("Bar")
|
||||
radBar.Size = UDim2.new(0.65, 0, 0, 5)
|
||||
radSliderPosition.Value = r - 1
|
||||
radSliderPosition.Changed:connect(function()
|
||||
r = radSliderPosition.Value
|
||||
radl.Text = "Radius: "..r
|
||||
end)
|
||||
|
||||
local scrollFrame, scrollUp, scrollDown, recalculateScroll = RbxGui.CreateScrollingFrame(nil,"grid")
|
||||
scrollFrame.Size = UDim2.new(0,240,0,170)
|
||||
scrollFrame.Position = UDim2.new(0.5,-scrollFrame.Size.X.Offset/2,0,30)
|
||||
scrollFrame.Parent = frame
|
||||
|
||||
scrollUp.Parent = frame
|
||||
scrollUp.Visible = false
|
||||
scrollUp.Position = UDim2.new(1,-19,0,30)
|
||||
|
||||
scrollDown.Parent = frame
|
||||
scrollDown.Visible = false
|
||||
scrollDown.Position = UDim2.new(1,-19,0,30 - 17 + scrollFrame.Size.Y.Offset)
|
||||
|
||||
scrollFrame.ChildRemoved:connect(function()
|
||||
if #scrollFrame:GetChildren() < 35 then
|
||||
scrollUp.Visible = false
|
||||
scrollDown.Visible = false
|
||||
end
|
||||
end)
|
||||
|
||||
scrollFrame.ChildAdded:connect(function()
|
||||
if #scrollFrame:GetChildren() >= 35 then
|
||||
scrollUp.Visible = true
|
||||
scrollDown.Visible = true
|
||||
end
|
||||
end)
|
||||
|
||||
function createMaterialButton(name)
|
||||
local buttonWrap = Instance.new("TextButton")
|
||||
buttonWrap.Text = ""
|
||||
buttonWrap.Size = UDim2.new(0,32,0,32)
|
||||
buttonWrap.BackgroundColor3 = Color3.new(1,1,1)
|
||||
buttonWrap.BorderSizePixel = 0
|
||||
buttonWrap.BackgroundTransparency = 1
|
||||
buttonWrap.AutoButtonColor = false
|
||||
buttonWrap.Name = tostring(name) .. "Button"
|
||||
|
||||
local imageButton = Instance.new("ImageButton")
|
||||
imageButton.AutoButtonColor = false
|
||||
imageButton.BackgroundTransparency = 1
|
||||
imageButton.Size = UDim2.new(0,30,0,30)
|
||||
imageButton.Position = UDim2.new(0,1,0,1)
|
||||
imageButton.Name = tostring(name) .. "Button"
|
||||
imageButton.Parent = buttonWrap
|
||||
imageButton.Image = materialToImageMap[name].Regular
|
||||
|
||||
imageButton.MouseEnter:connect(function()
|
||||
buttonWrap.BackgroundTransparency = 0
|
||||
end)
|
||||
imageButton.MouseLeave:connect(function()
|
||||
if selectedButton ~= buttonWrap then
|
||||
buttonWrap.BackgroundTransparency = 1
|
||||
end
|
||||
end)
|
||||
imageButton.MouseButton1Click:connect(function()
|
||||
updateMaterialChoice(name)
|
||||
if selectedButton ~= buttonWrap then
|
||||
buttonWrap.BackgroundTransparency = 0
|
||||
selectedButton.BackgroundTransparency = 1
|
||||
selectedButton = buttonWrap
|
||||
end
|
||||
end)
|
||||
|
||||
return buttonWrap
|
||||
end
|
||||
|
||||
for i = 1, #materialNames do
|
||||
local imageButton = createMaterialButton(materialNames[i])
|
||||
|
||||
if materialNames[i] == "Grass" then
|
||||
selectedButton = imageButton
|
||||
imageButton.BackgroundTransparency = 0
|
||||
end
|
||||
|
||||
imageButton.Parent = scrollFrame
|
||||
end
|
||||
|
||||
recalculateScroll()
|
||||
|
||||
|
||||
--------------------------
|
||||
--SUCCESSFUL LOAD MESSAGE-
|
||||
--------------------------
|
||||
loaded = true
|
||||
|
After Width: | Height: | Size: 1006 B |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,124 @@
|
||||
-----------------
|
||||
--DEFAULT VALUES-
|
||||
-----------------
|
||||
loaded = false
|
||||
on = false
|
||||
t = 720
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--PLUGIN SETUP-
|
||||
---------------
|
||||
|
||||
--make internal representation of plugin (needed to call functions like CreateToolbar() and Activate())
|
||||
self = PluginManager():CreatePlugin()
|
||||
|
||||
--Deactivation event is sent when another plugin calls Activate(), turn off when Deactivation event is received
|
||||
self.Deactivation:connect(function()
|
||||
Off()
|
||||
end)
|
||||
|
||||
--make a new toolbar, "Utilities" is the name of it, if another plugin also uses a toolbar named "Utilities" they will both create buttons on the same one
|
||||
toolbar = self:CreateToolbar("Utilities")
|
||||
|
||||
--make a button on the toolbar, the first parameter is the text on the button, second is the tooltip, and last is the icon
|
||||
toolbarbutton = toolbar:CreateButton("", "Time of Day", "time.png")
|
||||
|
||||
--make button turn plugin on and off
|
||||
toolbarbutton.Click:connect(function()
|
||||
if on then
|
||||
Off()
|
||||
elseif loaded then
|
||||
On()
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
--FUNCTION DEFINITIONS-
|
||||
-----------------------
|
||||
--converts time in minutes into a string of the format "hours:minutes:seconds" (seconds are always 00)
|
||||
function timestring(t)
|
||||
local tsTemp = "%0.2d:%0.2d:00"
|
||||
return tsTemp:format(math.floor(t/60), math.floor(t%60))
|
||||
end
|
||||
|
||||
function On()
|
||||
self:Activate(true)
|
||||
toolbarbutton:SetActive(true)
|
||||
frame.Visible = true
|
||||
for w = 0, 0.8, 0.16 do
|
||||
frame.Size = UDim2.new(w, 0, w/9, 0)
|
||||
wait(0.0000001)
|
||||
end
|
||||
title.Text = "Time of Day: "..timestring(t)
|
||||
on = true
|
||||
end
|
||||
|
||||
function Off()
|
||||
toolbarbutton:SetActive(false)
|
||||
title.Text = ""
|
||||
for w = 0.8, 0, -0.16 do
|
||||
frame.Size = UDim2.new(w, 0, w/9, 0)
|
||||
wait(0.0000001)
|
||||
end
|
||||
frame.Visible = false
|
||||
on = false
|
||||
end
|
||||
|
||||
|
||||
|
||||
------
|
||||
--GUI-
|
||||
------
|
||||
--screengui
|
||||
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
|
||||
--frame
|
||||
frame = Instance.new("Frame", g)
|
||||
frame.Position = UDim2.new(0.1, 0, 0.85, 0)
|
||||
frame.Size = UDim2.new(0.8, 0, 0.1, 0)
|
||||
frame.BackgroundTransparency = 0.7
|
||||
frame.Visible = false
|
||||
|
||||
--title
|
||||
title = Instance.new("TextLabel", frame)
|
||||
title.Position = UDim2.new(0.4, 0, 0.25, 0)
|
||||
title.Size = UDim2.new(0.2, 0, 0.05, 0)
|
||||
title.Text = ""
|
||||
title.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
title.TextColor3 = Color3.new(1, 1, 1)
|
||||
title.Font = Enum.Font.ArialBold
|
||||
title.FontSize = Enum.FontSize.Size24
|
||||
title.BorderColor3 = Color3.new(0, 0, 0)
|
||||
title.BackgroundTransparency = 1
|
||||
|
||||
--slider
|
||||
local RbxGui = LoadLibrary("RbxGui")
|
||||
sliderGui, sliderPosition = RbxGui.CreateSlider(1440, frame.AbsoluteSize.x * 0.95, UDim2.new(0.025, 0, 0.7, 0))
|
||||
sliderGui.Parent = frame
|
||||
bar = sliderGui:FindFirstChild("Bar")
|
||||
bar.Size = UDim2.new(0.95, 0, 0, 5)
|
||||
sliderPosition.Value = t
|
||||
sliderPosition.Changed:connect(function()
|
||||
t = sliderPosition.Value
|
||||
ts = timestring(t)
|
||||
title.Text = "Time of Day: "..ts
|
||||
title.Text = "Time of Day: "..ts
|
||||
game:GetService("Lighting").TimeOfDay = ts
|
||||
end)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------
|
||||
--SUCCESSFUL LOAD MESSAGE-
|
||||
--------------------------
|
||||
loaded = true
|
||||
print("Time of Day Plugin Loaded")
|
||||
@@ -0,0 +1,212 @@
|
||||
-----------------
|
||||
--DEFAULT VALUES-
|
||||
-----------------
|
||||
on = false
|
||||
loaded = false
|
||||
|
||||
|
||||
---------------
|
||||
--PLUGIN SETUP-
|
||||
---------------
|
||||
self = PluginManager():CreatePlugin()
|
||||
mouse = self:GetMouse()
|
||||
mouse.Button1Down:connect(function() eventl.Text = "Button1Down" end)
|
||||
mouse.Button1Up:connect(function() eventl.Text = "Button1Up" end)
|
||||
mouse.Button2Down:connect(function() eventl.Text = "Button2Down" end)
|
||||
mouse.Button2Up:connect(function() eventl.Text = "Button2Up" end)
|
||||
mouse.WheelForward:connect(function() eventl.Text = "WheelForward" end)
|
||||
mouse.WheelBackward:connect(function() eventl.Text = "WheelBackward" end)
|
||||
mouse.KeyDown:connect(function(key) eventl.Text = "KeyDown("..key..")" end)
|
||||
mouse.KeyUp:connect(function(key) eventl.Text = "KeyUp("..key..")" end)
|
||||
mouse.Move:connect(function()
|
||||
hitl.Text = mouse.Hit.p.x..", "..mouse.Hit.p.y..", "..mouse.Hit.p.z
|
||||
terrain = game.Workspace.Terrain
|
||||
if terrain then
|
||||
cellPos = terrain:WorldToCellPreferSolid(mouse.Hit.p)
|
||||
if cellPos then
|
||||
terrainl.Text = cellPos.x..", "..cellPos.y..", "..cellPos.z
|
||||
else
|
||||
terrainl.Text = ""
|
||||
end
|
||||
end
|
||||
screenl.Text = mouse.X..", "..mouse.Y
|
||||
end)
|
||||
self.Deactivation:connect(function()
|
||||
Off()
|
||||
end)
|
||||
toolbar = self:CreateToolbar("Utilities")
|
||||
toolbarbutton = toolbar:CreateButton("", "Input Info: Check coordinates of where you click and see input events triggered.", "inputinfo.png")
|
||||
toolbarbutton.Click:connect(function()
|
||||
if on then
|
||||
Off()
|
||||
elseif loaded then
|
||||
On()
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
--FUNCTION DEFINITIONS-
|
||||
-----------------------
|
||||
function On()
|
||||
self:Activate(true)
|
||||
toolbarbutton:SetActive(true)
|
||||
frame.Visible = true
|
||||
eventt.Text = ""
|
||||
eventl.Text = ""
|
||||
hitt.Text = ""
|
||||
hitl.Text = ""
|
||||
terraint.Text = ""
|
||||
terrainl.Text = ""
|
||||
screent.Text = ""
|
||||
screenl.Text = ""
|
||||
for w = 0, 0.6, 0.12 do
|
||||
frame.Size = UDim2.new(w, 0, w/4, 0)
|
||||
wait(0.0000001)
|
||||
end
|
||||
eventt.Text = "Last Input Event: "
|
||||
hitt.Text = "World Coordinates: "
|
||||
terraint.Text = "Terrain Coordinates: "
|
||||
screent.Text = "Screen Coordinates: "
|
||||
on = true
|
||||
end
|
||||
|
||||
function Off()
|
||||
toolbarbutton:SetActive(false)
|
||||
eventt.Text = ""
|
||||
eventl.Text = ""
|
||||
hitt.Text = ""
|
||||
hitl.Text = ""
|
||||
terraint.Text = ""
|
||||
terrainl.Text = ""
|
||||
screent.Text = ""
|
||||
screenl.Text = ""
|
||||
for w = 0.6, 0, -0.12 do
|
||||
frame.Size = UDim2.new(w, 0, w/4, 0)
|
||||
wait(0.0000001)
|
||||
end
|
||||
frame.Visible = false
|
||||
on = false
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
------
|
||||
--GUI-
|
||||
------
|
||||
--screengui
|
||||
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
|
||||
--frame
|
||||
frame = Instance.new("Frame", g)
|
||||
frame.Position = UDim2.new(0.2, 0, 0.8, 0)
|
||||
frame.Size = UDim2.new(0.6, 0, 0.2, 0)
|
||||
frame.BackgroundTransparency = 0.5
|
||||
frame.Visible = false
|
||||
|
||||
--last event title
|
||||
eventt = Instance.new("TextLabel", frame)
|
||||
eventt.Position = UDim2.new(0.1, 0, 0.125, 0)
|
||||
eventt.Size = UDim2.new(0.2, 0, 0.15, 0)
|
||||
eventt.Text = ""
|
||||
eventt.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
eventt.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
eventt.Font = Enum.Font.ArialBold
|
||||
eventt.FontSize = Enum.FontSize.Size14
|
||||
eventt.BorderColor3 = Color3.new(0, 0, 0)
|
||||
eventt.BackgroundTransparency = 1
|
||||
|
||||
--last event display label
|
||||
eventl = Instance.new("TextLabel", frame)
|
||||
eventl.Position = UDim2.new(0.4, 0, 0.125, 0)
|
||||
eventl.Size = UDim2.new(0.5, 0, 0.15, 0)
|
||||
eventl.Text = ""
|
||||
eventl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
eventl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
eventl.Font = Enum.Font.ArialBold
|
||||
eventl.FontSize = Enum.FontSize.Size14
|
||||
eventl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
eventl.BackgroundTransparency = 1
|
||||
|
||||
--current world coordinates title
|
||||
hitt = Instance.new("TextLabel", frame)
|
||||
hitt.Position = UDim2.new(0.1, 0, 0.325, 0)
|
||||
hitt.Size = UDim2.new(0.2, 0, 0.15, 0)
|
||||
hitt.Text = ""
|
||||
hitt.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
hitt.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
hitt.Font = Enum.Font.ArialBold
|
||||
hitt.FontSize = Enum.FontSize.Size14
|
||||
hitt.BorderColor3 = Color3.new(0, 0, 0)
|
||||
hitt.BackgroundTransparency = 1
|
||||
|
||||
--current world coordinates display label
|
||||
hitl = Instance.new("TextLabel", frame)
|
||||
hitl.Position = UDim2.new(0.4, 0, 0.325, 0)
|
||||
hitl.Size = UDim2.new(0.5, 0, 0.15, 0)
|
||||
hitl.Text = ""
|
||||
hitl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
hitl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
hitl.Font = Enum.Font.ArialBold
|
||||
hitl.FontSize = Enum.FontSize.Size14
|
||||
hitl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
hitl.BackgroundTransparency = 1
|
||||
|
||||
--current terrain coordinates title
|
||||
terraint = Instance.new("TextLabel", frame)
|
||||
terraint.Position = UDim2.new(0.1, 0, 0.525, 0)
|
||||
terraint.Size = UDim2.new(0.2, 0, 0.15, 0)
|
||||
terraint.Text = ""
|
||||
terraint.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
terraint.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
terraint.Font = Enum.Font.ArialBold
|
||||
terraint.FontSize = Enum.FontSize.Size14
|
||||
terraint.BorderColor3 = Color3.new(0, 0, 0)
|
||||
terraint.BackgroundTransparency = 1
|
||||
|
||||
--current terrain coordinates display label
|
||||
terrainl = Instance.new("TextLabel", frame)
|
||||
terrainl.Position = UDim2.new(0.4, 0, 0.525, 0)
|
||||
terrainl.Size = UDim2.new(0.5, 0, 0.15, 0)
|
||||
terrainl.Text = ""
|
||||
terrainl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
terrainl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
terrainl.Font = Enum.Font.ArialBold
|
||||
terrainl.FontSize = Enum.FontSize.Size14
|
||||
terrainl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
terrainl.BackgroundTransparency = 1
|
||||
|
||||
--current screen coordinates title
|
||||
screent = Instance.new("TextLabel", frame)
|
||||
screent.Position = UDim2.new(0.1, 0, 0.725, 0)
|
||||
screent.Size = UDim2.new(0.2, 0, 0.15, 0)
|
||||
screent.Text = ""
|
||||
screent.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
screent.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
screent.Font = Enum.Font.ArialBold
|
||||
screent.FontSize = Enum.FontSize.Size14
|
||||
screent.BorderColor3 = Color3.new(0, 0, 0)
|
||||
screent.BackgroundTransparency = 1
|
||||
|
||||
--current screen coordinates display label
|
||||
screenl = Instance.new("TextLabel", frame)
|
||||
screenl.Position = UDim2.new(0.4, 0, 0.725, 0)
|
||||
screenl.Size = UDim2.new(0.5, 0, 0.15, 0)
|
||||
screenl.Text = ""
|
||||
screenl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
||||
screenl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
screenl.Font = Enum.Font.ArialBold
|
||||
screenl.FontSize = Enum.FontSize.Size14
|
||||
screenl.BorderColor3 = Color3.new(0, 0, 0)
|
||||
screenl.BackgroundTransparency = 1
|
||||
|
||||
|
||||
--------------------------
|
||||
--SUCCESSFUL LOAD MESSAGE-
|
||||
--------------------------
|
||||
loaded = true
|
||||
print("Input Info Plugin Loaded")
|
||||
@@ -0,0 +1,772 @@
|
||||
-- we'll load this later; workaround for strange crash
|
||||
local RbxStamper = nil
|
||||
|
||||
local stampControl = nil
|
||||
local stampingCon = nil
|
||||
|
||||
|
||||
-----------------
|
||||
--DEFAULT VALUES-
|
||||
-----------------
|
||||
local on = false
|
||||
local loaded = false
|
||||
local selectionConnection = nil
|
||||
local myModel = nil
|
||||
local whichStep = 1
|
||||
|
||||
local backEnabled = false
|
||||
local continueEnabled = false
|
||||
|
||||
local bbPreviewCoroutine = nil
|
||||
local facePreviewCoroutine = nil
|
||||
|
||||
local bbPreview = Instance.new("Part")
|
||||
bbPreview.Name = "SideSelectionBox"
|
||||
bbPreview.Transparency = .7
|
||||
bbPreview.formFactor = "Custom"
|
||||
bbPreview.Size = Vector3.new(4, 4, 4)
|
||||
bbPreview.Transparency = 1
|
||||
bbPreview.CanCollide = false
|
||||
bbPreview.Anchored = true
|
||||
bbPreview.CFrame = CFrame.new(0, 0, 0)
|
||||
bbPreview.TopSurface = "Smooth"
|
||||
bbPreview.BottomSurface = "Smooth"
|
||||
|
||||
local alignmentVect = Vector3.new(0, 0, 0)
|
||||
local alignToFaceText = "[None]"
|
||||
local unstampableFacesText = "[None]"
|
||||
local unstampableFaces = {false, false, false, false, false, false}
|
||||
local unjoinableFacesText = "[None]"
|
||||
local unjoinableFaces = {false, false, false, false, false, false}
|
||||
|
||||
local SURFACE_FROM_NUMBER = {Enum.NormalId.Back, Enum.NormalId.Bottom, Enum.NormalId.Front, Enum.NormalId.Left, Enum.NormalId.Right, Enum.NormalId.Top}
|
||||
local ALIGN_TO_FACE_MAPPING = {1, nil, 3, 2, 0, nil}
|
||||
local UNSTAMPABLE_FACE_MAPPING = {"3", "-2", "-3", "-1", "1", "2"}
|
||||
local SURFACE_TO_NUMBER = {}
|
||||
local REVERSE_ALIGN_TO_FACE_MAPPING = {}
|
||||
local REVERSE_UNSTAMPABLE_FACE_MAPPING = {}
|
||||
|
||||
for i = 1, #SURFACE_FROM_NUMBER do
|
||||
SURFACE_TO_NUMBER[SURFACE_FROM_NUMBER[i]] = i
|
||||
end
|
||||
for i = 1, #ALIGN_TO_FACE_MAPPING do
|
||||
if ALIGN_TO_FACE_MAPPING[i] then REVERSE_ALIGN_TO_FACE_MAPPING[ALIGN_TO_FACE_MAPPING[i]] = SURFACE_FROM_NUMBER[i] end
|
||||
end
|
||||
for i = 1, #UNSTAMPABLE_FACE_MAPPING do
|
||||
REVERSE_UNSTAMPABLE_FACE_MAPPING[tonumber(UNSTAMPABLE_FACE_MAPPING[i])] = i
|
||||
end
|
||||
---------------
|
||||
--PLUGIN SETUP-
|
||||
---------------
|
||||
|
||||
self = PluginManager():CreatePlugin()
|
||||
mouse = self:GetMouse()
|
||||
mouse.Button1Down:connect(function() onClicked(mouse) end)
|
||||
self.Deactivation:connect(function()
|
||||
Off()
|
||||
end)
|
||||
toolbar = self:CreateToolbar("Utilities")
|
||||
toolbarbutton = toolbar:CreateButton("", "Stamper Wizard: Make models you can stamp out!", "stampwizard.png")
|
||||
toolbarbutton.Click:connect(function()
|
||||
if on then
|
||||
Off()
|
||||
elseif loaded then
|
||||
On()
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
--FUNCTION DEFINITIONS-
|
||||
-----------------------
|
||||
|
||||
function roundToGrid(vect)
|
||||
return Vector3.new(math.ceil(vect.X/4)*4, math.ceil(vect.Y/4)*4, math.ceil(vect.Z/4)*4)
|
||||
end
|
||||
|
||||
function toAlignmentString(vect)
|
||||
local aString = ""
|
||||
aString = aString .. tostring(math.floor(vect.X*100 + .5) / 100) .. ", "
|
||||
aString = aString .. tostring(math.floor(vect.Y*100 + .5) / 100) .. ", "
|
||||
aString = aString .. tostring(math.floor(vect.Z*100 + .5) / 100)
|
||||
return aString
|
||||
end
|
||||
|
||||
function updateBBPreview()
|
||||
while bbPreviewBox.Visible do
|
||||
myModel:SetIdentityOrientation()
|
||||
local myModelSize = myModel:GetModelSize()
|
||||
bbPreview.Size = roundToGrid(myModelSize)
|
||||
bbPreview.CFrame = myModel:GetModelCFrame() + alignmentVect*(bbPreview.Size - myModelSize)*.5
|
||||
if whichStep == 3 then selectedLabel.Text = "Size: " .. tostring(bbPreview.Size)
|
||||
elseif whichStep == 4 then selectedLabel.Text = "Alignment: " .. toAlignmentString(alignmentVect)
|
||||
elseif whichStep == 5 then selectedLabel.Text = alignToFaceText
|
||||
elseif whichStep == 6 then selectedLabel.Text = unjoinableFacesText
|
||||
elseif whichStep == 7 then selectedLabel.Text = unstampableFacesText end
|
||||
wait(.1)
|
||||
end
|
||||
bbPreviewCoroutine = nil
|
||||
end
|
||||
|
||||
function getFaceArrayText(array)
|
||||
local currText = ""
|
||||
local foundOne = false
|
||||
for i = 1, 6 do
|
||||
if array[i] then
|
||||
if foundOne then currText = currText .. ", " end
|
||||
currText = currText .. string.gsub(tostring(SURFACE_FROM_NUMBER[i]), "Enum.NormalId.", "")
|
||||
foundOne = true
|
||||
end
|
||||
end
|
||||
if not foundOne then return "[None]" else return currText end
|
||||
end
|
||||
|
||||
|
||||
function loadMetaData(myModel)
|
||||
if not myModel or not myModel:IsA("Model") then return end
|
||||
|
||||
if myModel.PrimaryPart then myPrimaryPart = myModel.PrimaryPart end
|
||||
|
||||
local jTag = myModel:FindFirstChild("Justification")
|
||||
local aTag = myModel:FindFirstChild("AutoAlignToFace")
|
||||
local usTag = myModel:FindFirstChild("UnstampableFaces")
|
||||
local ujTag = myModel:FindFirstChild("UnjoinableFaces")
|
||||
if jTag then
|
||||
alignmentVect = -jTag.Value + Vector3.new(1, 1, 1)
|
||||
end
|
||||
if aTag then
|
||||
alignToFaceSelection.TargetSurface = REVERSE_ALIGN_TO_FACE_MAPPING[aTag.Value]
|
||||
alignToFaceText = string.gsub(tostring(alignToFaceSelection.TargetSurface), "Enum.NormalId.", "")
|
||||
end
|
||||
if usTag then
|
||||
local uString = usTag.Value
|
||||
for i = 1, 6 do unstampableFaces[i] = false end
|
||||
|
||||
for w in string.gmatch(uString, "[^,]*") do
|
||||
if tonumber(w) then unstampableFaces[REVERSE_UNSTAMPABLE_FACE_MAPPING[tonumber(w)]] = true end
|
||||
end
|
||||
unstampableFacesText = getFaceArrayText(unstampableFaces)
|
||||
end
|
||||
if ujTag then
|
||||
local uString = ujTag.Value
|
||||
for i = 1, 6 do unjoinableFaces[i] = false end
|
||||
|
||||
for w in string.gmatch(uString, "[^,]*") do
|
||||
if tonumber(w) then unjoinableFaces[REVERSE_UNSTAMPABLE_FACE_MAPPING[tonumber(w)]] = true end
|
||||
end
|
||||
unjoinableFacesText = getFaceArrayText(unjoinableFaces)
|
||||
end
|
||||
end
|
||||
|
||||
function setupStamper(stampModel)
|
||||
if stampControl then stampControl.Destroy() end
|
||||
if stampingCon then
|
||||
stampingCon:disconnect()
|
||||
stampingCon = nil
|
||||
end
|
||||
|
||||
stampControl = RbxStamper.SetupStamperDragger(stampModel, mouse)
|
||||
stampingCon = stampControl.Stamped.Changed:connect(function()
|
||||
if stampControl and stampControl.Stamped.Value then
|
||||
stampControl.ReloadModel()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local stampTesting = false
|
||||
function testStamperModel()
|
||||
if stampTesting then
|
||||
stopStampTest()
|
||||
else
|
||||
startStampTest()
|
||||
end
|
||||
end
|
||||
|
||||
local stampedModelListener = nil
|
||||
local stampedModels = {}
|
||||
|
||||
|
||||
function listenForStampedModels(childAdded)
|
||||
if childAdded and childAdded.Parent == game.Workspace and childAdded:FindFirstChild("RobloxStamper", true) then
|
||||
table.insert(stampedModels, childAdded)
|
||||
end
|
||||
end
|
||||
|
||||
function insertStamperTags(parentModel)
|
||||
local stampTag = parentModel:FindFirstChild("RobloxStamper")
|
||||
if not stampTag then
|
||||
stampTag = Instance.new("BoolValue")
|
||||
stampTag.Name = "RobloxStamper"
|
||||
stampTag.Parent = parentModel
|
||||
end
|
||||
|
||||
local modelTag = parentModel:FindFirstChild("RobloxModel")
|
||||
if not modelTag then
|
||||
modelTag = Instance.new("BoolValue")
|
||||
modelTag.Name = "RobloxModel"
|
||||
modelTag.Parent = parentModel
|
||||
end
|
||||
end
|
||||
|
||||
function startStampTest()
|
||||
stampTesting = true
|
||||
testButton.Text = "Stop testing"
|
||||
|
||||
-- start listening for all models stamped via testing mechanism
|
||||
stampedModelListener = game.Workspace.ChildAdded:connect(listenForStampedModels)
|
||||
|
||||
local cloneInstance = myModel:Clone()
|
||||
finishModel(cloneInstance)
|
||||
insertStamperTags(cloneInstance)
|
||||
cloneInstance:ResetOrientationToIdentity()
|
||||
cloneInstance:BreakJoints()
|
||||
setupStamper(cloneInstance)
|
||||
end
|
||||
|
||||
function stopStampTest()
|
||||
stampTesting = false
|
||||
testButton.Text = "Test it!"
|
||||
|
||||
if stampControl then
|
||||
stampControl.Destroy()
|
||||
end
|
||||
|
||||
-- remove all models stamped via testing mechanism
|
||||
if stampedModelListener then stampedModelListener:disconnect() end
|
||||
for i = 1, #stampedModels do stampedModels[i]:Remove() end
|
||||
stampedModels = {}
|
||||
end
|
||||
|
||||
|
||||
-- just returns the first ancestor of type "Model", but nil if that model is a direct parent of the game (like game.Workspace)
|
||||
function getModelFromPart(part)
|
||||
if not part then return {} end
|
||||
if part.Parent == game then return {} end
|
||||
if part:IsA("Model") then
|
||||
return {part}
|
||||
else
|
||||
return getModelFromPart(part.Parent)
|
||||
end
|
||||
end
|
||||
|
||||
function onClicked(mouse)
|
||||
if surfaceSelection.Visible then
|
||||
if whichStep == 5 then
|
||||
if alignToFaceSelection.Visible and alignToFaceSelection.TargetSurface == surfaceSelection.TargetSurface then
|
||||
-- turn off that face
|
||||
alignToFaceText = "[None]"
|
||||
alignToFaceSelection.Visible = false
|
||||
else
|
||||
alignToFaceSelection.TargetSurface = surfaceSelection.TargetSurface
|
||||
alignToFaceSelection.Visible = true
|
||||
alignToFaceText = string.gsub(tostring(alignToFaceSelection.TargetSurface), "Enum.NormalId.", "")
|
||||
end
|
||||
elseif whichStep == 6 then
|
||||
local whichFace = SURFACE_TO_NUMBER[surfaceSelection.TargetSurface]
|
||||
local unjoinableFaceSelector = unjoinableFaceSelections[whichFace]
|
||||
if unjoinableFaceSelector.Visible then
|
||||
unjoinableFaceSelector.Visible = false
|
||||
unjoinableFaces[whichFace] = false
|
||||
unjoinableFacesText = getFaceArrayText(unjoinableFaces)
|
||||
else
|
||||
unjoinableFaceSelector.Visible = true
|
||||
unjoinableFaces[whichFace] = true
|
||||
unjoinableFacesText = getFaceArrayText(unjoinableFaces)
|
||||
end
|
||||
elseif whichStep == 7 then
|
||||
local whichFace = SURFACE_TO_NUMBER[surfaceSelection.TargetSurface]
|
||||
local unstampableFaceSelector = unstampableFaceSelections[whichFace]
|
||||
if unstampableFaceSelector.Visible then
|
||||
unstampableFaceSelector.Visible = false
|
||||
unstampableFaces[whichFace] = false
|
||||
unstampableFacesText = getFaceArrayText(unstampableFaces)
|
||||
else
|
||||
unstampableFaceSelector.Visible = true
|
||||
unstampableFaces[whichFace] = true
|
||||
unstampableFacesText = getFaceArrayText(unstampableFaces)
|
||||
end
|
||||
end
|
||||
elseif whichStep == 1 then
|
||||
-- allow them to click directly on the model they want to choose
|
||||
if mouse.Target then game.Selection:Set(getModelFromPart(mouse.Target)) end
|
||||
elseif whichStep == 2 then
|
||||
-- allow them to click directly on the part they want to choose
|
||||
if mouse.Target then game.Selection:Set({mouse.Target}) end
|
||||
end
|
||||
end
|
||||
|
||||
function updateFacePreview()
|
||||
while bbPreview.Parent do
|
||||
if mouse.Target == bbPreview and (whichStep ~= 5 or (mouse.TargetSurface ~= Enum.NormalId.Top and mouse.TargetSurface ~= Enum.NormalId.Bottom)) then
|
||||
surfaceSelection.TargetSurface = mouse.TargetSurface
|
||||
surfaceSelection.Visible = true
|
||||
if (whichStep == 5 and alignToFaceSelection.Visible and alignToFaceSelection.TargetSurface == surfaceSelection.TargetSurface) then surfaceSelection.Color = BrickColor.new("Toothpaste")
|
||||
elseif (whichStep == 6 and unjoinableFaces[SURFACE_TO_NUMBER[surfaceSelection.TargetSurface]]) then surfaceSelection.Color = BrickColor.new("New Yeller")
|
||||
elseif (whichStep == 7 and unstampableFaces[SURFACE_TO_NUMBER[surfaceSelection.TargetSurface]]) then surfaceSelection.Color = BrickColor.new("Really red")
|
||||
else surfaceSelection.Color = BrickColor.new("Light stone grey") end
|
||||
else
|
||||
surfaceSelection.Visible = false
|
||||
end
|
||||
|
||||
wait(.1)
|
||||
end
|
||||
facePreviewCoroutine = nil
|
||||
end
|
||||
|
||||
function alignmentTruncate(num)
|
||||
if num < -1 then return -1
|
||||
elseif num > 1 then return 1
|
||||
else return num end
|
||||
end
|
||||
|
||||
function dragBB(face, dist)
|
||||
if face == Enum.NormalId.Front then
|
||||
alignmentVect = Vector3.new(alignmentVect.X, alignmentVect.Y, alignmentTruncate(math.ceil(-dist/20)))
|
||||
elseif face == Enum.NormalId.Back then
|
||||
alignmentVect = Vector3.new(alignmentVect.X, alignmentVect.Y, alignmentTruncate(math.floor(dist/20)))
|
||||
elseif face == Enum.NormalId.Bottom then
|
||||
alignmentVect = Vector3.new(alignmentVect.X, alignmentTruncate(math.ceil(-dist/20)), alignmentVect.Z)
|
||||
elseif face == Enum.NormalId.Top then
|
||||
alignmentVect = Vector3.new(alignmentVect.X, alignmentTruncate(math.floor(dist/20)), alignmentVect.Z)
|
||||
elseif face == Enum.NormalId.Left then
|
||||
alignmentVect = Vector3.new(alignmentTruncate(math.ceil(-dist/20)), alignmentVect.Y, alignmentVect.Z)
|
||||
elseif face == Enum.NormalId.Right then
|
||||
alignmentVect = Vector3.new(alignmentTruncate(math.floor(dist/20)), alignmentVect.Y, alignmentVect.Z)
|
||||
else return end
|
||||
end
|
||||
|
||||
|
||||
function refreshPage(whichPage)
|
||||
print("refresh")
|
||||
if whichPage == 1 then
|
||||
-- Select Model
|
||||
continueButton.Text = "Continue"
|
||||
infoBox.Text = "Select the model you want to turn into a stamper part."
|
||||
if myModel then selectedLabel.Text = myModel.Name setContinueEnabled(true) if #game.Selection:Get() ~= 1 or game.Selection:Get()[1] ~= myModel then game.Selection:Set({myModel}) end else selectedLabel.Text = "[None]" setContinueEnabled(false) end
|
||||
elseif whichPage == 2 then
|
||||
-- Select Primary Part
|
||||
bbPreviewBox.Visible = false
|
||||
infoBox.Text = "Select one part inside your model to be the \"key part\"."
|
||||
if myPrimaryPart then selectedLabel.Text = myPrimaryPart.Name setContinueEnabled(true) if #game.Selection:Get() ~= 1 or game.Selection:Get()[1] ~= myPrimaryPart then game.Selection:Set({myPrimaryPart}) end else selectedLabel.Text = "[None]" setContinueEnabled(false) end
|
||||
elseif whichPage == 3 then
|
||||
-- Create Bounding Box
|
||||
alignmentHandles.Visible = false
|
||||
myModel.PrimaryPart = myPrimaryPart
|
||||
infoBox.Text = "Rotate and adjust the model so the green bounding box looks good."
|
||||
if #game.Selection:Get() ~= 1 or game.Selection:Get()[1] ~= myModel then game.Selection:Set({myModel}) end
|
||||
|
||||
setContinueEnabled(true)
|
||||
elseif whichPage == 4 then
|
||||
-- Set Alignment Within Bounding Box
|
||||
infoBox.Text = "Move the green bounding box so your model is aligned correctly inside it."
|
||||
alignToFaceSelection.Visible = false
|
||||
surfaceSelection.Visible = false
|
||||
alignmentHandles.Visible = true
|
||||
if #game.Selection:Get() ~= 1 or game.Selection:Get()[1] ~= myModel then game.Selection:Set({myModel}) end
|
||||
bbPreview.Parent = nil
|
||||
setContinueEnabled(true)
|
||||
elseif whichPage == 5 then
|
||||
-- AutoAlignToFace
|
||||
alignmentHandles.Visible = false
|
||||
if (alignToFaceText ~= "[None]") then alignToFaceSelection.Visible = true end
|
||||
for i = 1, 6 do unjoinableFaceSelections[i].Visible = false end
|
||||
infoBox.Text = "[Optional Step]: Select a side to be \"always facing the wall\"."
|
||||
if #game.Selection:Get() ~= 0 then game.Selection:Set({}) end
|
||||
setContinueEnabled(true)
|
||||
elseif whichPage == 6 then
|
||||
-- Unjoinable Faces
|
||||
alignToFaceSelection.Visible = false
|
||||
for i = 1, 6 do unjoinableFaceSelections[i].Visible = unjoinableFaces[i] end
|
||||
for i = 1, 6 do unstampableFaceSelections[i].Visible = false end
|
||||
infoBox.Text = "[Optional Step]: Select any sides you don't want things to join to when stamping."
|
||||
if #game.Selection:Get() ~= 0 then game.Selection:Set({}) end
|
||||
setContinueEnabled(true)
|
||||
elseif whichPage == 7 then
|
||||
-- Unstampable Faces
|
||||
for i = 1, 6 do unstampableFaceSelections[i].Visible = unstampableFaces[i] end
|
||||
for i = 1, 6 do unjoinableFaceSelections[i].Visible = false end
|
||||
infoBox.Text = "[Optional Step]: Select any sides you don't want to be stampable or have things stamp to."
|
||||
continueButton.Text = "Continue"
|
||||
testButton.Visible = false
|
||||
if #game.Selection:Get() ~= 0 then game.Selection:Set({}) end
|
||||
setContinueEnabled(true)
|
||||
stopStampTest()
|
||||
elseif whichPage == 8 then
|
||||
-- Test it out!
|
||||
for i = 1, 6 do unstampableFaceSelections[i].Visible = false end
|
||||
bbPreview.Parent = nil
|
||||
selectedLabel.Text = myModel.Name
|
||||
infoBox.Text = "Test it out! Click \"Finish\" when it's ready to publish!"
|
||||
continueButton.Text = "Finish"
|
||||
testButton.Visible = true
|
||||
setContinueEnabled(true)
|
||||
end
|
||||
|
||||
if whichPage >=3 and whichPage <= 7 then
|
||||
bbPreviewBox.Visible = true
|
||||
|
||||
if not bbPreviewCoroutine then
|
||||
bbPreviewCoroutine = coroutine.create(updateBBPreview)
|
||||
coroutine.resume(bbPreviewCoroutine)
|
||||
end
|
||||
|
||||
if whichPage > 4 then
|
||||
bbPreview.Parent = game.Workspace
|
||||
if not facePreviewCoroutine then
|
||||
facePreviewCoroutine = coroutine.create(updateFacePreview)
|
||||
coroutine.resume(facePreviewCoroutine)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
stepText.Text = "Step " .. tostring(whichPage) .. " of 8"
|
||||
end
|
||||
|
||||
|
||||
function setContinueEnabled(isEnabled)
|
||||
if isEnabled then
|
||||
continueButton.TextColor3 = Color3.new(1, 1, 1)
|
||||
else
|
||||
continueButton.TextColor3 = Color3.new(.5, .5, .5)
|
||||
end
|
||||
continueEnabled = isEnabled
|
||||
end
|
||||
|
||||
function setBackEnabled(isEnabled)
|
||||
if isEnabled then
|
||||
backButton.TextColor3 = Color3.new(1, 1, 1)
|
||||
else
|
||||
backButton.TextColor3 = Color3.new(.5, .5, .5)
|
||||
end
|
||||
backEnabled = isEnabled
|
||||
end
|
||||
|
||||
function onSelect()
|
||||
print("onSelect")
|
||||
local selected = game.Selection:Get()
|
||||
|
||||
if whichStep == 1 then -- looking for a single model to be selected
|
||||
if #selected == 1 and selected[1] == myModel then return end
|
||||
|
||||
if #selected == 1 and selected[1]:IsA("Model") and selected[1] ~= game.Workspace then
|
||||
myModel = selected[1]
|
||||
myPrimaryPart = nil
|
||||
else
|
||||
myModel = nil
|
||||
myPrimaryPart = nil
|
||||
end
|
||||
refreshPage(1)
|
||||
elseif whichStep == 2 then
|
||||
if #selected == 1 and selected[1] == myPrimaryPart then return end
|
||||
|
||||
if #selected == 1 and selected[1]:IsA("BasePart") and selected[1].Parent == myModel then
|
||||
myPrimaryPart = selected[1]
|
||||
else
|
||||
myPrimaryPart = nil
|
||||
end
|
||||
refreshPage(2)
|
||||
end
|
||||
end
|
||||
|
||||
function On()
|
||||
self:Activate(true)
|
||||
toolbarbutton:SetActive(true)
|
||||
frame.Visible = true
|
||||
|
||||
for w = 0, 0.6, 0.12 do
|
||||
frame.Size = UDim2.new(w, 0, 2*w/3, 0)
|
||||
wait()
|
||||
end
|
||||
|
||||
on = true
|
||||
|
||||
-- connect to the game's selection
|
||||
selectionConnection = game.Selection.SelectionChanged:connect(onSelect)
|
||||
|
||||
refreshPage(whichStep)
|
||||
end
|
||||
|
||||
function Off()
|
||||
toolbarbutton:SetActive(false)
|
||||
|
||||
for w = 0.6, 0, -0.12 do
|
||||
frame.Size = UDim2.new(w, 0, 2*w/3, 0)
|
||||
wait()
|
||||
end
|
||||
|
||||
frame.Visible = false
|
||||
on = false
|
||||
|
||||
if selectionConnection then selectionConnection:disconnect() selectionConnection = nil end
|
||||
|
||||
alignmentHandles.Visible = false
|
||||
surfaceSelection.Visible = false
|
||||
alignToFaceSelection.Visible = false
|
||||
for i = 1, 6 do unstampableFaceSelections[i].Visible = false end
|
||||
for i = 1, 6 do unjoinableFaceSelections[i].Visible = false end
|
||||
|
||||
stopStampTest()
|
||||
|
||||
if whichStep ~= 3 then bbPreviewBox.Visible = false end
|
||||
bbPreview.Parent = nil
|
||||
end
|
||||
|
||||
function resetWizard()
|
||||
bbPreview.Parent = nil
|
||||
bbPreviewBox.Visible = false
|
||||
wait(.5) -- so that we can kill our coroutines safely
|
||||
|
||||
myModel = nil
|
||||
myPrimaryPart = nil
|
||||
whichStep = 1
|
||||
for i = 1, 6 do unstampableFaces[i] = false end
|
||||
for i = 1, 6 do unjoinableFaces[i] = false end
|
||||
alignToFaceText = "[None]"
|
||||
alignmentVect = Vector3.new(0, 0, 0)
|
||||
testButton.Visible = false
|
||||
|
||||
setBackEnabled(false)
|
||||
setContinueEnabled(false)
|
||||
|
||||
alignmentHandles.Visible = false
|
||||
surfaceSelection.Visible = false
|
||||
alignToFaceSelection.Visible = false
|
||||
for i = 1, 6 do unstampableFaceSelections[i].Visible = false unstampableFaces[i] = false end
|
||||
for i = 1, 6 do unjoinableFaceSelections[i].Visible = false unjoinableFaces[i] = false end
|
||||
|
||||
refreshPage(whichStep)
|
||||
end
|
||||
|
||||
function finishModel(model)
|
||||
if alignmentVect.magnitude > .04 then
|
||||
local alignTag = model:FindFirstChild("Justification")
|
||||
if not alignTag then alignTag = Instance.new("Vector3Value") end
|
||||
alignTag.Name = "Justification"
|
||||
alignTag.Value = -alignmentVect + Vector3.new(1, 1, 1)
|
||||
alignTag.Parent = model
|
||||
elseif model:FindFirstChild("Justification") then model.Justification:Remove() end
|
||||
|
||||
if alignToFaceText ~= "[None]" then
|
||||
local autoAlignToFaceTag = model:FindFirstChild("AutoAlignToFace")
|
||||
if not autoAlignToFaceTag then autoAlignToFaceTag = Instance.new("NumberValue") end
|
||||
autoAlignToFaceTag.Name = "AutoAlignToFace"
|
||||
autoAlignToFaceTag.Value = ALIGN_TO_FACE_MAPPING[SURFACE_TO_NUMBER[alignToFaceSelection.TargetSurface]]
|
||||
autoAlignToFaceTag.Parent = model
|
||||
elseif model:FindFirstChild("AutoAlignToFace") then model.AutoAlignToFace:Remove() end
|
||||
|
||||
local unstampableFaceString = ""
|
||||
local foundOne = false
|
||||
for i = 1, #unstampableFaces do
|
||||
if unstampableFaces[i] then
|
||||
if foundOne then unstampableFaceString = unstampableFaceString .. ", " end
|
||||
unstampableFaceString = unstampableFaceString .. UNSTAMPABLE_FACE_MAPPING[i]
|
||||
foundOne = true
|
||||
end
|
||||
end
|
||||
if foundOne then
|
||||
local unstampableFaceTag = model:FindFirstChild("UnstampableFaces")
|
||||
if not unstampableFaceTag then unstampableFaceTag = Instance.new("StringValue") end
|
||||
unstampableFaceTag.Name = "UnstampableFaces"
|
||||
unstampableFaceTag.Value = unstampableFaceString
|
||||
unstampableFaceTag.Parent = model
|
||||
elseif model:FindFirstChild("UnstampableFaces") then model.UnstampableFaces:Remove() end
|
||||
|
||||
local unjoinableFaceString = ""
|
||||
foundOne = false
|
||||
for i = 1, #unjoinableFaces do
|
||||
if unjoinableFaces[i] then
|
||||
if foundOne then unjoinableFaceString = unjoinableFaceString .. ", " end
|
||||
unjoinableFaceString = unjoinableFaceString .. UNSTAMPABLE_FACE_MAPPING[i]
|
||||
foundOne = true
|
||||
end
|
||||
end
|
||||
if foundOne then
|
||||
local unjoinableFaceTag = model:FindFirstChild("UnjoinableFaces")
|
||||
if not unjoinableFaceTag then unjoinableFaceTag = Instance.new("StringValue") end
|
||||
unjoinableFaceTag.Name = "UnjoinableFaces"
|
||||
unjoinableFaceTag.Value = unjoinableFaceString
|
||||
unjoinableFaceTag.Parent = model
|
||||
elseif model:FindFirstChild("UnjoinableFaces") then model.UnjoinableFaces:Remove() end
|
||||
end
|
||||
|
||||
function goBack()
|
||||
if backEnabled then
|
||||
whichStep = whichStep - 1
|
||||
if whichStep == 1 then setBackEnabled(false) end
|
||||
setContinueEnabled(true)
|
||||
refreshPage(whichStep)
|
||||
end
|
||||
end
|
||||
|
||||
function goForwards()
|
||||
if continueEnabled then
|
||||
whichStep = whichStep + 1
|
||||
setContinueEnabled(false)
|
||||
setBackEnabled(true)
|
||||
if whichStep == 9 then
|
||||
stopStampTest()
|
||||
finishModel(myModel)
|
||||
resetWizard()
|
||||
--Off() -- if we want to auto-close the wizard after we finish
|
||||
else
|
||||
if whichStep == 2 then
|
||||
-- upon selecting a model, we propagate all other values with the current model's values
|
||||
loadMetaData(myModel)
|
||||
end
|
||||
|
||||
refreshPage(whichStep)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
------
|
||||
--GUI-
|
||||
------
|
||||
--screengui
|
||||
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
|
||||
--frame
|
||||
frame = Instance.new("Frame", g)
|
||||
frame.Position = UDim2.new(0.2, 20, 0, 0)
|
||||
frame.Size = UDim2.new(0.6, -40, .4, 0)
|
||||
frame.Style = Enum.FrameStyle.RobloxRound
|
||||
frame.BackgroundTransparency = 0.5
|
||||
frame.Visible = false
|
||||
|
||||
titleText = Instance.new("TextLabel", frame)
|
||||
titleText.Name = "Title"
|
||||
titleText.BackgroundTransparency = 1
|
||||
titleText.Font = Enum.Font.ArialBold
|
||||
titleText.FontSize = Enum.FontSize.Size24
|
||||
titleText.Size = UDim2.new(1, 0, 0, 24)
|
||||
titleText.Text = "Stamper Model Maker"
|
||||
titleText.TextColor3 = Color3.new(1,1,1)
|
||||
titleText.TextYAlignment = Enum.TextYAlignment.Center
|
||||
|
||||
stepText = titleText:Clone()
|
||||
stepText.Name = "StepsLabel"
|
||||
stepText.Text = "Step 1 of 6"
|
||||
stepText.Position = UDim2.new(0, -5, .81, 0)
|
||||
stepText.Font = Enum.Font.Arial
|
||||
stepText.Parent = frame
|
||||
|
||||
infoBox = Instance.new("TextLabel", frame)
|
||||
infoBox.Name = "InfoBox"
|
||||
infoBox.Font = Enum.Font.Arial
|
||||
infoBox.FontSize = Enum.FontSize.Size24
|
||||
infoBox.Size = UDim2.new(1,0,0,24)
|
||||
infoBox.Position = UDim2.new(0, 0, 0.15, 0)
|
||||
infoBox.BackgroundTransparency = 0.75
|
||||
infoBox.TextColor3 = Color3.new(1,1,1)
|
||||
infoBox.Text = "Select the model you want to turn into a stamper part."
|
||||
infoBox.TextWrap = false
|
||||
infoBox.TextXAlignment = Enum.TextXAlignment.Left
|
||||
infoBox.TextYAlignment = Enum.TextYAlignment.Top
|
||||
infoBox.Visible = true
|
||||
|
||||
modelInfoFrame = Instance.new("Frame", frame)
|
||||
modelInfoFrame.Style = Enum.FrameStyle.RobloxRound
|
||||
modelInfoFrame.Name = "ModelInfo"
|
||||
modelInfoFrame.Position = UDim2.new(.395, 0, .325, 0)
|
||||
modelInfoFrame.Size = UDim2.new(.2, 0, .4, 0)
|
||||
|
||||
selectedLabel = stepText:Clone()
|
||||
selectedLabel.Name = "SelectionLabel"
|
||||
selectedLabel.Text = "[None]"
|
||||
selectedLabel.Position = UDim2.new(0, 0, .35, 0)
|
||||
selectedLabel.Parent = modelInfoFrame
|
||||
|
||||
backButton = Instance.new("TextButton", frame)
|
||||
backButton.Name = "Back"
|
||||
backButton.Font = Enum.Font.Arial
|
||||
backButton.FontSize = Enum.FontSize.Size18
|
||||
backButton.Size = UDim2.new(0, 200, 0, 50)
|
||||
backButton.Position = UDim2.new(0, 1, 1, -55)
|
||||
backButton.BackgroundTransparency = 1
|
||||
backButton.Style = Enum.ButtonStyle.RobloxButtonDefault
|
||||
backButton.Text = "Back"
|
||||
backButton.TextColor3 = Color3.new(0.5, 0.5, 0.5)
|
||||
backButton.MouseButton1Click:connect(goBack)
|
||||
|
||||
continueButton = backButton:Clone()
|
||||
continueButton.Name = "Continue"
|
||||
continueButton.Text = "Continue"
|
||||
continueButton.Position = UDim2.new(1, -200, 1, -55)
|
||||
continueButton.MouseButton1Click:connect(goForwards)
|
||||
continueButton.Parent = frame
|
||||
|
||||
testButton = backButton:Clone()
|
||||
testButton.Name = "Test"
|
||||
testButton.Text = "Test it!"
|
||||
testButton.TextColor3 = Color3.new(1, 1, 1)
|
||||
testButton.Position = UDim2.new(1, -200, 1, -110)
|
||||
testButton.MouseButton1Click:connect(testStamperModel)
|
||||
testButton.Visible = false
|
||||
testButton.Parent = frame
|
||||
|
||||
bbPreviewBox = Instance.new("SelectionBox")
|
||||
bbPreviewBox.Color = BrickColor.new("Lime green")
|
||||
bbPreviewBox.Adornee = bbPreview
|
||||
bbPreviewBox.Visible = false
|
||||
bbPreviewBox.Parent = frame
|
||||
|
||||
alignmentHandles = Instance.new("Handles")
|
||||
alignmentHandles.Visible = false
|
||||
alignmentHandles.Adornee = bbPreview
|
||||
alignmentHandles.Parent = frame
|
||||
alignmentHandles.MouseDrag:connect(dragBB)
|
||||
alignmentHandles.Color = BrickColor.new("Lime green")
|
||||
|
||||
surfaceSelection = Instance.new("SurfaceSelection")
|
||||
surfaceSelection.Name = "SurfaceSelection"
|
||||
surfaceSelection.Color = BrickColor.new("White")
|
||||
surfaceSelection.Transparency = .8
|
||||
surfaceSelection.Visible = false
|
||||
surfaceSelection.Adornee = bbPreview
|
||||
|
||||
alignToFaceSelection = surfaceSelection:Clone()
|
||||
alignToFaceSelection.Name = "AlignToFaceSelection"
|
||||
alignToFaceSelection.Color = BrickColor.new("Cyan")
|
||||
|
||||
unstampableFaceSelections = {}
|
||||
for i = 1, 6 do
|
||||
local newUnstampableFaceSelection = alignToFaceSelection:Clone()
|
||||
newUnstampableFaceSelection.Name = "UnstampableFaceSelection"
|
||||
newUnstampableFaceSelection.Color = BrickColor.new("Bright red")
|
||||
newUnstampableFaceSelection.TargetSurface = SURFACE_FROM_NUMBER[i]
|
||||
newUnstampableFaceSelection.Parent = frame
|
||||
table.insert(unstampableFaceSelections, newUnstampableFaceSelection)
|
||||
end
|
||||
|
||||
unjoinableFaceSelections = {}
|
||||
for i = 1, 6 do
|
||||
local newUnjoinableFaceSelection = alignToFaceSelection:Clone()
|
||||
newUnjoinableFaceSelection.Name = "UnjoinableFaceSelection"
|
||||
newUnjoinableFaceSelection.Color = BrickColor.new("Deep orange")
|
||||
newUnjoinableFaceSelection.TargetSurface = SURFACE_FROM_NUMBER[i]
|
||||
newUnjoinableFaceSelection.Parent = frame
|
||||
table.insert(unjoinableFaceSelections, newUnjoinableFaceSelection)
|
||||
end
|
||||
|
||||
alignToFaceSelection.Parent = frame
|
||||
surfaceSelection.Parent = frame
|
||||
|
||||
|
||||
-- load the lib'ary!
|
||||
RbxStamper = LoadLibrary("RbxStamper")
|
||||
|
||||
if not RbxStamper then
|
||||
print("Error: RbxStamper Library Load Fail! Returning")
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--------------------------
|
||||
--SUCCESSFUL LOAD MESSAGE-
|
||||
--------------------------
|
||||
loaded = true
|
||||
print("StamperWizard Plugin Loaded")
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,748 @@
|
||||
--[[
|
||||
This tool is designed to create bodies of water in terrain, below is an explanation of all the parameters that are adjustable (also accessible from the help menu in the tool)
|
||||
|
||||
Length: Adjusts the z-axis size of the lake
|
||||
Width: Adjusts the x-axis size of the lake
|
||||
Depth: Adjusts the y-axis size of the lake, this size is always from the currently selected terrain cell down
|
||||
|
||||
Curvature:
|
||||
Approximates a spherical or ellipsoid shape that curves the lake inward. 100% is the maximum amount of curve (like a perfectly round sphere), 0% is no curve (like an above-ground swimming pool)
|
||||
Water Level:
|
||||
The percentage to the top of the lake that is full of water (this is a percentage of the depth slider, not volume of the lake)
|
||||
|
||||
Lake Types:
|
||||
Elliptical: draws a lake that approximates an ellpsoid
|
||||
Circular: the same thing as Elliptical, except it locks the length and width sliders so they are always the same.
|
||||
Rectangular: creates a lake to the exact shape of what is selected, which is always rectangular
|
||||
|
||||
Water Type:
|
||||
These are directions that the water force will be applied to. All cardinal directions are allows (x,y,z and their negatives)
|
||||
|
||||
Water Force:
|
||||
The amount of force to be applied to the specified water type. Current choices are None, Small, Medium, Strong, and Max.
|
||||
|
||||
Create Walls:
|
||||
builds walls around the the lake when created, so all water is encapsulated on its sides by a material (material selected by Material Selection scrollbar)
|
||||
|
||||
Remove Above:
|
||||
Removes cells that are above the lake to be generated. The cells to be removed are the ones inside the red selection box.
|
||||
|
||||
Material Selection:
|
||||
The material used to create walls, if this option is selected.
|
||||
]]
|
||||
|
||||
-- Local function definitions
|
||||
local c = game.Workspace.Terrain
|
||||
local SetCell = c.SetCell
|
||||
local SetWaterCell = c.SetWaterCell
|
||||
local SetCells = c.SetCells
|
||||
local GetCell = c.GetCell
|
||||
local WorldToCellPreferSolid = c.WorldToCellPreferSolid
|
||||
local CellCenterToWorld = c.CellCenterToWorld
|
||||
local AutoWedge = c.AutowedgeCell
|
||||
local AutoWedgeCells = c.AutowedgeCells
|
||||
local maxYExtents = c.MaxExtents.Max.Y
|
||||
|
||||
|
||||
-- UI variables
|
||||
local dragBar = nil
|
||||
local containerFrame = nil
|
||||
local buttonDownTick = nil
|
||||
local doubleClickTime = 0.4
|
||||
local didCancelCreate = false
|
||||
local loadingFrame, updateLoadingGuiPercent, cancelLoadingPressed = nil
|
||||
local currentSelection = nil
|
||||
local groundSelection = nil
|
||||
local shapes = {"Elliptical", "Circular", "Rectangular"}
|
||||
local waterTypes = {"NegX","X","NegY","Y","NegZ","Z"}
|
||||
local waterForces = {"None", "Small", "Medium", "Strong", "Max"}
|
||||
|
||||
-----------------
|
||||
--DEFAULT VALUES-
|
||||
-----------------
|
||||
local loaded = false
|
||||
local on = false
|
||||
local debounce = false
|
||||
local lastCell = nil
|
||||
|
||||
local zeroVector = Vector3.new(0,0,0)
|
||||
local selectionUpdateFunc, destroyFunc = nil
|
||||
local selectionGroundUpdateFunc, destroyGroundFunc = nil
|
||||
|
||||
-- values exposed to user
|
||||
local currMaterial = Enum.CellMaterial.Grass
|
||||
local radius = 15
|
||||
local depth = 15
|
||||
local xWidth = 15
|
||||
local zWidth = 15
|
||||
local waterLevel = 1.01
|
||||
local percentOfSphere = 1.01
|
||||
local createWalls = true
|
||||
local removeAbove = true
|
||||
local currLakeShape = nil
|
||||
local currWaterType = 0
|
||||
local currWaterForce = 0
|
||||
|
||||
--load libraries
|
||||
local RbxGui = LoadLibrary("RbxGui")
|
||||
local RbxUtil = LoadLibrary("RbxUtility")
|
||||
|
||||
---------------
|
||||
--PLUGIN SETUP-
|
||||
---------------
|
||||
self = PluginManager():CreatePlugin()
|
||||
self.Deactivation:connect(function() Off() end)
|
||||
|
||||
mouse = self:GetMouse()
|
||||
mouse.Button1Down:connect(function() onMouseButtonDown() end)
|
||||
mouse.Button1Up:connect(function() onMouseButtonUp() end)
|
||||
mouse.Move:connect(function() mouseMove() end)
|
||||
|
||||
toolbar = self:CreateToolbar("Water")
|
||||
toolbarbutton = toolbar:CreateButton("", "Lake Creator", "lake.png")
|
||||
toolbarbutton.Click:connect(function()
|
||||
if on then
|
||||
Off()
|
||||
elseif loaded then
|
||||
On()
|
||||
end
|
||||
end)
|
||||
|
||||
-----------------------
|
||||
--FUNCTION DEFINITIONS-
|
||||
-----------------------
|
||||
|
||||
-- srs translation from region3 to region3int16
|
||||
function Region3ToRegion3int16(region3)
|
||||
local theLowVec = region3.CFrame.p - (region3.Size/2) + Vector3.new(2,2,2)
|
||||
local lowCell = WorldToCellPreferSolid(c,theLowVec)
|
||||
|
||||
local theHighVec = region3.CFrame.p + (region3.Size/2) - Vector3.new(2,2,2)
|
||||
local highCell = WorldToCellPreferSolid(c, theHighVec)
|
||||
|
||||
local highIntVec = Vector3int16.new(highCell.x,highCell.y,highCell.z)
|
||||
local lowIntVec = Vector3int16.new(lowCell.x,lowCell.y,lowCell.z)
|
||||
|
||||
return Region3int16.new(lowIntVec,highIntVec)
|
||||
end
|
||||
|
||||
function cancelLakeCreate()
|
||||
loadingFrame.Visible = false
|
||||
didCancelCreate = true
|
||||
end
|
||||
|
||||
function makeRectangularLake(x,y,z)
|
||||
-- first, find region we need to cut out
|
||||
local selectionToCutout = currentSelection
|
||||
local selectionToFill = groundSelection
|
||||
local innerRegion = Region3.new(( selectionToFill.CFrame.p - selectionToFill.Size/2) + Vector3.new(4,4,4),
|
||||
( selectionToFill.CFrame.p + selectionToFill.Size/2) - Vector3.new(4,0,4))
|
||||
|
||||
|
||||
-- first, clear out all cells around selection if user specified so
|
||||
if removeAbove then
|
||||
SetCells(c,Region3ToRegion3int16(selectionToCutout),0,0,0)
|
||||
end
|
||||
|
||||
-- Make walls around lake if we specified so
|
||||
if createWalls then
|
||||
-- now fill in all cells with our border material
|
||||
SetCells(c,Region3ToRegion3int16(selectionToFill), currMaterial,0,0)
|
||||
-- cutout the cells in the lake
|
||||
SetCells(c,Region3ToRegion3int16(innerRegion), 0,0,0)
|
||||
else
|
||||
SetCells(c,Region3ToRegion3int16(innerRegion),0,0,0)
|
||||
end
|
||||
|
||||
-- last, fill with water to the appropriate level
|
||||
local waterHeight = ((selectionToFill.CFrame.p.y + selectionToFill.Size.y/2) - (selectionToFill.CFrame.p.y - selectionToFill.Size.y/2)) * waterLevel
|
||||
|
||||
local lowerVec,higherVec = nil
|
||||
if createWalls then
|
||||
lowerVec = innerRegion.CFrame.p - innerRegion.Size/2
|
||||
higherVec = innerRegion.CFrame.p + innerRegion.Size/2
|
||||
else
|
||||
lowerVec = selectionToFill.CFrame.p - selectionToFill.Size/2
|
||||
higherVec = selectionToFill.CFrame.p + selectionToFill.Size/2
|
||||
end
|
||||
|
||||
higherVec = Vector3.new(higherVec.x, lowerVec.y + waterHeight - 4, higherVec.z)
|
||||
local waterRegion = Region3ToRegion3int16(Region3.new(lowerVec,higherVec))
|
||||
-- todo: make this call do force/direction when can be mass set
|
||||
SetCells(c, waterRegion, Enum.CellMaterial.Water, 0, 0)
|
||||
for k = lowerVec.z + 2,higherVec.z - 2,4 do
|
||||
for j = lowerVec.y + 2,higherVec.y - 2,4 do
|
||||
for i = lowerVec.x + 2, higherVec.x - 2,4 do
|
||||
local cellPos = WorldToCellPreferSolid(c,Vector3.new(i,j,k))
|
||||
SetWaterCell(c,cellPos.x,cellPos.y,cellPos.z,currWaterForce,currWaterType)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function drillDownColumn(x,y,z, percentInEllipsoid, lowY, absoluteWaterLine)
|
||||
local waterOrEmptyCells = 0
|
||||
if percentInEllipsoid <= 1 then
|
||||
waterOrEmptyCells = (math.pow(percentInEllipsoid,2) * depth * percentOfSphere) + (math.pow(percentInEllipsoid,2) * percentOfSphere)
|
||||
waterOrEmptyCells = math.max(depth - waterOrEmptyCells,0)
|
||||
end
|
||||
local waterCells = math.max(absoluteWaterLine - (y - waterOrEmptyCells),0)
|
||||
local emptyCells = waterOrEmptyCells - waterCells
|
||||
|
||||
if waterCells > 0 then
|
||||
local emptyCellsLowY = math.max(y - emptyCells - waterCells + 1,2)
|
||||
-- todo: make this call do force/direction when can be mass set
|
||||
SetCells(c,Region3int16.new(Vector3int16.new(x,emptyCellsLowY,z),Vector3int16.new(x, y - emptyCells, z)),Enum.CellMaterial.Water,0,0)
|
||||
for i = emptyCellsLowY, y - emptyCells do
|
||||
SetWaterCell(c,x,i,z,currWaterForce,currWaterType)
|
||||
end
|
||||
end
|
||||
if emptyCells > 0 then
|
||||
local emptyCellsLowY = math.max(y - emptyCells + 1,2)
|
||||
SetCells(c,Region3int16.new(Vector3int16.new(x,emptyCellsLowY,z),Vector3int16.new(x,y,z)),Enum.CellMaterial.Empty,0,0)
|
||||
end
|
||||
if createWalls then
|
||||
local materialCells = math.max(depth - waterOrEmptyCells,0)
|
||||
if materialCells > 0 then
|
||||
SetCells(c,Region3int16.new(Vector3int16.new(x,math.max(lowY - 1,1),z),Vector3int16.new(x,lowY + (materialCells - 1),z)),currMaterial,0,0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function makeEllipsoidLake(x,y,z)
|
||||
local startTime = tick()
|
||||
|
||||
-- check to see if we should remove terrain above
|
||||
local topSelection = currentSelection
|
||||
local bottomSelection = groundSelection
|
||||
if topSelection ~= bottomSelection then
|
||||
local removeRegion = Region3.new(bottomSelection.CFrame.p + Vector3.new(-bottomSelection.Size.x/2,bottomSelection.Size.y/2,-bottomSelection.Size.z/2), topSelection.CFrame.p + topSelection.Size/2)
|
||||
SetCells(c, Region3ToRegion3int16(removeRegion), 0, 0, 0)
|
||||
end
|
||||
|
||||
-- reset our processing gui
|
||||
updateLoadingGuiPercent(0)
|
||||
-- calculate how many steps we will use for processing (For updating processing gui)
|
||||
local totalSteps = (xWidth*2 + 3) * (zWidth*2 + 3)
|
||||
totalSteps = totalSteps * 2
|
||||
local currStep = 0
|
||||
local percentDone = 0
|
||||
|
||||
-- some variables we can precompute before O(n^2) loop
|
||||
local lowY = y - (depth - 1)
|
||||
local absoluteWaterLine = y - (depth * (1 - waterLevel))
|
||||
|
||||
-- loop thru xz plane to determine what cells to nuke/fill
|
||||
for k = z - (zWidth + 1), z + (zWidth + 1) do
|
||||
-- used in inner loop, but set here for effeciency
|
||||
local zEllipsoidComponent = math.pow((z - k)/zWidth,2)
|
||||
for i = x - (xWidth + 1), x + (xWidth + 1) do
|
||||
-- check to see if we have canceled, if not keep going
|
||||
if didCancelCreate then
|
||||
didCancelCreate = false
|
||||
return
|
||||
end
|
||||
|
||||
-- using ellipsoid equation to detemine if cell should be deleted
|
||||
local percentInEllipsoid = math.pow((x - i)/xWidth,2) + zEllipsoidComponent
|
||||
|
||||
-- at each xz coordinate, drill down depth and set cells in larger chunks
|
||||
drillDownColumn(i,y,k, percentInEllipsoid, lowY, absoluteWaterLine)
|
||||
|
||||
-- update our processing gui
|
||||
currStep = currStep + 1
|
||||
percentDone = currStep/totalSteps
|
||||
updateLoadingGuiPercent(percentDone)
|
||||
|
||||
-- do a calculated wait every once and awhile (stops studio from hanging)
|
||||
currStep = currStep + 1
|
||||
local first, fraction = math.modf(currStep/1000)
|
||||
if fraction == 0 then wait() end
|
||||
end
|
||||
if not loadingFrame.Visible then
|
||||
loadingFrame.Visible = (tick() - startTime) > 0.5 and percentDone < 0.4
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- makes a crater at point (x, y, z) in cluster c
|
||||
function makeCrater(x, y, z)
|
||||
-- we need to autowedge a bit outside of selection, allows for smoother terain around lakes
|
||||
local autoWedgeSelection = Region3.new( (groundSelection.CFrame.p - groundSelection.Size/2) - Vector3.new(8,8,8),
|
||||
(groundSelection.CFrame.p + groundSelection.Size/2) + Vector3.new(8,8,8))
|
||||
|
||||
disablePreview()
|
||||
|
||||
|
||||
if currLakeShape == "Rectangular" then -- simply cut out the selection box for the lake
|
||||
makeRectangularLake(x, y, z)
|
||||
else -- we want something to approximate curves for our lake
|
||||
makeEllipsoidLake(x, y, z)
|
||||
end
|
||||
|
||||
AutoWedgeCells(c,Region3ToRegion3int16(autoWedgeSelection))
|
||||
|
||||
loadingFrame.Visible = false
|
||||
end
|
||||
|
||||
function disablePreview()
|
||||
if destroyFunc then
|
||||
destroyFunc()
|
||||
selectionUpdateFunc = nil
|
||||
destroyGroundFunc()
|
||||
selectionGroundUpdateFunc = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- creates selection boxes around the areas that will be affected by lake creator
|
||||
function createSelections()
|
||||
selectionUpdateFunc, destroyFunc = RbxUtil.SelectTerrainRegion(Region3.new(zeroVector,zeroVector),
|
||||
BrickColor.new("Really red"),
|
||||
true,
|
||||
game.CoreGui)
|
||||
selectionGroundUpdateFunc, destroyGroundFunc = RbxUtil.SelectTerrainRegion( Region3.new(zeroVector,zeroVector),
|
||||
BrickColor.new("Toothpaste"),
|
||||
true,
|
||||
game.CoreGui)
|
||||
end
|
||||
|
||||
-- moves selections boxes to the current cell region
|
||||
function updateSelections()
|
||||
if not selectionUpdateFunc then
|
||||
createSelections()
|
||||
return
|
||||
end
|
||||
|
||||
if not lastCell then
|
||||
lastCell = WorldToCellPreferSolid(c, mouse.Hit.p)
|
||||
end
|
||||
|
||||
local selectionBelowMinYExtents = lastCell.y - depth + 1 <= 0
|
||||
|
||||
local startPos = CellCenterToWorld(c, lastCell.x,lastCell.y,lastCell.z)
|
||||
|
||||
local minOverallVec = nil
|
||||
if createWalls then
|
||||
minOverallVec = startPos - Vector3.new(xWidth*4,(depth - 1) *4,zWidth*4) - Vector3.new(2,6,2)
|
||||
else
|
||||
minOverallVec = startPos - Vector3.new(xWidth*4,(depth - 1) *4,zWidth*4) - Vector3.new(2,2,2)
|
||||
end
|
||||
local minDeletionVec = startPos - Vector3.new(xWidth*4,0,zWidth*4) - Vector3.new(2,-2.5,2)
|
||||
local maxOverallVec = startPos + Vector3.new(xWidth*4,(depth)*4,zWidth*4) + Vector3.new(2,2,2)
|
||||
local maxGroundVec = startPos + Vector3.new(xWidth*4,0,zWidth*4) + Vector3.new(2,2,2)
|
||||
|
||||
if selectionBelowMinYExtents then
|
||||
|
||||
local yMin = WorldToCellPreferSolid(c, Vector3.new(0,1,0)) + Vector3.new(2,2,2)
|
||||
minOverallVec = Vector3.new(minOverallVec.x,yMin,minOverallVec.z)
|
||||
end
|
||||
|
||||
if removeAbove then
|
||||
currentSelection = Region3.new(minDeletionVec, maxOverallVec)
|
||||
selectionUpdateFunc(currentSelection)
|
||||
groundSelection = Region3.new(minOverallVec, maxGroundVec)
|
||||
selectionGroundUpdateFunc(groundSelection)
|
||||
else
|
||||
currentSelection = Region3.new(zeroVector,zeroVector)
|
||||
selectionUpdateFunc(currentSelection)
|
||||
groundSelection = Region3.new(minOverallVec, maxGroundVec)
|
||||
selectionGroundUpdateFunc(groundSelection)
|
||||
end
|
||||
end
|
||||
|
||||
function onMouseButtonDown()
|
||||
buttonDownTick = tick()
|
||||
end
|
||||
|
||||
function onMouseButtonUp()
|
||||
if tick() - buttonDownTick < doubleClickTime then
|
||||
onClicked()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function onClicked()
|
||||
if on and not debounce then
|
||||
debounce = true
|
||||
local cellPos = WorldToCellPreferSolid(c, mouse.Hit.p)
|
||||
local x = cellPos.x
|
||||
local y = cellPos.y
|
||||
local z = cellPos.z
|
||||
|
||||
makeCrater(x, y, z)
|
||||
debounce = false
|
||||
end
|
||||
end
|
||||
|
||||
function mouseMove()
|
||||
if on then
|
||||
if not mouse.Target then disablePreview() return end
|
||||
if debounce then return end
|
||||
|
||||
local newCell = WorldToCellPreferSolid(c, mouse.Hit.p)
|
||||
if newCell == lastCell then return end
|
||||
lastCell = newCell
|
||||
|
||||
updateSelections()
|
||||
end
|
||||
end
|
||||
|
||||
function On()
|
||||
self:Activate(true)
|
||||
toolbarbutton:SetActive(true)
|
||||
dragBar.Visible = true
|
||||
didCancelCreate = false
|
||||
on = true
|
||||
end
|
||||
|
||||
function Off()
|
||||
toolbarbutton:SetActive(false)
|
||||
dragBar.Visible = false
|
||||
disablePreview()
|
||||
cancelLakeCreate()
|
||||
on = false
|
||||
end
|
||||
|
||||
function createMenuButton(size,position,text,fontsize,name,parent)
|
||||
local button = Instance.new("TextButton",parent)
|
||||
button.AutoButtonColor = false
|
||||
button.Name = name
|
||||
button.BackgroundTransparency = 1
|
||||
button.Position = position
|
||||
button.Size = size
|
||||
button.Font = Enum.Font.ArialBold
|
||||
button.FontSize = fontsize
|
||||
button.Text = text
|
||||
button.TextColor3 = Color3.new(1,1,1)
|
||||
button.BorderSizePixel = 0
|
||||
button.BackgroundColor3 = Color3.new(20/255,20/255,20/255)
|
||||
|
||||
button.MouseEnter:connect(function ( )
|
||||
if button.Selected then return end
|
||||
button.BackgroundTransparency = 0
|
||||
end)
|
||||
button.MouseLeave:connect(function ( )
|
||||
if button.Selected then return end
|
||||
button.BackgroundTransparency = 1
|
||||
end)
|
||||
|
||||
return button
|
||||
|
||||
end
|
||||
|
||||
|
||||
------
|
||||
--GUI-
|
||||
------
|
||||
--screengui
|
||||
local g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
||||
g.Name = "LakeToolGui"
|
||||
|
||||
dragBar, containerFrame, helpFrame, closeEvent = RbxGui.CreatePluginFrame("Lake Creator",UDim2.new(0,163,0,400),UDim2.new(0,0,0,0),true,g)
|
||||
dragBar.Visible = false
|
||||
closeEvent.Event:connect(function ( )
|
||||
Off()
|
||||
end)
|
||||
|
||||
helpFrame.Size = UDim2.new(0,300,0,552)
|
||||
|
||||
local helpFirstText = Instance.new("TextLabel",helpFrame)
|
||||
helpFirstText.Name = "HelpText"
|
||||
helpFirstText.Font = Enum.Font.ArialBold
|
||||
helpFirstText.FontSize = Enum.FontSize.Size12
|
||||
helpFirstText.TextColor3 = Color3.new(227/255,227/255,227/255)
|
||||
helpFirstText.TextXAlignment = Enum.TextXAlignment.Left
|
||||
helpFirstText.TextYAlignment = Enum.TextYAlignment.Top
|
||||
helpFirstText.Position = UDim2.new(0,4,0,4)
|
||||
helpFirstText.Size = UDim2.new(1,-8,0,177)
|
||||
helpFirstText.BackgroundTransparency = 1
|
||||
helpFirstText.TextWrap = true
|
||||
helpFirstText.Text = "Length: Adjusts the z-axis size of the lake\nWidth: Adjusts the x-axis size of the lake\nDepth: Adjusts the y-axis size of the lake, this size is always from the currently selected terrain cell down\n\nCurvature: \nApproximates a spherical or ellipsoid shape that curves the lake inward. 100% is the maximum amount of curve (like a perfectly round sphere), 0% is no curve (like an above-ground swimming pool)\nWater Level:\nThe percentage to the top of the lake that is full of water (this is a percentage of the depth slider, not volume of the lake)"
|
||||
|
||||
local helpSecondText = helpFirstText:clone()
|
||||
helpSecondText.Name = "HelpSecondText"
|
||||
helpSecondText.Position = UDim2.new(0,0,1,0)
|
||||
helpSecondText.Size = UDim2.new(1,0,0,212)
|
||||
helpSecondText.Text = "Lake Types:\nElliptical: draws a lake that approximates an ellpsoid\nCircular: the same thing as Elliptical, except it locks the length and width sliders so they are always the same.\nRectangular: creates a lake to the exact shape of what is selected, which is always rectangular\n\nWater Type:\nThese are directions that the water force will be applied to. All cardinal directions are allows (x,y,z and their negatives)\n\nWater Force: \nThe amount of force to be applied to the specified water type. Current choices are None, Small, Medium, Strong, and Max."
|
||||
helpSecondText.Parent = helpFirstText
|
||||
|
||||
local helpThirdText = helpSecondText:clone()
|
||||
helpThirdText.Size = UDim2.new(1,0,0,159)
|
||||
helpThirdText.Name = "HelpThirdText"
|
||||
helpThirdText.Text = "Create Walls: \nbuilds walls around the the lake when created, so all water is encapsulated on its sides by a material (material selected by Material Selection scrollbar)\n\nRemove Above: \nRemoves cells that are above the lake to be generated. The cells to be removed are the ones inside the red selection box.\n\nMaterial Selection: \nThe material used to create walls, if this option is selected."
|
||||
helpThirdText.Parent = helpSecondText
|
||||
|
||||
local linkImage = Instance.new("ImageLabel",containerFrame)
|
||||
linkImage.Name = "LinkImage"
|
||||
linkImage.BackgroundTransparency = 1
|
||||
linkImage.Visible = false
|
||||
linkImage.Size = UDim2.new(0,15,0,15)
|
||||
linkImage.Position = UDim2.new(0,120,0,51)
|
||||
game:GetService("ContentProvider"):Preload("http://gametest.watrbx.wtf/asset/?id=129724452")
|
||||
linkImage.Image = "http://gametest.watrbx.wtf/asset/?id=129724452" --todo: put this in a better spot
|
||||
|
||||
--current width display label
|
||||
local lengthLabel = Instance.new("TextLabel", containerFrame)
|
||||
lengthLabel.Name = "LengthTextLabel"
|
||||
lengthLabel.Position = UDim2.new(0, 8, 0, 10)
|
||||
lengthLabel.Size = UDim2.new(0, 67, 0, 14)
|
||||
lengthLabel.Text = ""
|
||||
lengthLabel.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
lengthLabel.Font = Enum.Font.ArialBold
|
||||
lengthLabel.FontSize = Enum.FontSize.Size14
|
||||
lengthLabel.TextXAlignment = Enum.TextXAlignment.Left
|
||||
lengthLabel.BackgroundTransparency = 1
|
||||
|
||||
|
||||
local lengthSliderPosition, widthSliderPosition, widthSliderGui, lengthSliderGui = nil
|
||||
|
||||
--length slider
|
||||
lengthSliderGui, lengthSliderPosition = RbxGui.CreateSlider(128, 0, UDim2.new(0,0,0,0))
|
||||
lengthSliderGui.Parent = containerFrame
|
||||
lengthSliderGui.Position = UDim2.new(0,1,0,26)
|
||||
lengthSliderGui.Size = UDim2.new(0,160,0,20)
|
||||
local lengthBar = lengthSliderGui:FindFirstChild("Bar")
|
||||
lengthBar.Size = UDim2.new(1, -20, 0, 5)
|
||||
lengthBar.Position = UDim2.new(0,10,0.5,-2)
|
||||
lengthSliderPosition.Changed:connect(function()
|
||||
zWidth = lengthSliderPosition.Value
|
||||
lengthLabel.Text = "Length: ".. zWidth
|
||||
if currLakeShape == "Circular" then
|
||||
widthSliderPosition.Value = zWidth
|
||||
end
|
||||
end)
|
||||
lengthSliderPosition.Value = zWidth
|
||||
|
||||
--current width display label
|
||||
local widthLabel = Instance.new("TextLabel", containerFrame)
|
||||
widthLabel.Name = "WidthTextLabel"
|
||||
widthLabel.Position = UDim2.new(0, 8, 0, 51)
|
||||
widthLabel.Size = UDim2.new(0, 59, 0, 14)
|
||||
widthLabel.Text = ""
|
||||
widthLabel.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
widthLabel.Font = Enum.Font.ArialBold
|
||||
widthLabel.FontSize = Enum.FontSize.Size14
|
||||
widthLabel.TextXAlignment = Enum.TextXAlignment.Left
|
||||
widthLabel.BackgroundTransparency = 1
|
||||
|
||||
--width slider
|
||||
widthSliderGui, widthSliderPosition = RbxGui.CreateSlider(128,0, UDim2.new(0,0,0,0))
|
||||
widthSliderGui.Parent = containerFrame
|
||||
widthSliderGui.Position = UDim2.new(0,1,0,67)
|
||||
widthSliderGui.Size = UDim2.new(0,160,0,20)
|
||||
local widthBar = widthSliderGui:FindFirstChild("Bar")
|
||||
widthBar.Size = UDim2.new(1, -20, 0, 5)
|
||||
widthBar.Position = UDim2.new(0,10,0.5,-2)
|
||||
widthSliderPosition.Changed:connect(function()
|
||||
xWidth = widthSliderPosition.Value
|
||||
widthLabel.Text = "Width: " .. xWidth
|
||||
if currLakeShape == "Circular" then
|
||||
lengthSliderPosition.Value = xWidth
|
||||
end
|
||||
end)
|
||||
widthSliderPosition.Value = xWidth
|
||||
|
||||
--current depth factor display label
|
||||
local depthlabel = Instance.new("TextLabel", containerFrame)
|
||||
depthlabel.Name = "DepthTextLabel"
|
||||
depthlabel.Size = UDim2.new(0, 61, 0, 14)
|
||||
depthlabel.Text = ""
|
||||
depthlabel.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
depthlabel.Font = Enum.Font.ArialBold
|
||||
depthlabel.FontSize = Enum.FontSize.Size14
|
||||
depthlabel.Position = UDim2.new(0,8,0,90)
|
||||
depthlabel.Size = UDim2.new(0,61,0,14)
|
||||
depthlabel.TextXAlignment = Enum.TextXAlignment.Left
|
||||
depthlabel.BackgroundTransparency = 1
|
||||
|
||||
--depth factor slider
|
||||
local dfSliderGui, dfSliderPosition = RbxGui.CreateSlider(maxYExtents,0, UDim2.new(0,0,0,0))
|
||||
dfSliderGui.Position = UDim2.new(0,1,0,106)
|
||||
dfSliderGui.Size = UDim2.new(0,160,0,20)
|
||||
dfSliderGui.Parent = containerFrame
|
||||
local dfBar = dfSliderGui:FindFirstChild("Bar")
|
||||
dfBar.Size = UDim2.new(1,-20,0,5)
|
||||
dfBar.Position = UDim2.new(0,10,0.5,-2)
|
||||
dfSliderPosition.Changed:connect(function()
|
||||
depth = dfSliderPosition.Value
|
||||
depthlabel.Text = "Depth: ".. depth
|
||||
end)
|
||||
dfSliderPosition.Value = depth
|
||||
|
||||
-- curvature text label
|
||||
local curvatureLabel = Instance.new("TextLabel", containerFrame)
|
||||
curvatureLabel.Name = "CurvatureTextLabel"
|
||||
curvatureLabel.Size = UDim2.new(0, 106, 0, 14)
|
||||
curvatureLabel.Text = ""
|
||||
curvatureLabel.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
curvatureLabel.Font = Enum.Font.ArialBold
|
||||
curvatureLabel.FontSize = Enum.FontSize.Size14
|
||||
curvatureLabel.Position = UDim2.new(0,8,0,141)
|
||||
curvatureLabel.Size = UDim2.new(0,106,0,14)
|
||||
curvatureLabel.TextXAlignment = Enum.TextXAlignment.Left
|
||||
curvatureLabel.BackgroundTransparency = 1
|
||||
|
||||
--curvature factor slider
|
||||
local curveSliderGui, curveSliderPosition = RbxGui.CreateSlider(101,0, UDim2.new(0,0,0,0))
|
||||
curveSliderGui.Position = UDim2.new(0,1,0,157)
|
||||
curveSliderGui.Size = UDim2.new(0,160,0,20)
|
||||
curveSliderGui.Parent = containerFrame
|
||||
local curveBar = curveSliderGui:FindFirstChild("Bar")
|
||||
curveBar.Size = UDim2.new(1,-20,0,5)
|
||||
curveBar.Position = UDim2.new(0,10,0.5,-2)
|
||||
curveSliderPosition.Changed:connect(function()
|
||||
percentOfSphere = (curveSliderPosition.Value - 1)/100
|
||||
curvatureLabel.Text = "Curvature: ".. tostring(percentOfSphere) * 100 .. "%"
|
||||
end)
|
||||
curveSliderPosition.Value = percentOfSphere * 100
|
||||
|
||||
-- water level text label
|
||||
local waterLevelLabel = Instance.new("TextLabel", containerFrame)
|
||||
waterLevelLabel.Name = "WaterLevelTextLabel"
|
||||
waterLevelLabel.Size = UDim2.new(0.2, 0, 0.35, 0)
|
||||
waterLevelLabel.Text = ""
|
||||
waterLevelLabel.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
waterLevelLabel.Font = Enum.Font.ArialBold
|
||||
waterLevelLabel.FontSize = Enum.FontSize.Size14
|
||||
waterLevelLabel.Position = UDim2.new(0,8,0,180)
|
||||
waterLevelLabel.Size = UDim2.new(0,118,0,14)
|
||||
waterLevelLabel.TextXAlignment = Enum.TextXAlignment.Left
|
||||
waterLevelLabel.BackgroundTransparency = 1
|
||||
|
||||
--depth factor slider
|
||||
local waterLevelSliderGui, waterLevelSliderPosition = RbxGui.CreateSlider(101,0, UDim2.new(0,0,0,0))
|
||||
waterLevelSliderGui.Position = UDim2.new(0,1,0,196)
|
||||
waterLevelSliderGui.Size = UDim2.new(0,160,0,20)
|
||||
waterLevelSliderGui.Parent = containerFrame
|
||||
local waterLevelBar = waterLevelSliderGui:FindFirstChild("Bar")
|
||||
waterLevelBar.Size = UDim2.new(1,-20,0,5)
|
||||
waterLevelBar.Position = UDim2.new(0,10,0.5,-2)
|
||||
waterLevelSliderPosition.Changed:connect(function()
|
||||
waterLevel = (waterLevelSliderPosition.Value - 1)/100
|
||||
waterLevelLabel.Text = "Water Level: ".. tostring(waterLevel) * 100 .. "%"
|
||||
end)
|
||||
waterLevelSliderPosition.Value = waterLevel * 100
|
||||
|
||||
local lakeShapeSelectedFunc = function ( item )
|
||||
currLakeShape = item
|
||||
if currLakeShape == "Circular" then
|
||||
local maxSize = math.max(xWidth,zWidth)
|
||||
lengthSliderPosition.Value = maxSize
|
||||
widthSliderPosition.Value = maxSize
|
||||
linkImage.Visible = true
|
||||
else
|
||||
linkImage.Visible = false
|
||||
end
|
||||
end
|
||||
|
||||
local lakeShape, onShapeSelected = RbxGui.CreateDropDownMenu(shapes,lakeShapeSelectedFunc)
|
||||
onShapeSelected("Elliptical")
|
||||
lakeShape.ZIndex = 2
|
||||
lakeShape.Size = UDim2.new(0,150,0,32)
|
||||
lakeShape.Position = UDim2.new(0,5,0,244)
|
||||
lakeShape.Parent = containerFrame
|
||||
|
||||
local lakeTypeLabel = curvatureLabel:clone()
|
||||
lakeTypeLabel.Name = "LakeTypeLabel"
|
||||
lakeTypeLabel.Text = "Lake Type"
|
||||
lakeTypeLabel.Position = UDim2.new(0, 8, 0, 229)
|
||||
lakeTypeLabel.Size = UDim2.new(0,64,0,14)
|
||||
lakeTypeLabel.Parent = containerFrame
|
||||
|
||||
local waterTypeLabel = lakeTypeLabel:clone()
|
||||
waterTypeLabel.Name = "WaterTypeLabel"
|
||||
waterTypeLabel.Text = "Water Type"
|
||||
waterTypeLabel.Position = UDim2.new(0, 8, 0, 278)
|
||||
waterTypeLabel.Size = UDim2.new(0, 98, 0, 14)
|
||||
waterTypeLabel.Parent = containerFrame
|
||||
|
||||
local waterTypeSelectedFunc = function ( item )
|
||||
currWaterType = item
|
||||
end
|
||||
local waterType, forceWaterType = RbxGui.CreateDropDownMenu(waterTypes,waterTypeSelectedFunc)
|
||||
forceWaterType("NegX")
|
||||
waterType.Size = UDim2.new(0,150,0,32)
|
||||
waterType.Position = UDim2.new(0,5,0,294)
|
||||
waterType.Parent = containerFrame
|
||||
|
||||
local waterForceLabel = lakeTypeLabel:clone()
|
||||
waterForceLabel.Name = "WaterForceLabel"
|
||||
waterForceLabel.Text = "Water Force"
|
||||
waterForceLabel.Position = UDim2.new(0, 8, 0, 326)
|
||||
waterForceLabel.Size = UDim2.new(0, 98, 0, 14)
|
||||
waterForceLabel.Parent = containerFrame
|
||||
|
||||
local waterForceSelectedFunc = function ( item )
|
||||
currWaterForce = item
|
||||
end
|
||||
local waterForce, forceWaterForce = RbxGui.CreateDropDownMenu(waterForces,waterForceSelectedFunc)
|
||||
forceWaterForce("None")
|
||||
waterForce.Size = UDim2.new(0,150,0,32)
|
||||
waterForce.Position = UDim2.new(0,5,0,340)
|
||||
waterForce.Parent = containerFrame
|
||||
|
||||
-- create walls toggle
|
||||
local createWallsLabel = Instance.new("TextLabel", containerFrame)
|
||||
createWallsLabel.Name = "CreateWallsTextLabel"
|
||||
createWallsLabel.Size = UDim2.new(0.2, 0, 0.35, 0)
|
||||
createWallsLabel.Text = "Create Walls"
|
||||
createWallsLabel.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
||||
createWallsLabel.Font = Enum.Font.ArialBold
|
||||
createWallsLabel.FontSize = Enum.FontSize.Size14
|
||||
createWallsLabel.Position = UDim2.new(0,40,0,391)
|
||||
createWallsLabel.Size = UDim2.new(0,80,0,14)
|
||||
createWallsLabel.TextXAlignment = Enum.TextXAlignment.Left
|
||||
createWallsLabel.BackgroundTransparency = 1
|
||||
|
||||
local createWallsToggle = Instance.new("TextButton",createWallsLabel)
|
||||
createWallsToggle.Name = "CreateWallsToggle"
|
||||
createWallsToggle.Style = Enum.ButtonStyle.RobloxButton
|
||||
createWallsToggle.Size = UDim2.new(0,32,0,32)
|
||||
createWallsToggle.Position = UDim2.new(0,-34,0.5,-16)
|
||||
createWallsToggle.Text = "X"
|
||||
createWallsToggle.Font = Enum.Font.ArialBold
|
||||
createWallsToggle.FontSize = Enum.FontSize.Size18
|
||||
createWallsToggle.TextColor3 = Color3.new(1,1,1)
|
||||
createWallsToggle.MouseButton1Click:connect(function()
|
||||
createWalls = not createWalls
|
||||
if createWalls then
|
||||
createWallsToggle.Text = "X"
|
||||
else
|
||||
createWallsToggle.Text = ""
|
||||
end
|
||||
end)
|
||||
|
||||
local removeAboveLabel = createWallsLabel:clone()
|
||||
removeAboveLabel.Name = "RemoveAboveLabel"
|
||||
removeAboveLabel.Text = "Remove Above"
|
||||
removeAboveLabel.Position = UDim2.new(0,40,0,424)
|
||||
removeAboveLabel.Size = UDim2.new(0,93,0,14)
|
||||
removeAboveLabel.CreateWallsToggle.Name = "RemoveAboveToggle"
|
||||
removeAboveLabel.RemoveAboveToggle.MouseButton1Click:connect(function( )
|
||||
removeAbove = not removeAbove
|
||||
if removeAbove then
|
||||
removeAboveLabel.RemoveAboveToggle.Text = "X"
|
||||
else
|
||||
removeAboveLabel.RemoveAboveToggle.Text = ""
|
||||
end
|
||||
updateSelections()
|
||||
end)
|
||||
removeAboveLabel.Parent = containerFrame
|
||||
|
||||
local materialSelectionGui,newMaterialEvent,forceMaterialFunc = RbxGui.CreateTerrainMaterialSelector(UDim2.new(1,0,0,82),UDim2.new(0,0,0,450))
|
||||
materialSelectionGui.BackgroundTransparency = 1
|
||||
materialSelectionGui.Parent = containerFrame
|
||||
newMaterialEvent.Event:connect(function(newMat)
|
||||
currMaterial = newMat
|
||||
end)
|
||||
|
||||
loadingFrame, updateLoadingGuiPercent, cancelLoadingPressed = RbxGui.CreateLoadingFrame("Processing")
|
||||
loadingFrame.Visible = false
|
||||
loadingFrame.Parent = g
|
||||
|
||||
cancelLoadingPressed.Event:connect(function() cancelLakeCreate() end)
|
||||
--------------------------
|
||||
--SUCCESSFUL LOAD MESSAGE-
|
||||
--------------------------
|
||||
loaded = true
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 228 B |
|
After Width: | Height: | Size: 309 B |