2319 lines
76 KiB
Plaintext
2319 lines
76 KiB
Plaintext
<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
|
|
<External>null</External>
|
|
<External>nil</External>
|
|
<Item class="Tool" referent="RBX0">
|
|
<Properties>
|
|
<bool name="Enabled">true</bool>
|
|
<CoordinateFrame name="Grip">
|
|
<X>0</X>
|
|
<Y>0</Y>
|
|
<Z>0</Z>
|
|
<R00>1</R00>
|
|
<R01>0</R01>
|
|
<R02>0</R02>
|
|
<R10>0</R10>
|
|
<R11>1</R11>
|
|
<R12>0</R12>
|
|
<R20>0</R20>
|
|
<R21>0</R21>
|
|
<R22>1</R22>
|
|
</CoordinateFrame>
|
|
<string name="Name">ClassicTool</string>
|
|
<Content name="TextureId"><url>http://www.roblox.com/asset/?id=59105322</url></Content>
|
|
</Properties>
|
|
<Item class="LocalScript" referent="RBX1">
|
|
<Properties>
|
|
<bool name="Disabled">false</bool>
|
|
<Content name="LinkedSource"><null></null></Content>
|
|
<string name="Name">ClassicToolController</string>
|
|
<ProtectedString name="Source">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)
|
|
</ProtectedString>
|
|
</Properties>
|
|
</Item>
|
|
<Item class="Part" referent="RBX2">
|
|
<Properties>
|
|
<bool name="Anchored">false</bool>
|
|
<float name="BackParamA">-0.5</float>
|
|
<float name="BackParamB">0.5</float>
|
|
<token name="BackSurface">0</token>
|
|
<token name="BackSurfaceInput">0</token>
|
|
<float name="BottomParamA">-0.5</float>
|
|
<float name="BottomParamB">0.5</float>
|
|
<token name="BottomSurface">0</token>
|
|
<token name="BottomSurfaceInput">0</token>
|
|
<int name="BrickColor">199</int>
|
|
<CoordinateFrame name="CFrame">
|
|
<X>0.999433637</X>
|
|
<Y>7.98012686</Y>
|
|
<Z>-12.5012054</Z>
|
|
<R00>-1.50203878e-005</R00>
|
|
<R01>1.50579854e-006</R01>
|
|
<R02>-1.00000012</R02>
|
|
<R10>9.8371238e-006</R10>
|
|
<R11>1</R11>
|
|
<R12>1.50565256e-006</R12>
|
|
<R20>1.00000012</R20>
|
|
<R21>-9.83710197e-006</R21>
|
|
<R22>-1.50204023e-005</R22>
|
|
</CoordinateFrame>
|
|
<bool name="CanCollide">true</bool>
|
|
<float name="Elasticity">0.5</float>
|
|
<float name="Friction">0.300000012</float>
|
|
<float name="FrontParamA">-0.5</float>
|
|
<float name="FrontParamB">0.5</float>
|
|
<token name="FrontSurface">0</token>
|
|
<token name="FrontSurfaceInput">0</token>
|
|
<float name="LeftParamA">-0.5</float>
|
|
<float name="LeftParamB">0.5</float>
|
|
<token name="LeftSurface">0</token>
|
|
<token name="LeftSurfaceInput">0</token>
|
|
<bool name="Locked">true</bool>
|
|
<token name="Material">256</token>
|
|
<string name="Name">Handle</string>
|
|
<float name="Reflectance">0</float>
|
|
<float name="RightParamA">-0.5</float>
|
|
<float name="RightParamB">0.5</float>
|
|
<token name="RightSurface">0</token>
|
|
<token name="RightSurfaceInput">0</token>
|
|
<Vector3 name="RotVelocity">
|
|
<X>0</X>
|
|
<Y>0</Y>
|
|
<Z>0</Z>
|
|
</Vector3>
|
|
<float name="TopParamA">-0.5</float>
|
|
<float name="TopParamB">0.5</float>
|
|
<token name="TopSurface">0</token>
|
|
<token name="TopSurfaceInput">0</token>
|
|
<float name="Transparency">0</float>
|
|
<Vector3 name="Velocity">
|
|
<X>0</X>
|
|
<Y>0</Y>
|
|
<Z>0</Z>
|
|
</Vector3>
|
|
<token name="formFactorRaw">2</token>
|
|
<token name="shape">1</token>
|
|
<Vector3 name="size">
|
|
<X>1</X>
|
|
<Y>0.800000012</Y>
|
|
<Z>2</Z>
|
|
</Vector3>
|
|
</Properties>
|
|
<Item class="SpecialMesh" referent="RBX3">
|
|
<Properties>
|
|
<token name="LODX">2</token>
|
|
<token name="LODY">2</token>
|
|
<Content name="MeshId"><url>http://www.roblox.com/asset/?id=15952510</url></Content>
|
|
<token name="MeshType">5</token>
|
|
<string name="Name">Mesh</string>
|
|
<Vector3 name="Offset">
|
|
<X>0</X>
|
|
<Y>0</Y>
|
|
<Z>0</Z>
|
|
</Vector3>
|
|
<Vector3 name="Scale">
|
|
<X>0.400000006</X>
|
|
<Y>0.400000006</Y>
|
|
<Z>0.400000006</Z>
|
|
</Vector3>
|
|
<Content name="TextureId"><url>http://www.roblox.com/asset/?id=15952494</url></Content>
|
|
<Vector3 name="VertexColor">
|
|
<X>1</X>
|
|
<Y>1</Y>
|
|
<Z>1</Z>
|
|
</Vector3>
|
|
</Properties>
|
|
</Item>
|
|
<Item class="Sound" referent="RBX4">
|
|
<Properties>
|
|
<bool name="Looped">false</bool>
|
|
<string name="Name">Sound</string>
|
|
<float name="Pitch">1</float>
|
|
<bool name="PlayOnRemove">false</bool>
|
|
<Content name="SoundId"><url>rbxasset://sounds/swordslash.wav</url></Content>
|
|
<float name="Volume">1</float>
|
|
</Properties>
|
|
</Item>
|
|
<Item class="Sound" referent="RBX5">
|
|
<Properties>
|
|
<bool name="Looped">false</bool>
|
|
<string name="Name">Sound</string>
|
|
<float name="Pitch">1</float>
|
|
<bool name="PlayOnRemove">false</bool>
|
|
<Content name="SoundId"><url>rbxasset://sounds/unsheath.wav</url></Content>
|
|
<float name="Volume">1</float>
|
|
</Properties>
|
|
</Item>
|
|
<Item class="Sound" referent="RBX6">
|
|
<Properties>
|
|
<bool name="Looped">false</bool>
|
|
<string name="Name">Sound</string>
|
|
<float name="Pitch">1</float>
|
|
<bool name="PlayOnRemove">false</bool>
|
|
<Content name="SoundId"><url>rbxasset://sounds/swordslash.wav</url></Content>
|
|
<float name="Volume">1</float>
|
|
</Properties>
|
|
</Item>
|
|
<Item class="Sound" referent="RBX7">
|
|
<Properties>
|
|
<bool name="Looped">false</bool>
|
|
<string name="Name">Sound</string>
|
|
<float name="Pitch">1</float>
|
|
<bool name="PlayOnRemove">false</bool>
|
|
<Content name="SoundId"><url>rbxasset://sounds/unsheath.wav</url></Content>
|
|
<float name="Volume">1</float>
|
|
</Properties>
|
|
</Item>
|
|
</Item>
|
|
<Item class="LocalScript" referent="RBX8">
|
|
<Properties>
|
|
<bool name="Disabled">false</bool>
|
|
<Content name="LinkedSource"><null></null></Content>
|
|
<string name="Name">Color</string>
|
|
<ProtectedString name="Source">-- 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.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)</ProtectedString>
|
|
</Properties>
|
|
<Item class="BoolValue" referent="RBX9">
|
|
<Properties>
|
|
<string name="Name">Active</string>
|
|
<bool name="Value">false</bool>
|
|
</Properties>
|
|
</Item>
|
|
<Item class="BrickColorValue" referent="RBX10">
|
|
<Properties>
|
|
<string name="Name">CurrentColor</string>
|
|
<int name="Value">194</int>
|
|
</Properties>
|
|
</Item>
|
|
</Item>
|
|
<Item class="LocalScript" referent="RBX11">
|
|
<Properties>
|
|
<bool name="Disabled">false</bool>
|
|
<Content name="LinkedSource"><null></null></Content>
|
|
<string name="Name">Material</string>
|
|
<ProtectedString name="Source">-- 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)
|
|
</ProtectedString>
|
|
</Properties>
|
|
<Item class="BoolValue" referent="RBX12">
|
|
<Properties>
|
|
<string name="Name">Active</string>
|
|
<bool name="Value">false</bool>
|
|
</Properties>
|
|
</Item>
|
|
<Item class="StringValue" referent="RBX13">
|
|
<Properties>
|
|
<string name="Name">CurrentMaterial</string>
|
|
<string name="Value">Plastic</string>
|
|
</Properties>
|
|
</Item>
|
|
</Item>
|
|
<Item class="LocalScript" referent="RBX14">
|
|
<Properties>
|
|
<bool name="Disabled">false</bool>
|
|
<Content name="LinkedSource"><null></null></Content>
|
|
<string name="Name">Resize</string>
|
|
<ProtectedString name="Source">-- 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
|
|
|
|
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
|
|
			if handles.Adornee:Resize(normal, sizeDelta) then
