null
nil
-
true
true
0
0
-0.699999988
0
0
1
1
0
-0
-0
1
-0
WiringTool
http://www.roblox.com/asset?id=56954008
Wiring Tool
-
false
-0.5
0.5
0
0
-0.5
0.5
0
0
199
0
1.60000002
-0.5
0
0
-1
0
1
-0
1
0
-0
true
0.5
0.300000012
-0.5
0.5
0
0
-0.5
0.5
0
0
true
256
Handle
0
-0.5
0.5
0
0
0
0
0
-0.5
0.5
0
0
0
0
0
0
2
1
1
0.800000012
2
-
2
2
http://www.roblox.com/asset/?id=16884681
5
Mesh
0
0
0
0.600000024
0.600000024
0.600000024
http://www.roblox.com/asset/?id=16884673
1
1
1
-
false
WiringScript
function waitForChild(parent, child)
while not parent:FindFirstChild(child) do
parent.ChildAdded:wait()
end
end
local Tool = script.Parent
local mouseMoveCon, mouseButtonDownCon = nil
local eventTable = {}
local receiverTable = {}
local ServiceConnections = {}
local adornmentTable = {}
local eventBadgeCount = {}
local receiverBadgeCount = {}
local root = nil
local isRestricted = (game.PlaceId == 41324860 or game.PlaceId == 129686177)
waitForChild(Tool, "PlayerOwner")
local playerOwner = Tool.PlayerOwner
local CONNECT_BILLBOARD_GUI = "ConnectBillboardGui"
local WIRE_LASSO = "WireLasso"
local WIRE_TEXTURE = "http://www.roblox.com/asset?id=56954045"
local KILL_WIRE_TEXTURE = "rbxasset://Textures/ui/CloseButton_dn.png"
local STATIC_PLAYER_GUI = nil
local STATIC_BASE_PLATE = nil
local SELECTED_SOURCE = nil
local SELECTED_SINK = nil
local WIRE_LASSO_MAP = {}
local WIRING_PANEL_MAP = {}
local LAST_HOVERED_PART = nil
local SCREEN_MESSAGE = nil
local ANNOTATIONS = {}
local KNOWN_SOURCE_PARTS = {}
local KNOWN_SINK_PARTS = {}
local BASE_ANNOTATION_TRANSPARENCY = 0.5
local BASE_WIRE_TRANSPARENCY = 0.5
local BASE_WIRE_RADIUS = .06
local ENHANCED_WIRE_RADIUS = .12
local SOURCE_BUTTON_TEXT_COLOR = Color3.new(1, .5, 0)
local SOURCE_BUTTON_ICON_TEXTURE = "http://www.roblox.com/asset?id=61334830"
local SOURCE_BUTTON_ICON_HOVER_TEXTURE = "http://www.roblox.com/asset?id=61335012"
local SINK_BUTTON_TEXT_COLOR = Color3.new(0, 1, 0)
local SINK_BUTTON_ICON_TEXTURE = "http://www.roblox.com/asset?id=60730993"
local SINK_BUTTON_ICON_HOVER_TEXTURE = "http://www.roblox.com/asset?id=61335025"
local BUTTON_HOVER_TEXT_COLOR = Color3.new(1, 1, 1)
local BUTTON_ICON_WIDTH = 50
local DISCONNECT_ICON_HOVER_TEXTURE = "http://www.roblox.com/asset?id=55130256"
local DISCONNECT_SOURCE_ICON_TEXTURE = "http://www.roblox.com/asset?id=55130237"
local DISCONNECT_SINK_ICON_TEXTURE = "http://www.roblox.com/asset?id=55130219"
local TAIL_TEXTURE = "http://www.roblox.com/asset?id=55134078"
local USE_BILLBOARD_GUI = true
local LAST_CLICK_TIME = 0
local CLICK_HELP_TIME_DELTA = .8
local SOURCE_BADGE_TEXTURE = "http://www.roblox.com/asset?id=60730993"
local SINK_BADGE_TEXTURE = "http://www.roblox.com/asset?id=61334830"
local ALL_TEXTURES = { SOURCE_BUTTON_ICON_TEXTURE, SOURCE_BUTTON_ICON_HOVER_TEXTURE,
SINK_BUTTON_ICON_TEXTURE, SINK_BUTTON_ICON_HOVER_TEXTURE,
DISCONNECT_ICON_HOVER_TEXTURE, DISCONNECT_SOURCE_ICON_TEXTURE,
DISCONNECT_SINK_ICON_TEXTURE, TAIL_TEXTURE, WIRE_TEXTURE, SOURCE_BADGE_TEXTURE, SINK_BADGE_TEXTURE}
for idx, asset in ipairs(ALL_TEXTURES) do
game:GetService("ContentProvider"):Preload(asset)
end
function clearSelection()
SELECTED_SOURCE = nil
SELECTED_SINK = nil
getLocalLasso().From = nil
getLocalLasso().To = nil
end
function clearScreenMessage()
if SCREEN_MESSAGE ~= nil then
SCREEN_MESSAGE:Remove()
SCREEN_MESSAGE = nil
end
end
function clearHover()
if LAST_HOVERED_PART == nil then return end
local lastHover = LAST_HOVERED_PART
if not ANNOTATIONS[lastHover] then
lastHover = findModel(lastHover)
end
if not lastHover or not ANNOTATIONS[lastHover] then return end
if ANNOTATIONS[lastHover].Transparency ~= 1 then
ANNOTATIONS[lastHover].Transparency = BASE_ANNOTATION_TRANSPARENCY
end
local hoverGui = WIRING_PANEL_MAP[lastHover]
if hoverGui then hoverGui.Enabled = false end
-- hack: destroy object on server
local destroyObj = Instance.new("ObjectValue")
destroyObj.Value = hoverGui
destroyObj.Name = "ObjectToDestroy"
destroyObj.Parent = script.Parent.DestroyScript
WIRING_PANEL_MAP[lastHover] = nil
setPartWireTransparency(LAST_HOVERED_PART, BASE_WIRE_TRANSPARENCY, BASE_WIRE_RADIUS, "")
end
function getPlayerGui()
if STATIC_PLAYER_GUI == nil then
STATIC_PLAYER_GUI = game.Players:GetPlayerFromCharacter(Tool.Parent).PlayerGui
end
return STATIC_PLAYER_GUI
end
function findMyBasePlate()
if isRestricted then
if STATIC_BASE_PLATE == nil then
local buildingAreas = game.Workspace.BuildingAreas:GetChildren()
for i = 1, #buildingAreas do
if buildingAreas[i]:FindFirstChild("Player") then
if buildingAreas[i].Player.Value == game.Players.LocalPlayer.Name then
waitForChild(buildingAreas[i],"PlayerArea")
STATIC_BASE_PLATE = buildingAreas[i].PlayerArea
end
end
end
end
return STATIC_BASE_PLATE
end
return nil
end
function getLocalLasso()
if not game.Players.LocalPlayer.PlayerGui:FindFirstChild("lasso") then
local lasso = Instance.new("FloorWire")
lasso.Name = "lasso"
lasso.Parent = game.Players.LocalPlayer.PlayerGui
lasso.Color = BrickColor.new("Really black")
end
return game.Players.LocalPlayer.PlayerGui.lasso
end
function findModel(part)
if isRestricted then
local basePlate = findMyBasePlate()
while part ~= nil do
if part.className == "Model" and part.Name ~= basePlate.Name and part.Name ~= "GarbageParts" then
return part
elseif part.Name == basePlate.Name or part.Name == "GarbageParts" then
return nil
end
part = part.Parent
end
else
local origPart = part
while part ~= nil do
if part.className == "Model" then
return part
elseif part.Name == "Workspace" or part.Name == "game" then
return origPart
end
part = part.Parent
end
end
return nil
end
function createVisualAnnotation(part, guiMain)
local selection = Instance.new("SelectionBox", guiMain)
selection.Name = "Annotation"
selection.Color = BrickColor.new("Lime green")
selection.Transparency = BASE_ANNOTATION_TRANSPARENCY
selection.Adornee = part
return selection
end
function isInteractivePart(obj)
if obj == nil then return false end
if obj:IsA("Part") then
for idx, child in ipairs(obj:GetChildren()) do
if child:IsA("CustomEvent") or child:IsA("CustomEventReceiver") then
return true
end
end
end
return false
end
function applyToConnectorsWires(sourceOrSink, fn)
if sourceOrSink:IsA("CustomEvent") then
for idx, recv in ipairs(sourceOrSink:GetAttachedReceivers()) do
fn(WIRE_LASSO_MAP[sourceOrSink][recv])
end
else
local source = sourceOrSink.Source
if source ~= nil then
fn(WIRE_LASSO_MAP[source][sourceOrSink])
end
end
end
function warnNoWireableParts()
local topHint = nil
pcall(function() topHint = getPlayerGui().Gui.Hints.CenterHint end)
if topHint then
topHint.Add.Label.Value = "No Wiring Parts! Add Wiring Parts using the Stamper Tool."
topHint.Add.Width.Value = 580
topHint.Add.Time.Value = 10
topHint.Add.Disabled = true -- flip it off then on, in case it's currently running.
topHint.Add.Disabled = false
end
end
function warnNotClickingWireablePart()
if getPlayerGui():FindFirstChild("CenterHint", true) then
local topHint = getPlayerGui().Gui.Hints.CenterHint
topHint.Add.Label.Value = "This part isn't wireable :("
topHint.Add.Width.Value = 580
topHint.Add.Time.Value = 2
topHint.Add.Disabled = true -- flip it off then on, in case it's currently running.
topHint.Add.Disabled = false
end
end
--------------------------------------------------------------------------------
-- Screen messages (when source/sink is selected)
function stylizeScreenMessageLabel(label, text)
label.Text = text
label.FontSize = Enum.FontSize.Size24
label.Font = Enum.Font.ArialBold
label.BackgroundTransparency = 1
label.BorderSizePixel = 0
label.Size = UDim2.new(0, label.TextBounds.x, 0, label.TextBounds.y)
label.TextColor3 = Color3.new(1, 1, 1)
end
function createSourceIcon(parent, precedingText)
local sourceIcon = Instance.new("ImageLabel", frame)
sourceIcon.Archivable = false
sourceIcon.Image = SOURCE_BUTTON_ICON_TEXTURE
sourceIcon.Size = UDim2.new(0, 30, 0, 30)
sourceIcon.BackgroundTransparency = 1
sourceIcon.BorderSizePixel = 0
sourceIcon.Position = UDim2.new(0,
precedingText.Position.X.Offset + precedingText.TextBounds.x + 5,
0, precedingText.Position.Y.Offset +
((precedingText.Size.Y.Offset - sourceIcon.Size.Y.Offset) / 2))
return sourceIcon
end
function createSinkIcon(parent, precedingText)
local sinkIcon = Instance.new("ImageLabel", frame)
sinkIcon.Archivable = false
sinkIcon.Image = SINK_BUTTON_ICON_TEXTURE
sinkIcon.Size = UDim2.new(0, 30, 0, 30)
sinkIcon.BackgroundTransparency = 1
sinkIcon.BorderSizePixel = 0
sinkIcon.Position = UDim2.new(0,
precedingText.Position.X.Offset + precedingText.TextBounds.x + 5,
0, precedingText.Position.Y.Offset +
((precedingText.Size.Y.Offset - sinkIcon.Size.Y.Offset) / 2))
return sinkIcon
end
function addToAllXPositions(objs, offset)
for idx, obj in ipairs(objs) do
pos = obj.Position
obj.Position = UDim2.new(0, pos.X.Offset + offset, 0, pos.Y.Offset)
end
end
function showSourceScreenMessage(source)
gui = Instance.new("ScreenGui", getPlayerGui())
gui.Archivable = false
frame = Instance.new("Frame", gui)
frame.Archivable = false
frame.Style = Enum.FrameStyle.RobloxRound
local line1part1 = Instance.new("TextLabel", frame)
line1part1.Archivable = false
stylizeScreenMessageLabel(line1part1, "Choose a")
sinkIcon = createSinkIcon(frame, line1part1)
line1part2 = Instance.new("TextLabel", frame)
line1part2.Archivable = false
stylizeScreenMessageLabel(line1part2, "receiver to trigger when")
line1part2.Position = UDim2.new(0,
sinkIcon.Position.X.Offset + sinkIcon.Size.X.Offset + 5, 0, 0)
line1height = math.max(sinkIcon.Size.Y.Offset, line1part1.Size.Y.Offset)
line2part1 = Instance.new("TextLabel", frame)
line2part1.Archivable = false
stylizeScreenMessageLabel(line2part1, source.Parent.Name)
line2part1.Position = UDim2.new(0, 0, 0, line1height)
sourceIcon = createSourceIcon(frame, line2part1)
line2part2 = Instance.new("TextLabel", frame)
stylizeScreenMessageLabel(line2part2, "signals ")
line2part2.Position = UDim2.new(0,
sourceIcon.Position.X.Offset + sourceIcon.Size.X.Offset + 5,
0, line2part1.Position.Y.Offset)
line2part3 = Instance.new("TextLabel", frame)
stylizeScreenMessageLabel(line2part3, source.Name)
line2part3.TextColor3 = SOURCE_BUTTON_TEXT_COLOR
line2part3.Position = UDim2.new(0,
line2part2.Position.X.Offset + line2part2.Size.X.Offset,
0, line2part1.Position.Y.Offset)
-- re-center
line1width = line1part2.Position.X.Offset + line1part2.Size.X.Offset
line2width = line2part3.Position.X.Offset + line2part3.Size.X.Offset
if line1width > line2width then
local halfDelta = (line1width - line2width) / 2
addToAllXPositions({line2part1, sourceIcon, line2part2, line2part3}, halfDelta)
else
local halfDelta = (line2width - line1width) / 2
addToAllXPositions({line1part1, sinkIcon, line1part2}, halfDelta)
end
frame.Size = UDim2.new(0, math.max(line1width, line2width) + 15,
0, 2 * line1height + 5)
frame.Position = UDim2.new(.5, -frame.Size.X.Offset/2, 0, 0)
clearScreenMessage()
SCREEN_MESSAGE = gui
end
function showSinkScreenMessage(sink)
gui = Instance.new("ScreenGui", getPlayerGui())
frame = Instance.new("Frame", gui)
frame.Style = Enum.FrameStyle.RobloxRound
local line1part1 = Instance.new("TextLabel", frame)
stylizeScreenMessageLabel(line1part1, "Choose which")
local sourceIcon = createSourceIcon(frame, line1part1)
line1part2 = Instance.new("TextLabel", frame)
stylizeScreenMessageLabel(line1part2, "signal will cause")
line1part2.Position = UDim2.new(0,
sourceIcon.Position.X.Offset + sourceIcon.Size.X.Offset + 5, 0, 0)
local line1height = math.max(sourceIcon.Size.Y.Offset, line1part1.Size.Y.Offset)
line2part1 = Instance.new("TextLabel", frame)
stylizeScreenMessageLabel(line2part1, sink.Parent.Name .. " to")
line2part1.Position = UDim2.new(0, 0, 0, line1height)
local sinkIcon = createSinkIcon(frame, line2part1)
line2part2 = Instance.new("TextLabel", frame)
stylizeScreenMessageLabel(line2part2, sink.Name)
line2part2.TextColor3 = SINK_BUTTON_TEXT_COLOR
line2part2.Position = UDim2.new(0,
sinkIcon.Position.X.Offset + sinkIcon.Size.X.Offset,
0, line2part1.Position.Y.Offset)
-- re-center
line1width = line1part2.Position.X.Offset + line1part2.Size.X.Offset
line2width = line2part2.Position.X.Offset + line2part2.Size.X.Offset
if line1width > line2width then
local halfDelta = (line1width - line2width) / 2
addToAllXPositions({line2part1, sinkIcon, line2part2}, halfDelta)
else
local halfDelta = (line2width - line1width) / 2
addToAllXPositions({line1part1, sourceIcon, line1part2}, halfDelta)
end
frame.Size = UDim2.new(0, math.max(line1width, line2width) + 15,
0, 2 * line1height + 5)
frame.Position = UDim2.new(.5, -frame.Size.X.Offset/2, 0, 0)
clearScreenMessage()
SCREEN_MESSAGE = gui
end
--------------------------------------------------------------------------------
-- Hover
function setPartWireTransparency(part, transparency, wireRadius, texture)
if not part then return end
for idx, child in ipairs(part:GetChildren()) do
if child:IsA("CustomEvent") then
for idx2, recv in ipairs(child:GetAttachedReceivers()) do
addWireUiIfNotAlreadyThere(child, recv)
WIRE_LASSO_MAP[child][recv].Transparency = transparency
WIRE_LASSO_MAP[child][recv].WireRadius = wireRadius
WIRE_LASSO_MAP[child][recv].Texture = texture
WIRE_LASSO_MAP[child][recv].Color = BrickColor.new("Really black")
end
elseif child:IsA("CustomEventReceiver") then
local source = child.Source
if source ~= nil then
addWireUiIfNotAlreadyThere(source, child)
WIRE_LASSO_MAP[source][child].Transparency = transparency
WIRE_LASSO_MAP[source][child].WireRadius = wireRadius
WIRE_LASSO_MAP[source][child].Texture = texture
WIRE_LASSO_MAP[source][child].Color = BrickColor.new("Really black")
end
end
end
end
function canHighlight(part,model)
if (KNOWN_SOURCE_PARTS[part] and SELECTED_SOURCE == nil) or (KNOWN_SINK_PARTS[part] and SELECTED_SINK == nil) then
return true, part
elseif (KNOWN_SOURCE_PARTS[model] and SELECTED_SOURCE == nil) or (KNOWN_SINK_PARTS[model] and SELECTED_SINK == nil) then
return true, model
end
return false, nil
end
function hoverListener(mouse)
if mouse.Target == nil then
clearHover()
LAST_HOVERED_PART = nil
return
end
local part = mouse.Target
local model = findModel(part)
if LAST_HOVERED_PART ~= part and findModel(LAST_HOVERED_PART) ~= model then
clearHover()
LAST_HOVERED_PART = part
local highlight, instance = canHighlight(part,model)
if highlight then
ANNOTATIONS[model].Transparency = 0
buildScreenPanel(model, mouse.X, mouse.Y)
setPartWireTransparency(part, 0, ENHANCED_WIRE_RADIUS, "")
end
-- Point the temporary wire to the LAST_HOVERED_PART if not nil,
-- otherwise point it at the character
local otherEndOfWire = game.Players.LocalPlayer.Character.Humanoid.Torso
if canHighlight(LAST_HOVERED_PART, model) then
otherEndOfWire = LAST_HOVERED_PART
end
if SELECTED_SOURCE ~= nil then
getLocalLasso().To = otherEndOfWire
end
if SELECTED_SINK ~= nil then
getLocalLasso().From = otherEndOfWire
end
end
end
--------------------------------------------------------------------------------
-- Connect / Disconnect dialog
function addWireUiIfNotAlreadyThere(source, sink)
if WIRE_LASSO_MAP[source] == nil then
WIRE_LASSO_MAP[source] = {}
end
if WIRE_LASSO_MAP[source][sink] ~= nil then
return
end
pairLasso = Instance.new("FloorWire", getPlayerGui())
pairLasso.From = source.Parent
pairLasso.To = sink.Parent
pairLasso.Transparency = BASE_WIRE_TRANSPARENCY
pairLasso.Texture = ""
pairLasso.Name = WIRE_LASSO
pairLasso.Color = BrickColor.new("Really black")
WIRE_LASSO_MAP[source][sink] = pairLasso
end
function connectHelper(source, sink)
-- clear wires coming to sink
local old_source = sink.Source
if old_source ~= nil then
wire = WIRE_LASSO_MAP[old_source][sink]
if wire ~= nil then
wire:Remove()
WIRE_LASSO_MAP[old_source][sink] = nil
end
sink.Source = nil
end
sink.Source = source
addWireUiIfNotAlreadyThere(source, sink)
end
function makeSourceConnectCallback(source)
return function()
clearHover()
if SELECTED_SINK ~= nil then
connectHelper(source, SELECTED_SINK)
clearSelection()
clearScreenMessage()
for part, val in pairs(KNOWN_SINK_PARTS) do
local model = findModel(part)
ANNOTATIONS[model].Transparency = BASE_ANNOTATION_TRANSPARENCY
end
else
SELECTED_SOURCE = source
getLocalLasso().From = source.Parent
getLocalLasso().To = game.Players.LocalPlayer.Character.Humanoid.Torso
showSourceScreenMessage(SELECTED_SOURCE)
for part, val in pairs(KNOWN_SOURCE_PARTS) do
if not KNOWN_SINK_PARTS[part] then
local model = findModel(part)
ANNOTATIONS[model].Transparency = 1
end
end
end
end
end
function makeSinkConnectCallback(sink)
return function()
clearHover()
if SELECTED_SOURCE ~= nil then
connectHelper(SELECTED_SOURCE, sink)
clearSelection()
clearScreenMessage()
for part, val in pairs(KNOWN_SOURCE_PARTS) do
local model = findModel(part)
ANNOTATIONS[model].Transparency = BASE_ANNOTATION_TRANSPARENCY
end
else
SELECTED_SINK = sink
getLocalLasso().From = game.Players.LocalPlayer.Character.Humanoid.Torso
getLocalLasso().To = sink.Parent
showSinkScreenMessage(SELECTED_SINK)
for part, val in pairs(KNOWN_SINK_PARTS) do
if not KNOWN_SOURCE_PARTS[part] then
local model = findModel(part)
ANNOTATIONS[model].Transparency = 1
end
end
end
end
end
function makeControlButton(y_position, frame, sourceOrSink, textColor, iconImage, iconHoverImage, callbackBuilder)
local button = Instance.new("TextButton", frame)
button.Position = UDim2.new(.025, 0, 0, y_position)
button.Text = sourceOrSink.Name
button.TextXAlignment = Enum.TextXAlignment.Left
button.Style = Enum.ButtonStyle.Custom
button.BorderSizePixel = 0
button.BackgroundTransparency = 1
button.BackgroundColor3 = Color3.new(0, 0 ,0)
button.TextColor3 = textColor
button.Font = Enum.Font.ArialBold
button.FontSize = Enum.FontSize.Size18
button.ZIndex = 2
button.Size = UDim2.new(.95, 0, 0, button.TextBounds.y)
local icon = Instance.new("ImageLabel", button)
icon.Image = iconImage
icon.ZIndex = 2
icon.Position = UDim2.new(0, button.TextBounds.x + 10, 0, -8)
icon.Size = UDim2.new(0, 30, 0 , 30)
icon.BackgroundTransparency = 1
button.MouseEnter:connect(function()
applyToConnectorsWires(sourceOrSink, function(wire)
wire.Texture = WIRE_TEXTURE
wire.Velocity = 2
end)
button.BackgroundTransparency = 0
button.TextColor3 = BUTTON_HOVER_TEXT_COLOR
icon.Image = iconHoverImage
end)
local leaveCallback = function()
applyToConnectorsWires(sourceOrSink, function(wire)
wire.Texture = ""
end)
button.BackgroundTransparency = 1
button.TextColor3 = textColor
icon.Image = iconImage
end
button.MouseLeave:connect(leaveCallback)
button.MouseButton1Click:connect(function()
callbackBuilder(sourceOrSink)()
leaveCallback()
end)
return button
end
function makeDisconnectCallback(source, sink)
clearHover()
sink.Source = nil
if WIRE_LASSO_MAP[source] ~= nil then
lassoUi = WIRE_LASSO_MAP[source][sink]
if lassoUi ~= nil then
lassoUi:Remove()
WIRE_LASSO_MAP[source][sink] = nil
end
end
end
function makeDisconnectButton(y_position, frame, localConnector, foreignConnector, textColor, iconImage)
local source = nil
local sink = nil
if localConnector:IsA("CustomEvent") then
source = localConnector
sink = foreignConnector
else
source = foreignConnector
sink = localConnector
end
local button = Instance.new("TextButton", frame)
button.Position = UDim2.new(0, 17, 0, y_position)
button.Text = foreignConnector.Name .. " (" .. foreignConnector.Parent.Name .. ")"
button.TextXAlignment = Enum.TextXAlignment.Left
button.Style = Enum.ButtonStyle.Custom
button.BackgroundTransparency = 1
button.BackgroundColor3 = Color3.new(0, 0 ,0)
button.TextColor3 = textColor
button.BorderSizePixel = 0
button.Font = Enum.Font.Arial
button.FontSize = Enum.FontSize.Size18
button.ZIndex = 3
button.Size = UDim2.new(.95, -10, 0, button.TextBounds.y + 2)
local icon = Instance.new("ImageLabel", button)
icon.Image = iconImage
icon.Parent = button
icon.Position = UDim2.new(0, button.TextBounds.x + 10, 0, 2)
icon.Size = UDim2.new(0, 15, 0 , 15)
icon.BackgroundTransparency = 1
local buttonCons = {}
table.insert(buttonCons,
button.MouseButton1Click:connect(function()
makeDisconnectCallback(source, sink)
end)
)
table.insert(buttonCons,
button.MouseEnter:connect(function()
button.BackgroundTransparency = 0
button.TextColor3 = BUTTON_HOVER_TEXT_COLOR
icon.Image = DISCONNECT_ICON_HOVER_TEXTURE
WIRE_LASSO_MAP[source][sink].Color = BrickColor.new("Really red")
end)
)
table.insert(buttonCons,
button.MouseLeave:connect(function()
button.BackgroundTransparency = 1
button.TextColor3 = textColor
icon.Image = iconImage
WIRE_LASSO_MAP[source][sink].Color = BrickColor.new("Really black")
end)
)
table.insert(buttonCons,
button.AncestryChanged:connect(function(child,parent)
if parent == nil then
for i = 1, #buttonCons do
buttonCons[i]:disconnect()
end
end
end)
)
return button
end
function getPartSourcesAndSinks(part, sources,sinks)
for idx, child in ipairs(part:GetChildren()) do
if child:IsA("CustomEvent") then
table.insert(sources, child)
elseif child:IsA("CustomEventReceiver") then
table.insert(sinks, child)
end
end
end
function getSourcesAndSinks(instance,sources,sinks)
if instance:IsA("BasePart") then
getPartSourcesAndSinks(instance, sources,sinks)
elseif instance:IsA("Model") then
local modelChildren = instance:GetChildren()
for i = 1, #modelChildren do
if modelChildren[i]:IsA("BasePart") then
getPartSourcesAndSinks(modelChildren[i],sources,sinks)
elseif modelChildren[i]:IsA("Model") then
getSourcesAndSinks(modelChildren[i],sources,sinks)
end
end
end
end
local function findFirstConnector(node)
if node:IsA("BasePart") then
for idx, child in ipairs(node:GetChildren()) do
if connector == nil and (child:IsA("CustomEvent") or child:IsA("CustomEventReceiver")) then
return child
end
end
else
local children = node:GetChildren()
if #children == 0 then
return nil
end
for i = 1, #children do
local subConnector = findFirstConnector(children[i])
if subConnector then return subConnector end
end
end
end
function buildScreenPanel(part, x, y)
sources = {}
sinks = {}
getSourcesAndSinks(part,sources,sinks)
local gui = nil
if not gui then
local mouseFrame = nil
if USE_BILLBOARD_GUI then
gui = Instance.new("BillboardGui", getPlayerGui())
gui.Name = "WiringGui"
gui.StudsOffset = Vector3.new(0, 1.5, 0)
gui.ExtentsOffset = Vector3.new(0,0, 0)
gui.Adornee = part
gui.Active = true
gui.AlwaysOnTop = true
else
gui = Instance.new("ScreenGui", getPlayerGui())
end
end
local frame = Instance.new("Frame", gui)
frame.Style = Enum.FrameStyle.RobloxRound
frame.ZIndex = 1
frame.Active = true
local maxWidth = 0
local y_position = 5
if SELECTED_SOURCE == nil then
for idx, source in ipairs(sources) do
local button = makeControlButton(y_position, frame, source, SOURCE_BUTTON_TEXT_COLOR,
SOURCE_BUTTON_ICON_TEXTURE, SOURCE_BUTTON_ICON_HOVER_TEXTURE,
makeSourceConnectCallback)
maxWidth = math.max(1.25 * (button.TextBounds.x + BUTTON_ICON_WIDTH), maxWidth)
y_position = y_position + button.TextBounds.y
receivers = source:GetAttachedReceivers()
for sub_idx, receiver in ipairs(receivers) do
y_position = y_position + 2
addWireUiIfNotAlreadyThere(source, receiver)
local button = makeDisconnectButton(y_position, frame, source, receiver,
SINK_BUTTON_TEXT_COLOR, DISCONNECT_SINK_ICON_TEXTURE)
y_position = y_position + button.TextBounds.y
maxWidth = math.max(1.15 * (button.TextBounds.x + 17 + 25), maxWidth)
end
y_position = y_position + 5
end
end
if SELECTED_SINK == nil then
for idx, sink in ipairs(sinks) do
local button = makeControlButton(y_position, frame, sink, SINK_BUTTON_TEXT_COLOR,
SINK_BUTTON_ICON_TEXTURE, SINK_BUTTON_ICON_HOVER_TEXTURE,
makeSinkConnectCallback)
maxWidth = math.max(1.25 * (button.TextBounds.x + BUTTON_ICON_WIDTH), maxWidth)
y_position = y_position + button.TextBounds.y
local sender = sink.Source
if sender ~= nil then
y_position = y_position + 2
-- addWire takes source first
addWireUiIfNotAlreadyThere(sender, sink)
local button = makeDisconnectButton(y_position, frame, sink, sender,
SOURCE_BUTTON_TEXT_COLOR, DISCONNECT_SOURCE_ICON_TEXTURE)
y_position = y_position + button.TextBounds.y
maxWidth = math.max(1.15 * (button.TextBounds.x + 17 + 25), maxWidth)
end
y_position = y_position + 5
end
end
-- set size and position
if not getPlayerGui():FindFirstChild("ScreenGui") then
local screenGui = Instance.new("ScreenGui")
screenGui.Parent = getPlayerGui()
end
local screenSize = getPlayerGui().ScreenGui.AbsoluteSize
local menuWidth = maxWidth
local menuHeight = y_position + 17.5
if USE_BILLBOARD_GUI then
local size = Vector3.new(0,0,0)
if gui.Adornee:IsA("BasePart") then
size = gui.Adornee.Size
elseif gui.Adornee:IsA("Model") then
size = gui.Adornee:GetModelSize()
end
local xSize= size.X
if size.Y > xSize then
xSize = size.Y
end
gui.Size = UDim2.new(0, menuWidth,0,menuHeight + 150)
gui.SizeOffset = Vector2.new(0, -50.0 / (menuHeight + 150));
local tail = Instance.new("ImageLabel", frame)
tail.Size = UDim2.new(0, 32, 0, 32)
tail.Position = UDim2.new(.5, -16, 1, 8)
tail.Image = TAIL_TEXTURE
tail.BackgroundTransparency = 1
tail.Visible = true
f = Instance.new("Frame", gui)
f.Size = UDim2.new(1, 0, 1, 0)
f.BackgroundTransparency = 1
f.ZIndex = 1
f.Active = true
b = Instance.new("TextButton", f)
b.ZIndex = 1
b.BackgroundTransparency = 1
b.Text = ""
b.BorderSizePixel = 0
b.Size = UDim2.new(1, 0, 1, 0)
b.MouseButton1Click:connect(function()
local foundConnector = findFirstConnector(findModel(LAST_HOVERED_PART))
if foundConnector ~= nil and foundConnector:IsA("CustomEvent") then
makeSourceConnectCallback(foundConnector)()
elseif foundConnector ~= nil and foundConnector:IsA("CustomEventReceiver") then
makeSinkConnectCallback(foundConnector)()
end
end)
else
x = math.min(x - 9, screenSize.x - menuWidth)
y = math.min(y - 9, screenSize.y - menuHeight)
frame.Position = UDim2.new(0, x, 0, y)
end
frame.Size = UDim2.new(0, menuWidth, 0, menuHeight)
frame.Position = UDim2.new(0.5,-menuWidth/2,0.05,0)
WIRING_PANEL_MAP[part] = gui
end
function inBaseplate(instance)
if instance == STATIC_BASE_PLATE then return true end
local instanceCopy = instance
while instanceCopy and (instanceCopy.Parent ~= nil or instanceCopy.Parent ~= game.Workspace) do
if instanceCopy.Parent == STATIC_BASE_PLATE then
return true
end
instanceCopy = instanceCopy.Parent
end
return false
end
--------------------------------------------------------------------------------
-- Tool.Equipped/Unequipped
Tool.Equipped:connect(function(mouse)
local player = game.Players:getPlayerFromCharacter(Tool.Parent)
if not player then return end
if playerOwner.Value and playerOwner.Value ~= player then return end
playerOwner.Value = player
playerGui = getPlayerGui()
LAST_HOVERED_PART = nil
if isRestricted then
local theBumps = game.Workspace:FindFirstChild("BaseplateBumpers", true)
mouse.TargetFilter = game.Workspace:FindFirstChild("BaseplateBumpers", true)
root = findMyBasePlate()
else
root = game.Workspace
end
local interactiveCount = setUpConfigurationService()
if not interactiveCount or interactiveCount == 0 then
warnNoWireableParts()
end
getLocalLasso().Texture = WIRE_TEXTURE
getLocalLasso().WireRadius = ENHANCED_WIRE_RADIUS
clearSelection()
mouse.Icon = "http://www.roblox.com/asset?id=66887773"
mouseMoveCon = mouse.Move:connect(function() hoverListener(mouse) end)
mouseButtonDownCon = mouse.Button1Down:connect(function()
if LAST_HOVERED_PART ~= nil then return end
clearSelection()
clearScreenMessage()
clearHover()
local annotationCount = 0
for part, annotation in pairs(ANNOTATIONS) do
annotation.Transparency = BASE_ANNOTATION_TRANSPARENCY
annotationCount = annotationCount + 1
end
if annotationCount == 0 then
warnNoWireableParts()
elseif time() - LAST_CLICK_TIME < CLICK_HELP_TIME_DELTA then
warnNotClickingWireablePart()
end
LAST_CLICK_TIME = time()
end)
-- TODO: onkeydown/onmouse2down, prevent hover from triggering
-- until the up event comes
end)
Tool.Unequipped:connect(function()
playerGui = getPlayerGui()
destroyConfigurationService()
if mouseMoveCon then mouseMoveCon:disconnect() end
if mouseButtonDownCon then mouseButtonDownCon:disconnect() end
if playerGui:FindFirstChild("CenterHint", true) then
local centerHint = getPlayerGui().Gui.Hints.CenterHint
centerHint.Delete.Disabled = false
end
-- TODO: simplify these side effects
-- call clearHover before removing annotations, because
-- clear hover resets annotation boxes. Also before clearing
-- lassos because this may create lassos
clearHover()
for part, gui in pairs(WIRING_PANEL_MAP) do
if gui then gui:Destroy() end
end
WIRING_PANEL_MAP = {}
for source, submap in pairs(WIRE_LASSO_MAP) do
for sink, wire in pairs(submap) do
wire:Destroy()
end
end
WIRE_LASSO_MAP = {}
for k,adorneeTable in pairs(adornmentTable) do
for i = 1, #adorneeTable do
adorneeTable[i]:Destroy()
end
adorneeTable = nil
end
adornmentTable = {}
ANNOTATIONS = {}
KNOWN_SOURCE_PARTS = {}
KNOWN_SINK_PARTS = {}
clearSelection()
clearScreenMessage()
LAST_HOVERED_PART = nil
end)
function findBillboard(guiTable)
if not guiTable then return end
for i = 1, #guiTable do
if guiTable[i]:IsA("BillboardGui") then
return guiTable[i]
end
end
end
function getBillboard(adornee, parent)
local billboard = findBillboard(adornmentTable[adornee])
if not billboard and parent then
local screen = Instance.new("BillboardGui")
screen.Name = adornee.Name .. "BadgeGUI"
screen.Size = UDim2.new(1.5,0,1.5,0)
screen.Enabled = true
screen.Active = true
screen.AlwaysOnTop = true
screen.ExtentsOffset = Vector3.new(0,0,0)
screen.Adornee = adornee
screen.Parent = parent
local badgeFrame = Instance.new("Frame")
badgeFrame.Name = "BadgeFrame"
badgeFrame.Size = UDim2.new(2,0,1,0)
badgeFrame.Position = UDim2.new(-0.5,0,0,0)
badgeFrame.BackgroundTransparency = 1
badgeFrame.Parent = screen
table.insert(adornmentTable[adornee],screen)
return screen
end
return billboard
end
function repositionBadges(badgeFrame)
local badges = badgeFrame:GetChildren()
if #badges == 1 then
badges[1].Position = UDim2.new(0.25,0,0,0)
elseif #badges == 2 then
badges[1].Position = UDim2.new(0,0,0,0)
badges[2].Position = UDim2.new(0.5,0,0)
end
end
function hasBadge(adornee, type)
local screen = getBillboard(adornee)
return screen and screen:FindFirstChild(type .. "Badge",true)
end
function removeBadge(adornee, type)
local screen = getBillboard(adornee)
local badge = screen:FindFirstChild(type .. "Badge",true)
if badge then badge:Destroy() end
if screen then screen:remove() end
end
function createBadge(adornee,type,parent)
local screen = getBillboard(adornee, parent)
local wiringBadge = Instance.new("ImageLabel")
wiringBadge.Name = type .. "Badge"
wiringBadge.BackgroundTransparency = 1
if type == "Receiver" then
wiringBadge.Image = SOURCE_BADGE_TEXTURE
else
wiringBadge.Image = SINK_BADGE_TEXTURE
end
wiringBadge.Position = UDim2.new(0.25,0,0,0)
wiringBadge.Size = UDim2.new(0.5,0,1,0)
wiringBadge.Parent = screen.BadgeFrame
wiringBadge.Changed:connect(function(prop)
if prop == "AbsoluteSize" then
if wiringBadge.AbsoluteSize.X < 10 then
wiringBadge.Visible = false
else
wiringBadge.Visible = true
end
end
end)
repositionBadges(screen.BadgeFrame)
end
function upAdorneeCount(adornee,type)
local typeLower = string.lower(type)
if typeLower == "receiver" then
if not receiverBadgeCount[adornee] then
receiverBadgeCount[adornee] = 1
else
receiverBadgeCount[adornee] = receiverBadgeCount[adornee] + 1
end
elseif typeLower == "event" then
if not eventBadgeCount[adornee] then
eventBadgeCount[adornee] = 1
else
eventBadgeCount[adornee] = eventBadgeCount[adornee] + 1
end
end
end
function downAdorneeCount(adornee,type)
local typeLower = string.lower(type)
if typeLower == "receiver" then
if receiverBadgeCount[adornee] then
receiverBadgeCount[adornee] = receiverBadgeCount[adornee] - 1
if receiverBadgeCount[adornee] < 1 then
receiverBadgeCount[adornee] = nil
end
end
elseif typeLower == "event" then
if eventBadgeCount[adornee] then
eventBadgeCount[adornee] = eventBadgeCount[adornee] - 1
if eventBadgeCount[adornee] < 1 then
eventBadgeCount[adornee] = nil
end
end
end
end
function createAdornment(adornee,adornColor,type)
upAdorneeCount(adornee,type)
if receiverBadgeCount[adornee] == 1 or eventBadgeCount[adornee] == 1 then
local box = Instance.new("SelectionBox")
box.Color = adornColor
box.Name = adornee.Name .. "Selection" .. tostring(type)
box.Adornee = adornee
box.Transparency = 0.5
box.Parent = game.Players.LocalPlayer.PlayerGui
ANNOTATIONS[adornee] = box
if not adornmentTable[adornee] then
adornmentTable[adornee] = {}
end
table.insert(adornmentTable[adornee],box)
if not hasBadge(adornee,type) then
createBadge(adornee, type, box)
end
end
end
function doRemoveAdornment(adornee)
if not adornmentTable[adornee] then return end
local adorneeTable = adornmentTable[adornee]
for i = 1, #adorneeTable do
adorneeTable[i]:Destroy()
end
end
function removeAdornment(adornee, type)
downAdorneeCount(adornee,type)
if type == "Receiver" then
if not receiverBadgeCount[adornee] then
doRemoveAdornment(adornee)
end
elseif type == "Event" then
if not eventBadgeCount[adornee] then
doRemoveAdornment(adornee)
end
end
end
function eventReceiverAdded(receiver,wirePartCount)
if isRestricted then
if not inBaseplate(receiver) then return wirePartCount end
end
receiverTable[receiver] = findModel(receiver.Parent)
createAdornment(receiverTable[receiver], BrickColor.new("Lime green"), "Receiver")
setPartWireTransparency(receiver.Parent, BASE_WIRE_TRANSPARENCY, BASE_WIRE_RADIUS, "")
KNOWN_SINK_PARTS[receiver.Parent] = true
KNOWN_SINK_PARTS[receiverTable[receiver]]= true
if wirePartCount then
return wirePartCount + 1
else
return 0
end
end
function eventAdded(event,wirePartCount)
if isRestricted then
if not inBaseplate(event) then return wirePartCount end
end
eventTable[event] = findModel(event.Parent)
createAdornment(eventTable[event], BrickColor.new("Bright orange"), "Event")
setPartWireTransparency(event.Parent, BASE_WIRE_TRANSPARENCY, BASE_WIRE_RADIUS, "")
KNOWN_SOURCE_PARTS[event.Parent] = true
KNOWN_SOURCE_PARTS[eventTable[event]]= true
if wirePartCount then
return wirePartCount + 1
else
return 0
end
end
function eventReceiverRemoved(receiver)
if not receiverTable[receiver] then return end
KNOWN_SINK_PARTS[receiver.Parent] = false
KNOWN_SINK_PARTS[receiverTable[receiver]]= false
removeAdornment(receiverTable[receiver],"Receiver")
receiverTable[receiver] = nil
end
function eventRemoved(event)
if not eventTable[event] then return end
KNOWN_SOURCE_PARTS[event.Parent] = false
KNOWN_SOURCE_PARTS[eventTable[event]]= false
removeAdornment(eventTable[event], "Event")
eventTable[event] = nil
end
function setUpConfigurationService()
local wirePartCount = 0
ServiceConnections = {}
local collectionService = game:GetService("CollectionService")
-- first lets check if anything already exists
local receivers = collectionService:GetCollection("CustomEventReceiver")
if receivers then
for pos, receiver in pairs(receivers) do
wirePartCount = eventReceiverAdded(receiver, wirePartCount)
end
end
local events = collectionService:GetCollection("CustomEvent")
if events then
for pos, event in pairs(events) do
wirePartCount = eventAdded(event, wirePartCount)
end
end
-- Now lets listen for any future additions/removals
table.insert(ServiceConnections, collectionService.ItemAdded:connect(function(instance)
if instance:IsA("CustomEventReceiver") then
eventReceiverAdded(instance)
elseif instance:IsA("CustomEvent") then
eventAdded(instance)
end
end))
table.insert(ServiceConnections, collectionService.ItemRemoved:connect(function(instance)
if instance:IsA("CustomEventReceiver") then
eventReceiverRemoved(instance)
elseif instance:IsA("CustomEvent") then
eventRemoved(instance)
end
end))
return wirePartCount
end
function destroyConfigurationService()
-- first lets destroy the collection service
for index, connection in pairs(ServiceConnections) do
connection:disconnect()
end
ServiceConnections = {}
-- now lets remove all of our collection service objects that were generated
for event, object in pairs(eventTable) do
eventRemoved(event)
end
eventTable = {}
for eventReceiver, object in pairs(receiverTable) do
eventReceiverRemoved(eventReceiver)
end
receiverTable = {}
end
-
PlayerOwner
[null]
-
false
DestroyScript
local destroyObject = function(object)
if object and object.Value then
object.Value:Destroy()
object:Destroy()
end
end
script.ChildAdded:connect(function(child)
if child:IsA("ObjectValue") and child.Name == "ObjectToDestroy" then
destroyObject(child)
end
end)
-
ObjectToDestroy
[null]