Nevzyn

Untitled

Mar 9th, 2026
18
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 68.57 KB | None | 0 0
  1. --[[
  2. ╔══════════════════════════════════════════════════════════════════════╗
  3. ║ Save Locate (NickZ) - V5.0 MEGA UPDATE ║
  4. ║ ║
  5. ║ • Arquitetura modular com sistemas desacoplados ║
  6. ║ • Teleporte robusto anti-bug / anti-animação ║
  7. ║ • Paginação: 5 páginas × 10 slots = 50 saves ║
  8. ║ • Persistência dupla (JSON + BAK) com fallback inteligente ║
  9. ║ • UI totalmente refatorada: mais limpa, leve e organizada ║
  10. ║ • Gestão de memória otimizada (sem leaks de conexão) ║
  11. ║ • Sistema de notificações integrado ║
  12. ║ • Feedback visual aprimorado em todos os elementos ║
  13. ╚══════════════════════════════════════════════════════════════════════╝
  14. ]]
  15.  
  16. -- ============================================================
  17. -- SEÇÃO 1 ► AGUARDAR CARREGAMENTO DO JOGO
  18. -- ============================================================
  19.  
  20. if not game:IsLoaded() then
  21. game.Loaded:Wait()
  22. end
  23.  
  24. -- ============================================================
  25. -- SEÇÃO 2 ► SERVIÇOS (cache local para evitar chamadas repetidas)
  26. -- ============================================================
  27.  
  28. local Players = game:GetService("Players")
  29. local HttpService = game:GetService("HttpService")
  30. local TweenService = game:GetService("TweenService")
  31. local UserInputService = game:GetService("UserInputService")
  32. local RunService = game:GetService("RunService")
  33. local CoreGui = game:GetService("CoreGui")
  34.  
  35. -- ============================================================
  36. -- SEÇÃO 3 ► REFERÊNCIAS DO JOGADOR
  37. -- ============================================================
  38.  
  39. local plr = Players.LocalPlayer
  40. local chr = plr.Character or plr.CharacterAdded:Wait()
  41. local root = chr:WaitForChild("HumanoidRootPart")
  42.  
  43. -- ============================================================
  44. -- SEÇÃO 4 ► CONSTANTES DE CONFIGURAÇÃO
  45. -- ============================================================
  46.  
  47. local CFG = {
  48. MAX_SAVES = 50,
  49. SLOTS_PER_PAGE = 10,
  50. MAX_PAGES = 5,
  51. SAVE_DIR = "SaveLocate_NickZ",
  52. VERSION = "5.0",
  53. TWEEN_FAST = TweenInfo.new(0.18, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
  54. TWEEN_MED = TweenInfo.new(0.28, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
  55. TWEEN_SLOW = TweenInfo.new(0.45, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
  56. }
  57.  
  58. -- Paleta de cores centralizada (single source of truth)
  59. local CLR = {
  60. BG_DARK = Color3.fromRGB(14, 12, 22),
  61. BG_MID = Color3.fromRGB(22, 19, 35),
  62. BG_LIGHT = Color3.fromRGB(32, 28, 50),
  63. BG_CARD = Color3.fromRGB(28, 25, 42),
  64. BG_CARD_HOV = Color3.fromRGB(38, 34, 58),
  65. ACCENT = Color3.fromRGB(110, 80, 255),
  66. ACCENT_HOV = Color3.fromRGB(135, 105, 255),
  67. ACCENT_DIM = Color3.fromRGB(70, 55, 160),
  68. SUCCESS = Color3.fromRGB(60, 200, 110),
  69. SUCCESS_HOV = Color3.fromRGB(80, 225, 130),
  70. DANGER = Color3.fromRGB(220, 70, 70),
  71. DANGER_HOV = Color3.fromRGB(240, 95, 95),
  72. WARNING = Color3.fromRGB(220, 160, 40),
  73. INFO = Color3.fromRGB(70, 150, 230),
  74. INFO_HOV = Color3.fromRGB(90, 170, 250),
  75. TEXT_PRI = Color3.fromRGB(240, 238, 255),
  76. TEXT_SEC = Color3.fromRGB(170, 165, 200),
  77. TEXT_DIM = Color3.fromRGB(110, 105, 140),
  78. TEXT_MUTED = Color3.fromRGB(75, 70, 100),
  79. GOLD = Color3.fromRGB(255, 210, 60),
  80. STROKE = Color3.fromRGB(80, 65, 160),
  81. STROKE_BRIGHT= Color3.fromRGB(120, 95, 255),
  82. OVERLAY = Color3.fromRGB(5, 4, 10),
  83. WHITE = Color3.new(1, 1, 1),
  84. }
  85.  
  86. -- ============================================================
  87. -- SEÇÃO 5 ► SISTEMA DE FILESYSTEM (detecção de capacidades)
  88. -- ============================================================
  89.  
  90. local FS = {}
  91. do
  92. FS.canWrite = type(writefile) == "function"
  93. FS.canRead = type(readfile) == "function"
  94. FS.canFolder = type(isfolder) == "function" and type(makefolder) == "function"
  95. FS.canIsFile = type(isfile) == "function"
  96. FS.canDelete = type(delfile) == "function"
  97. FS.active = FS.canWrite and FS.canRead
  98.  
  99. local GAME_ID = tostring(game.PlaceId)
  100. local USER_ID = tostring(plr.UserId)
  101. local BASE_DIR = CFG.SAVE_DIR .. "/" .. GAME_ID
  102.  
  103. -- Cria diretórios se suportado
  104. if FS.canFolder then
  105. if not isfolder(CFG.SAVE_DIR) then
  106. pcall(makefolder, CFG.SAVE_DIR)
  107. end
  108. if not isfolder(BASE_DIR) then
  109. pcall(makefolder, BASE_DIR)
  110. end
  111. end
  112.  
  113. -- Resolve caminhos principais e de backup
  114. local function buildPath(dir, name)
  115. return dir .. "/" .. name
  116. end
  117.  
  118. if FS.canFolder then
  119. FS.SAVE_FILE = buildPath(BASE_DIR, "Saves_" .. USER_ID .. ".json")
  120. FS.SAVE_BAK = buildPath(BASE_DIR, "Saves_" .. USER_ID .. ".bak")
  121. FS.MAIN_FILE = buildPath(BASE_DIR, "MainPos_" .. USER_ID .. ".json")
  122. FS.MAIN_BAK = buildPath(BASE_DIR, "MainPos_" .. USER_ID .. ".bak")
  123. else
  124. -- Fallback flat (sem suporte a pastas)
  125. local prefix = string.format("%s_%s_%s", CFG.SAVE_DIR, GAME_ID, USER_ID)
  126. FS.SAVE_FILE = prefix .. "_Saves.json"
  127. FS.SAVE_BAK = prefix .. "_Saves.bak"
  128. FS.MAIN_FILE = prefix .. "_Main.json"
  129. FS.MAIN_BAK = prefix .. "_Main.bak"
  130. end
  131.  
  132. -- Caminhos legados para migração automática
  133. FS.LEGACY_PATHS_SAVES = {
  134. string.format("SkyTP/Saves_%s_%s.json", game.PlaceId, plr.UserId),
  135. string.format("SkyTP/Saves_%s_%s.bak", game.PlaceId, plr.UserId),
  136. string.format("Saves_%s_%s.json", game.PlaceId, plr.UserId),
  137. string.format("Saves_%s_%s.bak", game.PlaceId, plr.UserId),
  138. }
  139. FS.LEGACY_PATHS_MAIN = {
  140. string.format("SkyTP/MainPos_%s_%s.json", game.PlaceId, plr.UserId),
  141. string.format("SkyTP/MainPos_%s_%s.bak", game.PlaceId, plr.UserId),
  142. string.format("MainPos_%s_%s.json", game.PlaceId, plr.UserId),
  143. string.format("MainPos_%s_%s.bak", game.PlaceId, plr.UserId),
  144. }
  145.  
  146. -- Lê arquivo com proteção
  147. function FS.read(path)
  148. if not FS.active or type(path) ~= "string" then return nil end
  149. local ok, content = pcall(readfile, path)
  150. if ok and type(content) == "string" and #content > 2 then
  151. return content
  152. end
  153. return nil
  154. end
  155.  
  156. -- Lê o primeiro arquivo válido de uma lista de candidatos
  157. function FS.readFirst(paths)
  158. for _, p in ipairs(paths) do
  159. local content = FS.read(p)
  160. if content then return content, p end
  161. end
  162. return nil, nil
  163. end
  164.  
  165. -- Escreve em arquivo + backup atomicamente
  166. function FS.writeSafe(primary, backup, content)
  167. if not FS.active then return false end
  168. local ok1 = pcall(writefile, primary, content)
  169. local ok2 = pcall(writefile, backup, content)
  170. return ok1 or ok2
  171. end
  172.  
  173. -- Remove arquivo com segurança
  174. function FS.delete(path)
  175. if FS.active and FS.canDelete and type(path) == "string" then
  176. pcall(delfile, path)
  177. end
  178. end
  179. end
  180.  
  181. -- ============================================================
  182. -- SEÇÃO 6 ► CODIFICADOR DE CFRAME (compacto e seguro)
  183. -- ============================================================
  184.  
  185. local Codec = {}
  186. do
  187. function Codec.encode(cf)
  188. if typeof(cf) ~= "CFrame" then return nil end
  189. local x,y,z,r00,r01,r02,r10,r11,r12,r20,r21,r22 = cf:GetComponents()
  190. return {
  191. x=x, y=y, z=z,
  192. m={r00, r01, r02, r10, r11, r12, r20, r21, r22}
  193. }
  194. end
  195.  
  196. function Codec.decode(t)
  197. if type(t) ~= "table" then return nil end
  198. -- Suporte ao formato legado {x,y,z, R00..R22}
  199. if t.R00 ~= nil then
  200. return CFrame.new(
  201. t.x,t.y,t.z,
  202. t.R00,t.R01,t.R02,
  203. t.R10,t.R11,t.R12,
  204. t.R20,t.R21,t.R22
  205. )
  206. end
  207. -- Formato novo compacto
  208. if t.x and t.m and #t.m == 9 then
  209. local m = t.m
  210. return CFrame.new(t.x,t.y,t.z, m[1],m[2],m[3],m[4],m[5],m[6],m[7],m[8],m[9])
  211. end
  212. return nil
  213. end
  214.  
  215. function Codec.jsonEncode(data)
  216. local ok, result = pcall(function() return HttpService:JSONEncode(data) end)
  217. return ok and result or nil
  218. end
  219.  
  220. function Codec.jsonDecode(str)
  221. if type(str) ~= "string" or #str < 2 then return nil end
  222. local ok, result = pcall(function() return HttpService:JSONDecode(str) end)
  223. return ok and result or nil
  224. end
  225. end
  226.  
  227. -- ============================================================
  228. -- SEÇÃO 7 ► ESTADO GLOBAL DO SCRIPT
  229. -- ============================================================
  230.  
  231. local State = {
  232. saves = {}, -- [slot: number] = {position, name, timestamp}
  233. mainPos = nil, -- {position, name, timestamp}
  234. currentPage = 1,
  235. saveSlot = 1, -- slot de destino atual
  236. isDirty = false, -- controle de escrita pendente
  237. connections = {}, -- pool de conexões para cleanup
  238. optionFrames = {}, -- frames de opções flutuantes ativos
  239. }
  240.  
  241. -- ============================================================
  242. -- SEÇÃO 8 ► SISTEMA DE PERSISTÊNCIA
  243. -- ============================================================
  244.  
  245. local Persist = {}
  246. do
  247. -- Serializa saves para JSON
  248. function Persist.buildSavePayload()
  249. local positions = {}
  250. for slot, data in pairs(State.saves) do
  251. if type(slot) == "number" and slot >= 1 and slot <= CFG.MAX_SAVES
  252. and typeof(data.position) == "CFrame" then
  253. positions[tostring(slot)] = {
  254. name = data.name or ("Slot " .. slot),
  255. timestamp = data.timestamp or os.date("%Y-%m-%d %H:%M:%S"),
  256. position = Codec.encode(data.position),
  257. }
  258. end
  259. end
  260. return {
  261. version = CFG.VERSION,
  262. gameId = game.PlaceId,
  263. gameName = game.Name,
  264. userId = plr.UserId,
  265. userName = plr.Name,
  266. savedAt = os.date("%Y-%m-%d %H:%M:%S"),
  267. positions = positions,
  268. }
  269. end
  270.  
  271. -- Salva tudo no disco
  272. function Persist.save()
  273. if not FS.active then return end
  274.  
  275. -- Saves normais
  276. local payload = Codec.jsonEncode(Persist.buildSavePayload())
  277. if payload then
  278. FS.writeSafe(FS.SAVE_FILE, FS.SAVE_BAK, payload)
  279. end
  280.  
  281. -- Posição principal
  282. if State.mainPos then
  283. local mainPayload = Codec.jsonEncode({
  284. version = CFG.VERSION,
  285. gameId = game.PlaceId,
  286. gameName = game.Name,
  287. name = State.mainPos.name,
  288. timestamp = State.mainPos.timestamp,
  289. position = Codec.encode(State.mainPos.position),
  290. })
  291. if mainPayload then
  292. FS.writeSafe(FS.MAIN_FILE, FS.MAIN_BAK, mainPayload)
  293. end
  294. end
  295.  
  296. State.isDirty = false
  297. end
  298.  
  299. -- Carrega saves do disco com suporte a formatos legados
  300. function Persist.load()
  301. if not FS.active then return end
  302.  
  303. -- Tenta carregar saves
  304. local candidates = {FS.SAVE_FILE, FS.SAVE_BAK}
  305. for _, p in ipairs(FS.LEGACY_PATHS_SAVES) do
  306. table.insert(candidates, p)
  307. end
  308.  
  309. local content, usedPath = FS.readFirst(candidates)
  310. if content then
  311. local data = Codec.jsonDecode(content)
  312. if data and type(data) == "table" then
  313. -- Valida gameId para não misturar saves de jogos diferentes
  314. if not data.gameId or data.gameId == game.PlaceId then
  315. local positions = data.positions or data
  316. for k, v in pairs(positions) do
  317. local slot = tonumber(k)
  318. if slot and slot >= 1 and slot <= CFG.MAX_SAVES and type(v) == "table" then
  319. local cf = Codec.decode(v.position)
  320. if cf then
  321. State.saves[slot] = {
  322. position = cf,
  323. name = v.name or ("Slot " .. slot),
  324. timestamp = v.timestamp or os.date("%Y-%m-%d %H:%M:%S"),
  325. }
  326. end
  327. end
  328. end
  329. -- Migra legado para novo caminho
  330. if usedPath ~= FS.SAVE_FILE then
  331. Persist.save()
  332. end
  333. end
  334. end
  335. end
  336.  
  337. -- Tenta carregar posição principal
  338. local mainCandidates = {FS.MAIN_FILE, FS.MAIN_BAK}
  339. for _, p in ipairs(FS.LEGACY_PATHS_MAIN) do
  340. table.insert(mainCandidates, p)
  341. end
  342.  
  343. local mainContent, mainUsedPath = FS.readFirst(mainCandidates)
  344. if mainContent then
  345. local data = Codec.jsonDecode(mainContent)
  346. if data and type(data) == "table" then
  347. if not data.gameId or data.gameId == game.PlaceId then
  348. local cf = Codec.decode(data.position)
  349. if cf then
  350. State.mainPos = {
  351. position = cf,
  352. name = data.name or "Posição Principal",
  353. timestamp = data.timestamp or os.date("%Y-%m-%d %H:%M:%S"),
  354. }
  355. if mainUsedPath ~= FS.MAIN_FILE then
  356. Persist.save()
  357. end
  358. end
  359. end
  360. end
  361. end
  362. end
  363.  
  364. -- Salva de forma adiada (throttle para evitar spam de escrita)
  365. local saveDebounce = false
  366. function Persist.scheduleSave()
  367. State.isDirty = true
  368. if saveDebounce then return end
  369. saveDebounce = true
  370. task.delay(0.5, function()
  371. if State.isDirty then Persist.save() end
  372. saveDebounce = false
  373. end)
  374. end
  375.  
  376. -- Remove posição principal do disco
  377. function Persist.deleteMain()
  378. FS.delete(FS.MAIN_FILE)
  379. FS.delete(FS.MAIN_BAK)
  380. end
  381. end
  382.  
  383. -- ============================================================
  384. -- SEÇÃO 9 ► SISTEMA DE TELEPORTE ANTI-BUG
  385. -- ============================================================
  386.  
  387. local Teleport = {}
  388. do
  389. -- Atualiza referências do personagem (chamado ao respawn)
  390. function Teleport.refreshCharacter()
  391. chr = plr.Character
  392. root = chr and chr:FindFirstChild("HumanoidRootPart")
  393. end
  394.  
  395. -- Teleporte robusto: âncora → zera velocidade → aplica CFrame → desancora
  396. function Teleport.to(targetCFrame)
  397. if not targetCFrame then return false end
  398.  
  399. -- Garante referências atualizadas
  400. if not chr or not chr.Parent then
  401. Teleport.refreshCharacter()
  402. end
  403. if not root then return false end
  404.  
  405. local hum = chr:FindFirstChildWhichIsA("Humanoid")
  406.  
  407. -- Sai de assentos se necessário
  408. if hum and hum.SeatPart then
  409. hum.Sit = false
  410. task.wait(0.05)
  411. end
  412.  
  413. -- Desativa efeitos de física temporariamente
  414. local wasAnchored = root.Anchored
  415. root.Anchored = true
  416.  
  417. -- Zera momentum para evitar "lançamentos"
  418. if root:IsA("BasePart") then
  419. root.AssemblyLinearVelocity = Vector3.zero
  420. root.AssemblyAngularVelocity = Vector3.zero
  421. end
  422.  
  423. -- Aplica posição
  424. root.CFrame = targetCFrame
  425.  
  426. -- Aguarda confirmação de física e aplica novamente
  427. RunService.Heartbeat:Wait()
  428. root.CFrame = targetCFrame
  429.  
  430. -- Restaura estado original
  431. root.Anchored = wasAnchored
  432. return true
  433. end
  434. end
  435.  
  436. -- ============================================================
  437. -- SEÇÃO 10 ► UTILITÁRIOS DE UI
  438. -- ============================================================
  439.  
  440. local UI = {}
  441. do
  442. -- Cria UICorner de forma fluida
  443. function UI.corner(parent, radius)
  444. local c = Instance.new("UICorner")
  445. c.CornerRadius = UDim.new(0, radius or 8)
  446. c.Parent = parent
  447. return c
  448. end
  449.  
  450. -- Cria UIStroke de forma fluida
  451. function UI.stroke(parent, color, thickness)
  452. local s = Instance.new("UIStroke")
  453. s.Color = color or CLR.STROKE
  454. s.Thickness = thickness or 1.5
  455. s.Parent = parent
  456. return s
  457. end
  458.  
  459. -- Gradiente simples de cima para baixo
  460. function UI.gradient(parent, colorA, colorB, rotation)
  461. local g = Instance.new("UIGradient")
  462. g.Color = ColorSequence.new({
  463. ColorSequenceKeypoint.new(0, colorA),
  464. ColorSequenceKeypoint.new(1, colorB),
  465. })
  466. g.Rotation = rotation or 90
  467. g.Parent = parent
  468. return g
  469. end
  470.  
  471. -- Hover animado para botão (cor de fundo)
  472. function UI.hoverBG(button, hoverColor, baseColor)
  473. button.MouseEnter:Connect(function()
  474. TweenService:Create(button, CFG.TWEEN_FAST, {BackgroundColor3 = hoverColor}):Play()
  475. end)
  476. button.MouseLeave:Connect(function()
  477. TweenService:Create(button, CFG.TWEEN_FAST, {BackgroundColor3 = baseColor}):Play()
  478. end)
  479. end
  480.  
  481. -- Hover animado para botão (escala via Size)
  482. function UI.hoverScale(button, baseSize, scaleUp)
  483. local upSize = UDim2.new(baseSize.X.Scale * scaleUp, baseSize.X.Offset,
  484. baseSize.Y.Scale * scaleUp, baseSize.Y.Offset)
  485. button.MouseEnter:Connect(function()
  486. TweenService:Create(button, CFG.TWEEN_FAST, {Size = upSize}):Play()
  487. end)
  488. button.MouseLeave:Connect(function()
  489. TweenService:Create(button, CFG.TWEEN_FAST, {Size = baseSize}):Play()
  490. end)
  491. end
  492.  
  493. -- Fecha todos os menus de opções flutuantes abertos
  494. function UI.closeAllOptionMenus(except)
  495. for slot, frame in pairs(State.optionFrames) do
  496. if frame ~= except and frame and frame.Parent then
  497. frame.Visible = false
  498. end
  499. end
  500. end
  501.  
  502. -- Fábrica de Label padrão
  503. function UI.label(parent, props)
  504. local l = Instance.new("TextLabel")
  505. l.BackgroundTransparency = 1
  506. l.Font = props.font or Enum.Font.Gotham
  507. l.TextSize = props.size or 14
  508. l.TextColor3 = props.color or CLR.TEXT_PRI
  509. l.Text = props.text or ""
  510. l.TextXAlignment = props.align or Enum.TextXAlignment.Left
  511. l.TextWrapped = props.wrap or false
  512. l.TextTruncate = props.truncate or Enum.TextTruncate.None
  513. l.Size = props.sz or UDim2.new(1, 0, 1, 0)
  514. l.Position = props.pos or UDim2.new(0, 0, 0, 0)
  515. l.Parent = parent
  516. return l
  517. end
  518.  
  519. -- Fábrica de Button padrão
  520. function UI.button(parent, props)
  521. local b = Instance.new("TextButton")
  522. b.Font = props.font or Enum.Font.GothamSemibold
  523. b.TextSize = props.size or 14
  524. b.TextColor3 = props.textColor or CLR.WHITE
  525. b.Text = props.text or ""
  526. b.BackgroundColor3 = props.bgColor or CLR.ACCENT
  527. b.Size = props.sz or UDim2.new(0, 80, 0, 30)
  528. b.Position = props.pos or UDim2.new(0, 0, 0, 0)
  529. b.AutoButtonColor = false
  530. b.BorderSizePixel = 0
  531. b.Parent = parent
  532. UI.corner(b, props.radius or 7)
  533. if props.hoverColor then
  534. UI.hoverBG(b, props.hoverColor, props.bgColor)
  535. end
  536. return b
  537. end
  538. end
  539.  
  540. -- ============================================================
  541. -- SEÇÃO 11 ► CONSTRUÇÃO DA GUI
  542. -- ============================================================
  543.  
  544. -- Remove instâncias antigas para evitar duplicatas ao re-executar
  545. do
  546. local old = CoreGui:FindFirstChild("SaveLocate_NickZ_V5")
  547. if old then old:Destroy() end
  548. end
  549.  
  550. local ScreenGui = Instance.new("ScreenGui")
  551. ScreenGui.Name = "SaveLocate_NickZ_V5"
  552. ScreenGui.DisplayOrder = 999
  553. ScreenGui.ResetOnSpawn = false
  554. ScreenGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
  555. ScreenGui.IgnoreGuiInset = true
  556. ScreenGui.Parent = CoreGui
  557.  
  558. -- ────────────────────────────────────────────────
  559. -- 11.1 ► JANELA PRINCIPAL
  560. -- ────────────────────────────────────────────────
  561.  
  562. local MainFrame = Instance.new("Frame")
  563. MainFrame.Name = "MainFrame"
  564. MainFrame.Size = UDim2.new(0, 590, 0, 470)
  565. MainFrame.Position = UDim2.new(0.5, -295, 0.5, -235)
  566. MainFrame.BackgroundColor3 = CLR.BG_DARK
  567. MainFrame.BorderSizePixel = 0
  568. MainFrame.Active = true
  569. MainFrame.Draggable = true
  570. MainFrame.ClipsDescendants = true
  571. MainFrame.Parent = ScreenGui
  572.  
  573. UI.corner(MainFrame, 10)
  574. UI.stroke(MainFrame, CLR.STROKE_BRIGHT, 1.5)
  575. UI.gradient(MainFrame, CLR.BG_MID, CLR.BG_DARK, 135)
  576.  
  577. -- ────────────────────────────────────────────────
  578. -- 11.2 ► BARRA DE TÍTULO
  579. -- ────────────────────────────────────────────────
  580.  
  581. local TitleBar = Instance.new("Frame")
  582. TitleBar.Name = "TitleBar"
  583. TitleBar.Size = UDim2.new(1, 0, 0, 44)
  584. TitleBar.BackgroundColor3 = CLR.BG_MID
  585. TitleBar.BorderSizePixel = 0
  586. TitleBar.Parent = MainFrame
  587. UI.corner(TitleBar, 10)
  588.  
  589. -- Borda inferior da titlebar para separar visualmente
  590. local TitleDivider = Instance.new("Frame")
  591. TitleDivider.Name = "Divider"
  592. TitleDivider.Size = UDim2.new(1, 0, 0, 1)
  593. TitleDivider.Position = UDim2.new(0, 0, 1, -1)
  594. TitleDivider.BackgroundColor3 = CLR.STROKE
  595. TitleDivider.BorderSizePixel = 0
  596. TitleDivider.Parent = TitleBar
  597.  
  598. -- Ícone decorativo
  599. local TitleIcon = UI.label(TitleBar, {
  600. text = "✦",
  601. sz = UDim2.new(0, 30, 1, 0),
  602. pos = UDim2.new(0, 12, 0, 0),
  603. size = 18,
  604. color = CLR.ACCENT,
  605. font = Enum.Font.GothamBold,
  606. align = Enum.TextXAlignment.Center,
  607. })
  608.  
  609. local TitleLabel = UI.label(TitleBar, {
  610. text = "Save Locate · NickZ",
  611. sz = UDim2.new(1, -120, 1, 0),
  612. pos = UDim2.new(0, 46, 0, 0),
  613. size = 16,
  614. color = CLR.TEXT_PRI,
  615. font = Enum.Font.GothamBold,
  616. align = Enum.TextXAlignment.Left,
  617. })
  618.  
  619. local VersionBadge = Instance.new("Frame")
  620. VersionBadge.Size = UDim2.new(0, 42, 0, 20)
  621. VersionBadge.Position = UDim2.new(1, -90, 0.5, -10)
  622. VersionBadge.BackgroundColor3 = CLR.ACCENT_DIM
  623. VersionBadge.Parent = TitleBar
  624. UI.corner(VersionBadge, 5)
  625.  
  626. local VersionLabel = UI.label(VersionBadge, {
  627. text = "V 5.0",
  628. size = 10,
  629. color = CLR.TEXT_PRI,
  630. font = Enum.Font.GothamBold,
  631. align = Enum.TextXAlignment.Center,
  632. sz = UDim2.new(1, 0, 1, 0),
  633. })
  634.  
  635. local CloseBtn = UI.button(TitleBar, {
  636. text = "✕",
  637. sz = UDim2.new(0, 28, 0, 28),
  638. pos = UDim2.new(1, -36, 0.5, -14),
  639. bgColor = CLR.BG_LIGHT,
  640. hoverColor= CLR.DANGER,
  641. textColor = CLR.TEXT_SEC,
  642. font = Enum.Font.GothamBold,
  643. size = 14,
  644. radius = 7,
  645. })
  646.  
  647. -- ────────────────────────────────────────────────
  648. -- 11.3 ► ÁREA DE CONTROLES (Salvar / Nome / Slot)
  649. -- ────────────────────────────────────────────────
  650.  
  651. local CtrlFrame = Instance.new("Frame")
  652. CtrlFrame.Name = "Controls"
  653. CtrlFrame.Size = UDim2.new(1, -20, 0, 96)
  654. CtrlFrame.Position = UDim2.new(0, 10, 0, 50)
  655. CtrlFrame.BackgroundColor3 = CLR.BG_MID
  656. CtrlFrame.BorderSizePixel = 0
  657. CtrlFrame.Parent = MainFrame
  658. UI.corner(CtrlFrame, 8)
  659. UI.stroke(CtrlFrame, CLR.STROKE, 1)
  660.  
  661. -- Botão Salvar
  662. local SaveBtn = UI.button(CtrlFrame, {
  663. text = "+ Salvar Posição",
  664. sz = UDim2.new(0, 175, 0, 36),
  665. pos = UDim2.new(0, 10, 0, 10),
  666. bgColor = CLR.SUCCESS,
  667. hoverColor = CLR.SUCCESS_HOV,
  668. textColor = CLR.WHITE,
  669. font = Enum.Font.GothamBold,
  670. size = 14,
  671. radius = 7,
  672. })
  673.  
  674. -- Campo de nome
  675. local NameBox = Instance.new("TextBox")
  676. NameBox.Name = "NameBox"
  677. NameBox.PlaceholderText = " Nome da posição..."
  678. NameBox.Size = UDim2.new(1, -200, 0, 36)
  679. NameBox.Position = UDim2.new(0, 10, 0, 50)
  680. NameBox.BackgroundColor3 = CLR.BG_DARK
  681. NameBox.TextColor3 = CLR.TEXT_PRI
  682. NameBox.PlaceholderColor3 = CLR.TEXT_MUTED
  683. NameBox.Font = Enum.Font.Gotham
  684. NameBox.TextSize = 13
  685. NameBox.ClearTextOnFocus = false
  686. NameBox.TextXAlignment = Enum.TextXAlignment.Left
  687. NameBox.Parent = CtrlFrame
  688. UI.corner(NameBox, 7)
  689. UI.stroke(NameBox, CLR.STROKE, 1)
  690.  
  691. -- Painel de seleção de slot (lado direito dos controles)
  692. local SlotPanel = Instance.new("Frame")
  693. SlotPanel.Name = "SlotPanel"
  694. SlotPanel.Size = UDim2.new(0, 175, 0, 76)
  695. SlotPanel.Position = UDim2.new(1, -185, 0, 10)
  696. SlotPanel.BackgroundColor3 = CLR.BG_DARK
  697. SlotPanel.BorderSizePixel = 0
  698. SlotPanel.Parent = CtrlFrame
  699. UI.corner(SlotPanel, 7)
  700. UI.stroke(SlotPanel, CLR.STROKE, 1)
  701.  
  702. local SlotTitleLbl = UI.label(SlotPanel, {
  703. text = "SLOT DE DESTINO",
  704. sz = UDim2.new(1, 0, 0, 20),
  705. pos = UDim2.new(0, 0, 0, 4),
  706. size = 9,
  707. color = CLR.TEXT_DIM,
  708. font = Enum.Font.GothamBold,
  709. align = Enum.TextXAlignment.Center,
  710. })
  711.  
  712. local SlotValueLbl = UI.label(SlotPanel, {
  713. text = "01",
  714. sz = UDim2.new(0, 50, 0, 30),
  715. pos = UDim2.new(0.5, -25, 0, 22),
  716. size = 22,
  717. color = CLR.ACCENT,
  718. font = Enum.Font.GothamBold,
  719. align = Enum.TextXAlignment.Center,
  720. })
  721.  
  722. local SlotPrevBtn = UI.button(SlotPanel, {
  723. text = "‹",
  724. sz = UDim2.new(0, 32, 0, 28),
  725. pos = UDim2.new(0, 6, 0, 24),
  726. bgColor = CLR.ACCENT_DIM,
  727. hoverColor = CLR.ACCENT,
  728. size = 18,
  729. radius = 6,
  730. })
  731.  
  732. local SlotNextBtn = UI.button(SlotPanel, {
  733. text = "›",
  734. sz = UDim2.new(0, 32, 0, 28),
  735. pos = UDim2.new(1, -38, 0, 24),
  736. bgColor = CLR.ACCENT_DIM,
  737. hoverColor = CLR.ACCENT,
  738. size = 18,
  739. radius = 6,
  740. })
  741.  
  742. local SlotStatusLbl = UI.label(SlotPanel, {
  743. text = "livre",
  744. sz = UDim2.new(1, 0, 0, 14),
  745. pos = UDim2.new(0, 0, 1, -16),
  746. size = 9,
  747. color = CLR.SUCCESS,
  748. font = Enum.Font.GothamSemibold,
  749. align = Enum.TextXAlignment.Center,
  750. })
  751.  
  752. -- ────────────────────────────────────────────────
  753. -- 11.4 ► BARRA DE PAGINAÇÃO
  754. -- ────────────────────────────────────────────────
  755.  
  756. local PageBar = Instance.new("Frame")
  757. PageBar.Name = "PageBar"
  758. PageBar.Size = UDim2.new(1, -20, 0, 34)
  759. PageBar.Position = UDim2.new(0, 10, 0, 152)
  760. PageBar.BackgroundColor3 = CLR.BG_MID
  761. PageBar.BorderSizePixel = 0
  762. PageBar.Parent = MainFrame
  763. UI.corner(PageBar, 7)
  764. UI.stroke(PageBar, CLR.STROKE, 1)
  765.  
  766. local PagePrevBtn = UI.button(PageBar, {
  767. text = "◄",
  768. sz = UDim2.new(0, 70, 0, 26),
  769. pos = UDim2.new(0, 4, 0.5, -13),
  770. bgColor = CLR.BG_LIGHT,
  771. hoverColor = CLR.ACCENT_DIM,
  772. size = 12,
  773. radius = 6,
  774. })
  775.  
  776. local PageLabel = UI.label(PageBar, {
  777. text = "PÁGINA 1 / 5",
  778. sz = UDim2.new(1, -160, 1, 0),
  779. pos = UDim2.new(0, 80, 0, 0),
  780. size = 12,
  781. color = CLR.TEXT_SEC,
  782. font = Enum.Font.GothamBold,
  783. align = Enum.TextXAlignment.Center,
  784. })
  785.  
  786. -- Indicadores de paginação (bolinhas)
  787. local PageDotsFrame = Instance.new("Frame")
  788. PageDotsFrame.Size = UDim2.new(0, 70, 0, 10)
  789. PageDotsFrame.Position = UDim2.new(0.5, -35, 1, -13)
  790. PageDotsFrame.BackgroundTransparency = 1
  791. PageDotsFrame.Parent = PageBar
  792.  
  793. local PageDotLayout = Instance.new("UIListLayout")
  794. PageDotLayout.FillDirection = Enum.FillDirection.Horizontal
  795. PageDotLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
  796. PageDotLayout.Padding = UDim.new(0, 6)
  797. PageDotLayout.Parent = PageDotsFrame
  798.  
  799. local PageDots = {}
  800. for i = 1, CFG.MAX_PAGES do
  801. local dot = Instance.new("Frame")
  802. dot.Size = UDim2.new(0, 7, 0, 7)
  803. dot.BackgroundColor3 = (i == 1) and CLR.ACCENT or CLR.TEXT_MUTED
  804. dot.Parent = PageDotsFrame
  805. UI.corner(dot, 4)
  806. PageDots[i] = dot
  807. end
  808.  
  809. local PageNextBtn = UI.button(PageBar, {
  810. text = "►",
  811. sz = UDim2.new(0, 70, 0, 26),
  812. pos = UDim2.new(1, -74, 0.5, -13),
  813. bgColor = CLR.BG_LIGHT,
  814. hoverColor = CLR.ACCENT_DIM,
  815. size = 12,
  816. radius = 6,
  817. })
  818.  
  819. -- ────────────────────────────────────────────────
  820. -- 11.5 ► GRID DE SLOTS
  821. -- ────────────────────────────────────────────────
  822.  
  823. local SlotsFrame = Instance.new("Frame")
  824. SlotsFrame.Name = "Slots"
  825. SlotsFrame.Size = UDim2.new(1, -20, 1, -198)
  826. SlotsFrame.Position = UDim2.new(0, 10, 0, 194)
  827. SlotsFrame.BackgroundTransparency = 1
  828. SlotsFrame.Parent = MainFrame
  829.  
  830. local GridLayout = Instance.new("UIGridLayout")
  831. GridLayout.CellPadding = UDim2.new(0, 7, 0, 7)
  832. GridLayout.CellSize = UDim2.new(0.5, -4, 0, 48)
  833. GridLayout.FillDirection = Enum.FillDirection.Horizontal
  834. GridLayout.SortOrder = Enum.SortOrder.LayoutOrder
  835. GridLayout.Parent = SlotsFrame
  836.  
  837. -- ────────────────────────────────────────────────
  838. -- 11.6 ► BOTÃO FLUTUANTE (quando janela fechada)
  839. -- ────────────────────────────────────────────────
  840.  
  841. local FloatContainer = Instance.new("Frame")
  842. FloatContainer.Name = "FloatBtn"
  843. FloatContainer.Size = UDim2.new(0, 46, 0, 46)
  844. FloatContainer.Position = UDim2.new(0, 16, 0.5, -23)
  845. FloatContainer.BackgroundTransparency = 1
  846. FloatContainer.Active = true
  847. FloatContainer.Draggable = true
  848. FloatContainer.Visible = false
  849. FloatContainer.Parent = ScreenGui
  850.  
  851. local FloatBtn = UI.button(FloatContainer, {
  852. text = "✦",
  853. sz = UDim2.new(1, 0, 1, 0),
  854. bgColor = CLR.BG_MID,
  855. hoverColor = CLR.BG_LIGHT,
  856. textColor = CLR.ACCENT,
  857. font = Enum.Font.GothamBold,
  858. size = 22,
  859. radius = 10,
  860. })
  861. UI.stroke(FloatBtn, CLR.STROKE_BRIGHT, 1.5)
  862.  
  863. -- ────────────────────────────────────────────────
  864. -- 11.7 ► BOTÃO FLUTUANTE DE POSIÇÃO PRINCIPAL
  865. -- ────────────────────────────────────────────────
  866.  
  867. local MainPosContainer = Instance.new("Frame")
  868. MainPosContainer.Name = "MainPosBtn"
  869. MainPosContainer.Size = UDim2.new(0, 50, 0, 50)
  870. MainPosContainer.Position = UDim2.new(1, -64, 0, 14)
  871. MainPosContainer.BackgroundTransparency = 1
  872. MainPosContainer.Active = true
  873. MainPosContainer.Draggable = true
  874. MainPosContainer.Visible = false
  875. MainPosContainer.Parent = ScreenGui
  876.  
  877. local MainPosBtn = UI.button(MainPosContainer, {
  878. text = "🚀",
  879. sz = UDim2.new(1, 0, 1, 0),
  880. bgColor = CLR.BG_MID,
  881. hoverColor = CLR.BG_LIGHT,
  882. size = 22,
  883. radius = 25,
  884. })
  885. local MainPosStroke = UI.stroke(MainPosBtn, CLR.ACCENT, 2)
  886.  
  887. -- Tooltip da posição principal
  888. local MainPosTooltip = Instance.new("Frame")
  889. MainPosTooltip.Name = "Tooltip"
  890. MainPosTooltip.Size = UDim2.new(0, 160, 0, 32)
  891. MainPosTooltip.Position = UDim2.new(-3.4, 0, 0.5, -16)
  892. MainPosTooltip.BackgroundColor3 = CLR.BG_MID
  893. MainPosTooltip.BackgroundTransparency = 0.05
  894. MainPosTooltip.Visible = false
  895. MainPosTooltip.ZIndex = 5
  896. MainPosTooltip.Parent = MainPosBtn
  897. UI.corner(MainPosTooltip, 7)
  898. UI.stroke(MainPosTooltip, CLR.ACCENT, 1)
  899.  
  900. local TooltipLabel = UI.label(MainPosTooltip, {
  901. text = "",
  902. sz = UDim2.new(1, -8, 1, 0),
  903. pos = UDim2.new(0, 4, 0, 0),
  904. size = 11,
  905. color = CLR.TEXT_PRI,
  906. font = Enum.Font.GothamSemibold,
  907. align = Enum.TextXAlignment.Center,
  908. wrap = true,
  909. })
  910. TooltipLabel.ZIndex = 6
  911.  
  912. -- Botão X (remover posição principal)
  913. local MainPosRemoveBtn = UI.button(MainPosBtn, {
  914. text = "×",
  915. sz = UDim2.new(0, 18, 0, 18),
  916. pos = UDim2.new(1, -4, 0, -4),
  917. bgColor = CLR.DANGER,
  918. hoverColor = CLR.DANGER_HOV,
  919. size = 12,
  920. radius = 9,
  921. })
  922. MainPosRemoveBtn.Visible = false
  923. MainPosRemoveBtn.ZIndex = 6
  924.  
  925. -- ────────────────────────────────────────────────
  926. -- 11.8 ► SISTEMA DE NOTIFICAÇÃO (Toast)
  927. -- ────────────────────────────────────────────────
  928.  
  929. local ToastFrame = Instance.new("Frame")
  930. ToastFrame.Name = "Toast"
  931. ToastFrame.Size = UDim2.new(0, 260, 0, 38)
  932. ToastFrame.Position = UDim2.new(0.5, -130, 0, -50)
  933. ToastFrame.BackgroundColor3 = CLR.BG_MID
  934. ToastFrame.BackgroundTransparency = 0.05
  935. ToastFrame.Visible = false
  936. ToastFrame.ZIndex = 99
  937. ToastFrame.Parent = ScreenGui
  938. UI.corner(ToastFrame, 8)
  939. local ToastStroke = UI.stroke(ToastFrame, CLR.SUCCESS, 1.5)
  940.  
  941. local ToastLabel = UI.label(ToastFrame, {
  942. text = "",
  943. sz = UDim2.new(1, -16, 1, 0),
  944. pos = UDim2.new(0, 8, 0, 0),
  945. size = 13,
  946. color = CLR.TEXT_PRI,
  947. font = Enum.Font.GothamSemibold,
  948. align = Enum.TextXAlignment.Center,
  949. wrap = false,
  950. })
  951. ToastLabel.ZIndex = 100
  952.  
  953. local toastActive = false
  954. local function showToast(message, toastType)
  955. local colorMap = {
  956. success = CLR.SUCCESS,
  957. error = CLR.DANGER,
  958. info = CLR.INFO,
  959. warning = CLR.WARNING,
  960. }
  961. local color = colorMap[toastType] or CLR.SUCCESS
  962. ToastStroke.Color = color
  963. ToastLabel.Text = message
  964. ToastLabel.TextColor3 = color
  965. ToastFrame.Visible = true
  966. toastActive = true
  967.  
  968. TweenService:Create(ToastFrame, CFG.TWEEN_MED, {
  969. Position = UDim2.new(0.5, -130, 0, 12)
  970. }):Play()
  971.  
  972. task.delay(2.2, function()
  973. if toastActive then
  974. TweenService:Create(ToastFrame, CFG.TWEEN_MED, {
  975. Position = UDim2.new(0.5, -130, 0, -50)
  976. }):Play()
  977. task.wait(0.35)
  978. ToastFrame.Visible = false
  979. toastActive = false
  980. end
  981. end)
  982. end
  983.  
  984. -- ────────────────────────────────────────────────
  985. -- 11.9 ► OVERLAYS MODAIS (Confirmação / Renomear / Mover)
  986. -- ────────────────────────────────────────────────
  987.  
  988. -- Helper para criar overlay base
  989. local function createOverlay(parent, zIndex)
  990. local overlay = Instance.new("Frame")
  991. overlay.Size = UDim2.new(1, 0, 1, 0)
  992. overlay.BackgroundColor3 = CLR.OVERLAY
  993. overlay.BackgroundTransparency = 0.5
  994. overlay.Visible = false
  995. overlay.ZIndex = zIndex
  996. overlay.Parent = parent
  997. return overlay
  998. end
  999.  
  1000. local function createModalFrame(parent, w, h, zIndex)
  1001. local frame = Instance.new("Frame")
  1002. frame.Size = UDim2.new(0, w, 0, h)
  1003. frame.Position = UDim2.new(0.5, -w/2, 0.5, -h/2)
  1004. frame.BackgroundColor3 = CLR.BG_MID
  1005. frame.BorderSizePixel = 0
  1006. frame.ZIndex = zIndex
  1007. frame.Parent = parent
  1008. UI.corner(frame, 10)
  1009. UI.stroke(frame, CLR.STROKE_BRIGHT, 1.5)
  1010. return frame
  1011. end
  1012.  
  1013. -- ── Modal de Confirmação ──────────────────────
  1014. local ConfirmOverlay = createOverlay(MainFrame, 20)
  1015. local ConfirmFrame = createModalFrame(ConfirmOverlay, 310, 130, 21)
  1016.  
  1017. local ConfirmTitleBar = Instance.new("Frame")
  1018. ConfirmTitleBar.Size = UDim2.new(1, 0, 0, 32)
  1019. ConfirmTitleBar.BackgroundColor3 = CLR.BG_DARK
  1020. ConfirmTitleBar.BorderSizePixel = 0
  1021. ConfirmTitleBar.ZIndex = 22
  1022. ConfirmTitleBar.Parent = ConfirmFrame
  1023. UI.corner(ConfirmTitleBar, 10)
  1024.  
  1025. local ConfirmIcon = UI.label(ConfirmTitleBar, {
  1026. text = "⚠",
  1027. sz = UDim2.new(0, 30, 1, 0),
  1028. pos = UDim2.new(0, 8, 0, 0),
  1029. size = 14,
  1030. color = CLR.WARNING,
  1031. font = Enum.Font.GothamBold,
  1032. align = Enum.TextXAlignment.Center,
  1033. })
  1034. ConfirmIcon.ZIndex = 23
  1035.  
  1036. local ConfirmTitleLbl = UI.label(ConfirmTitleBar, {
  1037. text = "Confirmar Ação",
  1038. sz = UDim2.new(1, -40, 1, 0),
  1039. pos = UDim2.new(0, 38, 0, 0),
  1040. size = 13,
  1041. color = CLR.TEXT_PRI,
  1042. font = Enum.Font.GothamBold,
  1043. align = Enum.TextXAlignment.Left,
  1044. })
  1045. ConfirmTitleLbl.ZIndex = 23
  1046.  
  1047. local ConfirmLabel = UI.label(ConfirmFrame, {
  1048. text = "",
  1049. sz = UDim2.new(1, -20, 0, 40),
  1050. pos = UDim2.new(0, 10, 0, 36),
  1051. size = 13,
  1052. color = CLR.TEXT_SEC,
  1053. font = Enum.Font.Gotham,
  1054. align = Enum.TextXAlignment.Center,
  1055. wrap = true,
  1056. })
  1057. ConfirmLabel.ZIndex = 22
  1058.  
  1059. local ConfirmYesBtn = UI.button(ConfirmFrame, {
  1060. text = "Confirmar",
  1061. sz = UDim2.new(0.5, -12, 0, 32),
  1062. pos = UDim2.new(0, 8, 1, -40),
  1063. bgColor = CLR.DANGER,
  1064. hoverColor = CLR.DANGER_HOV,
  1065. size = 13,
  1066. radius = 7,
  1067. })
  1068. ConfirmYesBtn.ZIndex = 22
  1069.  
  1070. local ConfirmNoBtn = UI.button(ConfirmFrame, {
  1071. text = "Cancelar",
  1072. sz = UDim2.new(0.5, -12, 0, 32),
  1073. pos = UDim2.new(0.5, 4, 1, -40),
  1074. bgColor = CLR.ACCENT_DIM,
  1075. hoverColor = CLR.ACCENT,
  1076. size = 13,
  1077. radius = 7,
  1078. })
  1079. ConfirmNoBtn.ZIndex = 22
  1080.  
  1081. -- ── Modal de Renomear ─────────────────────────
  1082. local RenameOverlay = createOverlay(MainFrame, 25)
  1083. local RenameFrame = createModalFrame(RenameOverlay, 340, 155, 26)
  1084.  
  1085. local RenameTitleBar = Instance.new("Frame")
  1086. RenameTitleBar.Size = UDim2.new(1, 0, 0, 32)
  1087. RenameTitleBar.BackgroundColor3 = CLR.BG_DARK
  1088. RenameTitleBar.BorderSizePixel = 0
  1089. RenameTitleBar.ZIndex = 27
  1090. RenameTitleBar.Parent = RenameFrame
  1091. UI.corner(RenameTitleBar, 10)
  1092.  
  1093. local RenameTitleLbl = UI.label(RenameTitleBar, {
  1094. text = "✏ Renomear Posição",
  1095. sz = UDim2.new(1, -16, 1, 0),
  1096. pos = UDim2.new(0, 12, 0, 0),
  1097. size = 13,
  1098. color = CLR.TEXT_PRI,
  1099. font = Enum.Font.GothamBold,
  1100. align = Enum.TextXAlignment.Left,
  1101. })
  1102. RenameTitleLbl.ZIndex = 28
  1103.  
  1104. local RenameField = Instance.new("TextBox")
  1105. RenameField.Size = UDim2.new(1, -20, 0, 38)
  1106. RenameField.Position = UDim2.new(0, 10, 0, 40)
  1107. RenameField.BackgroundColor3 = CLR.BG_DARK
  1108. RenameField.TextColor3 = CLR.TEXT_PRI
  1109. RenameField.PlaceholderColor3 = CLR.TEXT_MUTED
  1110. RenameField.PlaceholderText = " Digite o novo nome..."
  1111. RenameField.Font = Enum.Font.Gotham
  1112. RenameField.TextSize = 14
  1113. RenameField.ClearTextOnFocus = false
  1114. RenameField.ZIndex = 27
  1115. RenameField.Parent = RenameFrame
  1116. UI.corner(RenameField, 7)
  1117. UI.stroke(RenameField, CLR.STROKE, 1)
  1118.  
  1119. local RenameConfirmBtn = UI.button(RenameFrame, {
  1120. text = "Confirmar",
  1121. sz = UDim2.new(0.5, -12, 0, 34),
  1122. pos = UDim2.new(0, 8, 1, -42),
  1123. bgColor = CLR.INFO,
  1124. hoverColor = CLR.INFO_HOV,
  1125. size = 13,
  1126. radius = 7,
  1127. })
  1128. RenameConfirmBtn.ZIndex = 27
  1129.  
  1130. local RenameCancelBtn = UI.button(RenameFrame, {
  1131. text = "Cancelar",
  1132. sz = UDim2.new(0.5, -12, 0, 34),
  1133. pos = UDim2.new(0.5, 4, 1, -42),
  1134. bgColor = CLR.ACCENT_DIM,
  1135. hoverColor = CLR.ACCENT,
  1136. size = 13,
  1137. radius = 7,
  1138. })
  1139. RenameCancelBtn.ZIndex = 27
  1140.  
  1141. -- ── Modal de Mover ────────────────────────────
  1142. local MoveOverlay = createOverlay(MainFrame, 30)
  1143. local MoveFrame = createModalFrame(MoveOverlay, 300, 170, 31)
  1144.  
  1145. local MoveTitleBar = Instance.new("Frame")
  1146. MoveTitleBar.Size = UDim2.new(1, 0, 0, 32)
  1147. MoveTitleBar.BackgroundColor3 = CLR.BG_DARK
  1148. MoveTitleBar.BorderSizePixel = 0
  1149. MoveTitleBar.ZIndex = 32
  1150. MoveTitleBar.Parent = MoveFrame
  1151. UI.corner(MoveTitleBar, 10)
  1152.  
  1153. local MoveTitleLbl = UI.label(MoveTitleBar, {
  1154. text = "↔ Mover Posição",
  1155. sz = UDim2.new(1, -16, 1, 0),
  1156. pos = UDim2.new(0, 12, 0, 0),
  1157. size = 13,
  1158. color = CLR.TEXT_PRI,
  1159. font = Enum.Font.GothamBold,
  1160. align = Enum.TextXAlignment.Left,
  1161. })
  1162. MoveTitleLbl.ZIndex = 33
  1163.  
  1164. local MoveSubLbl = UI.label(MoveFrame, {
  1165. text = "Slot de destino (1 – 50)",
  1166. sz = UDim2.new(1, -20, 0, 22),
  1167. pos = UDim2.new(0, 10, 0, 38),
  1168. size = 12,
  1169. color = CLR.TEXT_SEC,
  1170. font = Enum.Font.Gotham,
  1171. align = Enum.TextXAlignment.Center,
  1172. })
  1173. MoveSubLbl.ZIndex = 32
  1174.  
  1175. local MoveInput = Instance.new("TextBox")
  1176. MoveInput.Size = UDim2.new(0, 90, 0, 42)
  1177. MoveInput.Position = UDim2.new(0.5, -45, 0, 64)
  1178. MoveInput.BackgroundColor3 = CLR.BG_DARK
  1179. MoveInput.TextColor3 = CLR.TEXT_PRI
  1180. MoveInput.PlaceholderColor3 = CLR.TEXT_MUTED
  1181. MoveInput.PlaceholderText = "1 – 50"
  1182. MoveInput.Font = Enum.Font.GothamBold
  1183. MoveInput.TextSize = 20
  1184. MoveInput.ClearTextOnFocus = true
  1185. MoveInput.ZIndex = 32
  1186. MoveInput.Parent = MoveFrame
  1187. UI.corner(MoveInput, 8)
  1188. UI.stroke(MoveInput, CLR.STROKE, 1)
  1189.  
  1190. local MoveConfirmBtn = UI.button(MoveFrame, {
  1191. text = "Confirmar",
  1192. sz = UDim2.new(0.5, -12, 0, 34),
  1193. pos = UDim2.new(0, 8, 1, -42),
  1194. bgColor = CLR.INFO,
  1195. hoverColor = CLR.INFO_HOV,
  1196. size = 13,
  1197. radius = 7,
  1198. })
  1199. MoveConfirmBtn.ZIndex = 32
  1200.  
  1201. local MoveCancelBtn = UI.button(MoveFrame, {
  1202. text = "Cancelar",
  1203. sz = UDim2.new(0.5, -12, 0, 34),
  1204. pos = UDim2.new(0.5, 4, 1, -42),
  1205. bgColor = CLR.ACCENT_DIM,
  1206. hoverColor = CLR.ACCENT,
  1207. size = 13,
  1208. radius = 7,
  1209. })
  1210. MoveCancelBtn.ZIndex = 32
  1211.  
  1212. -- ============================================================
  1213. -- SEÇÃO 12 ► LÓGICA DE ESTADO E ATUALIZAÇÃO DA UI
  1214. -- ============================================================
  1215.  
  1216. -- Callbacks dos modais
  1217. local onConfirmYes = nil
  1218. local slotRenaming = nil
  1219. local slotMoving = nil
  1220.  
  1221. -- Atualiza o display do slot de destino
  1222. local function refreshSlotUI()
  1223. local n = State.saveSlot
  1224. local data = State.saves[n]
  1225. local disp = string.format("%02d", n)
  1226. SlotValueLbl.Text = disp
  1227. if data then
  1228. SlotStatusLbl.Text = "ocupado"
  1229. SlotStatusLbl.TextColor3 = CLR.WARNING
  1230. else
  1231. SlotStatusLbl.Text = "livre"
  1232. SlotStatusLbl.TextColor3 = CLR.SUCCESS
  1233. end
  1234. end
  1235.  
  1236. -- Atualiza os dots de paginação
  1237. local function refreshPageDots()
  1238. for i, dot in ipairs(PageDots) do
  1239. TweenService:Create(dot, CFG.TWEEN_FAST, {
  1240. BackgroundColor3 = (i == State.currentPage) and CLR.ACCENT or CLR.TEXT_MUTED,
  1241. Size = (i == State.currentPage)
  1242. and UDim2.new(0, 9, 0, 9)
  1243. or UDim2.new(0, 7, 0, 7),
  1244. }):Play()
  1245. end
  1246. end
  1247.  
  1248. -- Atualiza o label de página
  1249. local function refreshPageLabel()
  1250. PageLabel.Text = string.format("PÁGINA %d / %d", State.currentPage, CFG.MAX_PAGES)
  1251. end
  1252.  
  1253. -- Atualiza visibilidade do botão de posição principal
  1254. local function refreshMainPosUI()
  1255. MainPosContainer.Visible = (State.mainPos ~= nil)
  1256. end
  1257.  
  1258. -- Encontra o próximo slot vazio
  1259. local function findNextEmpty()
  1260. for i = 1, CFG.MAX_SAVES do
  1261. if not State.saves[i] then return i end
  1262. end
  1263. -- Se todos cheios, retorna o próximo após o atual
  1264. return (State.saveSlot % CFG.MAX_SAVES) + 1
  1265. end
  1266.  
  1267. local function advanceSlot()
  1268. State.saveSlot = findNextEmpty()
  1269. refreshSlotUI()
  1270. end
  1271.  
  1272. -- Mostra overlay de confirmação
  1273. local function showConfirm(message, yesText, callback)
  1274. ConfirmLabel.Text = message
  1275. ConfirmYesBtn.Text = yesText or "Confirmar"
  1276. onConfirmYes = callback
  1277. ConfirmOverlay.Visible = true
  1278. end
  1279.  
  1280. -- ────────────────────────────────────────────────
  1281. -- 12.1 ► RENDERIZAÇÃO DOS SLOTS (página atual)
  1282. -- ────────────────────────────────────────────────
  1283.  
  1284. local function buildSlot(slot)
  1285. local data = State.saves[slot]
  1286.  
  1287. local card = Instance.new("Frame")
  1288. card.Name = "Slot_" .. slot
  1289. card.LayoutOrder = slot
  1290. card.BackgroundColor3 = CLR.BG_CARD
  1291. card.BorderSizePixel = 0
  1292. card.ClipsDescendants = false
  1293. UI.corner(card, 7)
  1294.  
  1295. local cardStroke = UI.stroke(card, CLR.STROKE, 1)
  1296.  
  1297. if data then
  1298. -- ── Slot preenchido ───────────────────────────
  1299. local isMain = State.mainPos and typeof(State.mainPos.position) == "CFrame"
  1300. and State.mainPos.position == data.position
  1301.  
  1302. -- Indicador lateral colorido
  1303. local Accent = Instance.new("Frame")
  1304. Accent.Size = UDim2.new(0, 3, 1, -10)
  1305. Accent.Position = UDim2.new(0, 0, 0, 5)
  1306. Accent.BackgroundColor3 = isMain and CLR.GOLD or CLR.ACCENT
  1307. Accent.BorderSizePixel = 0
  1308. Accent.Parent = card
  1309. UI.corner(Accent, 2)
  1310.  
  1311. -- Número do slot (badge)
  1312. local SlotNumBg = Instance.new("Frame")
  1313. SlotNumBg.Size = UDim2.new(0, 24, 0, 18)
  1314. SlotNumBg.Position = UDim2.new(0, 7, 0.5, -9)
  1315. SlotNumBg.BackgroundColor3 = isMain and CLR.GOLD or CLR.ACCENT_DIM
  1316. SlotNumBg.BorderSizePixel = 0
  1317. SlotNumBg.Parent = card
  1318. UI.corner(SlotNumBg, 4)
  1319.  
  1320. local SlotNumLbl = UI.label(SlotNumBg, {
  1321. text = tostring(slot),
  1322. size = 9,
  1323. color = CLR.WHITE,
  1324. font = Enum.Font.GothamBold,
  1325. align = Enum.TextXAlignment.Center,
  1326. })
  1327.  
  1328. -- Nome da posição
  1329. local NameLbl = UI.label(card, {
  1330. text = data.name,
  1331. sz = UDim2.new(1, -105, 0, 22),
  1332. pos = UDim2.new(0, 38, 0, 4),
  1333. size = 12,
  1334. color = CLR.TEXT_PRI,
  1335. font = Enum.Font.GothamSemibold,
  1336. align = Enum.TextXAlignment.Left,
  1337. truncate = Enum.TextTruncate.AtEnd,
  1338. })
  1339.  
  1340. -- Timestamp
  1341. local TimeLbl = UI.label(card, {
  1342. text = data.timestamp,
  1343. sz = UDim2.new(1, -105, 0, 14),
  1344. pos = UDim2.new(0, 38, 0, 26),
  1345. size = 9,
  1346. color = CLR.TEXT_MUTED,
  1347. font = Enum.Font.Gotham,
  1348. align = Enum.TextXAlignment.Left,
  1349. })
  1350.  
  1351. -- Botão Teleportar
  1352. local TpBtn = UI.button(card, {
  1353. text = "TP",
  1354. sz = UDim2.new(0, 34, 0, 34),
  1355. pos = UDim2.new(1, -78, 0.5, -17),
  1356. bgColor = CLR.ACCENT,
  1357. hoverColor = CLR.ACCENT_HOV,
  1358. font = Enum.Font.GothamBold,
  1359. size = 13,
  1360. radius = 7,
  1361. })
  1362.  
  1363. -- Botão Favorito (estrela)
  1364. local StarBtn = UI.button(card, {
  1365. text = isMain and "★" or "☆",
  1366. sz = UDim2.new(0, 18, 0, 20),
  1367. pos = UDim2.new(1, -40, 0, 4),
  1368. bgColor = Color3.fromRGB(0,0,0),
  1369. textColor = isMain and CLR.GOLD or CLR.TEXT_DIM,
  1370. size = 14,
  1371. radius = 4,
  1372. })
  1373. StarBtn.BackgroundTransparency = 1
  1374. StarBtn.AutoButtonColor = false
  1375.  
  1376. -- Botão Menu de opções
  1377. local MenuBtn = UI.button(card, {
  1378. text = "⋮",
  1379. sz = UDim2.new(0, 18, 0, 20),
  1380. pos = UDim2.new(1, -40, 1, -24),
  1381. bgColor = Color3.fromRGB(0,0,0),
  1382. textColor = CLR.TEXT_DIM,
  1383. size = 15,
  1384. radius = 4,
  1385. })
  1386. MenuBtn.BackgroundTransparency = 1
  1387. MenuBtn.AutoButtonColor = false
  1388.  
  1389. -- Menu de opções flutuante (no ScreenGui para não ser cortado)
  1390. local OptionsMenu = Instance.new("Frame")
  1391. OptionsMenu.Name = "OptionsMenu_" .. slot
  1392. OptionsMenu.Size = UDim2.new(0, 130, 0, 102)
  1393. OptionsMenu.BackgroundColor3 = CLR.BG_MID
  1394. OptionsMenu.BackgroundTransparency = 0.04
  1395. OptionsMenu.Visible = false
  1396. OptionsMenu.ZIndex = 60
  1397. OptionsMenu.BorderSizePixel = 0
  1398. OptionsMenu.Parent = ScreenGui
  1399. UI.corner(OptionsMenu, 8)
  1400. UI.stroke(OptionsMenu, CLR.STROKE_BRIGHT, 1.5)
  1401.  
  1402. State.optionFrames[slot] = OptionsMenu
  1403.  
  1404. local function makeMenuOption(text, color, yPos)
  1405. local btn = UI.button(OptionsMenu, {
  1406. text = text,
  1407. sz = UDim2.new(1, -12, 0, 26),
  1408. pos = UDim2.new(0, 6, 0, yPos),
  1409. bgColor = CLR.BG_CARD,
  1410. hoverColor = CLR.BG_CARD_HOV,
  1411. textColor = color or CLR.TEXT_PRI,
  1412. font = Enum.Font.Gotham,
  1413. size = 12,
  1414. radius = 5,
  1415. })
  1416. btn.TextXAlignment = Enum.TextXAlignment.Left
  1417. btn.ZIndex = 61
  1418. -- Adiciona padding com label à esquerda
  1419. return btn
  1420. end
  1421.  
  1422. local RenameOpt = makeMenuOption(" ✏ Renomear", CLR.TEXT_PRI, 8)
  1423. local MoveOpt = makeMenuOption(" ↔ Mover", CLR.TEXT_PRI, 38)
  1424. local DeleteOpt = makeMenuOption(" 🗑 Excluir", CLR.DANGER, 68)
  1425.  
  1426. local menuOpen = false
  1427.  
  1428. local function closeMenu()
  1429. if not OptionsMenu.Parent then return end
  1430. OptionsMenu.Visible = false
  1431. menuOpen = false
  1432. end
  1433.  
  1434. local function openMenu()
  1435. UI.closeAllOptionMenus(OptionsMenu)
  1436. local absPos = MenuBtn.AbsolutePosition
  1437. local absSize = MenuBtn.AbsoluteSize
  1438. OptionsMenu.Position = UDim2.new(0,
  1439. absPos.X - 130 + absSize.X,
  1440. 0,
  1441. absPos.Y - 5
  1442. )
  1443. OptionsMenu.Visible = true
  1444. menuOpen = true
  1445. end
  1446.  
  1447. MenuBtn.MouseButton1Click:Connect(function()
  1448. if menuOpen then closeMenu() else openMenu() end
  1449. end)
  1450.  
  1451. -- Fecha menu ao clicar fora
  1452. UserInputService.InputBegan:Connect(function(input)
  1453. if not menuOpen then return end
  1454. if input.UserInputType == Enum.UserInputType.MouseButton1 then
  1455. task.wait(0.05)
  1456. if not OptionsMenu.Visible then return end
  1457. local mp = UserInputService:GetMouseLocation()
  1458. local fp = OptionsMenu.AbsolutePosition
  1459. local fs = OptionsMenu.AbsoluteSize
  1460. if mp.X < fp.X or mp.X > fp.X + fs.X
  1461. or mp.Y < fp.Y or mp.Y > fp.Y + fs.Y then
  1462. closeMenu()
  1463. end
  1464. end
  1465. end)
  1466.  
  1467. -- Hover visual no card
  1468. card.MouseEnter:Connect(function()
  1469. TweenService:Create(card, CFG.TWEEN_FAST,
  1470. {BackgroundColor3 = CLR.BG_CARD_HOV}):Play()
  1471. TweenService:Create(cardStroke, CFG.TWEEN_FAST,
  1472. {Color = CLR.STROKE_BRIGHT}):Play()
  1473. end)
  1474. card.MouseLeave:Connect(function()
  1475. TweenService:Create(card, CFG.TWEEN_FAST,
  1476. {BackgroundColor3 = CLR.BG_CARD}):Play()
  1477. TweenService:Create(cardStroke, CFG.TWEEN_FAST,
  1478. {Color = CLR.STROKE}):Play()
  1479. end)
  1480.  
  1481. -- Ações dos botões
  1482. TpBtn.MouseButton1Click:Connect(function()
  1483. if Teleport.to(data.position) then
  1484. TpBtn.Text = "✓"
  1485. TweenService:Create(TpBtn, CFG.TWEEN_FAST,
  1486. {BackgroundColor3 = CLR.SUCCESS}):Play()
  1487. task.wait(1.2)
  1488. if TpBtn.Parent then
  1489. TpBtn.Text = "TP"
  1490. TweenService:Create(TpBtn, CFG.TWEEN_FAST,
  1491. {BackgroundColor3 = CLR.ACCENT}):Play()
  1492. end
  1493. end
  1494. end)
  1495.  
  1496. StarBtn.MouseButton1Click:Connect(function()
  1497. if isMain then
  1498. showConfirm(
  1499. "Remover esta posição principal?",
  1500. "Remover",
  1501. function()
  1502. State.mainPos = nil
  1503. Persist.deleteMain()
  1504. refreshMainPosUI()
  1505. -- Força re-render da lista
  1506. task.defer(function()
  1507. local rebuilder = ScreenGui:FindFirstChild("__rebuild")
  1508. if rebuilder then rebuilder:Fire() end
  1509. end)
  1510. end
  1511. )
  1512. else
  1513. local hasMain = State.mainPos ~= nil
  1514. showConfirm(
  1515. hasMain and "Substituir a posição principal atual?"
  1516. or "Definir esta posição como principal?",
  1517. "Sim",
  1518. function()
  1519. State.mainPos = {
  1520. position = data.position,
  1521. name = data.name,
  1522. timestamp = data.timestamp,
  1523. }
  1524. Persist.scheduleSave()
  1525. refreshMainPosUI()
  1526. task.defer(function()
  1527. local rebuilder = ScreenGui:FindFirstChild("__rebuild")
  1528. if rebuilder then rebuilder:Fire() end
  1529. end)
  1530. end
  1531. )
  1532. end
  1533. end)
  1534.  
  1535. RenameOpt.MouseButton1Click:Connect(function()
  1536. closeMenu()
  1537. slotRenaming = slot
  1538. RenameField.Text = data.name
  1539. RenameOverlay.Visible = true
  1540. end)
  1541.  
  1542. MoveOpt.MouseButton1Click:Connect(function()
  1543. closeMenu()
  1544. slotMoving = slot
  1545. MoveInput.Text = ""
  1546. MoveOverlay.Visible = true
  1547. end)
  1548.  
  1549. DeleteOpt.MouseButton1Click:Connect(function()
  1550. closeMenu()
  1551. showConfirm(
  1552. string.format("Excluir o Slot %d \"%s\" ?", slot, data.name),
  1553. "Excluir",
  1554. function()
  1555. State.saves[slot] = nil
  1556. Persist.scheduleSave()
  1557. showToast("Slot " .. slot .. " excluído", "info")
  1558. advanceSlot()
  1559. -- Re-render
  1560. local rebuilder = ScreenGui:FindFirstChild("__rebuild")
  1561. if rebuilder then rebuilder:Fire() end
  1562. end
  1563. )
  1564. end)
  1565.  
  1566. else
  1567. -- ── Slot vazio ────────────────────────────────
  1568. local EmptyLbl = UI.label(card, {
  1569. text = string.format("Slot %02d — vazio", slot),
  1570. sz = UDim2.new(1, -10, 1, 0),
  1571. pos = UDim2.new(0, 10, 0, 0),
  1572. size = 12,
  1573. color = CLR.TEXT_MUTED,
  1574. font = Enum.Font.Gotham,
  1575. align = Enum.TextXAlignment.Left,
  1576. })
  1577.  
  1578. -- Destaca slot de destino atual
  1579. if slot == State.saveSlot then
  1580. cardStroke.Color = CLR.ACCENT
  1581. cardStroke.Thickness = 1.5
  1582. EmptyLbl.TextColor3 = CLR.ACCENT
  1583. EmptyLbl.Text = string.format("▶ Slot %02d — selecionado", slot)
  1584. end
  1585. end
  1586.  
  1587. return card
  1588. end
  1589.  
  1590. -- Renderiza a página atual
  1591. local function renderPage()
  1592. -- Limpa slots anteriores
  1593. for _, child in ipairs(SlotsFrame:GetChildren()) do
  1594. if child:IsA("Frame") then
  1595. child:Destroy()
  1596. end
  1597. end
  1598.  
  1599. -- Limpa menus de opções órfãos
  1600. for slot, frame in pairs(State.optionFrames) do
  1601. if frame and frame.Parent then
  1602. frame:Destroy()
  1603. end
  1604. end
  1605. State.optionFrames = {}
  1606.  
  1607. local startSlot = (State.currentPage - 1) * CFG.SLOTS_PER_PAGE + 1
  1608. local endSlot = State.currentPage * CFG.SLOTS_PER_PAGE
  1609.  
  1610. for slot = startSlot, endSlot do
  1611. local card = buildSlot(slot)
  1612. card.Parent = SlotsFrame
  1613. end
  1614.  
  1615. refreshPageDots()
  1616. refreshPageLabel()
  1617. end
  1618.  
  1619. -- Ponto de re-render global (via BindableEvent)
  1620. local RebuildEvent = Instance.new("BindableEvent")
  1621. RebuildEvent.Name = "__rebuild"
  1622. RebuildEvent.Parent = ScreenGui
  1623. RebuildEvent.Event:Connect(renderPage)
  1624.  
  1625. -- ============================================================
  1626. -- SEÇÃO 13 ► CONEXÕES DE CONTROLES
  1627. -- ============================================================
  1628.  
  1629. -- ── Fechar / Abrir janela ─────────────────────
  1630. CloseBtn.MouseButton1Click:Connect(function()
  1631. TweenService:Create(MainFrame, CFG.TWEEN_MED, {
  1632. Size = UDim2.new(0, 590, 0, 0),
  1633. Position = UDim2.new(0.5, -295, 0.5, 0),
  1634. }):Play()
  1635. task.wait(0.3)
  1636. MainFrame.Visible = false
  1637. MainFrame.Size = UDim2.new(0, 590, 0, 470)
  1638. MainFrame.Position = UDim2.new(0.5, -295, 0.5, -235)
  1639. end)
  1640.  
  1641. FloatBtn.MouseButton1Click:Connect(function()
  1642. MainFrame.Size = UDim2.new(0, 590, 0, 0)
  1643. MainFrame.Position = UDim2.new(0.5, -295, 0.5, 0)
  1644. MainFrame.Visible = true
  1645. TweenService:Create(MainFrame, CFG.TWEEN_MED, {
  1646. Size = UDim2.new(0, 590, 0, 470),
  1647. Position = UDim2.new(0.5, -295, 0.5, -235),
  1648. }):Play()
  1649. end)
  1650.  
  1651. MainFrame:GetPropertyChangedSignal("Visible"):Connect(function()
  1652. FloatContainer.Visible = not MainFrame.Visible
  1653. end)
  1654.  
  1655. -- ── Paginação ────────────────────────────────
  1656. local function changePage(delta)
  1657. local newPage = State.currentPage + delta
  1658. if newPage < 1 then newPage = CFG.MAX_PAGES end
  1659. if newPage > CFG.MAX_PAGES then newPage = 1 end
  1660. State.currentPage = newPage
  1661. renderPage()
  1662. end
  1663.  
  1664. PagePrevBtn.MouseButton1Click:Connect(function() changePage(-1) end)
  1665. PageNextBtn.MouseButton1Click:Connect(function() changePage( 1) end)
  1666.  
  1667. -- ── Seletor de Slot ───────────────────────────
  1668. SlotPrevBtn.MouseButton1Click:Connect(function()
  1669. State.saveSlot = ((State.saveSlot - 2 + CFG.MAX_SAVES) % CFG.MAX_SAVES) + 1
  1670. refreshSlotUI()
  1671. renderPage()
  1672. end)
  1673.  
  1674. SlotNextBtn.MouseButton1Click:Connect(function()
  1675. State.saveSlot = (State.saveSlot % CFG.MAX_SAVES) + 1
  1676. refreshSlotUI()
  1677. renderPage()
  1678. end)
  1679.  
  1680. -- ── Botão Salvar ──────────────────────────────
  1681. local function doSave()
  1682. if not root then return false end
  1683. local name = (NameBox.Text ~= "" and NameBox.Text) or ("Slot " .. State.saveSlot)
  1684. State.saves[State.saveSlot] = {
  1685. position = root.CFrame,
  1686. name = name,
  1687. timestamp = os.date("%Y-%m-%d %H:%M:%S"),
  1688. }
  1689. Persist.scheduleSave()
  1690.  
  1691. -- Navega para a página do slot salvo
  1692. local targetPage = math.ceil(State.saveSlot / CFG.SLOTS_PER_PAGE)
  1693. if targetPage ~= State.currentPage then
  1694. State.currentPage = targetPage
  1695. end
  1696.  
  1697. renderPage()
  1698. showToast(string.format("✓ Salvo no Slot %d", State.saveSlot), "success")
  1699. advanceSlot()
  1700. return true
  1701. end
  1702.  
  1703. SaveBtn.MouseButton1Click:Connect(function()
  1704. if State.saves[State.saveSlot] then
  1705. showConfirm(
  1706. string.format("O Slot %d já tem uma posição.\nDeseja substituir?", State.saveSlot),
  1707. "Substituir",
  1708. function()
  1709. doSave()
  1710. end
  1711. )
  1712. else
  1713. doSave()
  1714. end
  1715. end)
  1716.  
  1717. -- ── Botão Posição Principal (TP) ──────────────
  1718. MainPosBtn.MouseButton1Click:Connect(function()
  1719. if State.mainPos and Teleport.to(State.mainPos.position) then
  1720. MainPosBtn.Text = "✓"
  1721. TweenService:Create(MainPosBtn, CFG.TWEEN_FAST,
  1722. {BackgroundColor3 = CLR.SUCCESS}):Play()
  1723. task.wait(1)
  1724. if MainPosBtn.Parent then
  1725. MainPosBtn.Text = "🚀"
  1726. TweenService:Create(MainPosBtn, CFG.TWEEN_FAST,
  1727. {BackgroundColor3 = CLR.BG_MID}):Play()
  1728. end
  1729. end
  1730. end)
  1731.  
  1732. MainPosBtn.MouseEnter:Connect(function()
  1733. if State.mainPos then
  1734. TooltipLabel.Text = State.mainPos.name or "Principal"
  1735. MainPosTooltip.Visible = true
  1736. MainPosRemoveBtn.Visible = true
  1737. end
  1738. TweenService:Create(MainPosStroke, CFG.TWEEN_FAST, {Thickness = 3}):Play()
  1739. TweenService:Create(MainPosBtn, CFG.TWEEN_FAST,
  1740. {Size = UDim2.new(1.1, 0, 1.1, 0)}):Play()
  1741. end)
  1742.  
  1743. MainPosBtn.MouseLeave:Connect(function()
  1744. MainPosTooltip.Visible = false
  1745. MainPosRemoveBtn.Visible = false
  1746. TweenService:Create(MainPosStroke, CFG.TWEEN_FAST, {Thickness = 2}):Play()
  1747. TweenService:Create(MainPosBtn, CFG.TWEEN_FAST,
  1748. {Size = UDim2.new(1, 0, 1, 0)}):Play()
  1749. end)
  1750.  
  1751. MainPosRemoveBtn.MouseButton1Click:Connect(function()
  1752. showConfirm(
  1753. "Remover a posição principal?",
  1754. "Remover",
  1755. function()
  1756. State.mainPos = nil
  1757. Persist.deleteMain()
  1758. refreshMainPosUI()
  1759. renderPage()
  1760. end
  1761. )
  1762. end)
  1763.  
  1764. -- ── Confirmação ───────────────────────────────
  1765. ConfirmYesBtn.MouseButton1Click:Connect(function()
  1766. if onConfirmYes then onConfirmYes() end
  1767. onConfirmYes = nil
  1768. ConfirmOverlay.Visible = false
  1769. end)
  1770.  
  1771. ConfirmNoBtn.MouseButton1Click:Connect(function()
  1772. onConfirmYes = nil
  1773. ConfirmOverlay.Visible = false
  1774. end)
  1775.  
  1776. -- ── Renomear ──────────────────────────────────
  1777. RenameConfirmBtn.MouseButton1Click:Connect(function()
  1778. local newName = RenameField.Text
  1779. if not slotRenaming or newName == "" then return end
  1780.  
  1781. local data = State.saves[slotRenaming]
  1782. if data then
  1783. data.name = newName
  1784. -- Atualiza posição principal se for o mesmo
  1785. if State.mainPos and State.mainPos.position == data.position then
  1786. State.mainPos.name = newName
  1787. end
  1788. Persist.scheduleSave()
  1789. renderPage()
  1790. showToast("✏ Slot " .. slotRenaming .. " renomeado", "info")
  1791. end
  1792.  
  1793. RenameOverlay.Visible = false
  1794. slotRenaming = nil
  1795. end)
  1796.  
  1797. RenameCancelBtn.MouseButton1Click:Connect(function()
  1798. RenameOverlay.Visible = false
  1799. slotRenaming = nil
  1800. end)
  1801.  
  1802. -- ── Mover ─────────────────────────────────────
  1803. MoveConfirmBtn.MouseButton1Click:Connect(function()
  1804. local target = tonumber(MoveInput.Text)
  1805. if not slotMoving or not target then return end
  1806. if target < 1 or target > CFG.MAX_SAVES or target ~= math.floor(target) then
  1807. MoveInput.Text = ""
  1808. MoveInput.PlaceholderText = "Inválido! (1-50)"
  1809. task.delay(1.5, function()
  1810. MoveInput.PlaceholderText = "1 – 50"
  1811. end)
  1812. return
  1813. end
  1814.  
  1815. local from = slotMoving
  1816. local to = target
  1817.  
  1818. if from == to then
  1819. MoveOverlay.Visible = false
  1820. slotMoving = nil
  1821. return
  1822. end
  1823.  
  1824. -- Swap
  1825. if State.saves[to] then
  1826. local temp = State.saves[from]
  1827. State.saves[from] = State.saves[to]
  1828. State.saves[to] = temp
  1829. else
  1830. State.saves[to] = State.saves[from]
  1831. State.saves[from] = nil
  1832. end
  1833.  
  1834. Persist.scheduleSave()
  1835.  
  1836. -- Navega para a página do slot de destino
  1837. local targetPage = math.ceil(to / CFG.SLOTS_PER_PAGE)
  1838. State.currentPage = targetPage
  1839.  
  1840. renderPage()
  1841. showToast(string.format("↔ Slot %d → Slot %d", from, to), "info")
  1842. MoveOverlay.Visible = false
  1843. slotMoving = nil
  1844. end)
  1845.  
  1846. MoveCancelBtn.MouseButton1Click:Connect(function()
  1847. MoveOverlay.Visible = false
  1848. slotMoving = nil
  1849. end)
  1850.  
  1851. -- ── Teclado: Enter confirma campos ────────────
  1852. RenameField.FocusLost:Connect(function(enterPressed)
  1853. if enterPressed then RenameConfirmBtn.MouseButton1Click:Fire() end
  1854. end)
  1855.  
  1856. MoveInput.FocusLost:Connect(function(enterPressed)
  1857. if enterPressed then MoveConfirmBtn.MouseButton1Click:Fire() end
  1858. end)
  1859.  
  1860. -- ============================================================
  1861. -- SEÇÃO 14 ► EVENTOS DE CICLO DE VIDA
  1862. -- ============================================================
  1863.  
  1864. -- Respawn: atualiza referências do personagem
  1865. plr.CharacterAdded:Connect(function(character)
  1866. chr = character
  1867. root = character:WaitForChild("HumanoidRootPart")
  1868. end)
  1869.  
  1870. -- Salva ao fechar executor
  1871. game:BindToClose(Persist.save)
  1872.  
  1873. -- Salva periodicamente (a cada 60s) como segurança extra
  1874. task.spawn(function()
  1875. while task.wait(60) do
  1876. if State.isDirty then
  1877. Persist.save()
  1878. end
  1879. end
  1880. end)
  1881.  
  1882. -- ============================================================
  1883. -- SEÇÃO 15 ► INICIALIZAÇÃO
  1884. -- ============================================================
  1885.  
  1886. Persist.load()
  1887. refreshSlotUI()
  1888. refreshMainPosUI()
  1889. renderPage()
  1890.  
  1891. -- Log de inicialização
  1892. print(string.format([[
  1893. ╔══════════════════════════════════════════════════════╗
  1894. ║ ✦ Save Locate (NickZ) V%s — MEGA UPDATE ║
  1895. ║ ┌─────────────────────────────────────────────────┐ ║
  1896. ║ │ Slots : %d (5 páginas × 10) │ ║
  1897. ║ │ Saves : %d carregados do disco │ ║
  1898. ║ │ FS : %s │ ║
  1899. ║ │ Teleport: Hard-TP Anti-Bug ativo │ ║
  1900. ║ └─────────────────────────────────────────────────┘ ║
  1901. ╚══════════════════════════════════════════════════════╝
  1902. ]], CFG.VERSION,
  1903. CFG.MAX_SAVES,
  1904. (function() local n=0; for _ in pairs(State.saves) do n=n+1 end; return n end)(),
  1905. FS.active and "Ativo (leitura+escrita)" or "Inativo (sem suporte)"
  1906. ))
Add Comment
Please, Sign In to add comment