|
|
				previousDistance = distance
|
|
			end
|
|
		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) )
|
|
	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)
|
|
</ProtectedString>
|
|
</Properties>
|
|
<Item class="BoolValue" referent="RBX15">
|
|
<Properties>
|
|
<string name="Name">Active</string>
|
|
<bool name="Value">false</bool>
|
|
</Properties>
|
|
</Item>
|
|
</Item>
|
|
<Item class="LocalScript" referent="RBX16">
|
|
<Properties>
|
|
<bool name="Disabled">false</bool>
|
|
<Content name="LinkedSource"><null></null></Content>
|
|
<string name="Name">Surface</string>
|
|
<ProtectedString name="Source">-- 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)
|
|
</ProtectedString>
|
|
</Properties>
|
|
<Item class="BoolValue" referent="RBX17">
|
|
<Properties>
|
|
<string name="Name">Active</string>
|
|
<bool name="Value">false</bool>
|
|
</Properties>
|
|
</Item>
|
|
<Item class="StringValue" referent="RBX18">
|
|
<Properties>
|
|
<string name="Name">CurrentSurface</string>
|
|
<string name="Value">Smooth</string>
|
|
</Properties>
|
|
</Item>
|
|
</Item>
|
|
<Item class="ObjectValue" referent="RBX19">
|
|
<Properties>
|
|
<string name="Name">Mouse</string>
|
|
<Ref name="Value">null</Ref>
|
|
</Properties>
|
|
</Item>
|
|
<Item class="LocalScript" referent="RBX20">
|
|
<Properties>
|
|
<bool name="Disabled">false</bool>
|
|
<Content name="LinkedSource"><null></null></Content>
|
|
<string name="Name">Dragger</string>
|
|
<ProtectedString name="Source">-- 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)
|
|
|
|
</ProtectedString>
|
|
</Properties>
|
|
<Item class="LocalScript" referent="RBX21">
|
|
<Properties>
|
|
<bool name="Disabled">false</bool>
|
|
<Content name="LinkedSource"><null></null></Content>
|
|
<string name="Name">OldDragger</string>
|
|
<ProtectedString name="Source">-- 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)
|
|
</ProtectedString>
|
|
</Properties>
|
|
<Item class="BoolValue" referent="RBX22">
|
|
<Properties>
|
|
<string name="Name">Active</string>
|
|
<bool name="Value">false</bool>
|
|
</Properties>
|
|
</Item>
|
|
</Item>
|
|
<Item class="BoolValue" referent="RBX23">
|
|
<Properties>
|
|
<string name="Name">Active</string>
|
|
<bool name="Value">false</bool>
|
|
</Properties>
|
|
</Item>
|
|
<Item class="LocalScript" referent="RBX24">
|
|
<Properties>
|
|
<bool name="Disabled">false</bool>
|
|
<Content name="LinkedSource"><null></null></Content>
|
|
<string name="Name">NewDragger</string>
|
|
<ProtectedString name="Source">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)</ProtectedString>
|
|
</Properties>
|
|
<Item class="BoolValue" referent="RBX25">
|
|
<Properties>
|
|
<string name="Name">Active</string>
|
|
<bool name="Value">false</bool>
|
|
</Properties>
|
|
</Item>
|
|
</Item>
|
|
</Item>
|
|
<Item class="SelectionBox" referent="RBX26">
|
|
<Properties>
|
|
<Ref name="Adornee">null</Ref>
|
|
<int name="Color">21</int>
|
|
<string name="Name">ErrorBox</string>
|
|
<float name="Transparency">0</float>
|
|
<bool name="Visible">false</bool>
|
|
</Properties>
|
|
</Item>
|
|
</Item>
|
|
</roblox> |