null nil true true 0 0 0 1 0 0 0 1 0 0 0 1 ClassicTool http://www.roblox.com/asset/?id=59105322 Classic Tool false ClassicToolController local Tool = script.Parent local keyUpCon = nil local gui = nil local connections = {} local buttons = {} local colorButton,SurfaceButton,MaterialButton,ResizeButton,draggerButton = nil game:GetService("ContentProvider"):Preload("http://www.roblox.com/asset?id=59103051") game:GetService("ContentProvider"):Preload("http://www.roblox.com/asset?id=59103080") game:GetService("ContentProvider"):Preload("http://www.roblox.com/asset?id=59103092") game:GetService("ContentProvider"):Preload("http://www.roblox.com/asset?id=59103119") game:GetService("ContentProvider"):Preload("http://www.roblox.com/asset?id=59103152") function makeImageButton(buttonName, image, position, parent, hotKeyString) local button = Instance.new("ImageButton") button.Name = buttonName button.Style = Enum.ButtonStyle.RobloxButton button.Size = UDim2.new(0,45,0,45) if position then button.Position = position end button.Parent = parent local buttonImage = Instance.new("ImageLabel") buttonImage.Name = "ButtonImage" buttonImage.BackgroundTransparency = 1 buttonImage.Size = UDim2.new(1,12,1,12) buttonImage.Position = UDim2.new(0,-6,0,-6) buttonImage.Image = image buttonImage.Parent = button if hotKeyString then local textShortcut = Instance.new("TextLabel") textShortcut.Text = hotKeyString textShortcut.Name = "TextShortcut" textShortcut.Font = Enum.Font.ArialBold textShortcut.BackgroundTransparency = 1 textShortcut.FontSize = Enum.FontSize.Size14 textShortcut.TextColor3 = Color3.new(1,1,1) textShortcut.Size = UDim2.new(0,textShortcut.TextBounds.X,0,textShortcut.TextBounds.X) textShortcut.Parent = button end return button end function deactivateTool(script) local enable = script:FindFirstChild("Active") if enable and enable:IsA("BoolValue") then enable.Value = false end end function deactivateAllTools() local toolChildren = Tool:GetChildren() for i = 1, #toolChildren do if toolChildren[i]:IsA("BaseScript") and toolChildren[i] ~= script then deactivateTool(toolChildren[i]) end end for i = 1, #buttons do buttons[i].Selected = false end end function goToTool(toolName, button) deactivateAllTools() button.Selected = true wait() -- give scripts a heartbeat to get set straight local toolScript = Tool:FindFirstChild(toolName) if toolScript and toolScript:IsA("BaseScript") then local enable = toolScript:FindFirstChild("Active") if enable and enable:IsA("BoolValue") then enable.Value = true end end end function makeClassicControlGui() clearAllConnections() local classicGui = Instance.new("ScreenGui") classicGui.Name = "ClassicGui" local classicFrame = Instance.new("Frame") classicFrame.Name = "ClassicFrame" classicFrame.BackgroundTransparency = 1 classicFrame.Size = UDim2.new(0,246,0,45) classicFrame.Position = UDim2.new(0.5, -113, 1, -130) classicFrame.Parent = classicGui colorButton = makeImageButton("ColorButton","http://www.roblox.com/asset?id=59103051",UDim2.new(0,0,0.5,-23), classicFrame, "F") local colorCon = colorButton.MouseButton1Click:connect(function() goToTool("Color", colorButton) end) table.insert(connections,colorCon) table.insert(buttons,colorButton) SurfaceButton = makeImageButton("SurfaceButton","http://www.roblox.com/asset?id=59103080",UDim2.new(0,90,0.5,-23), classicFrame, "H") local surfaceCon = SurfaceButton.MouseButton1Click:connect(function() goToTool("Surface", SurfaceButton) end) table.insert(connections,surfaceCon) table.insert(buttons,SurfaceButton) MaterialButton = makeImageButton("MaterialButton","http://www.roblox.com/asset?id=59103092",UDim2.new(0,45,0.5,-23), classicFrame, "G") local materialCon = MaterialButton.MouseButton1Click:connect(function() goToTool("Material", MaterialButton) end) table.insert(connections,materialCon) table.insert(buttons,MaterialButton) ResizeButton = makeImageButton("ResizeButton","http://www.roblox.com/asset?id=59103119",UDim2.new(0,180,0.5,-23), classicFrame, "K") local resizeCon = ResizeButton.MouseButton1Click:connect(function() goToTool("Resize", ResizeButton) end) table.insert(connections,resizeCon) table.insert(buttons,ResizeButton) draggerButton = makeImageButton("ResizeButton","http://www.roblox.com/asset?id=59103152",UDim2.new(0,135,0.5,-23), classicFrame, "J") local draggerCon = draggerButton.MouseButton1Click:connect(function() goToTool("Dragger", draggerButton) end) table.insert(connections,draggerCon) table.insert(buttons,draggerButton) return classicGui end function clearAllConnections() for i = 1, #connections do connections[i]:disconnect() end connections = {} end function hotKey(key) key = key:lower() if key == "f" then goToTool("Color", colorButton) elseif key == "g" then goToTool("Material", MaterialButton) elseif key == "h" then goToTool("Surface", SurfaceButton) elseif key == "j" then goToTool("Dragger", draggerButton) elseif key == "k" then goToTool("Resize", ResizeButton) end end function onEquippedLocal(mouse) Tool.Mouse.Value = mouse if not gui then gui = makeClassicControlGui() end gui.Parent = game.Players.LocalPlayer.PlayerGui keyUpCon = mouse.KeyUp:connect(function(key) hotKey(key) end) end function onUnequippedLocal() if keyUpCon then keyUpCon:disconnect() end deactivateAllTools() gui.Parent = nil end Tool.Equipped:connect(onEquippedLocal) Tool.Unequipped:connect(onUnequippedLocal) false -0.5 0.5 0 0 -0.5 0.5 0 0 199 -0.000566363335 0.480126768 0.498794556 -1.50203878e-005 1.50579854e-006 -1.00000012 9.8371238e-006 1 1.50565256e-006 1.00000012 -9.83710197e-006 -1.50204023e-005 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=15952510 5 Mesh 0 0 0 0.400000006 0.400000006 0.400000006 http://www.roblox.com/asset/?id=15952494 1 1 1 false Sound 1 false rbxasset://sounds/swordslash.wav 1 false Sound 1 false rbxasset://sounds/unsheath.wav 1 false Sound 1 false rbxasset://sounds/swordslash.wav 1 false Sound 1 false rbxasset://sounds/unsheath.wav 1 false Color -- basic functions function waitForChild(instance, name) while not instance:findFirstChild(name) do instance.ChildAdded:wait() end end local Tool = script.Parent enabled = true local menu local origTexture = Tool.TextureId local localAssetBase = "rbxasset://textures/ui/" local currentColorButton = nil game:GetService("ContentProvider"):Preload("rbxasset://icons/color_sel.png") local buttonDownCon, mouseMoveCon local clickCons = {} function onButton1Down(mouse) if not enabled then return end enabled = false mouse.Icon = "rbxasset://textures\\GunWaitCursor.png" wait(.5) mouse.Icon = "rbxasset://textures\\GunCursor.png" enabled = true end local selectionBox local selectionLasso function setSelectionBox(part) unsetSelectionBox() selectionBox.Adornee = part selectionLasso.Part = part end function unsetSelectionBox() selectionBox.Adornee = nil selectionLasso.Part = nil end function canSelectObject(part) return part and not (part.Locked) and (part.Position - Tool.Parent.Head.Position).Magnitude < 60 end function on3dButton1Down(mouse) local part = mouse.Target if canSelectObject(part) then if Instance.Lock(part) then color = Tool.Color.CurrentColor.Value if color == nil then Instance.Unlock(part) return end part.BrickColor = color Instance.Unlock(part) end end end function on3dMouseMove(mouse) mouse.Icon ="rbxasset://textures\\FillCursor.png" local part = mouse.Target if canSelectObject(part) then setSelectionBox(part) else unsetSelectionBox() end end function makeColorMenu() local paintGui = Instance.new("ScreenGui") paintGui.Name = "PaintGui" local paintMenu = Instance.new("ImageLabel") paintMenu.Name = "PaintMenu" paintMenu.Position = UDim2.new(0,0,1,-600) paintMenu.Size = UDim2.new(0,120,0,500) paintMenu.BackgroundTransparency = 1 paintMenu.ZIndex = 2 paintMenu.Image = localAssetBase .. "PaintMenu.png" paintMenu.Parent = paintGui local paintColorButton = Instance.new("ImageButton") paintColorButton.BorderSizePixel = 0 paintColorButton.ZIndex = 3 paintColorButton.Modal = true paintColorButton.Size = UDim2.new(0.200000003, 0,0.0500000007, 0) local selection = Instance.new("Frame") selection.Name = "Selection" selection.BorderSizePixel = 0 selection.BackgroundColor3 = Color3.new(1,1,1) selection.BackgroundTransparency = 1 selection.ZIndex = 2 selection.Size = UDim2.new(1.1,0,1.1,0) selection.Position = UDim2.new(-0.05,0,-0.05,0) selection.Parent = paintColorButton local header = 0.08 local spacing = 18 local count = 1 local function findNextColor() colorName = tostring(BrickColor.new(count)) while colorName == "Medium stone grey" do count = count + 1 colorName = tostring(BrickColor.new(count)) end return count end for i = 0,15 do for j = 1, 4 do newButton = paintColorButton:clone() newButton.BackgroundColor3 = BrickColor.new(findNextColor()).Color newButton.Name = tostring(BrickColor.new(count)) count = count + 1 if j == 1 then newButton.Position = UDim2.new(0.08,0,i/spacing + header,0) elseif j == 2 then newButton.Position = UDim2.new(0.29,0,i/spacing + header,0) elseif j == 3 then newButton.Position = UDim2.new(0.5,0,i/spacing + header,0) elseif j == 4 then newButton.Position = UDim2.new(0.71,0,i/spacing + header,0) end newButton.Parent = paintMenu end end local paintButtons = paintMenu:GetChildren() for i = 1, #paintButtons do local newCon = paintButtons[i].MouseButton1Click:connect(function() Tool.Color.CurrentColor.Value = BrickColor.new(paintButtons[i].Name) if currentColorButton then if currentColorButton:FindFirstChild("Selection") then currentColorButton.Selection.BackgroundTransparency = 1 end end currentColorButton = paintButtons[i] paintButtons[i].Selection.BackgroundTransparency = 0 end) local anotherCon = paintButtons[i].MouseEnter:connect(function() paintButtons[i].Selection.BackgroundTransparency = 0 end) local oneMoreCon = paintButtons[i].MouseLeave:connect(function() if paintButtons[i] ~= currentColorButton then paintButtons[i].Selection.BackgroundTransparency = 1 end end) table.insert(clickCons,newCon) table.insert(clickCons,anotherCon) table.insert(clickCons,oneMoreCon) end return paintGui end function onEquippedLocal(mouse) Tool.TextureId = "rbxasset://icons/color_sel.png" local character = script.Parent.Parent local player = game.Players:GetPlayerFromCharacter(character) buttonDownCon = mouse.Button1Down:connect(function() on3dButton1Down(mouse) end) mouseMoveCon = mouse.Move:connect(function() on3dMouseMove(mouse) end) mouse.Icon ="rbxasset://textures\\FillCursor.png" selectionBox = Instance.new("SelectionBox") selectionBox.Color = Tool.Color.CurrentColor.Value selectionBox.Adornee = nil selectionBox.Parent = player.PlayerGui selectionLasso = Instance.new("SelectionPartLasso") selectionLasso.Name = "Model Delete Lasso" selectionLasso.Humanoid = character.Humanoid selectionLasso.Part = nil selectionLasso.Visible = true selectionLasso.archivable = false selectionLasso.Color = Tool.Color.CurrentColor.Value selectionLasso.Parent = game.workspace menu = makeColorMenu() menu.Parent = game.Players.LocalPlayer.PlayerGui end function onUnequippedLocal() if menu then menu:remove() end Tool.TextureId = origTexture for i = 1, #clickCons do clickCons[i]:disconnect() end clickCons = {} if selectionBox then selectionBox:Remove() end if selectionLasso then selectionLasso:Remove() end if mouseMoveCon then mouseMoveCon:disconnect() end if buttonDownCon then buttonDownCon:disconnect() end end waitForChild(Tool.Color,"CurrentColor") waitForChild(Tool.Color,"Active") Tool.Color.CurrentColor.Changed:connect(function() if selectionBox then selectionBox.Color = Tool.Color.CurrentColor.Value end if selectionLasso then selectionLasso.Color = Tool.Color.CurrentColor.Value end end) script.Active.Changed:connect(function(prop) if script.Active.Value == true then onEquippedLocal(Tool.Mouse.Value) else onUnequippedLocal() end end) Active false CurrentColor 194 false Material -- basic functions function waitForChild(instance, name) while not instance:findFirstChild(name) do instance.ChildAdded:wait() end end local Tool = script.Parent waitForChild(Tool.Material,"Active") waitForChild(Tool.Material,"CurrentMaterial") enabled = true local origTexture = Tool.TextureId local localAssetBase = "rbxasset://textures/ui/" game:GetService("ContentProvider"):Preload("rbxasset://icons/material_sel.png") local menu local selectionBox local selectionLasso local selectedButton local value = nil local downCons = {} local currentMaterialButton = nil function setSelectionBox(part) unsetSelectionBox() selectionBox.Adornee = part selectionLasso.Part = part end function unsetSelectionBox() selectionBox.Adornee = nil selectionLasso.Part = nil end local MaterialEnum = {} MaterialEnum["Plastic"] = Enum.Material.Plastic MaterialEnum["Wood"] = Enum.Material.Wood MaterialEnum["Slate"] = Enum.Material.Slate MaterialEnum["CorrodedMetal"] = Enum.Material.CorrodedMetal MaterialEnum["Ice"] = Enum.Material.Ice MaterialEnum["Grass"] = Enum.Material.Grass MaterialEnum["Foil"] = Enum.Material.Foil MaterialEnum["DiamondPlate"] = Enum.Material.DiamondPlate MaterialEnum["Concrete"] = Enum.Material.Concrete function on3dButton1Down(mouse) local part = mouse.Target if part and not (part.Locked) then if Instance.Lock(part) then part.Material = MaterialEnum[Tool.Material.CurrentMaterial.Value] Instance.Unlock(part) end end end function canSelectObject(part) return part and not (part.Locked) and (part.Position - Tool.Parent.Head.Position).Magnitude < 60 end function on3dMouseMove(mouse) mouse.Icon ="rbxasset://textures\\MaterialCursor.png" local part = mouse.Target if canSelectObject(part) then setSelectionBox(part) else unsetSelectionBox() end end function createMaterialMenu() local materialGui = Instance.new("ScreenGui") materialGui.Name = "MaterialGui" local materialMenu = Instance.new("ImageLabel") materialMenu.Name = "MaterialMenu" materialMenu.Position = UDim2.new(0,0,1,-350) materialMenu.Size = UDim2.new(0,100,0,250) materialMenu.BackgroundTransparency = 1 materialMenu.ZIndex = 2 materialMenu.Image = localAssetBase .. "MaterialMenu.png" materialMenu.Parent = materialGui local textures = {"Plastic","Wood","Slate","CorrodedMetal","Ice","Grass","Foil","DiamondPlate","Concrete"} local materialButtons = {} local materialButton = Instance.new("ImageButton") materialButton.BackgroundTransparency = 1 materialButton.Size = UDim2.new(0.400000003, 0,0.16, 0) materialButton.ZIndex = 4 local selection = Instance.new("Frame") selection.Name = "Selection" selection.BorderSizePixel = 0 selection.BackgroundColor3 = Color3.new(1,1,1) selection.BackgroundTransparency = 1 selection.ZIndex = 3 selection.Size = UDim2.new(1.1,0,1.1,0) selection.Position = UDim2.new(-0.05,0,-0.05,0) selection.Parent = materialButton local current = 1 local function getTextureAndName(button) if current > #textures then button:remove() return false end button.Image = localAssetBase .. textures[current] .. ".png" button.Name = textures[current] current = current + 1 return true end local ySpacing = 0.10 local xSpacing = 0.07 for i = 1,5 do for j = 1,2 do local button = materialButton:clone() button.Position = UDim2.new((j -1)/2.2 + xSpacing,0,ySpacing + (i - 1)/5.5,0) if getTextureAndName(button) then button.Parent = materialMenu else button:remove() end table.insert(materialButtons,button) end end for i = 1, #materialButtons do local newCon = materialButtons[i].MouseButton1Click:connect(function() Tool.Material.CurrentMaterial.Value = materialButtons[i].Name if currentMaterialButton then if currentMaterialButton:FindFirstChild("Selection") then currentMaterialButton.Selection.BackgroundTransparency = 1 end end currentMaterialButton = materialButtons[i] materialButtons[i].Selection.BackgroundTransparency = 0 end) local enterCon = materialButtons[i].MouseEnter:connect(function() materialButtons[i].Selection.BackgroundTransparency = 0 end) local leaveCon = materialButtons[i].MouseLeave:connect(function() if materialButtons[i] ~= currentMaterialButton then materialButtons[i].Selection.BackgroundTransparency = 1 end end) table.insert(downCons, newCon) table.insert(downCons, enterCon) table.insert(downCons, leaveCon) end return materialGui end function onEquippedLocal(mouse) Tool.TextureId = "rbxasset://icons/material_sel.png" value = nil selectedButton = nil local character = script.Parent.Parent local player = game.Players:GetPlayerFromCharacter(character) selectedButton = nil button1DownCon = mouse.Button1Down:connect(function() on3dButton1Down(mouse) end) mouseMoveCon = mouse.Move:connect(function() on3dMouseMove(mouse) end) mouse.Icon ="rbxasset://textures\\MaterialCursor.png" selectionBox = Instance.new("SelectionBox") selectionBox.Color = BrickColor.Yellow() selectionBox.Adornee = nil selectionBox.Parent = player.PlayerGui selectionLasso = Instance.new("SelectionPartLasso") selectionLasso.Name = "Model Material Lasso" selectionLasso.Humanoid = character.Humanoid selectionLasso.Parent = game.workspace selectionLasso.Part = nil selectionLasso.Visible = true selectionLasso.archivable = false selectionLasso.Color = BrickColor.Green() menu = createMaterialMenu() menu.Parent = game.Players.LocalPlayer.PlayerGui end function onUnequippedLocal() if button1DownCon then button1DownCon:disconnect() end if mouseMoveCon then mouseMoveCon:disconnect() end for i = 1, #downCons do downCons[i]:disconnect() end downCons = {} menu:remove() Tool.TextureId = origTexture if selectionBox then selectionBox:Remove() end if selectionLasso then selectionLasso:Remove() end end script.Active.Changed:connect(function(prop) if script.Active.Value == true then onEquippedLocal(Tool.Mouse.Value) else onUnequippedLocal() end end) Active false CurrentMaterial Plastic false Resize -- basic functions function waitForChild(instance, name) while not instance:findFirstChild(name) do instance.ChildAdded:wait() end end local Tool = script.Parent waitForChild(Tool.Resize,"Active") enabled = true local origTexture = Tool.TextureId game:GetService("ContentProvider"):Preload("rbxasset://icons/resize_sel.png") local selectionBox local selectionLasso local handles local previousDistance local needsCursor = true -- Wether a handle is being dragged, true if it is and false if not. local isDragging = false -- Hold the anchor state a piece was in when dragging started. local anchorState = false local currMouseTarget local connections = {} function onHandlesDown(normal) previousDistance = 0 end function onHandlesDrag(normal, distance) if handles.Adornee then local delta = distance - previousDistance if math.abs(delta) >= handles.Adornee.ResizeIncrement then local sizeDelta = math.floor(delta / handles.Adornee.ResizeIncrement + 0.5) * handles.Adornee.ResizeIncrement -- Keep the piece from falling while resizing. -- Auto join the piece to other pieces. if not isDragging then isDragging = true anchorState = handles.Adornee.Anchored handles.Adornee.Anchored = true end game.JointsService:SetJoinAfterMoveInstance(handles.Adornee) if handles.Adornee:Resize(normal, sizeDelta) then previousDistance = distance end game.JointsService:CreateJoinAfterMoveJoints() game.JointsService:SetJoinAfterMoveInstance(nil) end end end function onButton1Down(mouse) local success = pcall(function() theMouse = mouse.Target end) if success then if canSelect(mouse.Target) then selectionBox.Adornee = mouse.Target selectionLasso.Part = mouse.Target handles.Adornee = mouse.Target handles.Faces = mouse.Target.ResizeableFaces else selectionBox.Adornee = nil selectionLasso.Part = nil handles.Adornee = nil end end end function mouseTargetChanged(mouse) if canSelect(mouse.Target) then if needsCursor then mouse.Icon ="rbxasset://textures\\DragCursor.png" needsCursor = false end else needsCursor = true mouse.Icon = "" end end local function isPartOfModel(object) if object and object ~= game.Workspace and object:IsA("Model") then return true elseif not object or object == game.Workspace then return false else return isPartOfModel(object.Parent) end end function canSelect(object) local isModel = isPartOfModel(object) return object and object:IsA("BasePart") and not object.Locked and not isPartOfModel(object) end function onEquippedLocal(mouse) currMouseTarget = nil table.insert(connections,mouse.Button1Down:connect(function() onButton1Down(mouse) end) ) -- Track mouse up since up won't happen for the handle unless the mouse is over the handle. table.insert(connections,mouse.Button1Up:connect(function() if isDragging then handles.Adornee.Anchored = anchorState isDragging = false end end) ) table.insert(connections, mouse.Move:connect(function() if currMouseTarget ~= mouse.Target then mouseTargetChanged(mouse) currMouseTarget = mouse.Target end end) ) local character = script.Parent.Parent local player = game.Players:GetPlayerFromCharacter(character) selectionBox = Instance.new("SelectionBox") selectionBox.Color = BrickColor.Blue() selectionBox.Adornee = nil selectionBox.Parent = player.PlayerGui selectionLasso = Instance.new("SelectionPartLasso") selectionLasso.Name = "Model Delete Lasso" selectionLasso.Humanoid = character.Humanoid selectionLasso.Parent = game.workspace selectionLasso.Part = nil selectionLasso.Visible = true selectionLasso.archivable = false selectionLasso.Color = BrickColor.Red() handles = Instance.new("Handles") handles.Color = BrickColor.Blue() handles.Adornee = nil handles.MouseDrag:connect(onHandlesDrag) handles.MouseButton1Down:connect(onHandlesDown) handles.Parent = player.PlayerGui end function onUnequippedLocal() Tool.TextureId = origTexture selectionBox:Remove() selectionLasso:Remove() handles:Remove() for i = 1, #connections do if connections[i] then connections[i]:disconnect() end end connections = {} end script.Active.Changed:connect(function(prop) if script.Active.Value == true then onEquippedLocal(Tool.Mouse.Value) else onUnequippedLocal() end end) Active false false Surface -- basic functions function waitForChild(instance, name) while not instance:findFirstChild(name) do instance.ChildAdded:wait() end end local Tool = script.Parent local menu waitForChild(Tool.Surface,"Active") waitForChild(Tool.Surface,"CurrentSurface") enabled = true local origTexture = Tool.TextureId local localAssetBase = "rbxasset://textures/ui/" game:GetService("ContentProvider"):Preload("rbxasset://icons/surface_sel.png") local selectionSurface local selectionLasso local currentSurfaceButton = nil local mouseMoveCon, button1DownCon local conArray = {} function setSelectionSurface(part, surface) unsetSelectionSurface() selectionSurface.Adornee = part selectionSurface.TargetSurface = surface selectionLasso.Part = part end function unsetSelectionSurface() selectionSurface.Adornee = nil selectionLasso.Part = nil end local SurfaceEnum = {} SurfaceEnum["Smooth"] = Enum.SurfaceType.Smooth SurfaceEnum["Studs"] = Enum.SurfaceType.Studs SurfaceEnum["Inlet"] = Enum.SurfaceType.Inlet SurfaceEnum["Universal"] = Enum.SurfaceType.Universal SurfaceEnum["Glue"] = Enum.SurfaceType.Glue SurfaceEnum["Weld"] = Enum.SurfaceType.Weld SurfaceEnum["Hinge"] = Enum.SurfaceType.Hinge SurfaceEnum["Motor"] = Enum.SurfaceType.Motor function canSelectObject(part, surface) return part and not (part.Locked) and part:IsA("BasePart") and (part.Position - Tool.Parent.Head.Position).Magnitude < 60 and (not(part:IsA("WedgePart")) or surface ~= Enum.NormalId.Front) end function on3dMouseMove(mouse) local part = mouse.Target local surface = mouse.TargetSurface if canSelectObject(part, surface) then setSelectionSurface(part, surface) else unsetSelectionSurface() end end function on3dButton1Down(mouse) local part = selectionSurface.Adornee if part then local normalId = selectionSurface.TargetSurface local surface = Tool.Surface.CurrentSurface.Value if surface == nil then return end --Apply the selected surface to the current parts if normalId == Enum.NormalId.Top then part.TopSurface = surface elseif normalId == Enum.NormalId.Bottom then elseif normalId == Enum.NormalId.Front then part.BottomSurface = surface part.FrontSurface = surface elseif normalId == Enum.NormalId.Back then part.BackSurface = surface elseif normalId == Enum.NormalId.Left then part.LeftSurface = surface elseif normalId == Enum.NormalId.Right then part.RightSurface = surface end end end function createSurfaceMenu() local surfaceGui = Instance.new("ScreenGui") surfaceGui.Name = "SurfaceGui" local surfaceMenu = Instance.new("ImageLabel") surfaceMenu.Name = "SurfaceMenu" surfaceMenu.Position = UDim2.new(0,0,1,-400) surfaceMenu.Size = UDim2.new(0,150,0,300) surfaceMenu.BackgroundTransparency = 1 surfaceMenu.ZIndex = 2 surfaceMenu.Image = localAssetBase .. "SurfaceMenu.png" surfaceMenu.Parent = surfaceGui textures = {"Smooth", "Studs", "Inlets", "Universal", "Glue", "Weld", "Hinge", "Motor"} current = 1 local surfaceButtons = {} local surfaceButton = Instance.new("ImageButton") surfaceButton.BackgroundTransparency = 1 surfaceButton.Size = UDim2.new(0.400000003, 0,0.19, 0) surfaceButton.ZIndex = 4 local selection = Instance.new("Frame") selection.Name = "Selection" selection.BorderSizePixel = 0 selection.BackgroundColor3 = Color3.new(1,1,1) selection.BackgroundTransparency = 1 selection.ZIndex = 3 selection.Size = UDim2.new(1.1,0,1.1,0) selection.Position = UDim2.new(-0.05,0,-0.05,0) selection.Parent = surfaceButton local function getTextureAndName(button) if current > #textures then button:remove() return false end button.Image = localAssetBase .. textures[current] .. ".png" if textures[current] == "Inlets" then --nice hack to adjust for inconsistent namings button.Name = "Inlet" else button.Name = textures[current] end current = current + 1 return true end local ySpacing = 0.14 local xSpacing = 0.07 for i = 1,4 do for j = 1,2 do local button = surfaceButton:clone() button.Position = UDim2.new((j -1)/2.2 + xSpacing,0,ySpacing + (i - 1)/4.6,0) getTextureAndName(button) button.Parent = surfaceMenu table.insert(surfaceButtons,button) end end for i = 1, #surfaceButtons do local newCon = surfaceButtons[i].MouseButton1Click:connect(function() Tool.Surface.CurrentSurface.Value = surfaceButtons[i].Name if currentSurfaceButton then if currentSurfaceButton:FindFirstChild("Selection") then currentSurfaceButton.Selection.BackgroundTransparency = 1 end end currentSurfaceButton = surfaceButtons[i] surfaceButtons[i].Selection.BackgroundTransparency = 0 end) local enterCon = surfaceButtons[i].MouseEnter:connect(function() surfaceButtons[i].Selection.BackgroundTransparency = 0 end) local leaveCon = surfaceButtons[i].MouseLeave:connect(function() if surfaceButtons[i] ~= currentSurfaceButton then surfaceButtons[i].Selection.BackgroundTransparency = 1 end end) table.insert(conArray,newCon) table.insert(conArray,enterCon) table.insert(conArray,leaveCon) end return surfaceGui end function onEquippedLocal(mouse) Tool.TextureId = "rbxasset://icons/surface_sel.png" local character = script.Parent.Parent local player = game.Players:GetPlayerFromCharacter(character) mouseMoveCon = mouse.Move:connect(function() on3dMouseMove(mouse) end) button1DownCon = mouse.Button1Down:connect(function() on3dButton1Down(mouse) end) selectionSurface = Instance.new("SurfaceSelection") selectionSurface.Color = BrickColor.Red() selectionSurface.Adornee = nil selectionSurface.Parent = player.PlayerGui selectionLasso = Instance.new("SelectionPartLasso") selectionLasso.Name = "Model Surface Lasso" selectionLasso.Humanoid = character.Humanoid selectionLasso.Parent = game.workspace selectionLasso.Part = nil selectionLasso.Visible = true selectionLasso.archivable = false selectionLasso.Color = BrickColor.Yellow() menu = createSurfaceMenu() menu.Parent = game.Players.LocalPlayer.PlayerGui end function onUnequippedLocal() if mouseMoveCon then mouseMoveCon:disconnect() end if button1DownCon then button1DownCon:disconnect() end for i = 1, #conArray do if conArray[i] then conArray[i]:disconnect() end end conArray = {} menu:remove() Tool.TextureId = origTexture if selectionBox then selectionBox:Remove() end if selectionLasso then selectionLasso:Remove() end if selectionSurface then selectionSurface:Remove() end end script.Active.Changed:connect(function(prop) if script.Active.Value == true then onEquippedLocal(Tool.Mouse.Value) else onUnequippedLocal() end end) Active false CurrentSurface Smooth Mouse null false Dragger -- basic functions function waitForChild(instance, name) while not instance:findFirstChild(name) do instance.ChildAdded:wait() end end local Tool = script.Parent waitForChild(Tool.Dragger, "Active") local gui = nil local connections = {} function deactivateTool(script) local enable = script:FindFirstChild("Active") if enable and enable:IsA("BoolValue") then enable.Value = false end end function deactivateAllTools() local toolChildren = script:GetChildren() for i = 1, #toolChildren do if toolChildren[i]:IsA("BaseScript") and toolChildren[i] ~= script then deactivateTool(toolChildren[i]) end end end function switchGrid(type) deactivateAllTools() wait() if type == "1" then script.OldDragger.Active.Value = true gui.DraggerButton.Selected = true gui.Dragger4xButton.Selected = false else script.NewDragger.Active.Value = true gui.DraggerButton.Selected = false gui.Dragger4xButton.Selected = true end end function makeTextButton(buttonName, text, position, parent) local button = Instance.new("TextButton") button.Name = buttonName button.Style = Enum.ButtonStyle.RobloxButton button.Size = UDim2.new(0,100,0,40) if position then button.Position = position end button.Parent = parent button.Text = text button.Font = Enum.Font.ArialBold button.FontSize = Enum.FontSize.Size18 button.TextColor3 = Color3.new(1,1,1) return button end function makeDraggerGui() local draggerGui = Instance.new("ScreenGui") draggerGui.Name = "DraggerGui" local draggerButton = makeTextButton("DraggerButton","1x1 Grid",UDim2.new(0.5,-100,0,0),draggerGui) local dragger4xButton = makeTextButton("Dragger4xButton","4x4 Grid",UDim2.new(0.5,0,0,0),draggerGui) local con = draggerButton.MouseButton1Click:connect(function() switchGrid("1") end) local con2 = dragger4xButton.MouseButton1Click:connect(function() switchGrid("4") end) table.insert(connections,con) table.insert(connections,con2) return draggerGui end function onEquippedLocal(mouse) Tool.Mouse.Value = mouse if not gui then gui = makeDraggerGui() end gui.Parent = game.Players.LocalPlayer.PlayerGui script.NewDragger.Active.Value = true gui.Dragger4xButton.Selected = true end function onUnequippedLocal() for i = 1, #connections do connections[i]:disconnect() end connections = {} gui:remove() gui = nil deactivateAllTools() end script.Active.Changed:connect(function(prop) if script.Active.Value == true then onEquippedLocal(Tool.Mouse.Value) else onUnequippedLocal() end end) false OldDragger -- basic functions function waitForChild(instance, name) while not instance:findFirstChild(name) do instance.ChildAdded:wait() end end local Tool = script.Parent.Parent waitForChild(Tool.Dragger.OldDragger, "Active") enabled = true local origTexture = Tool.TextureId game:GetService("ContentProvider"):Preload("rbxasset://icons/freemove_sel.png") local selectionBox local currentSelection local currentSelectionColors = {} local selectionLasso local inGui = false local inPalette = false local connections = {} function canSelectObject(part) return part and not (part.Locked) and (part.Position - Tool.Parent.Head.Position).Magnitude < 60 end function findModel(part) while part ~= nil do if part:IsA("Model") and part ~= game.Workspace then return part elseif part == game.Workspace then return nil end part = part.Parent end return nil end function startDrag(mousePart, hitPoint, collection) dragger = Instance.new("Dragger") pcall(function() dragger:MouseDown(mousePart, hitPoint, collection) end) end function collectBaseParts(object, collection) if object == nil then return end if object:IsA("BasePart") then collection[#collection+1] = object end for index,child in pairs(object:GetChildren()) do collectBaseParts(child, collection) end end function onMouseDown(mouse) mouse.Icon ="rbxasset://textures\\GrabRotateCursor.png" local part = mouse.Target if canSelectObject(part) then local hitPoint = mouse.Hit:toObjectSpace(part.CFrame).p if trySelection(part) then local instances = {} collectBaseParts(currentSelection, instances) startDrag(part, hitPoint, instances) return end end onMouseUp(mouse) end function onMouseUp(mouse) mouse.Icon ="rbxasset://textures\\GrabCursor.png" if dragger ~= nil then pcall(function() dragger:MouseUp() end) dragger = nil end end function trySelection(part) if canSelectObject(part) then selectionLasso.Part = part local model = findModel(part) if model then return setSelection(model) else return setSelection(part) end else clearSelection() return false end end function onKeyDown(key) if dragger ~= nil then if key == 'R' or key == 'r' then dragger:AxisRotate(Enum.Axis.Y) elseif key == 'T' or key == 't' then dragger:AxisRotate(Enum.Axis.Z) end end end local alreadyMoving function onMouseMove(mouse) if alreadyMoving then return end alreadyMoving = true if dragger ~= nil then pcall(function() dragger:MouseMove(mouse.UnitRay) end) else trySelection(mouse.Target) end alreadyMoving = false end function saveSelectionColor(instance) if instance:IsA("BasePart") then currentSelectionColors[instance] = instance.BrickColor if instance.BrickColor == BrickColor.Blue() then instance.BrickColor = BrickColor.new("Deep blue") else instance.BrickColor = BrickColor.Blue() end end local children = instance:GetChildren() if children then for pos, child in pairs(children) do saveSelectionColor(child) end end end function setSelection(partOrModel) if partOrModel ~= currentSelection then clearSelection() currentSelection = partOrModel saveSelectionColor(currentSelection) selectionBox.Adornee = currentSelection return true else if currentSelection ~= nil then return true end end return false end function clearSelection() if currentSelection ~= nil then for part, color in pairs(currentSelectionColors) do part.BrickColor = color end selectionBox.Adornee = nil end currentSelectionColors = {} currentSelection = nil if(selectionLasso) then selectionLasso.Part = nil end if(selectionBox) then selectionBox.Adornee = nil end end function onEquippedLocal(mouse) wait(0.1) Tool.TextureId = "rbxasset://icons/freemove_sel.png" local character = script.Parent.Parent local player = game.Players:GetPlayerFromCharacter(character) guiMain = Instance.new("ScreenGui") guiMain.Parent = game.Players.LocalPlayer.PlayerGui inGui = false inPalette = false mouse.Icon ="rbxasset://textures\\GrabCursor.png" local con = mouse.Button1Down:connect(function() onMouseDown(mouse) end) table.insert(connections,con) con = mouse.Button1Up:connect(function() onMouseUp(mouse) end) con = table.insert(connections,con) con = mouse.Move:connect(function() onMouseMove(mouse) end) table.insert(connections,con) con = mouse.KeyDown:connect(function(string) onKeyDown(string) end) table.insert(connections,con) selectionBox = Instance.new("SelectionBox") selectionBox.Name = "Model Delete Selection" selectionBox.Color = BrickColor.Blue() selectionBox.Adornee = nil selectionBox.Parent = game.Players.LocalPlayer.PlayerGui selectionLasso = Instance.new("SelectionPartLasso") selectionLasso.Name = "Model Drag Lasso" selectionLasso.Humanoid = game.Players.LocalPlayer.Character.Humanoid selectionLasso.archivable = false selectionLasso.Visible = true selectionLasso.Parent = game.workspace selectionLasso.Color = BrickColor.Blue() alreadyMoving = false end function onUnequippedLocal() for i = 1, #connections do connections[i]:disconnect() end connections = {} Tool.TextureId = origTexture clearSelection() selectionBox:Remove() selectionLasso:Remove() end script.Active.Changed:connect(function() if script.Active.Value then onEquippedLocal(Tool.Mouse.Value) else onUnequippedLocal() end end) Active false Active false false NewDragger local Tool = script.Parent.Parent game:GetService("ContentProvider"):Preload("rbxasset://icons/freemove_sel.png") local selectionBox local currentSelection local currentSelectionColors = {} local Mouse = nil local player = nil local instances = {} local maxDragDistance = 60 local connections = {} while not Tool:FindFirstChild("ErrorBox") do Tool.ChildAdded:wait() end local errorBox = Tool.ErrorBox local lastTargetCFrame = nil function canSelectObject(part) return part and not (part.Locked) and (part.Position - script.Parent.Parent.Parent.Head.Position).Magnitude < maxDragDistance end function findModel(part) while part ~= nil do if part.className == "Model" then return part end part = part.Parent end return nil end function isPart(object) return object and (object:IsA("Part") or object:IsA("TrussPart") or object:IsA("WedgePart") or object:IsA("VehicleSeat")) end function positionPartsAtCFrame3(collection, aCFrame) local insertCFrame if collection[1]:IsA("Model") then -- we assume model has at least one part in it; need to find first part i = 1 while (i < (#collection[1]:GetChildren()) and not isPart(collection[1]:GetChildren()[i])) do i = i + 1 end insertCFrame = collection[1]:GetChildren()[i].CFrame for i, object in pairs(collection[1]:GetChildren()) do if isPart(object) then local posPartInWorld = object.Position local posPart1InWorld = insertCFrame.p local newPosPartInWorld = posPartInWorld - posPart1InWorld + aCFrame.p local x, y, z, R00, R01, R02, R10, R11, R12, R20, R21, R22 = object.CFrame:components() object.CFrame = CFrame.new(newPosPartInWorld.x, newPosPartInWorld.y, newPosPartInWorld.z, R00, R01, R02, R10, R11, R12, R20, R21, R22) end end else collection[1].CFrame = aCFrame end end function getBoundingBox2(partOrModel) -- for models, the bounding box is defined as the minimum and maximum individual part bounding boxes -- relative to the first part's coordinate frame. local minVec = Vector3.new(math.huge, math.huge, math.huge) local maxVec = Vector3.new(-math.huge, -math.huge, -math.huge) if isPart(partOrModel) then minVec = -0.5 * partOrModel.Size maxVec = -minVec elseif partOrModel:IsA("Terrain") then minVec = Vector3.new(-2, -2, -2) maxVec = Vector3.new(2, 2, 2) else local part1 = partOrModel:GetChildren()[1] for i, object in pairs(partOrModel:GetChildren()) do if isPart(object) then boxMinInWorld = object.CFrame:pointToWorldSpace(-0.5 * object.Size) boxMinInPart1 = part1.CFrame:pointToObjectSpace(boxMinInWorld) boxMaxInWorld = object.CFrame:pointToWorldSpace(0.5 * object.Size) boxMaxInPart1 = part1.CFrame:pointToObjectSpace(boxMaxInWorld) local minX = minVec.x local minY = minVec.y local minZ = minVec.z local maxX = maxVec.x local maxY = maxVec.y local maxZ = maxVec.z if boxMinInPart1.x < minVec.x then minX = boxMinInPart1.x end if boxMinInPart1.y < minVec.y then minY = boxMinInPart1.y end if boxMinInPart1.z < minVec.z then minZ = boxMinInPart1.z end if boxMaxInPart1.x < minX then minX = boxMaxInPart1.x end if boxMaxInPart1.y < minY then minY = boxMaxInPart1.y end if boxMaxInPart1.z < minZ then minZ = boxMaxInPart1.z end if boxMinInPart1.x > maxVec.x then maxX = boxMinInPart1.x end if boxMinInPart1.y > maxVec.y then maxY = boxMinInPart1.y end if boxMinInPart1.z > maxVec.z then maxZ = boxMinInPart1.z end if boxMaxInPart1.x > maxX then maxX = boxMaxInPart1.x end if boxMaxInPart1.y > maxY then maxY = boxMaxInPart1.y end if boxMaxInPart1.z > maxZ then maxZ = boxMaxInPart1.z end minVec = Vector3.new(minX, minY, minZ) maxVec = Vector3.new(maxX, maxY, maxZ) end end end return minVec, maxVec end -- function to do the same as above, but in world coordinates (really only used for region3-based bounds-checking) function getBoundingBoxInWorldCoordinates(partOrModel) local minVec = Vector3.new(math.huge, math.huge, math.huge) local maxVec = Vector3.new(-math.huge, -math.huge, -math.huge) if partOrModel:IsA("Part") or partOrModel:IsA("WedgePart") or partOrModel:IsA("TrussPart")then vec1 = partOrModel.CFrame:pointToWorldSpace(-0.5 * partOrModel.Size) vec2 = partOrModel.CFrame:pointToWorldSpace(0.5 * partOrModel.Size) minVec = Vector3.new(math.min(vec1.X, vec2.X), math.min(vec1.Y, vec2.Y), math.min(vec1.Z, vec2.Z)) maxVec = Vector3.new(math.max(vec1.X, vec2.X), math.max(vec1.Y, vec2.Y), math.max(vec1.Z, vec2.Z)) elseif partOrModel:IsA("Terrain") then -- we shouldn't have to deal with this case --minVec = Vector3.new(-2, -2, -2) --maxVec = Vector3.new(2, 2, 2) else local part1 = partOrModel:GetChildren()[1] for i, object in pairs(partOrModel:GetChildren()) do if (object:IsA("Part") or object:IsA("WedgePart") or object:IsA("TrussPart")) then boxMinInWorld = object.CFrame:pointToWorldSpace(-0.5 * object.Size) boxMinInPart1 = part1.CFrame:pointToObjectSpace(boxMinInWorld) boxMaxInWorld = object.CFrame:pointToWorldSpace(0.5 * object.Size) boxMaxInPart1 = part1.CFrame:pointToObjectSpace(boxMaxInWorld) local minX = minVec.x local minY = minVec.y local minZ = minVec.z local maxX = maxVec.x local maxY = maxVec.y local maxZ = maxVec.z if boxMinInWorld.x < minVec.x then minX = boxMinInWorld.x end if boxMinInWorld.y < minVec.y then minY = boxMinInWorld.y end if boxMinInWorld.z < minVec.z then minZ = boxMinInWorld.z end if boxMaxInWorld.x < minX then minX = boxMaxInWorld.x end if boxMaxInWorld.y < minY then minY = boxMaxInWorld.y end if boxMaxInWorld.z < minZ then minZ = boxMaxInWorld.z end if boxMinInWorld.x > maxVec.x then maxX = boxMinInWorld.x end if boxMinInWorld.y > maxVec.y then maxY = boxMinInWorld.y end if boxMinInWorld.z > maxVec.z then maxZ = boxMinInWorld.z end if boxMaxInWorld.x > maxX then maxX = boxMaxInWorld.x end if boxMaxInWorld.y > maxY then maxY = boxMaxInWorld.y end if boxMaxInWorld.z > maxZ then maxZ = boxMaxInWorld.z end minVec = Vector3.new(minX, minY, minZ) maxVec = Vector3.new(maxX, maxY, maxZ) end end end return minVec, maxVec end function getTargetPartBoundingBox(targetPart) if targetPart.Parent:FindFirstChild("RobloxModel") ~= nil then return getBoundingBox2(targetPart.Parent) else return getBoundingBox2(targetPart) end end function getMouseTargetCFrame(targetPart) if targetPart.Parent:FindFirstChild("RobloxModel") ~= nil then return targetPart.Parent:GetChildren()[1].CFrame else return targetPart.CFrame end end function getClosestAlignedWorldDirection(aVector3InWorld) local xDir = Vector3.new(1,0,0) local yDir = Vector3.new(0,1,0) local zDir = Vector3.new(0,0,1) local xDot = aVector3InWorld.x * xDir.x + aVector3InWorld.y * xDir.y + aVector3InWorld.z * xDir.z local yDot = aVector3InWorld.x * yDir.x + aVector3InWorld.y * yDir.y + aVector3InWorld.z * yDir.z local zDot = aVector3InWorld.x * zDir.x + aVector3InWorld.y * zDir.y + aVector3InWorld.z * zDir.z if math.abs(xDot) > math.abs(yDot) and math.abs(xDot) > math.abs(zDot) then if xDot > 0 then return 0 else return 3 end elseif math.abs(yDot) > math.abs(xDot) and math.abs(yDot) > math.abs(zDot) then if yDot > 0 then return 1 else return 4 end else if zDot > 0 then return 2 else return 5 end end end function findConfigAtMouseTarget(collection) -- *Critical Assumption* : -- This function assumes the target CF axes are orthogonal with the target bounding box faces -- And, it assumes the insert CF axes are orthongonal with the insert bounding box faces -- Therefore, insertion will not work with angled faces on wedges or other "non-block" parts, nor -- will it work for parts in a model that are not orthogonally aligned with the model's CF. local grid = 4.0 local admissibleConfig = false local targetConfig = CFrame.new(0,0,0) local minBB, maxBB = getBoundingBox2(collection[1]) local diagBB = maxBB - minBB local insertCFrame if collection[1]:IsA("Model") then i = 1 while (i < (#collection[1]:GetChildren()) and not isPart(collection[1]:GetChildren()[i])) do i = i + 1 end insertCFrame = collection[1]:GetChildren()[i].CFrame else insertCFrame = collection[1].CFrame end Mouse.TargetFilter = collection[1] local targetPart = Mouse.Target if targetPart == nil then return admissibleConfig, targetConfig end -- test mouse hit location local minBBTarget, maxBBTarget = getTargetPartBoundingBox(targetPart) local diagBBTarget = maxBBTarget - minBBTarget local targetCFrame = getMouseTargetCFrame(targetPart) local hitCFrame = Mouse.Hit local mouseHitInWorld = hitCFrame.p --local targetVectorInWorld = targetCFrame:vectorToWorldSpace(Vector3.FromNormalId(Mouse.TargetSurface)) if targetPart:IsA("Terrain") then if not cluster then cluster = game.Workspace.Terrain end -- the prefer solid is messing things up very slightly!! (because the TargetSurface stays correct when the cells are shifted very slightly prematurely) cellID = cluster:WorldToCellPreferSolid(mouseHitInWorld) targetCFrame = CFrame.new(cluster:CellCenterToWorld(cellID.x, cellID.y, cellID.z)) end local targetVectorInWorld = targetCFrame:vectorToWorldSpace(Vector3.FromNormalId(Mouse.TargetSurface)) local mouseHitInTarget = targetCFrame:pointToObjectSpace(mouseHitInWorld) local targetRefPointInTarget local clampToSurface if getClosestAlignedWorldDirection(targetVectorInWorld) == 0 then targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(1, -1, 1)) insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(-1, -1, 1)) clampToSurface = Vector3.new(0,1,1) elseif getClosestAlignedWorldDirection(targetVectorInWorld) == 3 then targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(-1, -1, -1)) insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(1, -1, -1)) clampToSurface = Vector3.new(0,1,1) elseif getClosestAlignedWorldDirection(targetVectorInWorld) == 1 then targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(-1, 1, 1)) insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(-1, -1, 1)) clampToSurface = Vector3.new(1,0,1) elseif getClosestAlignedWorldDirection(targetVectorInWorld) == 4 then targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(-1, -1, 1)) insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(-1, 1, 1)) clampToSurface = Vector3.new(1,0,1) elseif getClosestAlignedWorldDirection(targetVectorInWorld) == 2 then targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(-1, -1, 1)) insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(-1, -1, -1)) clampToSurface = Vector3.new(1,1,0) else targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(1, -1, -1)) insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(1, -1, 1)) clampToSurface = Vector3.new(1,1,0) end targetRefPointInTarget = targetRefPointInTarget * (0.5 * diagBBTarget) + 0.5 * (maxBBTarget + minBBTarget) insertRefPointInInsert = insertRefPointInInsert * (0.5 * diagBB) + 0.5 * (maxBB + minBB) -- To Do: For cases that are not aligned to the world grid, account for the minimal rotation -- needed to bring the Insert part(s) into alignment with the Target Part -- Apply the rotation here local delta = mouseHitInTarget - targetRefPointInTarget local deltaClamped = Vector3.new(grid * math.modf(delta.x/grid), grid * math.modf(delta.y/grid), grid * math.modf(delta.z/grid)) deltaClamped = deltaClamped * clampToSurface local targetTouchInTarget = deltaClamped + targetRefPointInTarget local TargetTouchRelToWorld = targetCFrame:pointToWorldSpace(targetTouchInTarget) local InsertTouchInWorld = insertCFrame:vectorToWorldSpace(insertRefPointInInsert) local posInsertOriginInWorld = TargetTouchRelToWorld - InsertTouchInWorld local x, y, z, R00, R01, R02, R10, R11, R12, R20, R21, R22 = insertCFrame:components() targetConfig = CFrame.new(posInsertOriginInWorld.x, posInsertOriginInWorld.y, posInsertOriginInWorld.z, R00, R01, R02, R10, R11, R12, R20, R21, R22) admissibleConfig = true return admissibleConfig, targetConfig end function startDrag(mousePart, hitPoint, collection) lastTargetCFrame = nil dragger = Instance.new("Dragger") pcall(function() dragger:MouseDown(mousePart, hitPoint, collection) end) end function collectBaseParts(object, collection) if object == nil then return end --if object:IsA("BasePart") then if isPart(object) then collection[#collection+1] = object end for index,child in pairs(object:GetChildren()) do collectBaseParts(child, collection) end end function onMouseDown(mouse) mouse.Icon ="rbxasset://textures\\GrabRotateCursor.png" local part = mouse.Target if canSelectObject(part) then local hitPoint = mouse.Hit:toObjectSpace(part.CFrame).p if trySelection(part) then instances = {} game.JointsService:ClearJoinAfterMoveJoints() game.JointsService:SetJoinAfterMoveInstance(mouse.Target) collectBaseParts(currentSelection, instances) startDrag(part, hitPoint, instances) return end end end -- stampability-checking functions (copied from StampScript) function flashRedBox(targetModel) if not player then return end errorBox.Parent = player.PlayerGui errorBox.Adornee = targetModel delay(0,function() for i = 1, 3 do errorBox.Visible = true wait(0.13) errorBox.Visible = false wait(0.13) end errorBox.Adornee = nil errorBox.Parent = Tool end) end -- below function should work as a Region3 query, returning true if a single cluster part is within this region function clusterPartsInRegion(startVector, endVector) if not cluster then return false end local startCell = cluster:WorldToCell(startVector) local endCell = cluster:WorldToCell(endVector) local startX = startCell.X local startY = startCell.Y local startZ = startCell.Z local endX = endCell.X local endY = endCell.Y local endZ = endCell.Z if startX < cluster.MaxExtents.Min.X then startX = cluster.MaxExtents.Min.X end if startY < cluster.MaxExtents.Min.Y then startY = cluster.MaxExtents.Min.Y end if startZ < cluster.MaxExtents.Min.Z then startZ = cluster.MaxExtents.Min.Z end if endX > cluster.MaxExtents.Max.X then endX = cluster.MaxExtents.Max.X end if endY > cluster.MaxExtents.Max.Y then endY = cluster.MaxExtents.Max.Y end if endZ > cluster.MaxExtents.Max.Z then endZ = cluster.MaxExtents.Max.Z end --print(startX, endX) --print(startY, endY) --print(startZ, endZ) for x = startX, endX do for y = startY, endY do for z = startZ, endZ do --if game.Workspace.Cluster:GetCell(x, y, z) > 0 then return true end if (cluster:GetCell(x, y, z).Value) > 0 then return true end end end end return false end -- helper function to determine if a character can be pushed upwards by a certain amount -- FILL THIS OUT!!! -- character is 5 studs tall, we'll check a 1.5 x 1.5 x 4.5 box around char, with center .5 studs below torsocenter function spaceAboveCharacter(charTorso, newTorsoY) local partsAboveChar = game.Workspace:FindPartsInRegion3(Region3.new(Vector3.new(charTorso.Position.X, newTorsoY, charTorso.Position.Z) - Vector3.new(.75, 2.75, .75), Vector3.new(charTorso.Position.X, newTorsoY, charTorso.Position.Z) + Vector3.new(.75, 1.75, .75)), charTorso.Parent, 100) for j = 1, #partsAboveChar do if partsAboveChar[j].CanCollide and not partsAboveChar[j]:IsDescendantOf(currentSelection) then return false end end if clusterPartsInRegion(Vector3.new(charTorso.Position.X, newTorsoY, charTorso.Position.Z) - Vector3.new(.75, 2.75, .75), Vector3.new(charTorso.Position.X, newTorsoY, charTorso.Position.Z) + Vector3.new(.75, 1.75, .75)) then return false end return true end local insertBoundingBoxOverlapVector = Vector3.new(1, 1, 1) function onMouseUp(mouse) mouse.Icon ="rbxasset://textures\\GrabCursor.png" local thingToPlace = {} thingToPlace[1] = currentSelection if dragger ~= nil then local minBB, maxBB = getBoundingBoxInWorldCoordinates(currentSelection) local configFound, targetCFrame = findConfigAtMouseTarget(thingToPlace) if configFound then -- don't drag into terrain if clusterPartsInRegion(minBB+insertBoundingBoxOverlapVector, maxBB-insertBoundingBoxOverlapVector) then flashRedBox(currentSelection) return end local blockingParts = game.Workspace:FindPartsInRegion3(Region3.new(minBB+insertBoundingBoxOverlapVector, maxBB-insertBoundingBoxOverlapVector), currentSelection, 100) for b = 1, #blockingParts do -- put code back here if we want to prevent dragger from dragging into other stamped models (once Region3 fix goes out) end local alreadyPushedUp = {} -- if no blocking model below, then see if stamping on top of a character for b = 1, #blockingParts do if blockingParts[b].Parent and not alreadyPushedUp[blockingParts[b].Parent] and blockingParts[b].Parent:FindFirstChild("Humanoid") and blockingParts[b].Parent:FindFirstChild("Humanoid"):IsA("Humanoid") then local blockingPersonTorso = blockingParts[b].Parent:FindFirstChild("Torso") alreadyPushedUp[blockingParts[b].Parent] = true if blockingPersonTorso then -- if so, let's push the person upwards so they pop on top of the stamped model/part (but only if there's space above them) local newY = maxBB.Y + 3 if spaceAboveCharacter(blockingPersonTorso, newY) then blockingPersonTorso.CFrame = blockingPersonTorso.CFrame + Vector3.new(0, newY - blockingPersonTorso.CFrame.p.Y, 0) else -- if no space, we just error flashRedBox(currentSelection) return end end end end Mouse.TargetFilter = nil pcall(function() dragger:MouseUp() end) game.JointsService:CreateJoinAfterMoveJoints() dragger = nil end end end function trySelection(part) if canSelectObject(part) then local model = findModel(part) if model then return setSelection(model) else return setSelection(part) end else clearSelection() return false end end function onKeyDown(key) if dragger ~= nil then if key == 'R' or key == 'r' then pcall(function() dragger:AxisRotate(Enum.Axis.Y) end) elseif key == 'T' or key == 't' then pcall(function() dragger:AxisRotate(Enum.Axis.Z) end) end end end local alreadyMoving = false function onMouseMove(mouse) if alreadyMoving then return end alreadyMoving = true if dragger ~= nil then local thingToDrag = {} thingToDrag[1] = currentSelection pcall(function() dragger:MouseMove(mouse.UnitRay) end)-- needed to break welds properly configFound, targetCFrame = findConfigAtMouseTarget(thingToDrag) if configFound then local minBB, maxBB = getBoundingBoxInWorldCoordinates(currentSelection) -- need to offset by distance to be dragged local currModelCFrame if currentSelection:IsA("Model") then -- we assume model has at least one part in it; need to find first part i = 1 while (i < (#currentSelection:GetChildren()) and not isPart(currentSelection:GetChildren()[i])) do i = i + 1 end currModelCFrame = currentSelection:GetChildren()[i].CFrame else currModelCFrame = currentSelection.CFrame end minBB = minBB + targetCFrame.p - currModelCFrame.p maxBB = maxBB + targetCFrame.p - currModelCFrame.p -- don't drag into terrain if clusterPartsInRegion(minBB+insertBoundingBoxOverlapVector, maxBB-insertBoundingBoxOverlapVector) then if lastTargetCFrame then positionPartsAtCFrame3(thingToDrag, lastTargetCFrame) end alreadyMoving = false return end local blockingParts = game.Workspace:FindPartsInRegion3(Region3.new(minBB+insertBoundingBoxOverlapVector, maxBB-insertBoundingBoxOverlapVector), currentSelection, 100) for b = 1, #blockingParts do -- put code back here if we want to prevent dragger from dragging into other stamped models (once Region3 fix goes out) end positionPartsAtCFrame3(thingToDrag, targetCFrame) lastTargetCFrame = targetCFrame end else trySelection(mouse.Target) end alreadyMoving = false end function saveSelectionColor(instance) if instance:IsA("BasePart") then currentSelectionColors[instance] = instance.BrickColor if instance.BrickColor == BrickColor.Blue() then instance.BrickColor = BrickColor.new("Deep blue") else instance.BrickColor = BrickColor.Blue() end end local children = instance:GetChildren() if children then for pos, child in pairs(children) do saveSelectionColor(child) end end end function setSelection(partOrModel) if partOrModel ~= currentSelection then clearSelection() currentSelection = partOrModel saveSelectionColor(currentSelection) selectionBox.Adornee = currentSelection return true elseif partOrModel == nil then clearSelection() return false end return partOrModel == currentSelection end function clearSelection() if currentSelection ~= nil then for part, color in pairs(currentSelectionColors) do part.BrickColor = color end selectionBox.Adornee = nil end currentSelectionColors = {} currentSelection = nil if(selectionBox) then selectionBox.Adornee = nil end end function onEquippedLocal(mouse) Mouse = mouse local character = script.Parent.Parent.Parent player = game.Players:GetPlayerFromCharacter(character) mouse.Icon ="rbxasset://textures\\GrabCursor.png" local con = Mouse.Button1Down:connect(function() onMouseDown(Mouse) end) table.insert(connections,con) con = Mouse.Button1Up:connect(function() onMouseUp(Mouse) end) con = table.insert(connections,con) con = Mouse.Move:connect(function() onMouseMove(Mouse) end) table.insert(connections,con) con = Mouse.KeyDown:connect(function(string) onKeyDown(string) end) table.insert(connections,con) selectionBox = Instance.new("SelectionBox") selectionBox.Name = "Model Delete Selection" selectionBox.Color = BrickColor.Blue() selectionBox.Adornee = nil selectionBox.Parent = player.PlayerGui alreadyMoving = false end function onUnequippedLocal() for i = 1, #connections do connections[i]:disconnect() end connections = {} clearSelection() selectionBox:Remove() end script.Active.Changed:connect(function() if script.Active.Value then onEquippedLocal(Tool.Mouse.Value) else onUnequippedLocal() end end) Active false null 21 ErrorBox 0 false