· 9 years ago · Dec 28, 2016, 09:40 PM
1--Created with ttyyuu12345's compiler
2--ttyyuu12345 is not responsible for damages caused to your game
3--This plugin does not remove things
4--ttyyuu12345 cannot be held resonsible for manual deletion for the purpose of testing
5--Keep in mind, any items that cause errors in compilation will be skipped and documented within the last line of the disclaimer comments
6--Thank you for using my plugin and enjoy :)
7--It is free to use
8--If you use this plugin to create your own, please give me credit
9--Z_V edited my plugin to look like his own and published it without giving me credit, and that makes me very angry
10--Errors:
11local runDummyScript = function(f,scri)
12local oldenv = getfenv(f)
13local newenv = setmetatable({}, {
14__index = function(_, k)
15if k:lower() == 'script' then
16return scri
17else
18return oldenv[k]
19end
20end
21})
22setfenv(f, newenv)
23ypcall(function() f() end)
24end
25cors = {}
26mas = Instance.new("Model",game:GetService("Lighting"))
27mas.Name = "CompiledModel"
28o1 = Instance.new("Tool")
29o1.Name = "StamperTool"
30o1.Parent = game.Players.LocalPlayer.Backpack
31o1.TextureId = "http://www.roblox.com/asset/?id=59102781"
32o1.GripPos = Vector3.new(0, 0, 0.349999994)
33o2 = Instance.new("Part")
34o2.Name = "Handle"
35o2.Parent = o1
36o2.Position = Vector3.new(93.6221466, 0.591779947, 23.7204399)
37o2.Rotation = Vector3.new(-179.878616, 8.34529877, 0.0595413931)
38o2.RotVelocity = Vector3.new(-0.0523095541, -0.00254237605, 0.0423163772)
39o2.Velocity = Vector3.new(0.00187618425, -0.00348494574, 0.000361006416)
40o2.CFrame = CFrame.new(93.6221466, 0.591779947, 23.7204399, 0.989410818, -0.00102818955, 0.145138487, -0.00134668022, -0.999996781, 0.00209616055, 0.145135894, -0.00226941914, -0.98940897)
41o2.Size = Vector3.new(1, 0.400000006, 1)
42o3 = Instance.new("SpecialMesh")
43o3.Parent = o2
44o3.MeshId = "http://www.roblox.com/asset/?id=42163552"
45o3.Scale = Vector3.new(0.899999976, 0.899999976, 0.899999976)
46o3.TextureId = "http://www.roblox.com/asset/?id=42163513"
47o3.MeshType = Enum.MeshType.FileMesh
48o4 = Instance.new("ObjectValue")
49o4.Name = "PlayerOwner"
50o4.Parent = o1
51o5 = Instance.new("ObjectValue")
52o5.Name = "SavedState"
53o5.Parent = o1
54o6 = Instance.new("Model")
55o6.Name = "LuaGlobalVariables"
56o6.Parent = o1
57o7 = Instance.new("Model")
58o7.Name = "InsertAsset"
59o7.Parent = o6
60o8 = Instance.new("StringValue")
61o8.Name = "AssetName"
62o8.Parent = o7
63o9 = Instance.new("IntValue")
64o9.Name = "AssetId"
65o9.Parent = o7
66o10 = Instance.new("StringValue")
67o10.Name = "Image"
68o10.Parent = o7
69o11 = Instance.new("BoolValue")
70o11.Name = "StampMode"
71o11.Parent = o7
72o11.Value = true
73o12 = Instance.new("BoolValue")
74o12.Name = "Updated"
75o12.Parent = o7
76o13 = Instance.new("BoolValue")
77o13.Name = "SwitchLoaderToDialog"
78o13.Parent = o6
79o14 = Instance.new("StringValue")
80o14.Name = "DialogType"
81o14.Parent = o13
82o14.Value = "Stamp"
83o15 = Instance.new("StringValue")
84o15.Name = "AssetImage"
85o15.Parent = o13
86o15.Value = "nil"
87o16 = Instance.new("BoolValue")
88o16.Name = "ShowInvalidPlacement"
89o16.Parent = o6
90o17 = Instance.new("BoolValue")
91o17.Name = "ShowMaxedOut"
92o17.Parent = o6
93o18 = Instance.new("BoolValue")
94o18.Name = "SwitchMode"
95o18.Parent = o6
96o19 = Instance.new("StringValue")
97o19.Name = "Mode"
98o19.Parent = o18
99o20 = Instance.new("BoolValue")
100o20.Name = "Stamped"
101o20.Parent = o6
102o21 = Instance.new("BoolValue")
103o21.Name = "Moving"
104o21.Parent = o6
105o22 = Instance.new("BoolValue")
106o22.Name = "ShowAdminCategories"
107o22.Parent = o6
108o23 = Instance.new("IntValue")
109o23.Name = "userIDs"
110o23.Parent = o6
111o23.Value = 6
112o24 = Instance.new("IntValue")
113o24.Name = "userID"
114o24.Parent = o23
115o24.Value = 11744447
116o25 = Instance.new("IntValue")
117o25.Name = "userID"
118o25.Parent = o23
119o25.Value = 18881789
120o26 = Instance.new("IntValue")
121o26.Name = "userID"
122o26.Parent = o23
123o26.Value = 18881808
124o27 = Instance.new("IntValue")
125o27.Name = "userID"
126o27.Parent = o23
127o27.Value = 18881829
128o28 = Instance.new("IntValue")
129o28.Name = "userID"
130o28.Parent = o23
131o28.Value = 18881853
132o29 = Instance.new("IntValue")
133o29.Name = "userID"
134o29.Parent = o23
135o29.Value = 18881866
136o30 = Instance.new("BoolValue")
137o30.Name = "ReloadCurrentAsset"
138o30.Parent = o6
139o31 = Instance.new("BoolValue")
140o31.Name = "ReloadCurrentAsset"
141o31.Parent = o6
142o32 = Instance.new("BoolValue")
143o32.Name = "MouseClick"
144o32.Parent = o6
145o33 = Instance.new("BoolValue")
146o33.Name = "IsRestricted"
147o33.Parent = o6
148o34 = Instance.new("LocalScript")
149o34.Name = "BasePlateGuide"
150o34.Parent = o1
151o34.Disabled = true
152table.insert(cors,coroutine.create(function()
153wait()
154runDummyScript(function()
155local pointDirection = nil
156
157local tailLength = 2 -- 2 or 7
158--local dSize = -.05 -- .01 or .005
159local dSize = 0 -- because we want the targets to all be the same size (tail isn't larger anymore; just "ghost" effect)
160local dTime = .04 --.025
161
162-- old targetLock pic (square): 48972746
163
164local targetLockSize = .2
165local arrowSize = .1
166
167local arrowScreenProportionSize = .95
168local arrowMoveFactor = .025
169
170local targetMoveFactor = targetLockSize / 2 - .025
171
172local halfDSize = dSize / 2
173
174local r = game:service("RunService")
175
176local vChar = script.Parent
177if vChar == nil then script.Parent = nil end
178
179local vPlay = game.Players:GetPlayerFromCharacter(vChar)
180if vPlay == nil then script.Parent = nil end
181
182local arrowGui = vPlay.PlayerGui:FindFirstChild("GuideArrowGui")
183if arrowGui == nil then
184 arrowGui = script.GuideArrowGui
185 arrowGui.Parent = vPlay.PlayerGui
186else
187 script.GuideArrowGui:remove()
188end
189
190local upArrow = arrowGui.UpArrow
191local downArrow = arrowGui.DownArrow
192local leftArrow = arrowGui.LeftArrow
193local rightArrow = arrowGui.RightArrow
194local targetLock = arrowGui.TargetLock
195local arrowList = {upArrow, downArrow, leftArrow, rightArrow, targetLock}
196
197local goAway = arrowGui.GoAwayButton
198goAway.Visible = true
199goAway.Active = true
200local keepShowing = true
201goAway.MouseButton1Click:connect(function () keepShowing = false end)
202
203
204local arrowHeightAugment = 0.0
205local arrowWidthAugment = 0.0
206local targetHeightAugment = 0.0
207local targetWidthAugment = 0.0
208
209
210local targetLockList = {targetLock}
211for i = 1, tailLength do table.insert(targetLockList, targetLock:Clone()) end
212
213targetLockList[1].Size = UDim2.new(targetLockSize, 0, targetLockSize, 0)
214for i = 1, #targetLockList-1 do
215 targetLockList[i+1].Parent = arrowGui
216 --targetLockList[i+1].Size = UDim2.new(targetLockSize-i*dSize, 0, targetLockSize-i*dSize, 0)
217end
218-- switching over to a "ghost-like" transparency effect, but this means we have to upload separate images :(
219-- if our tail is turned on, manually apply the ghosting to the next two images
220if tailLength > 0 then targetLockList[2].Image = "http://www.roblox.com/asset/?id=49324811" end
221if tailLength > 1 then targetLockList[3].Image = "http://www.roblox.com/asset/?id=49324846" end
222
223
224function onResize() -- force arrows into a square resolution
225 xSize = arrowGui.AbsoluteSize.X
226 ySize = arrowGui.AbsoluteSize.Y
227
228 if xSize >= ySize then
229 arrowHeightAugment = 0.0
230
231 -- calculate arrowWidthAugment and new arrow ratio here
232 newArrowUDim = UDim2.new(ySize / xSize * arrowSize, 0, arrowSize, 0)
233 rightArrow.Size = newArrowUDim
234 leftArrow.Size = newArrowUDim
235 upArrow.Size = newArrowUDim
236 downArrow.Size = newArrowUDim
237
238 for tli = 1, #targetLockList do
239 targetLockList[tli].Size = UDim2.new(ySize / xSize * (targetLockSize-tli*dSize), 0, targetLockSize-tli*dSize, 0)
240 end
241
242 arrowWidthAugment = (xSize - ySize)*arrowSize*.5 / xSize
243 else
244 arrowWidthAugment = 0.0
245
246 -- calculate arrowHeightAugment here
247 newArrowUDim = UDim2.new(arrowSize, 0, xSize / ySize * arrowSize, 0)
248 rightArrow.Size = newArrowUDim
249 leftArrow.Size = newArrowUDim
250 upArrow.Size = newArrowUDim
251 downArrow.Size = newArrowUDim
252
253 for tli = 1, #targetLockList do
254 targetLockList[tli].Size = UDim2.new(targetLockSize-tli*dSize, 0, xSize / ySize * (targetLockSize-tli*dSize), 0)
255 end
256
257 arrowHeightAugment = (ySize - xSize)*arrowSize*.5 / ySize
258 end
259
260 targetWidthAugment = targetLock.Size.X.Scale / 2 - .025
261 targetHeightAugment = targetLock.Size.Y.Scale / 2 - .025
262end
263
264arrowGui.Changed:connect(onResize) -- dynamically resize the arrows on screen resize
265
266function findMyBasePlate()
267 --if true then return game.Workspace.Base end -- for testing purposes
268
269 local buildingAreas = game.Workspace.BuildingAreas:GetChildren()
270 for i = 1, #buildingAreas do
271 if buildingAreas[i].Player.Value == script.Parent.Name then
272 return buildingAreas[i]:FindFirstChild("BasePlate") or buildingAreas[i].PlayerArea:FindFirstChild("BasePlate")
273 end
274 end
275end
276
277local myBase = findMyBasePlate()
278if myBase == nil then
279 print("BasePlateGuide script error: no base plate found!")
280 -- abort if no BasePlate found
281 arrowGui:remove()
282 script:remove()
283end
284
285function setVisible(whichArrow)
286 for i = 1, #arrowList do
287 if arrowList[i] == whichArrow then
288 arrowList[i].Visible = true
289 else
290 arrowList[i].Visible = false
291 end
292 end
293end
294
295function truncate(number, augmentation)
296 if number+augmentation < 0 then return 0
297 elseif number > (1 - arrowSize)+augmentation then return (1 - arrowSize)+2*augmentation -- furthest extent we want the arrows to reach is .95 - arrowSize
298 else return number+augmentation end
299end
300
301
302function notInBasePlate(myPos, base)
303 local corner1 = base.Position - base.Size/2
304 local corner2 = base.Position + base.Size/2
305 if myPos.X > corner1.X and myPos.Y > corner1.Y and myPos.Z > corner1.Z and myPos.X < corner2.X and myPos.Z < corner2.Z then -- we only care they're somewhere above baseplate
306 return false
307 else
308 return true
309 end
310end
311
312local lastTime = 0
313local camera = game.Workspace.CurrentCamera
314while notInBasePlate(script.Parent.Torso.Position, myBase) and keepShowing do
315 --pointDirection = (myBase.Position - script.Parent.Torso.Position) * Vector3.new(1, 0, 1)
316 camFrame = camera.CoordinateFrame
317 pointDirection = camFrame:vectorToObjectSpace(myBase.Position - camFrame.p)
318 camZ = pointDirection.Z
319 camX = pointDirection.X/math.abs(camZ)
320 camY = pointDirection.Y/math.abs(camZ)
321 --print(camX, camY, camZ)
322
323 -- was .55 for 610 (Y) and 1.15 for 1286 (X), so seems like scaling factor is universally 1114 on both axes
324 -- nvm: at 1662 x 666, we have ... and .55, so seems like .55 always for Y, then X is scaled according to its proportion to Y
325
326 local xThreshold = arrowGui.AbsoluteSize.X / arrowGui.AbsoluteSize.Y * .55
327 local yThreshold = .55
328
329 local nCamX = camX / xThreshold
330 local nCamY = camY / yThreshold
331
332 if (math.abs(nCamX) > 1 or math.abs(nCamY) > 1) or (camZ > 0) then -- camZ test makes sure we only lock on if facing right direction
333 for j = 2, #targetLockList do
334 targetLockList[j].Visible = false
335 end
336
337 if math.abs(nCamX) > math.abs(nCamY) then
338 --if nCamY > 1 then nCamY = 1
339 --elseif nCamY < -1 then nCamY = -1 end
340
341 if camX > 0 then
342 -- should go right
343 rightArrow.Position = UDim2.new(arrowScreenProportionSize - arrowMoveFactor - .025 + 2*arrowWidthAugment, 0, truncate(arrowScreenProportionSize*(1-nCamY)/2 - arrowMoveFactor, arrowHeightAugment), 0)
344 setVisible(rightArrow)
345 else
346 -- should go left
347 leftArrow.Position = UDim2.new(0, 0, truncate(arrowScreenProportionSize*(1-nCamY)/2 - arrowMoveFactor, arrowHeightAugment), 0)
348 setVisible(leftArrow)
349 end
350 else
351 --if nCamX > 1 then nCamX = 1
352 --elseif nCamX < -1 then nCamX = -1 end
353
354 if camY > 0 then
355 -- should go up
356 upArrow.Position = UDim2.new(truncate(arrowScreenProportionSize*(nCamX+1)/2 - arrowMoveFactor, arrowWidthAugment), 0, 0, 0)
357 setVisible(upArrow)
358 else
359 -- should go down
360 downArrow.Position = UDim2.new(truncate(arrowScreenProportionSize*(nCamX+1)/2 - arrowMoveFactor, arrowWidthAugment), 0, arrowScreenProportionSize - arrowMoveFactor -.025 + 2*arrowHeightAugment, 0)
361 setVisible(downArrow)
362 end
363 end
364 else
365 -- locked on target
366 --for j = 2, #targetLockList do
367 --targetLockList[j].Visible = true
368 --end
369 --targetLock.Position = UDim2.new(.95*(nCamX+1)/2 - targetMoveFactor, 0, .95*(1-nCamY)/2 - targetMoveFactor, 0)
370 targetLock.Position = UDim2.new(.95*(nCamX+1)/2 - targetWidthAugment, 0, .95*(1-nCamY)/2 - targetHeightAugment, 0)
371 setVisible(targetLock)
372 end
373
374 --wait()
375
376 -- update every dTime seconds
377
378 -- ok to do it this way instead of a ring array, because even though it's less efficient, it's less efficient by only one or two commands [since only have 2 "tails"]
379
380 local t = r.Stepped:wait()
381 if t - lastTime > dTime then
382 lastTime = t
383 for j = #targetLockList, 2, -1 do
384 targetLockList[j].Position = targetLockList[j-1].Position + UDim2.new(halfDSize, 0, halfDSize, 0)
385 targetLockList[j].Visible = targetLockList[j-1].Visible
386 end
387 end
388end
389
390--[[setVisible(nil)
391for j = 2, #targetLockList do
392 targetLockList[j].Visible = false
393end
394goAway.Visible = false
395goAway.Active = false
396]]--
397arrowGui:remove()
398script:remove()
399end,o34)
400end))
401o35 = Instance.new("ScreenGui")
402o35.Name = "GuideArrowGui"
403o35.Parent = o34
404o36 = Instance.new("ImageLabel")
405o36.Name = "UpArrow"
406o36.Parent = o35
407o36.Size = UDim2.new(0.050000000745058,0,0.050000000745058,0)
408o36.Visible = false
409o36.BackgroundTransparency = 1
410o36.Image = "http://www.roblox.com/asset/?id=48972729 "
411o37 = Instance.new("ImageLabel")
412o37.Name = "RightArrow"
413o37.Parent = o35
414o37.Size = UDim2.new(0.050000000745058,0,0.050000000745058,0)
415o37.Visible = false
416o37.BackgroundTransparency = 1
417o37.Image = "http://www.roblox.com/asset/?id=48972703"
418o38 = Instance.new("ImageLabel")
419o38.Name = "DownArrow"
420o38.Parent = o35
421o38.Size = UDim2.new(0.050000000745058,0,0.050000000745058,0)
422o38.Visible = false
423o38.BackgroundTransparency = 1
424o38.Image = "http://www.roblox.com/asset/?id=48972653"
425o39 = Instance.new("ImageLabel")
426o39.Name = "LeftArrow"
427o39.Parent = o35
428o39.Size = UDim2.new(0.050000000745058,0,0.050000000745058,0)
429o39.Visible = false
430o39.BackgroundTransparency = 1
431o39.Image = "http://www.roblox.com/asset/?id=48972682"
432o40 = Instance.new("ImageLabel")
433o40.Name = "TargetLock"
434o40.Parent = o35
435o40.Size = UDim2.new(0.050000000745058,0,0.050000000745058,0)
436o40.Visible = false
437o40.BackgroundTransparency = 1
438o40.Image = "http://www.roblox.com/asset/?id=49321779"
439o41 = Instance.new("TextButton")
440o41.Name = "GoAwayButton"
441o41.Parent = o35
442o41.Position = UDim2.new(0,20,0,40)
443o41.Size = UDim2.new(0,150,0,20)
444o41.Text = "Hide Guide Arrows"
445o41.BackgroundColor3 = Color3.new(0, 1, 0)
446o42 = Instance.new("LocalScript")
447o42.Name = "StampScript"
448o42.Parent = o1
449table.insert(cors,coroutine.create(function()
450wait()
451runDummyScript(function()
452-- basic functions
453
454function waitForChild(instance, name)
455 while not instance:findFirstChild(name) do
456 instance.ChildAdded:wait()
457 end
458end
459----------------------------------------------------------------------------------------
460
461-- Locals
462
463local Tool = script.Parent
464
465local Mouse
466local mouseMoveCon
467local mouseButton1DownCon
468local mouseButton1UpCon
469local cameraChangeCon
470
471local walking = false
472
473local pressedEsc = false
474
475local gInitial90DegreeRotations = 0
476local gStaticTrans = 1
477local gDesiredTrans = 0.7
478local transFadeInTime = 0.5
479local fadeInDelayTime = 0.5
480local eyedropperOffGridTolerance = 0.01
481
482local useAssetVersionId = false
483
484waitForChild(Tool,"LuaGlobalVariables")
485local variables = Tool.LuaGlobalVariables
486waitForChild(variables,"ShowInvalidPlacement")
487waitForChild(variables, "Stamped")
488waitForChild(Tool,"ErrorBox")
489waitForChild(variables, "ShowAdminCategories")
490local errorBox = Tool.ErrorBox
491
492waitForChild(variables, "IsRestricted")
493waitForChild(variables, "MouseClick")
494click = variables.MouseClick
495
496local Data = {}
497Data.Stamp = {}
498Data.Loading = {}
499
500local guiScriptIsLoadingSomething = false
501local unstampableSurface = false
502
503local eyeDropperConnection, eyeDropperMoveConnection
504
505local playerModel
506local player
507
508-- For Restricting Stamper Tool
509local isRestricted = variables.IsRestricted.Value
510local adminAccess = variables.ShowAdminCategories.Value
511
512-- For Delete highlighting
513local selectionBox
514local currentSelection
515local currentSelectionColors = {}
516
517if isRestricted then waitForChild(game.Workspace, "BaseplateBumpers") end
518----------------------------------------------------------------------------------------
519
520
521-- Functions
522local manualWeldTable = {}
523local manualWeldParentTable = {}
524function saveTheWelds(object)
525 if object:IsA("ManualWeld") then
526 table.insert(manualWeldTable, object)
527 table.insert(manualWeldParentTable, object.Parent)
528 else
529 local children = object:GetChildren()
530 for i = 1, #children do
531 saveTheWelds(children[i])
532 end
533 end
534end
535
536function restoreTheWelds()
537 for i = 1, #manualWeldTable do
538 manualWeldTable[i].Parent = manualWeldParentTable[i]
539 end
540end
541
542
543function findSeatsInModel(parent, seatTable)
544 if not parent then return end
545
546 if parent.className == "Seat" or parent.className == "VehicleSeat" then
547 table.insert(seatTable, parent)
548 end
549 local myChildren = parent:GetChildren()
550 for j = 1, #myChildren do
551 findSeatsInModel(myChildren[j], seatTable)
552 end
553end
554
555function setSeatEnabledStatus(model, isEnabled)
556 local seatList = {}
557 findSeatsInModel(model, seatList)
558
559 if isEnabled then
560 -- remove any welds called "SeatWeld" in seats
561 for i = 1, #seatList do
562 local nextSeat = seatList[i]:FindFirstChild("SeatWeld")
563 while nextSeat do nextSeat:Remove() nextSeat = seatList[i]:FindFirstChild("SeatWeld") end
564 end
565 else
566 -- put a weld called "SeatWeld" in every seat
567 -- this tricks it into thinking there's already someone sitting there, and it won't make you sit XD
568 for i = 1, #seatList do
569 local fakeWeld = Instance.new("Weld")
570 fakeWeld.Name = "SeatWeld"
571 fakeWeld.Parent = seatList[i]
572 end
573 end
574end
575
576
577function UnlockInstances(object)
578
579 if object:IsA("BasePart") then
580 object.Locked = false
581 end
582 for index,child in pairs(object:GetChildren()) do
583 UnlockInstances(child)
584 end
585
586end
587
588
589function getPlayer()
590 return game.Players:GetPlayerFromCharacter(script.Parent.Parent)
591end
592
593function beginInsertAssetStamp(assetName, assetId, image, stampMode)
594 -- trying to stop assets, gone back to Main Stamp Dialog
595 if assetId == 0 then
596 guiScriptIsLoadingSomething = true
597 cancelAssetPlacement()
598 return
599 end
600 -- This call will cause a "wait" until the data comes back
601 -- below we wait a max of 8 seconds before deciding to bail out on loading
602 local root
603 local loader
604 loading = true
605 if useAssetVersionId then
606 loader = coroutine.create(function()
607 root = game:GetService("InsertService"):LoadAssetVersion(assetId)
608 loading = false
609 end)
610 coroutine.resume(loader)
611 else
612 loader = coroutine.create(function()
613 root = game:GetService("InsertService"):LoadAsset(assetId)
614 loading = false
615 end)
616 coroutine.resume(loader)
617 end
618
619 local lastGameTime = 0
620 local totalTime = 0
621 local maxWait = 8
622 while loading and totalTime < maxWait do
623 lastGameTime = tick()
624 wait(1)
625 totalTime = totalTime + tick() - lastGameTime
626 end
627 loading = false
628
629 if totalTime >= maxWait or pressedEsc then
630 Data.Loading.Cancelled = true
631 pressedEsc = false
632 else
633 Data.Loading.Cancelled = false
634 end
635
636
637 if Data.Loading.Cancelled then
638 --The user got bored and wandered off
639 --Just delete the model from the world... a shame we loaded it when they got bored
640 -- 12/28/2010: Putting this inside a pcall (on gametest, first time equipping stamper, this was being called with root=nil.) (Jahr)
641 pcall(function() root:Remove() end)
642 signalInsertComplete("Main")
643 else
644 if root == nil then
645 signalInsertComplete("Main")
646 return
647 end
648
649 if not root:IsA("Model") then
650 signalInsertComplete("Main")
651 return
652 end
653
654 local instances = root:GetChildren()
655 if #instances == 0 then
656 root:Remove()
657 signalInsertComplete("Main")
658 return
659 end
660
661 --Unlock all parts that are inserted, to make sure they are editable
662 UnlockInstances(root)
663
664 --Continue the insert process
665 root.Name = "InsertedObject" .. assetId
666
667 --Examine the contents and decide what it looks like
668 for pos, instance in pairs(instances) do
669 --Single instance objects might be treated special, decals/skyboxes
670 if instance:IsA("Decal") then
671 --Current system here stops after finding one Decal (and gives you Decal tool)
672 --We should do the same (probably)
673 beginInsertDecal(instance)
674 root:Remove()
675
676 Window.Stamp.Frame.Visible = true
677 return
678 elseif instance:IsA("Team") then
679 instance.Parent = game:GetService("Teams")
680 elseif instance:IsA("SpawnLocation") then
681 -- uh.............
682 elseif instance:IsA("HopperBin") then
683 -- Must go into the starterPack, prompt user?
684 elseif instance:IsA("Tool") then
685 -- Ask them if it should go in StarterPack?
686 elseif instance:IsA("Sky") then
687 local lightingService = game:GetService("Lighting")
688 for index,child in pairs(lightingService:GetChildren()) do
689 if child:IsA("Sky") then
690 child:Remove();
691 end
692 end
693 instance.Parent = lightingService
694 return
695 else
696
697 end
698 end
699
700 if #root:GetChildren() == 0 then
701 root:Remove()
702 signalInsertComplete("Main")
703 return
704 end
705
706 signalInsertComplete("SideDialog")
707
708 cancelAssetPlacement()
709 Data.Stamp.Model = root
710 setupDraggableClone()
711 guiScriptIsLoadingSomething = false
712 end
713
714end
715
716function beginInsertDecal(decal)
717
718 Data.Stamp.DecalSelection = Instance.new("SurfaceSelection")
719 Data.Stamp.DecalSelection.Color = BrickColor.new("Bright orange")
720 Data.Stamp.DecalSelection.archivable = false
721 Data.Stamp.DecalSelection.Parent = getPlayer().PlayerGui
722
723 --Save the decal in our Lua code for later use
724 Data.Stamp.Decal = decal
725 Data.Stamp.Decal.Parent = nil
726
727end
728
729
730-- signal to gui to switch frames
731function signalInsertComplete(type)
732
733 if type == "SideDialog" then
734 variables.SwitchLoaderToDialog.DialogType.Value = "SideDialog"
735 variables.SwitchLoaderToDialog.Value = true
736 elseif type == "Main" then
737 variables.SwitchLoaderToDialog.DialogType.Value = "Main"
738 variables.SwitchLoaderToDialog.Value = true
739 elseif type == "EyeDropper" then
740 variables.SwitchLoaderToDialog.DialogType.Value = "EyeDropper"
741 variables.SwitchLoaderToDialog.Value = true
742 end
743
744 -- needed to make sure we disconnect eyedroper handler
745 if type ~= "EyeDropper" then
746 if eyeDropperConnection then
747 eyeDropperConnection:disconnect()
748 eyeDropperConnection = nil
749 end
750 if eyeDropperMoveConnection then eyeDropperMoveConnection:disconnect() end
751
752 if Mouse and not mouseButton1UpCon then mouseButton1UpCon = Mouse.Button1Up:connect(onInsertMouseButton1Up) end
753 end
754 clearSelection()
755
756end
757
758
759function p(assetName, assetId, image, stampMode)
760 -- trying to stop assets, gone back to Main Stamp Dialog
761 if assetId == 0 then
762 cancelAssetPlacement()
763 return
764 end
765
766 -- This call will cause a "wait" until the data comes back
767 -- below we wait a max of 8 seconds before deciding to bail out on loading
768 local root
769 local loader
770 loading = true
771 if useAssetVersionId then
772 loader = coroutine.create(function()
773 root = game:GetService("InsertService"):LoadAssetVersion(assetId)
774 loading = false
775 end)
776 coroutine.resume(loader)
777 else
778 loader = coroutine.create(function()
779 root = game:GetService("InsertService"):LoadAsset(assetId)
780 loading = false
781 end)
782 coroutine.resume(loader)
783 end
784
785 local lastGameTime = 0
786 local totalTime = 0
787 local maxWait = 8
788 while loading and totalTime < maxWait do
789 lastGameTime = tick()
790 wait(1)
791 totalTime = totalTime + tick() - lastGameTime
792 end
793 loading = false
794
795 if totalTime >= maxWait or pressedEsc then
796 Data.Loading.Cancelled = true
797 pressedEsc = false
798 else
799 Data.Loading.Cancelled = false
800 end
801
802
803 if Data.Loading.Cancelled then
804 --The user got bored and wandered off
805 --Just delete the model from the world... a shame we loaded it when they got bored
806 -- 12/28/2010: Putting this inside a pcall (on gametest, first time equipping stamper, this was being called with root=nil.) (Jahr)
807 pcall(function() root:Remove() end)
808 signalInsertComplete("Main")
809 else
810 local instances = root:GetChildren()
811 if #instances == 0 then
812 root:Remove()
813 signalInsertComplete("Main")
814 return
815 end
816
817 --Unlock all parts that are inserted, to make sure they are editable
818 UnlockInstances(root)
819
820 --Continue the insert process
821 root.Name = "InsertedObject" .. assetId
822
823 --Examine the contents and decide what it looks like
824 for pos, instance in pairs(instances) do
825 --Single instance objects might be treated special, decals/skyboxes
826 if instance:IsA("Decal") then
827 --Current system here stops after finding one Decal (and gives you Decal tool)
828 --We should do the same (probably)
829 beginInsertDecal(instance)
830 root:Remove()
831
832 Window.Stamp.Frame.Visible = true
833 return
834 elseif instance:IsA("Team") then
835 instance.Parent = game:GetService("Teams")
836 elseif instance:IsA("SpawnLocation") then
837 -- uh.............
838 elseif instance:IsA("HopperBin") then
839 -- Must go into the starterPack, prompt user?
840 elseif instance:IsA("Tool") then
841 -- Ask them if it should go in StarterPack?
842 elseif instance:IsA("Sky") then
843 local lightingService = game:GetService("Lighting")
844 for index,child in pairs(lightingService:GetChildren()) do
845 if child:IsA("Sky") then
846 child:Remove();
847 end
848 end
849 instance.Parent = lightingService
850 return
851 else
852
853 end
854 end
855
856 if #root:GetChildren() == 0 then
857 root:Remove()
858 signalInsertComplete("Main")
859 return
860 end
861
862 signalInsertComplete("SideDialog")
863
864 cancelAssetPlacement()
865 Data.Stamp.Model = root
866 setupDraggableClone()
867 end
868
869end
870
871
872function positionPartsAtCFrame3(partOrModel, aCFrame)
873
874 local insertCFrame
875 if Data.Stamp.CurrentParts[1]:IsA("Model") or Data.Stamp.CurrentParts[1]:IsA("Tool") then
876 --insertCFrame = Data.Stamp.CurrentParts[1]:GetChildren()[1].CFrame
877 -- we assume model has at least one part in it; need to find first part
878 i = 1
879 while (i < (#Data.Stamp.CurrentParts[1]:GetChildren()) and not Data.Stamp.CurrentParts[1]:GetChildren()[i]:IsA("Part") and not Data.Stamp.CurrentParts[1]:GetChildren()[i]:IsA("TrussPart") and not Data.Stamp.CurrentParts[1]:GetChildren()[i]:IsA("WedgePart")) do
880 i = i + 1
881 end
882 insertCFrame = Data.Stamp.CurrentParts[1]:GetChildren()[i].CFrame
883
884 for i, object in pairs(Data.Stamp.CurrentParts[1]:GetChildren()) do
885 if object:IsA("Flag") then object = object.Handle end
886 if (object:IsA("Part") or object:IsA("WedgePart") or object:IsA("TrussPart") or object:IsA("Seat") or object:IsA("VehicleSeat")) then
887 local posPartInWorld = object.Position
888 local posPart1InWorld = insertCFrame.p
889 local newPosPartInWorld = posPartInWorld - posPart1InWorld + aCFrame.p
890
891 local x, y, z, R00, R01, R02, R10, R11, R12, R20, R21, R22 = object.CFrame:components()
892 object.CFrame = CFrame.new(newPosPartInWorld.x, newPosPartInWorld.y, newPosPartInWorld.z, R00, R01, R02, R10, R11, R12, R20, R21, R22)
893 end
894 end
895 else
896 Data.Stamp.CurrentParts[1].CFrame = aCFrame
897 end
898
899end
900
901
902-- For Restricting Stamper Tool (isRestricted)
903function inBounds(object)
904
905 for part, transparency in pairs(object) do
906 if part:IsA("Part") or part:IsA("WedgePart") or part:IsA("TrussPart") then
907 if not partInBounds(part) then return false end
908 elseif part:IsA("Model") then
909 local primPart = object.PrimaryPart
910 if not partInBounds(primPart) then return false end
911 end
912 end
913 return true
914
915end
916
917function partInBounds(part)
918
919 if part == nil then return false end
920
921 local xOne= buildingPlate.Position.x + buildingPlate.Size.x/2
922 local xTwo = buildingPlate.Position.x - buildingPlate.Size.x/2
923 local zOne = buildingPlate.Position.z + buildingPlate.Size.z/2
924 local zTwo = buildingPlate.Position.z - buildingPlate.Size.z/2
925
926 if part.Position.x > xOne or part.Position.x < xTwo then return false end
927 if part.Position.z > zOne or part.Position.z < zTwo then return false end
928
929 return true
930
931end
932
933
934
935function canSelectObject(part)
936 return part and not (part.Locked) and part:IsA("BasePart") and (part.Position - Tool.Parent.Head.Position).Magnitude < 60
937end
938
939function canEyeDropperObject(part)
940 local stamperTag = part.Parent:FindFirstChild("RobloxStamper")
941 if stamperTag == nil then stamperTag = part:FindFirstChild("RobloxStamper") end
942
943 return part and not (part.Locked) and part:IsA("BasePart") and (part.Position - Tool.Parent.Head.Position).Magnitude < 60 and stamperTag ~= nil
944end
945
946function isOnGrid(partOrModel)
947 -- first check to see if off-grid, and if so, prevent eyedropperage
948 local modelExtentsInWorldCoords
949 if partOrModel:IsA("Model") then
950 modelExtentsInWorldCoords = partOrModel:GetModelCFrame():vectorToWorldSpace(partOrModel:GetModelSize())
951 else
952 modelExtentsInWorldCoords = partOrModel.CFrame:vectorToWorldSpace(partOrModel.Size)
953 end
954
955 -- we now simply check to see if the above property fits in a 4x4x4 gridspace
956 offX = math.fmod(math.abs(modelExtentsInWorldCoords.X), 4)
957 offY = math.fmod(math.abs(modelExtentsInWorldCoords.Y), 4)
958 offZ = math.fmod(math.abs(modelExtentsInWorldCoords.Z), 4)
959
960 local numberOfAxesOffGrid = 0
961 if math.min(offX, 4 - offX) > eyedropperOffGridTolerance then numberOfAxesOffGrid = numberOfAxesOffGrid + 1 end
962 if math.min(offY, 4 - offY) > eyedropperOffGridTolerance then numberOfAxesOffGrid = numberOfAxesOffGrid + 1 end
963 if math.min(offZ, 4 - offZ) > eyedropperOffGridTolerance then numberOfAxesOffGrid = numberOfAxesOffGrid + 1 end
964
965 if numberOfAxesOffGrid > 1 then return false -- we allow one axis to be not fit to grid, since any rotation must necessarily affect >= 2 axes (some of the models are like 4x4x6 :( ).
966 else return true end
967end
968
969
970--[[
971function canDeleteObject(part)
972 -- let them delete anything that they created *or* anything on their baseplate
973 return part and not (part.Locked) and part:IsA("BasePart") and (part.Position - Tool.Parent.Head.Position).Magnitude < 60 and (isChildOfMyModel(part) or partInBounds(part))
974end]]
975
976-- below is a helper function to help get the model surface instead of the part surface [for allowing a side to elect out of making joints automatically]
977function calcRayHitTime(rayStart, raySlope, intersectionPlane)
978 if math.abs(raySlope) < .01 then return 0 end -- 0 slope --> we just say intersection time is 0, and sidestep this dimension
979 -- rayStart + t*raySlope = intersectionPlane, so t = (intersectionPlane - rayStart) / raySlope
980 return (intersectionPlane - rayStart) / raySlope
981end
982
983
984function modelTargetSurface(partOrModel, rayStart, rayEnd)
985 if not partOrModel then
986 return 0
987 end
988
989 local modelCFrame = nil
990 local modelSize = nil
991 if partOrModel:IsA("Model") then
992 modelCFrame = partOrModel:GetModelCFrame()
993 modelSize = partOrModel:GetModelSize()
994 else
995 modelCFrame = partOrModel.CFrame
996 modelSize = partOrModel.Size
997 end
998
999 --local mouseRayStart = modelCFrame:pointToObjectSpace(game.Workspace.CurrentCamera.CoordinateFrame.p)
1000 --local mouseRayEnd = modelCFrame:pointToObjectSpace(Mouse.Hit.p)
1001 local mouseRayStart = modelCFrame:pointToObjectSpace(rayStart)
1002 local mouseRayEnd = modelCFrame:pointToObjectSpace(rayEnd)
1003 local mouseSlope = mouseRayEnd - mouseRayStart
1004
1005 local xPositive = 1
1006 local yPositive = 1
1007 local zPositive = 1
1008 if mouseSlope.X > 0 then xPositive = -1 end
1009 if mouseSlope.Y > 0 then yPositive = -1 end
1010 if mouseSlope.Z > 0 then zPositive = -1 end
1011
1012 -- find which surface the transformed mouse ray hits (using modelSize):
1013 local xHitTime = calcRayHitTime(mouseRayStart.X, mouseSlope.X, modelSize.X/2 * xPositive)
1014 local yHitTime = calcRayHitTime(mouseRayStart.Y, mouseSlope.Y, modelSize.Y/2 * yPositive)
1015 local zHitTime = calcRayHitTime(mouseRayStart.Z, mouseSlope.Z, modelSize.Z/2 * zPositive)
1016
1017 local hitFace = 0
1018
1019 --if xHitTime >= 0 and yHitTime >= 0 and zHitTime >= 0 then
1020 if xHitTime > yHitTime then
1021 if xHitTime > zHitTime then
1022 -- xFace is hit
1023 hitFace = 1*xPositive
1024 else
1025 -- zFace is hit
1026 hitFace = 3*zPositive
1027 end
1028 else
1029 if yHitTime > zHitTime then
1030 -- yFace is hit
1031 hitFace = 2*yPositive
1032 else
1033 -- zFace is hit
1034 hitFace = 3*zPositive
1035 end
1036 end
1037
1038 return hitFace
1039end
1040
1041
1042function onInsertMouseMove()
1043
1044 if Data.Stamp.MovingLock then
1045 return
1046 end
1047
1048 if isRestricted then
1049 Mouse.TargetFilter = game.Workspace.BaseplateBumpers
1050 end
1051
1052 Data.Stamp.MovingLock = true
1053 if Data.Stamp.Dragger == nil then
1054 if Data.Stamp.Model ~= nil then
1055 if isRestricted then
1056 if checkPartLimit() then
1057 setupDraggableClone()
1058 else
1059 variables.ShowMaxedOut.Value = true
1060 end
1061 else
1062 setupDraggableClone()
1063 end
1064 end
1065 else
1066 -- REM TL: Data.Stamp.Dragger:MouseMove(Mouse.UnitRay)
1067 -- don't move with dragger - will move in one step on mouse down
1068 -- draw ghost at acceptable positions
1069 configFound, targetCFrame, targetSurface = findConfigAtMouseTarget(Data.Stamp.TransparencyTable)
1070 if configFound then
1071
1072 if autoAlignToFace() and targetSurface ~= 1 and targetSurface ~= 4 then
1073 -- pre-rotate the flag or portrait so it's aligned correctly
1074 --local currCFrame
1075 --if Data.Stamp.CurrentParts[1]:IsA("Model") or Data.Stamp.CurrentParts[1]:IsA("Tool") then currCFrame = Data.Stamp.CurrentParts[1]:GetModelCFrame()
1076 --else currCFrame = Data.Stamp.CurrentParts[1].CFrame end
1077
1078 local numRotations = 0 -- update this according to how many rotations you need to get it to target surface
1079 if targetSurface == 3 then numRotations = 0 - gInitial90DegreeRotations + autoAlignToFace()
1080 elseif targetSurface == 0 then numRotations = 2 - gInitial90DegreeRotations + autoAlignToFace()
1081 elseif targetSurface == 5 then numRotations = 3 - gInitial90DegreeRotations + autoAlignToFace()
1082 elseif targetSurface == 2 then numRotations = 1 - gInitial90DegreeRotations + autoAlignToFace() end
1083
1084
1085 local ry = math.pi/2
1086 local rotCF = CFrame.fromEulerAnglesXYZ(0, ry*numRotations, 0)
1087 gInitial90DegreeRotations = gInitial90DegreeRotations + numRotations
1088 if Data.Stamp.CurrentParts[1]:IsA("Model") or Data.Stamp.CurrentParts[1]:IsA("Tool") then
1089 for i, object in pairs(Data.Stamp.CurrentParts[1]:GetChildren()) do
1090 if object:IsA("Flag") then object = object.Handle end
1091 if object:IsA("Part") or object:IsA("TrussPart") or object:IsA("WedgePart") or object:IsA("Seat") or object:IsA("VehicleSeat") then
1092 object.CFrame = rotCF * object.CFrame
1093 end
1094 end
1095 else
1096 Data.Stamp.CurrentParts[1].CFrame = rotCF * Data.Stamp.CurrentParts[1].CFrame
1097 end
1098 end
1099
1100 positionPartsAtCFrame3(Data.Stamp.CurrentParts[1], targetCFrame)
1101
1102 -- auto break joints code
1103 if Mouse.Target and Mouse.Target.Parent then
1104 local modelInfo = Mouse.Target:FindFirstChild("RobloxModel")
1105 if not modelInfo then modelInfo = Mouse.Target.Parent:FindFirstChild("RobloxModel") end
1106
1107 local myModelInfo = Data.Stamp.CurrentParts[1]:FindFirstChild("UnstampableFaces")
1108
1109 --if (modelInfo and modelInfo.Parent:FindFirstChild("UnstampableFaces")) or (modelInfo and myModelInfo) then -- need better targetSurface calcs
1110 if (true) then
1111 local breakingFaces = ""
1112 local myBreakingFaces = ""
1113 if modelInfo and modelInfo.Parent:FindFirstChild("UnstampableFaces") then breakingFaces = modelInfo.Parent.UnstampableFaces.Value end
1114 if myModelInfo then myBreakingFaces = myModelInfo.Value end
1115 local hitFace = 0
1116
1117 if modelInfo then hitFace = modelTargetSurface(modelInfo.Parent, game.Workspace.CurrentCamera.CoordinateFrame.p, Mouse.Hit.p) end
1118
1119 -- are we stamping TO an unstampable surface?
1120 for bf in string.gmatch(breakingFaces, "[^,]+") do
1121 if hitFace == tonumber(bf) then
1122 -- return before we hit the JointsService code below!
1123 unstampableSurface = true
1124 game.JointsService:ClearJoinAfterMoveJoints() -- clear the JointsService cache
1125 Data.Stamp.MovingLock = false
1126 return
1127 end
1128 end
1129
1130 -- now we have to cast the ray back in the other direction to find the surface we're stamping FROM
1131 hitFace = modelTargetSurface(Data.Stamp.CurrentParts[1], Mouse.Hit.p, game.Workspace.CurrentCamera.CoordinateFrame.p)
1132
1133 -- are we stamping WITH an unstampable surface?
1134 for bf in string.gmatch(myBreakingFaces, "[^,]+") do
1135 if hitFace == tonumber(bf) then
1136 unstampableSurface = true
1137 game.JointsService:ClearJoinAfterMoveJoints() -- clear the JointsService cache
1138 Data.Stamp.MovingLock = false
1139 return
1140 end
1141 end
1142
1143 -- just need to match breakingFace against targetSurface using rotation supplied by modelCFrame
1144 -- targetSurface: 1 is top, 4 is bottom,
1145 end
1146 end
1147
1148
1149 end
1150
1151 -- to show joints during the mouse move
1152 unstampableSurface = false
1153 game.JointsService:SetJoinAfterMoveInstance(Data.Stamp.CurrentParts[1])
1154 if Mouse.Target and Mouse.Target.Parent:FindFirstChild("RobloxModel") == nil then
1155 game.JointsService:SetJoinAfterMoveTarget(Mouse.Target)
1156 else
1157 game.JointsService:SetJoinAfterMoveTarget(nil)
1158 end
1159 game.JointsService:ShowPermissibleJoints()
1160 end
1161
1162 Data.Stamp.MovingLock = false
1163
1164end
1165
1166
1167function onInsertMouseButton1Down()
1168
1169 if Data.Stamp.Dragger or Data.Stamp.Decal then
1170 Data.Stamp.MouseDown = true
1171 end
1172
1173end
1174
1175
1176function cancelAssetPlacement()
1177
1178 gInitial90DegreeRotations = 0
1179 Data.Stamp.Cancelled = true
1180
1181 if Data.Stamp["Model"] then
1182 Data.Stamp.Model.Parent = nil
1183 end
1184
1185 if Data.Stamp.CurrentParts then
1186 for index, object in pairs(Data.Stamp.CurrentParts) do
1187 object.Parent = nil
1188 end
1189
1190 Data.Stamp.CurrentParts.Parent = nil
1191 end
1192
1193 if Data.Stamp.DecalSelection then
1194 Data.Stamp.DecalSelection:Remove()
1195 Data.Stamp.DecalSelection = nil
1196 end
1197 if Data.Stamp.Decal then
1198 Data.Stamp.Decal:Remove()
1199 Data.Stamp.Decal = nil
1200 end
1201
1202 if Mouse then
1203 Mouse.Icon ="rbxasset://textures\\ArrowCursor.png"
1204 end
1205 game.JointsService:ClearJoinAfterMoveJoints()
1206
1207end
1208
1209
1210function collectParts(object, baseParts, scripts, decals)
1211
1212 if object:IsA("BasePart") then
1213 baseParts[#baseParts+1] = object
1214 elseif object:IsA("Script") then
1215 scripts[#scripts+1] = object
1216 elseif object:IsA("Decal") then
1217 decals[#decals+1] = object
1218 end
1219
1220 for index,child in pairs(object:GetChildren()) do
1221 collectParts(child, baseParts, scripts, decals)
1222 end
1223
1224end
1225
1226function getTargetPartBoundingBox(targetPart)
1227
1228 if targetPart.Parent:FindFirstChild("RobloxModel") ~= nil then
1229 return getBoundingBox2(targetPart.Parent)
1230 else
1231 return getBoundingBox2(targetPart)
1232 end
1233
1234end
1235
1236
1237function getBoundingBox2(partOrModel)
1238
1239-- for models, the bounding box is defined as the minimum and maximum individual part bounding boxes
1240-- relative to the first part's coordinate frame.
1241
1242 local minVec = Vector3.new(math.huge, math.huge, math.huge)
1243 local maxVec = Vector3.new(-math.huge, -math.huge, -math.huge)
1244
1245 if partOrModel:IsA("Part") or partOrModel:IsA("WedgePart") or partOrModel:IsA("TrussPart")then
1246 minVec = -0.5 * partOrModel.Size
1247 maxVec = -minVec
1248 else
1249 local part1 = partOrModel:GetChildren()[1]
1250 if partOrModel:IsA("Tool") then part1 = partOrModel.Handle if not part1 then return end end
1251 if part1:IsA("Flag") then part1 = partOrModel:FindFirstChild("Part") if not part1 then return end end
1252 for i, object in pairs(partOrModel:GetChildren()) do
1253 if (object:IsA("Part") or object:IsA("WedgePart") or object:IsA("TrussPart")) then
1254 boxMinInWorld = object.CFrame:pointToWorldSpace(-0.5 * object.Size)
1255 boxMinInPart1 = part1.CFrame:pointToObjectSpace(boxMinInWorld)
1256 boxMaxInWorld = object.CFrame:pointToWorldSpace(0.5 * object.Size)
1257 boxMaxInPart1 = part1.CFrame:pointToObjectSpace(boxMaxInWorld)
1258
1259 local minX = minVec.x
1260 local minY = minVec.y
1261 local minZ = minVec.z
1262 local maxX = maxVec.x
1263 local maxY = maxVec.y
1264 local maxZ = maxVec.z
1265 if boxMinInPart1.x < minVec.x then
1266 minX = boxMinInPart1.x
1267 end
1268 if boxMinInPart1.y < minVec.y then
1269 minY = boxMinInPart1.y
1270 end
1271 if boxMinInPart1.z < minVec.z then
1272 minZ = boxMinInPart1.z
1273 end
1274 if boxMaxInPart1.x < minX then
1275 minX = boxMaxInPart1.x
1276 end
1277 if boxMaxInPart1.y < minY then
1278 minY = boxMaxInPart1.y
1279 end
1280 if boxMaxInPart1.z < minZ then
1281 minZ = boxMaxInPart1.z
1282 end
1283
1284 if boxMinInPart1.x > maxVec.x then
1285 maxX = boxMinInPart1.x
1286 end
1287 if boxMinInPart1.y > maxVec.y then
1288 maxY = boxMinInPart1.y
1289 end
1290 if boxMinInPart1.z > maxVec.z then
1291 maxZ = boxMinInPart1.z
1292 end
1293 if boxMaxInPart1.x > maxX then
1294 maxX = boxMaxInPart1.x
1295 end
1296 if boxMaxInPart1.y > maxY then
1297 maxY = boxMaxInPart1.y
1298 end
1299 if boxMaxInPart1.z > maxZ then
1300 maxZ = boxMaxInPart1.z
1301 end
1302
1303 minVec = Vector3.new(minX, minY, minZ)
1304 maxVec = Vector3.new(maxX, maxY, maxZ)
1305 end
1306 end
1307 end
1308
1309 -- Adjust bounding box to reflect what the model or part author wants in terms of justification
1310 local justifyValue = partOrModel:FindFirstChild("Justification")
1311 if justifyValue ~= nil then
1312 -- find the multiple of 4 that contains the model
1313 justify = justifyValue.Value
1314 two = Vector3.new(2, 2, 2)
1315 actualBox = maxVec - minVec - Vector3.new(0.01, 0.01, 0.01)
1316 containingGridBox = Vector3.new(4 * math.ceil(actualBox.x/4), 4 * math.ceil(actualBox.y/4), 4 * math.ceil(actualBox.z/4))
1317 adjustment = containingGridBox - actualBox
1318 minVec = minVec - 0.5 * adjustment * justify
1319 maxVec = maxVec + 0.5 * adjustment * (two - justify)
1320 end
1321
1322 return minVec, maxVec
1323
1324end
1325
1326
1327function getClosestAlignedWorldDirection(aVector3InWorld)
1328
1329 local xDir = Vector3.new(1,0,0)
1330 local yDir = Vector3.new(0,1,0)
1331 local zDir = Vector3.new(0,0,1)
1332 local xDot = aVector3InWorld.x * xDir.x + aVector3InWorld.y * xDir.y + aVector3InWorld.z * xDir.z
1333 local yDot = aVector3InWorld.x * yDir.x + aVector3InWorld.y * yDir.y + aVector3InWorld.z * yDir.z
1334 local zDot = aVector3InWorld.x * zDir.x + aVector3InWorld.y * zDir.y + aVector3InWorld.z * zDir.z
1335
1336 if math.abs(xDot) > math.abs(yDot) and math.abs(xDot) > math.abs(zDot) then
1337 if xDot > 0 then
1338 return 0
1339 else
1340 return 3
1341 end
1342 elseif math.abs(yDot) > math.abs(xDot) and math.abs(yDot) > math.abs(zDot) then
1343 if yDot > 0 then
1344 return 1
1345 else
1346 return 4
1347 end
1348 else
1349 if zDot > 0 then
1350 return 2
1351 else
1352 return 5
1353 end
1354 end
1355
1356end
1357
1358
1359function getMouseTargetCFrame(targetPart)
1360
1361 if targetPart.Parent:FindFirstChild("RobloxModel") ~= nil then
1362 if targetPart.Parent:IsA("Tool") then return targetPart.Parent.Handle.CFrame
1363 else return targetPart.Parent:GetChildren()[1].CFrame end
1364 else
1365 return targetPart.CFrame
1366 end
1367
1368end
1369
1370
1371function surfaceToVector(surf)
1372 local vect = 1
1373 if surf < 0 then
1374 surf = surf * -1
1375 vect = vect * -1
1376 end
1377 if surf == 1 then return vect*Vector3.new(1, 0, 0)
1378 elseif surf == 2 then return vect*Vector3.new(0, 1, 0)
1379 elseif surf == 3 then return vect*Vector3.new(0, 0, 1)
1380 else return Vector3.FromNormalId(Mouse.TargetSurface) end -- if we somehow got a "0", then we just revert to old behavior
1381end
1382
1383function findConfigAtMouseTarget(partsTable)
1384
1385-- *Critical Assumption* :
1386-- This function assumes the target CF axes are orthogonal with the target bounding box faces
1387-- And, it assumes the insert CF axes are orthongonal with the insert bounding box faces
1388-- Therefore, insertion will not work with angled faces on wedges or other "non-block" parts, nor
1389-- will it work for parts in a model that are not orthogonally aligned with the model's CF.
1390
1391 local grid = 4.0
1392 local admissibleConfig = false
1393 local targetConfig = CFrame.new(0,0,0)
1394
1395 local minBB, maxBB = getBoundingBox2(Data.Stamp.CurrentParts[1])
1396 local diagBB = maxBB - minBB
1397
1398 local insertCFrame
1399 if Data.Stamp.CurrentParts[1]:IsA("Model") or Data.Stamp.CurrentParts[1]:IsA("Tool") then
1400 i = 1
1401 while (i < (#Data.Stamp.CurrentParts[1]:GetChildren()) and not Data.Stamp.CurrentParts[1]:GetChildren()[i]:IsA("Part") and not Data.Stamp.CurrentParts[1]:GetChildren()[i]:IsA("TrussPart") and not Data.Stamp.CurrentParts[1]:GetChildren()[i]:IsA("WedgePart")) do
1402 i = i + 1
1403 end
1404 insertCFrame = Data.Stamp.CurrentParts[1]:GetChildren()[i].CFrame
1405 else
1406 insertCFrame = Data.Stamp.CurrentParts[1].CFrame
1407 end
1408
1409 if not isRestricted then
1410 if Data.Stamp.CurrentParts[1]:IsA("Tool") then Mouse.TargetFilter = Data.Stamp.CurrentParts[1].Handle
1411 else Mouse.TargetFilter = Data.Stamp.CurrentParts[1] end
1412 end
1413
1414 local targetPart = nil
1415 local success = pcall(function() targetPart = Mouse.Target end)
1416
1417 if not success or targetPart == nil then
1418 return admissibleConfig, targetConfig
1419 end
1420
1421 -- test mouse hit location
1422 local minBBTarget, maxBBTarget = getTargetPartBoundingBox(targetPart)
1423 local diagBBTarget = maxBBTarget - minBBTarget
1424 local targetCFrame = getMouseTargetCFrame(targetPart)
1425 local hitCFrame = Mouse.Hit
1426 local mouseHitInWorld = hitCFrame.p
1427 local mouseHitInTarget = targetCFrame:pointToObjectSpace(mouseHitInWorld)
1428
1429 -- find which axis of the insertion objects should match with the target surface
1430 -- this should use targetPart CFrame, not the model CFrame
1431
1432 --[[ attempt at fixing Mouse.TargetSurface below...
1433 local targetModel = targetPart
1434 if not targetPart:FindFirstChild("RobloxModel") and targetPart.Parent and targetPart.Parent:FindFirstChild("RobloxModel") then targetModel = targetPart.Parent end
1435 local correctedTargetSurfaceVector = surfaceToVector(modelTargetSurface(targetModel, game.Workspace.CurrentCamera.CoordinateFrame.p, mouseHitInWorld))
1436 local targetVectorInWorld = targetPart.CFrame:vectorToWorldSpace(correctedTargetSurfaceVector)
1437 --]]
1438 local targetVectorInWorld = targetPart.CFrame:vectorToWorldSpace(Vector3.FromNormalId(Mouse.TargetSurface))
1439
1440 local targetRefPointInTarget
1441 local clampToSurface
1442
1443 if getClosestAlignedWorldDirection(targetVectorInWorld) == 0 then
1444 targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(1, -1, 1))
1445 insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(-1, -1, 1))
1446 clampToSurface = Vector3.new(0,1,1)
1447 elseif getClosestAlignedWorldDirection(targetVectorInWorld) == 3 then
1448 targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(-1, -1, -1))
1449 insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(1, -1, -1))
1450 clampToSurface = Vector3.new(0,1,1)
1451 elseif getClosestAlignedWorldDirection(targetVectorInWorld) == 1 then
1452 targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(-1, 1, 1))
1453 insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(-1, -1, 1))
1454 clampToSurface = Vector3.new(1,0,1)
1455 elseif getClosestAlignedWorldDirection(targetVectorInWorld) == 4 then
1456 targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(-1, -1, 1))
1457 insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(-1, 1, 1))
1458 clampToSurface = Vector3.new(1,0,1)
1459 elseif getClosestAlignedWorldDirection(targetVectorInWorld) == 2 then
1460 targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(-1, -1, 1))
1461 insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(-1, -1, -1))
1462 clampToSurface = Vector3.new(1,1,0)
1463 else
1464 targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(1, -1, -1))
1465 insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(1, -1, 1))
1466 clampToSurface = Vector3.new(1,1,0)
1467 end
1468
1469 targetRefPointInTarget = targetRefPointInTarget * (0.5 * diagBBTarget) + 0.5 * (maxBBTarget + minBBTarget)
1470 insertRefPointInInsert = insertRefPointInInsert * (0.5 * diagBB) + 0.5 * (maxBB + minBB)
1471
1472 -- To Do: For cases that are not aligned to the world grid, account for the minimal rotation
1473 -- needed to bring the Insert part(s) into alignment with the Target Part
1474 -- Apply the rotation here
1475
1476 local delta = mouseHitInTarget - targetRefPointInTarget
1477 local deltaClamped = Vector3.new(grid * math.modf(delta.x/grid), grid * math.modf(delta.y/grid), grid * math.modf(delta.z/grid))
1478 deltaClamped = deltaClamped * clampToSurface
1479 local targetTouchInTarget = deltaClamped + targetRefPointInTarget
1480
1481 local TargetTouchRelToWorld = targetCFrame:pointToWorldSpace(targetTouchInTarget)
1482 local InsertTouchInWorld = insertCFrame:vectorToWorldSpace(insertRefPointInInsert)
1483 local posInsertOriginInWorld = TargetTouchRelToWorld - InsertTouchInWorld
1484
1485 local x, y, z, R00, R01, R02, R10, R11, R12, R20, R21, R22 = insertCFrame:components()
1486 targetConfig = CFrame.new(posInsertOriginInWorld.x, posInsertOriginInWorld.y, posInsertOriginInWorld.z, R00, R01, R02, R10, R11, R12, R20, R21, R22)
1487 admissibleConfig = true
1488
1489 return admissibleConfig, targetConfig, getClosestAlignedWorldDirection(targetVectorInWorld)
1490
1491end
1492
1493function checkPartLimit()
1494
1495 local numPoints = player.PointsUsed.Value
1496 local maxPoints = player.MaxPoints.Value
1497
1498 if numPoints < maxPoints then
1499 return true
1500 else
1501 return false
1502 end
1503
1504 return true
1505end
1506
1507function setupDraggableClone()
1508 if eyeDropperConnection then eyeDropperConnection:disconnect() eyeDropperConnection = nil end
1509
1510 --if not Mouse.Target then return end
1511 click.Value = false
1512
1513 if Data.Stamp.CurrentParts then
1514 for i = 1, #Data.Stamp.CurrentParts do
1515 if Data.Stamp.CurrentParts[i].Parent ~= nil then
1516 Data.Stamp.CurrentParts[i].Parent = partModel
1517 end
1518 end
1519 end
1520
1521 if Data.Stamp["Model"] == nil then return end
1522
1523 local clone = Data.Stamp.Model:Clone()
1524 local scripts = {}
1525 local parts = {}
1526 local decals = {}
1527
1528 collectParts(clone, parts, scripts, decals)
1529
1530 if #parts > 0 then
1531 Data.Stamp.DisabledScripts = {}
1532 Data.Stamp.TransparencyTable = {}
1533 Data.Stamp.MaterialTable = {}
1534 Data.Stamp.CanCollideTable = {}
1535 Data.Stamp.AnchoredTable = {}
1536 Data.Stamp.DecalTransparencyTable = {}
1537
1538 for index,script in pairs(scripts) do
1539 if not(script.Disabled) then
1540 script.Disabled = true
1541 Data.Stamp.DisabledScripts[#Data.Stamp.DisabledScripts +1] = script
1542 end
1543 end
1544 for index, part in pairs(parts) do
1545 Data.Stamp.TransparencyTable[part] = part.Transparency
1546 part.Transparency = gStaticTrans + (1-gStaticTrans)*part.Transparency
1547 Data.Stamp.MaterialTable[part] = part.Material
1548 part.Material = Enum.Material.Plastic
1549 Data.Stamp.CanCollideTable[part] = part.CanCollide
1550 part.CanCollide = false
1551 Data.Stamp.AnchoredTable[part] = part.Anchored
1552 part.Anchored = true
1553 part.archivable = false
1554
1555 delay(0,function()
1556 local con = nil
1557 local exitLoop = false
1558 con = click.Changed:connect(function()
1559 if click.Value then
1560 con:disconnect()
1561 exitLoop = true
1562 end
1563 end)
1564 wait(fadeInDelayTime) -- give it some time to be completely transparent
1565
1566 if exitLoop then return end -- if we already stamped, we don't need to do the rest of this
1567
1568 local begTime = tick()
1569 local currTime = begTime
1570 while (currTime - begTime) < transFadeInTime and part and part:IsA("BasePart") and part.Transparency > gDesiredTrans and not exitLoop do
1571 part.Transparency = 1 - (((currTime - begTime)/transFadeInTime) * (gStaticTrans - gDesiredTrans))
1572 wait(0.03)
1573 currTime = tick()
1574 end
1575 if part and part:IsA("BasePart") and not exitLoop then
1576 part.Transparency = gDesiredTrans
1577 end
1578 if con then con:disconnect() end
1579 end)
1580 end
1581
1582 for index, decal in pairs(decals) do
1583 Data.Stamp.DecalTransparencyTable[decal] = decal.Transparency
1584 decal.Transparency = gStaticTrans + (1-gStaticTrans)*decal.Transparency
1585 end
1586
1587 clone.Parent = game.Workspace
1588
1589 -- For Restricting Stamper Tool
1590 if(isRestricted) then
1591
1592 -- mark a particular spot in BaseplateBumpers, so we can remove any stragglers later, when player leaves
1593 local cloneInsertionSpot = game.Workspace.BaseplateBumpers:FindFirstChild(player.Name)
1594 if cloneInsertionSpot == nil then
1595 cloneInsertionSpot = Instance.new("Model")
1596 cloneInsertionSpot.Name = player.Name
1597 cloneInsertionSpot.Parent = game.Workspace.BaseplateBumpers
1598 end
1599
1600 clone.Parent = cloneInsertionSpot
1601 end
1602
1603 -- disable all seats
1604 setSeatEnabledStatus(clone, true)
1605 setSeatEnabledStatus(clone, false)
1606
1607 Data.Stamp.CurrentParts = clone:GetChildren()
1608
1609 -- if auto-alignable, we enforce a pre-rotation to the canonical "0-frame"
1610 if autoAlignToFace() then
1611 modelInverse = Data.Stamp.CurrentParts[1]:GetModelCFrame():inverse()
1612 for i, object in pairs(Data.Stamp.CurrentParts[1]:GetChildren()) do
1613 if object:IsA("Flag") then object = object.Handle end
1614 if object:IsA("Part") or object:IsA("TrussPart") or object:IsA("WedgePart") or object:IsA("Seat") or object:IsA("VehicleSeat") then object.CFrame = modelInverse*object.CFrame end
1615 end
1616 gInitial90DegreeRotations = autoAlignToFace()
1617 else
1618
1619 -- pre-rotate if necessary
1620 local ry = gInitial90DegreeRotations * math.pi/2
1621 local rotCF = CFrame.fromEulerAnglesXYZ(0, ry, 0)
1622 if Data.Stamp.CurrentParts[1]:IsA("Model") or Data.Stamp.CurrentParts[1]:IsA("Tool") then
1623 for i, object in pairs(Data.Stamp.CurrentParts[1]:GetChildren()) do
1624 if object:IsA("Flag") then object = object.Handle end
1625 if object:IsA("Part") or object:IsA("TrussPart") or object:IsA("WedgePart") or object:IsA("Seat") or object:IsA("VehicleSeat") then object.CFrame = rotCF * object.CFrame end
1626 end
1627 else
1628 Data.Stamp.CurrentParts[1].CFrame = rotCF * Data.Stamp.CurrentParts[1].CFrame
1629 end
1630 end
1631
1632 -- After rotating, update the position
1633 configFound, targetCFrame = findConfigAtMouseTarget(Data.Stamp.TransparencyTable)
1634 if configFound then
1635 positionPartsAtCFrame3(Data.Stamp.TransparencyTable, targetCFrame)
1636 end
1637 -- to show joints during the mouse move
1638 game.JointsService:SetJoinAfterMoveInstance(Data.Stamp.CurrentParts[1])
1639
1640 local mouseTarget = nil
1641 pcall(function() mouseTarget = Mouse.Target end)
1642
1643 if mouseTarget and mouseTarget.Parent:FindFirstChild("RobloxModel") == nil then
1644 game.JointsService:SetJoinAfterMoveTarget(mouseTarget)
1645 else
1646 game.JointsService:SetJoinAfterMoveTarget(nil)
1647 end
1648 game.JointsService:ShowPermissibleJoints()
1649
1650 for index, object in pairs(Data.Stamp.CurrentParts) do
1651 object.Parent = clone.Parent
1652 end
1653 clone:Remove()
1654
1655 Data.Stamp.Dragger = Instance.new("Dragger")
1656 --Begin a movement by faking a MouseDown signal
1657 Data.Stamp.Dragger:MouseDown(parts[1], Vector3.new(0,0,0), parts)
1658 Data.Stamp.Dragger:MouseUp()
1659 else
1660 --Nothing draggable in the Model
1661 Data.Stamp.Model:Remove()
1662 Data.Stamp.Model = nil
1663 Data.Stamp.TransparencyTable = nil
1664 Data.Stamp.MaterialTable = nil
1665 Data.Stamp.CanCollideTable = nil
1666 Data.Stamp.AnchoredTable = nil
1667 Data.Stamp.DisabledScripts = nil
1668 end
1669
1670end
1671
1672
1673function noManualWelds(part)
1674 local partChildren = part:GetChildren()
1675 for i = 1, #partChildren do
1676 if partChildren[i]:IsA("ManualWeld") then
1677 return false
1678 end
1679 end
1680 return true
1681end
1682
1683local debris = game:GetService("Debris")
1684function flashRedBox()
1685 errorBox.Parent = player.PlayerGui
1686 if Data.Stamp.CurrentParts[1]:IsA("Tool") then errorBox.Adornee = Data.Stamp.CurrentParts[1].Handle
1687 else errorBox.Adornee = Data.Stamp.CurrentParts[1] end
1688
1689 delay(0,function()
1690 for i = 1, 3 do
1691 errorBox.Visible = true
1692 wait(0.13)
1693 errorBox.Visible = false
1694 wait(0.13)
1695 end
1696 errorBox.Adornee = nil
1697 errorBox.Parent = Tool
1698 end)
1699end
1700
1701
1702-- helper function to determine if a character can be pushed upwards by a certain amount
1703-- 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
1704function spaceAboveCharacter(charTorso, newTorsoY)
1705 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)
1706 for j = 1, #partsAboveChar do
1707 if partsAboveChar[j].CanCollide then return false end
1708 end
1709
1710 return true
1711end
1712
1713
1714
1715local insertBoundingBoxOverlapVector = Vector3.new(1, 1, 1) -- we can still stamp if our character extrudes into the target stamping space by 1 or fewer units
1716
1717function onInsertMouseButton1Up()
1718 if guiScriptIsLoadingSomething then return end -- don't try to stamp while we're loading!
1719
1720 if eyeDropperConnection then
1721 eyeDropperConnection:disconnect()
1722 eyeDropperConnection = nil
1723 return
1724 end
1725
1726 if Data.Stamp.MouseDown then
1727 Data.Stamp.MouseDown = false
1728 if Data.Stamp.Dragger then
1729
1730 --Place the object where the mouse is currently positioned
1731 -- For Restricting Stamper Tool
1732
1733 while Data.Stamp.MouseLock do wait() end
1734 onInsertMouseMove()
1735 Data.Stamp.MouseLock = true
1736
1737 if(isRestricted) then
1738 -- if player tries to stamp out of bounds, tell them they can't
1739 if not inBounds(Data.Stamp.TransparencyTable) then
1740 variables.ShowInvalidPlacement.Value = true
1741 Data.Stamp.MouseLock = false
1742 return
1743 end
1744 end
1745
1746 -- if unstampable face, then don't let us stamp there!
1747 if unstampableSurface then
1748 Data.Stamp.MouseLock = false
1749 flashRedBox()
1750 return
1751 end
1752
1753 -- Prevent part from being stamped on top of a player
1754
1755 local minBB, maxBB = getBoundingBox2(Data.Stamp.CurrentParts[1])
1756 local configFound, targetCFrame = findConfigAtMouseTarget(Data.Stamp.TransparencyTable)
1757
1758 if configFound then
1759 local blockingParts = game.Workspace:FindPartsInRegion3(Region3.new(minBB+targetCFrame.p+insertBoundingBoxOverlapVector, maxBB+targetCFrame.p-insertBoundingBoxOverlapVector), Data.Stamp.CurrentParts[1], 100)
1760 for b = 1, #blockingParts do
1761 -- below if we only want to block stamping on self
1762 --if blockingParts[b].Parent == script.Parent.Parent then return end
1763
1764 -- below if we want to block stamping on self and also stamping that intersects a model we've previously stamped on our baseplate
1765 -- should work as soon as Region3 queries are fixed
1766 -- NOTE TO SELF: See if partModel applies when isRestricted is false
1767 --if blockingParts[b]:IsDescendantOf(partModel) or blockingParts[b].Parent == script.Parent.Parent then Data.Stamp.MouseLock = false flashRedBox() break end --return end
1768 if blockingParts[b]:IsDescendantOf(partModel) then Data.Stamp.MouseLock = false flashRedBox() end-- still error if overlapping another model [should return here too!]
1769 end
1770
1771 local alreadyPushedUp = {}
1772 -- if no blocking model below, then see if stamping on top of a character
1773 for b = 1, #blockingParts do
1774 --if blockingParts[b].Parent == script.Parent.Parent then
1775-- local blockingPersonTorso = script.Parent.Parent:FindFirstChild("Torso")
1776 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
1777 local blockingPersonTorso = blockingParts[b].Parent:FindFirstChild("Torso")
1778 alreadyPushedUp[blockingParts[b].Parent] = true
1779
1780 if blockingPersonTorso then
1781 -- 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)
1782 local newY = maxBB.Y + targetCFrame.p.Y + 3
1783 if spaceAboveCharacter(blockingPersonTorso, newY) then
1784 blockingPersonTorso.CFrame = blockingPersonTorso.CFrame + Vector3.new(0, newY - blockingPersonTorso.CFrame.p.Y, 0)
1785 else
1786 -- if no space, we just error
1787 Data.Stamp.MouseLock = false
1788 flashRedBox()
1789 return
1790 -- should return here too!
1791 end
1792 end
1793
1794 --break
1795 end
1796 end
1797 end
1798
1799 -- Post process: after positioning the part or model, restore transparency, material, anchored and collide states and create joints
1800 if Data.Stamp.CurrentParts[1]:IsA("Model") or Data.Stamp.CurrentParts[1]:IsA("Tool") then
1801
1802 if Data.Stamp.CurrentParts[1]:IsA("Model") then
1803 -- Tyler's magical hack-code for allowing/preserving clones of both Surface and Manual Welds... just don't ask X<
1804 manualWeldTable = {}
1805 manualWeldParentTable = {}
1806 saveTheWelds(Data.Stamp.CurrentParts[1])
1807 Data.Stamp.CurrentParts[1]:BreakJoints()
1808 Data.Stamp.CurrentParts[1]:MakeJoints()
1809 restoreTheWelds()
1810 end
1811
1812 -- if it's a model, we also want to fill in the playerID and playerName tags, if it has those (e.g. for the friend-only door)
1813 playerIdTag = Data.Stamp.CurrentParts[1]:FindFirstChild("PlayerIdTag")
1814 playerNameTag = Data.Stamp.CurrentParts[1]:FindFirstChild("PlayerNameTag")
1815 if playerIdTag ~= nil then
1816 tempPlayerValue = getPlayer()
1817 if tempPlayerValue ~= nil then playerIdTag.Value = tempPlayerValue.userId end
1818 end
1819 if playerNameTag ~= nil then
1820 tempPlayerValue = getPlayer()
1821 if tempPlayerValue ~= nil then playerNameTag.Value = tempPlayerValue.Name end
1822 end
1823 -- ...and tag all inserted models for subsequent origin identification
1824 -- if no RobloxModel tag already exists, then add it.
1825 if Data.Stamp.CurrentParts[1]:FindFirstChild("RobloxModel") == nil then
1826 local stringTag = Instance.new("BoolValue", Data.Stamp.CurrentParts[1])
1827 stringTag.Name = "RobloxModel"
1828
1829 if Data.Stamp.CurrentParts[1]:FindFirstChild("RobloxStamper") == nil then
1830 local stringTag2 = Instance.new("BoolValue", Data.Stamp.CurrentParts[1])
1831 stringTag2.Name = "RobloxStamper"
1832 end
1833 end
1834
1835 else
1836 Data.Stamp.CurrentParts[1]:BreakJoints()
1837 if Data.Stamp.CurrentParts[1]:FindFirstChild("RobloxStamper") == nil then
1838 local stringTag2 = Instance.new("BoolValue", Data.Stamp.CurrentParts[1])
1839 stringTag2.Name = "RobloxStamper"
1840 end
1841 end
1842
1843 -- make sure all the joints are activated before restoring anchor states
1844 if not createJoints then game.JointsService:CreateJoinAfterMoveJoints() end
1845
1846 click.Value = true
1847 --Fix the transparency and material of all the parts
1848 for part, transparency in pairs(Data.Stamp.TransparencyTable) do
1849 part.Transparency = transparency
1850 part.archivable = true
1851 end
1852 for part, material in pairs(Data.Stamp.MaterialTable) do
1853 part.Material = material
1854 end
1855 for part, collide in pairs(Data.Stamp.CanCollideTable) do
1856 part.CanCollide = collide
1857 end
1858 for part, anchored in pairs(Data.Stamp.AnchoredTable) do
1859 part.Anchored = anchored
1860 end
1861 for decal, transparency in pairs(Data.Stamp.DecalTransparencyTable) do
1862 decal.Transparency = transparency
1863 end
1864
1865 -- re-enable all seats
1866 setSeatEnabledStatus(Data.Stamp.CurrentParts[1], true)
1867
1868 Data.Stamp.TransparencyTable = nil
1869 Data.Stamp.MaterialTable = nil
1870 Data.Stamp.CanCollideTable = nil
1871 Data.Stamp.AnchoredTable = nil
1872
1873 -- ...and tag all inserted models for subsequent origin identification
1874 -- if no RobloxModel tag already exists, then add it.
1875 if Data.Stamp.CurrentParts[1]:FindFirstChild("RobloxModel") == nil then
1876 local stringTag = Instance.new("BoolValue", Data.Stamp.CurrentParts[1])
1877 stringTag.Name = "RobloxModel"
1878 end
1879
1880 -- set our object back to the player's plate
1881 Data.Stamp.CurrentParts[1].Parent = partModel
1882
1883 --Re-enable the scripts
1884 for index,script in pairs(Data.Stamp.DisabledScripts) do
1885 script.Disabled = false
1886 end
1887 --Now that they are all marked enabled, reinsert them into the world so they start running
1888 for index,script in pairs(Data.Stamp.DisabledScripts) do
1889 local oldParent = script.Parent
1890 script.Parent = nil
1891 script:Clone().Parent = oldParent
1892 end
1893 Data.Stamp.DisabledScripts = nil
1894 Data.Stamp.Dragger = nil
1895 Data.Stamp.CurrentParts.Parent = nil
1896 Data.Stamp.CurrentParts = nil
1897
1898 Data.Stamp.MouseLock = false
1899
1900 --Now set up a new instance of the object to allow a second copy to be stamped down
1901 variables.Stamped.Value = true
1902 variables.Stamped.Value = false
1903 if isRestricted then
1904 if checkPartLimit() then
1905 setupDraggableClone()
1906 else
1907 variables.ShowMaxedOut.Value = true
1908 end
1909 else
1910 setupDraggableClone()
1911 end
1912
1913 end
1914 end
1915end
1916
1917
1918------------------------ EyeDropper Code -------------------------------------------
1919
1920function disconnectAllWires(instance)
1921 if instance:IsA("CustomEvent") then
1922 for idx, recv in ipairs(instance:GetAttachedReceivers()) do
1923 instance:Disconnect(recv)
1924 end
1925 elseif instance:IsA("CustomEventReceiver") then
1926 for idx, sender in ipairs(instance:GetAttachedEvents()) do
1927 sender:Disconnect(instance)
1928 end
1929 else
1930 for idx, child in ipairs(instance:GetChildren()) do
1931 disconnectAllWires(child)
1932 end
1933 end
1934end
1935
1936
1937
1938function onEyeDropperMouseButton1Down()
1939 if eyeDropperMoveConnection then
1940 eyeDropperMoveConnection:disconnect()
1941 end
1942 clearSelection()
1943 Mouse.Icon = "rbxasset://textures//ArrowCursor.png"
1944
1945 -- deny any attempt to clone something that wasn't stamped using the Stamper tool
1946 if not Mouse.Target then
1947 startEyeDropperOperation()
1948 return
1949 end
1950
1951 local stamperTag = Mouse.Target.Parent:FindFirstChild("RobloxStamper")
1952 if stamperTag == nil then stamperTag = Mouse.Target:FindFirstChild("RobloxStamper") end
1953 if stamperTag == nil then
1954 startEyeDropperOperation()
1955 return
1956 end
1957
1958 local eyeDropperInstance
1959 -- find out if the target part is part of a Roblox Set Model
1960 local robloxModelTag = Mouse.Target.Parent:FindFirstChild("RobloxModel")
1961 if robloxModelTag ~= nil then
1962 eyeDropperInstance = Mouse.Target.Parent
1963 else
1964 eyeDropperInstance = Mouse.Target
1965 end
1966
1967 -- do not allow certain objects to be captured with eye-dropper
1968 -- for now, locked parts
1969 if eyeDropperInstance:IsA("Part") and eyeDropperInstance.Locked then
1970 startEyeDropperOperation()
1971 else
1972 local cloneInstance = eyeDropperInstance:clone()
1973 disconnectAllWires(cloneInstance)
1974 local tempModel = Instance.new("Model")
1975 cloneInstance.Parent = tempModel
1976
1977 -- once more, we make sure it's on grid before eyedroppering
1978 if not isOnGrid(tempModel) then startEyeDropperOperation() return end
1979
1980 Data.Stamp.Model = tempModel
1981 Data.Stamp.Model:BreakJoints()
1982
1983 -- will create and position clone without requiring user to move the mouse
1984
1985 if isRestricted then
1986 if checkPartLimit() then
1987 setupDraggableClone()
1988 if Mouse and not mouseButton1UpCon then mouseButton1UpCon = Mouse.Button1Up:connect(onInsertMouseButton1Up) end
1989 else
1990 variables.ShowMaxedOut.Value = true
1991 end
1992 else
1993 setupDraggableClone()
1994 if Mouse and not mouseButton1UpCon then mouseButton1UpCon = Mouse.Button1Up:connect(onInsertMouseButton1Up) end
1995 end
1996
1997 variables.SwitchLoaderToDialog.AssetImage.Value = "0"
1998 variables.SwitchLoaderToDialog.DialogType.Value = "SideDialog"
1999 variables.SwitchLoaderToDialog.Value = true
2000 end
2001end
2002
2003function onEyeDropperMouseMove()
2004 if not(inGui) and not(inPalette) then
2005 if not Mouse.Target then clearSelection() return end
2006 local part = Mouse.Target
2007 if canEyeDropperObject(part) then
2008 local model = findModel(part)
2009 if model and isOnGrid(model) then
2010 selectionBox.Color = BrickColor.Green()
2011 setSelection(model)
2012 elseif (not model) and isOnGrid(part) then
2013 selectionBox.Color = BrickColor.Green()
2014 setSelection(part)
2015 else
2016 clearSelection()
2017 end
2018 else
2019 clearSelection()
2020 end
2021 end
2022end
2023
2024function startEyeDropperOperation()
2025
2026 cancelAssetPlacement()
2027 pressedEsc = false
2028 signalInsertComplete("EyeDropper")
2029
2030 if mouseButton1UpCon then mouseButton1UpCon:disconnect() mouseButton1UpCon = nil end
2031
2032 if eyeDropperConnection then
2033 eyeDropperConnection:disconnect()
2034 eyeDropperConnection = nil
2035 end
2036 if eyeDropperMoveConnection then eyeDropperMoveConnection:disconnect() end
2037 Mouse.Icon ="rbxasset://textures//DropperCursor.png"
2038 eyeDropperConnection = Mouse.Button1Up:connect(onEyeDropperMouseButton1Down)
2039 eyeDropperMoveConnection = Mouse.Move:connect(onEyeDropperMouseMove)
2040
2041end
2042
2043function findModel(part)
2044
2045 if isRestricted then
2046 while part ~= nil do
2047 if part.className == "Model" and part.Name ~= playerModel.Name and part.Name ~= "GarbageParts" then
2048 return part
2049 elseif part.Name == playerModel.Name or part.Name == "GarbageParts" then
2050 return nil
2051 end
2052 part = part.Parent
2053 end
2054 return nil
2055
2056 else
2057 while part ~= game.Workspace do
2058 if part:FindFirstChild("RobloxModel") then
2059 return part
2060 end
2061 part = part.Parent
2062 end
2063 return nil
2064 end
2065
2066end
2067
2068------------------------ End EyeDropper Code ---------------------------------------
2069
2070
2071
2072
2073------------------------ Start Selection Highlighting Code --------------------------
2074
2075function setSelection(partOrModel)
2076 if partOrModel ~= currentSelection then
2077 clearSelection()
2078 currentSelection = partOrModel
2079 selectionBox.Adornee = currentSelection
2080 end
2081end
2082
2083function clearSelection()
2084 if currentSelection ~= nil then
2085 for part, color in pairs(currentSelectionColors) do
2086 part.BrickColor = color
2087 end
2088 selectionBox.Adornee = nil
2089 end
2090 currentSelectionColors = {}
2091 -- I put these inside if statements, because we can't assume these exist. (Jahr, 12-29-2010)
2092 if currentSelection then currentSelection = nil end
2093 if selectionBox then selectionBox.Adornee = nil end
2094end
2095
2096------------------------ End Selection Highlighting Code --------------------------
2097
2098function autoAlignToFace()
2099 local aatf = Data.Stamp.CurrentParts[1]:FindFirstChild("AutoAlignToFace")
2100 if aatf then return aatf.Value else return false end
2101end
2102
2103
2104function autoAlignHelper()
2105 local model = Data.Stamp.CurrentParts[1]
2106 local aatfTag = model:FindFirstChild("AutoAlignToFace")
2107 if not aatfTag then
2108 aatfTag = Instance.new("IntValue")
2109 aatfTag.Name = "AutoAlignToFace"
2110 aatfTag.Parent = Data.Stamp.CurrentParts[1]
2111 aatfTag.Value = 5
2112 end
2113 aatfTag.Value = aatfTag.Value + 1
2114 if aatfTag.Value > 5 then aatfTag.Value = 0 end
2115end
2116
2117function unstampableFaceHelper()
2118 if not Mouse.Target then return end
2119 local model = Mouse.Target
2120 if not model then return end
2121 if not model:FindFirstChild("RobloxModel") then model = model.Parent end
2122 if not model then return end
2123 if not model:FindFirstChild("RobloxModel") then return end
2124
2125 local ufhTag = model:FindFirstChild("UnstampableFaces")
2126 if not ufhTag then
2127 ufhTag = Instance.new("StringValue")
2128 ufhTag.Name = "UnstampableFaces"
2129 ufhTag.Parent = model
2130 ufhTag.Value = ""
2131 end
2132
2133 local hitFace = modelTargetSurface(model, game.Workspace.CurrentCamera.CoordinateFrame.p, Mouse.Hit.p)
2134
2135 -- put string list into table form
2136 breakingFaceList = {}
2137 for bf = -3, 3 do
2138 breakingFaceList[bf] = false
2139 end
2140 for bf in string.gmatch(ufhTag.Value, "[^,]+") do
2141 breakingFaceList[tonumber(bf)] = true
2142 end
2143
2144 -- toggle value of hit face
2145 breakingFaceList[hitFace] = not breakingFaceList[hitFace]
2146
2147 -- put table form back into string value
2148 ufhTag.Value = ""
2149 local seenAValueSoFar = false
2150 for bf = -3, 3 do
2151 if bf ~= 0 then -- ignore 0 face, since that doesn't exist
2152 if breakingFaceList[bf] then
2153 if seenAValueSoFar then ufhTag.Value = ufhTag.Value .. "," .. tostring(bf)
2154 else ufhTag.Value = tostring(bf) seenAValueSoFar = true end
2155 end
2156 end
2157 end
2158end
2159
2160function justificationHelper(whichAxis)
2161 local model = Data.Stamp.CurrentParts[1]
2162 local justTag = model:FindFirstChild("Justification")
2163 if not justTag then
2164 justTag = Instance.new("Vector3Value")
2165 justTag.Name = "Justification"
2166 justTag.Parent = Data.Stamp.CurrentParts[1]
2167 justTag.Value = Vector3.new(1, 1, 1)
2168 end
2169 local oldValue = justTag.Value
2170 if whichAxis == 1 then
2171 if oldValue.X == 2 then justTag.Value = Vector3.new(0, oldValue.Y, oldValue.Z)
2172 else justTag.Value = Vector3.new(oldValue.X+1, oldValue.Y, oldValue.Z) end
2173 elseif whichAxis == 2 then
2174 if oldValue.Y == 2 then justTag.Value = Vector3.new(oldValue.X, 0, oldValue.Z)
2175 else justTag.Value = Vector3.new(oldValue.X, oldValue.Y+1, oldValue.Z) end
2176 elseif whichAxis == 3 then
2177 if oldValue.Z == 2 then justTag.Value = Vector3.new(oldValue.X, oldValue.Y, 0)
2178 else justTag.Value = Vector3.new(oldValue.X, oldValue.Y, oldValue.Z+1) end
2179 end
2180end
2181
2182function onInsertKeyDown(key)
2183
2184 if Data.Stamp.Dragger then
2185 if key == 'R' or key == 'r' and not autoAlignToFace() then
2186 -- Rotate the parts or all the parts in the model
2187 local ry = math.pi/2
2188 local rotCF = CFrame.fromEulerAnglesXYZ(0, ry, 0)
2189 gInitial90DegreeRotations = gInitial90DegreeRotations + 1
2190 if Data.Stamp.CurrentParts[1]:IsA("Model") or Data.Stamp.CurrentParts[1]:IsA("Tool") then
2191 for i, object in pairs(Data.Stamp.CurrentParts[1]:GetChildren()) do
2192 if object:IsA("Flag") then object = object.Handle end
2193 if object:IsA("Part") or object:IsA("TrussPart") or object:IsA("WedgePart") or object:IsA("Seat") or object:IsA("VehicleSeat") then
2194 object.CFrame = rotCF * object.CFrame
2195 end
2196 end
2197 else
2198 Data.Stamp.CurrentParts[1].CFrame = rotCF * Data.Stamp.CurrentParts[1].CFrame
2199 end
2200 -- After rotating, update the position
2201 configFound, targetCFrame = findConfigAtMouseTarget(Data.Stamp.TransparencyTable)
2202 if configFound then
2203 positionPartsAtCFrame3(Data.Stamp.CurrentParts[1], targetCFrame)
2204
2205 -- update everything else in MouseMove
2206 onInsertMouseMove()
2207 end
2208 end
2209 end
2210 if key == 'E' or key == 'e' then
2211 startEyeDropperOperation()
2212 elseif key == 'P' or key =='p' then
2213 pressedEsc = true
2214 if eyeDropperConnection then
2215 eyeDropperConnection:disconnect()
2216 eyeDropperConnection = nil
2217 end
2218 if eyeDropperMoveConnection then eyeDropperMoveConnection:disconnect() end
2219
2220 if Mouse and not mouseButton1UpCon then mouseButton1UpCon = Mouse.Button1Up:connect(onInsertMouseButton1Up) end
2221
2222 clearSelection()
2223 cancelAssetPlacement()
2224 Data.Loading.Cancelled = true
2225 signalInsertComplete("Main")
2226 end
2227
2228 -- admin-only tools: helpful functions for construction purposes
2229 if adminAccess then
2230 if key == 'L' or key == 'l' then
2231 -- autoalign helper
2232 if Data.Stamp.Dragger then autoAlignHelper() onInsertMouseMove() end
2233 elseif key == 'U' or key == 'u' then
2234 -- unstampable face helper
2235 unstampableFaceHelper()
2236 --elseif key == 'C' or key == 'c' then
2237-- if Data.Stamp.Dragger then justificationHelper() end -- the 'c' stands for "Centering" since "j" is already reserved by GuiScript
2238 --end
2239 elseif key == 'X' or key == 'x' then -- change x justification
2240 if Data.Stamp.Dragger then justificationHelper(1) onInsertMouseMove() end
2241 elseif key == 'Y' or key == 'y' then -- change y justification
2242 if Data.Stamp.Dragger then justificationHelper(2) onInsertMouseMove() end
2243 elseif key == 'Z' or key == 'z' then -- change z justification
2244 if Data.Stamp.Dragger then justificationHelper(3) onInsertMouseMove() end
2245 end
2246 end
2247end
2248
2249
2250function onEquippedLocal(mouse)
2251
2252 Mouse = mouse
2253
2254 player = getPlayer()
2255
2256 -- if equip goes through while in backpack (so getPlayer() returns nil), we don't want to process anything else
2257 if not player then return end
2258
2259 if isRestricted then
2260 if game.Workspace:FindFirstChild("BuildingAreas") then
2261 local areas = game.Workspace.BuildingAreas:GetChildren()
2262 for i = 1, #areas do
2263 if areas[i]:FindFirstChild("Player") and areas[i].Player.Value == Tool.Parent.Name then
2264 playerModel = areas[i]:FindFirstChild("PlayerArea")
2265 break
2266 end
2267 end
2268 end
2269 else
2270 playerModel = game.Workspace
2271 end
2272
2273 if not playerModel then return end
2274
2275 -- used to move object when walking
2276 cameraChangeCon = game.Players.LocalPlayer.Character.Humanoid.Running:connect(function(speed)
2277 if speed > 0 then
2278 walking = true
2279 while walking do
2280 onInsertMouseMove()
2281 wait(1.0/30.0)
2282 end
2283 else
2284 walking = false
2285 end
2286 end)
2287 mouseMoveCon = mouse.Move:connect(onInsertMouseMove)
2288 mouseButton1DownCon = mouse.Button1Down:connect(onInsertMouseButton1Down)
2289 mouseButton1UpCon = mouse.Button1Up:connect(onInsertMouseButton1Up)
2290 Mouse.KeyDown:connect(onInsertKeyDown)
2291
2292 if(isRestricted) then
2293 local takenAreas = game.Workspace.BuildingAreas:GetChildren()
2294
2295 waitForChild(player, "playerNumber")
2296
2297 if(player.playerNumber.Value == 0) then
2298 buildingPlate = nil
2299 partModel = nil
2300 else
2301 waitForChild(game.Workspace, "BuildingAreas")
2302 local buildingAreas = game.Workspace.BuildingAreas
2303 waitForChild(buildingAreas, "Area"..tostring(player.playerNumber.Value))
2304 local targetArea = buildingAreas:FindFirstChild("Area"..tostring(player.playerNumber.Value))
2305
2306 waitForChild(targetArea, "PlayerArea")
2307 waitForChild(targetArea.PlayerArea, "BasePlate")
2308
2309 buildingPlate = targetArea.PlayerArea.BasePlate
2310 partModel = targetArea.PlayerArea
2311 end
2312 else
2313 partModel = game.Workspace
2314 end
2315
2316 selectionBox = Instance.new("SelectionBox")
2317 selectionBox.Name = "Model Delete Selection"
2318 selectionBox.Color = BrickColor.Red()
2319 selectionBox.Adornee = nil
2320 selectionBox.Parent = player.PlayerGui
2321
2322 alreadyMoving = false
2323end
2324
2325
2326function onUnequipped()
2327 if mouseMoveCon then mouseMoveCon:disconnect() end
2328 if mouseButton1DownCon then mouseButton1DownCon:disconnect() end
2329 if mouseButton1UpCon then mouseButton1UpCon:disconnect() end
2330 if cameraChangeCon then cameraChangeCon:disconnect() end
2331
2332 cancelAssetPlacement()
2333
2334 clearSelection()
2335 if selectionBox then selectionBox:Remove() end
2336end
2337----------------------------------------------------------------------------------------
2338
2339
2340
2341
2342-- Lua Start Script
2343Tool.Equipped:connect(function(Mouse) onEquippedLocal(Mouse) end)
2344
2345waitForChild(variables,"InsertAsset")
2346waitForChild(variables.InsertAsset, "Updated")
2347variables.InsertAsset.Updated.Changed:connect(function(prop)
2348 if variables.InsertAsset.Updated.Value == true then
2349 pressedEsc = false
2350 beginInsertAssetStamp(variables.InsertAsset.AssetName.Value, variables.InsertAsset.AssetId.Value,
2351 variables.InsertAsset.Image.Value, variables.InsertAsset.StampMode.Value)
2352 variables.InsertAsset.Updated.Value = false
2353 end
2354end)
2355
2356waitForChild(variables, "SwitchMode")
2357waitForChild(variables.SwitchMode, "Mode")
2358variables.SwitchMode.Changed:connect(function()
2359 if variables.SwitchMode.Value == true then
2360 if variables.SwitchMode.Mode.Value == "Clone" then
2361 startEyeDropperOperation()
2362 end
2363 variables.SwitchMode.Value = false
2364 end
2365end)
2366
2367waitForChild(variables, "ReloadCurrentAsset")
2368variables.ReloadCurrentAsset.Changed:connect(function()
2369 if variables.ReloadCurrentAsset.Value == true then
2370 setupDraggableClone()
2371 variables.ReloadCurrentAsset.Value = false
2372 end
2373end)
2374
2375Tool.Unequipped:connect(function() onUnequipped() end)
2376----------------------------------------------------------------------------------------
2377
2378
2379
2380end,o42)
2381end))
2382o43 = Instance.new("ScreenGui")
2383o43.Name = "StampGUI"
2384o43.Parent = o1
2385o44 = Instance.new("Frame")
2386o44.Name = "InsertPanel"
2387o44.Parent = o43
2388o44.Position = UDim2.new(0.20000000298023,2,0.10000000149012,24)
2389o44.Size = UDim2.new(0.60000002384186,-20,0.63999998569489,0)
2390o44.Style = Enum.FrameStyle.RobloxRound
2391o44.Active = true
2392o44.BackgroundTransparency = 1
2393o45 = Instance.new("Frame")
2394o45.Name = "ItemsFrame"
2395o45.Parent = o44
2396o45.Position = UDim2.new(0.23999999463558,0,0.08500000089407,0)
2397o45.Size = UDim2.new(0.54000002145767,0,0.80000001192093,0)
2398o45.BackgroundTransparency = 1
2399o45.BorderSizePixel = 0
2400o46 = Instance.new("Frame")
2401o46.Name = "InsertAssetButtonExample"
2402o46.Parent = o45
2403o46.Position = UDim2.new(0,128,0,64)
2404o46.Size = UDim2.new(0,64,0,64)
2405o46.Visible = false
2406o46.BackgroundColor3 = Color3.new(0.94902, 0.952941, 0.952941)
2407o46.BackgroundTransparency = 1
2408o46.BorderSizePixel = 0
2409o47 = Instance.new("TextButton")
2410o47.Name = "Button"
2411o47.Parent = o46
2412o47.Position = UDim2.new(0.025000000372529,0,0.025000000372529,0)
2413o47.Size = UDim2.new(0.94999998807907,0,0.94999998807907,0)
2414o47.Style = Enum.ButtonStyle.RobloxButton
2415o47.Text = ""
2416o47.BackgroundColor3 = Color3.new(0.278431, 0.278431, 0.278431)
2417o47.BackgroundTransparency = 0.10000000149012
2418o47.BorderSizePixel = 0
2419o47.TextTransparency = 0.10000000149012
2420o48 = Instance.new("ImageLabel")
2421o48.Name = "ButtonImage"
2422o48.Parent = o47
2423o48.Position = UDim2.new(0,-8,0,-8)
2424o48.Size = UDim2.new(1,16,1,16)
2425o48.BackgroundTransparency = 1
2426o48.Image = "http://gametest.roblox.com/Game/Tools/ThumbnailAsset.ashx?fmt=png&wd=420&ht=420&assetversionid=209411115"
2427o49 = Instance.new("IntValue")
2428o49.Name = "AssetId"
2429o49.Parent = o46
2430o49.Value = 209411115
2431o50 = Instance.new("StringValue")
2432o50.Name = "AssetName"
2433o50.Parent = o46
2434o50.Value = "Roof - Outer Corner"
2435o51 = Instance.new("ImageLabel")
2436o51.Name = "ConfigIcon"
2437o51.Parent = o46
2438o51.Position = UDim2.new(1,-23,1,-24)
2439o51.Size = UDim2.new(0,16,0,16)
2440o51.Visible = false
2441o51.BackgroundColor3 = Color3.new(0, 0, 0)
2442o51.BorderSizePixel = 0
2443o51.Image = "http://www.roblox.com/asset?id=54140547"
2444o52 = Instance.new("TextButton")
2445o52.Name = "CancelButton"
2446o52.Parent = o44
2447o52.Position = UDim2.new(1,-32,0,-2)
2448o52.Size = UDim2.new(0,34,0,34)
2449o52.Style = Enum.ButtonStyle.RobloxButtonDefault
2450o52.Text = ""
2451o52.Font = Enum.Font.ArialBold
2452o52.FontSize = Enum.FontSize.Size24
2453o52.TextColor3 = Color3.new(1, 1, 1)
2454o53 = Instance.new("ImageLabel")
2455o53.Parent = o52
2456o53.Position = UDim2.new(0,-2,0,-2)
2457o53.Size = UDim2.new(0,16,0,16)
2458o53.BackgroundTransparency = 1
2459o53.BorderSizePixel = 0
2460o53.Image = "http://www.roblox.com/asset?id=54135717"
2461o54 = Instance.new("TextButton")
2462o54.Name = "SelectSetButton"
2463o54.Parent = o44
2464o54.Size = UDim2.new(0.20000000298023,0,0.10000000149012,0)
2465o54.Style = Enum.ButtonStyle.RobloxButtonDefault
2466o54.Text = "Select Set"
2467o54.Visible = false
2468o54.Font = Enum.Font.ArialBold
2469o54.FontSize = Enum.FontSize.Size14
2470o54.TextColor3 = Color3.new(1, 1, 1)
2471o55 = Instance.new("Frame")
2472o55.Name = "PagingControls"
2473o55.Parent = o44
2474o55.Position = UDim2.new(0.23999999463558,0,0.89999997615814,0)
2475o55.Size = UDim2.new(0.54000002145767,0,0.10000000149012,0)
2476o55.BackgroundTransparency = 1
2477o55.BorderSizePixel = 0
2478o56 = Instance.new("TextButton")
2479o56.Name = "PreviousPageButton"
2480o56.Parent = o55
2481o56.Position = UDim2.new(0.5,-95,0.5,-20)
2482o56.Size = UDim2.new(0,60,0,40)
2483o56.Style = Enum.ButtonStyle.RobloxButton
2484o56.Text = ""
2485o56.Font = Enum.Font.ArialBold
2486o56.FontSize = Enum.FontSize.Size24
2487o56.TextColor3 = Color3.new(1, 1, 1)
2488o57 = Instance.new("ImageLabel")
2489o57.Parent = o56
2490o57.Position = UDim2.new(0,8,0,-1)
2491o57.Size = UDim2.new(0,18,0,18)
2492o57.BackgroundTransparency = 1
2493o57.BorderSizePixel = 0
2494o57.Image = "http://www.roblox.com/asset?id=54138586"
2495o58 = Instance.new("TextLabel")
2496o58.Name = "PageText"
2497o58.Parent = o55
2498o58.Position = UDim2.new(0.5,-30,0.5,-20)
2499o58.Size = UDim2.new(0,60,0,40)
2500o58.Text = "1 / 3"
2501o58.BackgroundColor3 = Color3.new(0.4, 0, 0.4)
2502o58.BackgroundTransparency = 1
2503o58.Font = Enum.Font.ArialBold
2504o58.FontSize = Enum.FontSize.Size24
2505o58.TextColor3 = Color3.new(1, 1, 1)
2506o59 = Instance.new("TextButton")
2507o59.Name = "NextPageButton"
2508o59.Parent = o55
2509o59.Position = UDim2.new(0.5,35,0.5,-20)
2510o59.Size = UDim2.new(0,60,0,40)
2511o59.Style = Enum.ButtonStyle.RobloxButton
2512o59.Text = ""
2513o59.Font = Enum.Font.ArialBold
2514o59.FontSize = Enum.FontSize.Size24
2515o59.TextColor3 = Color3.new(1, 1, 1)
2516o60 = Instance.new("ImageLabel")
2517o60.Parent = o59
2518o60.Position = UDim2.new(0,10,0,-1)
2519o60.Size = UDim2.new(0,18,0,18)
2520o60.BackgroundTransparency = 1
2521o60.BorderSizePixel = 0
2522o60.Image = "http://www.roblox.com/asset?id=54138563"
2523o61 = Instance.new("Frame")
2524o61.Name = "Sets"
2525o61.Parent = o44
2526o61.Position = UDim2.new(0,0,0,5)
2527o61.Size = UDim2.new(0.23000000417233,0,1,-5)
2528o61.BackgroundColor3 = Color3.new(1, 0, 0.4)
2529o61.BackgroundTransparency = 1
2530o61.BorderSizePixel = 0
2531o62 = Instance.new("Frame")
2532o62.Name = "Line"
2533o62.Parent = o61
2534o62.Position = UDim2.new(1,-3,0.059999998658895,0)
2535o62.Size = UDim2.new(0,3,0.89999997615814,0)
2536o62.BackgroundColor3 = Color3.new(1, 1, 1)
2537o62.BackgroundTransparency = 0.69999998807907
2538o62.BorderSizePixel = 0
2539o63 = Instance.new("TextLabel")
2540o63.Name = "SetsHeader"
2541o63.Parent = o61
2542o63.Size = UDim2.new(0,47,0,24)
2543o63.Text = "Sets"
2544o63.BackgroundTransparency = 1
2545o63.Font = Enum.Font.ArialBold
2546o63.FontSize = Enum.FontSize.Size24
2547o63.TextColor3 = Color3.new(1, 1, 1)
2548o63.TextXAlignment = Enum.TextXAlignment.Left
2549o63.TextYAlignment = Enum.TextYAlignment.Top
2550o64 = Instance.new("Frame")
2551o64.Name = "SetsLists"
2552o64.Parent = o61
2553o64.Position = UDim2.new(0,0,0.059999998658895,0)
2554o64.Size = UDim2.new(1,-6,0.93999999761581,0)
2555o64.BackgroundColor3 = Color3.new(0.8, 0, 0.6)
2556o64.BackgroundTransparency = 1
2557o65 = Instance.new("TextButton")
2558o65.Name = "SetButtonExample"
2559o65.Parent = o64
2560o65.Position = UDim2.new(0,5,0,18)
2561o65.Size = UDim2.new(1,-5,0,18)
2562o65.Text = "House Decorations"
2563o65.Visible = false
2564o65.BackgroundColor3 = Color3.new(1, 1, 1)
2565o65.BackgroundTransparency = 1
2566o65.BorderSizePixel = 0
2567o65.AutoButtonColor = false
2568o65.Font = Enum.Font.Arial
2569o65.FontSize = Enum.FontSize.Size18
2570o65.TextColor3 = Color3.new(1, 1, 1)
2571o65.TextWrapped = true
2572o65.TextXAlignment = Enum.TextXAlignment.Left
2573o66 = Instance.new("Frame")
2574o66.Name = "ItemPreview"
2575o66.Parent = o44
2576o66.Position = UDim2.new(0.79000002145767,0,0.08500000089407,0)
2577o66.Size = UDim2.new(0.20999999344349,0,0.89999997615814,0)
2578o66.BackgroundColor3 = Color3.new(0.4, 0, 0.2)
2579o66.BackgroundTransparency = 1
2580o67 = Instance.new("ImageLabel")
2581o67.Name = "LargePreview"
2582o67.Parent = o66
2583o67.Position = UDim2.new(0.5,-2,0,0)
2584o67.Size = UDim2.new(1,0,0,4)
2585o67.BackgroundColor3 = Color3.new(0, 0, 0)
2586o67.BackgroundTransparency = 0.5
2587o67.BorderSizePixel = 0
2588o67.ZIndex = 3
2589o67.Image = "http://gametest.roblox.com/Game/Tools/ThumbnailAsset.ashx?fmt=png&wd=420&ht=420&assetversionid=209433914"
2590o68 = Instance.new("Frame")
2591o68.Name = "TextPanel"
2592o68.Parent = o66
2593o68.Position = UDim2.new(0,0,0,4)
2594o68.Size = UDim2.new(1,0,0,-4)
2595o68.BackgroundColor3 = Color3.new(0.501961, 0, 0.501961)
2596o68.BackgroundTransparency = 1
2597o69 = Instance.new("TextLabel")
2598o69.Name = "RolloverText"
2599o69.Parent = o68
2600o69.Size = UDim2.new(1,0,0,48)
2601o69.Text = "Window - Diagonal"
2602o69.BackgroundColor3 = Color3.new(0.8, 1, 0.6)
2603o69.BackgroundTransparency = 1
2604o69.BorderSizePixel = 0
2605o69.Font = Enum.Font.ArialBold
2606o69.FontSize = Enum.FontSize.Size24
2607o69.TextColor3 = Color3.new(0.94902, 0.952941, 0.952941)
2608o69.TextWrapped = true
2609o69.TextXAlignment = Enum.TextXAlignment.Left
2610o69.TextYAlignment = Enum.TextYAlignment.Top
2611o70 = Instance.new("Frame")
2612o70.Name = "ConfigureText"
2613o70.Parent = o68
2614o70.Position = UDim2.new(0,0,0,48)
2615o70.Size = UDim2.new(1,0,1,-48)
2616o70.Visible = false
2617o70.BackgroundTransparency = 1
2618o71 = Instance.new("TextLabel")
2619o71.Name = "Configure"
2620o71.Parent = o70
2621o71.Size = UDim2.new(1,0,0,14)
2622o71.Text = "Configure:"
2623o71.BackgroundColor3 = Color3.new(1, 0, 0.4)
2624o71.BackgroundTransparency = 1
2625o71.BorderSizePixel = 0
2626o71.Font = Enum.Font.ArialBold
2627o71.FontSize = Enum.FontSize.Size14
2628o71.TextColor3 = Color3.new(0.94902, 0.952941, 0.952941)
2629o71.TextWrapped = true
2630o71.TextXAlignment = Enum.TextXAlignment.Left
2631o71.TextYAlignment = Enum.TextYAlignment.Top
2632o72 = Instance.new("TextLabel")
2633o72.Name = "Configure1"
2634o72.Parent = o70
2635o72.Position = UDim2.new(0,0,0,14)
2636o72.Size = UDim2.new(1,0,0,14)
2637o72.Text = "Speed"
2638o72.BackgroundTransparency = 1
2639o72.BorderSizePixel = 0
2640o72.Font = Enum.Font.Arial
2641o72.FontSize = Enum.FontSize.Size14
2642o72.TextColor3 = Color3.new(0.94902, 0.952941, 0.952941)
2643o72.TextWrapped = true
2644o72.TextXAlignment = Enum.TextXAlignment.Left
2645o72.TextYAlignment = Enum.TextYAlignment.Top
2646o73 = Instance.new("TextLabel")
2647o73.Name = "Configure2"
2648o73.Parent = o70
2649o73.Position = UDim2.new(0,0,0,28)
2650o73.Size = UDim2.new(1,0,0,14)
2651o73.Text = "Damage"
2652o73.BackgroundTransparency = 1
2653o73.BorderSizePixel = 0
2654o73.Font = Enum.Font.Arial
2655o73.FontSize = Enum.FontSize.Size14
2656o73.TextColor3 = Color3.new(0.94902, 0.952941, 0.952941)
2657o73.TextWrapped = true
2658o73.TextXAlignment = Enum.TextXAlignment.Left
2659o73.TextYAlignment = Enum.TextYAlignment.Top
2660o74 = Instance.new("TextLabel")
2661o74.Name = "Configure3"
2662o74.Parent = o70
2663o74.Position = UDim2.new(0,0,0,42)
2664o74.Size = UDim2.new(1,0,0,14)
2665o74.Text = "Delay"
2666o74.BackgroundTransparency = 1
2667o74.BorderSizePixel = 0
2668o74.Font = Enum.Font.Arial
2669o74.FontSize = Enum.FontSize.Size14
2670o74.TextColor3 = Color3.new(0.94902, 0.952941, 0.952941)
2671o74.TextWrapped = true
2672o74.TextXAlignment = Enum.TextXAlignment.Left
2673o74.TextYAlignment = Enum.TextYAlignment.Top
2674o75 = Instance.new("Frame")
2675o75.Name = "StamperPanel"
2676o75.Parent = o43
2677o75.Position = UDim2.new(0.5,-175,1,-135)
2678o75.Size = UDim2.new(0,350,0,48)
2679o75.Style = Enum.FrameStyle.RobloxRound
2680o75.Active = true
2681o75.ZIndex = 2
2682o76 = Instance.new("TextButton")
2683o76.Name = "MinimizeButton"
2684o76.Parent = o75
2685o76.Position = UDim2.new(1,-32,0,-2)
2686o76.Size = UDim2.new(0,34,0,34)
2687o76.Style = Enum.ButtonStyle.RobloxButtonDefault
2688o76.Text = ""
2689o76.ZIndex = 3
2690o76.Font = Enum.Font.ArialBold
2691o76.FontSize = Enum.FontSize.Size24
2692o76.TextColor3 = Color3.new(1, 1, 1)
2693o77 = Instance.new("ImageLabel")
2694o77.Parent = o76
2695o77.Position = UDim2.new(0,-3,0,-4)
2696o77.Size = UDim2.new(0,16,0,20)
2697o77.BackgroundTransparency = 1
2698o77.BorderSizePixel = 0
2699o77.ZIndex = 4
2700o77.Image = "http://www.roblox.com/asset?id=54932670"
2701o78 = Instance.new("Frame")
2702o78.Name = "StamperButtons"
2703o78.Parent = o75
2704o78.Size = UDim2.new(1,0,1,0)
2705o78.BackgroundTransparency = 1
2706o79 = Instance.new("Frame")
2707o79.Name = "RecentFrame"
2708o79.Parent = o78
2709o79.Position = UDim2.new(0,103,0,-6)
2710o79.Size = UDim2.new(0,192,0,44)
2711o79.Active = true
2712o79.BackgroundTransparency = 1
2713o79.ZIndex = 3
2714o80 = Instance.new("TextButton")
2715o80.Name = "Button1"
2716o80.Parent = o79
2717o80.Position = UDim2.new(0,0,0,-2)
2718o80.Size = UDim2.new(0,48,0,48)
2719o80.Style = Enum.ButtonStyle.RobloxButton
2720o80.Text = ""
2721o80.Visible = false
2722o80.BackgroundColor3 = Color3.new(0.278431, 0.278431, 0.278431)
2723o80.BackgroundTransparency = 0.10000000149012
2724o80.BorderSizePixel = 0
2725o80.ZIndex = 4
2726o80.TextColor3 = Color3.new(1, 1, 1)
2727o80.TextTransparency = 0.10000000149012
2728o80.TextXAlignment = Enum.TextXAlignment.Left
2729o80.TextYAlignment = Enum.TextYAlignment.Top
2730o81 = Instance.new("ImageLabel")
2731o81.Name = "ButtonImage"
2732o81.Parent = o80
2733o81.Position = UDim2.new(0,-8,0,-8)
2734o81.Size = UDim2.new(1,16,1,16)
2735o81.BackgroundTransparency = 1
2736o81.ZIndex = 5
2737o81.Image = "http://gametest.roblox.com/Game/Tools/ThumbnailAsset.ashx?fmt=png&wd=420&ht=420&assetversionid=209434543"
2738o82 = Instance.new("TextLabel")
2739o82.Name = "ShortcutText"
2740o82.Parent = o80
2741o82.Position = UDim2.new(0,-7,0,-8)
2742o82.Size = UDim2.new(0,7,0,12)
2743o82.Text = "F"
2744o82.BackgroundTransparency = 1
2745o82.ZIndex = 8
2746o82.Font = Enum.Font.ArialBold
2747o82.FontSize = Enum.FontSize.Size14
2748o82.TextColor3 = Color3.new(1, 1, 1)
2749o83 = Instance.new("TextButton")
2750o83.Name = "Button2"
2751o83.Parent = o79
2752o83.Position = UDim2.new(0,48,0,-2)
2753o83.Size = UDim2.new(0,48,0,48)
2754o83.Style = Enum.ButtonStyle.RobloxButton
2755o83.Text = ""
2756o83.Visible = false
2757o83.BackgroundColor3 = Color3.new(0.278431, 0.278431, 0.278431)
2758o83.BackgroundTransparency = 0.10000000149012
2759o83.BorderSizePixel = 0
2760o83.ZIndex = 4
2761o83.TextTransparency = 0.10000000149012
2762o84 = Instance.new("ImageLabel")
2763o84.Name = "ButtonImage"
2764o84.Parent = o83
2765o84.Position = UDim2.new(0,-8,0,-8)
2766o84.Size = UDim2.new(1,16,1,16)
2767o84.BackgroundTransparency = 1
2768o84.ZIndex = 5
2769o84.Image = "http://gametest.roblox.com/Game/Tools/ThumbnailAsset.ashx?fmt=png&wd=420&ht=420&assetversionid=209434543"
2770o85 = Instance.new("TextLabel")
2771o85.Name = "ShortcutText"
2772o85.Parent = o83
2773o85.Position = UDim2.new(0,-7,0,-8)
2774o85.Size = UDim2.new(0,7,0,12)
2775o85.Text = "G"
2776o85.BackgroundTransparency = 1
2777o85.ZIndex = 8
2778o85.Font = Enum.Font.ArialBold
2779o85.FontSize = Enum.FontSize.Size14
2780o85.TextColor3 = Color3.new(1, 1, 1)
2781o86 = Instance.new("TextButton")
2782o86.Name = "Button3"
2783o86.Parent = o79
2784o86.Position = UDim2.new(0,95,0,-3)
2785o86.Size = UDim2.new(0,48,0,48)
2786o86.Style = Enum.ButtonStyle.RobloxButton
2787o86.Text = ""
2788o86.Visible = false
2789o86.BackgroundColor3 = Color3.new(0.278431, 0.278431, 0.278431)
2790o86.BackgroundTransparency = 0.10000000149012
2791o86.BorderSizePixel = 0
2792o86.ZIndex = 4
2793o86.TextTransparency = 0.10000000149012
2794o87 = Instance.new("ImageLabel")
2795o87.Name = "ButtonImage"
2796o87.Parent = o86
2797o87.Position = UDim2.new(0,-8,0,-8)
2798o87.Size = UDim2.new(1,16,1,16)
2799o87.BackgroundTransparency = 1
2800o87.ZIndex = 5
2801o87.Image = "http://gametest.roblox.com/Game/Tools/ThumbnailAsset.ashx?fmt=png&wd=420&ht=420&assetversionid=209434543"
2802o88 = Instance.new("TextLabel")
2803o88.Name = "ShortcutText"
2804o88.Parent = o86
2805o88.Position = UDim2.new(0,-7,0,-8)
2806o88.Size = UDim2.new(0,7,0,12)
2807o88.Text = "H"
2808o88.BackgroundTransparency = 1
2809o88.ZIndex = 8
2810o88.Font = Enum.Font.ArialBold
2811o88.FontSize = Enum.FontSize.Size14
2812o88.TextColor3 = Color3.new(1, 1, 1)
2813o89 = Instance.new("TextButton")
2814o89.Name = "Button4"
2815o89.Parent = o79
2816o89.Position = UDim2.new(0,142,0,-3)
2817o89.Size = UDim2.new(0,48,0,48)
2818o89.Style = Enum.ButtonStyle.RobloxButton
2819o89.Text = ""
2820o89.Visible = false
2821o89.BackgroundColor3 = Color3.new(0.278431, 0.278431, 0.278431)
2822o89.BackgroundTransparency = 0.10000000149012
2823o89.BorderSizePixel = 0
2824o89.ZIndex = 4
2825o89.TextTransparency = 0.10000000149012
2826o90 = Instance.new("ImageLabel")
2827o90.Name = "ButtonImage"
2828o90.Parent = o89
2829o90.Position = UDim2.new(0,-8,0,-8)
2830o90.Size = UDim2.new(1,16,1,16)
2831o90.BackgroundTransparency = 1
2832o90.ZIndex = 5
2833o90.Image = "http://gametest.roblox.com/Game/Tools/ThumbnailAsset.ashx?fmt=png&wd=420&ht=420&assetversionid=209434543"
2834o91 = Instance.new("TextLabel")
2835o91.Name = "ShortcutText"
2836o91.Parent = o89
2837o91.Position = UDim2.new(0,-7,0,-8)
2838o91.Size = UDim2.new(0,7,0,12)
2839o91.Text = "J"
2840o91.BackgroundTransparency = 1
2841o91.ZIndex = 8
2842o91.Font = Enum.Font.ArialBold
2843o91.FontSize = Enum.FontSize.Size14
2844o91.TextColor3 = Color3.new(1, 1, 1)
2845o92 = Instance.new("TextButton")
2846o92.Name = "CloneButton"
2847o92.Parent = o78
2848o92.Position = UDim2.new(0,0,0,-6)
2849o92.Size = UDim2.new(0,45,0,45)
2850o92.Style = Enum.ButtonStyle.RobloxButton
2851o92.Text = ""
2852o92.ZIndex = 3
2853o92.Font = Enum.Font.ArialBold
2854o92.FontSize = Enum.FontSize.Size14
2855o92.TextColor3 = Color3.new(1, 1, 1)
2856o93 = Instance.new("ImageLabel")
2857o93.Parent = o92
2858o93.Position = UDim2.new(0,-7,0,-7)
2859o93.Size = UDim2.new(1,14,1,14)
2860o93.BackgroundTransparency = 1
2861o93.BorderSizePixel = 0
2862o93.ZIndex = 4
2863o93.Image = "http://www.roblox.com/asset?id=51641555"
2864o94 = Instance.new("TextLabel")
2865o94.Name = "CloneShortcut"
2866o94.Parent = o92
2867o94.Position = UDim2.new(0,-7,0,-8)
2868o94.Size = UDim2.new(0,8,0,12)
2869o94.Text = "E"
2870o94.BackgroundTransparency = 1
2871o94.ZIndex = 5
2872o94.Font = Enum.Font.ArialBold
2873o94.FontSize = Enum.FontSize.Size14
2874o94.TextColor3 = Color3.new(1, 1, 1)
2875o95 = Instance.new("TextButton")
2876o95.Name = "PartsButton"
2877o95.Parent = o78
2878o95.Position = UDim2.new(0,45,0,-6)
2879o95.Size = UDim2.new(0,45,0,45)
2880o95.Style = Enum.ButtonStyle.RobloxButton
2881o95.Text = ""
2882o95.ZIndex = 3
2883o95.Selected = true
2884o95.Font = Enum.Font.ArialBold
2885o95.FontSize = Enum.FontSize.Size14
2886o95.TextColor3 = Color3.new(1, 1, 1)
2887o96 = Instance.new("ImageLabel")
2888o96.Parent = o95
2889o96.Position = UDim2.new(0,-7,0,-7)
2890o96.Size = UDim2.new(1,14,1,14)
2891o96.BackgroundTransparency = 1
2892o96.BorderSizePixel = 0
2893o96.ZIndex = 4
2894o96.Image = "http://www.roblox.com/asset?id=54966682"
2895o97 = Instance.new("TextLabel")
2896o97.Name = "PartsShortcut"
2897o97.Parent = o95
2898o97.Position = UDim2.new(0,-7,0,-8)
2899o97.Size = UDim2.new(0,8,0,12)
2900o97.Text = "P"
2901o97.BackgroundTransparency = 1
2902o97.ZIndex = 5
2903o97.Font = Enum.Font.ArialBold
2904o97.FontSize = Enum.FontSize.Size14
2905o97.TextColor3 = Color3.new(1, 1, 1)
2906o98 = Instance.new("Frame")
2907o98.Name = "ClonePanel"
2908o98.Parent = o78
2909o98.Position = UDim2.new(0,0,0,-8)
2910o98.Size = UDim2.new(0,80,1,16)
2911o98.Style = Enum.FrameStyle.RobloxSquare
2912o98.Visible = false
2913o99 = Instance.new("TextLabel")
2914o99.Name = "ClonePanelText"
2915o99.Parent = o98
2916o99.Position = UDim2.new(0,-6,0,-8)
2917o99.Size = UDim2.new(1,12,1,16)
2918o99.Text = "Click on a part to clone it"
2919o99.Visible = false
2920o99.BackgroundTransparency = 1
2921o99.Font = Enum.Font.ArialBold
2922o99.FontSize = Enum.FontSize.Size14
2923o99.TextColor3 = Color3.new(1, 1, 1)
2924o99.TextWrapped = true
2925o100 = Instance.new("TextButton")
2926o100.Name = "RestoreButton"
2927o100.Parent = o75
2928o100.Position = UDim2.new(0,-25,0,-20)
2929o100.Size = UDim2.new(0,50,0,25)
2930o100.Style = Enum.ButtonStyle.RobloxButtonDefault
2931o100.Text = ""
2932o100.Visible = false
2933o100.ZIndex = 3
2934o100.Font = Enum.Font.ArialBold
2935o100.FontSize = Enum.FontSize.Size24
2936o100.TextColor3 = Color3.new(1, 1, 1)
2937o101 = Instance.new("ImageLabel")
2938o101.Parent = o100
2939o101.Position = UDim2.new(0,-4,0,-4)
2940o101.Size = UDim2.new(1,8,1,8)
2941o101.BackgroundTransparency = 1
2942o101.BorderSizePixel = 0
2943o101.ZIndex = 4
2944o101.Image = "http://www.roblox.com/asset?id=54933540"
2945o102 = Instance.new("LocalScript")
2946o102.Name = "StampGuiController"
2947o102.Parent = o43
2948table.insert(cors,coroutine.create(function()
2949wait()
2950runDummyScript(function()
2951local stampGui = script.Parent
2952local insertPanel = stampGui.InsertPanel
2953local stamperPanel = stampGui.StamperPanel
2954
2955local itemPreview = insertPanel.ItemPreview
2956
2957function handleResize()
2958 wait() -- neccessary to insure heartbeat happened
2959 itemPreview.LargePreview.Size = UDim2.new(1,0,0,itemPreview.AbsoluteSize.X)
2960 itemPreview.LargePreview.Position = UDim2.new(0.5,-itemPreview.LargePreview.AbsoluteSize.X/2,0,0)
2961 itemPreview.TextPanel.Position = UDim2.new(0,0,0,itemPreview.LargePreview.AbsoluteSize.Y)
2962 itemPreview.TextPanel.Size = UDim2.new(1,0,0,itemPreview.AbsoluteSize.Y - itemPreview.LargePreview.AbsoluteSize.Y)
2963end
2964
2965stampGui.Changed:connect(function(prop)
2966 if prop == "AbsoluteSize" then
2967 handleResize()
2968 end
2969end)
2970
2971handleResize()
2972end,o102)
2973end))
2974o103 = Instance.new("Frame")
2975o103.Name = "LoadDialog"
2976o103.Parent = o43
2977o103.Position = UDim2.new(0.5,-175,0.5,-25)
2978o103.Size = UDim2.new(0,350,0,50)
2979o103.Style = Enum.FrameStyle.RobloxRound
2980o103.Visible = false
2981o103.SizeConstraint = Enum.SizeConstraint.RelativeXX
2982o104 = Instance.new("TextLabel")
2983o104.Name = "LoadLabel"
2984o104.Parent = o103
2985o104.Position = UDim2.new(0,0,0,-8)
2986o104.Size = UDim2.new(0,155,0.5,36)
2987o104.Text = "Loading..."
2988o104.BackgroundTransparency = 1
2989o104.Font = Enum.Font.ArialBold
2990o104.FontSize = Enum.FontSize.Size36
2991o104.TextColor3 = Color3.new(0.972549, 0.972549, 0.972549)
2992o105 = Instance.new("SelectionBox")
2993o105.Name = "ErrorBox"
2994o105.Parent = o1
2995o105.Color = BrickColor.new("Bright red")
2996o105.Visible = false
2997o106 = Instance.new("LocalScript")
2998o106.Name = "GuiScript"
2999o106.Parent = o1
3000table.insert(cors,coroutine.create(function()
3001wait()
3002runDummyScript(function()
3003-- This script is responsible for working the gui
3004
3005-- basic functions
3006function waitForChild(instance, name)
3007 while not instance:findFirstChild(name) do
3008 instance.ChildAdded:wait()
3009 end
3010end
3011
3012function waitForProperty(instance, name)
3013 while not instance[name] do
3014 instance.Changed:wait()
3015 end
3016end
3017
3018
3019-- Locals
3020local Tool = script.Parent
3021
3022waitForChild(Tool, "LuaGlobalVariables")
3023local variables = Tool.LuaGlobalVariables
3024waitForChild(variables, "InsertAsset")
3025local insertAsset = variables.InsertAsset
3026waitForChild(variables, "SwitchMode")
3027local switchMode = variables.SwitchMode
3028waitForChild(variables, "ShowAdminCategories")
3029local showAdminCategories = variables.ShowAdminCategories
3030
3031waitForChild(variables, "ReloadCurrentAsset")
3032waitForChild(variables,"userIDs")
3033
3034game:GetService("ContentProvider"):Preload("http://www.roblox.com/asset/?id=42163425")
3035game:GetService("ContentProvider"):Preload("http://www.roblox.com/asset/?id=42563487")
3036
3037local BaseUrl = game:GetService("ContentProvider").BaseUrl
3038
3039local buttonHeight = 64
3040local buttonWidth = buttonHeight
3041
3042local waypointShowing = false
3043local showingPartPicker = true
3044local firstEquip = true
3045
3046local Window
3047local Data
3048local loading = false
3049
3050local startTime = 0
3051
3052local SetCache = {}
3053
3054local lastEnter = nil
3055
3056-- For Restricting Stamper Tool
3057local buildingPlate
3058local partModel
3059
3060-- wait for all of our set ids to load
3061local userIdsForStamperParts = variables.userIDs -- 7502714 This is UsabilityMan (on gametest)
3062
3063function giveNewUserId(id)
3064 local newUserId = Instance.new("IntValue")
3065 newUserId.Name = "userID"
3066 newUserId.Value = id
3067 newUserId.Parent = userIdsForStamperParts
3068 userIdsForStamperParts.Value = userIdsForStamperParts.Value + 1
3069end
3070
3071BaseUrl = BaseUrl:lower()
3072local isGametest = string.find(BaseUrl,"gametest")
3073
3074local isRestricted = Instance.new("BoolValue")
3075isRestricted.Name = "IsRestricted"
3076isRestricted.Value = false
3077
3078function isLocalWTRB()
3079 waitForChild(game,"StarterGui")
3080 if game.StarterGui:FindFirstChild("VersionGui") then
3081 if game.StarterGui.VersionGui:FindFirstChild("VersionText", true) then
3082 return true
3083 end
3084 end
3085 return false
3086end
3087
3088waitForProperty(game,"PlaceId")
3089if game.PlaceId == 41324860 or isLocalWTRB() then
3090 isRestricted.Value = true
3091end
3092isRestricted.Parent = variables
3093
3094if isGametest then
3095 giveNewUserId(28215009)
3096 giveNewUserId(28215010)
3097 if not isRestricted.Value then
3098 giveNewUserId(28215011)
3099 giveNewUserId(28215012)
3100 giveNewUserId(28215013)
3101 else
3102 giveNewUserId(2409156)
3103 giveNewUserId(28220612)
3104 giveNewUserId(28220614)
3105 end
3106else -- we are on prod
3107 giveNewUserId(18881789)
3108 giveNewUserId(18881808)
3109 if not isRestricted.Value then
3110 giveNewUserId(18881829)
3111 giveNewUserId(18881853)
3112 giveNewUserId(18881866)
3113 else
3114 giveNewUserId(2409156)
3115 giveNewUserId(19238067)
3116 giveNewUserId(19238114)
3117 end
3118end
3119
3120while #userIdsForStamperParts:GetChildren() < userIdsForStamperParts.Value do userIdsForStamperParts.ChildAdded:wait() end
3121userIdsForStamperParts = userIdsForStamperParts:GetChildren()
3122
3123local useAssetVersionId = false
3124local LargeThumbnailUrl
3125local SmallThumbnailUrl
3126
3127local InsertRows = 0
3128local InsertColumns = 0
3129local insertButtons = {}
3130
3131local CancelDuringLoad
3132
3133local prevPart = {AssetNameValue = "",AssetIdValue = 0 ,InsertFrameButtonImage = ""}
3134local recentPartStack = {}
3135
3136-- Connection Managers
3137local guiChangedCon = nil
3138local cloneButtonCon = nil
3139local partListClickCon = nil
3140local itemFrameChangedCon = nil
3141local setsNextPageCon = nil
3142local setsPrevPageCon = nil
3143local insertPanelCloseCon = nil
3144local minimizeCon = nil
3145local restoreCon = nil
3146local setButtonCons = {}
3147local insertButtonCons = {}
3148local recentPartStackCons = {}
3149
3150local Mouse = nil
3151local currSetPage = 1
3152
3153local mode = 0 -- 0 = main dialog, 1 = stamper, 2 = eyedropper
3154
3155waitForChild(script.Parent,"StampGUI")
3156local stamperGui = script.Parent.StampGUI
3157waitForChild(stamperGui,"InsertPanel")
3158waitForChild(stamperGui.InsertPanel, "CancelButton")
3159local currStampGui = nil
3160
3161local maxRecentParts = 4
3162for i = 1, maxRecentParts do
3163 recentPartStack[i] = {AssetNameValue,AssetIdValue,InsertFrameButtonImage}
3164 recentPartStack[i].AssetNameValue = ""
3165 recentPartStack[i].AssetIdValue = ""
3166 recentPartStack[i].InsertFrameButtonImage = ""
3167end
3168----------------------------------------------------------------------------------------
3169
3170
3171-- functions
3172function showBaseplateGuideArrows()
3173 playerCharacter = Tool.Parent
3174 if playerCharacter:FindFirstChild("Humanoid") and not playerCharacter:FindFirstChild("BasePlateGuide") then
3175 newGuide = Tool.BasePlateGuide:Clone()
3176 newGuide.Parent = playerCharacter
3177 newGuide.Disabled = false
3178 end
3179end
3180
3181function setAssetUrls()
3182 if useAssetVersionId then
3183 LargeThumbnailUrl = BaseUrl .. "Game/Tools/ThumbnailAsset.ashx?fmt=png&wd=420&ht=420&assetversionid="
3184 SmallThumbnailUrl = BaseUrl .. "Game/Tools/ThumbnailAsset.ashx?fmt=png&wd=75&ht=75&assetversionid="
3185 else
3186 LargeThumbnailUrl = BaseUrl .. "Game/Tools/ThumbnailAsset.ashx?fmt=png&wd=420&ht=420&aid="
3187 SmallThumbnailUrl = BaseUrl .. "Game/Tools/ThumbnailAsset.ashx?fmt=png&wd=75&ht=75&aid="
3188 end
3189end
3190
3191function signalSwitchMode(mode)
3192 switchMode.Mode.Value = mode
3193 switchMode.Value = true
3194end
3195
3196function goToClone()
3197 cancelLoadingWindow()
3198 closeInsertPanel()
3199 cancelAssetPlacement()
3200
3201 mode = 2
3202 --signalStamperScript("",0,"","",false)
3203 signalSwitchMode("Clone")
3204
3205 currStampGui.StamperPanel.StamperButtons.ClonePanel.Visible = true
3206 currStampGui.StamperPanel.StamperButtons.CloneButton.Selected = true
3207 if currStampGui.Parent ~= nil then
3208 currStampGui.StamperPanel.StamperButtons.ClonePanel:TweenPosition(UDim2.new(0, -88, 0, -8),Enum.EasingDirection.InOut,Enum.EasingStyle.Sine,0.35,true)
3209 delay(0.3,function() currStampGui.StamperPanel.StamperButtons.ClonePanel.ClonePanelText.Visible = true end)
3210 end
3211end
3212
3213function goToStamp()
3214 mode = 1
3215 cancelLoadingWindow()
3216 closeInsertPanel()
3217 closeClonePanel()
3218end
3219
3220function goToInsertPanel()
3221 cancelLoadingWindow()
3222 closeClonePanel()
3223 pcall(function() currStampGui.InsertPanel.CancelButton.Modal = true end)
3224 currStampGui.StamperPanel.StamperButtons.PartsButton.Selected = true
3225
3226 if not showingPartPicker then
3227 showingPartPicker = true
3228 if currStampGui.Parent ~= nil then
3229 currStampGui.InsertPanel:TweenPosition(UDim2.new(0.2, 2, 0.1, 24),Enum.EasingDirection.InOut,Enum.EasingStyle.Sine,0.35,true)
3230 end
3231 else
3232 closeInsertPanel()
3233 reloadCurrentAsset()
3234 end
3235end
3236
3237function closeInsertPanel()
3238 pcall(function() currStampGui.InsertPanel.CancelButton.Modal = false end)
3239 currStampGui.StamperPanel.StamperButtons.PartsButton.Selected = false
3240
3241 showingPartPicker = false
3242 if currStampGui.Parent ~= nil then
3243 currStampGui.InsertPanel:TweenPosition(UDim2.new(0.2, 2, 1, 24),Enum.EasingDirection.InOut,Enum.EasingStyle.Sine,0.35,true)
3244 end
3245end
3246
3247function closeClonePanel()
3248 currStampGui.StamperPanel.StamperButtons.ClonePanel.ClonePanelText.Visible = false
3249 currStampGui.StamperPanel.StamperButtons.CloneButton.Selected = false
3250 if currStampGui.Parent ~= nil then
3251 currStampGui.StamperPanel.StamperButtons.ClonePanel:TweenPosition(UDim2.new(0, 0, 0, -8),Enum.EasingDirection.InOut,Enum.EasingStyle.Sine,0.35,true)
3252 delay(0.3,function() currStampGui.StamperPanel.StamperButtons.ClonePanel.Visible = false end)
3253 end
3254end
3255
3256function cancelAssetPlacement()
3257 gInitial90DegreeRotations = 0
3258 Data.Stamp.Cancelled = true
3259 Data.Stamp.Dragger = nil
3260 if Data.Stamp.Model then
3261 Data.Stamp.Model:Remove()
3262 Data.Stamp.Model = nil
3263 end
3264 if Data.Stamp.CurrentParts then
3265 for index, object in pairs(Data.Stamp.CurrentParts) do
3266 object:Remove()
3267 end
3268 Data.Stamp.CurrentParts = nil
3269 end
3270
3271 if Mouse then
3272 Mouse.Icon ="rbxasset://textures\\ArrowCursor.png"
3273 end
3274 game.JointsService:ClearJoinAfterMoveJoints()
3275
3276end
3277
3278function hint(label)
3279
3280 -- Pass in a string, it shows a top hint. (Replaces previous hint, if exists)
3281 _player = game.Players:GetPlayerFromCharacter(Tool.Parent)
3282 if(_player.PlayerGui:FindFirstChild("topHint")~=nil) then
3283 local topHint = _player.PlayerGui.topHint
3284 topHint.Add.Label.Value = label
3285 topHint.Add.Width.Value = 3 -- widest width
3286 topHint.Add.Time.Value = 5
3287 topHint.Add.Disabled = true
3288 topHint.Add.Disabled = false
3289 end
3290
3291end
3292
3293function getPlayer()
3294 return game.Players:GetPlayerFromCharacter(script.Parent.Parent)
3295end
3296
3297function getHumanoid()
3298 local player = game.Players:GetPlayerFromCharacter(script.Parent.Parent)
3299 if player then
3300 waitForProperty(player,"Character")
3301 waitForChild(player.Character,"Humanoid")
3302 return player.Character.Humanoid
3303 else
3304 return nil
3305 end
3306end
3307
3308function buildSetButton(name, setId, setImageId, i, count)
3309
3310 local button = currStampGui.InsertPanel.Sets.SetsLists.SetButtonExample:Clone()
3311 button.Text = name
3312 button.Name = "SetButton"
3313 button.Visible = true
3314
3315 local setValue = Instance.new("IntValue")
3316 setValue.Name = "SetId"
3317 setValue.Value = setId
3318 setValue.Parent = button
3319
3320 local setName = Instance.new("StringValue")
3321 setName.Name = "SetName"
3322 setName.Value = name
3323 setName.Parent = button
3324
3325 return button
3326end
3327
3328
3329function previousSetPage()
3330 local newIndex = math.max(0, Data.Category[Data.CurrentCategory].Index - (InsertRows * InsertColumns))
3331 setSetIndex(newIndex)
3332end
3333
3334
3335function nextSetPage()
3336 local newIndex = math.max(0, Data.Category[Data.CurrentCategory].Index + (InsertRows * InsertColumns))
3337 setSetIndex(newIndex)
3338end
3339
3340function setInsertButtonImageBehavior(insertFrame, visible, name, assetId)
3341 if visible then
3342 insertFrame.AssetName.Value = name
3343 insertFrame.AssetId.Value = assetId
3344 local newImageUrl = SmallThumbnailUrl .. assetId
3345 if newImageUrl ~= insertFrame.Button.ButtonImage.Image then
3346 delay(0,function()
3347 game:GetService("ContentProvider"):Preload(SmallThumbnailUrl .. assetId)
3348 insertFrame.Button.ButtonImage.Image = SmallThumbnailUrl .. assetId
3349 end)
3350 end
3351 table.insert(insertButtonCons,
3352 insertFrame.Button.MouseButton1Click:connect(function()
3353 beginInsertAssetGui(insertFrame.AssetName.Value, insertFrame.AssetId.Value, insertFrame.Button.ButtonImage.Image, 1)
3354 end)
3355 )
3356 insertFrame.Visible = true
3357 else
3358 insertFrame.Visible = false
3359 end
3360end
3361
3362function setSetIndex(dataOffset)
3363
3364 Data.Category[Data.CurrentCategory].Index = dataOffset
3365
3366 InsertRows = math.floor(currStampGui.InsertPanel.ItemsFrame.AbsoluteSize.Y/buttonHeight)
3367 InsertColumns = math.floor(currStampGui.InsertPanel.ItemsFrame.AbsoluteSize.X/buttonWidth)
3368
3369 local PageSize = InsertRows * InsertColumns
3370 local contents = Data.Category[Data.CurrentCategory].Contents
3371 if contents then
3372
3373 local numOfPages = math.ceil((#contents)/(PageSize))
3374 local currPage = math.ceil((dataOffset/PageSize) + 1)
3375 currStampGui.InsertPanel.PagingControls.PageText.Text = tostring(currPage) .. "/" .. tostring(numOfPages)
3376 currStampGui.InsertPanel.PagingControls.PageText.Visible = (numOfPages > 1)
3377
3378 currStampGui.InsertPanel.PagingControls.PreviousPageButton.Visible = (numOfPages > 1) and dataOffset > 1
3379 currStampGui.InsertPanel.PagingControls.NextPageButton.Visible = (numOfPages > 1) and ((dataOffset - 1) + PageSize) < (#contents)
3380
3381 -- remove our buttons and their connections
3382 for i = 1, #insertButtons do
3383 insertButtons[i]:remove()
3384 end
3385 for i = 1, #insertButtonCons do
3386 pcall(function() insertButtonCons[i]:disconnect() end)
3387 end
3388
3389 insertButtonCons = {}
3390 insertButtons = {}
3391 local arrayPosition = 1
3392 for y = 1, InsertRows do
3393 for x = 1, InsertColumns do
3394 local buttonPosition = UDim2.new(0,(buttonWidth)*(x-1),0, (buttonHeight)*(y-1))
3395
3396 local buttonCon
3397 insertButtons[arrayPosition], buttonCon = buildInsertButton(buttonPosition)
3398 table.insert(insertButtonCons,buttonCon)
3399 insertButtons[arrayPosition].Parent = currStampGui.InsertPanel.ItemsFrame
3400 arrayPosition = arrayPosition + 1
3401 end
3402 end
3403
3404 Data.InsertButtons = insertButtons
3405
3406 for index = 1, PageSize do
3407 if insertButtons[index] then
3408 if contents[index + dataOffset] then
3409 local assetId
3410 if useAssetVersionId then
3411 assetId = contents[index + dataOffset].AssetVersionId
3412 else
3413 assetId = contents[index + dataOffset].AssetId
3414 end
3415 setInsertButtonImageBehavior(insertButtons[index], true, contents[index + dataOffset].Name, assetId)
3416 else
3417 setInsertButtonImageBehavior(insertButtons[index], false)
3418 end
3419 end
3420 end
3421 else
3422 currStampGui.InsertPanel.PagingControls.PreviousPageButton.Visible = false
3423 currStampGui.InsertPanel.PagingControls.NextPageButton.Visible = false
3424 end
3425
3426end
3427
3428function moveLoadingLeft()
3429 if (tick() - startTime > 5) and (currStampGui.Parent ~= nil) then
3430 loading = false
3431 cancelAssetPlacement()
3432 goToInsertPanel()
3433 end
3434 if loading then
3435 currStampGui.LoadDialog.LoadLabel:TweenPosition(UDim2.new(0, 0, 0, -8),Enum.EasingDirection.InOut,Enum.EasingStyle.Sine,0.7,true,function() moveLoadingRight() end)
3436 end
3437end
3438
3439function moveLoadingRight()
3440 if (tick() - startTime > 5) and (currStampGui.Parent ~= nil) then
3441 loading = false
3442 cancelAssetPlacement()
3443 goToInsertPanel()
3444 end
3445 if loading then
3446 currStampGui.LoadDialog.LoadLabel:TweenPosition(UDim2.new(0, 180, 0, -8),Enum.EasingDirection.InOut,Enum.EasingStyle.Sine,0.7,true,function() moveLoadingLeft() end)
3447 end
3448end
3449
3450function moveLoadingWindow()
3451 startTime = tick()
3452 currStampGui.LoadDialog.Visible = true
3453 loading = true
3454 moveLoadingRight()
3455end
3456
3457function cancelLoadingWindow()
3458 currStampGui.LoadDialog.Visible = false
3459 loading = false
3460end
3461
3462
3463function selectCategoryPage(buttons, page)
3464
3465 if buttons ~= Data.CurrentCategory then
3466 if Data.CurrentCategory then
3467 for key, button in pairs(Data.CurrentCategory) do
3468 button.Visible = false
3469 end
3470 end
3471
3472 Data.CurrentCategory = buttons
3473 if Data.Category[Data.CurrentCategory] == nil then
3474 Data.Category[Data.CurrentCategory] = {}
3475 if #buttons > 0 then
3476 selectSet(buttons[1], buttons[1].SetName.Value, buttons[1].SetId.Value, 0)
3477 end
3478 else
3479 Data.Category[Data.CurrentCategory].Button = nil
3480 selectSet(Data.Category[Data.CurrentCategory].ButtonFrame, Data.Category[Data.CurrentCategory].SetName, Data.Category[Data.CurrentCategory].SetId, Data.Category[Data.CurrentCategory].Index)
3481 end
3482 if Data.Main.FrameHeight then
3483 if Data.Category[Data.CurrentCategory].SetIndex then
3484 layoutSetButtons(Data.Main.FrameHeight, Data.Category[Data.CurrentCategory].SetIndex)
3485 else
3486 layoutSetButtons(Data.Main.FrameHeight, 1)
3487 end
3488 end
3489 end
3490
3491end
3492
3493function selectSet(button, setName, setId, setIndex)
3494
3495 if button and Data.Category[Data.CurrentCategory] ~= nil then
3496 if button ~= Data.Category[Data.CurrentCategory].Button then
3497 Data.Category[Data.CurrentCategory].Button = button
3498
3499 if SetCache[setId] == nil then
3500 SetCache[setId] = game:GetService("InsertService"):GetCollection(setId)
3501 end
3502 Data.Category[Data.CurrentCategory].Contents = SetCache[setId]
3503
3504 Data.Category[Data.CurrentCategory].SetName = setName
3505 Data.Category[Data.CurrentCategory].SetId = setId
3506 end
3507 setSetIndex(setIndex)
3508 end
3509
3510end
3511
3512
3513function selectCategory(button, category)
3514 selectCategoryPage(category, 0)
3515end
3516
3517
3518function processCategory(sets, setPanel)
3519 local setButtons = {}
3520 local numSkipped = 0
3521 for index, object in pairs(sets) do
3522 if not showAdminCategories.Value and object.Name == "Beta" then
3523 -- skip this if not an admin
3524 numSkipped = numSkipped + 1
3525 else
3526 setButtons[index - numSkipped] = buildSetButton(object.Name, object.CategoryId, object.ImageAssetId, index - numSkipped, #sets)
3527 setButtons[index - numSkipped].Parent = setPanel
3528 end
3529 end
3530 return setButtons
3531end
3532
3533
3534function setsNextPageClick(totalSetPages, gridSize)
3535 -- set our logic/gui correctly
3536 if currSetPage >= totalSetPages then return end
3537
3538 currSetPage = currSetPage + 1
3539 currStampGui.InsertPanel.PagingControls.PageText.Text = tostring(currSetPage) .. "/" .. tostring(totalSetPages)
3540 if currSetPage == totalSetPages then
3541 currStampGui.InsertPanel.PagingControls.NextPageButton.Visible = false
3542 currStampGui.InsertPanel.PagingControls.PreviousPageButton.Visible = true
3543 else
3544 Window.Sets.PagingControls.NextPageButton.Visible = true
3545 end
3546
3547 -- actually update the items
3548 makeCurrentSetsPageVisible(gridSize)
3549end
3550
3551function setsPrevPageClick(totalSetPages, gridSize)
3552 -- set our logic/gui correctly
3553 if currSetPage <= 1 then return end
3554
3555 currSetPage = currSetPage - 1
3556 currStampGui.InsertPanel.PagingControls.PageText.Text = tostring(currSetPage) .. "/" .. tostring(totalSetPages)
3557 if currSetPage == 1 then
3558 currStampGui.InsertPanel.PagingControls.NextPageButton.Visible = true
3559 currStampGui.InsertPanel.PagingControls.PreviousPageButton.Visible = false
3560 else
3561 currStampGui.InsertPanel.PagingControls.PreviousPageButton.Visible = true
3562 end
3563
3564 -- actually update the items
3565 makeCurrentSetsPageVisible(gridSize)
3566end
3567
3568function resetAllSetButtonSelection()
3569 local setButtons = Window.Sets.SetsLists:GetChildren()
3570 for i = 1, #setButtons do
3571 setButtons[i].Selected = false
3572 setButtons[i].BackgroundTransparency = 1
3573 setButtons[i].TextColor3 = Color3.new(1,1,1)
3574 setButtons[i].BackgroundColor3 = Color3.new(1,1,1)
3575 end
3576end
3577
3578function populateSetsFrame()
3579 local categories = #Data.UserCategoryButtons
3580 local robloxMaxCat = categories
3581
3582 -- don't do anything until window is visible (otherwise we won't layout anything!)
3583 while Window.Sets.SetsLists.AbsoluteSize.X <= 0 do
3584 Window.Sets.SetsLists.Changed:wait()
3585 end
3586 while Window.Sets.SetsLists.SetButtonExample.AbsoluteSize.X <= 0 do
3587 Window.Sets.SetsLists.SetButtonExample.Changed:wait()
3588 end
3589
3590 local totalColumns = math.floor(Window.Sets.SetsLists.AbsoluteSize.X/Window.Sets.SetsLists.SetButtonExample.AbsoluteSize.X)
3591 local totalRows = math.floor(Window.Sets.SetsLists.AbsoluteSize.Y/Window.Sets.SetsLists.SetButtonExample.AbsoluteSize.Y)
3592
3593 local currRow = 0
3594 local buttonVisible = true
3595
3596 local masterCategory = 1
3597 for i = 1, categories do
3598 local userCategory = masterCategory -- needed to maintain local scope for categories in event listeners below
3599 local button = Window.Sets.SetsLists.SetButtonExample:clone()
3600
3601 button.Name = "Set" .. tostring(Data.UserCategoryButtons[userCategory].SetName.Value) .. "Button"
3602 button.Parent = Window.Sets.SetsLists
3603 button.Position = UDim2.new(0,5,0,currRow * button.AbsoluteSize.Y)
3604 button.Visible = buttonVisible
3605 button.Text = tostring(Data.UserCategoryButtons[userCategory].SetName.Value)
3606
3607 if i == 1 then
3608 button.Selected = true
3609 button.BackgroundColor3 = Color3.new(0,204/255,0)
3610 button.TextColor3 = Color3.new(0,0,0)
3611 button.BackgroundTransparency = 0
3612 end
3613
3614 button.MouseEnter:connect(function()
3615 if not button.Selected then
3616 button.BackgroundTransparency = 0
3617 button.TextColor3 = Color3.new(0,0,0)
3618 end
3619 end)
3620 button.MouseLeave:connect(function()
3621 if not button.Selected then
3622 button.BackgroundTransparency = 1
3623 button.TextColor3 = Color3.new(1,1,1)
3624 end
3625 end)
3626 setButtonCons[i] = button.MouseButton1Click:connect(function()
3627 resetAllSetButtonSelection()
3628 button.Selected = not button.Selected
3629 button.BackgroundColor3 = Color3.new(0,204/255,0)
3630 button.TextColor3 = Color3.new(0,0,0)
3631 button.BackgroundTransparency = 0
3632
3633 selectSet(button, button.Text, Data.UserCategoryButtons[userCategory].SetId.Value, 0)
3634 end)
3635
3636 masterCategory = masterCategory + 1
3637
3638 currRow = currRow + 1
3639 end
3640
3641 -- don't use example button as the first set!
3642 local example = currStampGui.InsertPanel.Sets.SetsLists.SetButtonExample
3643 currStampGui.InsertPanel.Sets.SetsLists.SetButtonExample.Parent = nil
3644 local buttons = currStampGui.InsertPanel.Sets.SetsLists:GetChildren()
3645 example.Parent = currStampGui.InsertPanel.Sets.SetsLists
3646
3647 -- set first category as loaded for default
3648 selectSet(buttons[1], buttons[1].Text, Data.UserCategoryButtons[1].SetId.Value, 0)
3649 selectCategory(buttons[1], Data.UserCategoryButtons)
3650end
3651
3652
3653function layoutSetButtons(frameHeight, setIndex)
3654 Data.Main.FrameHeight = frameHeight
3655 Data.Main.InsertSets = math.floor(frameHeight / (height*2))
3656 if #Data.CurrentCategory > Data.Main.InsertSets then
3657 --Steal one entry since we have too many things
3658 Data.Main.InsertSets = Data.Main.InsertSets - 1
3659 end
3660
3661 Data.Category[Data.CurrentCategory].SetIndex = setIndex
3662end
3663
3664
3665function showLargePreview(insertButton)
3666 if insertButton:FindFirstChild("AssetId") then
3667 delay(0,function()
3668 game:GetService("ContentProvider"):Preload(LargeThumbnailUrl .. tostring(insertButton.AssetId.Value))
3669 currStampGui.InsertPanel.ItemPreview.LargePreview.Image = LargeThumbnailUrl .. tostring(insertButton.AssetId.Value)
3670 end)
3671 end
3672 if insertButton:FindFirstChild("AssetName") then
3673 currStampGui.InsertPanel.ItemPreview.TextPanel.RolloverText.Text = insertButton.AssetName.Value
3674 end
3675end
3676
3677
3678function buildInsertButton(buttonPosition)
3679 local insertButton = currStampGui.InsertPanel.ItemsFrame.InsertAssetButtonExample:clone()
3680 insertButton.Position = buttonPosition
3681 insertButton.Name = "InsertAssetButton"
3682 insertButton.Visible = true
3683
3684 local mouseEnterCon = insertButton.MouseEnter:connect(function()
3685 lastEnter = insertButton
3686 delay(0.1,function()
3687 if lastEnter == insertButton then
3688 showLargePreview(insertButton)
3689 end
3690 end)
3691 end)
3692 return insertButton, mouseEnterCon
3693end
3694
3695function minimizeStamperPanel()
3696 currStampGui.StamperPanel.StamperButtons.Visible = false
3697 currStampGui.StamperPanel.MinimizeButton.Visible = false
3698 if currStampGui.Parent ~= nil then
3699 currStampGui.StamperPanel:TweenSizeAndPosition(UDim2.new(0,0,0,0), UDim2.new(0.5,0,1,-92),Enum.EasingDirection.InOut,Enum.EasingStyle.Sine,0.5,true)
3700 delay(0.5,function()
3701 currStampGui.StamperPanel.RestoreButton.Visible = true
3702 end)
3703 end
3704end
3705
3706function restoreStamperPanel()
3707 currStampGui.StamperPanel.RestoreButton.Visible = false
3708 if currStampGui.Parent ~= nil then
3709 currStampGui.StamperPanel:TweenSizeAndPosition(UDim2.new(0,350,0,48), UDim2.new(0.5,-175,1,-135), Enum.EasingDirection.InOut,Enum.EasingStyle.Sine,0.5,true)
3710 delay(0.5,function()
3711 currStampGui.StamperPanel.StamperButtons.Visible = true
3712 currStampGui.StamperPanel.MinimizeButton.Visible = true
3713 end)
3714 end
3715end
3716
3717function setUpStamperGui()
3718 pcall(function() currStampGui.InsertPanel.CancelButton.Modal = true end)
3719 Window.Sets = currStampGui.InsertPanel.Sets
3720
3721 cloneButtonCon = currStampGui.StamperPanel.StamperButtons.CloneButton.MouseButton1Click:connect(goToClone)
3722 partListClickCon = currStampGui.StamperPanel.StamperButtons.PartsButton.MouseButton1Click:connect(goToInsertPanel)
3723
3724 Data.Main = {}
3725 Data.Category = {}
3726 Data.Stamp = {}
3727
3728 Data.BaseCategoryButtons = {}
3729 local userData = {}
3730 for id = 1, #userIdsForStamperParts do
3731 local newUserData = game:GetService("InsertService"):GetUserCategories(userIdsForStamperParts[id].Value)
3732 if newUserData and #newUserData > 2 then
3733 -- start at #3 to skip over My Decals and My Models for each account
3734 for category = 3, #newUserData do
3735 table.insert(userData, newUserData[category])
3736 end
3737 end
3738 end
3739
3740 if userData then
3741 Data.UserCategoryButtons = processCategory(userData, setPanel)
3742 end
3743
3744 guiChangedCon = currStampGui.Changed:connect(function(prop)
3745 if prop == "AbsoluteSize" then
3746 wait()
3747 setSetIndex(0)
3748 end
3749 end)
3750
3751 InsertRows = math.floor(currStampGui.InsertPanel.ItemsFrame.AbsoluteSize.Y/buttonHeight)
3752 InsertColumns = math.floor(currStampGui.InsertPanel.ItemsFrame.AbsoluteSize.X/buttonWidth)
3753
3754 populateSetsFrame()
3755
3756 setsPrevPageCon = currStampGui.InsertPanel.PagingControls.PreviousPageButton.MouseButton1Click:connect(function() previousSetPage() end)
3757 setsNextPageCon = currStampGui.InsertPanel.PagingControls.NextPageButton.MouseButton1Click:connect(function() nextSetPage() end)
3758
3759 insertPanelCloseCon = currStampGui.InsertPanel.CancelButton.MouseButton1Click:connect(function()
3760 closeInsertPanel()
3761 closeClonePanel()
3762 reloadCurrentAsset()
3763 end)
3764
3765 minimizeCon = currStampGui.StamperPanel.MinimizeButton.MouseButton1Click:connect(function() minimizeStamperPanel() end)
3766 restoreCon = currStampGui.StamperPanel.RestoreButton.MouseButton1Click:connect(function() restoreStamperPanel() end)
3767end
3768
3769-- signal to scripts we are ready to start manipulating objects
3770function signalStamperScript(assetName, assetId, image, stampMode)
3771 insertAsset.AssetName.Value = assetName
3772 insertAsset.AssetId.Value = assetId
3773 insertAsset.Image.Value = image
3774 insertAsset.StampMode.Value = stampMode
3775 insertAsset.Updated.Value = true
3776end
3777
3778function reloadCurrentAsset()
3779 variables.ReloadCurrentAsset.Value = true
3780end
3781
3782
3783function beginInsertAssetGui(assetName, assetId, image, stampMode)
3784 Data.Stamp.StampMode = stampMode
3785 closeInsertPanel()
3786 signalStamperScript("",0,"","",false)
3787 moveLoadingWindow()
3788 cancelAssetPlacement()
3789 signalStamperScript(assetName, assetId, image, stampMode)
3790end
3791
3792
3793function cancelAssetLoad()
3794 Data.Loading.Cancelled = true
3795 insertComplete()
3796 gInitial90DegreeRotations = 0
3797end
3798
3799function inBounds2(part)
3800 -- part must have a position property
3801 local xOne= buildingPlate.Position.x + buildingPlate.Size.x/2
3802 local xTwo = buildingPlate.Position.x - buildingPlate.Size.x/2
3803 local zOne = buildingPlate.Position.z + buildingPlate.Size.z/2
3804 local zTwo = buildingPlate.Position.z - buildingPlate.Size.z/2
3805 if part.Position.x > xOne or part.Position.x < xTwo then return false end
3806 if part.Position.z > zOne or part.Position.z < zTwo then return false end
3807 return true
3808end
3809
3810
3811-- For Restricting Stamper Tool (isRestricted)
3812function showHelp_pointToBuildingplate()
3813
3814 if(buildingPlate==nil) then
3815 hint("All building areas are taken. If you want to build, leave and join again.")
3816 else
3817 -- only show one waypoint at a time (because kids will click a million times outside their plate)
3818 hint("Stamper Tool only works in your area.")
3819 if(not waypointShowing) then
3820 waypointShowing = true
3821 local _character = Tool.Parent
3822 waitForChild(_character, "Torso")
3823 _player = game.Players:GetPlayerFromCharacter(_character)
3824 _player.PlayerGui.showBaseplateWaypoint.target.Value = buildingPlate
3825 _player.PlayerGui.showBaseplateWaypoint.Disabled = true
3826 _player.PlayerGui.showBaseplateWaypoint.Disabled = false
3827 -- Wait until character moves in bounds (check every 2 seconds)
3828 while(not inBounds2(_character.Torso) and isEquipped) do wait(2) end
3829 -- Then hide the waypoint
3830 hideHelp_pointToBuildingplate()
3831 end
3832 end
3833
3834end
3835
3836
3837function showHelp_tooManyParts()
3838 hint("You have reached maximum number of parts! Delete some to put more down.")
3839end
3840
3841
3842function hideHelp_pointToBuildingplate()
3843 waypointShowing = false
3844 _player.PlayerGui.hideBaseplateWaypoint.Disabled = true
3845 _player.PlayerGui.hideBaseplateWaypoint.Disabled = false
3846end
3847
3848
3849function setUpRestrictions()
3850 playerModel = game.Workspace.ActiveParts:FindFirstChild(player.Name .. "'s parts")
3851
3852 local takenAreas = game.Workspace.BuildingAreas:GetChildren()
3853
3854 waitForChild(player, "playerNumber")
3855
3856 if(player.playerNumber.Value == 0) then
3857 buildingPlate = nil
3858 partModel = nil
3859 else
3860 waitForChild(game.Workspace, "BuildingAreas")
3861 local buildingAreas = game.Workspace.BuildingAreas
3862 waitForChild(buildingAreas, "Area"..tostring(player.playerNumber.Value))
3863 local targetArea = buildingAreas:FindFirstChild("Area"..tostring(player.playerNumber.Value))
3864 waitForChild(targetArea, "PlayerArea")
3865 waitForChild(targetArea.PlayerArea, "BasePlate")
3866
3867 buildingPlate = targetArea.PlayerArea.BasePlate
3868 partModel = targetArea.PlayerArea
3869
3870 end
3871
3872 -- Check if player is standing in bounds, if not show error
3873 local _character = Tool.Parent
3874 waitForChild(_character, "Torso")
3875 _player = game.Players:GetPlayerFromCharacter(_character)
3876 if(buildingPlate~=nil) then
3877 if(not inBounds2(_character.Torso)) then
3878 showHelp_pointToBuildingplate()
3879 end
3880 else
3881 -- You have no building plate.
3882 hint("All building areas are taken. If you want to build, leave and join again.")
3883 end
3884end
3885
3886function onInsertKeyDown(key)
3887 if loading then return end -- don't try to switch while we're loading
3888
3889 key = string.lower(key)
3890
3891 -- go to mru buttons
3892 if key == 'f' then
3893 mruButtonClick(1)
3894 elseif key == 'g' then
3895 mruButtonClick(2)
3896 elseif key == 'h' then
3897 mruButtonClick(3)
3898 elseif key == 'j' then
3899 mruButtonClick(4)
3900 end
3901
3902end
3903
3904function onEquippedLocal(mouse)
3905 player = getPlayer()
3906 if not player then
3907 return
3908 end
3909 if Tool.PlayerOwner.Value and Tool.PlayerOwner.Value ~= player then return end
3910
3911 -- For Restricting Stamper Tool
3912 if isRestricted.Value then
3913 setUpRestrictions()
3914 end
3915
3916 Mouse = mouse
3917 if not firstEquip and currStampGui and Tool.SavedState.Value and Tool.PlayerOwner.Value == getPlayer() and Data and Data.FullyLoaded then
3918
3919 currStampGui.Parent = getPlayer().PlayerGui
3920
3921 if mode == 1 then -- if we were stamping, keep going
3922 signalStamperScript(insertAsset.AssetName.Value, insertAsset.AssetId.Value, insertAsset.Image.Value, true)
3923 elseif mode == 2 then -- time to clone
3924 goToClone()
3925 end
3926
3927 else
3928 if firstEquip then
3929 Tool.PlayerOwner.Value = player
3930 firstEquip = false
3931 end
3932 CancelDuringLoad = false
3933 resetCons()
3934
3935 Data = {}
3936 Data.FullyLoaded = false
3937
3938 Window = {}
3939 Window.Sets = {}
3940
3941 currStampGui = stamperGui:clone()
3942 currStampGui.Parent = getPlayer().PlayerGui
3943 wait()
3944 setUpStamperGui()
3945
3946 if not(CancelDuringLoad) then
3947 currStampGui.Parent = getPlayer().PlayerGui
3948 Tool.SavedState.Value = currStampGui
3949 end
3950
3951 Data.FullyLoaded = true
3952 end
3953
3954 Mouse.KeyDown:connect(onInsertKeyDown)
3955end
3956
3957
3958function onUnequippedLocal()
3959 if currStampGui then
3960 Tool.SavedState.Value = currStampGui
3961 currStampGui.Parent = nil
3962 end
3963
3964 pcall(function()
3965 cancelAssetPlacement()
3966 Data.Loading.Cancelled = true
3967 end)
3968 CancelDuringLoad = true
3969end
3970
3971
3972function killConnection(connection)
3973 if connection then connection:disconnect() end
3974end
3975
3976
3977function resetCons()
3978 killConnection(guiChangedCon)
3979 killConnection(cloneButtonCon)
3980 killConnection(partListClickCon)
3981 killConnection(itemFrameChangedCon)
3982 killConnection(setsPrevPageCon)
3983 killConnection(setsNextPageCon)
3984 killConnection(insertPanelCloseCon)
3985 killConnection(minimizeCon)
3986 killConnection(restoreCon)
3987end
3988
3989
3990function onAncestryChanged(child,parent)
3991 if Tool.PlayerOwner.Value and not Tool:IsDescendantOf(Tool.PlayerOwner.Value) and not Tool:IsDescendantOf(Tool.PlayerOwner.Value.Character) then
3992 --Tool was dropped in some way, so we need to nuke our external state
3993 Tool.SavedState.Value = nil
3994 resetCons()
3995 end
3996end
3997
3998
3999function getMaxNumOfRecentParts()
4000 return maxRecentParts
4001end
4002
4003
4004function pushRecentStackBack()
4005 for i = getMaxNumOfRecentParts() - 1, 1, -1 do
4006 recentPartStack[i + 1].AssetNameValue = recentPartStack[i].AssetNameValue
4007 recentPartStack[i + 1].AssetIdValue = recentPartStack[i].AssetIdValue
4008 recentPartStack[i + 1].InsertFrameButtonImage = recentPartStack[i].InsertFrameButtonImage
4009 end
4010end
4011
4012
4013function clearMRUList()
4014 local buttons = currStampGui.StamperPanel.StamperButtons.RecentFrame:GetChildren()
4015 for i = 1, #buttons do
4016 if recentPartStackCons[i] then recentPartStackCons[i]:disconnect() end
4017 buttons[i].Visible = false
4018 end
4019end
4020
4021
4022function mruButtonClick(position)
4023 if recentPartStack[position].AssetIdValue == insertAsset.AssetId.Value then return end -- already stamping part
4024 -- get rid of old part
4025 signalStamperScript("",0,"","",false)
4026
4027 --Show the dialog window
4028 moveLoadingWindow()
4029 signalStamperScript(recentPartStack[position].AssetNameValue, recentPartStack[position].AssetIdValue, recentPartStack[position].InsertFrameButtonImage, true)
4030end
4031
4032
4033function insertMRUButton(position)
4034 local mruButton = currStampGui.StamperPanel.StamperButtons.RecentFrame:FindFirstChild("Button" .. tostring(position))
4035 mruButton.ButtonImage.Image = recentPartStack[position].InsertFrameButtonImage
4036 if mruButton.ButtonImage.Image == "" then
4037 mruButton.Text = recentPartStack[position].AssetNameValue
4038 end
4039
4040 if recentPartStackCons[position] then pcall(function() recentPartStackCons[position]:Disconnect() end) end
4041 recentPartStackCons[position] = mruButton.MouseButton1Click:connect(function() mruButtonClick(position) end)
4042 mruButton.Visible = true
4043end
4044
4045
4046function refreshRecentParts()
4047 if insertAsset.Image.Value == "" then return end -- we don't have an asset, get out of here
4048 if not recentPartStack then return end -- if somehow not created yet (recentPartStack[i] calls below were nil somehow)
4049
4050 local numOfRecentParts = getMaxNumOfRecentParts()
4051
4052 for i = 1,numOfRecentParts do
4053 if insertAsset.AssetId and recentPartStack[i] and insertAsset.AssetId.Value == recentPartStack[i].AssetIdValue then -- already have part, don't push back
4054 return
4055 end
4056 end
4057
4058 pushRecentStackBack()
4059
4060 -- update our stack to show previously allocated part
4061 recentPartStack[1].AssetNameValue = insertAsset.AssetName.Value
4062 recentPartStack[1].AssetIdValue = insertAsset.AssetId.Value
4063 recentPartStack[1].InsertFrameButtonImage = insertAsset.Image.Value
4064
4065 clearMRUList()
4066
4067 for i = 1, numOfRecentParts do
4068 if recentPartStack[i] and recentPartStack[i].AssetIdValue ~= "" then
4069 insertMRUButton(i)
4070 end
4071 end
4072end
4073
4074
4075function updateGui(type)
4076 if type == "Main" then
4077 goToInsertPanel()
4078 elseif type == "EyeDropper" then
4079 goToClone()
4080 elseif type == "SideDialog" then
4081 goToStamp()
4082 end
4083end
4084----------------------------------------------------------------------------------------
4085
4086
4087
4088-- Lua Start Execution
4089setAssetUrls()
4090
4091Tool.Equipped:connect(onEquippedLocal)
4092Tool.Unequipped:connect(onUnequippedLocal)
4093Tool.AncestryChanged:connect(onAncestryChanged)
4094
4095waitForChild(variables, "SwitchLoaderToDialog")
4096variables.SwitchLoaderToDialog.Changed:connect(function(prop)
4097 if variables.SwitchLoaderToDialog.Value == true then
4098 updateGui(variables.SwitchLoaderToDialog.DialogType.Value)
4099 variables.SwitchLoaderToDialog.Value = false
4100 end
4101
4102end)
4103
4104waitForChild(variables, "ShowInvalidPlacement")
4105variables.ShowInvalidPlacement.Changed:connect(function(prop)
4106 if variables.ShowInvalidPlacement.Value == true then
4107 showHelp_pointToBuildingplate()
4108 showBaseplateGuideArrows()
4109 variables.ShowInvalidPlacement.Value = false
4110 end
4111end)
4112
4113waitForChild(variables, "ShowMaxedOut")
4114variables.ShowMaxedOut.Changed:connect(function(prop)
4115 if variables.ShowMaxedOut.Value == true then
4116 showHelp_tooManyParts()
4117 variables.ShowMaxedOut.Value = false
4118 end
4119end)
4120
4121waitForChild(variables, "Stamped")
4122variables.Stamped.Changed:connect(function()
4123 if variables.Stamped.Value == true then
4124 refreshRecentParts()
4125 end
4126end)
4127----------------------------------------------------------------------------------------
4128end,o106)
4129end))
4130o107 = Instance.new("LocalScript")
4131o107.Name = "Readme"
4132o107.Parent = o1
4133o107.Disabled = true
4134table.insert(cors,coroutine.create(function()
4135wait()
4136runDummyScript(function()
4137--[[
4138 Stamper Tool v1.0.0
4139
4140
4141 Welcome to the stamper tool readme!
4142 Currently, this doc only exists to show the Stamper Tool Version!
4143
4144]]
4145end,o107)
4146end))
4147mas.Parent = workspace
4148mas:MakeJoints()
4149local mas1 = mas:GetChildren()
4150for i=1,#mas1 do
4151 mas1[i].Parent = script
4152 ypcall(function() mas1[i]:MakeJoints() end)
4153end
4154mas:Destroy()
4155for i=1,#cors do
4156coroutine.resume(cors[i])
4157end