362 lines
8.2 KiB
Plaintext
362 lines
8.2 KiB
Plaintext
--!strict
|
|
while not game do
|
|
wait()
|
|
end
|
|
|
|
local ChangeHistoryService = game:GetService "ChangeHistoryService"
|
|
|
|
---------------
|
|
--PLUGIN SETUP-
|
|
---------------
|
|
local loaded = false
|
|
local on = false
|
|
|
|
local On, Off
|
|
|
|
local this = PluginManager():CreatePlugin() :: Plugin
|
|
local mouse = this:GetMouse()
|
|
local toolbar = this:CreateToolbar "Terrain" :: Toolbar
|
|
local toolbarbutton = toolbar:CreateButton("Roads", "Roads", "roads.png") :: Button
|
|
toolbarbutton.Click:connect(function()
|
|
if on then
|
|
Off()
|
|
elseif loaded then
|
|
On()
|
|
end
|
|
end)
|
|
|
|
game:WaitForChild "Workspace"
|
|
workspace:WaitForChild "Terrain"
|
|
|
|
-- Local function definitions
|
|
local c = workspace.Terrain
|
|
local GetCell = c.GetCell
|
|
local WorldToCellPreferSolid = c.WorldToCellPreferSolid
|
|
local WorldToCellPreferEmpty = c.WorldToCellPreferEmpty
|
|
local SetCells = c.SetCells
|
|
|
|
-----------------
|
|
--DEFAULT VALUES-
|
|
-----------------
|
|
local x1 = 200
|
|
local y1 = 200
|
|
local x2 = 300
|
|
local y2 = 300
|
|
local h = 20
|
|
local mode = 0
|
|
|
|
local DefaultTerrainMaterial = 1
|
|
|
|
local roadDragBar, roadFrame, roadCloseEvent
|
|
|
|
-----------------------
|
|
--FUNCTION DEFINITIONS-
|
|
-----------------------
|
|
|
|
--makes a column of blocks from 0 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)
|
|
),
|
|
DefaultTerrainMaterial,
|
|
0,
|
|
0
|
|
)
|
|
end
|
|
|
|
function coordCheck(x, z, height)
|
|
for hh = height, 0, -1 do
|
|
local material, _, _ = GetCell(c, x, hh, z)
|
|
if material.Value > 0 then
|
|
return true
|
|
elseif height == 0 then
|
|
return false
|
|
end
|
|
end
|
|
return
|
|
end
|
|
|
|
-- local function dist(dx1, dy1, dx2, dy2)
|
|
-- return math.sqrt(math.pow(dx2 - dx1, 2) + math.pow(dy2 - dy1, 2))
|
|
-- end
|
|
|
|
-- local function dist3d(dx1, dy1, dz1, dx2, dy2, dz2)
|
|
-- return math.sqrt(
|
|
-- math.pow(dist(dx1, dy1, dx2, dy2), 2) + math.pow(dz2 - dz1, 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(px1, pz1, px2, pz2, ph, pp)
|
|
local incx, n
|
|
if px2 < px1 then
|
|
incx = -1
|
|
n = 1
|
|
else
|
|
incx = 1
|
|
n = -1
|
|
end
|
|
for x = px1, px2 + n, incx do
|
|
SetCells(
|
|
c,
|
|
Region3int16.new(
|
|
Vector3int16.new(x, h + 1, pz1 - 1),
|
|
Vector3int16.new(x, ph + 3, pz1 + 1)
|
|
),
|
|
0,
|
|
0,
|
|
0
|
|
)
|
|
SetCells(
|
|
c,
|
|
Region3int16.new(
|
|
Vector3int16.new(x, ph, pz1 - 1),
|
|
Vector3int16.new(x, ph, pz1 + 1)
|
|
),
|
|
DefaultTerrainMaterial,
|
|
0,
|
|
0
|
|
)
|
|
end
|
|
if pp then
|
|
for x = px1, px2 + n, 16 * incx do
|
|
if coordCheck(x, pz1, ph - 1) then
|
|
coordHeight(x, pz1, ph - 1)
|
|
end
|
|
if coordCheck(x, pz1 - 1, ph - 1) then
|
|
coordHeight(x, pz1 - 1, ph - 1)
|
|
end
|
|
if coordCheck(x, pz1 + 1, ph - 1) then
|
|
coordHeight(x, pz1 + 1, ph - 1)
|
|
end
|
|
end
|
|
end
|
|
local incz, m
|
|
if pz2 < pz1 then
|
|
incz = -1
|
|
m = 1
|
|
n = 2
|
|
else
|
|
incz = 1
|
|
m = -1
|
|
n = -2
|
|
end
|
|
for z = pz1 + m, pz2 + n, incz do
|
|
SetCells(
|
|
c,
|
|
Region3int16.new(
|
|
Vector3int16.new(px2 - 1, ph + 1, z),
|
|
Vector3int16.new(px2 + 1, ph + 3, z)
|
|
),
|
|
0,
|
|
0,
|
|
0
|
|
)
|
|
SetCells(
|
|
c,
|
|
Region3int16.new(
|
|
Vector3int16.new(x2 - 1, ph, z),
|
|
Vector3int16.new(px2 + 1, ph, z)
|
|
),
|
|
DefaultTerrainMaterial,
|
|
0,
|
|
0
|
|
)
|
|
end
|
|
if pp then
|
|
for z = pz1 + m, pz2 + n, 16 * incz do
|
|
if coordCheck(px2, z, ph - 1) then
|
|
coordHeight(px2, z, ph - 1)
|
|
end
|
|
if coordCheck(px2 - 1, z, ph - 1) then
|
|
coordHeight(px2 - 1, z, ph - 1)
|
|
end
|
|
if coordCheck(px2 + 1, z, ph - 1) then
|
|
coordHeight(px2 + 1, z, ph - 1)
|
|
end
|
|
end
|
|
end
|
|
|
|
ChangeHistoryService:SetWaypoint "Roads"
|
|
end
|
|
|
|
-- Do a line/plane intersection. The line starts at the camera. The plane is at y == 0, normal(0, 1, 0)
|
|
--
|
|
-- vectorPos - End point of the line.
|
|
--
|
|
-- Return:
|
|
-- success - Value is true if there was a plane intersection, false if not.
|
|
-- cellPos - Value is the terrain cell intersection point if there is one, vectorPos if there isn't.
|
|
function PlaneIntersection(vectorPos)
|
|
local currCamera = workspace.CurrentCamera
|
|
local startPos = Vector3.new(
|
|
currCamera.CoordinateFrame.p.X,
|
|
currCamera.CoordinateFrame.p.Y,
|
|
currCamera.CoordinateFrame.p.Z
|
|
)
|
|
local endPos = Vector3.new(vectorPos.X, vectorPos.Y, vectorPos.Z)
|
|
local normal = Vector3.new(0, 1, 0)
|
|
local p3 = Vector3.new(0, 0, 0)
|
|
local startEndDot = normal:Dot(endPos - startPos)
|
|
local cellPos = vectorPos
|
|
local success = false
|
|
|
|
if startEndDot ~= 0 then
|
|
local t = normal:Dot(p3 - startPos) / startEndDot
|
|
if t >= 0 and t <= 1 then
|
|
local intersection = ((endPos - startPos) * t) + startPos
|
|
cellPos = c:WorldToCell(intersection)
|
|
success = true
|
|
end
|
|
end
|
|
|
|
return success, cellPos
|
|
end
|
|
|
|
mouse.Button1Down:connect(function()
|
|
if not on then
|
|
return
|
|
end
|
|
|
|
local cellPos = WorldToCellPreferEmpty(
|
|
c,
|
|
Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z)
|
|
)
|
|
local solidCell = WorldToCellPreferSolid(
|
|
c,
|
|
Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z)
|
|
)
|
|
local success = false
|
|
|
|
-- If nothing was hit, do the plane intersection.
|
|
if 0 == GetCell(c, solidCell.X, solidCell.Y, solidCell.Z).Value then
|
|
--print('Plane Intersection happens')
|
|
success, cellPos = PlaneIntersection(
|
|
Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z)
|
|
)
|
|
if not success then
|
|
cellPos = solidCell
|
|
end
|
|
end
|
|
|
|
local x = cellPos.x
|
|
local y = cellPos.y
|
|
local z = cellPos.z
|
|
|
|
if mode == 0 then
|
|
x1 = x
|
|
y1 = z
|
|
h = y
|
|
mode = 1
|
|
|
|
-- first click determines default material
|
|
local celMat = GetCell(c, x, y, z)
|
|
if celMat.Value > 0 then
|
|
DefaultTerrainMaterial = celMat.Value
|
|
elseif 0 == DefaultTerrainMaterial then
|
|
DefaultTerrainMaterial = 1
|
|
end
|
|
elseif mode == 1 then
|
|
x2 = x
|
|
y2 = z
|
|
makePath(x1, y1, x2, y2, h, true)
|
|
mode = 0
|
|
end
|
|
end)
|
|
|
|
function On()
|
|
if not c then
|
|
return
|
|
elseif this then
|
|
this:Activate(true)
|
|
end
|
|
if toolbarbutton then
|
|
toolbarbutton:SetActive(true)
|
|
end
|
|
if roadDragBar then
|
|
roadDragBar.Visible = true
|
|
end
|
|
|
|
mode = 0
|
|
on = true
|
|
end
|
|
|
|
function Off()
|
|
if toolbarbutton then
|
|
toolbarbutton:SetActive(false)
|
|
end
|
|
if roadDragBar then
|
|
roadDragBar.Visible = false
|
|
end
|
|
on = false
|
|
end
|
|
|
|
------
|
|
--GUI-
|
|
------
|
|
|
|
local RbxGui = LoadLibrary "RbxGui"
|
|
|
|
--screengui
|
|
local g = Instance.new "ScreenGui"
|
|
g.Name = "RoadGui"
|
|
g.Parent = game:GetService "CoreGui"
|
|
|
|
local roadHelpFrame
|
|
roadDragBar, roadFrame, roadHelpFrame, roadCloseEvent =
|
|
RbxGui.CreatePluginFrame(
|
|
"Roads",
|
|
UDim2.new(0, 141, 0, 80),
|
|
UDim2.new(0, 0, 0, 0),
|
|
false,
|
|
g
|
|
)
|
|
roadDragBar.Visible = false
|
|
roadCloseEvent.Event:connect(function()
|
|
Off()
|
|
end)
|
|
|
|
local roadTextHelper = Instance.new "TextLabel"
|
|
roadTextHelper.Text =
|
|
"Click once to set the starting point and again to set the endpoint of the road."
|
|
roadTextHelper.Font = Enum.Font.ArialBold
|
|
roadTextHelper.FontSize = Enum.FontSize.Size14
|
|
roadTextHelper.TextColor3 = Color3.new(1, 1, 1)
|
|
roadTextHelper.BackgroundTransparency = 1
|
|
roadTextHelper.Size = UDim2.new(1, -8, 1, -8)
|
|
roadTextHelper.Position = UDim2.new(0, 4, 0, 4)
|
|
roadTextHelper.TextXAlignment = Enum.TextXAlignment.Left
|
|
roadTextHelper.TextYAlignment = Enum.TextYAlignment.Top
|
|
roadTextHelper.TextWrapped = true
|
|
roadTextHelper.Parent = roadFrame
|
|
|
|
roadHelpFrame.Size = UDim2.new(0, 200, 0, 150)
|
|
local helpText = Instance.new "TextLabel"
|
|
helpText.Font = Enum.Font.ArialBold
|
|
helpText.FontSize = Enum.FontSize.Size12
|
|
helpText.TextColor3 = Color3.new(1, 1, 1)
|
|
helpText.BackgroundTransparency = 1
|
|
helpText.TextWrapped = true
|
|
helpText.Size = UDim2.new(1, -10, 1, -10)
|
|
helpText.Position = UDim2.new(0, 5, 0, 5)
|
|
helpText.TextXAlignment = Enum.TextXAlignment.Left
|
|
helpText.Text =
|
|
[[Creates roads in existing terrain. Roads are created by setting a beginning point (first click on terrain) and an ending point (second click on terrain). The material of terrain is determined by the first click point. After the second click the tool resets and will create a new segment of road, not neccessarily connected to the first road segment created.]]
|
|
helpText.Parent = roadHelpFrame
|
|
|
|
this.Deactivation:connect(function()
|
|
Off()
|
|
end)
|
|
|
|
--------------------------
|
|
--SUCCESSFUL LOAD MESSAGE-
|
|
--------------------------
|
|
loaded = true
|