Advertisement
Fraeric123

Roblox WiringTool Script

Apr 14th, 2024
672
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 37.20 KB | Source Code | 0 0
  1. function waitForChild(parent, child)
  2.     while not parent:FindFirstChild(child) do
  3.         parent.ChildAdded:wait()
  4.     end
  5. end
  6.  
  7. local Tool = script.Parent
  8. local mouseMoveCon, mouseButtonDownCon = nil
  9.  
  10. local eventTable = {}
  11. local receiverTable = {}
  12. local ServiceConnections = {}
  13. local adornmentTable = {}
  14.  
  15. local eventBadgeCount = {}
  16. local receiverBadgeCount = {}
  17.  
  18. local root = nil
  19.  
  20. local isRestricted = (game.PlaceId == 41324860 or game.PlaceId == 129686177)
  21.  
  22. waitForChild(Tool, "PlayerOwner")
  23. local playerOwner = Tool.PlayerOwner
  24.  
  25. local CONNECT_BILLBOARD_GUI = "ConnectBillboardGui"
  26. local WIRE_LASSO = "WireLasso"
  27. local WIRE_TEXTURE = "http://www.roblox.com/asset?id=56954045"
  28. --local WIRE_TEXTURE = "rbxasset://Textures/ui/playerlist_small_hide_dn.png"
  29. local KILL_WIRE_TEXTURE = "rbxasset://Textures/ui/CloseButton_dn.png"
  30. local STATIC_PLAYER_GUI = nil
  31. local STATIC_BASE_PLATE = nil
  32. local SELECTED_SOURCE = nil
  33. local SELECTED_SINK = nil
  34. local WIRE_LASSO_MAP = {}
  35. local WIRING_PANEL_MAP = {}
  36. local LAST_HOVERED_PART = nil
  37. local SCREEN_MESSAGE = nil
  38. local ANNOTATIONS = {}
  39. local KNOWN_SOURCE_PARTS = {}
  40. local KNOWN_SINK_PARTS = {}
  41. local BASE_ANNOTATION_TRANSPARENCY = 0.5
  42. local BASE_WIRE_TRANSPARENCY = 0.5
  43. local BASE_WIRE_RADIUS = .06
  44. local ENHANCED_WIRE_RADIUS = .12
  45. local SOURCE_BUTTON_TEXT_COLOR = Color3.new(1, .5, 0)
  46. local SOURCE_BUTTON_ICON_TEXTURE = "http://www.roblox.com/asset?id=61334830"
  47. local SOURCE_BUTTON_ICON_HOVER_TEXTURE = "http://www.roblox.com/asset?id=61335012"
  48. local SINK_BUTTON_TEXT_COLOR = Color3.new(0, 1, 0)
  49. local SINK_BUTTON_ICON_TEXTURE = "http://www.roblox.com/asset?id=60730993"
  50. local SINK_BUTTON_ICON_HOVER_TEXTURE = "http://www.roblox.com/asset?id=61335025"
  51. local BUTTON_HOVER_TEXT_COLOR = Color3.new(1, 1, 1)
  52. local BUTTON_ICON_WIDTH = 50
  53. local DISCONNECT_ICON_HOVER_TEXTURE = "http://www.roblox.com/asset?id=55130256"
  54. local DISCONNECT_SOURCE_ICON_TEXTURE = "http://www.roblox.com/asset?id=55130237"
  55. local DISCONNECT_SINK_ICON_TEXTURE = "http://www.roblox.com/asset?id=55130219"
  56. local TAIL_TEXTURE = "http://www.roblox.com/asset?id=55134078"
  57. local USE_BILLBOARD_GUI = true
  58. local LAST_CLICK_TIME = 0
  59. local CLICK_HELP_TIME_DELTA = .8
  60. local SOURCE_BADGE_TEXTURE = "http://www.roblox.com/asset?id=60730993"
  61. local SINK_BADGE_TEXTURE = "http://www.roblox.com/asset?id=61334830"
  62.  
  63. local ALL_TEXTURES = { SOURCE_BUTTON_ICON_TEXTURE, SOURCE_BUTTON_ICON_HOVER_TEXTURE,
  64.         SINK_BUTTON_ICON_TEXTURE, SINK_BUTTON_ICON_HOVER_TEXTURE,
  65.         DISCONNECT_ICON_HOVER_TEXTURE, DISCONNECT_SOURCE_ICON_TEXTURE,
  66.         DISCONNECT_SINK_ICON_TEXTURE, TAIL_TEXTURE, WIRE_TEXTURE, SOURCE_BADGE_TEXTURE, SINK_BADGE_TEXTURE}
  67.  
  68. for idx, asset in ipairs(ALL_TEXTURES) do
  69.     game:GetService("ContentProvider"):Preload(asset)
  70. end
  71.  
  72. function clearSelection()
  73.     SELECTED_SOURCE = nil
  74.     SELECTED_SINK = nil
  75.     getLocalLasso().From = nil
  76.     getLocalLasso().To = nil
  77. end
  78.  
  79. function clearScreenMessage()
  80.     if SCREEN_MESSAGE ~= nil then
  81.         SCREEN_MESSAGE:Remove()
  82.         SCREEN_MESSAGE = nil
  83.     end
  84. end
  85.  
  86. function clearHover()
  87.     if LAST_HOVERED_PART ~= nil then
  88.         local lastHover = LAST_HOVERED_PART
  89.         if not ANNOTATIONS[lastHover] then
  90.             lastHover = findModel(lastHover)
  91.         end
  92.  
  93.         ANNOTATIONS[lastHover].Transparency = BASE_ANNOTATION_TRANSPARENCY
  94.         if WIRING_PANEL_MAP[lastHover] ~= nil then
  95.             WIRING_PANEL_MAP[lastHover]:Remove()
  96.             WIRING_PANEL_MAP[lastHover] = nil
  97.         end
  98.         setPartWireTransparency(LAST_HOVERED_PART, BASE_WIRE_TRANSPARENCY, BASE_WIRE_RADIUS, "")
  99.     end
  100. end
  101.  
  102. function getPlayerGui()
  103.     if STATIC_PLAYER_GUI == nil then
  104.         STATIC_PLAYER_GUI = game.Players:GetPlayerFromCharacter(Tool.Parent).PlayerGui
  105.     end
  106.     return STATIC_PLAYER_GUI
  107. end
  108.  
  109. function findMyBasePlate()
  110.     if isRestricted then
  111.         if STATIC_BASE_PLATE == nil then
  112.             local buildingAreas = game.Workspace.BuildingAreas:GetChildren()
  113.             for i = 1, #buildingAreas do
  114.                 if buildingAreas[i]:FindFirstChild("Player") then
  115.                     if buildingAreas[i].Player.Value == game.Players.LocalPlayer.Name then
  116.                         waitForChild(buildingAreas[i],"PlayerArea")
  117.                         STATIC_BASE_PLATE = buildingAreas[i].PlayerArea
  118.                     end
  119.                 end
  120.             end
  121.         end
  122.         return STATIC_BASE_PLATE
  123.     end
  124.  
  125.     return nil
  126. end
  127.  
  128. function getLocalLasso()
  129.     if not game.Players.LocalPlayer.PlayerGui:FindFirstChild("lasso") then
  130.         local lasso = Instance.new("FloorWire")
  131.         lasso.Name = "lasso"
  132.         lasso.Parent = game.Players.LocalPlayer.PlayerGui
  133.         lasso.Color = BrickColor.new("Really black")
  134.     end
  135.  
  136.     return game.Players.LocalPlayer.PlayerGui.lasso
  137. end
  138.  
  139. function findModel(part)
  140.     if isRestricted then
  141.         local basePlate = findMyBasePlate()
  142.         while part ~= nil do
  143.             if part.className == "Model" and part.Name ~= basePlate.Name and part.Name ~= "GarbageParts" then
  144.                 return part
  145.             elseif part.Name == basePlate.Name or part.Name == "GarbageParts" then
  146.                 return nil
  147.             end
  148.             part = part.Parent
  149.         end
  150.     else
  151.         local origPart = part
  152.         while part ~= nil do
  153.             if part.className == "Model" then
  154.                 return part
  155.             elseif part.Name == "Workspace" or part.Name == "game" then
  156.                 return origPart
  157.             end
  158.             part = part.Parent
  159.         end
  160.     end
  161.  
  162.     return nil
  163. end
  164.  
  165. function createVisualAnnotation(part, guiMain)
  166.     local selection = Instance.new("SelectionBox", guiMain)
  167.     selection.Name = "Annotation"
  168.     selection.Color = BrickColor.new("Lime green")
  169.     selection.Transparency = BASE_ANNOTATION_TRANSPARENCY
  170.     selection.Adornee = part
  171.     return selection
  172. end
  173.  
  174. function isInteractivePart(obj)
  175.     if obj == nil then return false end
  176.     if obj:IsA("Part") then
  177.         for idx, child in ipairs(obj:GetChildren()) do
  178.             if child:IsA("CustomEvent") or child:IsA("CustomEventReceiver") then
  179.                 return true
  180.             end
  181.         end
  182.     end
  183.     return false
  184. end
  185.  
  186. function applyToConnectorsWires(sourceOrSink, fn)
  187.     if sourceOrSink:IsA("CustomEvent") then
  188.         for idx, recv in ipairs(sourceOrSink:GetAttachedReceivers()) do
  189.             fn(WIRE_LASSO_MAP[sourceOrSink][recv])
  190.         end
  191.     else
  192.         local source = sourceOrSink.Source
  193.         if source ~= nil then
  194.             fn(WIRE_LASSO_MAP[source][sourceOrSink])
  195.         end
  196.     end
  197. end
  198.  
  199. function warnNoWireableParts()
  200.     local topHint = nil
  201.     pcall(function() topHint = getPlayerGui().Gui.Hints.CenterHint end)
  202.    
  203.     if topHint then
  204.         topHint.Add.Label.Value = "No Wiring Parts!  Add Wiring Parts using the Stamper Tool."
  205.         topHint.Add.Width.Value = 580
  206.         topHint.Add.Time.Value = 10
  207.         topHint.Add.Disabled = true  -- flip it off then on, in case it's currently running.
  208.         topHint.Add.Disabled = false
  209.     end
  210. end
  211.  
  212. function warnNotClickingWireablePart()
  213.     if getPlayerGui():FindFirstChild("CenterHint", true) then
  214.         local topHint = getPlayerGui().Gui.Hints.CenterHint
  215.         topHint.Add.Label.Value = "This part isn't wireable :("
  216.         topHint.Add.Width.Value = 580
  217.         topHint.Add.Time.Value = 2
  218.         topHint.Add.Disabled = true  -- flip it off then on, in case it's currently running.
  219.         topHint.Add.Disabled = false
  220.     end
  221. end
  222.  
  223. --------------------------------------------------------------------------------
  224. -- Screen messages (when source/sink is selected)
  225.  
  226. function stylizeScreenMessageLabel(label, text)
  227.     label.Text = text
  228.     label.FontSize = Enum.FontSize.Size24
  229.     label.Font = Enum.Font.ArialBold
  230.     label.BackgroundTransparency = 1
  231.     label.BorderSizePixel = 0
  232.     label.Size = UDim2.new(0, label.TextBounds.x, 0, label.TextBounds.y)
  233.     label.TextColor3 = Color3.new(1, 1, 1)
  234. end
  235.  
  236. function createSourceIcon(parent, precedingText)
  237.     local sourceIcon = Instance.new("ImageLabel", frame)
  238.     sourceIcon.Archivable = false
  239.     sourceIcon.Image = SOURCE_BUTTON_ICON_TEXTURE
  240.     sourceIcon.Size = UDim2.new(0, 30, 0, 30)
  241.     sourceIcon.BackgroundTransparency = 1
  242.     sourceIcon.BorderSizePixel = 0
  243.     sourceIcon.Position = UDim2.new(0,
  244.             precedingText.Position.X.Offset + precedingText.TextBounds.x + 5,
  245.             0, precedingText.Position.Y.Offset +
  246.                 ((precedingText.Size.Y.Offset - sourceIcon.Size.Y.Offset) / 2))
  247.     return sourceIcon
  248. end
  249.  
  250. function createSinkIcon(parent, precedingText)
  251.     local sinkIcon = Instance.new("ImageLabel", frame)
  252.     sinkIcon.Archivable = false
  253.     sinkIcon.Image = SINK_BUTTON_ICON_TEXTURE
  254.     sinkIcon.Size = UDim2.new(0, 30, 0, 30)
  255.     sinkIcon.BackgroundTransparency = 1
  256.     sinkIcon.BorderSizePixel = 0
  257.     sinkIcon.Position = UDim2.new(0,
  258.             precedingText.Position.X.Offset + precedingText.TextBounds.x + 5,
  259.             0, precedingText.Position.Y.Offset +
  260.                 ((precedingText.Size.Y.Offset - sinkIcon.Size.Y.Offset) / 2))
  261.     return sinkIcon
  262. end
  263.  
  264. function addToAllXPositions(objs, offset)
  265.     for idx, obj in ipairs(objs) do
  266.         pos = obj.Position
  267.         obj.Position = UDim2.new(0, pos.X.Offset + offset, 0, pos.Y.Offset)
  268.     end
  269. end
  270.  
  271. function showSourceScreenMessage(source)
  272.     gui = Instance.new("ScreenGui", getPlayerGui())
  273.     gui.Archivable = false
  274.     frame = Instance.new("Frame", gui)
  275.     frame.Archivable = false
  276.     frame.Style = Enum.FrameStyle.RobloxRound
  277.  
  278.     local line1part1 = Instance.new("TextLabel", frame)
  279.     line1part1.Archivable = false
  280.     stylizeScreenMessageLabel(line1part1, "Choose a")
  281.  
  282.     sinkIcon = createSinkIcon(frame, line1part1)
  283.    
  284.     line1part2 = Instance.new("TextLabel", frame)
  285.     line1part2.Archivable = false
  286.     stylizeScreenMessageLabel(line1part2, "receiver to trigger when")
  287.     line1part2.Position = UDim2.new(0,
  288.         sinkIcon.Position.X.Offset + sinkIcon.Size.X.Offset + 5, 0, 0)
  289.  
  290.     line1height = math.max(sinkIcon.Size.Y.Offset, line1part1.Size.Y.Offset)
  291.  
  292.     line2part1 = Instance.new("TextLabel", frame)
  293.     line2part1.Archivable = false
  294.     stylizeScreenMessageLabel(line2part1, source.Parent.Name)
  295.     line2part1.Position = UDim2.new(0, 0, 0, line1height)
  296.    
  297.     sourceIcon = createSourceIcon(frame, line2part1)
  298.  
  299.     line2part2 = Instance.new("TextLabel", frame)
  300.     stylizeScreenMessageLabel(line2part2, "signals ")
  301.     line2part2.Position = UDim2.new(0,
  302.         sourceIcon.Position.X.Offset + sourceIcon.Size.X.Offset + 5,
  303.         0, line2part1.Position.Y.Offset)
  304.  
  305.     line2part3 = Instance.new("TextLabel", frame)
  306.     stylizeScreenMessageLabel(line2part3, source.Name)
  307.     line2part3.TextColor3 = SOURCE_BUTTON_TEXT_COLOR
  308.     line2part3.Position = UDim2.new(0,
  309.         line2part2.Position.X.Offset + line2part2.Size.X.Offset,
  310.         0, line2part1.Position.Y.Offset)
  311.  
  312.     -- re-center
  313.     line1width = line1part2.Position.X.Offset + line1part2.Size.X.Offset
  314.     line2width = line2part3.Position.X.Offset + line2part3.Size.X.Offset
  315.  
  316.     if line1width > line2width then
  317.         local halfDelta = (line1width - line2width) / 2
  318.         addToAllXPositions({line2part1, sourceIcon, line2part2, line2part3}, halfDelta)
  319.     else
  320.         local halfDelta = (line2width - line1width) / 2
  321.         addToAllXPositions({line1part1, sinkIcon, line1part2}, halfDelta)
  322.     end
  323.  
  324.     frame.Size = UDim2.new(0, math.max(line1width, line2width) + 15,
  325.             0, 2 * line1height + 5)
  326.     frame.Position = UDim2.new(.5, -frame.Size.X.Offset/2, 0, 0)
  327.  
  328.     clearScreenMessage()
  329.     SCREEN_MESSAGE = gui
  330. end
  331.  
  332. function showSinkScreenMessage(sink)
  333.     gui = Instance.new("ScreenGui", getPlayerGui())
  334.     frame = Instance.new("Frame", gui)
  335.     frame.Style = Enum.FrameStyle.RobloxRound
  336.  
  337.     local line1part1 = Instance.new("TextLabel", frame)
  338.     stylizeScreenMessageLabel(line1part1, "Choose which")
  339.  
  340.     local sourceIcon = createSourceIcon(frame, line1part1)
  341.    
  342.     line1part2 = Instance.new("TextLabel", frame)
  343.     stylizeScreenMessageLabel(line1part2, "signal will cause")
  344.     line1part2.Position = UDim2.new(0,
  345.         sourceIcon.Position.X.Offset + sourceIcon.Size.X.Offset + 5, 0, 0)
  346.  
  347.     local line1height = math.max(sourceIcon.Size.Y.Offset, line1part1.Size.Y.Offset)
  348.  
  349.     line2part1 = Instance.new("TextLabel", frame)
  350.     stylizeScreenMessageLabel(line2part1, sink.Parent.Name .. " to")
  351.     line2part1.Position = UDim2.new(0, 0, 0, line1height)
  352.    
  353.     local sinkIcon = createSinkIcon(frame, line2part1)
  354.  
  355.     line2part2 = Instance.new("TextLabel", frame)
  356.     stylizeScreenMessageLabel(line2part2, sink.Name)
  357.     line2part2.TextColor3 = SINK_BUTTON_TEXT_COLOR
  358.     line2part2.Position = UDim2.new(0,
  359.         sinkIcon.Position.X.Offset + sinkIcon.Size.X.Offset,
  360.         0, line2part1.Position.Y.Offset)
  361.  
  362.     -- re-center
  363.     line1width = line1part2.Position.X.Offset + line1part2.Size.X.Offset
  364.     line2width = line2part2.Position.X.Offset + line2part2.Size.X.Offset
  365.  
  366.     if line1width > line2width then
  367.         local halfDelta = (line1width - line2width) / 2
  368.         addToAllXPositions({line2part1, sinkIcon, line2part2}, halfDelta)
  369.     else
  370.         local halfDelta = (line2width - line1width) / 2
  371.         addToAllXPositions({line1part1, sourceIcon, line1part2}, halfDelta)
  372.     end
  373.  
  374.     frame.Size = UDim2.new(0, math.max(line1width, line2width) + 15,
  375.             0, 2 * line1height + 5)
  376.     frame.Position = UDim2.new(.5, -frame.Size.X.Offset/2, 0, 0)
  377.  
  378.     clearScreenMessage()
  379.     SCREEN_MESSAGE = gui
  380. end
  381.  
  382. --------------------------------------------------------------------------------
  383. -- Hover
  384.  
  385. function setPartWireTransparency(part, transparency, wireRadius, texture)
  386.     for idx, child in ipairs(part:GetChildren()) do
  387.         if child:IsA("CustomEvent") then
  388.             for idx2, recv in ipairs(child:GetAttachedReceivers()) do
  389.                 addWireUiIfNotAlreadyThere(child, recv)
  390.                 WIRE_LASSO_MAP[child][recv].Transparency = transparency
  391.                 WIRE_LASSO_MAP[child][recv].WireRadius = wireRadius
  392.                 WIRE_LASSO_MAP[child][recv].Texture = texture
  393.                 WIRE_LASSO_MAP[child][recv].Color = BrickColor.new("Really black")
  394.             end
  395.         elseif child:IsA("CustomEventReceiver") then
  396.             local source = child.Source
  397.             if source ~= nil then
  398.                 addWireUiIfNotAlreadyThere(source, child)
  399.                 WIRE_LASSO_MAP[source][child].Transparency = transparency
  400.                 WIRE_LASSO_MAP[source][child].WireRadius = wireRadius
  401.                 WIRE_LASSO_MAP[source][child].Texture = texture
  402.                 WIRE_LASSO_MAP[source][child].Color = BrickColor.new("Really black")
  403.             end
  404.         end
  405.     end
  406. end
  407.  
  408. function canHighlight(part,model)
  409.     if (KNOWN_SOURCE_PARTS[part] and SELECTED_SOURCE == nil) or (KNOWN_SINK_PARTS[part] and SELECTED_SINK == nil) then
  410.         return true, part
  411.     elseif (KNOWN_SOURCE_PARTS[model] and SELECTED_SOURCE == nil) or (KNOWN_SINK_PARTS[model] and SELECTED_SINK == nil) then
  412.         return true, model
  413.     end
  414.  
  415.     return false, nil
  416. end
  417.  
  418. function hoverListener(mouse)
  419.     if mouse.Target == nil then return end
  420.  
  421.     local part = mouse.Target
  422.     local model = findModel(part)
  423.     if LAST_HOVERED_PART ~= part and findModel(LAST_HOVERED_PART) ~= model then
  424.         clearHover()
  425.         local highlight, instance = canHighlight(part,model)
  426.         if highlight then
  427.             LAST_HOVERED_PART = part
  428.             ANNOTATIONS[model].Transparency = 0
  429.             buildScreenPanel(model, mouse.X, mouse.Y)
  430.             setPartWireTransparency(part, 0, ENHANCED_WIRE_RADIUS, "")
  431.         else
  432.             LAST_HOVERED_PART = nil
  433.         end
  434.  
  435.         -- Point the temporary wire to the LAST_HOVERED_PART if not nil,
  436.         -- otherwise point it at the character
  437.         local otherEndOfWire = game.Players.LocalPlayer.Character.Humanoid.Torso
  438.         if LAST_HOVERED_PART ~= nil then
  439.             otherEndOfWire = LAST_HOVERED_PART
  440.         end
  441.         if SELECTED_SOURCE ~= nil then
  442.             getLocalLasso().To = otherEndOfWire
  443.         end
  444.         if SELECTED_SINK ~= nil then
  445.             getLocalLasso().From = otherEndOfWire
  446.         end
  447.     end
  448. end
  449.  
  450. --------------------------------------------------------------------------------
  451. -- Connect / Disconnect dialog
  452.  
  453. function addWireUiIfNotAlreadyThere(source, sink)
  454.     if WIRE_LASSO_MAP[source] == nil then
  455.         WIRE_LASSO_MAP[source] = {}
  456.     end
  457.     if WIRE_LASSO_MAP[source][sink] ~= nil then
  458.         return
  459.     end
  460.  
  461.     pairLasso = Instance.new("FloorWire", getPlayerGui())
  462.     pairLasso.From = source.Parent
  463.     pairLasso.To = sink.Parent
  464.     pairLasso.Transparency = BASE_WIRE_TRANSPARENCY
  465.     pairLasso.Texture = ""
  466.     pairLasso.Name = WIRE_LASSO
  467.     pairLasso.Color = BrickColor.new("Really black")
  468.     WIRE_LASSO_MAP[source][sink] = pairLasso
  469. end
  470.  
  471. function connectHelper(source, sink)
  472.     -- clear wires coming to sink
  473.     local old_source = sink.Source
  474.     if old_source ~= nil then
  475.         wire = WIRE_LASSO_MAP[old_source][sink]
  476.         if wire ~= nil then
  477.             wire:Remove()
  478.             WIRE_LASSO_MAP[old_source][sink] = nil
  479.         end
  480.         sink.Source = nil
  481.     end
  482.  
  483.     sink.Source = source
  484.     addWireUiIfNotAlreadyThere(source, sink)
  485. end
  486.  
  487. function makeSourceConnectCallback(source)
  488.     return function()
  489.         clearHover()
  490.         if SELECTED_SINK ~= nil then
  491.             connectHelper(source, SELECTED_SINK)
  492.             clearSelection()
  493.             clearScreenMessage()
  494.             for part, val in pairs(KNOWN_SINK_PARTS) do
  495.                 local model = findModel(part)
  496.                 ANNOTATIONS[model].Transparency = BASE_ANNOTATION_TRANSPARENCY
  497.             end
  498.         else
  499.             SELECTED_SOURCE = source
  500.             getLocalLasso().From = source.Parent
  501.             getLocalLasso().To = game.Players.LocalPlayer.Character.Humanoid.Torso
  502.             showSourceScreenMessage(SELECTED_SOURCE)
  503.             for part, val in pairs(KNOWN_SOURCE_PARTS) do
  504.                 if not KNOWN_SINK_PARTS[part] then
  505.                     local model = findModel(part)
  506.                     ANNOTATIONS[model].Transparency = 1
  507.                 end
  508.             end
  509.         end
  510.     end
  511. end
  512.  
  513. function makeSinkConnectCallback(sink)
  514.     return function()
  515.         clearHover()
  516.         if SELECTED_SOURCE ~= nil then
  517.             connectHelper(SELECTED_SOURCE, sink)
  518.             clearSelection()
  519.             clearScreenMessage()
  520.             for part, val in pairs(KNOWN_SOURCE_PARTS) do
  521.                 local model = findModel(part)
  522.                 ANNOTATIONS[model].Transparency = BASE_ANNOTATION_TRANSPARENCY
  523.             end
  524.         else
  525.             SELECTED_SINK = sink
  526.             getLocalLasso().From = game.Players.LocalPlayer.Character.Humanoid.Torso
  527.             getLocalLasso().To = sink.Parent
  528.             showSinkScreenMessage(SELECTED_SINK)
  529.             for part, val in pairs(KNOWN_SINK_PARTS) do
  530.                 if not KNOWN_SOURCE_PARTS[part] then
  531.                     local model = findModel(part)
  532.                     ANNOTATIONS[model].Transparency = 1
  533.                 end
  534.             end
  535.         end
  536.     end
  537. end
  538.  
  539. function makeControlButton(y_position, frame, sourceOrSink, textColor, iconImage, iconHoverImage, callbackBuilder)
  540.     local button = Instance.new("TextButton", frame)
  541.     button.Position = UDim2.new(.025, 0, 0, y_position)
  542.     button.Text = sourceOrSink.Name
  543.     button.TextXAlignment = Enum.TextXAlignment.Left
  544.     button.Style = Enum.ButtonStyle.Custom
  545.     button.BorderSizePixel = 0
  546.     button.BackgroundTransparency = 1
  547.     button.BackgroundColor3 = Color3.new(0, 0 ,0)
  548.     button.TextColor3 = textColor
  549.     button.Font = Enum.Font.ArialBold
  550.     button.FontSize = Enum.FontSize.Size18
  551.     button.ZIndex = 2
  552.     button.Size = UDim2.new(.95, 0, 0, button.TextBounds.y)
  553.    
  554.     local icon = Instance.new("ImageLabel", button)
  555.     icon.Image = iconImage
  556.     icon.ZIndex = 2
  557.     icon.Position = UDim2.new(0, button.TextBounds.x + 10, 0, -8)
  558.     icon.Size = UDim2.new(0, 30, 0 , 30)
  559.     icon.BackgroundTransparency = 1
  560.  
  561.     button.MouseEnter:connect(function()
  562.         applyToConnectorsWires(sourceOrSink, function(wire)
  563.             wire.Texture = WIRE_TEXTURE
  564.             wire.Velocity = 2
  565.         end)
  566.         button.BackgroundTransparency = 0
  567.         button.TextColor3 = BUTTON_HOVER_TEXT_COLOR
  568.         icon.Image = iconHoverImage
  569.     end)
  570.     local leaveCallback = function()
  571.         applyToConnectorsWires(sourceOrSink, function(wire)
  572.             wire.Texture = ""
  573.         end)
  574.         button.BackgroundTransparency = 1
  575.         button.TextColor3 = textColor
  576.         icon.Image = iconImage
  577.     end
  578.     button.MouseLeave:connect(leaveCallback)
  579.     button.MouseButton1Click:connect(function()
  580.         callbackBuilder(sourceOrSink)()
  581.         leaveCallback()
  582.     end)
  583.     return button
  584. end
  585.  
  586. function makeDisconnectCallback(source, sink)
  587.     clearHover()
  588.     sink.Source = nil
  589.     if WIRE_LASSO_MAP[source] ~= nil then
  590.         lassoUi = WIRE_LASSO_MAP[source][sink]
  591.         if lassoUi ~= nil then
  592.             lassoUi:Remove()
  593.             WIRE_LASSO_MAP[source][sink] = nil
  594.         end
  595.     end
  596. end
  597.  
  598. function makeDisconnectButton(y_position, frame, localConnector, foreignConnector, textColor, iconImage)
  599.     local source = nil
  600.     local sink = nil
  601.     if localConnector:IsA("CustomEvent") then
  602.         source = localConnector
  603.         sink = foreignConnector
  604.     else
  605.         source = foreignConnector
  606.         sink = localConnector
  607.     end
  608.  
  609.     local button = Instance.new("TextButton", frame)
  610.     button.Position = UDim2.new(0, 17, 0, y_position)
  611.     button.Text = foreignConnector.Name .. " (" .. foreignConnector.Parent.Name .. ")"
  612.     button.TextXAlignment = Enum.TextXAlignment.Left
  613.     button.Style = Enum.ButtonStyle.Custom
  614.     button.BackgroundTransparency = 1
  615.     button.BackgroundColor3 = Color3.new(0, 0 ,0)
  616.     button.TextColor3 = textColor
  617.     button.BorderSizePixel = 0
  618.     button.Font = Enum.Font.Arial
  619.     button.FontSize = Enum.FontSize.Size18
  620.     button.ZIndex = 3
  621.     button.Size = UDim2.new(.95, -10, 0, button.TextBounds.y + 2)
  622.    
  623.     local icon = Instance.new("ImageLabel", button)
  624.     icon.Image = iconImage
  625.     icon.Parent = button
  626.     icon.Position = UDim2.new(0, button.TextBounds.x + 10, 0, 2)
  627.     icon.Size = UDim2.new(0, 15, 0 , 15)
  628.     icon.BackgroundTransparency = 1
  629.  
  630.     local buttonCons = {}
  631.  
  632.     table.insert(buttonCons,
  633.         button.MouseButton1Click:connect(function()
  634.             makeDisconnectCallback(source, sink)
  635.         end)
  636.     )
  637.     table.insert(buttonCons,
  638.         button.MouseEnter:connect(function()
  639.             button.BackgroundTransparency = 0
  640.             button.TextColor3 = BUTTON_HOVER_TEXT_COLOR
  641.             icon.Image = DISCONNECT_ICON_HOVER_TEXTURE
  642.             WIRE_LASSO_MAP[source][sink].Color = BrickColor.new("Really red")
  643.         end)
  644.     )
  645.     table.insert(buttonCons,
  646.         button.MouseLeave:connect(function()
  647.         button.BackgroundTransparency = 1
  648.         button.TextColor3 = textColor
  649.         icon.Image = iconImage
  650.         WIRE_LASSO_MAP[source][sink].Color = BrickColor.new("Really black")
  651.     end)
  652.     )
  653.  
  654.     table.insert(buttonCons,
  655.         button.AncestryChanged:connect(function(child,parent)
  656.             if parent == nil then
  657.                 for i = 1, #buttonCons do
  658.                     buttonCons[i]:disconnect()
  659.                 end
  660.             end
  661.         end)
  662.     )
  663.  
  664.     return button
  665. end
  666.  
  667. function getPartSourcesAndSinks(part, sources,sinks)
  668.     for idx, child in ipairs(part:GetChildren()) do
  669.         if child:IsA("CustomEvent") then
  670.             table.insert(sources, child)
  671.         elseif child:IsA("CustomEventReceiver") then
  672.             table.insert(sinks, child)
  673.         end
  674.     end
  675. end
  676.  
  677. function getSourcesAndSinks(instance,sources,sinks)
  678.     if instance:IsA("BasePart") then
  679.         getPartSourcesAndSinks(instance, sources,sinks)
  680.     elseif instance:IsA("Model") then
  681.         local modelChildren = instance:GetChildren()
  682.         for i = 1, #modelChildren do
  683.             if modelChildren[i]:IsA("BasePart") then
  684.                 getPartSourcesAndSinks(modelChildren[i],sources,sinks)
  685.             elseif modelChildren[i]:IsA("Model") then
  686.                 getSourcesAndSinks(modelChildren[i],sources,sinks)
  687.             end
  688.         end
  689.     end
  690. end
  691.  
  692. local function findFirstConnector(node)
  693.     if node:IsA("BasePart") then
  694.         for idx, child in ipairs(node:GetChildren()) do
  695.             if connector == nil and (child:IsA("CustomEvent") or child:IsA("CustomEventReceiver")) then
  696.                 return child
  697.             end
  698.         end
  699.     else
  700.         local children = node:GetChildren()
  701.         if #children == 0 then
  702.             return nil
  703.         end
  704.         for i = 1, #children do
  705.             local subConnector = findFirstConnector(children[i])
  706.             if subConnector then return subConnector end
  707.         end
  708.     end
  709. end
  710.  
  711. function buildScreenPanel(part, x, y)
  712.     sources = {}
  713.     sinks = {}
  714.     getSourcesAndSinks(part,sources,sinks)
  715.  
  716.     local gui = nil
  717.     local mouseFrame = nil
  718.     if USE_BILLBOARD_GUI then
  719.         gui = Instance.new("BillboardGui", getPlayerGui())
  720.         gui.Name = "WiringGui"
  721.         gui.StudsOffset = Vector3.new(0, 1.5, 0)
  722.         gui.ExtentsOffset = Vector3.new(0,0, 0)
  723.         gui.Adornee = part
  724.         gui.Active = true
  725.         gui.AlwaysOnTop = true
  726.     else
  727.         gui = Instance.new("ScreenGui", getPlayerGui())
  728.     end
  729.  
  730.     frame = Instance.new("Frame", gui)
  731.     frame.Style = Enum.FrameStyle.RobloxRound
  732.     frame.ZIndex = 1
  733.     frame.Active = true
  734.  
  735.     local maxWidth = 0
  736.     local y_position = 5
  737.  
  738.     if SELECTED_SOURCE == nil then
  739.         for idx, source in ipairs(sources) do
  740.             local button = makeControlButton(y_position, frame, source, SOURCE_BUTTON_TEXT_COLOR,
  741.                     SOURCE_BUTTON_ICON_TEXTURE, SOURCE_BUTTON_ICON_HOVER_TEXTURE,
  742.                     makeSourceConnectCallback)
  743.             maxWidth = math.max(1.25 * (button.TextBounds.x + BUTTON_ICON_WIDTH), maxWidth)
  744.             y_position = y_position + button.TextBounds.y
  745.  
  746.             receivers = source:GetAttachedReceivers()
  747.             for sub_idx, receiver in ipairs(receivers) do
  748.                 y_position = y_position + 2
  749.                 addWireUiIfNotAlreadyThere(source, receiver)
  750.                 local button = makeDisconnectButton(y_position, frame, source, receiver,
  751.                     SINK_BUTTON_TEXT_COLOR, DISCONNECT_SINK_ICON_TEXTURE)
  752.                 y_position = y_position + button.TextBounds.y
  753.                 maxWidth = math.max(1.15 * (button.TextBounds.x + 17 + 25), maxWidth)
  754.             end
  755.             y_position = y_position + 5
  756.         end
  757.     end
  758.  
  759.     if SELECTED_SINK == nil then
  760.         for idx, sink in ipairs(sinks) do
  761.             local button = makeControlButton(y_position, frame, sink, SINK_BUTTON_TEXT_COLOR,
  762.                     SINK_BUTTON_ICON_TEXTURE, SINK_BUTTON_ICON_HOVER_TEXTURE,
  763.                     makeSinkConnectCallback)
  764.             maxWidth = math.max(1.25 * (button.TextBounds.x + BUTTON_ICON_WIDTH), maxWidth)
  765.             y_position = y_position + button.TextBounds.y
  766.  
  767.             local sender = sink.Source
  768.             if sender ~= nil then
  769.                 y_position = y_position + 2
  770.                 -- addWire takes source first
  771.                 addWireUiIfNotAlreadyThere(sender, sink)
  772.                 local button = makeDisconnectButton(y_position, frame, sink, sender,
  773.                     SOURCE_BUTTON_TEXT_COLOR, DISCONNECT_SOURCE_ICON_TEXTURE)
  774.                 y_position = y_position + button.TextBounds.y
  775.                 maxWidth = math.max(1.15 * (button.TextBounds.x + 17 + 25), maxWidth)
  776.             end
  777.             y_position = y_position + 5
  778.         end
  779.     end
  780.  
  781.     -- set size and position
  782.     if not getPlayerGui():FindFirstChild("ScreenGui") then
  783.         local screenGui = Instance.new("ScreenGui")
  784.         screenGui.Parent = getPlayerGui()
  785.     end
  786.  
  787.     local screenSize = getPlayerGui().ScreenGui.AbsoluteSize
  788.     local menuWidth = maxWidth
  789.     local menuHeight = y_position + 17.5
  790.     if USE_BILLBOARD_GUI then
  791.  
  792.        
  793.         local size = Vector3.new(0,0,0)
  794.         if gui.Adornee:IsA("BasePart") then
  795.             size = gui.Adornee.Size
  796.         elseif gui.Adornee:IsA("Model") then
  797.             size = gui.Adornee:GetModelSize()
  798.         end
  799.  
  800.         local xSize= size.X
  801.         if size.Y > xSize then
  802.             xSize = size.Y
  803.         end
  804.  
  805.         gui.Size = UDim2.new(0, menuWidth,0,menuHeight + 150)
  806.         gui.SizeOffset = Vector2.new(0, -50.0 / (menuHeight + 150));
  807.        
  808.         local tail = Instance.new("ImageLabel", frame)
  809.         tail.Size = UDim2.new(0, 32, 0, 32)
  810.         tail.Position = UDim2.new(.5, -16, 1, 8)
  811.         tail.Image = TAIL_TEXTURE
  812.         tail.BackgroundTransparency = 1
  813.         tail.Visible = true
  814.  
  815.         f = Instance.new("Frame", gui)
  816.         f.Size = UDim2.new(1, 0, 1, 0)
  817.         f.BackgroundTransparency = 1
  818.         f.ZIndex = 1
  819.         f.Active = true
  820.         b = Instance.new("TextButton", f)
  821.         b.ZIndex = 1
  822.         b.BackgroundTransparency = 1
  823.         b.Text = ""
  824.         b.BorderSizePixel = 0
  825.         b.Size = UDim2.new(1, 0, 1, 0)
  826.         b.MouseButton1Click:connect(function()
  827.             local foundConnector = findFirstConnector(findModel(LAST_HOVERED_PART))
  828.             if foundConnector ~= nil and foundConnector:IsA("CustomEvent") then
  829.                 makeSourceConnectCallback(foundConnector)()
  830.             elseif foundConnector ~= nil and foundConnector:IsA("CustomEventReceiver") then
  831.                 makeSinkConnectCallback(foundConnector)()
  832.             end
  833.         end)
  834.     else
  835.         x = math.min(x - 9, screenSize.x - menuWidth)
  836.         y = math.min(y - 9, screenSize.y - menuHeight)
  837.         frame.Position = UDim2.new(0, x, 0, y)
  838.     end
  839.  
  840.     frame.Size = UDim2.new(0, menuWidth, 0, menuHeight)
  841.     frame.Position = UDim2.new(0.5,-menuWidth/2,0.05,0)
  842.     WIRING_PANEL_MAP[part] = gui
  843. end
  844.  
  845. function inBaseplate(instance)
  846.     if instance == STATIC_BASE_PLATE then return true end
  847.  
  848.     local instanceCopy = instance
  849.  
  850.     while instanceCopy and (instanceCopy.Parent ~= nil or instanceCopy.Parent ~= game.Workspace) do
  851.         if instanceCopy.Parent == STATIC_BASE_PLATE then
  852.             return true
  853.         end
  854.         instanceCopy = instanceCopy.Parent
  855.     end
  856.  
  857.     return false
  858. end
  859.  
  860. --------------------------------------------------------------------------------
  861. -- Tool.Equipped/Unequipped
  862.  
  863. Tool.Equipped:connect(function(mouse)
  864.     local player = game.Players:getPlayerFromCharacter(Tool.Parent)
  865.     if not player then return end
  866.  
  867.     if playerOwner.Value and playerOwner.Value ~= player then return end
  868.     playerOwner.Value = player
  869.  
  870.     playerGui = getPlayerGui()
  871.     LAST_HOVERED_PART = nil
  872.  
  873.     if isRestricted then
  874.         root = findMyBasePlate()
  875.     else
  876.         root = game.Workspace
  877.     end
  878.  
  879.     local interactiveCount = setUpConfigurationService()
  880.  
  881.     if not interactiveCount or interactiveCount == 0 then
  882.         warnNoWireableParts()
  883.     end
  884.  
  885.     getLocalLasso().Texture = WIRE_TEXTURE
  886.     getLocalLasso().WireRadius = ENHANCED_WIRE_RADIUS
  887.     clearSelection()
  888.  
  889.     mouse.Icon = "http://www.roblox.com/asset?id=66887773"
  890.     mouseMoveCon = mouse.Move:connect(function() hoverListener(mouse) end)
  891.     mouseButtonDownCon = mouse.Button1Down:connect(function()
  892.         if LAST_HOVERED_PART ~= nil then return end
  893.  
  894.         clearSelection()
  895.         clearScreenMessage()
  896.         clearHover()
  897.         local annotationCount = 0
  898.         for part, annotation in pairs(ANNOTATIONS) do
  899.             annotation.Transparency = BASE_ANNOTATION_TRANSPARENCY
  900.             annotationCount = annotationCount + 1
  901.         end
  902.         if annotationCount == 0 then
  903.             warnNoWireableParts()
  904.         elseif time() - LAST_CLICK_TIME < CLICK_HELP_TIME_DELTA then
  905.             warnNotClickingWireablePart()
  906.         end
  907.         LAST_CLICK_TIME = time()
  908.     end)
  909.     -- TODO: onkeydown/onmouse2down, prevent hover from triggering
  910.     -- until the up event comes
  911. end)
  912.  
  913. Tool.Unequipped:connect(function()
  914.     playerGui = getPlayerGui()
  915.  
  916.     destroyConfigurationService()
  917.  
  918.     if mouseMoveCon then mouseMoveCon:disconnect() end
  919.     if mouseButtonDownCon then mouseButtonDownCon:disconnect() end
  920.  
  921.     if playerGui:FindFirstChild("CenterHint", true) then
  922.         local centerHint = getPlayerGui().Gui.Hints.CenterHint
  923.         centerHint.Delete.Disabled = false
  924.     end
  925.  
  926.     -- TODO: simplify these side effects
  927.     -- call clearHover before removing annotations, because
  928.     -- clear hover resets annotation boxes. Also before clearing
  929.     -- lassos because this may create lassos
  930.     clearHover()
  931.  
  932.     for part, gui in pairs(WIRING_PANEL_MAP) do
  933.         if gui then gui:Remove() end
  934.     end
  935.     WIRING_PANEL_MAP = {}
  936.  
  937.     for source, submap in pairs(WIRE_LASSO_MAP) do
  938.         for sink, wire in pairs(submap) do
  939.             wire:Remove()
  940.         end
  941.     end
  942.     WIRE_LASSO_MAP = {}
  943.  
  944.     for k,box in pairs(ANNOTATIONS) do
  945.         box:Remove()
  946.     end
  947.     ANNOTATIONS = {}
  948.  
  949.     KNOWN_SOURCE_PARTS = {}
  950.     KNOWN_SINK_PARTS = {}
  951.  
  952.     clearSelection()
  953.     clearScreenMessage()
  954.     LAST_HOVERED_PART = nil
  955. end)
  956.  
  957. function findBillboard(guiTable)
  958.     if not guiTable then return end
  959.  
  960.     for i = 1, #guiTable do
  961.         if guiTable[i] and guiTable[i]:IsA("BillboardGui") then
  962.             return guiTable[i]
  963.         end
  964.     end
  965. end
  966.  
  967. function getBillboard(adornee)
  968.     local guiKey = adornee
  969.  
  970.    
  971.     local billboard = findBillboard(adornmentTable[guiKey])
  972.     if not billboard then
  973.         local screen = Instance.new("BillboardGui")
  974.         screen.Name = adornee.Name .. "BadgeGUI"
  975.         screen.Size = UDim2.new(1.5,0,1.5,0)
  976.         screen.Enabled = true
  977.         screen.Active = true
  978.         screen.AlwaysOnTop = true
  979.         screen.ExtentsOffset = Vector3.new(0,0,0)
  980.         screen.Adornee = adornee
  981.         screen.Parent = game.Players.LocalPlayer.PlayerGui
  982.  
  983.         if not adornmentTable[guiKey] then return end
  984.         table.insert(adornmentTable[guiKey],screen)
  985.  
  986.         local badgeFrame = Instance.new("Frame")
  987.         badgeFrame.Name = "BadgeFrame"
  988.         badgeFrame.Size = UDim2.new(2,0,1,0)
  989.         badgeFrame.Position = UDim2.new(-0.5,0,0,0)
  990.         badgeFrame.BackgroundTransparency = 1
  991.         badgeFrame.Parent = screen
  992.  
  993.         return screen
  994.     end
  995.  
  996.     return billboard
  997. end
  998.  
  999. function repositionBadges(badgeFrame)
  1000.     local badges = badgeFrame:GetChildren()
  1001.     if #badges == 1 then
  1002.         badges[1].Position = UDim2.new(0.25,0,0,0)
  1003.     elseif #badges == 2 then
  1004.         badges[1].Position = UDim2.new(0,0,0,0)
  1005.         badges[2].Position = UDim2.new(0.5,0,0)
  1006.     end
  1007. end
  1008.  
  1009. function hasBadge(adornee, type)
  1010.     local screen = getBillboard(adornee)
  1011.     return screen:FindFirstChild(type .. "Badge",true)
  1012. end
  1013.  
  1014. function removeBadge(adornee, type)
  1015.     local screen = getBillboard(adornee)
  1016.     local badge = screen:FindFirstChild(type .. "Badge",true)
  1017.     if badge then badge:remove() end
  1018. end
  1019.  
  1020. function createBadge(adornee,type)
  1021.     local screen = getBillboard(adornee)
  1022.  
  1023.     local wiringBadge = Instance.new("ImageLabel")
  1024.     wiringBadge.Name = type .. "Badge"
  1025.     wiringBadge.BackgroundTransparency = 1
  1026.     if type == "Receiver" then
  1027.         wiringBadge.Image = SOURCE_BADGE_TEXTURE
  1028.     else
  1029.         wiringBadge.Image = SINK_BADGE_TEXTURE
  1030.     end
  1031.  
  1032.     wiringBadge.Position = UDim2.new(0.25,0,0,0)
  1033.     wiringBadge.Size = UDim2.new(0.5,0,1,0)
  1034.     wiringBadge.Parent = screen.BadgeFrame
  1035.     wiringBadge.Changed:connect(function(prop)
  1036.         if prop == "AbsoluteSize" then
  1037.             if wiringBadge.AbsoluteSize.X < 10 then
  1038.                 wiringBadge.Visible = false
  1039.             else
  1040.                 wiringBadge.Visible = true
  1041.             end
  1042.         end
  1043.     end)
  1044.  
  1045.     repositionBadges(screen.BadgeFrame)
  1046. end
  1047.  
  1048. function upAdorneeCount(adornee,type)
  1049.     local typeLower = string.lower(type)
  1050.     if typeLower == "receiver" then
  1051.         if not receiverBadgeCount[adornee] then
  1052.             receiverBadgeCount[adornee] = 1
  1053.         else
  1054.             receiverBadgeCount[adornee] = receiverBadgeCount[adornee] + 1
  1055.         end
  1056.     elseif typeLower == "event" then
  1057.         if not eventBadgeCount[adornee] then
  1058.             eventBadgeCount[adornee] = 1
  1059.         else
  1060.             eventBadgeCount[adornee] = eventBadgeCount[adornee] + 1
  1061.         end
  1062.     end
  1063. end
  1064.  
  1065. function downAdorneeCount(adornee,type)
  1066.     local typeLower = string.lower(type)
  1067.     if typeLower == "receiver" then
  1068.         if receiverBadgeCount[adornee] then
  1069.             receiverBadgeCount[adornee] = receiverBadgeCount[adornee] - 1
  1070.             if receiverBadgeCount[adornee] < 1 then
  1071.                 receiverBadgeCount[adornee] = nil
  1072.             end
  1073.         end
  1074.     elseif typeLower == "event" then
  1075.         if eventBadgeCount[adornee] then
  1076.             eventBadgeCount[adornee] = eventBadgeCount[adornee] - 1
  1077.             if eventBadgeCount[adornee] < 1 then
  1078.                 eventBadgeCount[adornee] = nil
  1079.             end
  1080.         end
  1081.     end
  1082. end
  1083.  
  1084. function createAdornment(adornee,adornColor,type)
  1085.     upAdorneeCount(adornee,type)
  1086.  
  1087.     if receiverBadgeCount[adornee] == 1 or eventBadgeCount[adornee] == 1 then
  1088.         local box = Instance.new("SelectionBox")
  1089.         box.Color = adornColor
  1090.         box.Name = adornee.Name .. "Selection" .. tostring(type)
  1091.         box.Adornee = adornee
  1092.         box.Transparency = 0.5
  1093.         box.Parent = game.Players.LocalPlayer.PlayerGui
  1094.         if not adornmentTable[adornee] then
  1095.             adornmentTable[adornee] = {}
  1096.         end
  1097.  
  1098.         ANNOTATIONS[adornee] = box
  1099.         table.insert(adornmentTable[adornee],box)
  1100.  
  1101.         if not hasBadge(adornee,type) then
  1102.             createBadge(adornee,type)
  1103.         end
  1104.     end
  1105. end
  1106.  
  1107. function doRemoveAdornment(adornee, type)
  1108.     local key = adornee
  1109.     if not adornmentTable[key] then return end
  1110.     for i = 1, #adornmentTable[key] do
  1111.         if adornmentTable[key] and adornmentTable[key][i] then
  1112.             if string.find(adornmentTable[key][i].Name,type) then
  1113.                 adornmentTable[key][i]:remove()
  1114.                 adornmentTable[key][i] = nil
  1115.             end
  1116.         end
  1117.     end
  1118. end
  1119.  
  1120. function removeAdornment(adornee, type)
  1121.     downAdorneeCount(adornee,type)
  1122.  
  1123.     if type == "Receiver" then
  1124.         if not receiverBadgeCount[adornee]then
  1125.             removeBadge(adornee, type)
  1126.             doRemoveAdornment(adornee, type)
  1127.         end
  1128.     elseif type == "Event" then
  1129.         if not eventBadgeCount[adornee] then
  1130.             removeBadge(adornee, type)
  1131.             doRemoveAdornment(adornee, type)
  1132.         end
  1133.     end
  1134. end
  1135.  
  1136. function eventReceiverAdded(receiver,wirePartCount)
  1137.     if isRestricted then
  1138.         if not inBaseplate(receiver) then return wirePartCount end
  1139.     end
  1140.     receiverTable[receiver] = findModel(receiver.Parent)
  1141.     createAdornment(receiverTable[receiver], BrickColor.new("Lime green"), "Receiver")
  1142.     setPartWireTransparency(receiver.Parent, BASE_WIRE_TRANSPARENCY, BASE_WIRE_RADIUS, "")
  1143.  
  1144.     KNOWN_SINK_PARTS[receiver.Parent] = true
  1145.     KNOWN_SINK_PARTS[receiverTable[receiver]]= true
  1146.  
  1147.     if wirePartCount then
  1148.         return wirePartCount + 1
  1149.     else
  1150.         return 0
  1151.     end
  1152.  
  1153. end
  1154.  
  1155. function eventAdded(event,wirePartCount)
  1156.     if isRestricted then
  1157.         if not inBaseplate(event) then return wirePartCount end
  1158.     end
  1159.     eventTable[event] = findModel(event.Parent)
  1160.     createAdornment(eventTable[event], BrickColor.new("Bright orange"), "Event")
  1161.     setPartWireTransparency(event.Parent, BASE_WIRE_TRANSPARENCY, BASE_WIRE_RADIUS, "")
  1162.  
  1163.     KNOWN_SOURCE_PARTS[event.Parent] = true
  1164.     KNOWN_SOURCE_PARTS[eventTable[event]]= true
  1165.  
  1166.     if wirePartCount then
  1167.         return wirePartCount + 1
  1168.     else
  1169.         return 0
  1170.     end
  1171. end
  1172.  
  1173. function eventReceiverRemoved(receiver)
  1174.     if not receiverTable[receiver] then return end
  1175.  
  1176.     KNOWN_SINK_PARTS[receiver.Parent] = false
  1177.     KNOWN_SINK_PARTS[receiverTable[receiver]]= false
  1178.  
  1179.     removeAdornment(receiverTable[receiver],"Receiver")
  1180.     receiverTable[receiver] = nil
  1181. end
  1182.  
  1183. function eventRemoved(event)
  1184.     if not eventTable[event] then return end
  1185.  
  1186.     KNOWN_SOURCE_PARTS[event.Parent] = false
  1187.     KNOWN_SOURCE_PARTS[eventTable[event]]= false
  1188.  
  1189.     removeAdornment(eventTable[event], "Event")
  1190.     eventTable[event] = nil
  1191. end
  1192.  
  1193. function setUpConfigurationService()
  1194.     local wirePartCount = 0
  1195.     ServiceConnections = {}
  1196.     local collectionService = game:GetService("CollectionService")
  1197.  
  1198.     -- first lets check if anything already exists
  1199.     local receivers = collectionService:GetCollection("CustomEventReceiver")
  1200.     if receivers then
  1201.         for pos, receiver in pairs(receivers) do
  1202.             wirePartCount = eventReceiverAdded(receiver, wirePartCount)
  1203.         end
  1204.     end
  1205.  
  1206.     local events = collectionService:GetCollection("CustomEvent")
  1207.     if events then
  1208.         for pos, event in pairs(events) do
  1209.             wirePartCount = eventAdded(event, wirePartCount)
  1210.         end
  1211.     end
  1212.  
  1213.     -- Now lets listen for any future additions/removals
  1214.     ServiceConnections[#ServiceConnections+1] = collectionService.ItemAdded:connect(function(instance)
  1215.         if instance:IsA("CustomEventReceiver") then
  1216.             eventReceiverAdded(instance)
  1217.         elseif instance:IsA("CustomEvent") then
  1218.             eventAdded(instance)
  1219.         end
  1220.     end)
  1221.     ServiceConnections[#ServiceConnections+1] = collectionService.ItemRemoved:connect(function(instance)
  1222.         if instance:IsA("CustomEventReceiver") then
  1223.             eventReceiverRemoved(instance)
  1224.         elseif instance:IsA("CustomEvent") then
  1225.             eventRemoved(instance)
  1226.         end
  1227.     end)
  1228.  
  1229.     return wirePartCount
  1230. end
  1231.  
  1232. function destroyConfigurationService()
  1233.     -- first lets destroy the collection service
  1234.     for index, connection in pairs(ServiceConnections) do
  1235.         connection:disconnect()
  1236.     end
  1237.     ServiceConnections = {}
  1238.  
  1239.     -- now lets remove all of our collection service objects that were generated
  1240.     for event, object in pairs(eventTable) do
  1241.         eventRemoved(event)
  1242.     end
  1243.     for eventReceiver, object in pairs(receiverTable) do
  1244.         eventReceiverRemoved(eventReceiver)
  1245.     end
  1246. end
  1247.  
  1248.  
Tags: lua
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement