Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --Converted with ttyyuu12345's model to script plugin v4
- function sandbox(var,func)
- local env = getfenv(func)
- local newenv = setmetatable({},{
- __index = function(self,k)
- if k=="script" then
- return var
- else
- return env[k]
- end
- end,
- })
- setfenv(func,newenv)
- return func
- end
- cors = {}
- mas = Instance.new("Model",game:GetService("Lighting"))
- Tool0 = Instance.new("Tool")
- LocalScript1 = Instance.new("LocalScript")
- LocalScript2 = Instance.new("LocalScript")
- LocalScript3 = Instance.new("LocalScript")
- LocalScript4 = Instance.new("LocalScript")
- LocalScript5 = Instance.new("LocalScript")
- LocalScript6 = Instance.new("LocalScript")
- LocalScript7 = Instance.new("LocalScript")
- LocalScript8 = Instance.new("LocalScript")
- LocalScript9 = Instance.new("LocalScript")
- LocalScript10 = Instance.new("LocalScript")
- LocalScript11 = Instance.new("LocalScript")
- LocalScript12 = Instance.new("LocalScript")
- LocalScript13 = Instance.new("LocalScript")
- LocalScript14 = Instance.new("LocalScript")
- LocalScript15 = Instance.new("LocalScript")
- RemoteFunction16 = Instance.new("RemoteFunction")
- Script17 = Instance.new("Script")
- RemoteFunction18 = Instance.new("RemoteFunction")
- Script19 = Instance.new("Script")
- LocalScript20 = Instance.new("LocalScript")
- Part21 = Instance.new("Part")
- Decal22 = Instance.new("Decal")
- Decal23 = Instance.new("Decal")
- Decal24 = Instance.new("Decal")
- Decal25 = Instance.new("Decal")
- Decal26 = Instance.new("Decal")
- Decal27 = Instance.new("Decal")
- Camera28 = Instance.new("Camera")
- Frame29 = Instance.new("Frame")
- Frame30 = Instance.new("Frame")
- Frame31 = Instance.new("Frame")
- Frame32 = Instance.new("Frame")
- TextLabel33 = Instance.new("TextLabel")
- TextLabel34 = Instance.new("TextLabel")
- Frame35 = Instance.new("Frame")
- TextLabel36 = Instance.new("TextLabel")
- Frame37 = Instance.new("Frame")
- Frame38 = Instance.new("Frame")
- TextButton39 = Instance.new("TextButton")
- ImageLabel40 = Instance.new("ImageLabel")
- TextLabel41 = Instance.new("TextLabel")
- Frame42 = Instance.new("Frame")
- Frame43 = Instance.new("Frame")
- TextButton44 = Instance.new("TextButton")
- ImageLabel45 = Instance.new("ImageLabel")
- TextLabel46 = Instance.new("TextLabel")
- Frame47 = Instance.new("Frame")
- Frame48 = Instance.new("Frame")
- TextLabel49 = Instance.new("TextLabel")
- Frame50 = Instance.new("Frame")
- Frame51 = Instance.new("Frame")
- Frame52 = Instance.new("Frame")
- TextLabel53 = Instance.new("TextLabel")
- TextLabel54 = Instance.new("TextLabel")
- Frame55 = Instance.new("Frame")
- TextLabel56 = Instance.new("TextLabel")
- Frame57 = Instance.new("Frame")
- Frame58 = Instance.new("Frame")
- TextButton59 = Instance.new("TextButton")
- ImageLabel60 = Instance.new("ImageLabel")
- TextLabel61 = Instance.new("TextLabel")
- Frame62 = Instance.new("Frame")
- Frame63 = Instance.new("Frame")
- TextButton64 = Instance.new("TextButton")
- ImageLabel65 = Instance.new("ImageLabel")
- TextLabel66 = Instance.new("TextLabel")
- Frame67 = Instance.new("Frame")
- Frame68 = Instance.new("Frame")
- TextLabel69 = Instance.new("TextLabel")
- Frame70 = Instance.new("Frame")
- Frame71 = Instance.new("Frame")
- TextLabel72 = Instance.new("TextLabel")
- TextLabel73 = Instance.new("TextLabel")
- Frame74 = Instance.new("Frame")
- Frame75 = Instance.new("Frame")
- Frame76 = Instance.new("Frame")
- Frame77 = Instance.new("Frame")
- Frame78 = Instance.new("Frame")
- Frame79 = Instance.new("Frame")
- Frame80 = Instance.new("Frame")
- TextLabel81 = Instance.new("TextLabel")
- Frame82 = Instance.new("Frame")
- Frame83 = Instance.new("Frame")
- Frame84 = Instance.new("Frame")
- Frame85 = Instance.new("Frame")
- Frame86 = Instance.new("Frame")
- Frame87 = Instance.new("Frame")
- Frame88 = Instance.new("Frame")
- TextButton89 = Instance.new("TextButton")
- Frame90 = Instance.new("Frame")
- Frame91 = Instance.new("Frame")
- Frame92 = Instance.new("Frame")
- Frame93 = Instance.new("Frame")
- Frame94 = Instance.new("Frame")
- Frame95 = Instance.new("Frame")
- Frame96 = Instance.new("Frame")
- Frame97 = Instance.new("Frame")
- TextLabel98 = Instance.new("TextLabel")
- Frame99 = Instance.new("Frame")
- Frame100 = Instance.new("Frame")
- Frame101 = Instance.new("Frame")
- Frame102 = Instance.new("Frame")
- Frame103 = Instance.new("Frame")
- Frame104 = Instance.new("Frame")
- TextButton105 = Instance.new("TextButton")
- Frame106 = Instance.new("Frame")
- Frame107 = Instance.new("Frame")
- Frame108 = Instance.new("Frame")
- Frame109 = Instance.new("Frame")
- TextLabel110 = Instance.new("TextLabel")
- TextLabel111 = Instance.new("TextLabel")
- Frame112 = Instance.new("Frame")
- TextLabel113 = Instance.new("TextLabel")
- Frame114 = Instance.new("Frame")
- TextLabel115 = Instance.new("TextLabel")
- Frame116 = Instance.new("Frame")
- TextButton117 = Instance.new("TextButton")
- ImageLabel118 = Instance.new("ImageLabel")
- Frame119 = Instance.new("Frame")
- TextBox120 = Instance.new("TextBox")
- Frame121 = Instance.new("Frame")
- TextLabel122 = Instance.new("TextLabel")
- Frame123 = Instance.new("Frame")
- TextButton124 = Instance.new("TextButton")
- Frame125 = Instance.new("Frame")
- ImageLabel126 = Instance.new("ImageLabel")
- TextBox127 = Instance.new("TextBox")
- Frame128 = Instance.new("Frame")
- Frame129 = Instance.new("Frame")
- TextLabel130 = Instance.new("TextLabel")
- Frame131 = Instance.new("Frame")
- Frame132 = Instance.new("Frame")
- Frame133 = Instance.new("Frame")
- Frame134 = Instance.new("Frame")
- TextButton135 = Instance.new("TextButton")
- ImageLabel136 = Instance.new("ImageLabel")
- TextLabel137 = Instance.new("TextLabel")
- Frame138 = Instance.new("Frame")
- Frame139 = Instance.new("Frame")
- TextButton140 = Instance.new("TextButton")
- ImageLabel141 = Instance.new("ImageLabel")
- TextLabel142 = Instance.new("TextLabel")
- Frame143 = Instance.new("Frame")
- Frame144 = Instance.new("Frame")
- TextButton145 = Instance.new("TextButton")
- ImageLabel146 = Instance.new("ImageLabel")
- TextLabel147 = Instance.new("TextLabel")
- Frame148 = Instance.new("Frame")
- TextLabel149 = Instance.new("TextLabel")
- Frame150 = Instance.new("Frame")
- Frame151 = Instance.new("Frame")
- TextLabel152 = Instance.new("TextLabel")
- TextLabel153 = Instance.new("TextLabel")
- Frame154 = Instance.new("Frame")
- Frame155 = Instance.new("Frame")
- Frame156 = Instance.new("Frame")
- TextBox157 = Instance.new("TextBox")
- ImageLabel158 = Instance.new("ImageLabel")
- Frame159 = Instance.new("Frame")
- TextLabel160 = Instance.new("TextLabel")
- Frame161 = Instance.new("Frame")
- Frame162 = Instance.new("Frame")
- TextLabel163 = Instance.new("TextLabel")
- Frame164 = Instance.new("Frame")
- TextLabel165 = Instance.new("TextLabel")
- Frame166 = Instance.new("Frame")
- ImageLabel167 = Instance.new("ImageLabel")
- TextButton168 = Instance.new("TextButton")
- TextBox169 = Instance.new("TextBox")
- Frame170 = Instance.new("Frame")
- ImageLabel171 = Instance.new("ImageLabel")
- TextBox172 = Instance.new("TextBox")
- TextButton173 = Instance.new("TextButton")
- Frame174 = Instance.new("Frame")
- TextBox175 = Instance.new("TextBox")
- TextButton176 = Instance.new("TextButton")
- ImageLabel177 = Instance.new("ImageLabel")
- Frame178 = Instance.new("Frame")
- Frame179 = Instance.new("Frame")
- TextLabel180 = Instance.new("TextLabel")
- Frame181 = Instance.new("Frame")
- Frame182 = Instance.new("Frame")
- Frame183 = Instance.new("Frame")
- TextLabel184 = Instance.new("TextLabel")
- TextLabel185 = Instance.new("TextLabel")
- Frame186 = Instance.new("Frame")
- TextLabel187 = Instance.new("TextLabel")
- Frame188 = Instance.new("Frame")
- Frame189 = Instance.new("Frame")
- TextLabel190 = Instance.new("TextLabel")
- Frame191 = Instance.new("Frame")
- Frame192 = Instance.new("Frame")
- Frame193 = Instance.new("Frame")
- TextLabel194 = Instance.new("TextLabel")
- TextLabel195 = Instance.new("TextLabel")
- Frame196 = Instance.new("Frame")
- TextButton197 = Instance.new("TextButton")
- TextButton198 = Instance.new("TextButton")
- TextButton199 = Instance.new("TextButton")
- TextButton200 = Instance.new("TextButton")
- TextButton201 = Instance.new("TextButton")
- TextButton202 = Instance.new("TextButton")
- TextButton203 = Instance.new("TextButton")
- TextButton204 = Instance.new("TextButton")
- TextButton205 = Instance.new("TextButton")
- TextButton206 = Instance.new("TextButton")
- TextButton207 = Instance.new("TextButton")
- TextButton208 = Instance.new("TextButton")
- TextButton209 = Instance.new("TextButton")
- TextButton210 = Instance.new("TextButton")
- TextButton211 = Instance.new("TextButton")
- TextButton212 = Instance.new("TextButton")
- TextButton213 = Instance.new("TextButton")
- TextButton214 = Instance.new("TextButton")
- TextButton215 = Instance.new("TextButton")
- TextButton216 = Instance.new("TextButton")
- TextButton217 = Instance.new("TextButton")
- TextButton218 = Instance.new("TextButton")
- TextButton219 = Instance.new("TextButton")
- TextButton220 = Instance.new("TextButton")
- TextButton221 = Instance.new("TextButton")
- TextButton222 = Instance.new("TextButton")
- TextButton223 = Instance.new("TextButton")
- TextButton224 = Instance.new("TextButton")
- TextButton225 = Instance.new("TextButton")
- TextButton226 = Instance.new("TextButton")
- TextButton227 = Instance.new("TextButton")
- TextButton228 = Instance.new("TextButton")
- TextButton229 = Instance.new("TextButton")
- TextButton230 = Instance.new("TextButton")
- TextButton231 = Instance.new("TextButton")
- TextButton232 = Instance.new("TextButton")
- TextButton233 = Instance.new("TextButton")
- TextButton234 = Instance.new("TextButton")
- TextButton235 = Instance.new("TextButton")
- TextButton236 = Instance.new("TextButton")
- TextButton237 = Instance.new("TextButton")
- TextButton238 = Instance.new("TextButton")
- TextButton239 = Instance.new("TextButton")
- TextButton240 = Instance.new("TextButton")
- TextButton241 = Instance.new("TextButton")
- TextButton242 = Instance.new("TextButton")
- TextButton243 = Instance.new("TextButton")
- TextButton244 = Instance.new("TextButton")
- TextButton245 = Instance.new("TextButton")
- TextButton246 = Instance.new("TextButton")
- TextButton247 = Instance.new("TextButton")
- TextButton248 = Instance.new("TextButton")
- TextButton249 = Instance.new("TextButton")
- TextButton250 = Instance.new("TextButton")
- TextButton251 = Instance.new("TextButton")
- TextButton252 = Instance.new("TextButton")
- TextButton253 = Instance.new("TextButton")
- TextButton254 = Instance.new("TextButton")
- TextButton255 = Instance.new("TextButton")
- TextButton256 = Instance.new("TextButton")
- TextButton257 = Instance.new("TextButton")
- TextButton258 = Instance.new("TextButton")
- TextButton259 = Instance.new("TextButton")
- TextButton260 = Instance.new("TextButton")
- Frame261 = Instance.new("Frame")
- Frame262 = Instance.new("Frame")
- Frame263 = Instance.new("Frame")
- Frame264 = Instance.new("Frame")
- TextButton265 = Instance.new("TextButton")
- ImageLabel266 = Instance.new("ImageLabel")
- TextLabel267 = Instance.new("TextLabel")
- Frame268 = Instance.new("Frame")
- Frame269 = Instance.new("Frame")
- TextButton270 = Instance.new("TextButton")
- ImageLabel271 = Instance.new("ImageLabel")
- TextLabel272 = Instance.new("TextLabel")
- Frame273 = Instance.new("Frame")
- TextLabel274 = Instance.new("TextLabel")
- Frame275 = Instance.new("Frame")
- Frame276 = Instance.new("Frame")
- TextLabel277 = Instance.new("TextLabel")
- TextLabel278 = Instance.new("TextLabel")
- Frame279 = Instance.new("Frame")
- Frame280 = Instance.new("Frame")
- Frame281 = Instance.new("Frame")
- TextBox282 = Instance.new("TextBox")
- ImageLabel283 = Instance.new("ImageLabel")
- Frame284 = Instance.new("Frame")
- TextLabel285 = Instance.new("TextLabel")
- Frame286 = Instance.new("Frame")
- Frame287 = Instance.new("Frame")
- TextLabel288 = Instance.new("TextLabel")
- Frame289 = Instance.new("Frame")
- TextLabel290 = Instance.new("TextLabel")
- Frame291 = Instance.new("Frame")
- TextBox292 = Instance.new("TextBox")
- TextButton293 = Instance.new("TextButton")
- ImageLabel294 = Instance.new("ImageLabel")
- Frame295 = Instance.new("Frame")
- TextBox296 = Instance.new("TextBox")
- TextButton297 = Instance.new("TextButton")
- ImageLabel298 = Instance.new("ImageLabel")
- Frame299 = Instance.new("Frame")
- TextBox300 = Instance.new("TextBox")
- TextButton301 = Instance.new("TextButton")
- ImageLabel302 = Instance.new("ImageLabel")
- Frame303 = Instance.new("Frame")
- Frame304 = Instance.new("Frame")
- TextLabel305 = Instance.new("TextLabel")
- Frame306 = Instance.new("Frame")
- Frame307 = Instance.new("Frame")
- Frame308 = Instance.new("Frame")
- Frame309 = Instance.new("Frame")
- TextButton310 = Instance.new("TextButton")
- ImageLabel311 = Instance.new("ImageLabel")
- TextLabel312 = Instance.new("TextLabel")
- Frame313 = Instance.new("Frame")
- Frame314 = Instance.new("Frame")
- TextButton315 = Instance.new("TextButton")
- ImageLabel316 = Instance.new("ImageLabel")
- TextLabel317 = Instance.new("TextLabel")
- Frame318 = Instance.new("Frame")
- Frame319 = Instance.new("Frame")
- TextButton320 = Instance.new("TextButton")
- ImageLabel321 = Instance.new("ImageLabel")
- TextLabel322 = Instance.new("TextLabel")
- Frame323 = Instance.new("Frame")
- TextLabel324 = Instance.new("TextLabel")
- Frame325 = Instance.new("Frame")
- Frame326 = Instance.new("Frame")
- TextLabel327 = Instance.new("TextLabel")
- TextLabel328 = Instance.new("TextLabel")
- Frame329 = Instance.new("Frame")
- Frame330 = Instance.new("Frame")
- Frame331 = Instance.new("Frame")
- TextBox332 = Instance.new("TextBox")
- ImageLabel333 = Instance.new("ImageLabel")
- Frame334 = Instance.new("Frame")
- TextLabel335 = Instance.new("TextLabel")
- Frame336 = Instance.new("Frame")
- Frame337 = Instance.new("Frame")
- TextLabel338 = Instance.new("TextLabel")
- Frame339 = Instance.new("Frame")
- TextLabel340 = Instance.new("TextLabel")
- Frame341 = Instance.new("Frame")
- TextBox342 = Instance.new("TextBox")
- TextButton343 = Instance.new("TextButton")
- ImageLabel344 = Instance.new("ImageLabel")
- Frame345 = Instance.new("Frame")
- TextBox346 = Instance.new("TextBox")
- TextButton347 = Instance.new("TextButton")
- ImageLabel348 = Instance.new("ImageLabel")
- Frame349 = Instance.new("Frame")
- TextBox350 = Instance.new("TextBox")
- TextButton351 = Instance.new("TextButton")
- ImageLabel352 = Instance.new("ImageLabel")
- Frame353 = Instance.new("Frame")
- Frame354 = Instance.new("Frame")
- TextLabel355 = Instance.new("TextLabel")
- TextLabel356 = Instance.new("TextLabel")
- Frame357 = Instance.new("Frame")
- Frame358 = Instance.new("Frame")
- Frame359 = Instance.new("Frame")
- TextLabel360 = Instance.new("TextLabel")
- TextLabel361 = Instance.new("TextLabel")
- Frame362 = Instance.new("Frame")
- TextLabel363 = Instance.new("TextLabel")
- Frame364 = Instance.new("Frame")
- TextLabel365 = Instance.new("TextLabel")
- Frame366 = Instance.new("Frame")
- Frame367 = Instance.new("Frame")
- TextLabel368 = Instance.new("TextLabel")
- Frame369 = Instance.new("Frame")
- Frame370 = Instance.new("Frame")
- Frame371 = Instance.new("Frame")
- TextLabel372 = Instance.new("TextLabel")
- TextLabel373 = Instance.new("TextLabel")
- Frame374 = Instance.new("Frame")
- TextLabel375 = Instance.new("TextLabel")
- Frame376 = Instance.new("Frame")
- TextLabel377 = Instance.new("TextLabel")
- Frame378 = Instance.new("Frame")
- TextButton379 = Instance.new("TextButton")
- ImageLabel380 = Instance.new("ImageLabel")
- Frame381 = Instance.new("Frame")
- TextBox382 = Instance.new("TextBox")
- Frame383 = Instance.new("Frame")
- TextButton384 = Instance.new("TextButton")
- ImageLabel385 = Instance.new("ImageLabel")
- Frame386 = Instance.new("Frame")
- TextBox387 = Instance.new("TextBox")
- Frame388 = Instance.new("Frame")
- Frame389 = Instance.new("Frame")
- TextLabel390 = Instance.new("TextLabel")
- Frame391 = Instance.new("Frame")
- TextButton392 = Instance.new("TextButton")
- ImageLabel393 = Instance.new("ImageLabel")
- Frame394 = Instance.new("Frame")
- TextBox395 = Instance.new("TextBox")
- Frame396 = Instance.new("Frame")
- TextLabel397 = Instance.new("TextLabel")
- Frame398 = Instance.new("Frame")
- Frame399 = Instance.new("Frame")
- TextButton400 = Instance.new("TextButton")
- ImageLabel401 = Instance.new("ImageLabel")
- TextLabel402 = Instance.new("TextLabel")
- Frame403 = Instance.new("Frame")
- TextButton404 = Instance.new("TextButton")
- ImageLabel405 = Instance.new("ImageLabel")
- TextLabel406 = Instance.new("TextLabel")
- Frame407 = Instance.new("Frame")
- Frame408 = Instance.new("Frame")
- TextLabel409 = Instance.new("TextLabel")
- Frame410 = Instance.new("Frame")
- Frame411 = Instance.new("Frame")
- Frame412 = Instance.new("Frame")
- Frame413 = Instance.new("Frame")
- Frame414 = Instance.new("Frame")
- TextButton415 = Instance.new("TextButton")
- TextBox416 = Instance.new("TextBox")
- Frame417 = Instance.new("Frame")
- TextButton418 = Instance.new("TextButton")
- Frame419 = Instance.new("Frame")
- Frame420 = Instance.new("Frame")
- TextButton421 = Instance.new("TextButton")
- Frame422 = Instance.new("Frame")
- TextLabel423 = Instance.new("TextLabel")
- Frame424 = Instance.new("Frame")
- Frame425 = Instance.new("Frame")
- Frame426 = Instance.new("Frame")
- TextLabel427 = Instance.new("TextLabel")
- TextLabel428 = Instance.new("TextLabel")
- Frame429 = Instance.new("Frame")
- TextButton430 = Instance.new("TextButton")
- Frame431 = Instance.new("Frame")
- TextButton432 = Instance.new("TextButton")
- Frame433 = Instance.new("Frame")
- Frame434 = Instance.new("Frame")
- Frame435 = Instance.new("Frame")
- TextLabel436 = Instance.new("TextLabel")
- Frame437 = Instance.new("Frame")
- Frame438 = Instance.new("Frame")
- Frame439 = Instance.new("Frame")
- Frame440 = Instance.new("Frame")
- TextLabel441 = Instance.new("TextLabel")
- TextLabel442 = Instance.new("TextLabel")
- Frame443 = Instance.new("Frame")
- TextLabel444 = Instance.new("TextLabel")
- ImageButton445 = Instance.new("ImageButton")
- Frame446 = Instance.new("Frame")
- TextButton447 = Instance.new("TextButton")
- TextButton448 = Instance.new("TextButton")
- Frame449 = Instance.new("Frame")
- Frame450 = Instance.new("Frame")
- Frame451 = Instance.new("Frame")
- TextLabel452 = Instance.new("TextLabel")
- Frame453 = Instance.new("Frame")
- TextButton454 = Instance.new("TextButton")
- ImageLabel455 = Instance.new("ImageLabel")
- Frame456 = Instance.new("Frame")
- TextBox457 = Instance.new("TextBox")
- Frame458 = Instance.new("Frame")
- TextButton459 = Instance.new("TextButton")
- ImageLabel460 = Instance.new("ImageLabel")
- Frame461 = Instance.new("Frame")
- TextBox462 = Instance.new("TextBox")
- Frame463 = Instance.new("Frame")
- TextButton464 = Instance.new("TextButton")
- ImageLabel465 = Instance.new("ImageLabel")
- Frame466 = Instance.new("Frame")
- TextBox467 = Instance.new("TextBox")
- ImageButton468 = Instance.new("ImageButton")
- Frame469 = Instance.new("Frame")
- Frame470 = Instance.new("Frame")
- Frame471 = Instance.new("Frame")
- Frame472 = Instance.new("Frame")
- Frame473 = Instance.new("Frame")
- TextLabel474 = Instance.new("TextLabel")
- Frame475 = Instance.new("Frame")
- TextButton476 = Instance.new("TextButton")
- ImageLabel477 = Instance.new("ImageLabel")
- Frame478 = Instance.new("Frame")
- TextBox479 = Instance.new("TextBox")
- Frame480 = Instance.new("Frame")
- TextLabel481 = Instance.new("TextLabel")
- Frame482 = Instance.new("Frame")
- TextButton483 = Instance.new("TextButton")
- ImageLabel484 = Instance.new("ImageLabel")
- Frame485 = Instance.new("Frame")
- TextBox486 = Instance.new("TextBox")
- Frame487 = Instance.new("Frame")
- TextLabel488 = Instance.new("TextLabel")
- Frame489 = Instance.new("Frame")
- TextButton490 = Instance.new("TextButton")
- ImageLabel491 = Instance.new("ImageLabel")
- Frame492 = Instance.new("Frame")
- TextBox493 = Instance.new("TextBox")
- Frame494 = Instance.new("Frame")
- TextLabel495 = Instance.new("TextLabel")
- Frame496 = Instance.new("Frame")
- TextLabel497 = Instance.new("TextLabel")
- Frame498 = Instance.new("Frame")
- Frame499 = Instance.new("Frame")
- TextButton500 = Instance.new("TextButton")
- ImageLabel501 = Instance.new("ImageLabel")
- TextLabel502 = Instance.new("TextLabel")
- Frame503 = Instance.new("Frame")
- Frame504 = Instance.new("Frame")
- TextButton505 = Instance.new("TextButton")
- ImageLabel506 = Instance.new("ImageLabel")
- TextLabel507 = Instance.new("TextLabel")
- TextLabel508 = Instance.new("TextLabel")
- Frame509 = Instance.new("Frame")
- TextLabel510 = Instance.new("TextLabel")
- ImageButton511 = Instance.new("ImageButton")
- Frame512 = Instance.new("Frame")
- TextButton513 = Instance.new("TextButton")
- TextButton514 = Instance.new("TextButton")
- Frame515 = Instance.new("Frame")
- Frame516 = Instance.new("Frame")
- Frame517 = Instance.new("Frame")
- TextLabel518 = Instance.new("TextLabel")
- Frame519 = Instance.new("Frame")
- TextButton520 = Instance.new("TextButton")
- ImageLabel521 = Instance.new("ImageLabel")
- Frame522 = Instance.new("Frame")
- TextBox523 = Instance.new("TextBox")
- Frame524 = Instance.new("Frame")
- TextButton525 = Instance.new("TextButton")
- ImageLabel526 = Instance.new("ImageLabel")
- Frame527 = Instance.new("Frame")
- TextBox528 = Instance.new("TextBox")
- Frame529 = Instance.new("Frame")
- TextButton530 = Instance.new("TextButton")
- ImageLabel531 = Instance.new("ImageLabel")
- Frame532 = Instance.new("Frame")
- TextBox533 = Instance.new("TextBox")
- ImageButton534 = Instance.new("ImageButton")
- Frame535 = Instance.new("Frame")
- Frame536 = Instance.new("Frame")
- Frame537 = Instance.new("Frame")
- Frame538 = Instance.new("Frame")
- Frame539 = Instance.new("Frame")
- TextLabel540 = Instance.new("TextLabel")
- Frame541 = Instance.new("Frame")
- TextButton542 = Instance.new("TextButton")
- ImageLabel543 = Instance.new("ImageLabel")
- Frame544 = Instance.new("Frame")
- TextBox545 = Instance.new("TextBox")
- Frame546 = Instance.new("Frame")
- TextLabel547 = Instance.new("TextLabel")
- Frame548 = Instance.new("Frame")
- TextButton549 = Instance.new("TextButton")
- ImageLabel550 = Instance.new("ImageLabel")
- Frame551 = Instance.new("Frame")
- TextBox552 = Instance.new("TextBox")
- Frame553 = Instance.new("Frame")
- TextLabel554 = Instance.new("TextLabel")
- Frame555 = Instance.new("Frame")
- Frame556 = Instance.new("Frame")
- TextButton557 = Instance.new("TextButton")
- ImageLabel558 = Instance.new("ImageLabel")
- TextLabel559 = Instance.new("TextLabel")
- Frame560 = Instance.new("Frame")
- Frame561 = Instance.new("Frame")
- TextButton562 = Instance.new("TextButton")
- ImageLabel563 = Instance.new("ImageLabel")
- TextLabel564 = Instance.new("TextLabel")
- Frame565 = Instance.new("Frame")
- ImageButton566 = Instance.new("ImageButton")
- ImageLabel567 = Instance.new("ImageLabel")
- ImageButton568 = Instance.new("ImageButton")
- Frame569 = Instance.new("Frame")
- ImageLabel570 = Instance.new("ImageLabel")
- Frame571 = Instance.new("Frame")
- TextLabel572 = Instance.new("TextLabel")
- Frame573 = Instance.new("Frame")
- TextButton574 = Instance.new("TextButton")
- ImageLabel575 = Instance.new("ImageLabel")
- TextBox576 = Instance.new("TextBox")
- Frame577 = Instance.new("Frame")
- Frame578 = Instance.new("Frame")
- Frame579 = Instance.new("Frame")
- TextLabel580 = Instance.new("TextLabel")
- Frame581 = Instance.new("Frame")
- TextButton582 = Instance.new("TextButton")
- ImageLabel583 = Instance.new("ImageLabel")
- TextBox584 = Instance.new("TextBox")
- Frame585 = Instance.new("Frame")
- Frame586 = Instance.new("Frame")
- Frame587 = Instance.new("Frame")
- TextLabel588 = Instance.new("TextLabel")
- Frame589 = Instance.new("Frame")
- TextButton590 = Instance.new("TextButton")
- ImageLabel591 = Instance.new("ImageLabel")
- TextBox592 = Instance.new("TextBox")
- Frame593 = Instance.new("Frame")
- Frame594 = Instance.new("Frame")
- Frame595 = Instance.new("Frame")
- Frame596 = Instance.new("Frame")
- TextButton597 = Instance.new("TextButton")
- Frame598 = Instance.new("Frame")
- TextButton599 = Instance.new("TextButton")
- Frame600 = Instance.new("Frame")
- Frame601 = Instance.new("Frame")
- Frame602 = Instance.new("Frame")
- Frame603 = Instance.new("Frame")
- TextLabel604 = Instance.new("TextLabel")
- TextLabel605 = Instance.new("TextLabel")
- Frame606 = Instance.new("Frame")
- TextLabel607 = Instance.new("TextLabel")
- Frame608 = Instance.new("Frame")
- TextLabel609 = Instance.new("TextLabel")
- Frame610 = Instance.new("Frame")
- TextButton611 = Instance.new("TextButton")
- ImageLabel612 = Instance.new("ImageLabel")
- Frame613 = Instance.new("Frame")
- TextBox614 = Instance.new("TextBox")
- Frame615 = Instance.new("Frame")
- TextButton616 = Instance.new("TextButton")
- ImageLabel617 = Instance.new("ImageLabel")
- Frame618 = Instance.new("Frame")
- TextBox619 = Instance.new("TextBox")
- Frame620 = Instance.new("Frame")
- TextButton621 = Instance.new("TextButton")
- ImageLabel622 = Instance.new("ImageLabel")
- Frame623 = Instance.new("Frame")
- TextBox624 = Instance.new("TextBox")
- Frame625 = Instance.new("Frame")
- TextButton626 = Instance.new("TextButton")
- Frame627 = Instance.new("Frame")
- Frame628 = Instance.new("Frame")
- TextLabel629 = Instance.new("TextLabel")
- TextBox630 = Instance.new("TextBox")
- Frame631 = Instance.new("Frame")
- Frame632 = Instance.new("Frame")
- Frame633 = Instance.new("Frame")
- Frame634 = Instance.new("Frame")
- Frame635 = Instance.new("Frame")
- TextButton636 = Instance.new("TextButton")
- Frame637 = Instance.new("Frame")
- Frame638 = Instance.new("Frame")
- TextLabel639 = Instance.new("TextLabel")
- TextBox640 = Instance.new("TextBox")
- Frame641 = Instance.new("Frame")
- Frame642 = Instance.new("Frame")
- Frame643 = Instance.new("Frame")
- Frame644 = Instance.new("Frame")
- Frame645 = Instance.new("Frame")
- TextButton646 = Instance.new("TextButton")
- Frame647 = Instance.new("Frame")
- TextButton648 = Instance.new("TextButton")
- Frame649 = Instance.new("Frame")
- Frame650 = Instance.new("Frame")
- TextLabel651 = Instance.new("TextLabel")
- Frame652 = Instance.new("Frame")
- TextButton653 = Instance.new("TextButton")
- ImageLabel654 = Instance.new("ImageLabel")
- Frame655 = Instance.new("Frame")
- TextBox656 = Instance.new("TextBox")
- Frame657 = Instance.new("Frame")
- TextButton658 = Instance.new("TextButton")
- ImageLabel659 = Instance.new("ImageLabel")
- Frame660 = Instance.new("Frame")
- TextBox661 = Instance.new("TextBox")
- Frame662 = Instance.new("Frame")
- TextButton663 = Instance.new("TextButton")
- ImageLabel664 = Instance.new("ImageLabel")
- Frame665 = Instance.new("Frame")
- TextBox666 = Instance.new("TextBox")
- Frame667 = Instance.new("Frame")
- Frame668 = Instance.new("Frame")
- Frame669 = Instance.new("Frame")
- ImageButton670 = Instance.new("ImageButton")
- Frame671 = Instance.new("Frame")
- TextLabel672 = Instance.new("TextLabel")
- Frame673 = Instance.new("Frame")
- Frame674 = Instance.new("Frame")
- Frame675 = Instance.new("Frame")
- Frame676 = Instance.new("Frame")
- TextLabel677 = Instance.new("TextLabel")
- TextLabel678 = Instance.new("TextLabel")
- Frame679 = Instance.new("Frame")
- TextLabel680 = Instance.new("TextLabel")
- ImageButton681 = Instance.new("ImageButton")
- Frame682 = Instance.new("Frame")
- TextButton683 = Instance.new("TextButton")
- TextButton684 = Instance.new("TextButton")
- Frame685 = Instance.new("Frame")
- Frame686 = Instance.new("Frame")
- Frame687 = Instance.new("Frame")
- TextLabel688 = Instance.new("TextLabel")
- Frame689 = Instance.new("Frame")
- TextButton690 = Instance.new("TextButton")
- ImageLabel691 = Instance.new("ImageLabel")
- Frame692 = Instance.new("Frame")
- TextBox693 = Instance.new("TextBox")
- Frame694 = Instance.new("Frame")
- TextButton695 = Instance.new("TextButton")
- ImageLabel696 = Instance.new("ImageLabel")
- Frame697 = Instance.new("Frame")
- TextBox698 = Instance.new("TextBox")
- Frame699 = Instance.new("Frame")
- TextButton700 = Instance.new("TextButton")
- ImageLabel701 = Instance.new("ImageLabel")
- Frame702 = Instance.new("Frame")
- TextBox703 = Instance.new("TextBox")
- ImageButton704 = Instance.new("ImageButton")
- Frame705 = Instance.new("Frame")
- Frame706 = Instance.new("Frame")
- Frame707 = Instance.new("Frame")
- Frame708 = Instance.new("Frame")
- Frame709 = Instance.new("Frame")
- TextLabel710 = Instance.new("TextLabel")
- Frame711 = Instance.new("Frame")
- TextButton712 = Instance.new("TextButton")
- ImageLabel713 = Instance.new("ImageLabel")
- Frame714 = Instance.new("Frame")
- TextBox715 = Instance.new("TextBox")
- Frame716 = Instance.new("Frame")
- TextLabel717 = Instance.new("TextLabel")
- Frame718 = Instance.new("Frame")
- TextButton719 = Instance.new("TextButton")
- ImageLabel720 = Instance.new("ImageLabel")
- Frame721 = Instance.new("Frame")
- TextBox722 = Instance.new("TextBox")
- Frame723 = Instance.new("Frame")
- TextLabel724 = Instance.new("TextLabel")
- Frame725 = Instance.new("Frame")
- TextButton726 = Instance.new("TextButton")
- ImageLabel727 = Instance.new("ImageLabel")
- Frame728 = Instance.new("Frame")
- TextBox729 = Instance.new("TextBox")
- TextLabel730 = Instance.new("TextLabel")
- Frame731 = Instance.new("Frame")
- TextLabel732 = Instance.new("TextLabel")
- ImageButton733 = Instance.new("ImageButton")
- Frame734 = Instance.new("Frame")
- TextButton735 = Instance.new("TextButton")
- TextButton736 = Instance.new("TextButton")
- Frame737 = Instance.new("Frame")
- Frame738 = Instance.new("Frame")
- Frame739 = Instance.new("Frame")
- TextLabel740 = Instance.new("TextLabel")
- Frame741 = Instance.new("Frame")
- TextButton742 = Instance.new("TextButton")
- ImageLabel743 = Instance.new("ImageLabel")
- Frame744 = Instance.new("Frame")
- TextBox745 = Instance.new("TextBox")
- Frame746 = Instance.new("Frame")
- TextButton747 = Instance.new("TextButton")
- ImageLabel748 = Instance.new("ImageLabel")
- Frame749 = Instance.new("Frame")
- TextBox750 = Instance.new("TextBox")
- Frame751 = Instance.new("Frame")
- TextButton752 = Instance.new("TextButton")
- ImageLabel753 = Instance.new("ImageLabel")
- Frame754 = Instance.new("Frame")
- TextBox755 = Instance.new("TextBox")
- ImageButton756 = Instance.new("ImageButton")
- Frame757 = Instance.new("Frame")
- Frame758 = Instance.new("Frame")
- Frame759 = Instance.new("Frame")
- Frame760 = Instance.new("Frame")
- Frame761 = Instance.new("Frame")
- TextLabel762 = Instance.new("TextLabel")
- Frame763 = Instance.new("Frame")
- TextButton764 = Instance.new("TextButton")
- ImageLabel765 = Instance.new("ImageLabel")
- Frame766 = Instance.new("Frame")
- TextBox767 = Instance.new("TextBox")
- Frame768 = Instance.new("Frame")
- TextLabel769 = Instance.new("TextLabel")
- Frame770 = Instance.new("Frame")
- TextButton771 = Instance.new("TextButton")
- ImageLabel772 = Instance.new("ImageLabel")
- Frame773 = Instance.new("Frame")
- TextBox774 = Instance.new("TextBox")
- Frame775 = Instance.new("Frame")
- TextLabel776 = Instance.new("TextLabel")
- Frame777 = Instance.new("Frame")
- TextButton778 = Instance.new("TextButton")
- ImageLabel779 = Instance.new("ImageLabel")
- Frame780 = Instance.new("Frame")
- TextBox781 = Instance.new("TextBox")
- Frame782 = Instance.new("Frame")
- TextButton783 = Instance.new("TextButton")
- ImageLabel784 = Instance.new("ImageLabel")
- Frame785 = Instance.new("Frame")
- TextBox786 = Instance.new("TextBox")
- Frame787 = Instance.new("Frame")
- TextButton788 = Instance.new("TextButton")
- ImageLabel789 = Instance.new("ImageLabel")
- Frame790 = Instance.new("Frame")
- TextBox791 = Instance.new("TextBox")
- ImageButton792 = Instance.new("ImageButton")
- Frame793 = Instance.new("Frame")
- Frame794 = Instance.new("Frame")
- Frame795 = Instance.new("Frame")
- Frame796 = Instance.new("Frame")
- Frame797 = Instance.new("Frame")
- TextLabel798 = Instance.new("TextLabel")
- ImageButton799 = Instance.new("ImageButton")
- Frame800 = Instance.new("Frame")
- TextButton801 = Instance.new("TextButton")
- TextButton802 = Instance.new("TextButton")
- Frame803 = Instance.new("Frame")
- Frame804 = Instance.new("Frame")
- Frame805 = Instance.new("Frame")
- TextLabel806 = Instance.new("TextLabel")
- Frame807 = Instance.new("Frame")
- TextButton808 = Instance.new("TextButton")
- ImageLabel809 = Instance.new("ImageLabel")
- Frame810 = Instance.new("Frame")
- TextBox811 = Instance.new("TextBox")
- Frame812 = Instance.new("Frame")
- TextButton813 = Instance.new("TextButton")
- ImageLabel814 = Instance.new("ImageLabel")
- Frame815 = Instance.new("Frame")
- TextBox816 = Instance.new("TextBox")
- Frame817 = Instance.new("Frame")
- TextButton818 = Instance.new("TextButton")
- ImageLabel819 = Instance.new("ImageLabel")
- Frame820 = Instance.new("Frame")
- TextBox821 = Instance.new("TextBox")
- ImageButton822 = Instance.new("ImageButton")
- Frame823 = Instance.new("Frame")
- Frame824 = Instance.new("Frame")
- Frame825 = Instance.new("Frame")
- Frame826 = Instance.new("Frame")
- Frame827 = Instance.new("Frame")
- Frame828 = Instance.new("Frame")
- Frame829 = Instance.new("Frame")
- Frame830 = Instance.new("Frame")
- Frame831 = Instance.new("Frame")
- Frame832 = Instance.new("Frame")
- TextLabel833 = Instance.new("TextLabel")
- TextLabel834 = Instance.new("TextLabel")
- TextLabel835 = Instance.new("TextLabel")
- TextLabel836 = Instance.new("TextLabel")
- Frame837 = Instance.new("Frame")
- TextLabel838 = Instance.new("TextLabel")
- TextLabel839 = Instance.new("TextLabel")
- Frame840 = Instance.new("Frame")
- TextLabel841 = Instance.new("TextLabel")
- TextLabel842 = Instance.new("TextLabel")
- Frame843 = Instance.new("Frame")
- Frame844 = Instance.new("Frame")
- Frame845 = Instance.new("Frame")
- TextLabel846 = Instance.new("TextLabel")
- TextLabel847 = Instance.new("TextLabel")
- Frame848 = Instance.new("Frame")
- TextLabel849 = Instance.new("TextLabel")
- TextLabel850 = Instance.new("TextLabel")
- Frame851 = Instance.new("Frame")
- TextLabel852 = Instance.new("TextLabel")
- TextLabel853 = Instance.new("TextLabel")
- Frame854 = Instance.new("Frame")
- Frame855 = Instance.new("Frame")
- Frame856 = Instance.new("Frame")
- TextLabel857 = Instance.new("TextLabel")
- TextLabel858 = Instance.new("TextLabel")
- Frame859 = Instance.new("Frame")
- Frame860 = Instance.new("Frame")
- Frame861 = Instance.new("Frame")
- TextLabel862 = Instance.new("TextLabel")
- TextLabel863 = Instance.new("TextLabel")
- Frame864 = Instance.new("Frame")
- Frame865 = Instance.new("Frame")
- Frame866 = Instance.new("Frame")
- Frame867 = Instance.new("Frame")
- TextLabel868 = Instance.new("TextLabel")
- TextLabel869 = Instance.new("TextLabel")
- TextLabel870 = Instance.new("TextLabel")
- TextLabel871 = Instance.new("TextLabel")
- Frame872 = Instance.new("Frame")
- TextLabel873 = Instance.new("TextLabel")
- TextLabel874 = Instance.new("TextLabel")
- Frame875 = Instance.new("Frame")
- TextLabel876 = Instance.new("TextLabel")
- TextLabel877 = Instance.new("TextLabel")
- Frame878 = Instance.new("Frame")
- Frame879 = Instance.new("Frame")
- Frame880 = Instance.new("Frame")
- TextLabel881 = Instance.new("TextLabel")
- TextLabel882 = Instance.new("TextLabel")
- Frame883 = Instance.new("Frame")
- Frame884 = Instance.new("Frame")
- Frame885 = Instance.new("Frame")
- TextLabel886 = Instance.new("TextLabel")
- TextLabel887 = Instance.new("TextLabel")
- Frame888 = Instance.new("Frame")
- Frame889 = Instance.new("Frame")
- Frame890 = Instance.new("Frame")
- TextLabel891 = Instance.new("TextLabel")
- TextLabel892 = Instance.new("TextLabel")
- Frame893 = Instance.new("Frame")
- Frame894 = Instance.new("Frame")
- Frame895 = Instance.new("Frame")
- TextLabel896 = Instance.new("TextLabel")
- TextLabel897 = Instance.new("TextLabel")
- Frame898 = Instance.new("Frame")
- Frame899 = Instance.new("Frame")
- Frame900 = Instance.new("Frame")
- TextLabel901 = Instance.new("TextLabel")
- TextLabel902 = Instance.new("TextLabel")
- Frame903 = Instance.new("Frame")
- Frame904 = Instance.new("Frame")
- Frame905 = Instance.new("Frame")
- TextLabel906 = Instance.new("TextLabel")
- TextLabel907 = Instance.new("TextLabel")
- Frame908 = Instance.new("Frame")
- Frame909 = Instance.new("Frame")
- Frame910 = Instance.new("Frame")
- TextLabel911 = Instance.new("TextLabel")
- TextLabel912 = Instance.new("TextLabel")
- Frame913 = Instance.new("Frame")
- Frame914 = Instance.new("Frame")
- Frame915 = Instance.new("Frame")
- TextLabel916 = Instance.new("TextLabel")
- TextLabel917 = Instance.new("TextLabel")
- Frame918 = Instance.new("Frame")
- Frame919 = Instance.new("Frame")
- Frame920 = Instance.new("Frame")
- TextLabel921 = Instance.new("TextLabel")
- TextLabel922 = Instance.new("TextLabel")
- Frame923 = Instance.new("Frame")
- TextLabel924 = Instance.new("TextLabel")
- ImageButton925 = Instance.new("ImageButton")
- Frame926 = Instance.new("Frame")
- TextLabel927 = Instance.new("TextLabel")
- Frame928 = Instance.new("Frame")
- Frame929 = Instance.new("Frame")
- ImageButton930 = Instance.new("ImageButton")
- Frame931 = Instance.new("Frame")
- TextLabel932 = Instance.new("TextLabel")
- ImageButton933 = Instance.new("ImageButton")
- Frame934 = Instance.new("Frame")
- TextLabel935 = Instance.new("TextLabel")
- ImageButton936 = Instance.new("ImageButton")
- Frame937 = Instance.new("Frame")
- TextLabel938 = Instance.new("TextLabel")
- ImageButton939 = Instance.new("ImageButton")
- Frame940 = Instance.new("Frame")
- TextLabel941 = Instance.new("TextLabel")
- ImageButton942 = Instance.new("ImageButton")
- Frame943 = Instance.new("Frame")
- TextLabel944 = Instance.new("TextLabel")
- Frame945 = Instance.new("Frame")
- ImageButton946 = Instance.new("ImageButton")
- TextLabel947 = Instance.new("TextLabel")
- ImageButton948 = Instance.new("ImageButton")
- TextLabel949 = Instance.new("TextLabel")
- ImageButton950 = Instance.new("ImageButton")
- TextLabel951 = Instance.new("TextLabel")
- ImageButton952 = Instance.new("ImageButton")
- TextLabel953 = Instance.new("TextLabel")
- ImageButton954 = Instance.new("ImageButton")
- TextLabel955 = Instance.new("TextLabel")
- ImageButton956 = Instance.new("ImageButton")
- TextLabel957 = Instance.new("TextLabel")
- ImageButton958 = Instance.new("ImageButton")
- TextLabel959 = Instance.new("TextLabel")
- ImageButton960 = Instance.new("ImageButton")
- TextLabel961 = Instance.new("TextLabel")
- ImageButton962 = Instance.new("ImageButton")
- TextLabel963 = Instance.new("TextLabel")
- ImageButton964 = Instance.new("ImageButton")
- TextLabel965 = Instance.new("TextLabel")
- ImageButton966 = Instance.new("ImageButton")
- TextLabel967 = Instance.new("TextLabel")
- ImageButton968 = Instance.new("ImageButton")
- TextLabel969 = Instance.new("TextLabel")
- ImageButton970 = Instance.new("ImageButton")
- TextLabel971 = Instance.new("TextLabel")
- ImageButton972 = Instance.new("ImageButton")
- TextLabel973 = Instance.new("TextLabel")
- Frame974 = Instance.new("Frame")
- Frame975 = Instance.new("Frame")
- Frame976 = Instance.new("Frame")
- Frame977 = Instance.new("Frame")
- Frame978 = Instance.new("Frame")
- Frame979 = Instance.new("Frame")
- Frame980 = Instance.new("Frame")
- Frame981 = Instance.new("Frame")
- TextLabel982 = Instance.new("TextLabel")
- Frame983 = Instance.new("Frame")
- Frame984 = Instance.new("Frame")
- Frame985 = Instance.new("Frame")
- Frame986 = Instance.new("Frame")
- Frame987 = Instance.new("Frame")
- Frame988 = Instance.new("Frame")
- TextLabel989 = Instance.new("TextLabel")
- Frame990 = Instance.new("Frame")
- TextLabel991 = Instance.new("TextLabel")
- TextLabel992 = Instance.new("TextLabel")
- Frame993 = Instance.new("Frame")
- TextLabel994 = Instance.new("TextLabel")
- TextLabel995 = Instance.new("TextLabel")
- Tool996 = Instance.new("Tool")
- Part997 = Instance.new("Part")
- SpecialMesh998 = Instance.new("SpecialMesh")
- Fire999 = Instance.new("Fire")
- LocalScript1000 = Instance.new("LocalScript")
- Script1001 = Instance.new("Script")
- HopperBin1002 = Instance.new("HopperBin")
- LocalScript1003 = Instance.new("LocalScript")
- ScreenGui1004 = Instance.new("ScreenGui")
- Frame1005 = Instance.new("Frame")
- TextLabel1006 = Instance.new("TextLabel")
- TextLabel1007 = Instance.new("TextLabel")
- Frame1008 = Instance.new("Frame")
- TextLabel1009 = Instance.new("TextLabel")
- TextButton1010 = Instance.new("TextButton")
- TextButton1011 = Instance.new("TextButton")
- TextButton1012 = Instance.new("TextButton")
- TextButton1013 = Instance.new("TextButton")
- TextButton1014 = Instance.new("TextButton")
- TextButton1015 = Instance.new("TextButton")
- Frame1016 = Instance.new("Frame")
- TextLabel1017 = Instance.new("TextLabel")
- TextButton1018 = Instance.new("TextButton")
- TextButton1019 = Instance.new("TextButton")
- TextButton1020 = Instance.new("TextButton")
- TextButton1021 = Instance.new("TextButton")
- TextButton1022 = Instance.new("TextButton")
- TextButton1023 = Instance.new("TextButton")
- Frame1024 = Instance.new("Frame")
- TextLabel1025 = Instance.new("TextLabel")
- TextButton1026 = Instance.new("TextButton")
- TextButton1027 = Instance.new("TextButton")
- TextButton1028 = Instance.new("TextButton")
- TextButton1029 = Instance.new("TextButton")
- TextButton1030 = Instance.new("TextButton")
- TextButton1031 = Instance.new("TextButton")
- Frame1032 = Instance.new("Frame")
- TextLabel1033 = Instance.new("TextLabel")
- TextButton1034 = Instance.new("TextButton")
- TextButton1035 = Instance.new("TextButton")
- TextButton1036 = Instance.new("TextButton")
- TextButton1037 = Instance.new("TextButton")
- Frame1038 = Instance.new("Frame")
- TextLabel1039 = Instance.new("TextLabel")
- TextButton1040 = Instance.new("TextButton")
- TextButton1041 = Instance.new("TextButton")
- TextButton1042 = Instance.new("TextButton")
- TextButton1043 = Instance.new("TextButton")
- Frame1044 = Instance.new("Frame")
- TextLabel1045 = Instance.new("TextLabel")
- TextButton1046 = Instance.new("TextButton")
- TextButton1047 = Instance.new("TextButton")
- TextButton1048 = Instance.new("TextButton")
- TextButton1049 = Instance.new("TextButton")
- TextLabel1050 = Instance.new("TextLabel")
- Frame1051 = Instance.new("Frame")
- TextLabel1052 = Instance.new("TextLabel")
- TextButton1053 = Instance.new("TextButton")
- TextButton1054 = Instance.new("TextButton")
- TextButton1055 = Instance.new("TextButton")
- TextButton1056 = Instance.new("TextButton")
- Script1057 = Instance.new("Script")
- HopperBin1058 = Instance.new("HopperBin")
- Handles1059 = Instance.new("Handles")
- SelectionBox1060 = Instance.new("SelectionBox")
- LocalScript1061 = Instance.new("LocalScript")
- Script1062 = Instance.new("Script")
- HopperBin1063 = Instance.new("HopperBin")
- BoolValue1064 = Instance.new("BoolValue")
- StringValue1065 = Instance.new("StringValue")
- BoolValue1066 = Instance.new("BoolValue")
- StringValue1067 = Instance.new("StringValue")
- BoolValue1068 = Instance.new("BoolValue")
- SelectionBox1069 = Instance.new("SelectionBox")
- Script1070 = Instance.new("Script")
- ScreenGui1071 = Instance.new("ScreenGui")
- Frame1072 = Instance.new("Frame")
- TextLabel1073 = Instance.new("TextLabel")
- TextButton1074 = Instance.new("TextButton")
- TextButton1075 = Instance.new("TextButton")
- BoolValue1076 = Instance.new("BoolValue")
- TextLabel1077 = Instance.new("TextLabel")
- TextButton1078 = Instance.new("TextButton")
- TextButton1079 = Instance.new("TextButton")
- TextButton1080 = Instance.new("TextButton")
- TextButton1081 = Instance.new("TextButton")
- TextBox1082 = Instance.new("TextBox")
- TextLabel1083 = Instance.new("TextLabel")
- TextLabel1084 = Instance.new("TextLabel")
- TextButton1085 = Instance.new("TextButton")
- TextLabel1086 = Instance.new("TextLabel")
- TextLabel1087 = Instance.new("TextLabel")
- LocalScript1088 = Instance.new("LocalScript")
- TextButton1089 = Instance.new("TextButton")
- Frame1090 = Instance.new("Frame")
- TextLabel1091 = Instance.new("TextLabel")
- TextLabel1092 = Instance.new("TextLabel")
- TextLabel1093 = Instance.new("TextLabel")
- TextButton1094 = Instance.new("TextButton")
- Script1095 = Instance.new("Script")
- TextButton1096 = Instance.new("TextButton")
- Script1097 = Instance.new("Script")
- LocalScript1098 = Instance.new("LocalScript")
- Frame1099 = Instance.new("Frame")
- TextButton1100 = Instance.new("TextButton")
- BoolValue1101 = Instance.new("BoolValue")
- TextBox1102 = Instance.new("TextBox")
- TextButton1103 = Instance.new("TextButton")
- TextLabel1104 = Instance.new("TextLabel")
- TextLabel1105 = Instance.new("TextLabel")
- TextLabel1106 = Instance.new("TextLabel")
- TextButton1107 = Instance.new("TextButton")
- TextLabel1108 = Instance.new("TextLabel")
- TextBox1109 = Instance.new("TextBox")
- Frame1110 = Instance.new("Frame")
- TextLabel1111 = Instance.new("TextLabel")
- TextLabel1112 = Instance.new("TextLabel")
- TextButton1113 = Instance.new("TextButton")
- Script1114 = Instance.new("Script")
- TextButton1115 = Instance.new("TextButton")
- Script1116 = Instance.new("Script")
- ObjectValue1117 = Instance.new("ObjectValue")
- HopperBin1118 = Instance.new("HopperBin")
- LocalScript1119 = Instance.new("LocalScript")
- LocalScript1120 = Instance.new("LocalScript")
- Model1121 = Instance.new("Model")
- Model1122 = Instance.new("Model")
- StringValue1123 = Instance.new("StringValue")
- Color3Value1124 = Instance.new("Color3Value")
- StringValue1125 = Instance.new("StringValue")
- StringValue1126 = Instance.new("StringValue")
- LocalScript1127 = Instance.new("LocalScript")
- StringValue1128 = Instance.new("StringValue")
- LocalScript1129 = Instance.new("LocalScript")
- LocalScript1130 = Instance.new("LocalScript")
- StringValue1131 = Instance.new("StringValue")
- StringValue1132 = Instance.new("StringValue")
- LocalScript1133 = Instance.new("LocalScript")
- StringValue1134 = Instance.new("StringValue")
- Color3Value1135 = Instance.new("Color3Value")
- StringValue1136 = Instance.new("StringValue")
- StringValue1137 = Instance.new("StringValue")
- LocalScript1138 = Instance.new("LocalScript")
- LocalScript1139 = Instance.new("LocalScript")
- LocalScript1140 = Instance.new("LocalScript")
- StringValue1141 = Instance.new("StringValue")
- Color3Value1142 = Instance.new("Color3Value")
- StringValue1143 = Instance.new("StringValue")
- StringValue1144 = Instance.new("StringValue")
- StringValue1145 = Instance.new("StringValue")
- Color3Value1146 = Instance.new("Color3Value")
- StringValue1147 = Instance.new("StringValue")
- StringValue1148 = Instance.new("StringValue")
- LocalScript1149 = Instance.new("LocalScript")
- StringValue1150 = Instance.new("StringValue")
- Color3Value1151 = Instance.new("Color3Value")
- StringValue1152 = Instance.new("StringValue")
- StringValue1153 = Instance.new("StringValue")
- LocalScript1154 = Instance.new("LocalScript")
- StringValue1155 = Instance.new("StringValue")
- LocalScript1156 = Instance.new("LocalScript")
- StringValue1157 = Instance.new("StringValue")
- LocalScript1158 = Instance.new("LocalScript")
- StringValue1159 = Instance.new("StringValue")
- StringValue1160 = Instance.new("StringValue")
- Color3Value1161 = Instance.new("Color3Value")
- StringValue1162 = Instance.new("StringValue")
- StringValue1163 = Instance.new("StringValue")
- LocalScript1164 = Instance.new("LocalScript")
- LocalScript1165 = Instance.new("LocalScript")
- StringValue1166 = Instance.new("StringValue")
- Color3Value1167 = Instance.new("Color3Value")
- StringValue1168 = Instance.new("StringValue")
- StringValue1169 = Instance.new("StringValue")
- LocalScript1170 = Instance.new("LocalScript")
- Model1171 = Instance.new("Model")
- LocalScript1172 = Instance.new("LocalScript")
- StringValue1173 = Instance.new("StringValue")
- LocalScript1174 = Instance.new("LocalScript")
- StringValue1175 = Instance.new("StringValue")
- LocalScript1176 = Instance.new("LocalScript")
- StringValue1177 = Instance.new("StringValue")
- StringValue1178 = Instance.new("StringValue")
- LocalScript1179 = Instance.new("LocalScript")
- LocalScript1180 = Instance.new("LocalScript")
- StringValue1181 = Instance.new("StringValue")
- StringValue1182 = Instance.new("StringValue")
- LocalScript1183 = Instance.new("LocalScript")
- StringValue1184 = Instance.new("StringValue")
- LocalScript1185 = Instance.new("LocalScript")
- LocalScript1186 = Instance.new("LocalScript")
- StringValue1187 = Instance.new("StringValue")
- StringValue1188 = Instance.new("StringValue")
- LocalScript1189 = Instance.new("LocalScript")
- StringValue1190 = Instance.new("StringValue")
- LocalScript1191 = Instance.new("LocalScript")
- StringValue1192 = Instance.new("StringValue")
- Color3Value1193 = Instance.new("Color3Value")
- StringValue1194 = Instance.new("StringValue")
- StringValue1195 = Instance.new("StringValue")
- LocalScript1196 = Instance.new("LocalScript")
- StringValue1197 = Instance.new("StringValue")
- LocalScript1198 = Instance.new("LocalScript")
- StringValue1199 = Instance.new("StringValue")
- Color3Value1200 = Instance.new("Color3Value")
- StringValue1201 = Instance.new("StringValue")
- StringValue1202 = Instance.new("StringValue")
- LocalScript1203 = Instance.new("LocalScript")
- StringValue1204 = Instance.new("StringValue")
- LocalScript1205 = Instance.new("LocalScript")
- StringValue1206 = Instance.new("StringValue")
- StringValue1207 = Instance.new("StringValue")
- Color3Value1208 = Instance.new("Color3Value")
- StringValue1209 = Instance.new("StringValue")
- StringValue1210 = Instance.new("StringValue")
- LocalScript1211 = Instance.new("LocalScript")
- LocalScript1212 = Instance.new("LocalScript")
- StringValue1213 = Instance.new("StringValue")
- StringValue1214 = Instance.new("StringValue")
- Color3Value1215 = Instance.new("Color3Value")
- StringValue1216 = Instance.new("StringValue")
- StringValue1217 = Instance.new("StringValue")
- LocalScript1218 = Instance.new("LocalScript")
- LocalScript1219 = Instance.new("LocalScript")
- StringValue1220 = Instance.new("StringValue")
- StringValue1221 = Instance.new("StringValue")
- LocalScript1222 = Instance.new("LocalScript")
- StringValue1223 = Instance.new("StringValue")
- Color3Value1224 = Instance.new("Color3Value")
- StringValue1225 = Instance.new("StringValue")
- StringValue1226 = Instance.new("StringValue")
- LocalScript1227 = Instance.new("LocalScript")
- LocalScript1228 = Instance.new("LocalScript")
- StringValue1229 = Instance.new("StringValue")
- LocalScript1230 = Instance.new("LocalScript")
- StringValue1231 = Instance.new("StringValue")
- LocalScript1232 = Instance.new("LocalScript")
- StringValue1233 = Instance.new("StringValue")
- Color3Value1234 = Instance.new("Color3Value")
- StringValue1235 = Instance.new("StringValue")
- StringValue1236 = Instance.new("StringValue")
- LocalScript1237 = Instance.new("LocalScript")
- StringValue1238 = Instance.new("StringValue")
- LocalScript1239 = Instance.new("LocalScript")
- StringValue1240 = Instance.new("StringValue")
- Color3Value1241 = Instance.new("Color3Value")
- StringValue1242 = Instance.new("StringValue")
- StringValue1243 = Instance.new("StringValue")
- LocalScript1244 = Instance.new("LocalScript")
- StringValue1245 = Instance.new("StringValue")
- LocalScript1246 = Instance.new("LocalScript")
- StringValue1247 = Instance.new("StringValue")
- StringValue1248 = Instance.new("StringValue")
- LocalScript1249 = Instance.new("LocalScript")
- StringValue1250 = Instance.new("StringValue")
- StringValue1251 = Instance.new("StringValue")
- Color3Value1252 = Instance.new("Color3Value")
- LocalScript1253 = Instance.new("LocalScript")
- StringValue1254 = Instance.new("StringValue")
- Color3Value1255 = Instance.new("Color3Value")
- StringValue1256 = Instance.new("StringValue")
- StringValue1257 = Instance.new("StringValue")
- LocalScript1258 = Instance.new("LocalScript")
- StringValue1259 = Instance.new("StringValue")
- LocalScript1260 = Instance.new("LocalScript")
- StringValue1261 = Instance.new("StringValue")
- StringValue1262 = Instance.new("StringValue")
- Color3Value1263 = Instance.new("Color3Value")
- StringValue1264 = Instance.new("StringValue")
- StringValue1265 = Instance.new("StringValue")
- LocalScript1266 = Instance.new("LocalScript")
- LocalScript1267 = Instance.new("LocalScript")
- StringValue1268 = Instance.new("StringValue")
- StringValue1269 = Instance.new("StringValue")
- Color3Value1270 = Instance.new("Color3Value")
- StringValue1271 = Instance.new("StringValue")
- StringValue1272 = Instance.new("StringValue")
- LocalScript1273 = Instance.new("LocalScript")
- StringValue1274 = Instance.new("StringValue")
- Color3Value1275 = Instance.new("Color3Value")
- StringValue1276 = Instance.new("StringValue")
- StringValue1277 = Instance.new("StringValue")
- LocalScript1278 = Instance.new("LocalScript")
- StringValue1279 = Instance.new("StringValue")
- LocalScript1280 = Instance.new("LocalScript")
- StringValue1281 = Instance.new("StringValue")
- StringValue1282 = Instance.new("StringValue")
- Color3Value1283 = Instance.new("Color3Value")
- StringValue1284 = Instance.new("StringValue")
- StringValue1285 = Instance.new("StringValue")
- LocalScript1286 = Instance.new("LocalScript")
- StringValue1287 = Instance.new("StringValue")
- LocalScript1288 = Instance.new("LocalScript")
- StringValue1289 = Instance.new("StringValue")
- LocalScript1290 = Instance.new("LocalScript")
- LocalScript1291 = Instance.new("LocalScript")
- StringValue1292 = Instance.new("StringValue")
- StringValue1293 = Instance.new("StringValue")
- Color3Value1294 = Instance.new("Color3Value")
- StringValue1295 = Instance.new("StringValue")
- StringValue1296 = Instance.new("StringValue")
- LocalScript1297 = Instance.new("LocalScript")
- LocalScript1298 = Instance.new("LocalScript")
- LocalScript1299 = Instance.new("LocalScript")
- Model1300 = Instance.new("Model")
- LocalScript1301 = Instance.new("LocalScript")
- StringValue1302 = Instance.new("StringValue")
- LocalScript1303 = Instance.new("LocalScript")
- LocalScript1304 = Instance.new("LocalScript")
- StringValue1305 = Instance.new("StringValue")
- StringValue1306 = Instance.new("StringValue")
- LocalScript1307 = Instance.new("LocalScript")
- StringValue1308 = Instance.new("StringValue")
- StringValue1309 = Instance.new("StringValue")
- StringValue1310 = Instance.new("StringValue")
- LocalScript1311 = Instance.new("LocalScript")
- StringValue1312 = Instance.new("StringValue")
- LocalScript1313 = Instance.new("LocalScript")
- LocalScript1314 = Instance.new("LocalScript")
- LocalScript1315 = Instance.new("LocalScript")
- LocalScript1316 = Instance.new("LocalScript")
- StringValue1317 = Instance.new("StringValue")
- LocalScript1318 = Instance.new("LocalScript")
- StringValue1319 = Instance.new("StringValue")
- StringValue1320 = Instance.new("StringValue")
- LocalScript1321 = Instance.new("LocalScript")
- LocalScript1322 = Instance.new("LocalScript")
- StringValue1323 = Instance.new("StringValue")
- StringValue1324 = Instance.new("StringValue")
- StringValue1325 = Instance.new("StringValue")
- LocalScript1326 = Instance.new("LocalScript")
- StringValue1327 = Instance.new("StringValue")
- LocalScript1328 = Instance.new("LocalScript")
- StringValue1329 = Instance.new("StringValue")
- LocalScript1330 = Instance.new("LocalScript")
- LocalScript1331 = Instance.new("LocalScript")
- HopperBin1332 = Instance.new("HopperBin")
- Script1333 = Instance.new("Script")
- HopperBin1334 = Instance.new("HopperBin")
- Script1335 = Instance.new("Script")
- HopperBin1336 = Instance.new("HopperBin")
- Script1337 = Instance.new("Script")
- HopperBin1338 = Instance.new("HopperBin")
- ScreenGui1339 = Instance.new("ScreenGui")
- Frame1340 = Instance.new("Frame")
- TextLabel1341 = Instance.new("TextLabel")
- TextLabel1342 = Instance.new("TextLabel")
- Frame1343 = Instance.new("Frame")
- TextLabel1344 = Instance.new("TextLabel")
- TextButton1345 = Instance.new("TextButton")
- TextButton1346 = Instance.new("TextButton")
- TextButton1347 = Instance.new("TextButton")
- TextButton1348 = Instance.new("TextButton")
- TextButton1349 = Instance.new("TextButton")
- TextButton1350 = Instance.new("TextButton")
- Frame1351 = Instance.new("Frame")
- TextLabel1352 = Instance.new("TextLabel")
- TextButton1353 = Instance.new("TextButton")
- TextButton1354 = Instance.new("TextButton")
- TextButton1355 = Instance.new("TextButton")
- TextButton1356 = Instance.new("TextButton")
- TextButton1357 = Instance.new("TextButton")
- TextButton1358 = Instance.new("TextButton")
- Frame1359 = Instance.new("Frame")
- TextLabel1360 = Instance.new("TextLabel")
- TextButton1361 = Instance.new("TextButton")
- TextButton1362 = Instance.new("TextButton")
- TextButton1363 = Instance.new("TextButton")
- TextButton1364 = Instance.new("TextButton")
- TextButton1365 = Instance.new("TextButton")
- TextButton1366 = Instance.new("TextButton")
- Frame1367 = Instance.new("Frame")
- TextLabel1368 = Instance.new("TextLabel")
- TextButton1369 = Instance.new("TextButton")
- TextButton1370 = Instance.new("TextButton")
- TextButton1371 = Instance.new("TextButton")
- TextButton1372 = Instance.new("TextButton")
- Frame1373 = Instance.new("Frame")
- TextLabel1374 = Instance.new("TextLabel")
- TextButton1375 = Instance.new("TextButton")
- TextButton1376 = Instance.new("TextButton")
- TextButton1377 = Instance.new("TextButton")
- TextButton1378 = Instance.new("TextButton")
- Frame1379 = Instance.new("Frame")
- TextLabel1380 = Instance.new("TextLabel")
- TextButton1381 = Instance.new("TextButton")
- TextButton1382 = Instance.new("TextButton")
- TextButton1383 = Instance.new("TextButton")
- TextButton1384 = Instance.new("TextButton")
- TextLabel1385 = Instance.new("TextLabel")
- Frame1386 = Instance.new("Frame")
- TextLabel1387 = Instance.new("TextLabel")
- TextButton1388 = Instance.new("TextButton")
- TextButton1389 = Instance.new("TextButton")
- TextButton1390 = Instance.new("TextButton")
- TextButton1391 = Instance.new("TextButton")
- LocalScript1392 = Instance.new("LocalScript")
- Script1393 = Instance.new("Script")
- HopperBin1394 = Instance.new("HopperBin")
- Script1395 = Instance.new("Script")
- Script1396 = Instance.new("Script")
- Tool0.Name = "Building Tools"
- Tool0.Parent = mas
- Tool0.ToolTip = "Building Tools by F3X"
- LocalScript1.Name = "Building Tools by F3X"
- LocalScript1.Parent = Tool0
- table.insert(cors,sandbox(LocalScript1,function()
- ------------------------------------------
- -- Create references to important objects
- ------------------------------------------
- Services = {
- ["Workspace"] = Game:GetService( "Workspace" );
- ["Players"] = Game:GetService( "Players" );
- ["Lighting"] = Game:GetService( "Lighting" );
- ["Teams"] = Game:GetService( "Teams" );
- ["Debris"] = Game:GetService( "Debris" );
- ["MarketplaceService"] = Game:GetService( "MarketplaceService" );
- ["JointsService"] = Game.JointsService;
- ["BadgeService"] = Game:GetService( "BadgeService" );
- ["RunService"] = Game:GetService( "RunService" );
- ["ContentProvider"] = Game:GetService( "ContentProvider" );
- ["TeleportService"] = Game:GetService( "TeleportService" );
- ["SoundService"] = Game:GetService( "SoundService" );
- ["InsertService"] = Game:GetService( "InsertService" );
- ["CollectionService"] = Game:GetService( "CollectionService" );
- ["UserInputService"] = Game:GetService( "UserInputService" );
- ["GamePassService"] = Game:GetService( "GamePassService" );
- ["StarterPack"] = Game:GetService( "StarterPack" );
- ["StarterGui"] = Game:GetService( "StarterGui" );
- ["TestService"] = Game:GetService( "TestService" );
- ["ReplicatedStorage"] = Game:GetService( "ReplicatedStorage" );
- ["Selection"] = Game:GetService( "Selection" );
- ["CoreGui"] = Game:GetService( "CoreGui" );
- };
- Tool = script.Parent;
- Player = Services.Players.LocalPlayer;
- Mouse = nil;
- -- Determine whether this is the plugin or tool
- if plugin then
- ToolType = 'plugin';
- elseif Tool:IsA( 'Tool' ) then
- ToolType = 'tool';
- end;
- -- Get tool type-specific resources
- if ToolType == 'tool' then
- GUIContainer = Player:WaitForChild( 'PlayerGui' );
- in_server = not not Game:FindFirstChild( 'NetworkClient' );
- elseif ToolType == 'plugin' then
- GUIContainer = Services.CoreGui;
- in_server = not not Game:FindFirstChild( 'NetworkServer' );
- end;
- if in_server then
- Tool:WaitForChild( "GetAsync" );
- Tool:WaitForChild( "PostAsync" );
- GetAsync = function ( ... )
- return Tool.GetAsync:InvokeServer( ... );
- end;
- PostAsync = function ( ... )
- return Tool.PostAsync:InvokeServer( ... );
- end;
- end;
- dark_slanted_rectangle = "http://www.roblox.com/asset/?id=127774197";
- light_slanted_rectangle = "http://www.roblox.com/asset/?id=127772502";
- action_completion_sound = "http://www.roblox.com/asset/?id=99666917";
- expand_arrow = "http://www.roblox.com/asset/?id=134367382";
- tool_decal = "http://www.roblox.com/asset/?id=129748355";
- undo_active_decal = "http://www.roblox.com/asset/?id=141741408";
- undo_inactive_decal = "http://www.roblox.com/asset/?id=142074557";
- redo_active_decal = "http://www.roblox.com/asset/?id=141741327";
- redo_inactive_decal = "http://www.roblox.com/asset/?id=142074553";
- delete_active_decal = "http://www.roblox.com/asset/?id=141896298";
- delete_inactive_decal = "http://www.roblox.com/asset/?id=142074644";
- export_active_decal = "http://www.roblox.com/asset/?id=141741337";
- export_inactive_decal = "http://www.roblox.com/asset/?id=142074569";
- clone_active_decal = "http://www.roblox.com/asset/?id=142073926";
- clone_inactive_decal = "http://www.roblox.com/asset/?id=142074563";
- plugin_icon = "http://www.roblox.com/asset/?id=142287521";
- ------------------------------------------
- -- Load external dependencies
- ------------------------------------------
- RbxUtility = LoadLibrary( "RbxUtility" );
- Services.ContentProvider:Preload( dark_slanted_rectangle );
- Services.ContentProvider:Preload( light_slanted_rectangle );
- Services.ContentProvider:Preload( action_completion_sound );
- Services.ContentProvider:Preload( expand_arrow );
- Services.ContentProvider:Preload( tool_decal );
- Services.ContentProvider:Preload( undo_active_decal );
- Services.ContentProvider:Preload( undo_inactive_decal );
- Services.ContentProvider:Preload( redo_inactive_decal );
- Services.ContentProvider:Preload( redo_active_decal );
- Services.ContentProvider:Preload( delete_active_decal );
- Services.ContentProvider:Preload( delete_inactive_decal );
- Services.ContentProvider:Preload( export_active_decal );
- Services.ContentProvider:Preload( export_inactive_decal );
- Services.ContentProvider:Preload( clone_active_decal );
- Services.ContentProvider:Preload( clone_inactive_decal );
- Services.ContentProvider:Preload( plugin_icon );
- Tool:WaitForChild( "Interfaces" );
- repeat wait( 0 ) until _G.gloo;
- Gloo = _G.gloo;
- ------------------------------------------
- -- Define functions that are depended-upon
- ------------------------------------------
- function _findTableOccurrences( haystack, needle )
- -- Returns the positions of instances of `needle` in table `haystack`
- local positions = {};
- -- Add any indexes from `haystack` that have `needle`
- for index, value in pairs( haystack ) do
- if value == needle then
- table.insert( positions, index );
- end;
- end;
- return positions;
- end;
- function _getCollectionInfo( part_collection )
- -- Returns the size and position of collection of parts `part_collection`
- -- Get the corners
- local corners = {};
- -- Create shortcuts to certain things that are expensive to call constantly
- -- (note: otherwise it actually becomes an issue if the selection grows
- -- considerably large)
- local table_insert = table.insert;
- local newCFrame = CFrame.new;
- for _, Part in pairs( part_collection ) do
- local PartCFrame = Part.CFrame;
- local partCFrameOffset = PartCFrame.toWorldSpace;
- local PartSize = Part.Size / 2;
- local size_x, size_y, size_z = PartSize.x, PartSize.y, PartSize.z;
- table_insert( corners, partCFrameOffset( PartCFrame, newCFrame( size_x, size_y, size_z ) ) );
- table_insert( corners, partCFrameOffset( PartCFrame, newCFrame( -size_x, size_y, size_z ) ) );
- table_insert( corners, partCFrameOffset( PartCFrame, newCFrame( size_x, -size_y, size_z ) ) );
- table_insert( corners, partCFrameOffset( PartCFrame, newCFrame( size_x, size_y, -size_z ) ) );
- table_insert( corners, partCFrameOffset( PartCFrame, newCFrame( -size_x, size_y, -size_z ) ) );
- table_insert( corners, partCFrameOffset( PartCFrame, newCFrame( -size_x, -size_y, size_z ) ) );
- table_insert( corners, partCFrameOffset( PartCFrame, newCFrame( size_x, -size_y, -size_z ) ) );
- table_insert( corners, partCFrameOffset( PartCFrame, newCFrame( -size_x, -size_y, -size_z ) ) );
- end;
- -- Get the extents
- local x, y, z = {}, {}, {};
- for _, Corner in pairs( corners ) do
- table_insert( x, Corner.x );
- table_insert( y, Corner.y );
- table_insert( z, Corner.z );
- end;
- local x_min, y_min, z_min = math.min( unpack( x ) ),
- math.min( unpack( y ) ),
- math.min( unpack( z ) );
- local x_max, y_max, z_max = math.max( unpack( x ) ),
- math.max( unpack( y ) ),
- math.max( unpack( z ) );
- -- Get the size between the extents
- local x_size, y_size, z_size = x_max - x_min,
- y_max - y_min,
- z_max - z_min;
- local Size = Vector3.new( x_size, y_size, z_size );
- -- Get the centroid of the collection of points
- local Position = CFrame.new( x_min + ( x_max - x_min ) / 2,
- y_min + ( y_max - y_min ) / 2,
- z_min + ( z_max - z_min ) / 2 );
- -- Return the size of the collection of parts
- return Size, Position;
- end;
- function _round( number, places )
- -- Returns `number` rounded to the number of decimal `places`
- -- (from lua-users)
- local mult = 10 ^ ( places or 0 );
- return math.floor( number * mult + 0.5 ) / mult;
- end
- function _cloneTable( source )
- -- Returns a deep copy of table `source`
- -- Get a copy of `source`'s metatable, since the hacky method
- -- we're using to copy the table doesn't include its metatable
- local source_mt = getmetatable( source );
- -- Return a copy of `source` including its metatable
- return setmetatable( { unpack( source ) }, source_mt );
- end;
- function _getAllDescendants( Parent )
- -- Recursively gets all the descendants of `Parent` and returns them
- local descendants = {};
- for _, Child in pairs( Parent:GetChildren() ) do
- -- Add the direct descendants of `Parent`
- table.insert( descendants, Child );
- -- Add the descendants of each child
- for _, Subchild in pairs( _getAllDescendants( Child ) ) do
- table.insert( descendants, Subchild );
- end;
- end;
- return descendants;
- end;
- function _pointToScreenSpace( Point )
- -- Returns Vector3 `Point`'s position on the screen when rendered
- -- (kudos to stravant for this)
- local point = Services.Workspace.CurrentCamera.CoordinateFrame:pointToObjectSpace( Point );
- local aspectRatio = Mouse.ViewSizeX / Mouse.ViewSizeY;
- local hfactor = math.tan( math.rad( Services.Workspace.CurrentCamera.FieldOfView ) / 2 )
- local wfactor = aspectRatio * hfactor;
- local x = ( point.x / point.z ) / -wfactor;
- local y = ( point.y / point.z ) / hfactor;
- local screen_pos = Vector2.new( Mouse.ViewSizeX * ( 0.5 + 0.5 * x ), Mouse.ViewSizeY * ( 0.5 + 0.5 * y ) );
- if ( screen_pos.x < 0 or screen_pos.x > Mouse.ViewSizeX ) or ( screen_pos.y < 0 or screen_pos.y > Mouse.ViewSizeY ) then
- return nil;
- end;
- if Services.Workspace.CurrentCamera.CoordinateFrame:toObjectSpace( CFrame.new( Point ) ).z > 0 then
- return nil;
- end;
- return screen_pos;
- end;
- function _cloneParts( parts )
- -- Returns a table of cloned `parts`
- local new_parts = {};
- -- Copy the parts into `new_parts`
- for part_index, Part in pairs( parts ) do
- new_parts[part_index] = Part:Clone();
- end;
- return new_parts;
- end;
- function _replaceParts( old_parts, new_parts )
- -- Removes `old_parts` and inserts `new_parts`
- -- Remove old parts
- for _, OldPart in pairs( old_parts ) do
- OldPart.Parent = nil;
- end;
- -- Insert `new_parts
- for _, NewPart in pairs( new_parts ) do
- NewPart.Parent = Services.Workspace;
- NewPart:MakeJoints();
- end;
- end;
- function _splitString( str, delimiter )
- -- Returns a table of string `str` split by pattern `delimiter`
- local parts = {};
- local pattern = ( "([^%s]+)" ):format( delimiter );
- str:gsub( pattern, function ( part )
- table.insert( parts, part );
- end );
- return parts;
- end;
- function _generateSerializationID()
- -- Returns a random 5-character string
- -- with characters A-Z, a-z, and 0-9
- -- (there are 916,132,832 unique IDs)
- local characters = {
- "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
- "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
- "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
- local serialization_id = "";
- -- Pick out 5 random characters
- for _ = 1, 5 do
- serialization_id = serialization_id .. ( characters[math.random( #characters )] );
- end;
- return serialization_id;
- end;
- function _splitNumberListString( str )
- -- Returns the contents of _splitString( str, ", " ), except
- -- each value in the table is turned into a number
- -- Get the number strings
- local numbers = _splitString( str, ", " );
- -- Turn them into numbers
- for number_index, number in pairs( numbers ) do
- numbers[number_index] = tonumber( number );
- end;
- -- Return `numbers`
- return numbers;
- end;
- function _getSerializationPartType( Part )
- -- Returns a special number that determines the type of
- -- part `Part` is
- local Types = {
- Normal = 1,
- Truss = 2,
- Wedge = 3,
- Corner = 4,
- Cylinder = 5,
- Ball = 6,
- Seat = 7,
- VehicleSeat = 8,
- Spawn = 9
- };
- -- Return the appropriate type number
- if Part.ClassName == "Part" then
- if Part.Shape == Enum.PartType.Block then
- return Types.Normal;
- elseif Part.Shape == Enum.PartType.Cylinder then
- return Types.Cylinder;
- elseif Part.Shape == Enum.PartType.Ball then
- return Types.Ball;
- end;
- elseif Part.ClassName == "Seat" then
- return Types.Seat;
- elseif Part.ClassName == "VehicleSeat" then
- return Types.VehicleSeat;
- elseif Part.ClassName == "SpawnLocation" then
- return Types.Spawn;
- elseif Part.ClassName == "WedgePart" then
- return Types.Wedge;
- elseif Part.ClassName == "CornerWedgePart" then
- return Types.Corner;
- elseif Part.ClassName == "TrussPart" then
- return Types.Truss;
- end;
- end;
- function _serializeParts( parts )
- -- Returns JSON-encoded data about parts in
- -- table `parts` that can be used to recreate them
- local data = {
- version = 1,
- parts = {}
- };
- local objects = {};
- -- Store part data
- for _, Part in pairs( parts ) do
- local part_id = _generateSerializationID();
- local PartData = {
- _getSerializationPartType( Part ),
- _splitNumberListString( tostring( Part.Size ) ),
- _splitNumberListString( tostring( Part.CFrame ) ),
- Part.BrickColor.Number,
- Part.Material.Value,
- Part.Anchored,
- Part.CanCollide,
- Part.Reflectance,
- Part.Transparency,
- Part.TopSurface.Value,
- Part.BottomSurface.Value,
- Part.LeftSurface.Value,
- Part.RightSurface.Value,
- Part.FrontSurface.Value,
- Part.BackSurface.Value
- };
- data.parts[part_id] = PartData;
- objects[part_id] = Part;
- end;
- -- Get any welds in the selection
- local welds = {};
- for object_id, Object in pairs( objects ) do
- if Object:IsA( "BasePart" ) then
- for _, Joint in pairs( _getAllDescendants( Services.Workspace ) ) do
- if Joint:IsA( "Weld" ) and Joint.Name == "BTWeld" then
- if Joint.Part0 == Object and #_findTableOccurrences( objects, Joint.Part1 ) > 0 then
- table.insert( welds, Joint );
- end;
- end;
- end;
- end;
- end;
- -- Serialize any welds
- if #welds > 0 then
- data.welds = {};
- for _, Weld in pairs( welds ) do
- local weld_id = _generateSerializationID();
- local WeldData = {
- _findTableOccurrences( objects, Weld.Part0 )[1],
- _findTableOccurrences( objects, Weld.Part1 )[1],
- _splitNumberListString( tostring( Weld.C1 ) )
- };
- data.welds[weld_id] = WeldData;
- objects[weld_id] = Weld;
- end;
- end;
- -- Get any meshes in the selection
- local meshes = {};
- for _, Part in pairs( parts ) do
- local Mesh = _getChildOfClass( Part, "SpecialMesh" );
- if Mesh then
- table.insert( meshes, Mesh );
- end;
- end;
- -- Serialize any meshes
- if #meshes > 0 then
- data.meshes = {};
- for _, Mesh in pairs( meshes ) do
- local mesh_id = _generateSerializationID();
- local MeshData = {
- _findTableOccurrences( objects, Mesh.Parent )[1],
- Mesh.MeshType.Value,
- _splitNumberListString( tostring( Mesh.Scale ) ),
- Mesh.MeshId,
- Mesh.TextureId,
- _splitNumberListString( tostring( Mesh.VertexColor ) )
- };
- data.meshes[mesh_id] = MeshData;
- objects[mesh_id] = Mesh;
- end;
- end;
- -- Get any textures in the selection
- local textures = {};
- for _, Part in pairs( parts ) do
- local textures_found = _getChildrenOfClass( Part, "Texture" );
- for _, Texture in pairs( textures_found ) do
- table.insert( textures, Texture );
- end;
- local decals_found = _getChildrenOfClass( Part, "Decal" );
- for _, Decal in pairs( decals_found ) do
- table.insert( textures, Decal );
- end;
- end;
- -- Serialize any textures
- if #textures > 0 then
- data.textures = {};
- for _, Texture in pairs( textures ) do
- local texture_type;
- if Texture.ClassName == "Decal" then
- texture_type = 1;
- elseif Texture.ClassName == "Texture" then
- texture_type = 2;
- end;
- local texture_id = _generateSerializationID();
- local TextureData = {
- _findTableOccurrences( objects, Texture.Parent )[1],
- texture_type,
- Texture.Face.Value,
- Texture.Texture,
- Texture.Transparency,
- texture_type == 2 and Texture.StudsPerTileU or nil,
- texture_type == 2 and Texture.StudsPerTileV or nil
- };
- data.textures[texture_id] = TextureData;
- objects[texture_id] = Texture;
- end;
- end;
- -- Get any lights in the selection
- local lights = {};
- for _, Part in pairs( parts ) do
- local lights_found = _getChildrenOfClass( Part, "Light", true );
- for _, Light in pairs( lights_found ) do
- table.insert( lights, Light );
- end;
- end;
- -- Serialize any lights
- if #lights > 0 then
- data.lights = {};
- for _, Light in pairs( lights ) do
- local light_type;
- if Light:IsA( "PointLight" ) then
- light_type = 1;
- elseif Light:IsA( "SpotLight" ) then
- light_type = 2;
- end;
- local light_id = _generateSerializationID();
- local LightData = {
- _findTableOccurrences( objects, Light.Parent )[1];
- light_type,
- _splitNumberListString( tostring( Light.Color ) ),
- Light.Brightness,
- Light.Range,
- Light.Shadows,
- light_type == 2 and Light.Angle or nil,
- light_type == 2 and Light.Face.Value or nil
- };
- data.lights[light_id] = LightData;
- objects[light_id] = Light;
- end;
- end;
- -- Get any decorations in the selection
- local decorations = {};
- for _, Part in pairs( parts ) do
- table.insert( decorations, _getChildOfClass( Part, 'Smoke' ) )
- table.insert( decorations, _getChildOfClass( Part, 'Fire' ) );
- table.insert( decorations, _getChildOfClass( Part, 'Sparkles' ) );
- end;
- -- Serialize any decorations
- if #decorations > 0 then
- data.decorations = {};
- for _, Decoration in pairs( decorations ) do
- local decoration_type;
- if Decoration:IsA( 'Smoke' ) then
- decoration_type = 1;
- elseif Decoration:IsA( 'Fire' ) then
- decoration_type = 2;
- elseif Decoration:IsA( 'Sparkles' ) then
- decoration_type = 3;
- end;
- local decoration_id = _generateSerializationID();
- local DecorationData = {
- _findTableOccurrences( objects, Decoration.Parent )[1],
- decoration_type
- };
- if decoration_type == 1 then
- DecorationData[3] = _splitNumberListString( tostring( Decoration.Color ) );
- DecorationData[4] = Decoration.Opacity;
- DecorationData[5] = Decoration.RiseVelocity;
- DecorationData[6] = Decoration.Size;
- elseif decoration_type == 2 then
- DecorationData[3] = _splitNumberListString( tostring( Decoration.Color ) );
- DecorationData[4] = _splitNumberListString( tostring( Decoration.SecondaryColor ) );
- DecorationData[5] = Decoration.Heat;
- DecorationData[6] = Decoration.Size;
- elseif decoration_type == 3 then
- DecorationData[3] = _splitNumberListString( tostring( Decoration.SparkleColor ) );
- end;
- data.decorations[decoration_id] = DecorationData;
- objects[decoration_id] = Decoration;
- end;
- end;
- return RbxUtility.EncodeJSON( data );
- end;
- function _getChildOfClass( Parent, class_name, inherit )
- -- Returns the first child of `Parent` that is of class `class_name`
- -- or nil if it couldn't find any
- -- Look for a child of `Parent` of class `class_name` and return it
- if not inherit then
- for _, Child in pairs( Parent:GetChildren() ) do
- if Child.ClassName == class_name then
- return Child;
- end;
- end;
- else
- for _, Child in pairs( Parent:GetChildren() ) do
- if Child:IsA( class_name ) then
- return Child;
- end;
- end;
- end;
- return nil;
- end;
- function _getChildrenOfClass( Parent, class_name, inherit )
- -- Returns a table containing the children of `Parent` that are
- -- of class `class_name`
- local matches = {};
- if not inherit then
- for _, Child in pairs( Parent:GetChildren() ) do
- if Child.ClassName == class_name then
- table.insert( matches, Child );
- end;
- end;
- else
- for _, Child in pairs( Parent:GetChildren() ) do
- if Child:IsA( class_name ) then
- table.insert( matches, Child );
- end;
- end;
- end;
- return matches;
- end;
- function _HSVToRGB( hue, saturation, value )
- -- Returns the RGB equivalent of the given HSV-defined color
- -- (adapted from some code found around the web)
- -- If it's achromatic, just return the value
- if saturation == 0 then
- return value;
- end;
- -- Get the hue sector
- local hue_sector = math.floor( hue / 60 );
- local hue_sector_offset = ( hue / 60 ) - hue_sector;
- local p = value * ( 1 - saturation );
- local q = value * ( 1 - saturation * hue_sector_offset );
- local t = value * ( 1 - saturation * ( 1 - hue_sector_offset ) );
- if hue_sector == 0 then
- return value, t, p;
- elseif hue_sector == 1 then
- return q, value, p;
- elseif hue_sector == 2 then
- return p, value, t;
- elseif hue_sector == 3 then
- return p, q, value;
- elseif hue_sector == 4 then
- return t, p, value;
- elseif hue_sector == 5 then
- return value, p, q;
- end;
- end;
- function _RGBToHSV( red, green, blue )
- -- Returns the HSV equivalent of the given RGB-defined color
- -- (adapted from some code found around the web)
- local hue, saturation, value;
- local min_value = math.min( red, green, blue );
- local max_value = math.max( red, green, blue );
- value = max_value;
- local value_delta = max_value - min_value;
- -- If the color is not black
- if max_value ~= 0 then
- saturation = value_delta / max_value;
- -- If the color is purely black
- else
- saturation = 0;
- hue = -1;
- return hue, saturation, value;
- end;
- if red == max_value then
- hue = ( green - blue ) / value_delta;
- elseif green == max_value then
- hue = 2 + ( blue - red ) / value_delta;
- else
- hue = 4 + ( red - green ) / value_delta;
- end;
- hue = hue * 60;
- if hue < 0 then
- hue = hue + 360;
- end;
- return hue, saturation, value;
- end;
- ------------------------------------------
- -- Create data containers
- ------------------------------------------
- ActiveKeys = {};
- CurrentTool = nil;
- function equipTool( NewTool )
- -- If it's a different tool than the current one
- if CurrentTool ~= NewTool then
- -- Run (if existent) the old tool's `Unequipped` listener
- if CurrentTool and CurrentTool.Listeners.Unequipped then
- CurrentTool.Listeners.Unequipped();
- end;
- CurrentTool = NewTool;
- -- Recolor the handle
- if ToolType == 'tool' then
- Tool.Handle.BrickColor = NewTool.Color;
- end;
- -- Highlight the right button on the dock
- for _, Button in pairs( Dock.ToolButtons:GetChildren() ) do
- Button.BackgroundTransparency = 1;
- end;
- local Button = Dock.ToolButtons:FindFirstChild( getToolName( NewTool ) .. "Button" );
- if Button then
- Button.BackgroundTransparency = 0;
- end;
- -- Run (if existent) the new tool's `Equipped` listener
- if NewTool.Listeners.Equipped then
- NewTool.Listeners.Equipped();
- end;
- end;
- end;
- function cloneSelection()
- -- Clones the items in the selection
- -- Make sure that there are items in the selection
- if #Selection.Items > 0 then
- local item_copies = {};
- -- Make a copy of every item in the selection and add it to table `item_copies`
- for _, Item in pairs( Selection.Items ) do
- local ItemCopy = Item:Clone();
- ItemCopy.Parent = Services.Workspace;
- table.insert( item_copies, ItemCopy );
- end;
- -- Replace the selection with the copied items
- Selection:clear();
- for _, Item in pairs( item_copies ) do
- Selection:add( Item );
- end;
- local HistoryRecord = {
- copies = item_copies;
- unapply = function ( self )
- for _, Copy in pairs( self.copies ) do
- if Copy then
- Copy.Parent = nil;
- end;
- end;
- end;
- apply = function ( self )
- Selection:clear();
- for _, Copy in pairs( self.copies ) do
- if Copy then
- Copy.Parent = Services.Workspace;
- Copy:MakeJoints();
- Selection:add( Copy );
- end;
- end;
- end;
- };
- History:add( HistoryRecord );
- -- Play a confirmation sound
- local Sound = RbxUtility.Create "Sound" {
- Name = "BTActionCompletionSound";
- Pitch = 1.5;
- SoundId = action_completion_sound;
- Volume = 1;
- Parent = Player or Services.SoundService;
- };
- Sound:Play();
- Sound:Destroy();
- -- Highlight the outlines of the new parts
- coroutine.wrap( function ()
- for transparency = 1, 0.5, -0.1 do
- for Item, SelectionBox in pairs( SelectionBoxes ) do
- SelectionBox.Transparency = transparency;
- end;
- wait( 0.1 );
- end;
- end )();
- end;
- end;
- function deleteSelection()
- -- Deletes the items in the selection
- if #Selection.Items == 0 then
- return;
- end;
- local selection_items = _cloneTable( Selection.Items );
- -- Create a history record
- local HistoryRecord = {
- targets = selection_items;
- parents = {};
- apply = function ( self )
- for _, Target in pairs( self.targets ) do
- if Target then
- Target.Parent = nil;
- end;
- end;
- end;
- unapply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target.Parent = self.parents[Target];
- Target:MakeJoints();
- Selection:add( Target );
- end;
- end;
- end;
- };
- for _, Item in pairs( selection_items ) do
- HistoryRecord.parents[Item] = Item.Parent;
- Item.Parent = nil;
- end;
- History:add( HistoryRecord );
- end;
- function prismSelect()
- -- Selects all the parts within the area of the selected parts
- -- Make sure parts to define the area are present
- if #Selection.Items == 0 then
- return;
- end;
- local parts = {};
- -- Get all the parts in workspace
- local workspace_parts = {};
- local workspace_children = _getAllDescendants( Services.Workspace );
- for _, Child in pairs( workspace_children ) do
- if Child:IsA( 'BasePart' ) and not Selection:find( Child ) then
- table.insert( workspace_parts, Child );
- end;
- end;
- -- Go through each part and perform area tests on each one
- local checks = {};
- for _, Item in pairs( workspace_parts ) do
- checks[Item] = 0;
- for _, SelectionItem in pairs( Selection.Items ) do
- -- Calculate the position of the item in question in relation to the area-defining parts
- local offset = SelectionItem.CFrame:toObjectSpace( Item.CFrame );
- local extents = SelectionItem.Size / 2;
- -- Check the item off if it passed this test (if it's within the range of the extents)
- if ( math.abs( offset.x ) <= extents.x ) and ( math.abs( offset.y ) <= extents.y ) and ( math.abs( offset.z ) <= extents.z ) then
- checks[Item] = checks[Item] + 1;
- end;
- end;
- end;
- -- Delete the parts that were used to select the area
- local selection_items = _cloneTable( Selection.Items );
- local selection_item_parents = {};
- for _, Item in pairs( selection_items ) do
- selection_item_parents[Item] = Item.Parent;
- Item.Parent = nil;
- end;
- -- Select the parts that passed any area checks
- for _, Item in pairs( workspace_parts ) do
- if checks[Item] > 0 then
- Selection:add( Item );
- end;
- end;
- -- Add a history record
- History:add( {
- selection_parts = selection_items;
- selection_part_parents = selection_item_parents;
- new_selection = _cloneTable( Selection.Items );
- apply = function ( self )
- Selection:clear();
- for _, Item in pairs( self.selection_parts ) do
- Item.Parent = nil;
- end;
- for _, Item in pairs( self.new_selection ) do
- Selection:add( Item );
- end;
- end;
- unapply = function ( self )
- Selection:clear();
- for _, Item in pairs( self.selection_parts ) do
- Item.Parent = self.selection_part_parents[Item];
- Selection:add( Item );
- end;
- end;
- } );
- end;
- function toggleHelp()
- -- Make sure the dock is ready
- if not Dock then
- return;
- end;
- -- Toggle the visibility of the help tooltip
- Dock.HelpInfo.Visible = not Dock.HelpInfo.Visible;
- end;
- function getToolName( tool )
- -- Returns the name of `tool` as registered in `Tools`
- local name_search = _findTableOccurrences( Tools, tool );
- if #name_search > 0 then
- return name_search[1];
- end;
- end;
- function isSelectable( Object )
- -- Returns whether `Object` is selectable
- if not Object or not Object.Parent or not Object:IsA( "BasePart" ) or Object.Locked or Selection:find( Object ) then
- return false;
- end;
- -- If it passes all checks, return true
- return true;
- end;
- -- Keep some state data
- clicking = false;
- selecting = false;
- click_x, click_y = 0, 0;
- override_selection = false;
- SelectionBoxes = {};
- SelectionExistenceListeners = {};
- SelectionBoxColor = BrickColor.new( "Cyan" );
- TargetBox = nil;
- -- Keep a container for temporary connections
- -- from the platform
- Connections = {};
- -- Set the grip for the handle
- if ToolType == 'tool' then
- Tool.Grip = CFrame.new( 0, 0, 0.4 );
- end;
- -- Make sure the UI container gets placed
- UI = RbxUtility.Create "ScreenGui" {
- Name = "Building Tools by F3X (UI)"
- };
- if ToolType == 'tool' then
- UI.Parent = GUIContainer;
- elseif ToolType == 'plugin' then
- UI.Parent = Services.CoreGui;
- end;
- Dragger = nil;
- function updateSelectionBoxColor()
- -- Updates the color of the selectionboxes
- for _, SelectionBox in pairs( SelectionBoxes ) do
- SelectionBox.Color = SelectionBoxColor;
- end;
- end;
- Selection = {
- ["Items"] = {};
- -- Provide events to listen to changes in the selection
- ["Changed"] = RbxUtility.CreateSignal();
- ["ItemAdded"] = RbxUtility.CreateSignal();
- ["ItemRemoved"] = RbxUtility.CreateSignal();
- -- Provide a method to get an item's index in the selection
- ["find"] = function ( self, Needle )
- -- Look through all the selected items and return the matching item's index
- for item_index, Item in pairs( self.Items ) do
- if Item == Needle then
- return item_index;
- end;
- end;
- -- Otherwise, return `nil`
- end;
- -- Provide a method to add items to the selection
- ["add"] = function ( self, NewPart )
- -- Make sure `NewPart` is selectable
- if not isSelectable( NewPart ) then
- return false;
- end;
- -- Make sure `NewPart` isn't already in the selection
- if #_findTableOccurrences( self.Items, NewPart ) > 0 then
- return false;
- end;
- -- Insert it into the selection
- table.insert( self.Items, NewPart );
- -- Add its SelectionBox
- SelectionBoxes[NewPart] = Instance.new( "SelectionBox", UI );
- SelectionBoxes[NewPart].Name = "BTSelectionBox";
- SelectionBoxes[NewPart].Color = SelectionBoxColor;
- SelectionBoxes[NewPart].Adornee = NewPart;
- SelectionBoxes[NewPart].Transparency = 0.5;
- -- Remove any target selection box focus
- if NewPart == TargetBox.Adornee then
- TargetBox.Adornee = nil;
- end;
- -- Make sure to remove the item from the selection when it's deleted
- SelectionExistenceListeners[NewPart] = NewPart.AncestryChanged:connect( function ( Object, NewParent )
- if NewParent == nil then
- Selection:remove( NewPart );
- end;
- end );
- -- Provide a reference to the last item added to the selection (i.e. NewPart)
- self:focus( NewPart );
- -- Fire events
- self.ItemAdded:fire( NewPart );
- self.Changed:fire();
- end;
- -- Provide a method to remove items from the selection
- ["remove"] = function ( self, Item )
- -- Make sure selection item `Item` exists
- if not self:find( Item ) then
- return false;
- end;
- -- Remove `Item`'s SelectionBox
- local SelectionBox = SelectionBoxes[Item];
- if SelectionBox then
- SelectionBox:Destroy();
- end;
- SelectionBoxes[Item] = nil;
- -- Delete the item from the selection
- table.remove( self.Items, self:find( Item ) );
- -- If it was logged as the last item, change it
- if self.Last == Item then
- self:focus( ( #self.Items > 0 ) and self.Items[#self.Items] or nil );
- end;
- -- Delete the existence listeners of the item
- SelectionExistenceListeners[Item]:disconnect();
- SelectionExistenceListeners[Item] = nil;
- -- Fire events
- self.ItemRemoved:fire( Item );
- self.Changed:fire();
- end;
- -- Provide a method to clear the selection
- ["clear"] = function ( self )
- -- Go through all the items in the selection and call `self.remove` on them
- for _, Item in pairs( _cloneTable( self.Items ) ) do
- self:remove( Item );
- end;
- end;
- -- Provide a method to change the focus of the selection
- ["focus"] = function ( self, NewFocus )
- -- Change the focus
- self.Last = NewFocus;
- -- Fire events
- self.Changed:fire();
- end;
- };
- -- Keep the Studio selection up-to-date (if applicable)
- if ToolType == 'plugin' then
- Selection.Changed:connect( function ()
- Services.Selection:Set( Selection.Items );
- end );
- end;
- Tools = {};
- ------------------------------------------
- -- Define other utilities needed by tools
- ------------------------------------------
- function createDropdown()
- local Frame = RbxUtility.Create "Frame" {
- Name = "Dropdown";
- Size = UDim2.new( 0, 20, 0, 20 );
- BackgroundTransparency = 1;
- BorderSizePixel = 0;
- ClipsDescendants = true;
- };
- RbxUtility.Create "ImageLabel" {
- Parent = Frame;
- Name = "Arrow";
- BackgroundTransparency = 1;
- BorderSizePixel = 0;
- Image = expand_arrow;
- Position = UDim2.new( 1, -21, 0, 3 );
- Size = UDim2.new( 0, 20, 0, 20 );
- ZIndex = 3;
- };
- local DropdownObject = {
- -- Provide access to the actual frame
- Frame = Frame;
- -- Keep a list of all the options in the dropdown
- _options = {};
- -- Provide a function to add options to the dropdown
- addOption = function ( self, option )
- -- Add the option to the list
- table.insert( self._options, option );
- -- Create the GUI for the option
- local Button = RbxUtility.Create "TextButton" {
- Parent = self.Frame;
- BackgroundColor3 = Color3.new( 0, 0, 0 );
- BackgroundTransparency = 0.3;
- BorderColor3 = Color3.new( 27 / 255, 42 / 255, 53 / 255 );
- BorderSizePixel = 1;
- Name = option;
- Position = UDim2.new( math.ceil( #self._options / 9 ) - 1, 0, 0, 25 * ( ( #self._options % 9 == 0 ) and 9 or ( #self._options % 9 ) ) );
- Size = UDim2.new( 1, 0, 0, 25 );
- ZIndex = 3;
- Text = "";
- };
- local Label = RbxUtility.Create "TextLabel" {
- Parent = Button;
- BackgroundTransparency = 1;
- BorderSizePixel = 0;
- Position = UDim2.new( 0, 6, 0, 0 );
- Size = UDim2.new( 1, -30, 1, 0 );
- ZIndex = 3;
- Font = Enum.Font.ArialBold;
- FontSize = Enum.FontSize.Size12;
- Text = option;
- TextColor3 = Color3.new( 1, 1, 1 );
- TextXAlignment = Enum.TextXAlignment.Left;
- TextYAlignment = Enum.TextYAlignment.Center;
- };
- -- Return the button object
- return Button;
- end;
- selectOption = function ( self, option )
- self.Frame.MainButton.CurrentOption.Text = option;
- end;
- open = false;
- toggle = function ( self )
- -- If it's open, close it
- if self.open then
- self.Frame.MainButton.BackgroundTransparency = 0.3;
- self.Frame.ClipsDescendants = true;
- self.open = false;
- -- If it's not open, open it
- else
- self.Frame.MainButton.BackgroundTransparency = 0;
- self.Frame.ClipsDescendants = false;
- self.open = true;
- end;
- end;
- };
- -- Create the GUI for the option
- local MainButton = RbxUtility.Create "TextButton" {
- Parent = Frame;
- Name = "MainButton";
- BackgroundColor3 = Color3.new( 0, 0, 0 );
- BackgroundTransparency = 0.3;
- BorderColor3 = Color3.new( 27 / 255, 42 / 255, 53 / 255 );
- BorderSizePixel = 1;
- Position = UDim2.new( 0, 0, 0, 0 );
- Size = UDim2.new( 1, 0, 0, 25 );
- ZIndex = 2;
- Text = "";
- -- Toggle the dropdown when pressed
- [RbxUtility.Create.E "MouseButton1Up"] = function ()
- DropdownObject:toggle();
- end;
- };
- RbxUtility.Create "TextLabel" {
- Parent = MainButton;
- Name = "CurrentOption";
- BackgroundTransparency = 1;
- BorderSizePixel = 0;
- Position = UDim2.new( 0, 6, 0, 0 );
- Size = UDim2.new( 1, -30, 1, 0 );
- ZIndex = 3;
- Font = Enum.Font.ArialBold;
- FontSize = Enum.FontSize.Size12;
- Text = "";
- TextColor3 = Color3.new( 1, 1, 1 );
- TextXAlignment = Enum.TextXAlignment.Left;
- TextYAlignment = Enum.TextYAlignment.Center;
- };
- return DropdownObject;
- end;
- ------------------------------------------
- -- Provide an interface to the 2D
- -- selection system
- ------------------------------------------
- Select2D = {
- -- Keep state data
- ["enabled"] = false;
- -- Keep objects
- ["GUI"] = nil;
- -- Keep temporary, disposable connections
- ["Connections"] = {};
- -- Provide an interface to the functions
- ["start"] = function ( self )
- if enabled then
- return;
- end;
- self.enabled = true;
- -- Create the GUI
- self.GUI = RbxUtility.Create "ScreenGui" {
- Name = "BTSelectionRectangle";
- Parent = UI;
- };
- local Rectangle = RbxUtility.Create "Frame" {
- Name = "Rectangle";
- Active = false;
- Parent = self.GUI;
- BackgroundColor3 = Color3.new( 0, 0, 0 );
- BackgroundTransparency = 0.5;
- BorderSizePixel = 0;
- Position = UDim2.new( 0, math.min( click_x, Mouse.X ), 0, math.min( click_y, Mouse.Y ) );
- Size = UDim2.new( 0, math.max( click_x, Mouse.X ) - math.min( click_x, Mouse.X ), 0, math.max( click_y, Mouse.Y ) - math.min( click_y, Mouse.Y ) );
- };
- -- Listen for when to resize the selection
- self.Connections.SelectionResize = Mouse.Move:connect( function ()
- Rectangle.Position = UDim2.new( 0, math.min( click_x, Mouse.X ), 0, math.min( click_y, Mouse.Y ) );
- Rectangle.Size = UDim2.new( 0, math.max( click_x, Mouse.X ) - math.min( click_x, Mouse.X ), 0, math.max( click_y, Mouse.Y ) - math.min( click_y, Mouse.Y ) );
- end );
- -- Listen for when the selection ends
- self.Connections.SelectionEnd = Mouse.Button1Up:connect( function ()
- self:select();
- self:finish();
- end );
- end;
- ["select"] = function ( self )
- if not self.enabled then
- return;
- end;
- for _, Object in pairs( _getAllDescendants( Services.Workspace ) ) do
- -- Make sure we can select this part
- if isSelectable( Object ) then
- -- Check if the part is rendered within the range of the selection area
- local PartPosition = _pointToScreenSpace( Object.Position );
- if PartPosition then
- local left_check = PartPosition.x >= self.GUI.Rectangle.AbsolutePosition.x;
- local right_check = PartPosition.x <= ( self.GUI.Rectangle.AbsolutePosition.x + self.GUI.Rectangle.AbsoluteSize.x );
- local top_check = PartPosition.y >= self.GUI.Rectangle.AbsolutePosition.y;
- local bottom_check = PartPosition.y <= ( self.GUI.Rectangle.AbsolutePosition.y + self.GUI.Rectangle.AbsoluteSize.y );
- -- If the part is within the selection area, select it
- if left_check and right_check and top_check and bottom_check then
- Selection:add( Object );
- end;
- end;
- end;
- end;
- end;
- ["finish"] = function ( self )
- if not self.enabled then
- return;
- end;
- -- Disconnect temporary connections
- for connection_index, Connection in pairs( self.Connections ) do
- Connection:disconnect();
- self.Connections[connection_index] = nil;
- end;
- -- Remove temporary objects
- self.GUI:Destroy();
- self.GUI = nil;
- self.enabled = false;
- end;
- };
- ------------------------------------------
- -- Provide an interface to the edge
- -- selection system
- ------------------------------------------
- SelectEdge = {
- -- Keep state data
- ["enabled"] = false;
- ["started"] = false;
- -- Keep objects
- ["Marker"] = nil;
- ["MarkerOutline"] = RbxUtility.Create "SelectionBox" {
- Color = BrickColor.new( "Institutional white" );
- Parent = UI;
- Name = "BTEdgeSelectionMarkerOutline";
- };
- -- Keep temporary, disposable connections
- ["Connections"] = {};
- -- Provide an interface to the functions
- ["start"] = function ( self, edgeSelectionCallback )
- if self.started then
- return;
- end;
- -- Listen for when to engage in selection
- self.Connections.KeyListener = Mouse.KeyDown:connect( function ( key )
- local key = key:lower();
- local key_code = key:byte();
- if key == "t" and #Selection.Items > 0 then
- self:enable( edgeSelectionCallback );
- end;
- end );
- self.started = true;
- end;
- ["enable"] = function ( self, edgeSelectionCallback )
- if self.enabled then
- return;
- end;
- self.Connections.MoveListener = Mouse.Move:connect( function ()
- -- Make sure the target can be selected
- if not Selection:find( Mouse.Target ) then
- return;
- end;
- -- Calculate the proximity to each edge
- local Proximity = {};
- local edges = {};
- -- Create shortcuts to certain things that are expensive to call constantly
- local table_insert = table.insert;
- local newCFrame = CFrame.new;
- local PartCFrame = Mouse.Target.CFrame;
- local partCFrameOffset = PartCFrame.toWorldSpace;
- local PartSize = Mouse.Target.Size / 2;
- local size_x, size_y, size_z = PartSize.x, PartSize.y, PartSize.z;
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( size_x, size_y, size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( -size_x, size_y, size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( size_x, -size_y, size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( size_x, size_y, -size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( -size_x, size_y, -size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( -size_x, -size_y, size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( size_x, -size_y, -size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( -size_x, -size_y, -size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( size_x, size_y, 0 ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( size_x, 0, size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( 0, size_y, size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( size_x, 0, 0 ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( 0, size_y, 0 ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( 0, 0, size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( -size_x, size_y, 0 ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( -size_x, 0, size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( 0, -size_y, size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( -size_x, 0, 0 ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( 0, -size_y, 0 ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( 0, 0, -size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( size_x, -size_y, 0 ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( size_x, 0, -size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( 0, size_y, -size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( -size_x, -size_y, 0 ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( -size_x, 0, -size_z ) ) );
- table_insert( edges, partCFrameOffset( PartCFrame, newCFrame( 0, -size_y, -size_z ) ) );
- -- Calculate the proximity of every edge to the mouse
- for edge_index, Edge in pairs( edges ) do
- Proximity[edge_index] = ( Mouse.Hit.p - Edge.p ).magnitude;
- end;
- -- Get the closest edge to the mouse
- local highest_proximity = 1;
- for proximity_index, proximity in pairs( Proximity ) do
- if proximity < Proximity[highest_proximity] then
- highest_proximity = proximity_index;
- end;
- end;
- -- Replace the current target edge (if any)
- local ClosestEdge = edges[highest_proximity];
- if self.Marker then
- self.Marker:Destroy();
- end;
- self.Marker = RbxUtility.Create "Part" {
- Name = "BTEdgeSelectionMarker";
- Anchored = true;
- Locked = true;
- CanCollide = false;
- Transparency = 1;
- FormFactor = Enum.FormFactor.Custom;
- Size = Vector3.new( 0.2, 0.2, 0.2 );
- CFrame = ClosestEdge;
- };
- self.MarkerOutline.Adornee = self.Marker;
- end );
- self.Connections.ClickListener = Mouse.Button1Up:connect( function ()
- override_selection = true;
- self:select( edgeSelectionCallback );
- end );
- self.enabled = true;
- end;
- ["select"] = function ( self, callback )
- if not self.enabled or not self.Marker then
- return;
- end;
- self.MarkerOutline.Adornee = self.Marker;
- callback( self.Marker );
- -- Stop treating it like a marker
- self.Marker = nil;
- self:disable();
- end;
- ["disable"] = function ( self )
- if not self.enabled then
- return;
- end;
- -- Disconnect unnecessary temporary connections
- if self.Connections.ClickListener then
- self.Connections.ClickListener:disconnect();
- self.Connections.ClickListener = nil;
- end;
- if self.Connections.MoveListener then
- self.Connections.MoveListener:disconnect();
- self.Connections.MoveListener = nil;
- end;
- -- Remove temporary objects
- if self.Marker then
- self.Marker:Destroy();
- end;
- self.Marker = nil;
- self.MarkerOutline.Adornee = nil;
- self.enabled = false;
- end;
- ["stop"] = function ( self )
- if not self.started then
- return;
- end;
- -- Disconnect & remove all temporary connections
- for connection_index, Connection in pairs( self.Connections ) do
- Connection:disconnect();
- self.Connections[connection_index] = nil;
- end;
- -- Remove temporary objects
- if self.Marker then
- self.Marker:Destroy();
- end;
- self.started = false;
- end;
- };
- ------------------------------------------
- -- Provide an interface to the history
- -- system
- ------------------------------------------
- History = {
- -- Keep a container for the actual history data
- ["Data"] = {};
- -- Keep state data
- ["index"] = 0;
- -- Provide events for the platform to listen for changes
- ["Changed"] = RbxUtility.CreateSignal();
- -- Provide functions to control the system
- ["undo"] = function ( self )
- -- Make sure we're not getting out of boundary
- if self.index - 1 < 0 then
- return;
- end;
- -- Fetch the history record & unapply it
- local CurrentRecord = self.Data[self.index];
- CurrentRecord:unapply();
- -- Go back in the history
- self.index = self.index - 1;
- -- Fire the relevant events
- self.Changed:fire();
- end;
- ["redo"] = function ( self )
- -- Make sure we're not getting out of boundary
- if self.index + 1 > #self.Data then
- return;
- end;
- -- Go forward in the history
- self.index = self.index + 1;
- -- Fetch the new history record & apply it
- local NewRecord = self.Data[self.index];
- NewRecord:apply();
- -- Fire the relevant events
- self.Changed:fire();
- end;
- ["add"] = function ( self, Record )
- -- Place the record in its right spot
- self.Data[self.index + 1] = Record;
- -- Advance the history index
- self.index = self.index + 1;
- -- Clear out the following history
- for index = self.index + 1, #self.Data do
- self.Data[index] = nil;
- end;
- -- Fire the relevant events
- self.Changed:fire();
- end;
- };
- ------------------------------------------
- -- Provide an interface color picker
- -- system
- ------------------------------------------
- ColorPicker = {
- -- Keep some state data
- ["enabled"] = false;
- ["callback"] = nil;
- ["track_mouse"] = nil;
- ["hue"] = 0;
- ["saturation"] = 1;
- ["value"] = 1;
- -- Keep the current GUI here
- ["GUI"] = nil;
- -- Keep temporary, disposable connections here
- ["Connections"] = {};
- -- Provide an interface to the functions
- ["start"] = function ( self, callback, start_color )
- -- Replace any existing color pickers
- if self.enabled then
- self:cancel();
- end;
- self.enabled = true;
- -- Create the GUI
- self.GUI = Tool.Interfaces.BTHSVColorPicker:Clone();
- self.GUI.Parent = UI;
- -- Register the callback function for when we're done here
- self.callback = callback;
- -- Update the GUI
- local start_color = start_color or Color3.new( 1, 0, 0 );
- self:_changeColor( _RGBToHSV( start_color.r, start_color.g, start_color.b ) );
- -- Add functionality to the GUI's interactive elements
- table.insert( self.Connections, self.GUI.HueSaturation.MouseButton1Down:connect( function ( x, y )
- self.track_mouse = 'hue-saturation';
- self:_onMouseMove( x, y );
- end ) );
- table.insert( self.Connections, self.GUI.HueSaturation.MouseButton1Up:connect( function ()
- self.track_mouse = nil;
- end ) );
- table.insert( self.Connections, self.GUI.MouseMoved:connect( function ( x, y )
- self:_onMouseMove( x, y );
- end ) );
- table.insert( self.Connections, self.GUI.Value.MouseButton1Down:connect( function ( x, y )
- self.track_mouse = 'value';
- self:_onMouseMove( x, y );
- end ) );
- table.insert( self.Connections, self.GUI.Value.MouseButton1Up:connect( function ()
- self.track_mouse = nil;
- end ) );
- table.insert( self.Connections, self.GUI.OkButton.MouseButton1Up:connect( function ()
- self:finish();
- end ) );
- table.insert( self.Connections, self.GUI.CancelButton.MouseButton1Up:connect( function ()
- self:cancel();
- end ) );
- table.insert( self.Connections, self.GUI.HueOption.Input.TextButton.MouseButton1Down:connect( function ()
- self.GUI.HueOption.Input.TextBox:CaptureFocus();
- end ) );
- table.insert( self.Connections, self.GUI.HueOption.Input.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( self.GUI.HueOption.Input.TextBox.Text );
- if potential_new then
- if potential_new > 360 then
- potential_new = 360;
- elseif potential_new < 0 then
- potential_new = 0;
- end;
- self:_changeColor( potential_new, self.saturation, self.value );
- else
- self:_updateGUI();
- end;
- end ) );
- table.insert( self.Connections, self.GUI.SaturationOption.Input.TextButton.MouseButton1Down:connect( function ()
- self.GUI.SaturationOption.Input.TextBox:CaptureFocus();
- end ) );
- table.insert( self.Connections, self.GUI.SaturationOption.Input.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( ( self.GUI.SaturationOption.Input.TextBox.Text:gsub( '%%', '' ) ) );
- if potential_new then
- if potential_new > 100 then
- potential_new = 100;
- elseif potential_new < 0 then
- potential_new = 0;
- end;
- self:_changeColor( self.hue, potential_new / 100, self.value );
- else
- self:_updateGUI();
- end;
- end ) );
- table.insert( self.Connections, self.GUI.ValueOption.Input.TextButton.MouseButton1Down:connect( function ()
- self.GUI.ValueOption.Input.TextBox:CaptureFocus();
- end ) );
- table.insert( self.Connections, self.GUI.ValueOption.Input.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( ( self.GUI.ValueOption.Input.TextBox.Text:gsub( '%%', '' ) ) );
- if potential_new then
- if potential_new < 0 then
- potential_new = 0;
- elseif potential_new > 100 then
- potential_new = 100;
- end;
- self:_changeColor( self.hue, self.saturation, potential_new / 100 );
- else
- self:_updateGUI();
- end;
- end ) );
- end;
- ["_onMouseMove"] = function ( self, x, y )
- if not self.track_mouse then
- return;
- end;
- if self.track_mouse == 'hue-saturation' then
- -- Calculate the mouse position relative to the graph
- local graph_x, graph_y = x - self.GUI.HueSaturation.AbsolutePosition.x, y - self.GUI.HueSaturation.AbsolutePosition.y;
- -- Make sure we're not going out of bounds
- if graph_x < 0 then
- graph_x = 0;
- elseif graph_x > self.GUI.HueSaturation.AbsoluteSize.x then
- graph_x = self.GUI.HueSaturation.AbsoluteSize.x;
- end;
- if graph_y < 0 then
- graph_y = 0;
- elseif graph_y > self.GUI.HueSaturation.AbsoluteSize.y then
- graph_y = self.GUI.HueSaturation.AbsoluteSize.y;
- end;
- -- Calculate the new color and change it
- self:_changeColor( 359 * graph_x / 209, 1 - graph_y / 200, self.value );
- elseif self.track_mouse == 'value' then
- -- Calculate the mouse position relative to the value bar
- local bar_y = y - self.GUI.Value.AbsolutePosition.y;
- -- Make sure we're not going out of bounds
- if bar_y < 0 then
- bar_y = 0;
- elseif bar_y > self.GUI.Value.AbsoluteSize.y then
- bar_y = self.GUI.Value.AbsoluteSize.y;
- end;
- -- Calculate the new color and change it
- self:_changeColor( self.hue, self.saturation, 1 - bar_y / 200 );
- end;
- end;
- ["_changeColor"] = function ( self, hue, saturation, value )
- if hue ~= hue then
- hue = 359;
- end;
- self.hue = hue;
- self.saturation = saturation == 0 and 0.01 or saturation;
- self.value = value;
- self:_updateGUI();
- end;
- ["_updateGUI"] = function ( self )
- self.GUI.HueSaturation.Cursor.Position = UDim2.new( 0, 209 * self.hue / 360 - 8, 0, ( 1 - self.saturation ) * 200 - 8 );
- self.GUI.Value.Cursor.Position = UDim2.new( 0, -2, 0, ( 1 - self.value ) * 200 - 8 );
- local color = Color3.new( _HSVToRGB( self.hue, self.saturation, self.value ) );
- self.GUI.ColorDisplay.BackgroundColor3 = color;
- self.GUI.Value.ColorBG.BackgroundColor3 = Color3.new( _HSVToRGB( self.hue, self.saturation, 1 ) );
- self.GUI.HueOption.Bar.BackgroundColor3 = color;
- self.GUI.SaturationOption.Bar.BackgroundColor3 = color;
- self.GUI.ValueOption.Bar.BackgroundColor3 = color;
- self.GUI.HueOption.Input.TextBox.Text = math.floor( self.hue );
- self.GUI.SaturationOption.Input.TextBox.Text = math.floor( self.saturation * 100 ) .. "%";
- self.GUI.ValueOption.Input.TextBox.Text = math.floor( self.value * 100 ) .. "%";
- end;
- ["finish"] = function ( self )
- if not self.enabled then
- return;
- end;
- -- Remove the GUI
- if self.GUI then
- self.GUI:Destroy();
- end;
- self.GUI = nil;
- self.track_mouse = nil;
- -- Disconnect all temporary connections
- for connection_index, connection in pairs( self.Connections ) do
- connection:disconnect();
- self.Connections[connection_index] = nil;
- end;
- -- Call the callback function that was provided to us
- self.callback( self.hue, self.saturation, self.value );
- self.callback = nil;
- self.enabled = false;
- end;
- ["cancel"] = function ( self )
- if not self.enabled then
- return;
- end;
- -- Remove the GUI
- if self.GUI then
- self.GUI:Destroy();
- end;
- self.GUI = nil;
- self.track_mouse = nil;
- -- Disconnect all temporary connections
- for connection_index, connection in pairs( self.Connections ) do
- connection:disconnect();
- self.Connections[connection_index] = nil;
- end;
- -- Call the callback function that was provided to us
- self.callback();
- self.callback = nil;
- self.enabled = false;
- end;
- };
- ------------------------------------------
- -- Provide an interface to the
- -- import/export system
- ------------------------------------------
- IE = {
- ["export"] = function ()
- if #Selection.Items == 0 then
- return;
- end;
- local serialized_selection = _serializeParts( Selection.Items );
- -- Dump to logs
- -- Services.TestService:Warn( false, "[Building Tools by F3X] Exported Model: \n" .. serialized_selection );
- -- Get ready to upload to the web for retrieval
- local upload_data;
- local cancelUpload;
- -- Create the export dialog
- local Dialog = Tool.Interfaces.BTExportDialog:Clone();
- Dialog.Loading.Size = UDim2.new( 1, 0, 0, 0 );
- Dialog.Parent = UI;
- Dialog.Loading:TweenSize( UDim2.new( 1, 0, 0, 80 ), Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.25 );
- Dialog.Loading.CloseButton.MouseButton1Up:connect( function ()
- cancelUpload();
- Dialog:Destroy();
- end );
- -- Run the upload/post-upload/failure code in a coroutine
- -- so it can be cancelled
- coroutine.resume( coroutine.create( function ()
- cancelUpload = function ()
- coroutine.yield();
- end;
- local upload_attempt = ypcall( function ()
- upload_data = PostAsync( "http://www.f3xteam.com/bt/export", serialized_selection );
- end );
- -- Make sure we're in a server
- if ToolType == 'plugin' and not in_server then
- Dialog.Loading.TextLabel.Text = "Use Tools > Test > Start Server to export from Studio";
- Dialog.Loading.TextLabel.TextWrapped = true;
- Dialog.Loading.CloseButton.Position = UDim2.new( 0, 0, 0, 50 );
- Dialog.Loading.CloseButton.Text = 'Got it';
- return;
- end;
- -- Fail graciously
- if not upload_attempt then
- Dialog.Loading.TextLabel.Text = "Upload failed";
- Dialog.Loading.CloseButton.Text = 'Ok :(';
- return;
- end;
- if not ( upload_data and type( upload_data ) == 'string' and upload_data:len() > 0 ) then
- Dialog.Loading.TextLabel.Text = "Upload failed";
- Dialog.Loading.CloseButton.Text = 'Ok ;(';
- return;
- end;
- if not pcall( function () upload_data = RbxUtility.DecodeJSON( upload_data ); end ) or not upload_data then
- Dialog.Loading.TextLabel.Text = "Upload failed";
- Dialog.Loading.CloseButton.Text = "Ok :'(";
- return;
- end;
- if not upload_data.success then
- Dialog.Loading.TextLabel.Text = "Upload failed";
- Dialog.Loading.CloseButton.Text = "Ok :''(";
- end;
- print( "[Building Tools by F3X] Uploaded Export: " .. upload_data.id );
- Dialog.Loading.Visible = false;
- Dialog.Info.Size = UDim2.new( 1, 0, 0, 0 );
- Dialog.Info.CreationID.Text = upload_data.id;
- Dialog.Info.Visible = true;
- Dialog.Info:TweenSize( UDim2.new( 1, 0, 0, 75 ), Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.25 );
- Dialog.Tip.Size = UDim2.new( 1, 0, 0, 0 );
- Dialog.Tip.Visible = true;
- Dialog.Tip:TweenSize( UDim2.new( 1, 0, 0, 30 ), Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.25 );
- Dialog.Close.Size = UDim2.new( 1, 0, 0, 0 );
- Dialog.Close.Visible = true;
- Dialog.Close:TweenSize( UDim2.new( 1, 0, 0, 20 ), Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.25 );
- Dialog.Close.Button.MouseButton1Up:connect( function ()
- Dialog:Destroy();
- end );
- -- Play a confirmation sound
- local Sound = RbxUtility.Create "Sound" {
- Name = "BTActionCompletionSound";
- Pitch = 1.5;
- SoundId = action_completion_sound;
- Volume = 1;
- Parent = Player or Services.SoundService;
- };
- Sound:Play();
- Sound:Destroy();
- end ) );
- end;
- };
- ------------------------------------------
- -- Prepare the dock UI
- ------------------------------------------
- Tooltips = {};
- Dock = Tool.Interfaces:WaitForChild( "BTDockGUI" ):Clone();
- Dock.Parent = UI;
- Dock.Visible = false;
- -- Add functionality to each tool button
- for _, ToolButton in pairs( Dock.ToolButtons:GetChildren() ) do
- -- Get the tool name and the tool
- local tool_name = ToolButton.Name:match( "(.+)Button" );
- if tool_name then
- -- Create the click connection
- ToolButton.MouseButton1Up:connect( function ()
- local Tool = Tools[tool_name];
- if Tool then
- equipTool( Tool );
- end;
- end );
- ToolButton.MouseEnter:connect( function ()
- local Tooltip = Tooltips[tool_name];
- if Tooltip then
- Tooltip:focus( 'button' );
- end;
- end );
- ToolButton.MouseLeave:connect( function ()
- local Tooltip = Tooltips[tool_name];
- if Tooltip then
- Tooltip:unfocus( 'button' );
- end;
- end );
- end;
- end;
- -- Prepare the tooltips
- for _, Tooltip in pairs( Dock.Tooltips:GetChildren() ) do
- local tool_name = Tooltip.Name:match( "(.+)Info" );
- Tooltips[tool_name] = {
- GUI = Tooltip;
- button_focus = false;
- tooltip_focus = false;
- focus = function ( self, source )
- if Dock.HelpInfo.Visible then
- return;
- end;
- if source == 'button' then
- self.button_focus = true;
- elseif source == 'tooltip' then
- self.tooltip_focus = true;
- end;
- for _, Tooltip in pairs( Dock.Tooltips:GetChildren() ) do
- Tooltip.Visible = false;
- end;
- self.GUI.Visible = true;
- end;
- unfocus = function ( self, source )
- if source == 'button' then
- self.button_focus = false;
- elseif source == 'tooltip' then
- self.tooltip_focus = false;
- end;
- if not self.button_focus and not self.tooltip_focus then
- self.GUI.Visible = false;
- end;
- end;
- };
- -- Make it disappear after it's out of mouse focus
- Tooltip.MouseEnter:connect( function ()
- Tooltips[tool_name]:focus( 'tooltip' );
- end );
- Tooltip.MouseLeave:connect( function ()
- Tooltips[tool_name]:unfocus( 'tooltip' );
- end );
- -- Create the scrolling container
- local ScrollingContainer = Gloo.ScrollingContainer( true, false, 15 );
- ScrollingContainer.GUI.Parent = Tooltip;
- -- Put the tooltip content in the container
- for _, Child in pairs( Tooltip.Content:GetChildren() ) do
- Child.Parent = ScrollingContainer.Container;
- end;
- ScrollingContainer.GUI.Size = Dock.Tooltips.Size;
- ScrollingContainer.Container.Size = Tooltip.Content.Size;
- ScrollingContainer.Boundary.Size = Dock.Tooltips.Size;
- ScrollingContainer.Boundary.BackgroundTransparency = 1;
- Tooltip.Content:Destroy();
- end;
- -- Create the scrolling container for the help tooltip
- local ScrollingContainer = Gloo.ScrollingContainer( true, false, 15 );
- ScrollingContainer.GUI.Parent = Dock.HelpInfo;
- -- Put the help tooltip content in the container
- for _, Child in pairs( Dock.HelpInfo.Content:GetChildren() ) do
- Child.Parent = ScrollingContainer.Container;
- end;
- ScrollingContainer.GUI.Size = Dock.HelpInfo.Size;
- ScrollingContainer.Container.Size = Dock.HelpInfo.Content.Size;
- ScrollingContainer.Boundary.Size = Dock.HelpInfo.Size;
- ScrollingContainer.Boundary.BackgroundTransparency = 1;
- Dock.HelpInfo.Content:Destroy();
- -- Add functionality to the other GUI buttons
- Dock.SelectionButtons.UndoButton.MouseButton1Up:connect( function ()
- History:undo();
- end );
- Dock.SelectionButtons.RedoButton.MouseButton1Up:connect( function ()
- History:redo();
- end );
- Dock.SelectionButtons.DeleteButton.MouseButton1Up:connect( function ()
- deleteSelection();
- end );
- Dock.SelectionButtons.CloneButton.MouseButton1Up:connect( function ()
- cloneSelection();
- end );
- Dock.SelectionButtons.ExportButton.MouseButton1Up:connect( function ()
- IE:export();
- end );
- Dock.InfoButtons.HelpButton.MouseButton1Up:connect( function ()
- toggleHelp();
- end );
- -- Shade the buttons according to whether they'll function or not
- Selection.Changed:connect( function ()
- -- If there are items, they should be active
- if #Selection.Items > 0 then
- Dock.SelectionButtons.DeleteButton.Image = delete_active_decal;
- Dock.SelectionButtons.CloneButton.Image = clone_active_decal;
- Dock.SelectionButtons.ExportButton.Image = export_active_decal;
- -- If there aren't items, they shouldn't be active
- else
- Dock.SelectionButtons.DeleteButton.Image = delete_inactive_decal;
- Dock.SelectionButtons.CloneButton.Image = clone_inactive_decal;
- Dock.SelectionButtons.ExportButton.Image = export_inactive_decal;
- end;
- end );
- -- Make the selection/info buttons display tooltips upon hovering over them
- for _, SelectionButton in pairs( Dock.SelectionButtons:GetChildren() ) do
- SelectionButton.MouseEnter:connect( function ()
- if SelectionButton:FindFirstChild( 'Tooltip' ) then
- SelectionButton.Tooltip.Visible = true;
- end;
- end );
- SelectionButton.MouseLeave:connect( function ()
- if SelectionButton:FindFirstChild( 'Tooltip' ) then
- SelectionButton.Tooltip.Visible = false;
- end;
- end );
- end;
- Dock.InfoButtons.HelpButton.MouseEnter:connect( function ()
- Dock.InfoButtons.HelpButton.Tooltip.Visible = true;
- end );
- Dock.InfoButtons.HelpButton.MouseLeave:connect( function ()
- Dock.InfoButtons.HelpButton.Tooltip.Visible = false;
- end );
- History.Changed:connect( function ()
- -- If there are any records
- if #History.Data > 0 then
- -- If we're at the beginning
- if History.index == 0 then
- Dock.SelectionButtons.UndoButton.Image = undo_inactive_decal;
- Dock.SelectionButtons.RedoButton.Image = redo_active_decal;
- -- If we're at the end
- elseif History.index == #History.Data then
- Dock.SelectionButtons.UndoButton.Image = undo_active_decal;
- Dock.SelectionButtons.RedoButton.Image = redo_inactive_decal;
- -- If we're neither at the beginning or the end
- else
- Dock.SelectionButtons.UndoButton.Image = undo_active_decal;
- Dock.SelectionButtons.RedoButton.Image = redo_active_decal;
- end;
- -- If there are no records
- else
- Dock.SelectionButtons.UndoButton.Image = undo_inactive_decal;
- Dock.SelectionButtons.RedoButton.Image = redo_inactive_decal;
- end;
- end );
- ------------------------------------------
- -- Attach tool event listeners
- ------------------------------------------
- function equipBT( CurrentMouse )
- Mouse = CurrentMouse;
- -- Enable the move tool if there's no tool currently enabled
- if not CurrentTool then
- equipTool( Tools.Move );
- end;
- if not TargetBox then
- TargetBox = Instance.new( "SelectionBox", UI );
- TargetBox.Name = "BTTargetBox";
- TargetBox.Color = BrickColor.new( "Institutional white" );
- TargetBox.Transparency = 0.5;
- end;
- -- Enable any temporarily-disabled selection boxes
- for _, SelectionBox in pairs( SelectionBoxes ) do
- SelectionBox.Parent = UI;
- end;
- -- Update the internal selection if this is a plugin
- if ToolType == 'plugin' then
- for _, Item in pairs( Services.Selection:Get() ) do
- Selection:add( Item );
- end;
- end;
- -- Call the `Equipped` listener of the current tool
- if CurrentTool and CurrentTool.Listeners.Equipped then
- CurrentTool.Listeners.Equipped();
- end;
- -- Show the dock
- Dock.Visible = true;
- table.insert( Connections, Mouse.KeyDown:connect( function ( key )
- local key = key:lower();
- local key_code = key:byte();
- -- Provide the abiltiy to delete via the shift + X key combination
- if ActiveKeys[47] or ActiveKeys[48] and key == "x" then
- deleteSelection();
- return;
- end;
- -- Provide the ability to clone via the shift + C key combination
- if ActiveKeys[47] or ActiveKeys[48] and key == "c" then
- cloneSelection();
- return;
- end;
- -- Undo if shift+z is pressed
- if key == "z" and ( ActiveKeys[47] or ActiveKeys[48] ) then
- History:undo();
- return;
- -- Redo if shift+y is pressed
- elseif key == "y" and ( ActiveKeys[47] or ActiveKeys[48] ) then
- History:redo();
- return;
- end;
- -- Serialize and dump selection to logs if shift+p is pressed
- if key == "p" and ( ActiveKeys[47] or ActiveKeys[48] ) then
- IE:export();
- return;
- end;
- -- Perform a prism selection if shift + k is pressed
- if key == "k" and ( ActiveKeys[47] or ActiveKeys[48] ) then
- prismSelect();
- return;
- end;
- -- Clear the selection if shift + r is pressed
- if key == "r" and ( ActiveKeys[47] or ActiveKeys[48] ) then
- Selection:clear();
- return;
- end;
- if key == "z" then
- equipTool( Tools.Move );
- elseif key == "x" then
- equipTool( Tools.Resize );
- elseif key == "c" then
- equipTool( Tools.Rotate );
- elseif key == "v" then
- equipTool( Tools.Paint );
- elseif key == "b" then
- equipTool( Tools.Surface );
- elseif key == "n" then
- equipTool( Tools.Material );
- elseif key == "m" then
- equipTool( Tools.Anchor );
- elseif key == "k" then
- equipTool( Tools.Collision );
- elseif key == "j" then
- equipTool( Tools.NewPart );
- elseif key == "h" then
- equipTool( Tools.Mesh );
- elseif key == "g" then
- equipTool( Tools.Texture );
- elseif key == "f" then
- equipTool( Tools.Weld );
- elseif key == "u" then
- equipTool( Tools.Lighting );
- elseif key == "p" then
- equipTool( Tools.Decorate );
- end;
- ActiveKeys[key_code] = key_code;
- ActiveKeys[key] = key;
- -- If it's now in multiselection mode, update `selecting`
- -- (these are the left/right ctrl & shift keys)
- if ActiveKeys[47] or ActiveKeys[48] or ActiveKeys[49] or ActiveKeys[50] then
- selecting = ActiveKeys[47] or ActiveKeys[48] or ActiveKeys[49] or ActiveKeys[50];
- end;
- end ) );
- table.insert( Connections, Mouse.KeyUp:connect( function ( key )
- local key = key:lower();
- local key_code = key:byte();
- ActiveKeys[key_code] = nil;
- ActiveKeys[key] = nil;
- -- If it's no longer in multiselection mode, update `selecting` & related values
- if selecting and not ActiveKeys[selecting] then
- selecting = false;
- if Select2D.enabled then
- Select2D:select();
- Select2D:finish();
- end;
- end;
- -- Fire tool listeners
- if CurrentTool and CurrentTool.Listeners.KeyUp then
- CurrentTool.Listeners.KeyUp( key );
- end;
- end ) );
- table.insert( Connections, Mouse.Button1Down:connect( function ()
- clicking = true;
- click_x, click_y = Mouse.X, Mouse.Y;
- -- If multiselection is, just add to the selection
- if selecting then
- return;
- end;
- -- Fire tool listeners
- if CurrentTool and CurrentTool.Listeners.Button1Down then
- CurrentTool.Listeners.Button1Down();
- end;
- end ) );
- table.insert( Connections, Mouse.Move:connect( function ()
- -- If the mouse has moved since it was clicked, start 2D selection mode
- if not override_selection and not Select2D.enabled and clicking and selecting and ( click_x ~= Mouse.X or click_y ~= Mouse.Y ) then
- Select2D:start();
- end;
- -- If the target has changed, update the selectionbox appropriately
- if not override_selection and isSelectable( Mouse.Target ) and TargetBox.Adornee ~= Mouse.Target then
- TargetBox.Adornee = Mouse.Target;
- end;
- -- When aiming at something invalid, don't highlight any targets
- if not override_selection and not isSelectable( Mouse.Target ) then
- TargetBox.Adornee = nil;
- end;
- -- Fire tool listeners
- if CurrentTool and CurrentTool.Listeners.Move then
- CurrentTool.Listeners.Move();
- end;
- if override_selection then
- override_selection = false;
- end;
- end ) );
- table.insert( Connections, Mouse.Button1Up:connect( function ()
- clicking = false;
- -- Make sure the person didn't accidentally miss a handle or something
- if not Select2D.enabled and ( Mouse.X ~= click_x or Mouse.Y ~= click_y ) then
- override_selection = true;
- end;
- -- If the target when clicking was invalid then clear the selection (unless we're multi-selecting)
- if not override_selection and not selecting and not isSelectable( Mouse.Target ) then
- Selection:clear();
- end;
- -- If multi-selecting, add to/remove from the selection
- if not override_selection and selecting then
- -- If the item isn't already selected, add it to the selection
- if not Selection:find( Mouse.Target ) then
- if isSelectable( Mouse.Target ) then
- Selection:add( Mouse.Target );
- end;
- -- If the item _is_ already selected, remove it from the selection
- else
- if ( Mouse.X == click_x and Mouse.Y == click_y ) and Selection:find( Mouse.Target ) then
- Selection:remove( Mouse.Target );
- end;
- end;
- -- If not multi-selecting, replace the selection
- else
- if not override_selection and isSelectable( Mouse.Target ) then
- Selection:clear();
- Selection:add( Mouse.Target );
- end;
- end;
- -- Fire tool listeners
- if CurrentTool and CurrentTool.Listeners.Button1Up then
- CurrentTool.Listeners.Button1Up();
- end;
- if override_selection then
- override_selection = false;
- end;
- end ) );
- table.insert( Connections, Mouse.Button2Down:connect( function ()
- -- Fire tool listeners
- if CurrentTool and CurrentTool.Listeners.Button2Down then
- CurrentTool.Listeners.Button2Down();
- end;
- end ) );
- table.insert( Connections, Mouse.Button2Up:connect( function ()
- -- Fire tool listeners
- if CurrentTool and CurrentTool.Listeners.Button2Up then
- CurrentTool.Listeners.Button2Up();
- end;
- end ) );
- end;
- function unequipBT()
- Mouse = nil;
- -- Remove the mouse target SelectionBox from `Player`
- if TargetBox then
- TargetBox:Destroy();
- TargetBox = nil;
- end;
- -- Disable all the selection boxes temporarily
- for _, SelectionBox in pairs( SelectionBoxes ) do
- SelectionBox.Parent = nil;
- end;
- -- Hide the dock
- Dock.Visible = false;
- -- Disconnect temporary platform-related connections
- for connection_index, Connection in pairs( Connections ) do
- Connection:disconnect();
- Connections[connection_index] = nil;
- end;
- -- Call the `Unequipped` listener of the current tool
- if CurrentTool and CurrentTool.Listeners.Unequipped then
- CurrentTool.Listeners.Unequipped();
- end;
- end;
- ------------------------------------------
- -- Provide the platform's environment for
- -- other tool scripts to extend upon
- ------------------------------------------
- local tool_list = {
- "Anchor",
- "Collision",
- "Material",
- "Mesh",
- "Move",
- "NewPart",
- "Paint",
- "Resize",
- "Rotate",
- "Surface",
- "Texture",
- "Weld",
- "Lighting",
- "Decorate"
- };
- -- Make sure all the tool scripts are in the tool & deactivate them
- for _, tool_name in pairs( tool_list ) do
- local script_name = "BT" .. tool_name .. "Tool";
- repeat wait() until script:FindFirstChild( script_name );
- script[script_name].Disabled = true;
- end;
- -- Load the platform
- if not _G.BTCoreEnv then
- _G.BTCoreEnv = {};
- end;
- _G.BTCoreEnv[Tool] = getfenv( 0 );
- CoreReady = true;
- -- Reload the tool scripts
- for _, tool_name in pairs( tool_list ) do
- local script_name = "BT" .. tool_name .. "Tool";
- script[script_name].Disabled = false;
- end;
- -- Wait for all the tools to load
- for _, tool_name in pairs( tool_list ) do
- if not Tools[tool_name] then
- repeat wait() until Tools[tool_name];
- end;
- repeat wait() until Tools[tool_name].Loaded;
- end;
- -- Activate the plugin and tool connections
- if ToolType == 'plugin' then
- local ToolbarButton = plugin:CreateToolbar( 'Building Tools by F3X' ):CreateButton( '', 'Building Tools by F3X', plugin_icon );
- local plugin_active = false;
- ToolbarButton.Click:connect( function ()
- if plugin_active then
- plugin_active = false;
- unequipBT();
- else
- plugin_active = true;
- plugin:Activate( true );
- equipBT( plugin:GetMouse() );
- end;
- end );
- plugin.Deactivation:connect( unequipBT );
- elseif ToolType == 'tool' then
- Tool.Equipped:connect( equipBT );
- Tool.Unequipped:connect( unequipBT );
- end;
- end))
- LocalScript2.Name = "BTMoveTool"
- LocalScript2.Parent = LocalScript1
- table.insert(cors,sandbox(LocalScript2,function()
- -- Load the main tool's core environment when it's ready
- repeat wait() until (
- _G.BTCoreEnv and
- _G.BTCoreEnv[script.Parent.Parent] and
- _G.BTCoreEnv[script.Parent.Parent].CoreReady
- );
- setfenv( 1, _G.BTCoreEnv[script.Parent.Parent] );
- ------------------------------------------
- -- Move tool
- ------------------------------------------
- -- Create the main container for this tool
- Tools.Move = {};
- -- Define the color of the tool
- Tools.Move.Color = BrickColor.new( "Deep orange" );
- -- Keep a container for temporary connections
- Tools.Move.Connections = {};
- -- Keep options in a container too
- Tools.Move.Options = {
- ["increment"] = 1;
- ["axes"] = "global";
- };
- -- Keep internal state data in its own container
- Tools.Move.State = {
- ["distance_moved"] = 0;
- ["moving"] = false;
- ["PreMove"] = {};
- };
- -- Add listeners
- Tools.Move.Listeners = {};
- Tools.Move.Listeners.Equipped = function ()
- local self = Tools.Move;
- -- Make sure the tool is actually being equipped (because this is the default tool)
- if not Mouse then
- return;
- end;
- -- Change the color of selection boxes temporarily
- self.State.PreviousSelectionBoxColor = SelectionBoxColor;
- SelectionBoxColor = self.Color;
- updateSelectionBoxColor();
- -- Reveal the GUI
- self:showGUI();
- -- Create the boundingbox if it doesn't already exist
- if not self.BoundingBox then
- self.BoundingBox = RbxUtility.Create "Part" {
- Name = "BTBoundingBox";
- CanCollide = false;
- Transparency = 1;
- Anchored = true;
- };
- end;
- Mouse.TargetFilter = self.BoundingBox;
- -- Refresh the axis type option
- self:changeAxes( self.Options.axes );
- -- Listen for any keystrokes that might affect any dragging operation
- self.Connections.DraggerKeyListener = Mouse.KeyDown:connect( function ( key )
- local key = key:lower();
- -- Make sure a dragger exists
- if not self.Dragger then
- return;
- end;
- -- Rotate along the Z axis if `r` is pressed
- if key == "r" then
- self.Dragger:AxisRotate( Enum.Axis.Z );
- -- Rotate along the X axis if `t` is pressed
- elseif key == "t" then
- self.Dragger:AxisRotate( Enum.Axis.X );
- -- Rotate along the Y axis if `y` is pressed
- elseif key == "y" then
- self.Dragger:AxisRotate( Enum.Axis.Y );
- end;
- -- Simulate a mouse move so that it applies the changes
- self.Dragger:MouseMove( Mouse.UnitRay );
- end );
- -- Oh, and update the boundingbox and the GUI regularly
- coroutine.wrap( function ()
- updater_on = true;
- -- Provide a function to stop the loop
- self.Updater = function ()
- updater_on = false;
- end;
- while wait( 0.1 ) and updater_on do
- -- Make sure the tool's equipped
- if CurrentTool == self then
- -- Update the GUI if it's visible
- if self.GUI and self.GUI.Visible then
- self:updateGUI();
- end;
- -- Update the boundingbox if it's visible
- if self.Options.axes == "global" then
- self:updateBoundingBox();
- end;
- end;
- end;
- end )();
- end;
- Tools.Move.Listeners.Unequipped = function ()
- local self = Tools.Move;
- -- Stop the update loop
- if self.Updater then
- self.Updater();
- self.Updater = nil;
- end;
- -- Hide the GUI
- self:hideGUI();
- -- Hide the handles
- self:hideHandles();
- -- Clear out any temporary connections
- for connection_index, Connection in pairs( self.Connections ) do
- Connection:disconnect();
- self.Connections[connection_index] = nil;
- end;
- -- Restore the original color of the selection boxes
- SelectionBoxColor = self.State.PreviousSelectionBoxColor;
- updateSelectionBoxColor();
- end;
- Tools.Move.updateGUI = function ( self )
- if self.GUI then
- local GUI = self.GUI;
- if #Selection.Items > 0 then
- -- Look for identical numbers in each axis
- local position_x, position_y, position_z = nil, nil, nil;
- for item_index, Item in pairs( Selection.Items ) do
- -- Set the first values for the first item
- if item_index == 1 then
- position_x, position_y, position_z = _round( Item.Position.x, 2 ), _round( Item.Position.y, 2 ), _round( Item.Position.z, 2 );
- -- Otherwise, compare them and set them to `nil` if they're not identical
- else
- if position_x ~= _round( Item.Position.x, 2 ) then
- position_x = nil;
- end;
- if position_y ~= _round( Item.Position.y, 2 ) then
- position_y = nil;
- end;
- if position_z ~= _round( Item.Position.z, 2 ) then
- position_z = nil;
- end;
- end;
- end;
- -- If each position along each axis is the same, display that number; otherwise, display "*"
- if not self.State.pos_x_focused then
- GUI.Info.Center.X.TextBox.Text = position_x and tostring( position_x ) or "*";
- end;
- if not self.State.pos_y_focused then
- GUI.Info.Center.Y.TextBox.Text = position_y and tostring( position_y ) or "*";
- end;
- if not self.State.pos_z_focused then
- GUI.Info.Center.Z.TextBox.Text = position_z and tostring( position_z ) or "*";
- end;
- GUI.Info.Visible = true;
- else
- GUI.Info.Visible = false;
- end;
- if self.State.distance_moved then
- GUI.Changes.Text.Text = "moved " .. tostring( self.State.distance_moved ) .. " studs";
- GUI.Changes.Position = GUI.Info.Visible and UDim2.new( 0, 5, 0, 165 ) or UDim2.new( 0, 5, 0, 100 );
- GUI.Changes.Visible = true;
- else
- GUI.Changes.Text.Text = "";
- GUI.Changes.Visible = false;
- end;
- end;
- end;
- Tools.Move.changePosition = function ( self, component, new_value )
- self:startHistoryRecord();
- -- Change the position of each item selected
- for _, Item in pairs( Selection.Items ) do
- Item.CFrame = CFrame.new(
- component == 'x' and new_value or Item.Position.x,
- component == 'y' and new_value or Item.Position.y,
- component == 'z' and new_value or Item.Position.z
- ) * CFrame.Angles( Item.CFrame:toEulerAnglesXYZ() );
- end;
- self:finishHistoryRecord();
- end;
- Tools.Move.startHistoryRecord = function ( self )
- if self.State.HistoryRecord then
- self.State.HistoryRecord = nil;
- end;
- -- Create a history record
- self.State.HistoryRecord = {
- targets = _cloneTable( Selection.Items );
- initial_positions = {};
- terminal_positions = {};
- unapply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target.CFrame = self.initial_positions[Target];
- Target:MakeJoints();
- Selection:add( Target );
- end;
- end;
- end;
- apply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target.CFrame = self.terminal_positions[Target];
- Target:MakeJoints();
- Selection:add( Target );
- end;
- end;
- end;
- };
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.initial_positions[Item] = Item.CFrame;
- end;
- end;
- end;
- Tools.Move.finishHistoryRecord = function ( self )
- if not self.State.HistoryRecord then
- return;
- end;
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.terminal_positions[Item] = Item.CFrame;
- end;
- end;
- History:add( self.State.HistoryRecord );
- self.State.HistoryRecord = nil;
- end;
- Tools.Move.Listeners.Button1Down = function ()
- local self = Tools.Move;
- local Target = self.ManualTarget or Mouse.Target;
- self.ManualTarget = nil;
- -- If an unselected part is being moved, switch to it
- if not Selection:find( Target ) and isSelectable( Target ) then
- Selection:clear();
- Selection:add( Target );
- end;
- -- If the unselected target can't be selected at all, ignore the rest of the procedure
- if not Selection:find( Target ) then
- return;
- end;
- for _, Item in pairs( Selection.Items ) do
- Item.RotVelocity = Vector3.new( 0, 0, 0 );
- Item.Velocity = Vector3.new( 0, 0, 0 );
- end;
- self:startHistoryRecord();
- self.State.dragging = true;
- override_selection = true;
- self.Dragger = Instance.new( "Dragger" );
- self.Dragger:MouseDown( Target, Target.CFrame:toObjectSpace( CFrame.new( Mouse.Hit.p ) ).p, Selection.Items );
- self.Connections.DraggerConnection = Mouse.Button1Up:connect( function ()
- override_selection = true;
- -- Disable the dragger
- if self.Connections.DraggerConnection then
- self.Connections.DraggerConnection:disconnect();
- self.Connections.DraggerConnection = nil;
- end;
- if not self.Dragger then
- return;
- end;
- self.Dragger:MouseUp();
- self.State.dragging = false;
- self.Dragger:Destroy();
- self.Dragger = nil;
- self:finishHistoryRecord();
- end );
- end;
- Tools.Move.Listeners.Move = function ()
- local self = Tools.Move;
- if not self.Dragger then
- return;
- end;
- override_selection = true;
- self.Dragger:MouseMove( Mouse.UnitRay );
- end;
- Tools.Move.showGUI = function ( self )
- -- Initialize the GUI if it's not ready yet
- if not self.GUI then
- local Container = Tool.Interfaces:WaitForChild( "BTMoveToolGUI" ):Clone();
- Container.Parent = UI;
- -- Change the axis type option when the button is clicked
- Container.AxesOption.Global.Button.MouseButton1Down:connect( function ()
- self:changeAxes( "global" );
- Container.AxesOption.Global.SelectedIndicator.BackgroundTransparency = 0;
- Container.AxesOption.Global.Background.Image = dark_slanted_rectangle;
- Container.AxesOption.Local.SelectedIndicator.BackgroundTransparency = 1;
- Container.AxesOption.Local.Background.Image = light_slanted_rectangle;
- Container.AxesOption.Last.SelectedIndicator.BackgroundTransparency = 1;
- Container.AxesOption.Last.Background.Image = light_slanted_rectangle;
- end );
- Container.AxesOption.Local.Button.MouseButton1Down:connect( function ()
- self:changeAxes( "local" );
- Container.AxesOption.Global.SelectedIndicator.BackgroundTransparency = 1;
- Container.AxesOption.Global.Background.Image = light_slanted_rectangle;
- Container.AxesOption.Local.SelectedIndicator.BackgroundTransparency = 0;
- Container.AxesOption.Local.Background.Image = dark_slanted_rectangle;
- Container.AxesOption.Last.SelectedIndicator.BackgroundTransparency = 1;
- Container.AxesOption.Last.Background.Image = light_slanted_rectangle;
- end );
- Container.AxesOption.Last.Button.MouseButton1Down:connect( function ()
- self:changeAxes( "last" );
- Container.AxesOption.Global.SelectedIndicator.BackgroundTransparency = 1;
- Container.AxesOption.Global.Background.Image = light_slanted_rectangle;
- Container.AxesOption.Local.SelectedIndicator.BackgroundTransparency = 1;
- Container.AxesOption.Local.Background.Image = light_slanted_rectangle;
- Container.AxesOption.Last.SelectedIndicator.BackgroundTransparency = 0;
- Container.AxesOption.Last.Background.Image = dark_slanted_rectangle;
- end );
- -- Change the increment option when the value of the textbox is updated
- Container.IncrementOption.Increment.TextBox.FocusLost:connect( function ( enter_pressed )
- self.Options.increment = tonumber( Container.IncrementOption.Increment.TextBox.Text ) or self.Options.increment;
- Container.IncrementOption.Increment.TextBox.Text = tostring( self.Options.increment );
- end );
- -- Add functionality to the position inputs
- Container.Info.Center.X.TextButton.MouseButton1Down:connect( function ()
- self.State.pos_x_focused = true;
- Container.Info.Center.X.TextBox:CaptureFocus();
- end );
- Container.Info.Center.X.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.Info.Center.X.TextBox.Text );
- if potential_new then
- self:changePosition( 'x', potential_new );
- end;
- self.State.pos_x_focused = false;
- end );
- Container.Info.Center.Y.TextButton.MouseButton1Down:connect( function ()
- self.State.pos_y_focused = true;
- Container.Info.Center.Y.TextBox:CaptureFocus();
- end );
- Container.Info.Center.Y.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.Info.Center.Y.TextBox.Text );
- if potential_new then
- self:changePosition( 'y', potential_new );
- end;
- self.State.pos_y_focused = false;
- end );
- Container.Info.Center.Z.TextButton.MouseButton1Down:connect( function ()
- self.State.pos_z_focused = true;
- Container.Info.Center.Z.TextBox:CaptureFocus();
- end );
- Container.Info.Center.Z.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.Info.Center.Z.TextBox.Text );
- if potential_new then
- self:changePosition( 'z', potential_new );
- end;
- self.State.pos_z_focused = false;
- end );
- self.GUI = Container;
- end;
- -- Reveal the GUI
- self.GUI.Visible = true;
- end;
- Tools.Move.hideGUI = function ( self )
- -- Hide the GUI if it exists
- if self.GUI then
- self.GUI.Visible = false;
- end;
- end;
- Tools.Move.showHandles = function ( self, Part )
- -- Create the handles if they don't exist yet
- if not self.Handles then
- -- Create the object
- self.Handles = RbxUtility.Create "Handles" {
- Name = "BTMovementHandles";
- Color = self.Color;
- Parent = GUIContainer;
- };
- -- Add functionality to the handles
- self.Handles.MouseButton1Down:connect( function ()
- -- Prevent the platform from thinking we're selecting
- override_selection = true;
- self.State.moving = true;
- -- Clear the change stats
- self.State.distance_moved = 0;
- self:startHistoryRecord();
- -- Do a few things to the selection before manipulating it
- for _, Item in pairs( Selection.Items ) do
- -- Keep a copy of the state of each item
- self.State.PreMove[Item] = Item:Clone();
- -- Anchor each item
- Item.Anchored = true;
- end;
- -- Return stuff to normal once the mouse button is released
- self.Connections.HandleReleaseListener = Mouse.Button1Up:connect( function ()
- -- Prevent the platform from thinking we're selecting
- override_selection = true;
- self.State.moving = false;
- -- Stop this connection from firing again
- if self.Connections.HandleReleaseListener then
- self.Connections.HandleReleaseListener:disconnect();
- self.Connections.HandleReleaseListener = nil;
- end;
- self:finishHistoryRecord();
- -- Restore properties that may have been changed temporarily
- -- from the pre-movement state copies
- for Item, PreviousItemState in pairs( self.State.PreMove ) do
- Item.Anchored = PreviousItemState.Anchored;
- self.State.PreMove[Item] = nil;
- Item:MakeJoints();
- Item.Velocity = Vector3.new( 0, 0, 0 );
- Item.RotVelocity = Vector3.new( 0, 0, 0 );
- end;
- end );
- end );
- self.Handles.MouseDrag:connect( function ( face, drag_distance )
- -- Calculate which multiple of the increment to use based on the current drag distance's
- -- proximity to their nearest upper and lower multiples
- local difference = drag_distance % self.Options.increment;
- local lower_degree = drag_distance - difference;
- local upper_degree = drag_distance - difference + self.Options.increment;
- local lower_degree_proximity = math.abs( drag_distance - lower_degree );
- local upper_degree_proximity = math.abs( drag_distance - upper_degree );
- if lower_degree_proximity <= upper_degree_proximity then
- drag_distance = lower_degree;
- else
- drag_distance = upper_degree;
- end;
- local increase = drag_distance;
- self.State.distance_moved = drag_distance;
- -- Increment the position of each selected item in the direction of `face`
- for _, Item in pairs( Selection.Items ) do
- -- Remove any joints connected with `Item` so that it can freely move
- Item:BreakJoints();
- -- Update the position of `Item` depending on the type of axes that is currently set
- if face == Enum.NormalId.Top then
- if self.Options.axes == "global" then
- Item.CFrame = CFrame.new( self.State.PreMove[Item].CFrame.p ):toWorldSpace( CFrame.new( 0, increase, 0 ) ) * CFrame.Angles( self.State.PreMove[Item].CFrame:toEulerAnglesXYZ() );
- elseif self.Options.axes == "local" then
- Item.CFrame = self.State.PreMove[Item].CFrame:toWorldSpace( CFrame.new( 0, increase, 0 ) );
- elseif self.Options.axes == "last" then
- Item.CFrame = self.State.PreMove[Selection.Last].CFrame:toWorldSpace( CFrame.new( 0, increase, 0 ) ):toWorldSpace( self.State.PreMove[Item].CFrame:toObjectSpace( self.State.PreMove[Selection.Last].CFrame ):inverse() );
- end;
- elseif face == Enum.NormalId.Bottom then
- if self.Options.axes == "global" then
- Item.CFrame = CFrame.new( self.State.PreMove[Item].CFrame.p ):toWorldSpace( CFrame.new( 0, -increase, 0 ) ) * CFrame.Angles( self.State.PreMove[Item].CFrame:toEulerAnglesXYZ() );
- elseif self.Options.axes == "local" then
- Item.CFrame = self.State.PreMove[Item].CFrame:toWorldSpace( CFrame.new( 0, -increase, 0 ) );
- elseif self.Options.axes == "last" then
- Item.CFrame = self.State.PreMove[Selection.Last].CFrame:toWorldSpace( CFrame.new( 0, -increase, 0 ) ):toWorldSpace( self.State.PreMove[Item].CFrame:toObjectSpace( self.State.PreMove[Selection.Last].CFrame ):inverse() );
- end;
- elseif face == Enum.NormalId.Front then
- if self.Options.axes == "global" then
- Item.CFrame = CFrame.new( self.State.PreMove[Item].CFrame.p ):toWorldSpace( CFrame.new( 0, 0, -increase ) ) * CFrame.Angles( self.State.PreMove[Item].CFrame:toEulerAnglesXYZ() );
- elseif self.Options.axes == "local" then
- Item.CFrame = self.State.PreMove[Item].CFrame:toWorldSpace( CFrame.new( 0, 0, -increase ) );
- elseif self.Options.axes == "last" then
- Item.CFrame = self.State.PreMove[Selection.Last].CFrame:toWorldSpace( CFrame.new( 0, 0, -increase ) ):toWorldSpace( self.State.PreMove[Item].CFrame:toObjectSpace( self.State.PreMove[Selection.Last].CFrame ):inverse() );
- end;
- elseif face == Enum.NormalId.Back then
- if self.Options.axes == "global" then
- Item.CFrame = CFrame.new( self.State.PreMove[Item].CFrame.p ):toWorldSpace( CFrame.new( 0, 0, increase ) ) * CFrame.Angles( self.State.PreMove[Item].CFrame:toEulerAnglesXYZ() );
- elseif self.Options.axes == "local" then
- Item.CFrame = self.State.PreMove[Item].CFrame:toWorldSpace( CFrame.new( 0, 0, increase ) );
- elseif self.Options.axes == "last" then
- Item.CFrame = self.State.PreMove[Selection.Last].CFrame:toWorldSpace( CFrame.new( 0, 0, increase ) ):toWorldSpace( self.State.PreMove[Item].CFrame:toObjectSpace( self.State.PreMove[Selection.Last].CFrame ):inverse() );
- end;
- elseif face == Enum.NormalId.Right then
- if self.Options.axes == "global" then
- Item.CFrame = CFrame.new( self.State.PreMove[Item].CFrame.p ):toWorldSpace( CFrame.new( increase, 0, 0 ) ) * CFrame.Angles( self.State.PreMove[Item].CFrame:toEulerAnglesXYZ() );
- elseif self.Options.axes == "local" then
- Item.CFrame = self.State.PreMove[Item].CFrame:toWorldSpace( CFrame.new( increase, 0, 0 ) );
- elseif self.Options.axes == "last" then
- Item.CFrame = self.State.PreMove[Selection.Last].CFrame:toWorldSpace( CFrame.new( increase, 0, 0 ) ):toWorldSpace( self.State.PreMove[Item].CFrame:toObjectSpace( self.State.PreMove[Selection.Last].CFrame ):inverse() );
- end;
- elseif face == Enum.NormalId.Left then
- if self.Options.axes == "global" then
- Item.CFrame = CFrame.new( self.State.PreMove[Item].CFrame.p ):toWorldSpace( CFrame.new( -increase, 0, 0 ) ) * CFrame.Angles( self.State.PreMove[Item].CFrame:toEulerAnglesXYZ() );
- elseif self.Options.axes == "local" then
- Item.CFrame = self.State.PreMove[Item].CFrame:toWorldSpace( CFrame.new( -increase, 0, 0 ) );
- elseif self.Options.axes == "last" then
- Item.CFrame = self.State.PreMove[Selection.Last].CFrame:toWorldSpace( CFrame.new( -increase, 0, 0 ) ):toWorldSpace( self.State.PreMove[Item].CFrame:toObjectSpace( self.State.PreMove[Selection.Last].CFrame ):inverse() );
- end;
- end;
- end;
- end );
- end;
- -- Stop listening for the existence of the previous adornee (if any)
- if self.Connections.AdorneeExistenceListener then
- self.Connections.AdorneeExistenceListener:disconnect();
- self.Connections.AdorneeExistenceListener = nil;
- end;
- -- Attach the handles to `Part`
- self.Handles.Adornee = Part;
- -- Make sure to hide the handles if `Part` suddenly stops existing
- self.Connections.AdorneeExistenceListener = Part.AncestryChanged:connect( function ( Object, NewParent )
- -- Make sure this change in parent applies directly to `Part`
- if Object ~= Part then
- return;
- end;
- -- Show the handles according to the existence of the part
- if NewParent == nil then
- self:hideHandles();
- else
- self:showHandles( Part );
- end;
- end );
- end;
- Tools.Move.hideHandles = function ( self )
- -- Hide the handles if they exist
- if self.Handles then
- self.Handles.Adornee = nil;
- end;
- end;
- Tools.Move.updateBoundingBox = function ( self )
- if #Selection.Items > 0 and not self.State.dragging then
- local SelectionSize, SelectionPosition = _getCollectionInfo( Selection.Items );
- self.BoundingBox.Size = SelectionSize;
- self.BoundingBox.CFrame = SelectionPosition;
- self:showHandles( self.BoundingBox );
- else
- self:hideHandles();
- end;
- end;
- Tools.Move.changeAxes = function ( self, new_axes )
- -- Have a quick reference to the GUI (if any)
- local AxesOptionGUI = self.GUI and self.GUI.AxesOption or nil;
- -- Disconnect any handle-related listeners that are specific to a certain axes option
- if self.Connections.HandleFocusChangeListener then
- self.Connections.HandleFocusChangeListener:disconnect();
- self.Connections.HandleFocusChangeListener = nil;
- end;
- if self.Connections.HandleSelectionChangeListener then
- self.Connections.HandleSelectionChangeListener:disconnect();
- self.Connections.HandleSelectionChangeListener = nil;
- end;
- if new_axes == "global" then
- -- Update the options
- self.Options.axes = "global";
- -- Clear out any previous adornee
- self:hideHandles();
- -- Focus the handles on the boundary box
- self:showHandles( self.BoundingBox );
- -- Update the GUI's option panel
- if self.GUI then
- AxesOptionGUI.Global.SelectedIndicator.BackgroundTransparency = 0;
- AxesOptionGUI.Global.Background.Image = dark_slanted_rectangle;
- AxesOptionGUI.Local.SelectedIndicator.BackgroundTransparency = 1;
- AxesOptionGUI.Local.Background.Image = light_slanted_rectangle;
- AxesOptionGUI.Last.SelectedIndicator.BackgroundTransparency = 1;
- AxesOptionGUI.Last.Background.Image = light_slanted_rectangle;
- end;
- end;
- if new_axes == "local" then
- -- Update the options
- self.Options.axes = "local";
- -- Always have the handles on the most recent addition to the selection
- self.Connections.HandleSelectionChangeListener = Selection.Changed:connect( function ()
- -- Clear out any previous adornee
- self:hideHandles();
- -- If there /is/ a last item in the selection, attach the handles to it
- if Selection.Last then
- self:showHandles( Selection.Last );
- end;
- end );
- -- Switch the adornee of the handles if the second mouse button is pressed
- self.Connections.HandleFocusChangeListener = Mouse.Button2Up:connect( function ()
- -- Make sure the platform doesn't think we're selecting
- override_selection = true;
- -- If the target is in the selection, make it the new adornee
- if Selection:find( Mouse.Target ) then
- Selection:focus( Mouse.Target );
- self:showHandles( Mouse.Target );
- end;
- end );
- -- Finally, attach the handles to the last item added to the selection (if any)
- if Selection.Last then
- self:showHandles( Selection.Last );
- end;
- -- Update the GUI's option panel
- if self.GUI then
- AxesOptionGUI.Global.SelectedIndicator.BackgroundTransparency = 1;
- AxesOptionGUI.Global.Background.Image = light_slanted_rectangle;
- AxesOptionGUI.Local.SelectedIndicator.BackgroundTransparency = 0;
- AxesOptionGUI.Local.Background.Image = dark_slanted_rectangle;
- AxesOptionGUI.Last.SelectedIndicator.BackgroundTransparency = 1;
- AxesOptionGUI.Last.Background.Image = light_slanted_rectangle;
- end;
- end;
- if new_axes == "last" then
- -- Update the options
- self.Options.axes = "last";
- -- Always have the handles on the most recent addition to the selection
- self.Connections.HandleSelectionChangeListener = Selection.Changed:connect( function ()
- -- Clear out any previous adornee
- self:hideHandles();
- -- If there /is/ a last item in the selection, attach the handles to it
- if Selection.Last then
- self:showHandles( Selection.Last );
- end;
- end );
- -- Switch the adornee of the handles if the second mouse button is pressed
- self.Connections.HandleFocusChangeListener = Mouse.Button2Up:connect( function ()
- -- Make sure the platform doesn't think we're selecting
- override_selection = true;
- -- If the target is in the selection, make it the new adornee
- if Selection:find( Mouse.Target ) then
- Selection:focus( Mouse.Target );
- self:showHandles( Mouse.Target );
- end;
- end );
- -- Finally, attach the handles to the last item added to the selection (if any)
- if Selection.Last then
- self:showHandles( Selection.Last );
- end;
- -- Update the GUI's option panel
- if self.GUI then
- AxesOptionGUI.Global.SelectedIndicator.BackgroundTransparency = 1;
- AxesOptionGUI.Global.Background.Image = light_slanted_rectangle;
- AxesOptionGUI.Local.SelectedIndicator.BackgroundTransparency = 1;
- AxesOptionGUI.Local.Background.Image = light_slanted_rectangle;
- AxesOptionGUI.Last.SelectedIndicator.BackgroundTransparency = 0;
- AxesOptionGUI.Last.Background.Image = dark_slanted_rectangle;
- end;
- end;
- end;
- Tools.Move.Loaded = true;
- end))
- LocalScript2.Disabled = true
- LocalScript3.Name = "BTResizeTool"
- LocalScript3.Parent = LocalScript1
- table.insert(cors,sandbox(LocalScript3,function()
- -- Load the main tool's core environment when it's ready
- repeat wait() until (
- _G.BTCoreEnv and
- _G.BTCoreEnv[script.Parent.Parent] and
- _G.BTCoreEnv[script.Parent.Parent].CoreReady
- );
- setfenv( 1, _G.BTCoreEnv[script.Parent.Parent] );
- ------------------------------------------
- -- Resize tool
- ------------------------------------------
- -- Create the tool
- Tools.Resize = {};
- -- Create structures that will be used within the tool
- Tools.Resize.Connections = {};
- Tools.Resize.Options = {
- ["increment"] = 1;
- ["directions"] = "normal";
- };
- Tools.Resize.State = {
- ["PreResize"] = {};
- ["previous_distance"] = 0;
- ["resizing"] = false;
- ["length_resized"] = 0;
- };
- Tools.Resize.Listeners = {};
- -- Define the color of the tool
- Tools.Resize.Color = BrickColor.new( "Cyan" );
- Tools.Resize.Listeners.Equipped = function ()
- local self = Tools.Resize;
- -- Change the color of selection boxes temporarily
- self.State.PreviousSelectionBoxColor = SelectionBoxColor;
- SelectionBoxColor = self.Color;
- updateSelectionBoxColor();
- -- Reveal the GUI
- self:showGUI();
- -- Always have the handles on the most recent addition to the selection
- table.insert( self.Connections, Selection.Changed:connect( function ()
- -- Clear out any previous adornee
- self:hideHandles();
- -- If there /is/ a last item in the selection, attach the handles to it
- if Selection.Last then
- self:showHandles( Selection.Last );
- end;
- end ) );
- -- Switch the adornee of the handles if the second mouse button is pressed
- table.insert( self.Connections, Mouse.Button2Up:connect( function ()
- -- Make sure the platform doesn't think we're selecting
- override_selection = true;
- -- If the target is in the selection, make it the new adornee
- if Selection:find( Mouse.Target ) then
- Selection:focus( Mouse.Target );
- end;
- end ) );
- -- Finally, attach the handles to the last item added to the selection (if any)
- if Selection.Last then
- self:showHandles( Selection.Last );
- end;
- -- Update the GUI regularly
- coroutine.wrap( function ()
- updater_on = true;
- -- Provide a function to stop the loop
- self.Updater = function ()
- updater_on = false;
- end;
- while wait( 0.1 ) and updater_on do
- -- Make sure the tool's equipped
- if CurrentTool == self then
- -- Update the GUI if it's visible
- if self.GUI and self.GUI.Visible then
- self:updateGUI();
- end;
- end;
- end;
- end )();
- end;
- Tools.Resize.Listeners.Unequipped = function ()
- local self = Tools.Resize;
- -- Stop the update loop
- if self.Updater then
- self.Updater();
- self.Updater = nil;
- end;
- -- Hide the GUI
- self:hideGUI();
- -- Hide the handles
- self:hideHandles();
- -- Clear out any temporary connections
- for connection_index, Connection in pairs( self.Connections ) do
- Connection:disconnect();
- self.Connections[connection_index] = nil;
- end;
- -- Restore the original color of the selection boxes
- SelectionBoxColor = self.State.PreviousSelectionBoxColor;
- updateSelectionBoxColor();
- end;
- Tools.Resize.showGUI = function ( self )
- -- Initialize the GUI if it's not ready yet
- if not self.GUI then
- local Container = Tool.Interfaces:WaitForChild( "BTResizeToolGUI" ):Clone();
- Container.Parent = UI;
- -- Change the axis type option when the button is clicked
- Container.DirectionsOption.Normal.Button.MouseButton1Down:connect( function ()
- self.Options.directions = "normal";
- Container.DirectionsOption.Normal.SelectedIndicator.BackgroundTransparency = 0;
- Container.DirectionsOption.Normal.Background.Image = dark_slanted_rectangle;
- Container.DirectionsOption.Both.SelectedIndicator.BackgroundTransparency = 1;
- Container.DirectionsOption.Both.Background.Image = light_slanted_rectangle;
- end );
- Container.DirectionsOption.Both.Button.MouseButton1Down:connect( function ()
- self.Options.directions = "both";
- Container.DirectionsOption.Normal.SelectedIndicator.BackgroundTransparency = 1;
- Container.DirectionsOption.Normal.Background.Image = light_slanted_rectangle;
- Container.DirectionsOption.Both.SelectedIndicator.BackgroundTransparency = 0;
- Container.DirectionsOption.Both.Background.Image = dark_slanted_rectangle;
- end );
- -- Change the increment option when the value of the textbox is updated
- Container.IncrementOption.Increment.TextBox.FocusLost:connect( function ( enter_pressed )
- self.Options.increment = tonumber( Container.IncrementOption.Increment.TextBox.Text ) or self.Options.increment;
- Container.IncrementOption.Increment.TextBox.Text = tostring( self.Options.increment );
- end );
- -- Add functionality to the size inputs
- Container.Info.SizeInfo.X.TextButton.MouseButton1Down:connect( function ()
- self.State.size_x_focused = true;
- Container.Info.SizeInfo.X.TextBox:CaptureFocus();
- end );
- Container.Info.SizeInfo.X.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.Info.SizeInfo.X.TextBox.Text );
- if potential_new then
- self:changeSize( 'x', potential_new );
- end;
- self.State.size_x_focused = false;
- end );
- Container.Info.SizeInfo.Y.TextButton.MouseButton1Down:connect( function ()
- self.State.size_y_focused = true;
- Container.Info.SizeInfo.Y.TextBox:CaptureFocus();
- end );
- Container.Info.SizeInfo.Y.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.Info.SizeInfo.Y.TextBox.Text );
- if potential_new then
- self:changeSize( 'y', potential_new );
- end;
- self.State.size_y_focused = false;
- end );
- Container.Info.SizeInfo.Z.TextButton.MouseButton1Down:connect( function ()
- self.State.size_z_focused = true;
- Container.Info.SizeInfo.Z.TextBox:CaptureFocus();
- end );
- Container.Info.SizeInfo.Z.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.Info.SizeInfo.Z.TextBox.Text );
- if potential_new then
- self:changeSize( 'z', potential_new );
- end;
- self.State.size_z_focused = false;
- end );
- self.GUI = Container;
- end;
- -- Reveal the GUI
- self.GUI.Visible = true;
- end;
- Tools.Resize.startHistoryRecord = function ( self )
- if self.State.HistoryRecord then
- self.State.HistoryRecord = nil;
- end;
- -- Create a history record
- self.State.HistoryRecord = {
- targets = _cloneTable( Selection.Items );
- initial_positions = {};
- terminal_positions = {};
- initial_sizes = {};
- terminal_sizes = {};
- unapply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target.Size = self.initial_sizes[Target];
- Target.CFrame = self.initial_positions[Target];
- Target:MakeJoints();
- Selection:add( Target );
- end;
- end;
- end;
- apply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target.Size = self.terminal_sizes[Target];
- Target.CFrame = self.terminal_positions[Target];
- Target:MakeJoints();
- Selection:add( Target );
- end;
- end;
- end;
- };
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.initial_sizes[Item] = Item.Size;
- self.State.HistoryRecord.initial_positions[Item] = Item.CFrame;
- end;
- end;
- end;
- Tools.Resize.finishHistoryRecord = function ( self )
- if not self.State.HistoryRecord then
- return;
- end;
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.terminal_sizes[Item] = Item.Size;
- self.State.HistoryRecord.terminal_positions[Item] = Item.CFrame;
- end;
- end;
- History:add( self.State.HistoryRecord );
- self.State.HistoryRecord = nil;
- end;
- Tools.Resize.changeSize = function ( self, component, new_value )
- self:startHistoryRecord();
- -- Change the size of each item selected
- for _, Item in pairs( Selection.Items ) do
- local OldCFrame = Item.CFrame;
- -- Make the item be able to be freely resized
- if ( pcall( function () local test = Item.FormFactor; end ) ) then
- Item.FormFactor = Enum.FormFactor.Custom;
- end;
- Item.Size = Vector3.new(
- component == 'x' and new_value or Item.Size.x,
- component == 'y' and new_value or Item.Size.y,
- component == 'z' and new_value or Item.Size.z
- );
- Item.CFrame = OldCFrame;
- end;
- self:finishHistoryRecord();
- end;
- Tools.Resize.updateGUI = function ( self )
- -- Make sure the GUI exists
- if not self.GUI then
- return;
- end;
- local GUI = self.GUI;
- if #Selection.Items > 0 then
- -- Look for identical numbers in each axis
- local size_x, size_y, size_z = nil, nil, nil;
- for item_index, Item in pairs( Selection.Items ) do
- -- Set the first values for the first item
- if item_index == 1 then
- size_x, size_y, size_z = _round( Item.Size.x, 2 ), _round( Item.Size.y, 2 ), _round( Item.Size.z, 2 );
- -- Otherwise, compare them and set them to `nil` if they're not identical
- else
- if size_x ~= _round( Item.Size.x, 2 ) then
- size_x = nil;
- end;
- if size_y ~= _round( Item.Size.y, 2 ) then
- size_y = nil;
- end;
- if size_z ~= _round( Item.Size.z, 2 ) then
- size_z = nil;
- end;
- end;
- end;
- -- Update the size info on the GUI
- if not self.State.size_x_focused then
- GUI.Info.SizeInfo.X.TextBox.Text = size_x and tostring( size_x ) or "*";
- end;
- if not self.State.size_y_focused then
- GUI.Info.SizeInfo.Y.TextBox.Text = size_y and tostring( size_y ) or "*";
- end;
- if not self.State.size_z_focused then
- GUI.Info.SizeInfo.Z.TextBox.Text = size_z and tostring( size_z ) or "*";
- end;
- GUI.Info.Visible = true;
- else
- GUI.Info.Visible = false;
- end;
- if self.State.length_resized then
- GUI.Changes.Text.Text = "resized " .. tostring( self.State.length_resized ) .. " studs";
- GUI.Changes.Position = GUI.Info.Visible and UDim2.new( 0, 5, 0, 165 ) or UDim2.new( 0, 5, 0, 100 );
- GUI.Changes.Visible = true;
- else
- GUI.Changes.Text.Text = "";
- GUI.Changes.Visible = false;
- end;
- end;
- Tools.Resize.hideGUI = function ( self )
- -- Hide the GUI if it exists
- if self.GUI then
- self.GUI.Visible = false;
- end;
- end;
- Tools.Resize.showHandles = function ( self, Part )
- -- Create the handles if they don't exist yet
- if not self.Handles then
- -- Create the object
- self.Handles = RbxUtility.Create "Handles" {
- Name = "BTResizeHandles";
- Style = Enum.HandlesStyle.Resize;
- Color = self.Color;
- Parent = GUIContainer;
- };
- -- Add functionality to the handles
- self.Handles.MouseButton1Down:connect( function ()
- -- Prevent the platform from thinking we're selecting
- override_selection = true;
- self.State.resizing = true;
- -- Clear the change stats
- self.State.length_resized = 0;
- self:startHistoryRecord();
- -- Do a few things to the selection before manipulating it
- for _, Item in pairs( Selection.Items ) do
- -- Keep a copy of the state of each item
- self.State.PreResize[Item] = Item:Clone();
- -- Make the item be able to be freely resized
- if ( pcall( function () local test = Item.FormFactor; end ) ) then
- Item.FormFactor = Enum.FormFactor.Custom;
- end;
- -- Anchor each item
- Item.Anchored = true;
- end;
- -- Return stuff to normal once the mouse button is released
- self.Connections.HandleReleaseListener = Mouse.Button1Up:connect( function ()
- -- Prevent the platform from thinking we're selecting
- override_selection = true;
- self.State.resizing = false;
- -- Stop this connection from firing again
- if self.Connections.HandleReleaseListener then
- self.Connections.HandleReleaseListener:disconnect();
- self.Connections.HandleReleaseListener = nil;
- end;
- self:finishHistoryRecord();
- -- Restore properties that may have been changed temporarily
- -- from the pre-resize state copies
- for Item, PreviousItemState in pairs( self.State.PreResize ) do
- Item.Anchored = PreviousItemState.Anchored;
- self.State.PreResize[Item] = nil;
- Item:MakeJoints();
- end;
- end );
- end );
- self.Handles.MouseDrag:connect( function ( face, drag_distance )
- -- Calculate which multiple of the increment to use based on the current drag distance's
- -- proximity to their nearest upper and lower multiples
- local difference = drag_distance % self.Options.increment;
- local lower_degree = drag_distance - difference;
- local upper_degree = drag_distance - difference + self.Options.increment;
- local lower_degree_proximity = math.abs( drag_distance - lower_degree );
- local upper_degree_proximity = math.abs( drag_distance - upper_degree );
- if lower_degree_proximity <= upper_degree_proximity then
- drag_distance = lower_degree;
- else
- drag_distance = upper_degree;
- end;
- local increase = drag_distance;
- -- Log the distance that the handle was dragged
- self.State.previous_distance = drag_distance;
- -- Note the length by which the selection will be enlarged
- if self.Options.directions == "both" then
- increase = drag_distance * 2;
- end;
- self.State.length_resized = increase;
- -- Go through the selection and make changes to it
- for _, Item in pairs( Selection.Items ) do
- -- Keep a copy of `Item` in case we need to revert anything
- local PreviousItemState = Item:Clone();
- -- Break any of `Item`'s joints so it can move freely
- Item:BreakJoints();
- -- Position and resize `Item` according to the options and the handle that was used
- if face == Enum.NormalId.Top then
- -- Calculate the appropriate increment to the size based on the shape of `Item`
- local SizeIncrease;
- if ( pcall( function () local test = Item.Shape; end ) ) and ( Item.Shape == Enum.PartType.Ball or Item.Shape == Enum.PartType.Cylinder ) then
- SizeIncrease = Vector3.new( increase, increase, increase );
- elseif not ( pcall( function () local test = Item.Shape; end ) ) or ( Item.Shape and Item.Shape == Enum.PartType.Block ) then
- SizeIncrease = Vector3.new( 0, increase, 0 );
- end;
- Item.Size = self.State.PreResize[Item].Size + SizeIncrease;
- if Item.Size == self.State.PreResize[Item].Size + SizeIncrease then
- Item.CFrame = ( self.Options.directions == "normal" and self.State.PreResize[Item].CFrame:toWorldSpace( CFrame.new( 0, increase / 2, 0 ) ) )
- or ( self.Options.directions == "both" and self.State.PreResize[Item].CFrame );
- -- If the resizing was not possible, revert `Item`'s state
- else
- Item.Size = PreviousItemState.Size;
- Item.CFrame = PreviousItemState.CFrame;
- end;
- elseif face == Enum.NormalId.Bottom then
- -- Calculate the appropriate increment to the size based on the shape of `Item`
- local SizeIncrease;
- if ( pcall( function () local test = Item.Shape; end ) ) and ( Item.Shape == Enum.PartType.Ball or Item.Shape == Enum.PartType.Cylinder ) then
- SizeIncrease = Vector3.new( increase, increase, increase );
- elseif not ( pcall( function () local test = Item.Shape; end ) ) or ( Item.Shape and Item.Shape == Enum.PartType.Block ) then
- SizeIncrease = Vector3.new( 0, increase, 0 );
- end;
- Item.Size = self.State.PreResize[Item].Size + SizeIncrease;
- if Item.Size == self.State.PreResize[Item].Size + SizeIncrease then
- Item.CFrame = ( self.Options.directions == "normal" and self.State.PreResize[Item].CFrame:toWorldSpace( CFrame.new( 0, -increase / 2, 0 ) ) )
- or ( self.Options.directions == "both" and self.State.PreResize[Item].CFrame );
- -- If the resizing was not possible, revert `Item`'s state
- else
- Item.Size = PreviousItemState.Size;
- Item.CFrame = PreviousItemState.CFrame;
- end;
- elseif face == Enum.NormalId.Front then
- -- Calculate the appropriate increment to the size based on the shape of `Item`
- local SizeIncrease;
- if ( pcall( function () local test = Item.Shape; end ) ) and ( Item.Shape == Enum.PartType.Ball or Item.Shape == Enum.PartType.Cylinder ) then
- SizeIncrease = Vector3.new( increase, increase, increase );
- elseif not ( pcall( function () local test = Item.Shape; end ) ) or ( Item.Shape and Item.Shape == Enum.PartType.Block ) then
- SizeIncrease = Vector3.new( 0, 0, increase );
- end;
- Item.Size = self.State.PreResize[Item].Size + SizeIncrease;
- if Item.Size == self.State.PreResize[Item].Size + SizeIncrease then
- Item.CFrame = ( self.Options.directions == "normal" and self.State.PreResize[Item].CFrame:toWorldSpace( CFrame.new( 0, 0, -increase / 2 ) ) )
- or ( self.Options.directions == "both" and self.State.PreResize[Item].CFrame );
- -- If the resizing was not possible, revert `Item`'s state
- else
- Item.Size = PreviousItemState.Size;
- Item.CFrame = PreviousItemState.CFrame;
- end;
- elseif face == Enum.NormalId.Back then
- -- Calculate the appropriate increment to the size based on the shape of `Item`
- local SizeIncrease;
- if ( pcall( function () local test = Item.Shape; end ) ) and ( Item.Shape == Enum.PartType.Ball or Item.Shape == Enum.PartType.Cylinder ) then
- SizeIncrease = Vector3.new( increase, increase, increase );
- elseif not ( pcall( function () local test = Item.Shape; end ) ) or ( Item.Shape and Item.Shape == Enum.PartType.Block ) then
- SizeIncrease = Vector3.new( 0, 0, increase );
- end;
- Item.Size = self.State.PreResize[Item].Size + SizeIncrease;
- if Item.Size == self.State.PreResize[Item].Size + SizeIncrease then
- Item.CFrame = ( self.Options.directions == "normal" and self.State.PreResize[Item].CFrame:toWorldSpace( CFrame.new( 0, 0, increase / 2 ) ) )
- or ( self.Options.directions == "both" and self.State.PreResize[Item].CFrame );
- -- If the resizing was not possible, revert `Item`'s state
- else
- Item.Size = PreviousItemState.Size;
- Item.CFrame = PreviousItemState.CFrame;
- end;
- elseif face == Enum.NormalId.Left then
- -- Calculate the appropriate increment to the size based on the shape of `Item`
- local SizeIncrease;
- if ( pcall( function () local test = Item.Shape; end ) ) and ( Item.Shape == Enum.PartType.Ball or Item.Shape == Enum.PartType.Cylinder ) then
- SizeIncrease = Vector3.new( increase, increase, increase );
- elseif not ( pcall( function () local test = Item.Shape; end ) ) or ( Item.Shape and Item.Shape == Enum.PartType.Block ) then
- SizeIncrease = Vector3.new( increase, 0, 0 );
- end;
- Item.Size = self.State.PreResize[Item].Size + SizeIncrease;
- if Item.Size == self.State.PreResize[Item].Size + SizeIncrease then
- Item.CFrame = ( self.Options.directions == "normal" and self.State.PreResize[Item].CFrame:toWorldSpace( CFrame.new( -increase / 2, 0, 0 ) ) )
- or ( self.Options.directions == "both" and self.State.PreResize[Item].CFrame );
- -- If the resizing was not possible, revert `Item`'s state
- else
- Item.Size = PreviousItemState.Size;
- Item.CFrame = PreviousItemState.CFrame;
- end;
- elseif face == Enum.NormalId.Right then
- -- Calculate the appropriate increment to the size based on the shape of `Item`
- local SizeIncrease;
- if ( pcall( function () local test = Item.Shape; end ) ) and ( Item.Shape == Enum.PartType.Ball or Item.Shape == Enum.PartType.Cylinder ) then
- SizeIncrease = Vector3.new( increase, increase, increase );
- elseif not ( pcall( function () local test = Item.Shape; end ) ) or ( Item.Shape and Item.Shape == Enum.PartType.Block ) then
- SizeIncrease = Vector3.new( increase, 0, 0 );
- end;
- Item.Size = self.State.PreResize[Item].Size + SizeIncrease;
- if Item.Size == self.State.PreResize[Item].Size + SizeIncrease then
- Item.CFrame = ( self.Options.directions == "normal" and self.State.PreResize[Item].CFrame:toWorldSpace( CFrame.new( increase / 2, 0, 0 ) ) )
- or ( self.Options.directions == "both" and self.State.PreResize[Item].CFrame );
- -- If the resizing was not possible, revert `Item`'s state
- else
- Item.Size = PreviousItemState.Size;
- Item.CFrame = PreviousItemState.CFrame;
- end;
- end;
- -- Make joints with surrounding parts again once the resizing is done
- Item:MakeJoints();
- end;
- end );
- end;
- -- Stop listening for the existence of the previous adornee (if any)
- if self.Connections.AdorneeExistenceListener then
- self.Connections.AdorneeExistenceListener:disconnect();
- self.Connections.AdorneeExistenceListener = nil;
- end;
- -- Attach the handles to `Part`
- self.Handles.Adornee = Part;
- -- Make sure to hide the handles if `Part` suddenly stops existing
- self.Connections.AdorneeExistenceListener = Part.AncestryChanged:connect( function ( Object, NewParent )
- -- Make sure this change in parent applies directly to `Part`
- if Object ~= Part then
- return;
- end;
- -- Show the handles according to the existence of the part
- if NewParent == nil then
- self:hideHandles();
- else
- self:showHandles( Part );
- end;
- end );
- end;
- Tools.Resize.hideHandles = function ( self )
- -- Hide the handles if they exist
- if self.Handles then
- self.Handles.Adornee = nil;
- end;
- end;
- Tools.Resize.Loaded = true;
- end))
- LocalScript3.Disabled = true
- LocalScript4.Name = "BTRotateTool"
- LocalScript4.Parent = LocalScript1
- table.insert(cors,sandbox(LocalScript4,function()
- -- Load the main tool's core environment when it's ready
- repeat wait() until (
- _G.BTCoreEnv and
- _G.BTCoreEnv[script.Parent.Parent] and
- _G.BTCoreEnv[script.Parent.Parent].CoreReady
- );
- setfenv( 1, _G.BTCoreEnv[script.Parent.Parent] );
- ------------------------------------------
- -- Rotate tool
- ------------------------------------------
- -- Create the tool
- Tools.Rotate = {};
- -- Create structures to hold data that the tool needs
- Tools.Rotate.Connections = {};
- Tools.Rotate.Options = {
- ["increment"] = 15;
- ["pivot"] = "center"
- };
- Tools.Rotate.State = {
- ["PreRotation"] = {};
- ["rotating"] = false;
- ["previous_distance"] = 0;
- ["degrees_rotated"] = 0;
- ["rotation_size"] = 0;
- };
- Tools.Rotate.Listeners = {};
- -- Define the color of the tool
- Tools.Rotate.Color = BrickColor.new( "Bright green" );
- -- Start adding functionality to the tool
- Tools.Rotate.Listeners.Equipped = function ()
- local self = Tools.Rotate;
- -- Change the color of selection boxes temporarily
- self.State.PreviousSelectionBoxColor = SelectionBoxColor;
- SelectionBoxColor = self.Color;
- updateSelectionBoxColor();
- -- Reveal the GUI
- self:showGUI();
- -- Create the boundingbox if it doesn't already exist
- if not self.BoundingBox then
- self.BoundingBox = RbxUtility.Create "Part" {
- Name = "BTBoundingBox";
- CanCollide = false;
- Transparency = 1;
- Anchored = true;
- };
- end;
- Mouse.TargetFilter = self.BoundingBox;
- -- Update the pivot option
- self:changePivot( self.Options.pivot );
- -- Oh, and update the boundingbox and the GUI regularly
- coroutine.wrap( function ()
- updater_on = true;
- -- Provide a function to stop the loop
- self.Updater = function ()
- updater_on = false;
- end;
- while wait( 0.1 ) and updater_on do
- -- Make sure the tool's equipped
- if CurrentTool == self then
- -- Update the GUI if it's visible
- if self.GUI and self.GUI.Visible then
- self:updateGUI();
- end;
- -- Update the boundingbox if it's visible
- if self.Options.pivot == "center" then
- self:updateBoundingBox();
- end;
- end;
- end;
- end )();
- -- Also enable the ability to select an edge as a pivot
- SelectEdge:start( function ( EdgeMarker )
- self:changePivot( "last" );
- self.Options.PivotPoint = EdgeMarker.CFrame;
- self.Connections.EdgeSelectionRemover = Selection.Changed:connect( function ()
- self.Options.PivotPoint = nil;
- if self.Connections.EdgeSelectionRemover then
- self.Connections.EdgeSelectionRemover:disconnect();
- self.Connections.EdgeSelectionRemover = nil;
- end;
- end );
- self:showHandles( EdgeMarker );
- end );
- end;
- Tools.Rotate.Listeners.Unequipped = function ()
- local self = Tools.Rotate;
- -- Stop the update loop
- if self.Updater then
- self.Updater();
- self.Updater = nil;
- end;
- -- Disable the ability to select edges
- SelectEdge:stop();
- if self.Options.PivotPoint then
- self.Options.PivotPoint = nil;
- end;
- -- Hide the GUI
- self:hideGUI();
- -- Hide the handles
- self:hideHandles();
- -- Clear out any temporary connections
- for connection_index, Connection in pairs( self.Connections ) do
- Connection:disconnect();
- self.Connections[connection_index] = nil;
- end;
- -- Restore the original color of the selection boxes
- SelectionBoxColor = self.State.PreviousSelectionBoxColor;
- updateSelectionBoxColor();
- end;
- Tools.Rotate.Listeners.Button1Down = function ()
- local self = Tools.Rotate;
- if not self.State.rotating and self.Options.PivotPoint then
- self.Options.PivotPoint = nil;
- end;
- end;
- Tools.Rotate.showGUI = function ( self )
- -- Initialize the GUI if it's not ready yet
- if not self.GUI then
- local Container = Tool.Interfaces:WaitForChild( "BTRotateToolGUI" ):Clone();
- Container.Parent = UI;
- -- Change the pivot type option when the button is clicked
- Container.PivotOption.Center.Button.MouseButton1Down:connect( function ()
- self:changePivot( "center" );
- end );
- Container.PivotOption.Local.Button.MouseButton1Down:connect( function ()
- self:changePivot( "local" );
- end );
- Container.PivotOption.Last.Button.MouseButton1Down:connect( function ()
- self:changePivot( "last" );
- end );
- -- Change the increment option when the value of the textbox is updated
- Container.IncrementOption.Increment.TextBox.FocusLost:connect( function ( enter_pressed )
- self.Options.increment = tonumber( Container.IncrementOption.Increment.TextBox.Text ) or self.Options.increment;
- Container.IncrementOption.Increment.TextBox.Text = tostring( self.Options.increment );
- end );
- -- Add functionality to the rotation inputs
- Container.Info.RotationInfo.X.TextButton.MouseButton1Down:connect( function ()
- self.State.rot_x_focused = true;
- Container.Info.RotationInfo.X.TextBox:CaptureFocus();
- end );
- Container.Info.RotationInfo.X.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.Info.RotationInfo.X.TextBox.Text );
- if potential_new then
- self:changeRotation( 'x', math.rad( potential_new ) );
- end;
- self.State.rot_x_focused = false;
- end );
- Container.Info.RotationInfo.Y.TextButton.MouseButton1Down:connect( function ()
- self.State.rot_y_focused = true;
- Container.Info.RotationInfo.Y.TextBox:CaptureFocus();
- end );
- Container.Info.RotationInfo.Y.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.Info.RotationInfo.Y.TextBox.Text );
- if potential_new then
- self:changeRotation( 'y', math.rad( potential_new ) );
- end;
- self.State.rot_y_focused = false;
- end );
- Container.Info.RotationInfo.Z.TextButton.MouseButton1Down:connect( function ()
- self.State.rot_z_focused = true;
- Container.Info.RotationInfo.Z.TextBox:CaptureFocus();
- end );
- Container.Info.RotationInfo.Z.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.Info.RotationInfo.Z.TextBox.Text );
- if potential_new then
- self:changeRotation( 'z', math.rad( potential_new ) );
- end;
- self.State.rot_z_focused = false;
- end );
- self.GUI = Container;
- end;
- -- Reveal the GUI
- self.GUI.Visible = true;
- end;
- Tools.Rotate.startHistoryRecord = function ( self )
- if self.State.HistoryRecord then
- self.State.HistoryRecord = nil;
- end;
- -- Create a history record
- self.State.HistoryRecord = {
- targets = _cloneTable( Selection.Items );
- initial_cframes = {};
- terminal_cframes = {};
- unapply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target.CFrame = self.initial_cframes[Target];
- Target:MakeJoints();
- Selection:add( Target );
- end;
- end;
- end;
- apply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target.CFrame = self.terminal_cframes[Target];
- Target:MakeJoints();
- Selection:add( Target );
- end;
- end;
- end;
- };
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.initial_cframes[Item] = Item.CFrame;
- end;
- end;
- end;
- Tools.Rotate.finishHistoryRecord = function ( self )
- if not self.State.HistoryRecord then
- return;
- end;
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.terminal_cframes[Item] = Item.CFrame;
- end;
- end;
- History:add( self.State.HistoryRecord );
- self.State.HistoryRecord = nil;
- end;
- Tools.Rotate.changeRotation = function ( self, component, new_value )
- self:startHistoryRecord();
- -- Change the rotation of each item selected
- for _, Item in pairs( Selection.Items ) do
- local old_x_rot, old_y_rot, old_z_rot = Item.CFrame:toEulerAnglesXYZ();
- Item.CFrame = CFrame.new( Item.Position ) * CFrame.Angles(
- component == 'x' and new_value or old_x_rot,
- component == 'y' and new_value or old_y_rot,
- component == 'z' and new_value or old_z_rot
- );
- end;
- self:finishHistoryRecord();
- end;
- Tools.Rotate.updateGUI = function ( self )
- -- Make sure the GUI exists
- if not self.GUI then
- return;
- end;
- local GUI = self.GUI;
- if #Selection.Items > 0 then
- -- Look for identical numbers in each axis
- local rot_x, rot_y, rot_z = nil, nil, nil;
- for item_index, Item in pairs( Selection.Items ) do
- local item_rot_x, item_rot_y, item_rot_z = Item.CFrame:toEulerAnglesXYZ();
- -- Set the first values for the first item
- if item_index == 1 then
- rot_x, rot_y, rot_z = _round( math.deg( item_rot_x ), 2 ), _round( math.deg( item_rot_y ), 2 ), _round( math.deg( item_rot_z ), 2 );
- -- Otherwise, compare them and set them to `nil` if they're not identical
- else
- if rot_x ~= _round( math.deg( item_rot_x ), 2 ) then
- rot_x = nil;
- end;
- if rot_y ~= _round( math.deg( item_rot_y ), 2 ) then
- rot_y = nil;
- end;
- if rot_z ~= _round( math.deg( item_rot_z ), 2 ) then
- rot_z = nil;
- end;
- end;
- end;
- -- Update the size info on the GUI
- if not self.State.rot_x_focused then
- GUI.Info.RotationInfo.X.TextBox.Text = rot_x and tostring( rot_x ) or "*";
- end;
- if not self.State.rot_y_focused then
- GUI.Info.RotationInfo.Y.TextBox.Text = rot_y and tostring( rot_y ) or "*";
- end;
- if not self.State.rot_z_focused then
- GUI.Info.RotationInfo.Z.TextBox.Text = rot_z and tostring( rot_z ) or "*";
- end;
- GUI.Info.Visible = true;
- else
- GUI.Info.Visible = false;
- end;
- if self.State.degrees_rotated then
- GUI.Changes.Text.Text = "rotated " .. tostring( self.State.degrees_rotated ) .. " degrees";
- GUI.Changes.Position = GUI.Info.Visible and UDim2.new( 0, 5, 0, 165 ) or UDim2.new( 0, 5, 0, 100 );
- GUI.Changes.Visible = true;
- else
- GUI.Changes.Text.Text = "";
- GUI.Changes.Visible = false;
- end;
- end;
- Tools.Rotate.hideGUI = function ( self )
- -- Hide the GUI if it exists
- if self.GUI then
- self.GUI.Visible = false;
- end;
- end;
- Tools.Rotate.updateBoundingBox = function ( self )
- if #Selection.Items > 0 then
- local SelectionSize, SelectionPosition = _getCollectionInfo( Selection.Items );
- self.BoundingBox.Size = SelectionSize;
- self.BoundingBox.CFrame = SelectionPosition;
- self:showHandles( self.BoundingBox );
- else
- self:hideHandles();
- end;
- end;
- Tools.Rotate.changePivot = function ( self, new_pivot )
- -- Have a quick reference to the GUI (if any)
- local PivotOptionGUI = self.GUI and self.GUI.PivotOption or nil;
- -- Disconnect any handle-related listeners that are specific to a certain pivot option
- if self.Connections.HandleFocusChangeListener then
- self.Connections.HandleFocusChangeListener:disconnect();
- self.Connections.HandleFocusChangeListener = nil;
- end;
- if self.Connections.HandleSelectionChangeListener then
- self.Connections.HandleSelectionChangeListener:disconnect();
- self.Connections.HandleSelectionChangeListener = nil;
- end;
- -- Remove any temporary edge selection
- if self.Options.PivotPoint then
- self.Options.PivotPoint = nil;
- end;
- if new_pivot == "center" then
- -- Update the options
- self.Options.pivot = "center";
- -- Focus the handles on the boundingbox
- self:showHandles( self.BoundingBox );
- -- Update the GUI's option panel
- if self.GUI then
- PivotOptionGUI.Center.SelectedIndicator.BackgroundTransparency = 0;
- PivotOptionGUI.Center.Background.Image = dark_slanted_rectangle;
- PivotOptionGUI.Local.SelectedIndicator.BackgroundTransparency = 1;
- PivotOptionGUI.Local.Background.Image = light_slanted_rectangle;
- PivotOptionGUI.Last.SelectedIndicator.BackgroundTransparency = 1;
- PivotOptionGUI.Last.Background.Image = light_slanted_rectangle;
- end;
- end;
- if new_pivot == "local" then
- -- Update the options
- self.Options.pivot = "local";
- -- Always have the handles on the most recent addition to the selection
- self.Connections.HandleSelectionChangeListener = Selection.Changed:connect( function ()
- -- Clear out any previous adornee
- self:hideHandles();
- -- If there /is/ a last item in the selection, attach the handles to it
- if Selection.Last then
- self:showHandles( Selection.Last );
- end;
- end );
- -- Switch the adornee of the handles if the second mouse button is pressed
- self.Connections.HandleFocusChangeListener = Mouse.Button2Up:connect( function ()
- -- Make sure the platform doesn't think we're selecting
- override_selection = true;
- -- If the target is in the selection, make it the new adornee
- if Selection:find( Mouse.Target ) then
- Selection:focus( Mouse.Target );
- self:showHandles( Mouse.Target );
- end;
- end );
- -- Finally, attach the handles to the last item added to the selection (if any)
- if Selection.Last then
- self:showHandles( Selection.Last );
- end;
- -- Update the GUI's option panel
- if self.GUI then
- PivotOptionGUI.Center.SelectedIndicator.BackgroundTransparency = 1;
- PivotOptionGUI.Center.Background.Image = light_slanted_rectangle;
- PivotOptionGUI.Local.SelectedIndicator.BackgroundTransparency = 0;
- PivotOptionGUI.Local.Background.Image = dark_slanted_rectangle;
- PivotOptionGUI.Last.SelectedIndicator.BackgroundTransparency = 1;
- PivotOptionGUI.Last.Background.Image = light_slanted_rectangle;
- end;
- end;
- if new_pivot == "last" then
- -- Update the options
- self.Options.pivot = "last";
- -- Always have the handles on the most recent addition to the selection
- self.Connections.HandleSelectionChangeListener = Selection.Changed:connect( function ()
- -- Clear out any previous adornee
- if not self.Options.PivotPoint then
- self:hideHandles();
- end;
- -- If there /is/ a last item in the selection, attach the handles to it
- if Selection.Last and not self.Options.PivotPoint then
- self:showHandles( Selection.Last );
- end;
- end );
- -- Switch the adornee of the handles if the second mouse button is pressed
- self.Connections.HandleFocusChangeListener = Mouse.Button2Up:connect( function ()
- -- Make sure the platform doesn't think we're selecting
- override_selection = true;
- -- If the target is in the selection, make it the new adornee
- if Selection:find( Mouse.Target ) then
- Selection:focus( Mouse.Target );
- self:showHandles( Mouse.Target );
- end;
- end );
- -- Finally, attach the handles to the last item added to the selection (if any)
- if Selection.Last then
- self:showHandles( Selection.Last );
- end;
- -- Update the GUI's option panel
- if self.GUI then
- PivotOptionGUI.Center.SelectedIndicator.BackgroundTransparency = 1;
- PivotOptionGUI.Center.Background.Image = light_slanted_rectangle;
- PivotOptionGUI.Local.SelectedIndicator.BackgroundTransparency = 1;
- PivotOptionGUI.Local.Background.Image = light_slanted_rectangle;
- PivotOptionGUI.Last.SelectedIndicator.BackgroundTransparency = 0;
- PivotOptionGUI.Last.Background.Image = dark_slanted_rectangle;
- end;
- end;
- end;
- Tools.Rotate.showHandles = function ( self, Part )
- -- Create the handles if they don't exist yet
- if not self.Handles then
- -- Create the object
- self.Handles = RbxUtility.Create "ArcHandles" {
- Name = "BTRotationHandles";
- Color = self.Color;
- Parent = GUIContainer;
- };
- -- Add functionality to the handles
- self.Handles.MouseButton1Down:connect( function ()
- -- Prevent the platform from thinking we're selecting
- override_selection = true;
- self.State.rotating = true;
- -- Clear the change stats
- self.State.degrees_rotated = 0;
- self.State.rotation_size = 0;
- self:startHistoryRecord();
- -- Do a few things to the selection before manipulating it
- for _, Item in pairs( Selection.Items ) do
- -- Keep a copy of the state of each item
- self.State.PreRotation[Item] = Item:Clone();
- -- Anchor each item
- Item.Anchored = true;
- end;
- -- Also keep the position of the original selection
- local PreRotationSize, PreRotationPosition = _getCollectionInfo( self.State.PreRotation );
- self.State.PreRotationPosition = PreRotationPosition;
- -- Return stuff to normal once the mouse button is released
- self.Connections.HandleReleaseListener = Mouse.Button1Up:connect( function ()
- -- Prevent the platform from thinking we're selecting
- override_selection = true;
- self.State.rotating = false;
- -- Stop this connection from firing again
- if self.Connections.HandleReleaseListener then
- self.Connections.HandleReleaseListener:disconnect();
- self.Connections.HandleReleaseListener = nil;
- end;
- self:finishHistoryRecord();
- -- Restore properties that may have been changed temporarily
- -- from the pre-rotation state copies
- for Item, PreviousItemState in pairs( self.State.PreRotation ) do
- Item.Anchored = PreviousItemState.Anchored;
- self.State.PreRotation[Item] = nil;
- Item:MakeJoints();
- end;
- end );
- end );
- self.Handles.MouseDrag:connect( function ( axis, drag_distance )
- -- Round down and convert the drag distance to degrees to make it easier to work with
- local drag_distance = math.floor( math.deg( drag_distance ) );
- -- Calculate which multiple of the increment to use based on the current angle's
- -- proximity to their nearest upper and lower multiples
- local difference = drag_distance % self.Options.increment;
- local lower_degree = drag_distance - difference;
- local upper_degree = drag_distance - difference + self.Options.increment;
- local lower_degree_proximity = math.abs( drag_distance - lower_degree );
- local upper_degree_proximity = math.abs( drag_distance - upper_degree );
- if lower_degree_proximity <= upper_degree_proximity then
- drag_distance = lower_degree;
- else
- drag_distance = upper_degree;
- end;
- local increase = self.Options.increment * math.floor( drag_distance / self.Options.increment );
- self.State.degrees_rotated = drag_distance;
- -- Go through the selection and make changes to it
- for _, Item in pairs( Selection.Items ) do
- -- Keep a copy of `Item` in case we need to revert anything
- local PreviousItemState = Item:Clone();
- -- Break any of `Item`'s joints so it can move freely
- Item:BreakJoints();
- -- Rotate `Item` according to the options and the handle that was used
- if axis == Enum.Axis.Y then
- if self.Options.pivot == "center" then
- Item.CFrame = self.State.PreRotationPosition:toWorldSpace( CFrame.new( 0, 0, 0 ) * CFrame.Angles( 0, math.rad( increase ), 0 ) ):toWorldSpace( self.State.PreRotation[Item].CFrame:toObjectSpace( self.State.PreRotationPosition ):inverse() );
- elseif self.Options.pivot == "local" then
- Item.CFrame = self.State.PreRotation[Item].CFrame:toWorldSpace( CFrame.new( 0, 0, 0 ) * CFrame.Angles( 0, math.rad( increase ), 0 ) );
- elseif self.Options.pivot == "last" then
- Item.CFrame = ( self.Options.PivotPoint or self.State.PreRotation[Selection.Last].CFrame ):toWorldSpace( CFrame.new( 0, 0, 0 ) * CFrame.Angles( 0, math.rad( increase ), 0 ) ):toWorldSpace( self.State.PreRotation[Item].CFrame:toObjectSpace( self.Options.PivotPoint or self.State.PreRotation[Selection.Last].CFrame ):inverse() );
- end;
- elseif axis == Enum.Axis.X then
- if self.Options.pivot == "center" then
- Item.CFrame = self.State.PreRotationPosition:toWorldSpace( CFrame.new( 0, 0, 0 ) * CFrame.Angles( math.rad( increase ), 0, 0 ) ):toWorldSpace( self.State.PreRotation[Item].CFrame:toObjectSpace( self.State.PreRotationPosition ):inverse() );
- elseif self.Options.pivot == "local" then
- Item.CFrame = self.State.PreRotation[Item].CFrame:toWorldSpace( CFrame.new( 0, 0, 0 ) * CFrame.Angles( math.rad( increase ), 0, 0 ) );
- elseif self.Options.pivot == "last" then
- Item.CFrame = ( self.Options.PivotPoint or self.State.PreRotation[Selection.Last].CFrame ):toWorldSpace( CFrame.new( 0, 0, 0 ) * CFrame.Angles( math.rad( increase ), 0, 0 ) ):toWorldSpace( self.State.PreRotation[Item].CFrame:toObjectSpace( self.Options.PivotPoint or self.State.PreRotation[Selection.Last].CFrame ):inverse() );
- end;
- elseif axis == Enum.Axis.Z then
- if self.Options.pivot == "center" then
- Item.CFrame = self.State.PreRotationPosition:toWorldSpace( CFrame.new( 0, 0, 0 ) * CFrame.Angles( 0, 0, math.rad( increase ) ) ):toWorldSpace( self.State.PreRotation[Item].CFrame:toObjectSpace( self.State.PreRotationPosition ):inverse() );
- elseif self.Options.pivot == "local" then
- Item.CFrame = self.State.PreRotation[Item].CFrame:toWorldSpace( CFrame.new( 0, 0, 0 ) * CFrame.Angles( 0, 0, math.rad( increase ) ) );
- elseif self.Options.pivot == "last" then
- Item.CFrame = ( self.Options.PivotPoint or self.State.PreRotation[Selection.Last].CFrame ):toWorldSpace( CFrame.new( 0, 0, 0 ) * CFrame.Angles( 0, 0, math.rad( increase ) ) ):toWorldSpace( self.State.PreRotation[Item].CFrame:toObjectSpace( self.Options.PivotPoint or self.State.PreRotation[Selection.Last].CFrame ):inverse() );
- end;
- end;
- -- Make joints with surrounding parts again once the resizing is done
- Item:MakeJoints();
- end;
- end );
- end;
- -- Stop listening for the existence of the previous adornee (if any)
- if self.Connections.AdorneeExistenceListener then
- self.Connections.AdorneeExistenceListener:disconnect();
- self.Connections.AdorneeExistenceListener = nil;
- end;
- -- Attach the handles to `Part`
- self.Handles.Adornee = Part;
- -- Make sure to hide the handles if `Part` suddenly stops existing
- self.Connections.AdorneeExistenceListener = Part.AncestryChanged:connect( function ( Object, NewParent )
- -- Make sure this change in parent applies directly to `Part`
- if Object ~= Part then
- return;
- end;
- -- Show the handles according to the existence of the part
- if NewParent == nil then
- self:hideHandles();
- else
- self:showHandles( Part );
- end;
- end );
- end;
- Tools.Rotate.hideHandles = function ( self )
- -- Hide the handles if they exist
- if self.Handles then
- self.Handles.Adornee = nil;
- end;
- end;
- Tools.Rotate.Loaded = true;
- end))
- LocalScript4.Disabled = true
- LocalScript5.Name = "BTPaintTool"
- LocalScript5.Parent = LocalScript1
- table.insert(cors,sandbox(LocalScript5,function()
- -- Load the main tool's core environment when it's ready
- repeat wait() until (
- _G.BTCoreEnv and
- _G.BTCoreEnv[script.Parent.Parent] and
- _G.BTCoreEnv[script.Parent.Parent].CoreReady
- );
- setfenv( 1, _G.BTCoreEnv[script.Parent.Parent] );
- ------------------------------------------
- -- Paint tool
- ------------------------------------------
- -- Create the main container for this tool
- Tools.Paint = {};
- -- Define the color of the tool
- Tools.Paint.Color = BrickColor.new( "Really red" );
- -- Define options
- Tools.Paint.Options = {
- ["Color"] = nil
- };
- Tools.Paint.State = {};
- -- Add listeners
- Tools.Paint.Listeners = {};
- Tools.Paint.Listeners.Equipped = function ()
- local self = Tools.Paint;
- -- Change the color of selection boxes temporarily
- self.State.PreviousSelectionBoxColor = SelectionBoxColor;
- SelectionBoxColor = self.Color;
- updateSelectionBoxColor();
- -- Show the GUI
- self:showGUI();
- -- Update the selected color
- self:changeColor( self.Options.Color );
- end;
- Tools.Paint.Listeners.Unequipped = function ()
- local self = Tools.Paint;
- -- Clear out the preferred color option
- self:changeColor( nil );
- -- Hide the GUI
- self:hideGUI();
- -- Restore the original color of the selection boxes
- SelectionBoxColor = self.State.PreviousSelectionBoxColor;
- updateSelectionBoxColor();
- end;
- Tools.Paint.startHistoryRecord = function ( self )
- if self.State.HistoryRecord then
- self.State.HistoryRecord = nil;
- end;
- -- Create a history record
- self.State.HistoryRecord = {
- targets = _cloneTable( Selection.Items );
- initial_colors = {};
- terminal_colors = {};
- unapply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target.BrickColor = self.initial_colors[Target];
- Selection:add( Target );
- end;
- end;
- end;
- apply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target.BrickColor = self.terminal_colors[Target];
- Selection:add( Target );
- end;
- end;
- end;
- };
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.initial_colors[Item] = Item.BrickColor;
- end;
- end;
- end;
- Tools.Paint.finishHistoryRecord = function ( self )
- if not self.State.HistoryRecord then
- return;
- end;
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.terminal_colors[Item] = Item.BrickColor;
- end;
- end;
- History:add( self.State.HistoryRecord );
- self.State.HistoryRecord = nil;
- end;
- Tools.Paint.Listeners.Button1Up = function ()
- local self = Tools.Paint;
- -- Make sure that they clicked on one of the items in their selection
- -- (and they weren't multi-selecting)
- if Selection:find( Mouse.Target ) and not selecting and not selecting then
- override_selection = true;
- self:startHistoryRecord();
- -- Paint all of the selected items `Tools.Paint.Options.Color`
- if self.Options.Color then
- for _, Item in pairs( Selection.Items ) do
- Item.BrickColor = self.Options.Color;
- end;
- end;
- self:finishHistoryRecord();
- end;
- end;
- Tools.Paint.changeColor = function ( self, Color )
- -- Alright so if `Color` is given, set that as the preferred color
- if Color then
- -- First of all, change the color option itself
- self.Options.Color = Color;
- self:startHistoryRecord();
- -- Then, we want to update the color of any items in the selection
- for _, Item in pairs( Selection.Items ) do
- Item.BrickColor = Color;
- end;
- self:finishHistoryRecord();
- -- After that, we want to mark our new color in the palette
- if self.GUI then
- -- First clear out any other marks
- for _, ColorSquare in pairs( self.GUI.Palette:GetChildren() ) do
- ColorSquare.Text = "";
- end;
- -- Then mark the right square
- self.GUI.Palette[Color.Name].Text = "X";
- end;
- -- Otherwise, let's assume no color at all
- else
- -- Set the preferred color to none
- self.Options.Color = nil;
- -- Clear out any color option marks on any of the squares
- if self.GUI then
- for _, ColorSquare in pairs( self.GUI.Palette:GetChildren() ) do
- ColorSquare.Text = "";
- end;
- end;
- end;
- end;
- Tools.Paint.showGUI = function ( self )
- -- Initialize the GUI if it's not ready yet
- if not self.GUI then
- local Container = Tool.Interfaces:WaitForChild( "BTPaintToolGUI" ):Clone();
- Container.Parent = UI;
- for _, ColorButton in pairs( Container.Palette:GetChildren() ) do
- ColorButton.MouseButton1Click:connect( function ()
- self:changeColor( BrickColor.new( ColorButton.Name ) );
- end );
- end;
- self.GUI = Container;
- end;
- -- Reveal the GUI
- self.GUI.Visible = true;
- end;
- Tools.Paint.hideGUI = function ( self )
- -- Hide the GUI if it exists
- if self.GUI then
- self.GUI.Visible = false;
- end;
- end;
- Tools.Paint.Loaded = true;
- end))
- LocalScript5.Disabled = true
- LocalScript6.Name = "BTSurfaceTool"
- LocalScript6.Parent = LocalScript1
- table.insert(cors,sandbox(LocalScript6,function()
- -- Load the main tool's core environment when it's ready
- repeat wait() until (
- _G.BTCoreEnv and
- _G.BTCoreEnv[script.Parent.Parent] and
- _G.BTCoreEnv[script.Parent.Parent].CoreReady
- );
- setfenv( 1, _G.BTCoreEnv[script.Parent.Parent] );
- ------------------------------------------
- -- Surface tool
- ------------------------------------------
- -- Create the tool
- Tools.Surface = {};
- -- Define the tool's color
- Tools.Surface.Color = BrickColor.new( "Bright violet" );
- -- Keep a container for temporary connections
- Tools.Surface.Connections = {};
- -- Keep a container for state data
- Tools.Surface.State = {
- ["type"] = nil;
- };
- -- Maintain a container for options
- Tools.Surface.Options = {
- ["side"] = Enum.NormalId.Front;
- };
- -- Keep a container for platform event connections
- Tools.Surface.Listeners = {};
- -- Start adding functionality to the tool
- Tools.Surface.Listeners.Equipped = function ()
- local self = Tools.Surface;
- -- Change the color of selection boxes temporarily
- self.State.PreviousSelectionBoxColor = SelectionBoxColor;
- SelectionBoxColor = self.Color;
- updateSelectionBoxColor();
- -- Reveal the GUI
- self:showGUI();
- -- Restore the side option
- self:changeSurface( self.Options.side );
- -- Update the GUI regularly
- coroutine.wrap( function ()
- updater_on = true;
- -- Provide a function to stop the loop
- self.Updater = function ()
- updater_on = false;
- end;
- while wait( 0.1 ) and updater_on do
- -- Make sure the tool's equipped
- if CurrentTool == self then
- -- Update the surface type of every item in the selection
- local surface_type = nil;
- for item_index, Item in pairs( Selection.Items ) do
- -- Set the first values for the first item
- if item_index == 1 then
- surface_type = Item[self.Options.side.Name .. "Surface"];
- -- Otherwise, compare them and set them to `nil` if they're not identical
- else
- if surface_type ~= Item[self.Options.side.Name .. "Surface"] then
- surface_type = nil;
- end;
- end;
- end;
- self.State.type = surface_type;
- -- Update the GUI if it's visible
- if self.GUI and self.GUI.Visible then
- self:updateGUI();
- end;
- end;
- end;
- end )();
- end;
- Tools.Surface.Listeners.Unequipped = function ()
- local self = Tools.Surface;
- -- Stop the GUI updating loop
- self.Updater();
- self.Updater = nil;
- -- Hide the GUI
- self:hideGUI();
- -- Disconnect temporary connections
- for connection_index, Connection in pairs( self.Connections ) do
- Connection:disconnect();
- self.Connections[connection_index] = nil;
- end;
- -- Restore the original color of selection boxes
- SelectionBoxColor = self.State.PreviousSelectionBoxColor;
- updateSelectionBoxColor();
- end;
- Tools.Surface.Listeners.Button2Down = function ()
- local self = Tools.Surface;
- -- Capture the camera rotation (for later use
- -- in determining whether a surface was being
- -- selected or the camera was being rotated
- -- with the right mouse button)
- local cr_x, cr_y, cr_z = Services.Workspace.CurrentCamera.CoordinateFrame:toEulerAnglesXYZ();
- self.State.PreB2DownCameraRotation = Vector3.new( cr_x, cr_y, cr_z );
- end;
- Tools.Surface.Listeners.Button2Up = function ()
- local self = Tools.Surface;
- local cr_x, cr_y, cr_z = Services.Workspace.CurrentCamera.CoordinateFrame:toEulerAnglesXYZ();
- local CameraRotation = Vector3.new( cr_x, cr_y, cr_z );
- -- If a surface is selected
- if Selection:find( Mouse.Target ) and self.State.PreB2DownCameraRotation == CameraRotation then
- self:changeSurface( Mouse.TargetSurface );
- end;
- end;
- Tools.Surface.startHistoryRecord = function ( self )
- if self.State.HistoryRecord then
- self.State.HistoryRecord = nil;
- end;
- -- Create a history record
- self.State.HistoryRecord = {
- targets = _cloneTable( Selection.Items );
- target_surface = self.Options.side;
- initial_surfaces = {};
- terminal_surfaces = {};
- unapply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target[self.target_surface.Name .. "Surface"] = self.initial_surfaces[Target];
- Target:MakeJoints();
- Selection:add( Target );
- end;
- end;
- end;
- apply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target[self.target_surface.Name .. "Surface"] = self.terminal_surfaces[Target];
- Target:MakeJoints();
- Selection:add( Target );
- end;
- end;
- end;
- };
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.initial_surfaces[Item] = Item[self.Options.side.Name .. "Surface"];
- end;
- end;
- end;
- Tools.Surface.finishHistoryRecord = function ( self )
- if not self.State.HistoryRecord then
- return;
- end;
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.terminal_surfaces[Item] = Item[self.Options.side.Name .. "Surface"];
- end;
- end;
- History:add( self.State.HistoryRecord );
- self.State.HistoryRecord = nil;
- end;
- Tools.Surface.SpecialTypeNames = {
- SmoothNoOutlines = "NO OUTLINE",
- Inlet = "INLETS"
- };
- Tools.Surface.changeType = function ( self, surface_type )
- self:startHistoryRecord();
- -- Apply `surface_type` to all items in the selection
- for _, Item in pairs( Selection.Items ) do
- Item[self.Options.side.Name .. "Surface"] = surface_type;
- Item:MakeJoints();
- end;
- self:finishHistoryRecord();
- self.TypeDropdown:selectOption( self.SpecialTypeNames[surface_type.Name] or surface_type.Name:upper() );
- if self.TypeDropdown.open then
- self.TypeDropdown:toggle();
- end;
- end;
- Tools.Surface.changeSurface = function ( self, surface )
- self.Options.side = surface;
- self.SideDropdown:selectOption( surface.Name:upper() );
- if self.SideDropdown.open then
- self.SideDropdown:toggle();
- end;
- end;
- Tools.Surface.updateGUI = function ( self )
- -- Make sure the GUI exists
- if not self.GUI then
- return;
- end;
- if #Selection.Items > 0 then
- self.TypeDropdown:selectOption( self.State.type and ( self.SpecialTypeNames[self.State.type.Name] or self.State.type.Name:upper() ) or "*" );
- else
- self.TypeDropdown:selectOption( "" );
- end;
- end;
- Tools.Surface.showGUI = function ( self )
- -- Initialize the GUI if it's not ready yet
- if not self.GUI then
- local Container = Tool.Interfaces:WaitForChild( "BTSurfaceToolGUI" ):Clone();
- Container.Parent = UI;
- local SideDropdown = createDropdown();
- self.SideDropdown = SideDropdown;
- SideDropdown.Frame.Parent = Container.SideOption;
- SideDropdown.Frame.Position = UDim2.new( 0, 30, 0, 0 );
- SideDropdown.Frame.Size = UDim2.new( 0, 72, 0, 25 );
- SideDropdown:addOption( "TOP" ).MouseButton1Up:connect( function ()
- self:changeSurface( Enum.NormalId.Top );
- end );
- SideDropdown:addOption( "BOTTOM" ).MouseButton1Up:connect( function ()
- self:changeSurface( Enum.NormalId.Bottom );
- end );
- SideDropdown:addOption( "FRONT" ).MouseButton1Up:connect( function ()
- self:changeSurface( Enum.NormalId.Front );
- end );
- SideDropdown:addOption( "BACK" ).MouseButton1Up:connect( function ()
- self:changeSurface( Enum.NormalId.Back );
- end );
- SideDropdown:addOption( "LEFT" ).MouseButton1Up:connect( function ()
- self:changeSurface( Enum.NormalId.Left );
- end );
- SideDropdown:addOption( "RIGHT" ).MouseButton1Up:connect( function ()
- self:changeSurface( Enum.NormalId.Right );
- end );
- local TypeDropdown = createDropdown();
- self.TypeDropdown = TypeDropdown;
- TypeDropdown.Frame.Parent = Container.TypeOption;
- TypeDropdown.Frame.Position = UDim2.new( 0, 30, 0, 0 );
- TypeDropdown.Frame.Size = UDim2.new( 0, 87, 0, 25 );
- TypeDropdown:addOption( "STUDS" ).MouseButton1Up:connect( function ()
- self:changeType( Enum.SurfaceType.Studs );
- end );
- TypeDropdown:addOption( "INLETS" ).MouseButton1Up:connect( function ()
- self:changeType( Enum.SurfaceType.Inlet );
- end );
- TypeDropdown:addOption( "SMOOTH" ).MouseButton1Up:connect( function ()
- self:changeType( Enum.SurfaceType.Smooth );
- end );
- TypeDropdown:addOption( "WELD" ).MouseButton1Up:connect( function ()
- self:changeType( Enum.SurfaceType.Weld );
- end );
- TypeDropdown:addOption( "GLUE" ).MouseButton1Up:connect( function ()
- self:changeType( Enum.SurfaceType.Glue );
- end );
- TypeDropdown:addOption( "UNIVERSAL" ).MouseButton1Up:connect( function ()
- self:changeType( Enum.SurfaceType.Universal );
- end );
- TypeDropdown:addOption( "HINGE" ).MouseButton1Up:connect( function ()
- self:changeType( Enum.SurfaceType.Hinge );
- end );
- TypeDropdown:addOption( "MOTOR" ).MouseButton1Up:connect( function ()
- self:changeType( Enum.SurfaceType.Motor );
- end );
- TypeDropdown:addOption( "NO OUTLINE" ).MouseButton1Up:connect( function ()
- self:changeType( Enum.SurfaceType.SmoothNoOutlines );
- end );
- self.GUI = Container;
- end;
- -- Reveal the GUI
- self.GUI.Visible = true;
- end;
- Tools.Surface.hideGUI = function ( self )
- -- Hide the GUI if it exists already
- if self.GUI then
- self.GUI.Visible = false;
- end;
- end;
- Tools.Surface.Loaded = true;
- end))
- LocalScript6.Disabled = true
- LocalScript7.Name = "BTMaterialTool"
- LocalScript7.Parent = LocalScript1
- table.insert(cors,sandbox(LocalScript7,function()
- -- Load the main tool's core environment when it's ready
- repeat wait() until (
- _G.BTCoreEnv and
- _G.BTCoreEnv[script.Parent.Parent] and
- _G.BTCoreEnv[script.Parent.Parent].CoreReady
- );
- setfenv( 1, _G.BTCoreEnv[script.Parent.Parent] );
- ------------------------------------------
- -- Material tool
- ------------------------------------------
- -- Create the tool
- Tools.Material = {};
- Tools.Material.Color = BrickColor.new( "Bright violet" );
- Tools.Material.Connections = {};
- Tools.Material.State = {
- ["material"] = nil;
- ["reflectance_focused"] = false;
- ["transparency_focused"] = false;
- };
- Tools.Material.Listeners = {};
- Tools.Material.SpecialMaterialNames = {
- CorrodedMetal = "CORRODED METAL",
- DiamondPlate = "DIAMOND PLATE",
- SmoothPlastic = "SMOOTH PLASTIC"
- };
- -- Start adding functionality to the tool
- Tools.Material.Listeners.Equipped = function ()
- local self = Tools.Material;
- -- Change the color of selection boxes temporarily
- self.State.PreviousSelectionBoxColor = SelectionBoxColor;
- SelectionBoxColor = self.Color;
- updateSelectionBoxColor();
- -- Reveal the GUI
- self:showGUI();
- -- Update the GUI regularly
- coroutine.wrap( function ()
- updater_on = true;
- -- Provide a function to stop the loop
- self.Updater = function ()
- updater_on = false;
- end;
- while wait( 0.1 ) and updater_on do
- -- Make sure the tool's equipped
- if CurrentTool == self then
- -- Update the material type of every item in the selection
- local material_type, transparency, reflectance = nil, nil, nil;
- for item_index, Item in pairs( Selection.Items ) do
- -- Set the first values for the first item
- if item_index == 1 then
- material_type = Item.Material;
- transparency = Item.Transparency;
- reflectance = Item.Reflectance;
- -- Otherwise, compare them and set them to `nil` if they're not identical
- else
- if material_type ~= Item.Material then
- material_type = nil;
- end;
- if reflectance ~= Item.Reflectance then
- reflectance = nil;
- end;
- if transparency ~= Item.Transparency then
- transparency = nil;
- end;
- end;
- end;
- self.State.material = material_type;
- self.State.transparency = transparency;
- self.State.reflectance = reflectance;
- -- Update the GUI if it's visible
- if self.GUI and self.GUI.Visible then
- self:updateGUI();
- end;
- end;
- end;
- end )();
- end;
- Tools.Material.Listeners.Unequipped = function ()
- local self = Tools.Material;
- -- Stop the GUI updating loop
- self.Updater();
- self.Updater = nil;
- -- Hide the GUI
- self:hideGUI();
- -- Disconnect temporary connections
- for connection_index, Connection in pairs( self.Connections ) do
- Connection:disconnect();
- self.Connections[connection_index] = nil;
- end;
- -- Restore the original color of selection boxes
- SelectionBoxColor = self.State.PreviousSelectionBoxColor;
- updateSelectionBoxColor();
- end;
- Tools.Material.startHistoryRecord = function ( self )
- if self.State.HistoryRecord then
- self.State.HistoryRecord = nil;
- end;
- -- Create a history record
- self.State.HistoryRecord = {
- targets = _cloneTable( Selection.Items );
- initial_material = {};
- terminal_material = {};
- initial_transparency = {};
- terminal_transparency = {};
- initial_reflectance = {};
- terminal_reflectance = {};
- unapply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target.Material = self.initial_material[Target];
- Target.Transparency = self.initial_transparency[Target];
- Target.Reflectance = self.initial_reflectance[Target];
- Selection:add( Target );
- end;
- end;
- end;
- apply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target.Material = self.terminal_material[Target];
- Target.Transparency = self.terminal_transparency[Target];
- Target.Reflectance = self.terminal_reflectance[Target];
- Selection:add( Target );
- end;
- end;
- end;
- };
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.initial_material[Item] = Item.Material;
- self.State.HistoryRecord.initial_transparency[Item] = Item.Transparency;
- self.State.HistoryRecord.initial_reflectance[Item] = Item.Reflectance;
- end;
- end;
- end;
- Tools.Material.finishHistoryRecord = function ( self )
- if not self.State.HistoryRecord then
- return;
- end;
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.terminal_material[Item] = Item.Material;
- self.State.HistoryRecord.terminal_transparency[Item] = Item.Transparency;
- self.State.HistoryRecord.terminal_reflectance[Item] = Item.Reflectance;
- end;
- end;
- History:add( self.State.HistoryRecord );
- self.State.HistoryRecord = nil;
- end;
- Tools.Material.changeMaterial = function ( self, material_type )
- self:startHistoryRecord();
- -- Apply `material_type` to all items in the selection
- for _, Item in pairs( Selection.Items ) do
- Item.Material = material_type;
- end;
- self:finishHistoryRecord();
- if self.MaterialDropdown.open then
- self.MaterialDropdown:toggle();
- end;
- end;
- Tools.Material.changeTransparency = function ( self, transparency )
- self:startHistoryRecord();
- -- Apply `transparency` to all items in the selection
- for _, Item in pairs( Selection.Items ) do
- Item.Transparency = transparency;
- end;
- self:finishHistoryRecord();
- end;
- Tools.Material.changeReflectance = function ( self, reflectance )
- self:startHistoryRecord();
- -- Apply `reflectance` to all items in the selection
- for _, Item in pairs( Selection.Items ) do
- Item.Reflectance = reflectance;
- end;
- self:finishHistoryRecord();
- end;
- Tools.Material.updateGUI = function ( self )
- -- Make sure the GUI exists
- if not self.GUI then
- return;
- end;
- if #Selection.Items > 0 then
- self.GUI.Size = UDim2.new( 0, 200, 0, 145 );
- self.GUI.MaterialOption.Visible = true;
- self.GUI.ReflectanceOption.Visible = true;
- self.GUI.TransparencyOption.Visible = true;
- self.GUI.SelectNote.Visible = false;
- self.MaterialDropdown:selectOption( self.State.material and ( self.SpecialMaterialNames[self.State.material.Name] or self.State.material.Name:upper() ) or "*" );
- -- Update the text inputs without interrupting the user
- if not self.State.transparency_focused then
- self.GUI.TransparencyOption.TransparencyInput.TextBox.Text = self.State.transparency and tostring( _round( self.State.transparency, 2 ) ) or "*";
- end;
- if not self.State.reflectance_focused then
- self.GUI.ReflectanceOption.ReflectanceInput.TextBox.Text = self.State.reflectance and tostring( _round( self.State.reflectance, 2 ) ) or "*";
- end;
- else
- self.GUI.Size = UDim2.new( 0, 200, 0, 62 );
- self.GUI.MaterialOption.Visible = false;
- self.GUI.ReflectanceOption.Visible = false;
- self.GUI.TransparencyOption.Visible = false;
- self.GUI.SelectNote.Visible = true;
- self.MaterialDropdown:selectOption( "" );
- self.GUI.TransparencyOption.TransparencyInput.TextBox.Text = "";
- self.GUI.ReflectanceOption.ReflectanceInput.TextBox.Text = "";
- end;
- end;
- Tools.Material.showGUI = function ( self )
- -- Initialize the GUI if it's not ready yet
- if not self.GUI then
- local Container = Tool.Interfaces:WaitForChild( "BTMaterialToolGUI" ):Clone();
- Container.Parent = UI;
- local MaterialDropdown = createDropdown();
- self.MaterialDropdown = MaterialDropdown;
- MaterialDropdown.Frame.Parent = Container.MaterialOption;
- MaterialDropdown.Frame.Position = UDim2.new( 0, 50, 0, 0 );
- MaterialDropdown.Frame.Size = UDim2.new( 0, 130, 0, 25 );
- MaterialDropdown:addOption( "SMOOTH PLASTIC" ).MouseButton1Up:connect( function ()
- self:changeMaterial( Enum.Material.SmoothPlastic );
- end );
- MaterialDropdown:addOption( "PLASTIC" ).MouseButton1Up:connect( function ()
- self:changeMaterial( Enum.Material.Plastic );
- end );
- MaterialDropdown:addOption( "CONCRETE" ).MouseButton1Up:connect( function ()
- self:changeMaterial( Enum.Material.Concrete );
- end );
- MaterialDropdown:addOption( "DIAMOND PLATE" ).MouseButton1Up:connect( function ()
- self:changeMaterial( Enum.Material.DiamondPlate );
- end );
- MaterialDropdown:addOption( "CORRODED METAL" ).MouseButton1Up:connect( function ()
- self:changeMaterial( Enum.Material.CorrodedMetal );
- end );
- MaterialDropdown:addOption( "BRICK" ).MouseButton1Up:connect( function ()
- self:changeMaterial( Enum.Material.Brick );
- end );
- MaterialDropdown:addOption( "FABRIC" ).MouseButton1Up:connect( function ()
- self:changeMaterial( Enum.Material.Fabric );
- end );
- MaterialDropdown:addOption( "FOIL" ).MouseButton1Up:connect( function ()
- self:changeMaterial( Enum.Material.Foil );
- end );
- MaterialDropdown:addOption( "GRANITE" ).MouseButton1Up:connect( function ()
- self:changeMaterial( Enum.Material.Granite );
- end );
- MaterialDropdown:addOption( "GRASS" ).MouseButton1Up:connect( function ()
- self:changeMaterial( Enum.Material.Grass );
- end );
- MaterialDropdown:addOption( "ICE" ).MouseButton1Up:connect( function ()
- self:changeMaterial( Enum.Material.Ice );
- end );
- MaterialDropdown:addOption( "MARBLE" ).MouseButton1Up:connect( function ()
- self:changeMaterial( Enum.Material.Marble );
- end );
- MaterialDropdown:addOption( "PEBBLE" ).MouseButton1Up:connect( function ()
- self:changeMaterial( Enum.Material.Pebble );
- end );
- MaterialDropdown:addOption( "SAND" ).MouseButton1Up:connect( function ()
- self:changeMaterial( Enum.Material.Sand );
- end );
- MaterialDropdown:addOption( "SLATE" ).MouseButton1Up:connect( function ()
- self:changeMaterial( Enum.Material.Slate );
- end );
- MaterialDropdown:addOption( "WOOD" ).MouseButton1Up:connect( function ()
- self:changeMaterial( Enum.Material.Wood );
- end );
- -- Capture focus of the input when clicked
- -- (so we can detect when it is focused-on)
- Container.TransparencyOption.TransparencyInput.TextButton.MouseButton1Down:connect( function ()
- self.State.transparency_focused = true;
- Container.TransparencyOption.TransparencyInput.TextBox:CaptureFocus();
- end );
- -- Change the transparency when the value of the textbox is updated
- Container.TransparencyOption.TransparencyInput.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.TransparencyOption.TransparencyInput.TextBox.Text );
- if potential_new then
- if potential_new > 1 then
- potential_new = 1;
- elseif potential_new < 0 then
- potential_new = 0;
- end;
- self:changeTransparency( potential_new );
- end;
- self.State.transparency_focused = false;
- end );
- -- Capture focus of the input when clicked
- -- (so we can detect when it is focused-on)
- Container.ReflectanceOption.ReflectanceInput.TextButton.MouseButton1Down:connect( function ()
- self.State.reflectance_focused = true;
- Container.ReflectanceOption.ReflectanceInput.TextBox:CaptureFocus();
- end );
- -- Change the reflectance when the value of the textbox is updated
- Container.ReflectanceOption.ReflectanceInput.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.ReflectanceOption.ReflectanceInput.TextBox.Text );
- if potential_new then
- if potential_new > 1 then
- potential_new = 1;
- elseif potential_new < 0 then
- potential_new = 0;
- end;
- self:changeReflectance( potential_new );
- end;
- self.State.reflectance_focused = false;
- end );
- self.GUI = Container;
- end;
- -- Reveal the GUI
- self.GUI.Visible = true;
- end;
- Tools.Material.hideGUI = function ( self )
- -- Hide the GUI if it exists already
- if self.GUI then
- self.GUI.Visible = false;
- end;
- end;
- Tools.Material.Loaded = true;
- end))
- LocalScript7.Disabled = true
- LocalScript8.Name = "BTAnchorTool"
- LocalScript8.Parent = LocalScript1
- table.insert(cors,sandbox(LocalScript8,function()
- -- Load the main tool's core environment when it's ready
- repeat wait() until (
- _G.BTCoreEnv and
- _G.BTCoreEnv[script.Parent.Parent] and
- _G.BTCoreEnv[script.Parent.Parent].CoreReady
- );
- setfenv( 1, _G.BTCoreEnv[script.Parent.Parent] );
- ------------------------------------------
- -- Anchor tool
- ------------------------------------------
- -- Create the tool
- Tools.Anchor = {};
- -- Create structures to hold data that the tool needs
- Tools.Anchor.Connections = {};
- Tools.Anchor.State = {
- ["anchored"] = nil;
- };
- Tools.Anchor.Listeners = {};
- -- Define the color of the tool
- Tools.Anchor.Color = BrickColor.new( "Really black" );
- -- Start adding functionality to the tool
- Tools.Anchor.Listeners.Equipped = function ()
- local self = Tools.Anchor;
- -- Change the color of selection boxes temporarily
- self.State.PreviousSelectionBoxColor = SelectionBoxColor;
- SelectionBoxColor = self.Color;
- updateSelectionBoxColor();
- -- Reveal the GUI
- self:showGUI();
- -- Update the GUI regularly
- coroutine.wrap( function ()
- updater_on = true;
- -- Provide a function to stop the loop
- self.Updater = function ()
- updater_on = false;
- end;
- while wait( 0.1 ) and updater_on do
- -- Make sure the tool's equipped
- if CurrentTool == self then
- -- Update the anchor status of every item in the selection
- local anchor_status = nil;
- for item_index, Item in pairs( Selection.Items ) do
- -- Set the first values for the first item
- if item_index == 1 then
- anchor_status = Item.Anchored;
- -- Otherwise, compare them and set them to `nil` if they're not identical
- else
- if anchor_status ~= Item.Anchored then
- anchor_status = nil;
- end;
- end;
- end;
- self.State.anchored = anchor_status;
- -- Update the GUI if it's visible
- if self.GUI and self.GUI.Visible then
- self:updateGUI();
- end;
- end;
- end;
- end )();
- -- Listen for the Enter button to be pressed to toggle the anchor
- self.Connections.EnterButtonListener = Mouse.KeyDown:connect( function ( key )
- local key = key:lower();
- local key_code = key:byte();
- -- If the Enter button is pressed
- if key_code == 13 then
- if self.State.anchored == true then
- self:unanchor();
- elseif self.State.anchored == false then
- self:anchor();
- elseif self.State.anchored == nil then
- self:anchor();
- end;
- end;
- end );
- end;
- Tools.Anchor.startHistoryRecord = function ( self )
- if self.State.HistoryRecord then
- self.State.HistoryRecord = nil;
- end;
- -- Create a history record
- self.State.HistoryRecord = {
- targets = _cloneTable( Selection.Items );
- initial_positions = {};
- terminal_positions = {};
- initial_anchors = {};
- terminal_anchors = {};
- unapply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target.RotVelocity = Vector3.new( 0, 0, 0 );
- Target.Velocity = Vector3.new( 0, 0, 0 );
- Target.CFrame = self.initial_positions[Target];
- Target.Anchored = self.initial_anchors[Target];
- Target:MakeJoints();
- Selection:add( Target );
- end;
- end;
- end;
- apply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target.RotVelocity = Vector3.new( 0, 0, 0 );
- Target.Velocity = Vector3.new( 0, 0, 0 );
- Target.CFrame = self.terminal_positions[Target];
- Target.Anchored = self.terminal_anchors[Target];
- Target:MakeJoints();
- Selection:add( Target );
- end;
- end;
- end;
- };
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.initial_anchors[Item] = Item.Anchored;
- self.State.HistoryRecord.initial_positions[Item] = Item.CFrame;
- end;
- end;
- end;
- Tools.Anchor.finishHistoryRecord = function ( self )
- if not self.State.HistoryRecord then
- return;
- end;
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.terminal_anchors[Item] = Item.Anchored;
- self.State.HistoryRecord.terminal_positions[Item] = Item.CFrame;
- end;
- end;
- History:add( self.State.HistoryRecord );
- self.State.HistoryRecord = nil;
- end;
- Tools.Anchor.anchor = function ( self )
- self:startHistoryRecord();
- -- Anchor all the items in the selection
- for _, Item in pairs( Selection.Items ) do
- Item.Anchored = true;
- Item:MakeJoints();
- end;
- self:finishHistoryRecord();
- end;
- Tools.Anchor.unanchor = function ( self )
- self:startHistoryRecord();
- -- Unanchor all the items in the selection
- for _, Item in pairs( Selection.Items ) do
- Item.Anchored = false;
- Item.Velocity = Vector3.new( 0, 0, 0 );
- Item.RotVelocity = Vector3.new( 0, 0, 0 );
- Item:MakeJoints();
- end;
- self:finishHistoryRecord();
- end;
- Tools.Anchor.showGUI = function ( self )
- -- Initialize the GUI if it's not ready yet
- if not self.GUI then
- local Container = Tool.Interfaces:WaitForChild( "BTAnchorToolGUI" ):Clone();
- Container.Parent = UI;
- -- Change the anchor status when the button is clicked
- Container.Status.Anchored.Button.MouseButton1Down:connect( function ()
- self:anchor();
- end );
- Container.Status.Unanchored.Button.MouseButton1Down:connect( function ()
- self:unanchor();
- end );
- self.GUI = Container;
- end;
- -- Reveal the GUI
- self.GUI.Visible = true;
- end;
- Tools.Anchor.updateGUI = function ( self )
- -- Make sure the GUI exists
- if not self.GUI then
- return;
- end;
- local GUI = self.GUI;
- if self.State.anchored == nil then
- GUI.Status.Anchored.Background.Image = light_slanted_rectangle;
- GUI.Status.Anchored.SelectedIndicator.BackgroundTransparency = 1;
- GUI.Status.Unanchored.Background.Image = light_slanted_rectangle;
- GUI.Status.Unanchored.SelectedIndicator.BackgroundTransparency = 1;
- elseif self.State.anchored == true then
- GUI.Status.Anchored.Background.Image = dark_slanted_rectangle;
- GUI.Status.Anchored.SelectedIndicator.BackgroundTransparency = 0;
- GUI.Status.Unanchored.Background.Image = light_slanted_rectangle;
- GUI.Status.Unanchored.SelectedIndicator.BackgroundTransparency = 1;
- elseif self.State.anchored == false then
- GUI.Status.Anchored.Background.Image = light_slanted_rectangle;
- GUI.Status.Anchored.SelectedIndicator.BackgroundTransparency = 1;
- GUI.Status.Unanchored.Background.Image = dark_slanted_rectangle;
- GUI.Status.Unanchored.SelectedIndicator.BackgroundTransparency = 0;
- end;
- end;
- Tools.Anchor.hideGUI = function ( self )
- -- Hide the GUI if it exists
- if self.GUI then
- self.GUI.Visible = false;
- end;
- end;
- Tools.Anchor.Listeners.Unequipped = function ()
- local self = Tools.Anchor;
- -- Stop the update loop
- if self.Updater then
- self.Updater();
- self.Updater = nil;
- end;
- -- Hide the GUI
- self:hideGUI();
- -- Clear out any temporary connections
- for connection_index, Connection in pairs( self.Connections ) do
- Connection:disconnect();
- self.Connections[connection_index] = nil;
- end;
- -- Restore the original color of the selection boxes
- SelectionBoxColor = self.State.PreviousSelectionBoxColor;
- updateSelectionBoxColor();
- end;
- Tools.Anchor.Loaded = true;
- end))
- LocalScript8.Disabled = true
- LocalScript9.Name = "BTCollisionTool"
- LocalScript9.Parent = LocalScript1
- table.insert(cors,sandbox(LocalScript9,function()
- -- Load the main tool's core environment when it's ready
- repeat wait() until (
- _G.BTCoreEnv and
- _G.BTCoreEnv[script.Parent.Parent] and
- _G.BTCoreEnv[script.Parent.Parent].CoreReady
- );
- setfenv( 1, _G.BTCoreEnv[script.Parent.Parent] );
- ------------------------------------------
- -- Collision tool
- ------------------------------------------
- -- Create the tool
- Tools.Collision = {};
- -- Create structures to hold data that the tool needs
- Tools.Collision.Connections = {};
- Tools.Collision.State = {
- ["colliding"] = nil;
- };
- Tools.Collision.Listeners = {};
- -- Define the color of the tool
- Tools.Collision.Color = BrickColor.new( "Really black" );
- -- Start adding functionality to the tool
- Tools.Collision.Listeners.Equipped = function ()
- local self = Tools.Collision;
- -- Change the color of selection boxes temporarily
- self.State.PreviousSelectionBoxColor = SelectionBoxColor;
- SelectionBoxColor = self.Color;
- updateSelectionBoxColor();
- -- Reveal the GUI
- self:showGUI();
- -- Update the GUI regularly
- coroutine.wrap( function ()
- updater_on = true;
- -- Provide a function to stop the loop
- self.Updater = function ()
- updater_on = false;
- end;
- while wait( 0.1 ) and updater_on do
- -- Make sure the tool's equipped
- if CurrentTool == self then
- -- Update the collision status of every item in the selection
- local colliding = nil;
- for item_index, Item in pairs( Selection.Items ) do
- -- Set the first values for the first item
- if item_index == 1 then
- colliding = Item.CanCollide;
- -- Otherwise, compare them and set them to `nil` if they're not identical
- else
- if colliding ~= Item.CanCollide then
- colliding = nil;
- end;
- end;
- end;
- self.State.colliding = colliding;
- -- Update the GUI if it's visible
- if self.GUI and self.GUI.Visible then
- self:updateGUI();
- end;
- end;
- end;
- end )();
- -- Listen for the Enter button to be pressed to toggle collision
- self.Connections.EnterButtonListener = Mouse.KeyDown:connect( function ( key )
- local key = key:lower();
- local key_code = key:byte();
- -- If the Enter button is pressed
- if key_code == 13 then
- if self.State.colliding == true then
- self:disable();
- elseif self.State.colliding == false then
- self:enable();
- elseif self.State.colliding == nil then
- self:enable();
- end;
- end;
- end );
- end;
- Tools.Collision.startHistoryRecord = function ( self )
- if self.State.HistoryRecord then
- self.State.HistoryRecord = nil;
- end;
- -- Create a history record
- self.State.HistoryRecord = {
- targets = _cloneTable( Selection.Items );
- initial_collide = {};
- terminal_collide = {};
- initial_cframe = {};
- terminal_cframe = {};
- unapply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target.CanCollide = self.initial_collide[Target];
- Target.CFrame = self.initial_cframe[Target];
- Target:MakeJoints();
- Selection:add( Target );
- end;
- end;
- end;
- apply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Target.CanCollide = self.terminal_collide[Target];
- Target.CFrame = self.terminal_cframe[Target];
- Target:MakeJoints();
- Selection:add( Target );
- end;
- end;
- end;
- };
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.initial_collide[Item] = Item.CanCollide;
- self.State.HistoryRecord.initial_cframe[Item] = Item.CFrame;
- end;
- end;
- end;
- Tools.Collision.finishHistoryRecord = function ( self )
- if not self.State.HistoryRecord then
- return;
- end;
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.terminal_collide[Item] = Item.CanCollide;
- self.State.HistoryRecord.terminal_cframe[Item] = Item.CFrame;
- end;
- end;
- History:add( self.State.HistoryRecord );
- self.State.HistoryRecord = nil;
- end;
- Tools.Collision.enable = function ( self )
- self:startHistoryRecord();
- -- Enable collision for all the items in the selection
- for _, Item in pairs( Selection.Items ) do
- Item.CanCollide = true;
- Item:MakeJoints();
- end;
- self:finishHistoryRecord();
- end;
- Tools.Collision.disable = function ( self )
- self:startHistoryRecord();
- -- Disable collision for all the items in the selection
- for _, Item in pairs( Selection.Items ) do
- Item.CanCollide = false;
- Item:MakeJoints();
- end;
- self:finishHistoryRecord();
- end;
- Tools.Collision.showGUI = function ( self )
- -- Initialize the GUI if it's not ready yet
- if not self.GUI then
- local Container = Tool.Interfaces:WaitForChild( "BTCollisionToolGUI" ):Clone();
- Container.Parent = UI;
- Container.Status.On.Button.MouseButton1Down:connect( function ()
- self:enable();
- end );
- Container.Status.Off.Button.MouseButton1Down:connect( function ()
- self:disable();
- end );
- self.GUI = Container;
- end;
- -- Reveal the GUI
- self.GUI.Visible = true;
- end;
- Tools.Collision.updateGUI = function ( self )
- -- Make sure the GUI exists
- if not self.GUI then
- return;
- end;
- local GUI = self.GUI;
- if self.State.colliding == nil then
- GUI.Status.On.Background.Image = light_slanted_rectangle;
- GUI.Status.On.SelectedIndicator.BackgroundTransparency = 1;
- GUI.Status.Off.Background.Image = light_slanted_rectangle;
- GUI.Status.Off.SelectedIndicator.BackgroundTransparency = 1;
- elseif self.State.colliding == true then
- GUI.Status.On.Background.Image = dark_slanted_rectangle;
- GUI.Status.On.SelectedIndicator.BackgroundTransparency = 0;
- GUI.Status.Off.Background.Image = light_slanted_rectangle;
- GUI.Status.Off.SelectedIndicator.BackgroundTransparency = 1;
- elseif self.State.colliding == false then
- GUI.Status.On.Background.Image = light_slanted_rectangle;
- GUI.Status.On.SelectedIndicator.BackgroundTransparency = 1;
- GUI.Status.Off.Background.Image = dark_slanted_rectangle;
- GUI.Status.Off.SelectedIndicator.BackgroundTransparency = 0;
- end;
- end;
- Tools.Collision.hideGUI = function ( self )
- -- Hide the GUI if it exists
- if self.GUI then
- self.GUI.Visible = false;
- end;
- end;
- Tools.Collision.Listeners.Unequipped = function ()
- local self = Tools.Collision;
- -- Stop the update loop
- if self.Updater then
- self.Updater();
- self.Updater = nil;
- end;
- -- Hide the GUI
- self:hideGUI();
- -- Clear out any temporary connections
- for connection_index, Connection in pairs( self.Connections ) do
- Connection:disconnect();
- self.Connections[connection_index] = nil;
- end;
- -- Restore the original color of the selection boxes
- SelectionBoxColor = self.State.PreviousSelectionBoxColor;
- updateSelectionBoxColor();
- end;
- Tools.Collision.Loaded = true;
- end))
- LocalScript9.Disabled = true
- LocalScript10.Name = "BTNewPartTool"
- LocalScript10.Parent = LocalScript1
- table.insert(cors,sandbox(LocalScript10,function()
- -- Load the main tool's core environment when it's ready
- repeat wait() until (
- _G.BTCoreEnv and
- _G.BTCoreEnv[script.Parent.Parent] and
- _G.BTCoreEnv[script.Parent.Parent].CoreReady
- );
- setfenv( 1, _G.BTCoreEnv[script.Parent.Parent] );
- ------------------------------------------
- -- New part tool
- ------------------------------------------
- -- Create the tool
- Tools.NewPart = {};
- -- Define the tool's color
- Tools.NewPart.Color = BrickColor.new( "Really black" );
- -- Keep a container for temporary connections
- Tools.NewPart.Connections = {};
- -- Keep a container for state data
- Tools.NewPart.State = {
- ["Part"] = nil;
- };
- -- Maintain a container for options
- Tools.NewPart.Options = {
- ["type"] = "normal"
- };
- -- Keep a container for platform event connections
- Tools.NewPart.Listeners = {};
- -- Start adding functionality to the tool
- Tools.NewPart.Listeners.Equipped = function ()
- local self = Tools.NewPart;
- -- Change the color of selection boxes temporarily
- self.State.PreviousSelectionBoxColor = SelectionBoxColor;
- SelectionBoxColor = self.Color;
- updateSelectionBoxColor();
- -- Reveal the GUI
- self:showGUI();
- -- Restore the type option
- self:changeType( self.Options.type );
- end;
- Tools.NewPart.Listeners.Unequipped = function ()
- local self = Tools.NewPart;
- -- Hide the GUI
- self:hideGUI();
- -- Disconnect temporary connections
- for connection_index, Connection in pairs( self.Connections ) do
- Connection:disconnect();
- self.Connections[connection_index] = nil;
- end;
- -- Restore the original color of selection boxes
- SelectionBoxColor = self.State.PreviousSelectionBoxColor;
- updateSelectionBoxColor();
- end;
- Tools.NewPart.Listeners.Button1Down = function ()
- local self = Tools.NewPart;
- local NewPart;
- -- Create the new part of type `self.Options.type`
- if self.Options.type == "normal" then
- NewPart = Instance.new( "Part", Services.Workspace );
- NewPart.FormFactor = "Custom";
- NewPart.Size = Vector3.new( 4, 1, 2 );
- elseif self.Options.type == "truss" then
- NewPart = Instance.new( "TrussPart", Services.Workspace );
- elseif self.Options.type == "wedge" then
- NewPart = Instance.new( "WedgePart", Services.Workspace );
- elseif self.Options.type == "corner" then
- NewPart = Instance.new( "CornerWedgePart", Services.Workspace );
- elseif self.Options.type == "cylinder" then
- NewPart = Instance.new( "Part", Services.Workspace );
- NewPart.Shape = "Cylinder";
- elseif self.Options.type == "ball" then
- NewPart = Instance.new( "Part", Services.Workspace );
- NewPart.Shape = "Ball";
- elseif self.Options.type == "seat" then
- NewPart = Instance.new( "Seat", Services.Workspace );
- elseif self.Options.type == "vehicle seat" then
- NewPart = Instance.new( "VehicleSeat", Services.Workspace );
- elseif self.Options.type == "spawn" then
- NewPart = Instance.new( "SpawnLocation", Services.Workspace );
- end;
- NewPart.Anchored = true;
- -- Select the new part
- Selection:clear();
- Selection:add( NewPart );
- local HistoryRecord = {
- target = NewPart;
- apply = function ( self )
- Selection:clear();
- if self.target then
- self.target.Parent = Services.Workspace;
- Selection:add( self.target );
- end;
- end;
- unapply = function ( self )
- if self.target then
- self.target.Parent = nil;
- end;
- end;
- };
- History:add( HistoryRecord );
- -- Switch to the move tool and simulate clicking so
- -- that the user could easily position their new part
- equipTool( Tools.Move );
- Tools.Move.ManualTarget = NewPart;
- NewPart.CFrame = CFrame.new( Mouse.Hit.p );
- Tools.Move.Listeners.Button1Down();
- Tools.Move.Listeners.Move();
- end;
- Tools.NewPart.changeType = function ( self, new_type )
- self.Options.type = new_type;
- self.TypeDropdown:selectOption( new_type:upper() );
- if self.TypeDropdown.open then
- self.TypeDropdown:toggle();
- end;
- end;
- Tools.NewPart.showGUI = function ( self )
- -- Initialize the GUI if it's not ready yet
- if not self.GUI then
- local Container = Tool.Interfaces:WaitForChild( "BTNewPartToolGUI" ):Clone();
- Container.Parent = UI;
- local TypeDropdown = createDropdown();
- self.TypeDropdown = TypeDropdown;
- TypeDropdown.Frame.Parent = Container.TypeOption;
- TypeDropdown.Frame.Position = UDim2.new( 0, 70, 0, 0 );
- TypeDropdown.Frame.Size = UDim2.new( 0, 140, 0, 25 );
- TypeDropdown:addOption( "NORMAL" ).MouseButton1Up:connect( function ()
- self:changeType( "normal" );
- end );
- TypeDropdown:addOption( "TRUSS" ).MouseButton1Up:connect( function ()
- self:changeType( "truss" );
- end );
- TypeDropdown:addOption( "WEDGE" ).MouseButton1Up:connect( function ()
- self:changeType( "wedge" );
- end );
- TypeDropdown:addOption( "CORNER" ).MouseButton1Up:connect( function ()
- self:changeType( "corner" );
- end );
- TypeDropdown:addOption( "CYLINDER" ).MouseButton1Up:connect( function ()
- self:changeType( "cylinder" );
- end );
- TypeDropdown:addOption( "BALL" ).MouseButton1Up:connect( function ()
- self:changeType( "ball" );
- end );
- TypeDropdown:addOption( "SEAT" ).MouseButton1Up:connect( function ()
- self:changeType( "seat" );
- end );
- TypeDropdown:addOption( "VEHICLE SEAT" ).MouseButton1Up:connect( function ()
- self:changeType( "vehicle seat" );
- end );
- TypeDropdown:addOption( "SPAWN" ).MouseButton1Up:connect( function ()
- self:changeType( "spawn" );
- end );
- self.GUI = Container;
- end;
- -- Reveal the GUI
- self.GUI.Visible = true;
- end;
- Tools.NewPart.hideGUI = function ( self )
- -- Hide the GUI if it exists already
- if self.GUI then
- self.GUI.Visible = false;
- end;
- end;
- Tools.NewPart.Loaded = true;
- end))
- LocalScript10.Disabled = true
- LocalScript11.Name = "BTMeshTool"
- LocalScript11.Parent = LocalScript1
- table.insert(cors,sandbox(LocalScript11,function()
- -- Load the main tool's core environment when it's ready
- repeat wait() until (
- _G.BTCoreEnv and
- _G.BTCoreEnv[script.Parent.Parent] and
- _G.BTCoreEnv[script.Parent.Parent].CoreReady
- );
- setfenv( 1, _G.BTCoreEnv[script.Parent.Parent] );
- ------------------------------------------
- -- Mesh tool
- ------------------------------------------
- -- Create the tool
- Tools.Mesh = {};
- -- Define the tool's color
- Tools.Mesh.Color = BrickColor.new( "Bright violet" );
- -- Keep a container for state data
- Tools.Mesh.State = {};
- -- Keep a container for temporary connections
- Tools.Mesh.Connections = {};
- -- Keep a container for platform event connections
- Tools.Mesh.Listeners = {};
- -- Start adding functionality to the tool
- Tools.Mesh.Listeners.Equipped = function ()
- local self = Tools.Mesh;
- -- Change the color of selection boxes temporarily
- self.State.PreviousSelectionBoxColor = SelectionBoxColor;
- SelectionBoxColor = self.Color;
- updateSelectionBoxColor();
- -- Reveal the GUI
- self:showGUI();
- -- Update the GUI regularly
- coroutine.wrap( function ()
- updater_on = true;
- -- Provide a function to stop the loop
- self.stopGUIUpdater = function ( self )
- updater_on = false;
- end;
- while wait( 0.1 ) and updater_on do
- -- Make sure the tool's equipped
- if CurrentTool == self then
- -- Update the GUI if it's visible
- if self.GUI and self.GUI.Visible then
- self:updateGUI();
- end;
- end;
- end;
- end )();
- end;
- Tools.Mesh.Listeners.Unequipped = function ()
- local self = Tools.Mesh;
- -- Stop the GUI updater
- self:stopGUIUpdater();
- -- Hide the GUI
- self:hideGUI();
- -- Disconnect temporary connections
- for connection_index, Connection in pairs( self.Connections ) do
- Connection:disconnect();
- self.Connections[connection_index] = nil;
- end;
- -- Restore the original color of selection boxes
- SelectionBoxColor = self.State.PreviousSelectionBoxColor;
- updateSelectionBoxColor();
- end;
- Tools.Mesh.TypeDropdownLabels = {
- [Enum.MeshType.Brick] = "BLOCK";
- [Enum.MeshType.Cylinder] = "CYLINDER";
- [Enum.MeshType.FileMesh] = "FILE";
- [Enum.MeshType.Head] = "HEAD";
- [Enum.MeshType.Sphere] = "SPHERE";
- [Enum.MeshType.Torso] = "TRAPEZOID";
- [Enum.MeshType.Wedge] = "WEDGE";
- };
- Tools.Mesh.changeType = function ( self, new_type )
- -- Apply type `new_type` to all the meshes in items from the selection
- local meshes = {};
- for _, Item in pairs( Selection.Items ) do
- local Mesh = _getChildOfClass( Item, "SpecialMesh" );
- if Mesh then
- table.insert( meshes, Mesh );
- end;
- end;
- self:startHistoryRecord( meshes );
- for _, Mesh in pairs( meshes ) do
- Mesh.MeshType = new_type;
- end;
- self:finishHistoryRecord();
- if self.TypeDropdown.open then
- self.TypeDropdown:toggle();
- end;
- self:finishHistoryRecord();
- end;
- Tools.Mesh.updateGUI = function ( self )
- -- Make sure the GUI exists
- if not self.GUI then
- return;
- end;
- local GUI = self.GUI;
- if #Selection.Items > 0 then
- local meshes = {};
- for _, Item in pairs( Selection.Items ) do
- local Mesh = _getChildOfClass( Item, "SpecialMesh" );
- if Mesh then
- table.insert( meshes, Mesh );
- end;
- end;
- local show_add, show_remove, show_mesh_id;
- local mesh_type, mesh_scale_x, mesh_scale_y, mesh_scale_z, mesh_id, mesh_texture, mesh_tint_r, mesh_tint_g, mesh_tint_b;
- -- If every item has a mesh
- if #meshes == #Selection.Items then
- show_add = false;
- show_remove = true;
- -- If no item has a mesh
- elseif #meshes == 0 then
- show_add = true;
- show_remove = false;
- -- If some items have a mesh
- else
- show_add = true;
- show_remove = true;
- end;
- -- If there are meshes
- if #meshes > 0 then
- show_type = true;
- for mesh_index, Mesh in pairs( meshes ) do
- -- Set the start values for later comparison
- if mesh_index == 1 then
- mesh_type = Mesh.MeshType;
- mesh_scale_x, mesh_scale_y, mesh_scale_z = Mesh.Scale.x, Mesh.Scale.y, Mesh.Scale.z;
- mesh_id = Mesh.MeshId:lower();
- mesh_texture = Mesh.TextureId:lower();
- mesh_tint_r, mesh_tint_g, mesh_tint_b = Mesh.VertexColor.x, Mesh.VertexColor.y, Mesh.VertexColor.z;
- -- Set the values to `nil` if they vary across the selection
- else
- if mesh_type ~= Mesh.MeshType then
- mesh_type = nil;
- end;
- if mesh_scale_x ~= Mesh.Scale.x then
- mesh_scale_x = nil;
- end;
- if mesh_scale_y ~= Mesh.Scale.y then
- mesh_scale_y = nil;
- end;
- if mesh_scale_z ~= Mesh.Scale.z then
- mesh_scale_z = nil;
- end;
- if mesh_id ~= Mesh.MeshId:lower() then
- mesh_id = nil;
- end;
- if mesh_texture ~= Mesh.TextureId:lower() then
- mesh_texture = nil;
- end;
- if mesh_tint_r ~= Mesh.VertexColor.x then
- mesh_tint_r = nil;
- end;
- if mesh_tint_g ~= Mesh.VertexColor.y then
- mesh_tint_g = nil;
- end;
- if mesh_tint_b ~= Mesh.VertexColor.z then
- mesh_tint_b = nil;
- end;
- end;
- -- If there's a FileMesh around here, note that
- if Mesh.MeshType == Enum.MeshType.FileMesh then
- show_mesh_id = true;
- end;
- end;
- self.State.mesh_tint = ( mesh_tint_r and mesh_tint_g and mesh_tint_b ) and Color3.new( mesh_tint_r, mesh_tint_g, mesh_tint_b ) or nil;
- if show_mesh_id and show_add and show_remove then
- self.GUI.AddButton.Visible = true;
- self.GUI.RemoveButton.Visible = true;
- self.GUI.MeshIDOption.Visible = true;
- self.GUI.TextureIDOption.Visible = true;
- self.GUI.ScaleOption.Visible = true;
- self.GUI.TintOption.Visible = true;
- self.GUI.TypeOption.Visible = true;
- self.GUI.TypeOption.Position = UDim2.new( 0, 14, 0, 65 );
- self.GUI.ScaleOption.Position = UDim2.new( 0, 0, 0, 100 );
- self.GUI.MeshIDOption.Position = UDim2.new( 0, 14, 0, 135 );
- self.GUI.TextureIDOption.Position = UDim2.new( 0, 14, 0, 165 );
- self.GUI.TintOption.Position = UDim2.new( 0, 0, 0, 200 );
- self.GUI.Size = UDim2.new( 0, 200, 0, 265 );
- elseif show_mesh_id and not show_add and show_remove then
- self.GUI.AddButton.Visible = false;
- self.GUI.RemoveButton.Visible = true;
- self.GUI.MeshIDOption.Visible = true;
- self.GUI.TextureIDOption.Visible = true;
- self.GUI.ScaleOption.Visible = true;
- self.GUI.TintOption.Visible = true;
- self.GUI.TypeOption.Visible = true;
- self.GUI.TypeOption.Position = UDim2.new( 0, 14, 0, 30 );
- self.GUI.ScaleOption.Position = UDim2.new( 0, 0, 0, 65 );
- self.GUI.MeshIDOption.Position = UDim2.new( 0, 14, 0, 100 );
- self.GUI.TextureIDOption.Position = UDim2.new( 0, 14, 0, 130 );
- self.GUI.TintOption.Position = UDim2.new( 0, 0, 0, 165 );
- self.GUI.Size = UDim2.new( 0, 200, 0, 230 );
- elseif not show_mesh_id and show_add and show_remove then
- self.GUI.AddButton.Visible = true;
- self.GUI.RemoveButton.Visible = true;
- self.GUI.MeshIDOption.Visible = false;
- self.GUI.TextureIDOption.Visible = false;
- self.GUI.ScaleOption.Visible = true;
- self.GUI.TintOption.Visible = false;
- self.GUI.TypeOption.Visible = true;
- self.GUI.TypeOption.Position = UDim2.new( 0, 14, 0, 65 );
- self.GUI.ScaleOption.Position = UDim2.new( 0, 0, 0, 100 );
- self.GUI.Size = UDim2.new( 0, 200, 0, 165 );
- elseif not show_mesh_id and not show_add and show_remove then
- self.GUI.AddButton.Visible = false;
- self.GUI.RemoveButton.Visible = true;
- self.GUI.MeshIDOption.Visible = false;
- self.GUI.TextureIDOption.Visible = false;
- self.GUI.ScaleOption.Visible = true;
- self.GUI.TintOption.Visible = false;
- self.GUI.TypeOption.Visible = true;
- self.GUI.TypeOption.Position = UDim2.new( 0, 14, 0, 30 );
- self.GUI.ScaleOption.Position = UDim2.new( 0, 0, 0, 65 );
- self.GUI.Size = UDim2.new( 0, 200, 0, 130 );
- end;
- -- Update the values shown on the GUI
- if not self.State.mesh_id_focused then
- self.GUI.MeshIDOption.TextBox.Text = mesh_id and ( mesh_id:match( "%?id=([0-9]+)" ) or "" ) or "*";
- end;
- if not self.State.texture_id_focused then
- self.GUI.TextureIDOption.TextBox.Text = mesh_texture and ( mesh_texture:match( "%?id=([0-9]+)" ) or "" ) or "*";
- end;
- self.TypeDropdown:selectOption( mesh_type and self.TypeDropdownLabels[mesh_type] or "*" );
- if not self.State.scale_x_focused then
- self.GUI.ScaleOption.XInput.TextBox.Text = mesh_scale_x and _round( mesh_scale_x, 2 ) or "*";
- end;
- if not self.State.scale_y_focused then
- self.GUI.ScaleOption.YInput.TextBox.Text = mesh_scale_y and _round( mesh_scale_y, 2 ) or "*";
- end;
- if not self.State.scale_z_focused then
- self.GUI.ScaleOption.ZInput.TextBox.Text = mesh_scale_z and _round( mesh_scale_z, 2 ) or "*";
- end;
- if not self.State.tint_r_focused then
- self.GUI.TintOption.RInput.TextBox.Text = mesh_tint_r and _round( mesh_tint_r * 255, 0 ) or "*";
- end;
- if not self.State.tint_g_focused then
- self.GUI.TintOption.GInput.TextBox.Text = mesh_tint_g and _round( mesh_tint_g * 255, 0 ) or "*";
- end;
- if not self.State.tint_b_focused then
- self.GUI.TintOption.BInput.TextBox.Text = mesh_tint_b and _round( mesh_tint_b * 255, 0 ) or "*";
- end;
- -- If there are no meshes
- else
- self.GUI.AddButton.Visible = true;
- self.GUI.RemoveButton.Visible = false;
- self.GUI.MeshIDOption.Visible = false;
- self.GUI.TextureIDOption.Visible = false;
- self.GUI.ScaleOption.Visible = false;
- self.GUI.TintOption.Visible = false;
- self.GUI.TypeOption.Visible = false;
- self.GUI.Size = UDim2.new( 0, 200, 0, 62 );
- end;
- self.GUI.SelectNote.Visible = false;
- -- Show a note that says to select something
- else
- self.GUI.AddButton.Visible = false;
- self.GUI.RemoveButton.Visible = false;
- self.GUI.MeshIDOption.Visible = false;
- self.GUI.TextureIDOption.Visible = false;
- self.GUI.ScaleOption.Visible = false;
- self.GUI.TintOption.Visible = false;
- self.GUI.TypeOption.Visible = false;
- self.GUI.SelectNote.Visible = true;
- self.GUI.Size = UDim2.new( 0, 200, 0, 55 );
- end;
- end;
- Tools.Mesh.showGUI = function ( self )
- -- Initialize the GUI if it's not ready yet
- if not self.GUI then
- local Container = Tool.Interfaces:WaitForChild( "BTMeshToolGUI" ):Clone();
- Container.Parent = UI;
- -- Add functionality to the add/remove buttons
- Container.AddButton.Button.MouseButton1Up:connect( function ()
- self:addMesh();
- end );
- Container.RemoveButton.Button.MouseButton1Up:connect( function ()
- self:removeMesh();
- end );
- -- Add the type dropdown
- local TypeDropdown = createDropdown();
- self.TypeDropdown = TypeDropdown;
- TypeDropdown.Frame.Parent = Container.TypeOption;
- TypeDropdown.Frame.Position = UDim2.new( 0, 40, 0, 0 );
- TypeDropdown.Frame.Size = UDim2.new( 1, -40, 0, 25 );
- TypeDropdown:addOption( "BLOCK" ).MouseButton1Up:connect( function ()
- self:changeType( Enum.MeshType.Brick );
- end );
- TypeDropdown:addOption( "CYLINDER" ).MouseButton1Up:connect( function ()
- self:changeType( Enum.MeshType.Cylinder );
- end );
- TypeDropdown:addOption( "FILE" ).MouseButton1Up:connect( function ()
- self:changeType( Enum.MeshType.FileMesh );
- end );
- TypeDropdown:addOption( "HEAD" ).MouseButton1Up:connect( function ()
- self:changeType( Enum.MeshType.Head );
- end );
- TypeDropdown:addOption( "SPHERE" ).MouseButton1Up:connect( function ()
- self:changeType( Enum.MeshType.Sphere );
- end );
- TypeDropdown:addOption( "TRAPEZOID" ).MouseButton1Up:connect( function ()
- self:changeType( Enum.MeshType.Torso );
- end );
- TypeDropdown:addOption( "WEDGE" ).MouseButton1Up:connect( function ()
- self:changeType( Enum.MeshType.Wedge );
- end );
- -- Add functionality to the scale inputs
- Container.ScaleOption.XInput.TextButton.MouseButton1Down:connect( function ()
- self.State.scale_x_focused = true;
- Container.ScaleOption.XInput.TextBox:CaptureFocus();
- end );
- Container.ScaleOption.XInput.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.ScaleOption.XInput.TextBox.Text );
- if potential_new then
- self:changeScale( 'x', potential_new );
- end;
- self.State.scale_x_focused = false;
- end );
- Container.ScaleOption.YInput.TextButton.MouseButton1Down:connect( function ()
- self.State.scale_y_focused = true;
- Container.ScaleOption.YInput.TextBox:CaptureFocus();
- end );
- Container.ScaleOption.YInput.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.ScaleOption.YInput.TextBox.Text );
- if potential_new then
- self:changeScale( 'y', potential_new );
- end;
- self.State.scale_y_focused = false;
- end );
- Container.ScaleOption.ZInput.TextButton.MouseButton1Down:connect( function ()
- self.State.scale_z_focused = true;
- Container.ScaleOption.ZInput.TextBox:CaptureFocus();
- end );
- Container.ScaleOption.ZInput.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.ScaleOption.ZInput.TextBox.Text );
- if potential_new then
- self:changeScale( 'z', potential_new );
- end;
- self.State.scale_z_focused = false;
- end );
- -- Add functionality to the mesh/texture ID inputs
- Container.MeshIDOption.TextButton.MouseButton1Down:connect( function ()
- self.State.mesh_id_focused = true;
- Container.MeshIDOption.TextBox:CaptureFocus();
- end );
- Container.MeshIDOption.TextBox.FocusLost:connect( function ( enter_pressed )
- local input = Container.MeshIDOption.TextBox.Text;
- local potential_new = tonumber( input ) or input:lower():match( "%?id=([0-9]+)" );
- if potential_new then
- self:changeMesh( potential_new );
- end;
- self.State.mesh_id_focused = false;
- end );
- Container.TextureIDOption.TextButton.MouseButton1Down:connect( function ()
- self.State.texture_id_focused = true;
- Container.TextureIDOption.TextBox:CaptureFocus();
- end );
- Container.TextureIDOption.TextBox.FocusLost:connect( function ( enter_pressed )
- local input = Container.TextureIDOption.TextBox.Text;
- local potential_new = tonumber( input ) or input:lower():match( "%?id=([0-9]+)" );
- if potential_new then
- self:changeTexture( potential_new );
- end;
- self.State.texture_id_focused = false;
- end );
- -- Add functionality to the tint inputs
- Container.TintOption.RInput.TextButton.MouseButton1Down:connect( function ()
- self.State.tint_r_focused = true;
- Container.TintOption.RInput.TextBox:CaptureFocus();
- end );
- Container.TintOption.RInput.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.TintOption.RInput.TextBox.Text );
- if potential_new then
- if potential_new > 255 then
- potential_new = 255;
- elseif potential_new < 0 then
- potential_new = 0;
- end;
- self:changeTint( 'r', potential_new / 255 );
- end;
- self.State.tint_r_focused = false;
- end );
- Container.TintOption.GInput.TextButton.MouseButton1Down:connect( function ()
- self.State.tint_g_focused = true;
- Container.TintOption.GInput.TextBox:CaptureFocus();
- end );
- Container.TintOption.GInput.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.TintOption.GInput.TextBox.Text );
- if potential_new then
- if potential_new > 255 then
- potential_new = 255;
- elseif potential_new < 0 then
- potential_new = 0;
- end;
- self:changeTint( 'g', potential_new / 255 );
- end;
- self.State.tint_g_focused = false;
- end );
- Container.TintOption.BInput.TextButton.MouseButton1Down:connect( function ()
- self.State.tint_b_focused = true;
- Container.TintOption.BInput.TextBox:CaptureFocus();
- end );
- Container.TintOption.BInput.TextBox.FocusLost:connect( function ( enter_pressed )
- local potential_new = tonumber( Container.TintOption.BInput.TextBox.Text );
- if potential_new then
- if potential_new > 255 then
- potential_new = 255;
- elseif potential_new < 0 then
- potential_new = 0;
- end;
- self:changeTint( 'b', potential_new / 255 );
- end;
- self.State.tint_b_focused = false;
- end );
- Container.TintOption.HSVPicker.MouseButton1Up:connect( function ()
- ColorPicker:start( function ( ... )
- local args = { ... };
- -- If a color was picked, change the spotlights' color
- -- to the selected color
- if #args == 3 then
- local meshes = {};
- for _, Item in pairs( Selection.Items ) do
- local Mesh = _getChildOfClass( Item, "SpecialMesh" );
- if Mesh then
- table.insert( meshes, Mesh );
- end;
- end;
- self:startHistoryRecord( meshes );
- for _, Mesh in pairs( meshes ) do
- Mesh.VertexColor = Vector3.new( _HSVToRGB( ... ) );
- end;
- self:finishHistoryRecord();
- end;
- end, self.State.mesh_tint );
- end );
- self.GUI = Container;
- end;
- -- Reveal the GUI
- self.GUI.Visible = true;
- end;
- Tools.Mesh.addMesh = function ( self )
- local HistoryRecord = {
- apply = function ( self )
- Selection:clear();
- for _, Mesh in pairs( self.meshes ) do
- Mesh.Parent = self.mesh_parents[Mesh];
- Selection:add( Mesh.Parent );
- end;
- end;
- unapply = function ( self )
- Selection:clear();
- for _, Mesh in pairs( self.meshes ) do
- Selection:add( Mesh.Parent );
- Mesh.Parent = nil;
- end;
- end;
- };
- -- Add meshes to all the items from the selection that
- -- don't already have one
- local meshes = {};
- local mesh_parents = {};
- for _, Item in pairs( Selection.Items ) do
- local Mesh = _getChildOfClass( Item, "SpecialMesh" );
- if not Mesh then
- local Mesh = RbxUtility.Create "SpecialMesh" {
- Parent = Item;
- MeshType = Enum.MeshType.Brick;
- };
- table.insert( meshes, Mesh );
- mesh_parents[Mesh] = Item;
- end;
- end;
- HistoryRecord.meshes = meshes;
- HistoryRecord.mesh_parents = mesh_parents;
- History:add( HistoryRecord );
- end;
- Tools.Mesh.removeMesh = function ( self )
- local HistoryRecord = {
- apply = function ( self )
- Selection:clear();
- for _, Mesh in pairs( self.meshes ) do
- Selection:add( Mesh.Parent );
- Mesh.Parent = nil;
- end;
- end;
- unapply = function ( self )
- Selection:clear();
- for _, Mesh in pairs( self.meshes ) do
- Mesh.Parent = self.mesh_parents[Mesh];
- Selection:add( Mesh.Parent );
- end;
- end;
- };
- local meshes = {};
- local mesh_parents = {};
- -- Remove meshes from all the selected items
- for _, Item in pairs( Selection.Items ) do
- local meshes_found = _getChildrenOfClass( Item, "SpecialMesh" );
- for _, Mesh in pairs( meshes_found ) do
- table.insert( meshes, Mesh );
- mesh_parents[Mesh] = Mesh.Parent;
- Mesh.Parent = nil;
- end;
- end;
- HistoryRecord.meshes = meshes;
- HistoryRecord.mesh_parents = mesh_parents;
- History:add( HistoryRecord );
- end;
- Tools.Mesh.startHistoryRecord = function ( self, meshes )
- if self.State.HistoryRecord then
- self.State.HistoryRecord = nil;
- end;
- -- Create a history record
- self.State.HistoryRecord = {
- targets = _cloneTable( meshes );
- initial_type = {};
- terminal_type = {};
- initial_mesh = {};
- terminal_mesh = {};
- initial_texture = {};
- terminal_texture = {};
- initial_scale = {};
- terminal_scale = {};
- initial_tint = {};
- terminal_tint = {};
- unapply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Selection:add( Target.Parent );
- Target.MeshType = self.initial_type[Target];
- Target.MeshId = self.initial_mesh[Target];
- Target.TextureId = self.initial_texture[Target];
- Target.Scale = self.initial_scale[Target];
- Target.VertexColor = self.initial_tint[Target];
- end;
- end;
- end;
- apply = function ( self )
- Selection:clear();
- for _, Target in pairs( self.targets ) do
- if Target then
- Selection:add( Target.Parent );
- Target.MeshType = self.terminal_type[Target];
- Target.MeshId = self.terminal_mesh[Target];
- Target.TextureId = self.terminal_texture[Target];
- Target.Scale = self.terminal_scale[Target];
- Target.VertexColor = self.terminal_tint[Target];
- end;
- end;
- end;
- };
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.initial_type[Item] = Item.MeshType;
- self.State.HistoryRecord.initial_mesh[Item] = Item.MeshId;
- self.State.HistoryRecord.initial_texture[Item] = Item.TextureId;
- self.State.HistoryRecord.initial_scale[Item] = Item.Scale;
- self.State.HistoryRecord.initial_tint[Item] = Item.VertexColor;
- end;
- end;
- end;
- Tools.Mesh.finishHistoryRecord = function ( self )
- if not self.State.HistoryRecord then
- return;
- end;
- for _, Item in pairs( self.State.HistoryRecord.targets ) do
- if Item then
- self.State.HistoryRecord.terminal_type[Item] = Item.MeshType;
- self.State.HistoryRecord.terminal_mesh[Item] = Item.MeshId;
- self.State.HistoryRecord.terminal_texture[Item] = Item.TextureId;
- self.State.HistoryRecord.terminal_scale[Item] = Item.Scale;
- self.State.HistoryRecord.terminal_tint[Item] = Item.VertexColor;
- end;
- end;
- History:add( self.State.HistoryRecord );
- self.State.HistoryRecord = nil;
- end;
- Tools.Mesh.changeMesh = function ( self, mesh_id )
- local meshes = {};
- for _, Item in pairs( Selection.Items ) do
- local Mesh = _getChildOfClass( Item, "SpecialMesh" );
- if Mesh then
- table.insert( meshes, Mesh );
- end;
- end;
- self:startHistoryRecord( meshes );
- for _, Mesh in pairs( meshes ) do
- Mesh.MeshId = "http://www.roblox.com/asset/?id=" .. mesh_id;
- end;
- self:finishHistoryRecord();
- end;
- Tools.Mesh.changeTexture = function ( self, texture_id )
- local meshes = {};
- for _, Item in pairs( Selection.Items ) do
- local Mesh = _getChildOfClass( Item, "SpecialMesh" );
- if Mesh then
- table.insert( meshes, Mesh );
- end;
- end;
- self:startHistoryRecord( meshes );
- for _, Mesh in pairs( meshes ) do
- Mesh.TextureId = "http://www.roblox.com/asset/?id=" .. texture_id;
- end;
- self:finishHistoryRecord();
- end;
- Tools.Mesh.changeScale = function ( self, component, new_value )
- local meshes = {};
- for _, Item in pairs( Selection.Items ) do
- local Mesh = _getChildOfClass( Item, "SpecialMesh" );
- if Mesh then
- table.insert( meshes, Mesh );
- end;
- end;
- self:startHistoryRecord( meshes );
- for _, Mesh in pairs( meshes ) do
- Mesh.Scale = Vector3.new(
- component == 'x' and new_value or Mesh.Scale.x,
- component == 'y' and new_value or Mesh.Scale.y,
- component == 'z' and new_value or Mesh.Scale.z
- );
- end;
- self:finishHistoryRecord();
- end;
- Tools.Mesh.changeTint = function ( self, component, new_value )
- local meshes = {};
- for _, Item in pairs( Selection.Items ) do
- local Mesh = _getChildOfClass( Item, "SpecialMesh" );
- if Mesh then
- table.insert( meshes, Mesh );
- end;
- end;
- self:startHistoryRecord( meshes );
- for _, Mesh in pairs( meshes ) do
- Mesh.VertexColor = Vector3.new(
- component == 'r' and new_value or Mesh.VertexColor.x,
- component == 'g' and new_value or Mesh.VertexColor.y,
- component == 'b' and new_value or Mesh.VertexColor.z
- );
- end;
- self:finishHistoryRecord();
- end;
- Tools.Mesh.hideGUI = function ( self )
- -- Hide the GUI if it exists already
- if self.GUI then
- self.GUI.Visible = false;
- end;
- end;
- Tools.Mesh.Loaded = true;
- end))
- LocalScript11.Disabled = true
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement