Nevzyn

Untitled

Mar 8th, 2026
20
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 61.21 KB | None | 0 0
  1. --[[
  2. ╔══════════════════════════════════════════════════════════════╗
  3. ║ SAVE LOCATE (NickZ) - v5.0 ULTIMATE ║
  4. ║ ║
  5. ║ • 50 Slots de Salvamento (5 Páginas) ║
  6. ║ • Sistema de Posição Principal ║
  7. ║ • Teleporte Anti-Bug/Anti-Animação Avançado ║
  8. ║ • Sistema de Arquivos Multiplataforma ║
  9. ║ • Interface Moderna e Otimizada ║
  10. ║ • Código Modular e Altamente Otimizado ║
  11. ╚══════════════════════════════════════════════════════════════╝
  12. ]]
  13.  
  14. --==============================================================================
  15. -- [1] INICIALIZAÇÃO E ESPERA DO JOGO
  16. --==============================================================================
  17. if not game or not game:IsLoaded() then
  18. game.Loaded:Wait()
  19. end
  20.  
  21. repeat task.wait() until game:IsLoaded()
  22.  
  23. --==============================================================================
  24. -- [2] SERVIÇOS (CACHE PARA PERFORMANCE)
  25. --==============================================================================
  26. local Services = {
  27. Players = game:GetService("Players"),
  28. HttpService = game:GetService("HttpService"),
  29. TweenService = game:GetService("TweenService"),
  30. UserInputService = game:GetService("UserInputService"),
  31. RunService = game:GetService("RunService"),
  32. CoreGui = game:GetService("CoreGui")
  33. }
  34.  
  35. --==============================================================================
  36. -- [3] VARIÁVEIS GLOBAIS E CONFIGURAÇÃO
  37. --==============================================================================
  38. local Config = {
  39. MAX_SAVES = 50,
  40. SLOTS_PER_PAGE = 10,
  41. MAX_PAGES = 5,
  42. SAVE_DEBOUNCE = 0.5, -- Evita salvamentos múltiplos rápidos
  43. TWEEN_SPEED = 0.2,
  44. ANIMATION_INFO = TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
  45. }
  46.  
  47. local State = {
  48. savedPositions = {},
  49. currentPage = 1,
  50. currentSaveSlot = 1,
  51. mainPosition = nil,
  52. lastSaveTime = 0,
  53. isInitialized = false
  54. }
  55.  
  56. local Player = {
  57. instance = Services.Players.LocalPlayer,
  58. character = nil,
  59. humanoidRoot = nil,
  60. userId = Services.Players.LocalPlayer.UserId,
  61. userName = Services.Players.LocalPlayer.Name
  62. }
  63.  
  64. --==============================================================================
  65. -- [4] SISTEMA DE ARQUIVOS (MULTIPLATAFORMA)
  66. --==============================================================================
  67. local FileSystem = {}
  68.  
  69. do
  70. -- Verificação de capacidades do executor
  71. FileSystem.capabilities = {
  72. write = (type(writefile) == "function"),
  73. read = (type(readfile) == "function"),
  74. folder = (type(isfolder) == "function" and type(makefolder) == "function"),
  75. isFile = (type(isfile) == "function"),
  76. delete = (type(delfile) == "function")
  77. }
  78.  
  79. FileSystem.hasFS = (FileSystem.capabilities.write and FileSystem.capabilities.read)
  80.  
  81. -- Configuração de diretórios
  82. local SAVE_DIR = "SaveLocate_NickZ"
  83. local GAME_DIR = tostring(game.PlaceId)
  84.  
  85. if FileSystem.capabilities.folder then
  86. if not isfolder(SAVE_DIR) then
  87. pcall(makefolder, SAVE_DIR)
  88. end
  89. if not isfolder(SAVE_DIR .. "/" .. GAME_DIR) then
  90. pcall(makefolder, SAVE_DIR .. "/" .. GAME_DIR)
  91. end
  92. end
  93.  
  94. -- Nomes de arquivo
  95. local function generatePaths()
  96. local baseName = string.format("Saves_%s.json", Player.userId)
  97. local mainName = string.format("MainPos_%s.json", Player.userId)
  98. local baseBak = string.format("Saves_%s.bak", Player.userId)
  99. local mainBak = string.format("MainPos_%s.bak", Player.userId)
  100.  
  101. if FileSystem.capabilities.folder then
  102. return {
  103. save = SAVE_DIR .. "/" .. GAME_DIR .. "/" .. baseName,
  104. main = SAVE_DIR .. "/" .. GAME_DIR .. "/" .. mainName,
  105. saveBak = SAVE_DIR .. "/" .. GAME_DIR .. "/" .. baseBak,
  106. mainBak = SAVE_DIR .. "/" .. GAME_DIR .. "/" .. mainBak
  107. }
  108. else
  109. return {
  110. save = string.format("SaveLocate_%d_%s.json", game.PlaceId, Player.userId),
  111. main = string.format("MainPos_%d_%s.json", game.PlaceId, Player.userId),
  112. saveBak = string.format("SaveLocate_%d_%s.bak", game.PlaceId, Player.userId),
  113. mainBak = string.format("MainPos_%d_%s.bak", game.PlaceId, Player.userId)
  114. }
  115. end
  116. end
  117.  
  118. FileSystem.paths = generatePaths()
  119.  
  120. -- Funções auxiliares
  121. function FileSystem:tryRead(path)
  122. if not self.hasFS or type(path) ~= "string" then return nil end
  123. local success, content = pcall(readfile, path)
  124. return (success and type(content) == "string" and #content > 0) and content or nil
  125. end
  126.  
  127. function FileSystem:tryWrite(path, content)
  128. if not self.hasFS or type(path) ~= "string" or type(content) ~= "string" then
  129. return false
  130. end
  131. local success = pcall(writefile, path, content)
  132. return success
  133. end
  134.  
  135. function FileSystem:getCandidatePaths(fileType)
  136. local paths = {}
  137. if fileType == "save" then
  138. table.insert(paths, self.paths.save)
  139. table.insert(paths, self.paths.saveBak)
  140. elseif fileType == "main" then
  141. table.insert(paths, self.paths.main)
  142. table.insert(paths, self.paths.mainBak)
  143. end
  144. return paths
  145. end
  146.  
  147. function FileSystem:findExistingContent(fileType)
  148. local candidates = self:getCandidatePaths(fileType)
  149. for _, path in ipairs(candidates) do
  150. local content = self:tryRead(path)
  151. if content then
  152. return content, path
  153. end
  154. end
  155. return nil, nil
  156. end
  157. end
  158.  
  159. --==============================================================================
  160. -- [5] CODIFICAÇÃO CFRAME (OTIMIZADO)
  161. --==============================================================================
  162. local CFrameUtils = {}
  163.  
  164. function CFrameUtils.encode(cf)
  165. if typeof(cf) ~= "CFrame" then return nil end
  166. local x, y, z, R00, R01, R02, R10, R11, R12, R20, R21, R22 = cf:GetComponents()
  167. return {
  168. x = x, y = y, z = z,
  169. R00 = R00, R01 = R01, R02 = R02,
  170. R10 = R10, R11 = R11, R12 = R12,
  171. R20 = R20, R21 = R21, R22 = R22
  172. }
  173. end
  174.  
  175. function CFrameUtils.decode(data)
  176. if type(data) ~= "table" or not data.x or not data.R00 then return nil end
  177. return CFrame.new(
  178. data.x, data.y, data.z,
  179. data.R00, data.R01, data.R02,
  180. data.R10, data.R11, data.R12,
  181. data.R20, data.R21, data.R22
  182. )
  183. end
  184.  
  185. --==============================================================================
  186. -- [6] SISTEMA DE PERSISTÊNCIA (COM DEBOUNCE)
  187. --==============================================================================
  188. local Persistence = {}
  189.  
  190. do
  191. local saveQueue = false
  192.  
  193. function Persistence:saveMainPosition()
  194. if not FileSystem.hasFS or not State.mainPosition then return end
  195.  
  196. local data = {
  197. position = CFrameUtils.encode(State.mainPosition.position),
  198. name = State.mainPosition.name,
  199. timestamp = State.mainPosition.timestamp,
  200. gameId = game.PlaceId,
  201. gameName = game.Name
  202. }
  203.  
  204. local success, encoded = pcall(function()
  205. return Services.HttpService:JSONEncode(data)
  206. end)
  207.  
  208. if success and encoded then
  209. FileSystem:tryWrite(FileSystem.paths.main, encoded)
  210. FileSystem:tryWrite(FileSystem.paths.mainBak, encoded)
  211. end
  212. end
  213.  
  214. function Persistence:loadMainPosition()
  215. if not FileSystem.hasFS then return end
  216.  
  217. local content, usedPath = FileSystem:findExistingContent("main")
  218. if not content then return end
  219.  
  220. local success, data = pcall(function()
  221. return Services.HttpService:JSONDecode(content)
  222. end)
  223.  
  224. if not success or type(data) ~= "table" then return end
  225. if data.gameId and data.gameId ~= game.PlaceId then return end
  226.  
  227. local cf = CFrameUtils.decode(data.position)
  228. if cf then
  229. State.mainPosition = {
  230. position = cf,
  231. name = data.name or "Posição Principal",
  232. timestamp = data.timestamp or os.date("%Y-%m-%d %H:%M:%S")
  233. }
  234.  
  235. if usedPath ~= FileSystem.paths.main then
  236. self:saveMainPosition()
  237. end
  238. end
  239. end
  240.  
  241. function Persistence:saveToDisk()
  242. if not FileSystem.hasFS then return end
  243.  
  244. -- Debounce para evitar salvamentos excessivos
  245. local currentTime = tick()
  246. if currentTime - State.lastSaveTime < Config.SAVE_DEBOUNCE then
  247. saveQueue = true
  248. return
  249. end
  250.  
  251. State.lastSaveTime = currentTime
  252. saveQueue = false
  253.  
  254. local data = {
  255. gameId = game.PlaceId,
  256. gameName = game.Name,
  257. userId = Player.userId,
  258. userName = Player.userName,
  259. saveDate = os.date("%Y-%m-%d %H:%M:%S"),
  260. version = "5.0",
  261. positions = {}
  262. }
  263.  
  264. for slot, slotData in pairs(State.savedPositions) do
  265. if type(slot) == "number" and slot >= 1 and slot <= Config.MAX_SAVES then
  266. if typeof(slotData.position) == "CFrame" then
  267. data.positions[tostring(slot)] = {
  268. name = slotData.name or ("Slot " .. slot),
  269. timestamp = slotData.timestamp or os.date("%Y-%m-%d %H:%M:%S"),
  270. position = CFrameUtils.encode(slotData.position)
  271. }
  272. end
  273. end
  274. end
  275.  
  276. local success, encoded = pcall(function()
  277. return Services.HttpService:JSONEncode(data)
  278. end)
  279.  
  280. if success and encoded then
  281. FileSystem:tryWrite(FileSystem.paths.save, encoded)
  282. FileSystem:tryWrite(FileSystem.paths.saveBak, encoded)
  283. end
  284.  
  285. self:saveMainPosition()
  286.  
  287. -- Processar fila se houver
  288. if saveQueue then
  289. task.delay(Config.SAVE_DEBOUNCE, function()
  290. self:saveToDisk()
  291. end)
  292. end
  293. end
  294.  
  295. function Persistence:loadFromDisk()
  296. if not FileSystem.hasFS then return end
  297.  
  298. local content, usedPath = FileSystem:findExistingContent("save")
  299. if not content then
  300. self:loadMainPosition()
  301. return
  302. end
  303.  
  304. local success, data = pcall(function()
  305. return Services.HttpService:JSONDecode(content)
  306. end)
  307.  
  308. if not success or type(data) ~= "table" then
  309. self:loadMainPosition()
  310. return
  311. end
  312.  
  313. local positions = data.positions or data
  314. if data.gameId and data.gameId ~= game.PlaceId then
  315. self:loadMainPosition()
  316. return
  317. end
  318.  
  319. for key, value in pairs(positions) do
  320. local slot = tonumber(key)
  321. if slot and slot >= 1 and slot <= Config.MAX_SAVES and type(value) == "table" then
  322. local cf = CFrameUtils.decode(value.position)
  323. if cf then
  324. State.savedPositions[slot] = {
  325. position = cf,
  326. name = value.name or ("Slot " .. slot),
  327. timestamp = value.timestamp or os.date("%Y-%m-%d %H:%M:%S")
  328. }
  329. end
  330. end
  331. end
  332.  
  333. if usedPath ~= FileSystem.paths.save then
  334. self:saveToDisk()
  335. end
  336.  
  337. self:loadMainPosition()
  338. end
  339. end
  340.  
  341. --==============================================================================
  342. -- [7] SISTEMA DE TELEPORTE AVANÇADO (ANTI-BUG)
  343. --==============================================================================
  344. local Teleport = {}
  345.  
  346. function Teleport:updateCharacterReferences()
  347. Player.character = Player.instance.Character or Player.instance.CharacterAdded:Wait()
  348. Player.humanoidRoot = Player.character:WaitForChild("HumanoidRootPart", 5)
  349. return Player.humanoidRoot ~= nil
  350. end
  351.  
  352. function Teleport:execute(targetCFrame)
  353. if typeof(targetCFrame) ~= "CFrame" then return false end
  354.  
  355. -- Atualiza referências se necessário
  356. if not Player.humanoidRoot or not Player.humanoidRoot.Parent then
  357. if not self:updateCharacterReferences() then
  358. return false
  359. end
  360. end
  361.  
  362. local hrp = Player.humanoidRoot
  363. local humanoid = Player.character:FindFirstChildWhichIsA("Humanoid")
  364.  
  365. -- Método de teleporte robusto em múltiplas etapas
  366. local function hardTeleport(cf)
  367. -- 1. Força sair de assentos
  368. if humanoid and humanoid.SeatPart then
  369. humanoid.Sit = false
  370. task.wait(0.1)
  371. end
  372.  
  373. -- 2. Ancoragem e limpeza de velocidade
  374. local originalAnchor = hrp.Anchored
  375. hrp.Anchored = true
  376.  
  377. if hrp:IsA("BasePart") then
  378. hrp.Velocity = Vector3.zero
  379. hrp.RotVelocity = Vector3.zero
  380. hrp.AssemblyLinearVelocity = Vector3.zero
  381. hrp.AssemblyAngularVelocity = Vector3.zero
  382. end
  383.  
  384. -- 3. Aplicação do CFrame (dupla para segurança)
  385. hrp.CFrame = cf
  386. Services.RunService.Heartbeat:Wait()
  387. hrp.CFrame = cf
  388.  
  389. -- 4. Aguarda sincronização física
  390. task.wait(0.05)
  391.  
  392. -- 5. Restaura estado
  393. hrp.Anchored = originalAnchor
  394.  
  395. return true
  396. end
  397.  
  398. return pcall(hardTeleport, targetCFrame)
  399. end
  400.  
  401. --==============================================================================
  402. -- [8] INTERFACE - CORES E TEMAS (REFINADO)
  403. --==============================================================================
  404. local Theme = {
  405. -- Cores principais
  406. Primary = Color3.fromRGB(120, 90, 255),
  407. PrimaryHover = Color3.fromRGB(140, 110, 255),
  408.  
  409. -- Backgrounds
  410. Background = Color3.fromRGB(20, 18, 28),
  411. BackgroundSecondary = Color3.fromRGB(30, 28, 42),
  412. BackgroundTertiary = Color3.fromRGB(40, 38, 55),
  413.  
  414. -- Gradientes
  415. GradientStart = Color3.fromRGB(25, 22, 38),
  416. GradientEnd = Color3.fromRGB(45, 40, 65),
  417.  
  418. -- Textos
  419. TextPrimary = Color3.fromRGB(255, 255, 255),
  420. TextSecondary = Color3.fromRGB(200, 200, 255),
  421. TextDisabled = Color3.fromRGB(130, 130, 160),
  422.  
  423. -- Estados
  424. Success = Color3.fromRGB(80, 200, 120),
  425. SuccessHover = Color3.fromRGB(100, 220, 140),
  426. Error = Color3.fromRGB(220, 80, 80),
  427. ErrorHover = Color3.fromRGB(240, 100, 100),
  428. Warning = Color3.fromRGB(255, 180, 80),
  429.  
  430. -- Bordas
  431. Stroke = Color3.fromRGB(120, 90, 255),
  432. StrokeSecondary = Color3.fromRGB(80, 70, 130),
  433.  
  434. -- Especiais
  435. Gold = Color3.fromRGB(255, 215, 0),
  436. SlotEmpty = Color3.fromRGB(100, 100, 120)
  437. }
  438.  
  439. --==============================================================================
  440. -- [9] UTILITÁRIOS DE UI (OTIMIZADO)
  441. --==============================================================================
  442. local UIUtils = {}
  443.  
  444. function UIUtils.createCorner(parent, radius)
  445. local corner = Instance.new("UICorner")
  446. corner.CornerRadius = UDim.new(0, radius or 8)
  447. corner.Parent = parent
  448. return corner
  449. end
  450.  
  451. function UIUtils.createStroke(parent, color, thickness)
  452. local stroke = Instance.new("UIStroke")
  453. stroke.Color = color or Theme.Stroke
  454. stroke.Thickness = thickness or 1.5
  455. stroke.Parent = parent
  456. return stroke
  457. end
  458.  
  459. function UIUtils.createGradient(parent, colorSequence, rotation)
  460. local gradient = Instance.new("UIGradient")
  461. gradient.Color = colorSequence or ColorSequence.new({
  462. ColorSequenceKeypoint.new(0, Theme.GradientStart),
  463. ColorSequenceKeypoint.new(1, Theme.GradientEnd)
  464. })
  465. gradient.Rotation = rotation or 90
  466. gradient.Parent = parent
  467. return gradient
  468. end
  469.  
  470. function UIUtils.animateHover(button, hoverColor, normalColor)
  471. local normalBg = normalColor or button.BackgroundColor3
  472. local hoverBg = hoverColor or Theme.PrimaryHover
  473.  
  474. local enterConn = button.MouseEnter:Connect(function()
  475. Services.TweenService:Create(button, Config.ANIMATION_INFO, {
  476. BackgroundColor3 = hoverBg
  477. }):Play()
  478. end)
  479.  
  480. local leaveConn = button.MouseLeave:Connect(function()
  481. Services.TweenService:Create(button, Config.ANIMATION_INFO, {
  482. BackgroundColor3 = normalBg
  483. }):Play()
  484. end)
  485.  
  486. return {enterConn, leaveConn}
  487. end
  488.  
  489. function UIUtils.createButton(parent, config)
  490. local button = Instance.new("TextButton")
  491. button.Size = config.Size or UDim2.new(0, 100, 0, 40)
  492. button.Position = config.Position or UDim2.new(0, 0, 0, 0)
  493. button.BackgroundColor3 = config.BackgroundColor or Theme.Primary
  494. button.Text = config.Text or ""
  495. button.Font = config.Font or Enum.Font.GothamSemibold
  496. button.TextSize = config.TextSize or 14
  497. button.TextColor3 = config.TextColor or Theme.TextPrimary
  498. button.AutoButtonColor = false
  499. button.Parent = parent
  500.  
  501. if config.Corner ~= false then
  502. UIUtils.createCorner(button, config.CornerRadius)
  503. end
  504.  
  505. if config.Hover then
  506. UIUtils.animateHover(button, config.HoverColor, config.BackgroundColor)
  507. end
  508.  
  509. return button
  510. end
  511.  
  512. --==============================================================================
  513. -- [10] CRIAÇÃO DA INTERFACE PRINCIPAL
  514. --==============================================================================
  515. local UI = {}
  516.  
  517. function UI:initialize()
  518. -- ScreenGui principal
  519. self.ScreenGui = Instance.new("ScreenGui")
  520. self.ScreenGui.Name = "SaveLocate_NickZ_v5"
  521. self.ScreenGui.ResetOnSpawn = false
  522. self.ScreenGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
  523.  
  524. -- Proteção contra múltiplas instâncias
  525. local existing = Services.CoreGui:FindFirstChild(self.ScreenGui.Name)
  526. if existing then
  527. existing:Destroy()
  528. end
  529.  
  530. self.ScreenGui.Parent = Services.CoreGui
  531.  
  532. self:createMainFrame()
  533. self:createTopBar()
  534. self:createOpenButton()
  535. self:createControlsFrame()
  536. self:createPageControls()
  537. self:createSlotsContainer()
  538. self:createMainPositionButton()
  539. self:createOverlays()
  540. end
  541.  
  542. function UI:createMainFrame()
  543. self.MainFrame = Instance.new("Frame")
  544. self.MainFrame.Name = "MainFrame"
  545. self.MainFrame.Size = UDim2.new(0, 600, 0, 480)
  546. self.MainFrame.Position = UDim2.new(0.5, -300, 0.5, -240)
  547. self.MainFrame.BackgroundColor3 = Theme.Background
  548. self.MainFrame.BackgroundTransparency = 0.1
  549. self.MainFrame.BorderSizePixel = 0
  550. self.MainFrame.AnchorPoint = Vector2.new(0.5, 0.5)
  551. self.MainFrame.Active = true
  552. self.MainFrame.Draggable = true
  553. self.MainFrame.ClipsDescendants = true
  554. self.MainFrame.Parent = self.ScreenGui
  555.  
  556. UIUtils.createCorner(self.MainFrame, 10)
  557. UIUtils.createStroke(self.MainFrame, Theme.Stroke, 2)
  558. UIUtils.createGradient(self.MainFrame)
  559. end
  560.  
  561. function UI:createTopBar()
  562. local topBar = Instance.new("Frame")
  563. topBar.Name = "TopBar"
  564. topBar.Size = UDim2.new(1, 0, 0, 45)
  565. topBar.BackgroundTransparency = 1
  566. topBar.Parent = self.MainFrame
  567.  
  568. -- Título
  569. local title = Instance.new("TextLabel")
  570. title.Name = "Title"
  571. title.Size = UDim2.new(1, -50, 1, 0)
  572. title.Position = UDim2.new(0, 15, 0, 0)
  573. title.BackgroundTransparency = 1
  574. title.Text = "✧ Save Locate (NickZ) v5.0"
  575. title.TextColor3 = Theme.TextPrimary
  576. title.Font = Enum.Font.GothamBold
  577. title.TextSize = 18
  578. title.TextXAlignment = Enum.TextXAlignment.Left
  579. title.Parent = topBar
  580.  
  581. -- Botão fechar
  582. self.CloseBtn = UIUtils.createButton(topBar, {
  583. Size = UDim2.new(0, 35, 0, 35),
  584. Position = UDim2.new(1, -40, 0.5, -17.5),
  585. BackgroundColor = Color3.fromRGB(50, 45, 70),
  586. Text = "✕",
  587. Font = Enum.Font.GothamBold,
  588. TextSize = 18,
  589. TextColor = Theme.Error,
  590. Hover = true,
  591. HoverColor = Theme.Error
  592. })
  593.  
  594. self.CloseBtn.MouseButton1Click:Connect(function()
  595. self.MainFrame.Visible = false
  596. end)
  597. end
  598.  
  599. function UI:createOpenButton()
  600. self.OpenBtn = UIUtils.createButton(self.ScreenGui, {
  601. Size = UDim2.new(0, 50, 0, 50),
  602. Position = UDim2.new(0, 15, 0.5, -25),
  603. BackgroundColor = Theme.Background,
  604. Text = "✧",
  605. Font = Enum.Font.GothamBold,
  606. TextSize = 26,
  607. TextColor = Theme.Primary,
  608. Hover = true,
  609. CornerRadius = 10
  610. })
  611.  
  612. UIUtils.createStroke(self.OpenBtn, Theme.Stroke, 2)
  613. self.OpenBtn.Visible = false
  614.  
  615. self.OpenBtn.MouseButton1Click:Connect(function()
  616. self.MainFrame.Visible = true
  617. end)
  618.  
  619. -- Sincronização de visibilidade
  620. self.MainFrame:GetPropertyChangedSignal("Visible"):Connect(function()
  621. self.OpenBtn.Visible = not self.MainFrame.Visible
  622. end)
  623. end
  624.  
  625. function UI:createControlsFrame()
  626. local controls = Instance.new("Frame")
  627. controls.Name = "ControlsFrame"
  628. controls.Size = UDim2.new(1, -20, 0, 95)
  629. controls.Position = UDim2.new(0, 10, 0, 50)
  630. controls.BackgroundTransparency = 1
  631. controls.Parent = self.MainFrame
  632.  
  633. -- Botão Salvar
  634. self.SaveButton = UIUtils.createButton(controls, {
  635. Size = UDim2.new(0.48, 0, 0, 40),
  636. Position = UDim2.new(0, 0, 0, 0),
  637. BackgroundColor = Theme.Success,
  638. Text = "💾 Salvar Posição",
  639. TextSize = 15,
  640. Hover = true,
  641. HoverColor = Theme.SuccessHover
  642. })
  643.  
  644. -- Campo de nome
  645. self.NameField = Instance.new("TextBox")
  646. self.NameField.Name = "NameField"
  647. self.NameField.Size = UDim2.new(1, 0, 0, 42)
  648. self.NameField.Position = UDim2.new(0, 0, 0, 48)
  649. self.NameField.BackgroundColor3 = Theme.BackgroundSecondary
  650. self.NameField.TextColor3 = Theme.TextPrimary
  651. self.NameField.PlaceholderColor3 = Theme.TextDisabled
  652. self.NameField.Font = Enum.Font.Gotham
  653. self.NameField.TextSize = 14
  654. self.NameField.PlaceholderText = "✏️ Nome da Posição (Opcional)..."
  655. self.NameField.Text = ""
  656. self.NameField.ClearTextOnFocus = false
  657. self.NameField.Parent = controls
  658.  
  659. UIUtils.createCorner(self.NameField, 8)
  660. UIUtils.createStroke(self.NameField, Theme.StrokeSecondary, 1)
  661.  
  662. -- Label de slot
  663. self.SaveSlotLabel = Instance.new("TextLabel")
  664. self.SaveSlotLabel.Name = "SlotLabel"
  665. self.SaveSlotLabel.Size = UDim2.new(0.48, 0, 0, 20)
  666. self.SaveSlotLabel.Position = UDim2.new(0.52, 0, 0, 5)
  667. self.SaveSlotLabel.BackgroundTransparency = 1
  668. self.SaveSlotLabel.Text = "📍 Slot: " .. State.currentSaveSlot
  669. self.SaveSlotLabel.TextColor3 = Theme.TextSecondary
  670. self.SaveSlotLabel.Font = Enum.Font.GothamSemibold
  671. self.SaveSlotLabel.TextSize = 13
  672. self.SaveSlotLabel.TextXAlignment = Enum.TextXAlignment.Left
  673. self.SaveSlotLabel.Parent = controls
  674.  
  675. -- Botões de navegação de slot
  676. self.SlotPrev = UIUtils.createButton(controls, {
  677. Size = UDim2.new(0, 38, 0, 32),
  678. Position = UDim2.new(0.52, 0, 0, 25),
  679. BackgroundColor = Theme.BackgroundTertiary,
  680. Text = "◄",
  681. TextSize = 16,
  682. Hover = true
  683. })
  684.  
  685. self.SlotNext = UIUtils.createButton(controls, {
  686. Size = UDim2.new(0, 38, 0, 32),
  687. Position = UDim2.new(0.52, 45, 0, 25),
  688. BackgroundColor = Theme.BackgroundTertiary,
  689. Text = "►",
  690. TextSize = 16,
  691. Hover = true
  692. })
  693. end
  694.  
  695. function UI:createPageControls()
  696. local pageFrame = Instance.new("Frame")
  697. pageFrame.Name = "PageControls"
  698. pageFrame.Size = UDim2.new(1, -20, 0, 35)
  699. pageFrame.Position = UDim2.new(0, 10, 0, 150)
  700. pageFrame.BackgroundTransparency = 1
  701. pageFrame.Parent = self.MainFrame
  702.  
  703. -- Label da página
  704. self.PageLabel = Instance.new("TextLabel")
  705. self.PageLabel.Name = "PageLabel"
  706. self.PageLabel.Size = UDim2.new(0, 140, 1, 0)
  707. self.PageLabel.Position = UDim2.new(0.5, -70, 0, 0)
  708. self.PageLabel.BackgroundTransparency = 1
  709. self.PageLabel.Text = string.format("📄 Página %d/%d", State.currentPage, Config.MAX_PAGES)
  710. self.PageLabel.TextColor3 = Theme.TextPrimary
  711. self.PageLabel.Font = Enum.Font.GothamBold
  712. self.PageLabel.TextSize = 15
  713. self.PageLabel.Parent = pageFrame
  714.  
  715. -- Botão página anterior
  716. self.PagePrev = UIUtils.createButton(pageFrame, {
  717. Size = UDim2.new(0, 95, 0, 28),
  718. Position = UDim2.new(0, 0, 0, 3),
  719. BackgroundColor = Theme.BackgroundTertiary,
  720. Text = "◄ Anterior",
  721. TextSize = 12,
  722. Hover = true
  723. })
  724.  
  725. -- Botão próxima página
  726. self.PageNext = UIUtils.createButton(pageFrame, {
  727. Size = UDim2.new(0, 95, 0, 28),
  728. Position = UDim2.new(1, -95, 0, 3),
  729. BackgroundColor = Theme.BackgroundTertiary,
  730. Text = "Próxima ►",
  731. TextSize = 12,
  732. Hover = true
  733. })
  734. end
  735.  
  736. function UI:createSlotsContainer()
  737. self.SlotsContainer = Instance.new("Frame")
  738. self.SlotsContainer.Name = "SlotsContainer"
  739. self.SlotsContainer.Size = UDim2.new(1, -20, 1, -200)
  740. self.SlotsContainer.Position = UDim2.new(0, 10, 0, 190)
  741. self.SlotsContainer.BackgroundTransparency = 1
  742. self.SlotsContainer.ClipsDescendants = false
  743. self.SlotsContainer.Parent = self.MainFrame
  744.  
  745. local gridLayout = Instance.new("UIGridLayout")
  746. gridLayout.CellPadding = UDim2.new(0, 10, 0, 10)
  747. gridLayout.CellSize = UDim2.new(0.5, -5, 0, 50)
  748. gridLayout.FillDirection = Enum.FillDirection.Vertical
  749. gridLayout.SortOrder = Enum.SortOrder.LayoutOrder
  750. gridLayout.StartCorner = Enum.StartCorner.TopLeft
  751. gridLayout.Parent = self.SlotsContainer
  752. end
  753.  
  754. function UI:createMainPositionButton()
  755. local container = Instance.new("Frame")
  756. container.Name = "MainPosContainer"
  757. container.Size = UDim2.new(0, 55, 0, 55)
  758. container.Position = UDim2.new(1, -70, 0, 15)
  759. container.BackgroundTransparency = 1
  760. container.Visible = false
  761. container.Active = true
  762. container.Draggable = true
  763. container.Parent = self.ScreenGui
  764.  
  765. self.MainPosBtn = Instance.new("TextButton")
  766. self.MainPosBtn.Name = "MainPosBtn"
  767. self.MainPosBtn.Size = UDim2.new(1, 0, 1, 0)
  768. self.MainPosBtn.BackgroundColor3 = Theme.Background
  769. self.MainPosBtn.BackgroundTransparency = 0.1
  770. self.MainPosBtn.Text = "🚀"
  771. self.MainPosBtn.Font = Enum.Font.GothamBold
  772. self.MainPosBtn.TextSize = 28
  773. self.MainPosBtn.TextColor3 = Theme.TextPrimary
  774. self.MainPosBtn.Parent = container
  775.  
  776. UIUtils.createCorner(self.MainPosBtn, 28)
  777. local mainStroke = UIUtils.createStroke(self.MainPosBtn, Theme.Stroke, 2.5)
  778.  
  779. -- Tooltip
  780. self.MainTooltip = Instance.new("TextLabel")
  781. self.MainTooltip.Name = "Tooltip"
  782. self.MainTooltip.Size = UDim2.new(0, 160, 0, 32)
  783. self.MainTooltip.Position = UDim2.new(-3.1, 0, 0.5, -16)
  784. self.MainTooltip.BackgroundColor3 = Theme.Background
  785. self.MainTooltip.BackgroundTransparency = 0.05
  786. self.MainTooltip.Text = ""
  787. self.MainTooltip.TextColor3 = Theme.TextPrimary
  788. self.MainTooltip.Font = Enum.Font.GothamSemibold
  789. self.MainTooltip.TextSize = 12
  790. self.MainTooltip.Visible = false
  791. self.MainTooltip.ZIndex = 10
  792. self.MainTooltip.Parent = self.MainPosBtn
  793.  
  794. UIUtils.createCorner(self.MainTooltip, 8)
  795. UIUtils.createStroke(self.MainTooltip, Theme.Stroke, 1.5)
  796.  
  797. -- Botão remover
  798. self.MainRemoveBtn = UIUtils.createButton(self.MainPosBtn, {
  799. Size = UDim2.new(0, 22, 0, 22),
  800. Position = UDim2.new(1, -6, 0, -6),
  801. BackgroundColor = Theme.Error,
  802. Text = "×",
  803. TextSize = 16,
  804. Font = Enum.Font.GothamBold,
  805. Hover = true,
  806. HoverColor = Theme.ErrorHover,
  807. CornerRadius = 11
  808. })
  809.  
  810. self.MainRemoveBtn.Visible = false
  811. self.MainRemoveBtn.ZIndex = 5
  812.  
  813. -- Animações hover
  814. self.MainPosBtn.MouseEnter:Connect(function()
  815. if State.mainPosition then
  816. self.MainTooltip.Text = State.mainPosition.name or "Principal"
  817. self.MainTooltip.Visible = true
  818. self.MainRemoveBtn.Visible = true
  819. end
  820. Services.TweenService:Create(self.MainPosBtn, Config.ANIMATION_INFO, {
  821. Size = UDim2.new(1.15, 0, 1.15, 0)
  822. }):Play()
  823. Services.TweenService:Create(mainStroke, Config.ANIMATION_INFO, {
  824. Thickness = 3.5
  825. }):Play()
  826. end)
  827.  
  828. self.MainPosBtn.MouseLeave:Connect(function()
  829. self.MainTooltip.Visible = false
  830. self.MainRemoveBtn.Visible = false
  831. Services.TweenService:Create(self.MainPosBtn, Config.ANIMATION_INFO, {
  832. Size = UDim2.new(1, 0, 1, 0)
  833. }):Play()
  834. Services.TweenService:Create(mainStroke, Config.ANIMATION_INFO, {
  835. Thickness = 2.5
  836. }):Play()
  837. end)
  838.  
  839. self.MainPosContainer = container
  840. end
  841.  
  842. function UI:createOverlays()
  843. self:createConfirmationOverlay()
  844. self:createRenameOverlay()
  845. self:createMoveOverlay()
  846. end
  847.  
  848. function UI:createConfirmationOverlay()
  849. local overlay = Instance.new("Frame")
  850. overlay.Name = "ConfirmationOverlay"
  851. overlay.Size = UDim2.new(1, 0, 1, 0)
  852. overlay.BackgroundColor3 = Color3.new(0, 0, 0)
  853. overlay.BackgroundTransparency = 0.5
  854. overlay.Visible = false
  855. overlay.ZIndex = 100
  856. overlay.Parent = self.MainFrame
  857.  
  858. local frame = Instance.new("Frame")
  859. frame.Size = UDim2.new(0, 320, 0, 130)
  860. frame.Position = UDim2.new(0.5, -160, 0.5, -65)
  861. frame.BackgroundColor3 = Theme.BackgroundSecondary
  862. frame.BackgroundTransparency = 0.05
  863. frame.ZIndex = 101
  864. frame.Parent = overlay
  865.  
  866. UIUtils.createCorner(frame, 10)
  867. UIUtils.createStroke(frame, Theme.Stroke, 2)
  868.  
  869. self.ConfirmLabel = Instance.new("TextLabel")
  870. self.ConfirmLabel.Size = UDim2.new(1, -20, 0, 65)
  871. self.ConfirmLabel.Position = UDim2.new(0, 10, 0, 5)
  872. self.ConfirmLabel.BackgroundTransparency = 1
  873. self.ConfirmLabel.TextColor3 = Theme.TextPrimary
  874. self.ConfirmLabel.Font = Enum.Font.GothamSemibold
  875. self.ConfirmLabel.TextSize = 15
  876. self.ConfirmLabel.TextWrapped = true
  877. self.ConfirmLabel.ZIndex = 102
  878. self.ConfirmLabel.Parent = frame
  879.  
  880. self.ConfirmYes = UIUtils.createButton(frame, {
  881. Size = UDim2.new(0.48, 0, 0, 42),
  882. Position = UDim2.new(0, 10, 1, -52),
  883. BackgroundColor = Theme.Error,
  884. Text = "✓ Sim",
  885. TextSize = 14,
  886. Hover = true,
  887. HoverColor = Theme.ErrorHover
  888. })
  889. self.ConfirmYes.ZIndex = 102
  890.  
  891. self.ConfirmNo = UIUtils.createButton(frame, {
  892. Size = UDim2.new(0.48, 0, 0, 42),
  893. Position = UDim2.new(0.52, 0, 1, -52),
  894. BackgroundColor = Theme.BackgroundTertiary,
  895. Text = "✕ Não",
  896. TextSize = 14,
  897. Hover = true
  898. })
  899. self.ConfirmNo.ZIndex = 102
  900.  
  901. self.ConfirmationOverlay = overlay
  902. end
  903.  
  904. function UI:createRenameOverlay()
  905. local overlay = Instance.new("Frame")
  906. overlay.Name = "RenameOverlay"
  907. overlay.Size = UDim2.new(1, 0, 1, 0)
  908. overlay.BackgroundColor3 = Color3.new(0, 0, 0)
  909. overlay.BackgroundTransparency = 0.5
  910. overlay.Visible = false
  911. overlay.ZIndex = 110
  912. overlay.Parent = self.MainFrame
  913.  
  914. local frame = Instance.new("Frame")
  915. frame.Size = UDim2.new(0, 360, 0, 170)
  916. frame.Position = UDim2.new(0.5, -180, 0.5, -85)
  917. frame.BackgroundColor3 = Theme.BackgroundSecondary
  918. frame.BackgroundTransparency = 0.05
  919. frame.ZIndex = 111
  920. frame.Parent = overlay
  921.  
  922. UIUtils.createCorner(frame, 10)
  923. UIUtils.createStroke(frame, Theme.Stroke, 2)
  924.  
  925. self.RenameTitle = Instance.new("TextLabel")
  926. self.RenameTitle.Size = UDim2.new(1, -20, 0, 40)
  927. self.RenameTitle.Position = UDim2.new(0, 10, 0, 5)
  928. self.RenameTitle.BackgroundTransparency = 1
  929. self.RenameTitle.Text = "✏️ Renomear Posição"
  930. self.RenameTitle.TextColor3 = Theme.TextPrimary
  931. self.RenameTitle.Font = Enum.Font.GothamBold
  932. self.RenameTitle.TextSize = 16
  933. self.RenameTitle.ZIndex = 112
  934. self.RenameTitle.Parent = frame
  935.  
  936. self.RenameField = Instance.new("TextBox")
  937. self.RenameField.Size = UDim2.new(1, -20, 0, 45)
  938. self.RenameField.Position = UDim2.new(0, 10, 0, 55)
  939. self.RenameField.BackgroundColor3 = Theme.Background
  940. self.RenameField.TextColor3 = Theme.TextPrimary
  941. self.RenameField.Font = Enum.Font.Gotham
  942. self.RenameField.TextSize = 14
  943. self.RenameField.PlaceholderText = "Digite o novo nome..."
  944. self.RenameField.ZIndex = 112
  945. self.RenameField.Parent = frame
  946.  
  947. UIUtils.createCorner(self.RenameField, 8)
  948. UIUtils.createStroke(self.RenameField, Theme.StrokeSecondary, 1)
  949.  
  950. self.RenameConfirm = UIUtils.createButton(frame, {
  951. Size = UDim2.new(0.48, 0, 0, 42),
  952. Position = UDim2.new(0, 10, 1, -52),
  953. BackgroundColor = Theme.Primary,
  954. Text = "✓ Confirmar",
  955. TextSize = 14,
  956. Hover = true,
  957. HoverColor = Theme.PrimaryHover
  958. })
  959. self.RenameConfirm.ZIndex = 112
  960.  
  961. self.RenameCancel = UIUtils.createButton(frame, {
  962. Size = UDim2.new(0.48, 0, 0, 42),
  963. Position = UDim2.new(0.52, 0, 1, -52),
  964. BackgroundColor = Theme.BackgroundTertiary,
  965. Text = "✕ Cancelar",
  966. TextSize = 14,
  967. Hover = true
  968. })
  969. self.RenameCancel.ZIndex = 112
  970.  
  971. self.RenameOverlay = overlay
  972. end
  973.  
  974. function UI:createMoveOverlay()
  975. local overlay = Instance.new("Frame")
  976. overlay.Name = "MoveOverlay"
  977. overlay.Size = UDim2.new(1, 0, 1, 0)
  978. overlay.BackgroundColor3 = Color3.new(0, 0, 0)
  979. overlay.BackgroundTransparency = 0.5
  980. overlay.Visible = false
  981. overlay.ZIndex = 120
  982. overlay.Parent = self.MainFrame
  983.  
  984. local frame = Instance.new("Frame")
  985. frame.Size = UDim2.new(0, 320, 0, 190)
  986. frame.Position = UDim2.new(0.5, -160, 0.5, -95)
  987. frame.BackgroundColor3 = Theme.BackgroundSecondary
  988. frame.BackgroundTransparency = 0.05
  989. frame.ZIndex = 121
  990. frame.Parent = overlay
  991.  
  992. UIUtils.createCorner(frame, 10)
  993. UIUtils.createStroke(frame, Theme.Stroke, 2)
  994.  
  995. self.MoveTitle = Instance.new("TextLabel")
  996. self.MoveTitle.Size = UDim2.new(1, -20, 0, 35)
  997. self.MoveTitle.Position = UDim2.new(0, 10, 0, 10)
  998. self.MoveTitle.BackgroundTransparency = 1
  999. self.MoveTitle.Text = "↔️ Mover Posição"
  1000. self.MoveTitle.TextColor3 = Theme.TextPrimary
  1001. self.MoveTitle.Font = Enum.Font.GothamBold
  1002. self.MoveTitle.TextSize = 16
  1003. self.MoveTitle.ZIndex = 122
  1004. self.MoveTitle.Parent = frame
  1005.  
  1006. local moveInfo = Instance.new("TextLabel")
  1007. moveInfo.Size = UDim2.new(1, -20, 0, 22)
  1008. moveInfo.Position = UDim2.new(0, 10, 0, 50)
  1009. moveInfo.BackgroundTransparency = 1
  1010. moveInfo.Text = "Digite o slot de destino (1-50):"
  1011. moveInfo.TextColor3 = Theme.TextSecondary
  1012. moveInfo.Font = Enum.Font.Gotham
  1013. moveInfo.TextSize = 13
  1014. moveInfo.ZIndex = 122
  1015. moveInfo.Parent = frame
  1016.  
  1017. self.MoveInput = Instance.new("TextBox")
  1018. self.MoveInput.Size = UDim2.new(0, 90, 0, 45)
  1019. self.MoveInput.Position = UDim2.new(0.5, -45, 0, 80)
  1020. self.MoveInput.BackgroundColor3 = Theme.Background
  1021. self.MoveInput.TextColor3 = Theme.TextPrimary
  1022. self.MoveInput.Font = Enum.Font.GothamBold
  1023. self.MoveInput.TextSize = 22
  1024. self.MoveInput.PlaceholderText = "1-50"
  1025. self.MoveInput.Text = ""
  1026. self.MoveInput.ZIndex = 122
  1027. self.MoveInput.Parent = frame
  1028.  
  1029. UIUtils.createCorner(self.MoveInput, 8)
  1030. UIUtils.createStroke(self.MoveInput, Theme.StrokeSecondary, 1)
  1031.  
  1032. self.MoveConfirm = UIUtils.createButton(frame, {
  1033. Size = UDim2.new(0.48, 0, 0, 40),
  1034. Position = UDim2.new(0, 10, 1, -50),
  1035. BackgroundColor = Theme.Primary,
  1036. Text = "✓ Confirmar",
  1037. TextSize = 14,
  1038. Hover = true,
  1039. HoverColor = Theme.PrimaryHover
  1040. })
  1041. self.MoveConfirm.ZIndex = 122
  1042.  
  1043. self.MoveCancel = UIUtils.createButton(frame, {
  1044. Size = UDim2.new(0.48, 0, 0, 40),
  1045. Position = UDim2.new(0.52, 0, 1, -50),
  1046. BackgroundColor = Theme.BackgroundTertiary,
  1047. Text = "✕ Cancelar",
  1048. TextSize = 14,
  1049. Hover = true
  1050. })
  1051. self.MoveCancel.ZIndex = 122
  1052.  
  1053. self.MoveOverlay = overlay
  1054. end
  1055.  
  1056. --==============================================================================
  1057. -- [11] LÓGICA DE NEGÓCIO
  1058. --==============================================================================
  1059. local Logic = {}
  1060.  
  1061. do
  1062. Logic.onConfirmCallback = nil
  1063. Logic.slotToRename = nil
  1064. Logic.slotToMove = nil
  1065.  
  1066. function Logic:updateMainPositionUI()
  1067. UI.MainPosContainer.Visible = (State.mainPosition ~= nil)
  1068. end
  1069.  
  1070. function Logic:setMainPosition(slot)
  1071. if State.savedPositions[slot] then
  1072. State.mainPosition = {
  1073. position = State.savedPositions[slot].position,
  1074. name = State.savedPositions[slot].name,
  1075. timestamp = State.savedPositions[slot].timestamp
  1076. }
  1077. Persistence:saveMainPosition()
  1078. self:updateMainPositionUI()
  1079. end
  1080. end
  1081.  
  1082. function Logic:removeMainPosition()
  1083. State.mainPosition = nil
  1084. if FileSystem.capabilities.delete then
  1085. pcall(delfile, FileSystem.paths.main)
  1086. pcall(delfile, FileSystem.paths.mainBak)
  1087. end
  1088. self:updateMainPositionUI()
  1089. end
  1090.  
  1091. function Logic:swapPositions(fromSlot, toSlot)
  1092. if fromSlot == toSlot then return end
  1093.  
  1094. if State.savedPositions[toSlot] then
  1095. -- Swap
  1096. local temp = State.savedPositions[fromSlot]
  1097. State.savedPositions[fromSlot] = State.savedPositions[toSlot]
  1098. State.savedPositions[toSlot] = temp
  1099. else
  1100. -- Move simples
  1101. State.savedPositions[toSlot] = State.savedPositions[fromSlot]
  1102. State.savedPositions[fromSlot] = nil
  1103. end
  1104.  
  1105. Persistence:saveToDisk()
  1106. end
  1107.  
  1108. function Logic:findNextEmptySlot()
  1109. for i = 1, Config.MAX_SAVES do
  1110. if not State.savedPositions[i] then
  1111. return i
  1112. end
  1113. end
  1114. return (State.currentSaveSlot % Config.MAX_SAVES) + 1
  1115. end
  1116.  
  1117. function Logic:selectNextSlot()
  1118. State.currentSaveSlot = self:findNextEmptySlot()
  1119. UI.SaveSlotLabel.Text = "📍 Slot: " .. State.currentSaveSlot
  1120. end
  1121.  
  1122. function Logic:changePage(direction)
  1123. local newPage = State.currentPage + direction
  1124. if newPage < 1 then newPage = Config.MAX_PAGES end
  1125. if newPage > Config.MAX_PAGES then newPage = 1 end
  1126.  
  1127. State.currentPage = newPage
  1128. UI.PageLabel.Text = string.format("📄 Página %d/%d", State.currentPage, Config.MAX_PAGES)
  1129. self:updateSlotsList()
  1130. end
  1131.  
  1132. function Logic:changeSlot(direction)
  1133. State.currentSaveSlot = ((State.currentSaveSlot - 1 + direction + Config.MAX_SAVES) % Config.MAX_SAVES) + 1
  1134. UI.SaveSlotLabel.Text = "📍 Slot: " .. State.currentSaveSlot
  1135. end
  1136.  
  1137. function Logic:performSave()
  1138. if not Player.humanoidRoot then return false end
  1139.  
  1140. local name = UI.NameField.Text
  1141. State.savedPositions[State.currentSaveSlot] = {
  1142. position = Player.humanoidRoot.CFrame,
  1143. name = (#name > 0) and name or ("Slot " .. State.currentSaveSlot),
  1144. timestamp = os.date("%Y-%m-%d %H:%M:%S")
  1145. }
  1146.  
  1147. Persistence:saveToDisk()
  1148.  
  1149. -- Navega para a página do slot salvo
  1150. local pageOfSlot = math.ceil(State.currentSaveSlot / Config.SLOTS_PER_PAGE)
  1151. if pageOfSlot ~= State.currentPage then
  1152. State.currentPage = pageOfSlot
  1153. UI.PageLabel.Text = string.format("📄 Página %d/%d", State.currentPage, Config.MAX_PAGES)
  1154. end
  1155.  
  1156. self:updateSlotsList()
  1157. return true
  1158. end
  1159.  
  1160. function Logic:animateSaveButton(success)
  1161. local button = UI.SaveButton
  1162. local originalColor = Theme.Success
  1163. local originalText = "💾 Salvar Posição"
  1164.  
  1165. if success then
  1166. button.Text = "✅ Salvo!"
  1167. button.BackgroundColor3 = Theme.SuccessHover
  1168. else
  1169. button.Text = "❌ Erro!"
  1170. button.BackgroundColor3 = Theme.Error
  1171. end
  1172.  
  1173. task.wait(1.5)
  1174.  
  1175. button.Text = originalText
  1176. Services.TweenService:Create(button, Config.ANIMATION_INFO, {
  1177. BackgroundColor3 = originalColor
  1178. }):Play()
  1179. end
  1180.  
  1181. function Logic:updateSlotsList()
  1182. -- Limpa slots existentes
  1183. for _, child in ipairs(UI.SlotsContainer:GetChildren()) do
  1184. if child:IsA("Frame") then
  1185. child:Destroy()
  1186. end
  1187. end
  1188.  
  1189. -- Calcula range da página atual
  1190. local startSlot = (State.currentPage - 1) * Config.SLOTS_PER_PAGE + 1
  1191. local endSlot = State.currentPage * Config.SLOTS_PER_PAGE
  1192.  
  1193. for slot = startSlot, endSlot do
  1194. self:createSlotEntry(slot)
  1195. end
  1196. end
  1197.  
  1198. function Logic:createSlotEntry(slot)
  1199. local entryFrame = Instance.new("Frame")
  1200. entryFrame.Name = "Slot_" .. slot
  1201. entryFrame.LayoutOrder = slot
  1202. entryFrame.BackgroundColor3 = Theme.BackgroundTertiary
  1203. entryFrame.BackgroundTransparency = 0.3
  1204. entryFrame.BorderSizePixel = 0
  1205. entryFrame.Parent = UI.SlotsContainer
  1206.  
  1207. UIUtils.createCorner(entryFrame, 8)
  1208.  
  1209. local slotData = State.savedPositions[slot]
  1210.  
  1211. if slotData then
  1212. self:createFilledSlot(entryFrame, slot, slotData)
  1213. else
  1214. self:createEmptySlot(entryFrame, slot)
  1215. end
  1216. end
  1217.  
  1218. function Logic:createFilledSlot(parent, slot, data)
  1219. -- Container de ações (estrela + menu)
  1220. local actionsFrame = Instance.new("Frame")
  1221. actionsFrame.Name = "ActionsFrame"
  1222. actionsFrame.Size = UDim2.new(0, 32, 1, 0)
  1223. actionsFrame.Position = UDim2.new(0, 5, 0, 0)
  1224. actionsFrame.BackgroundTransparency = 1
  1225. actionsFrame.Parent = parent
  1226.  
  1227. -- Botão de posição principal
  1228. local mainBtn = Instance.new("TextButton")
  1229. mainBtn.Name = "MainBtn"
  1230. local isMain = (State.mainPosition and State.mainPosition.position == data.position)
  1231. mainBtn.Text = isMain and "★" or "☆"
  1232. mainBtn.Size = UDim2.new(1, 0, 0, 24)
  1233. mainBtn.Position = UDim2.new(0, 0, 0, 2)
  1234. mainBtn.BackgroundTransparency = 1
  1235. mainBtn.Font = Enum.Font.GothamBold
  1236. mainBtn.TextSize = 15
  1237. mainBtn.TextColor3 = Theme.Gold
  1238. mainBtn.Parent = actionsFrame
  1239.  
  1240. mainBtn.MouseEnter:Connect(function()
  1241. mainBtn.TextSize = 17
  1242. end)
  1243. mainBtn.MouseLeave:Connect(function()
  1244. mainBtn.TextSize = 15
  1245. end)
  1246.  
  1247. -- Botão de menu
  1248. local menuBtn = Instance.new("TextButton")
  1249. menuBtn.Name = "MenuBtn"
  1250. menuBtn.Text = "⋮"
  1251. menuBtn.Size = UDim2.new(1, 0, 0, 24)
  1252. menuBtn.Position = UDim2.new(0, 0, 0, 26)
  1253. menuBtn.BackgroundTransparency = 1
  1254. menuBtn.Font = Enum.Font.GothamBold
  1255. menuBtn.TextSize = 19
  1256. menuBtn.TextColor3 = Theme.TextDisabled
  1257. menuBtn.Parent = actionsFrame
  1258.  
  1259. menuBtn.MouseEnter:Connect(function()
  1260. menuBtn.TextColor3 = Theme.TextPrimary
  1261. menuBtn.TextSize = 21
  1262. end)
  1263. menuBtn.MouseLeave:Connect(function()
  1264. menuBtn.TextColor3 = Theme.TextDisabled
  1265. menuBtn.TextSize = 19
  1266. end)
  1267.  
  1268. -- Nome da posição
  1269. local nameLabel = Instance.new("TextLabel")
  1270. nameLabel.Name = "NameLabel"
  1271. nameLabel.Size = UDim2.new(1, -95, 0, 26)
  1272. nameLabel.Position = UDim2.new(0, 42, 0, 4)
  1273. nameLabel.BackgroundTransparency = 1
  1274. nameLabel.Text = data.name
  1275. nameLabel.TextColor3 = Theme.TextSecondary
  1276. nameLabel.Font = Enum.Font.GothamSemibold
  1277. nameLabel.TextSize = 14
  1278. nameLabel.TextXAlignment = Enum.TextXAlignment.Left
  1279. nameLabel.TextTruncate = Enum.TextTruncate.AtEnd
  1280. nameLabel.Parent = parent
  1281.  
  1282. -- Timestamp
  1283. local timeLabel = Instance.new("TextLabel")
  1284. timeLabel.Name = "TimeLabel"
  1285. timeLabel.Size = UDim2.new(1, -95, 0, 16)
  1286. timeLabel.Position = UDim2.new(0, 42, 0, 30)
  1287. timeLabel.BackgroundTransparency = 1
  1288. timeLabel.Text = "🕒 " .. data.timestamp
  1289. timeLabel.TextColor3 = Theme.TextDisabled
  1290. timeLabel.Font = Enum.Font.Gotham
  1291. timeLabel.TextSize = 10
  1292. timeLabel.TextXAlignment = Enum.TextXAlignment.Left
  1293. timeLabel.Parent = parent
  1294.  
  1295. -- Botão de teleporte
  1296. local tpBtn = UIUtils.createButton(parent, {
  1297. Size = UDim2.new(0, 40, 0, 38),
  1298. Position = UDim2.new(1, -45, 0.5, -19),
  1299. BackgroundColor = Theme.Primary,
  1300. Text = "TP",
  1301. TextSize = 14,
  1302. Hover = true,
  1303. HoverColor = Theme.PrimaryHover
  1304. })
  1305.  
  1306. -- Menu de opções (criado dinamicamente)
  1307. local optionsFrame = self:createOptionsMenu(slot, data)
  1308. local menuOpen = false
  1309. local closeConnection = nil
  1310.  
  1311. menuBtn.MouseButton1Click:Connect(function()
  1312. menuOpen = not menuOpen
  1313. if menuOpen then
  1314. local btnPos = menuBtn.AbsolutePosition
  1315. optionsFrame.Position = UDim2.new(0, btnPos.X + 40, 0, btnPos.Y - 10)
  1316. optionsFrame.Visible = true
  1317.  
  1318. -- Fecha outros menus
  1319. for _, child in ipairs(UI.ScreenGui:GetChildren()) do
  1320. if child.Name:match("^OptionsMenu_") and child ~= optionsFrame then
  1321. child.Visible = false
  1322. end
  1323. end
  1324.  
  1325. -- Sistema de fechar ao clicar fora
  1326. if closeConnection then closeConnection:Disconnect() end
  1327. closeConnection = Services.UserInputService.InputBegan:Connect(function(input)
  1328. if input.UserInputType == Enum.UserInputType.MouseButton1 then
  1329. task.wait(0.05)
  1330. local mousePos = Services.UserInputService:GetMouseLocation()
  1331. local framePos = optionsFrame.AbsolutePosition
  1332. local frameSize = optionsFrame.AbsoluteSize
  1333.  
  1334. if mousePos.X < framePos.X or mousePos.X > framePos.X + frameSize.X or
  1335. mousePos.Y < framePos.Y or mousePos.Y > framePos.Y + frameSize.Y then
  1336. optionsFrame.Visible = false
  1337. menuOpen = false
  1338. if closeConnection then
  1339. closeConnection:Disconnect()
  1340. closeConnection = nil
  1341. end
  1342. end
  1343. end
  1344. end)
  1345. else
  1346. optionsFrame.Visible = false
  1347. if closeConnection then
  1348. closeConnection:Disconnect()
  1349. closeConnection = nil
  1350. end
  1351. end
  1352. end)
  1353.  
  1354. -- Lógica do botão principal
  1355. mainBtn.MouseButton1Click:Connect(function()
  1356. local isAlreadyMain = (State.mainPosition and State.mainPosition.position == data.position)
  1357.  
  1358. if isAlreadyMain then
  1359. UI.ConfirmLabel.Text = "Remover posição principal?"
  1360. UI.ConfirmYes.Text = "✓ Remover"
  1361. Logic.onConfirmCallback = function()
  1362. Logic:removeMainPosition()
  1363. Logic:updateSlotsList()
  1364. end
  1365. else
  1366. UI.ConfirmLabel.Text = State.mainPosition and "Substituir posição principal?" or "Definir como principal?"
  1367. UI.ConfirmYes.Text = "✓ Sim"
  1368. Logic.onConfirmCallback = function()
  1369. Logic:setMainPosition(slot)
  1370. Logic:updateSlotsList()
  1371. end
  1372. end
  1373.  
  1374. UI.ConfirmationOverlay.Visible = true
  1375. end)
  1376.  
  1377. -- Lógica do botão de teleporte
  1378. tpBtn.MouseButton1Click:Connect(function()
  1379. local success = Teleport:execute(data.position)
  1380. if success then
  1381. tpBtn.Text = "✅"
  1382. tpBtn.BackgroundColor3 = Theme.Success
  1383. task.wait(1)
  1384. if tpBtn.Parent then
  1385. tpBtn.Text = "TP"
  1386. Services.TweenService:Create(tpBtn, Config.ANIMATION_INFO, {
  1387. BackgroundColor3 = Theme.Primary
  1388. }):Play()
  1389. end
  1390. else
  1391. tpBtn.Text = "❌"
  1392. tpBtn.BackgroundColor3 = Theme.Error
  1393. task.wait(1)
  1394. if tpBtn.Parent then
  1395. tpBtn.Text = "TP"
  1396. Services.TweenService:Create(tpBtn, Config.ANIMATION_INFO, {
  1397. BackgroundColor3 = Theme.Primary
  1398. }):Play()
  1399. end
  1400. end
  1401. end)
  1402. end
  1403.  
  1404. function Logic:createEmptySlot(parent, slot)
  1405. local label = Instance.new("TextLabel")
  1406. label.Name = "EmptyLabel"
  1407. label.Size = UDim2.new(1, -20, 1, 0)
  1408. label.Position = UDim2.new(0, 10, 0, 0)
  1409. label.BackgroundTransparency = 1
  1410. label.Text = string.format("Slot %d: Vazio", slot)
  1411. label.TextColor3 = Theme.SlotEmpty
  1412. label.Font = Enum.Font.Gotham
  1413. label.TextSize = 14
  1414. label.TextXAlignment = Enum.TextXAlignment.Left
  1415. label.Parent = parent
  1416. end
  1417.  
  1418. function Logic:createOptionsMenu(slot, data)
  1419. local optionsFrame = Instance.new("Frame")
  1420. optionsFrame.Name = "OptionsMenu_" .. slot
  1421. optionsFrame.Size = UDim2.new(0, 125, 0, 115)
  1422. optionsFrame.BackgroundColor3 = Theme.BackgroundSecondary
  1423. optionsFrame.BackgroundTransparency = 0.02
  1424. optionsFrame.BorderSizePixel = 0
  1425. optionsFrame.Visible = false
  1426. optionsFrame.ZIndex = 200
  1427. optionsFrame.Parent = UI.ScreenGui
  1428.  
  1429. UIUtils.createCorner(optionsFrame, 10)
  1430. UIUtils.createStroke(optionsFrame, Theme.Stroke, 2)
  1431.  
  1432. local buttonsContainer = Instance.new("Frame")
  1433. buttonsContainer.Name = "Container"
  1434. buttonsContainer.Size = UDim2.new(1, -12, 1, -28)
  1435. buttonsContainer.Position = UDim2.new(0, 6, 0, 24)
  1436. buttonsContainer.BackgroundTransparency = 1
  1437. buttonsContainer.ZIndex = 201
  1438. buttonsContainer.Parent = optionsFrame
  1439.  
  1440. -- Helper para botões de menu
  1441. local function createMenuButton(pos, text, icon, textColor)
  1442. local btn = Instance.new("TextButton")
  1443. btn.Size = UDim2.new(1, 0, 0, 26)
  1444. btn.Position = UDim2.new(0, 0, 0, pos)
  1445. btn.BackgroundColor3 = Theme.BackgroundTertiary
  1446. btn.BackgroundTransparency = 0.4
  1447. btn.Text = icon .. " " .. text
  1448. btn.TextColor3 = textColor or Theme.TextSecondary
  1449. btn.Font = Enum.Font.GothamSemibold
  1450. btn.TextSize = 12
  1451. btn.ZIndex = 202
  1452. btn.Parent = buttonsContainer
  1453.  
  1454. UIUtils.createCorner(btn, 6)
  1455.  
  1456. btn.MouseEnter:Connect(function()
  1457. Services.TweenService:Create(btn, Config.ANIMATION_INFO, {
  1458. BackgroundTransparency = 0,
  1459. BackgroundColor3 = Color3.fromRGB(65, 60, 85)
  1460. }):Play()
  1461. end)
  1462. btn.MouseLeave:Connect(function()
  1463. Services.TweenService:Create(btn, Config.ANIMATION_INFO, {
  1464. BackgroundTransparency = 0.4,
  1465. BackgroundColor3 = Theme.BackgroundTertiary
  1466. }):Play()
  1467. end)
  1468.  
  1469. return btn
  1470. end
  1471.  
  1472. local renameBtn = createMenuButton(0, "Renomear", "✏️")
  1473. local moveBtn = createMenuButton(29, "Mover", "↔️")
  1474. local deleteBtn = createMenuButton(58, "Excluir", "🗑️", Theme.Error)
  1475.  
  1476. -- Eventos dos botões
  1477. renameBtn.MouseButton1Click:Connect(function()
  1478. optionsFrame.Visible = false
  1479. Logic.slotToRename = slot
  1480. UI.RenameTitle.Text = string.format("✏️ Renomear Slot %d", slot)
  1481. UI.RenameField.Text = data.name
  1482. UI.RenameOverlay.Visible = true
  1483. end)
  1484.  
  1485. moveBtn.MouseButton1Click:Connect(function()
  1486. optionsFrame.Visible = false
  1487. Logic.slotToMove = slot
  1488. UI.MoveTitle.Text = string.format("↔️ Mover: %s", data.name)
  1489. UI.MoveInput.Text = ""
  1490. UI.MoveOverlay.Visible = true
  1491. end)
  1492.  
  1493. deleteBtn.MouseButton1Click:Connect(function()
  1494. optionsFrame.Visible = false
  1495. UI.ConfirmLabel.Text = string.format("Excluir o Slot %d?\n\"%s\"", slot, data.name)
  1496. UI.ConfirmYes.Text = "✓ Excluir"
  1497. Logic.onConfirmCallback = function()
  1498. State.savedPositions[slot] = nil
  1499. Persistence:saveToDisk()
  1500. Logic:updateSlotsList()
  1501. Logic:selectNextSlot()
  1502. end
  1503. UI.ConfirmationOverlay.Visible = true
  1504. end)
  1505.  
  1506. return optionsFrame
  1507. end
  1508. end
  1509.  
  1510. --==============================================================================
  1511. -- [12] CONECTAR EVENTOS DA UI
  1512. --==============================================================================
  1513. local function connectUIEvents()
  1514. -- Botão de salvar
  1515. UI.SaveButton.MouseButton1Click:Connect(function()
  1516. if State.savedPositions[State.currentSaveSlot] then
  1517. UI.ConfirmLabel.Text = string.format("Substituir posição do Slot %d?", State.currentSaveSlot)
  1518. UI.ConfirmYes.Text = "✓ Substituir"
  1519. Logic.onConfirmCallback = function()
  1520. local success = Logic:performSave()
  1521. if success then Logic:selectNextSlot() end
  1522. Logic:animateSaveButton(success)
  1523. end
  1524. UI.ConfirmationOverlay.Visible = true
  1525. else
  1526. local success = Logic:performSave()
  1527. if success then Logic:selectNextSlot() end
  1528. Logic:animateSaveButton(success)
  1529. end
  1530. end)
  1531.  
  1532. -- Navegação de slots
  1533. UI.SlotPrev.MouseButton1Click:Connect(function()
  1534. Logic:changeSlot(-1)
  1535. end)
  1536.  
  1537. UI.SlotNext.MouseButton1Click:Connect(function()
  1538. Logic:changeSlot(1)
  1539. end)
  1540.  
  1541. -- Navegação de páginas
  1542. UI.PagePrev.MouseButton1Click:Connect(function()
  1543. Logic:changePage(-1)
  1544. end)
  1545.  
  1546. UI.PageNext.MouseButton1Click:Connect(function()
  1547. Logic:changePage(1)
  1548. end)
  1549.  
  1550. -- Confirmação overlay
  1551. UI.ConfirmYes.MouseButton1Click:Connect(function()
  1552. if Logic.onConfirmCallback then
  1553. Logic.onConfirmCallback()
  1554. end
  1555. Logic.onConfirmCallback = nil
  1556. UI.ConfirmationOverlay.Visible = false
  1557. end)
  1558.  
  1559. UI.ConfirmNo.MouseButton1Click:Connect(function()
  1560. Logic.onConfirmCallback = nil
  1561. UI.ConfirmationOverlay.Visible = false
  1562. end)
  1563.  
  1564. -- Rename overlay
  1565. UI.RenameConfirm.MouseButton1Click:Connect(function()
  1566. if Logic.slotToRename and #UI.RenameField.Text > 0 then
  1567. local newName = UI.RenameField.Text
  1568. local slotData = State.savedPositions[Logic.slotToRename]
  1569.  
  1570. if slotData then
  1571. slotData.name = newName
  1572.  
  1573. -- Atualiza nome principal se for o mesmo
  1574. if State.mainPosition and State.mainPosition.position == slotData.position then
  1575. State.mainPosition.name = newName
  1576. Persistence:saveMainPosition()
  1577. end
  1578.  
  1579. Persistence:saveToDisk()
  1580. Logic:updateSlotsList()
  1581. Logic:updateMainPositionUI()
  1582. end
  1583.  
  1584. UI.RenameOverlay.Visible = false
  1585. Logic.slotToRename = nil
  1586. end
  1587. end)
  1588.  
  1589. UI.RenameCancel.MouseButton1Click:Connect(function()
  1590. UI.RenameOverlay.Visible = false
  1591. Logic.slotToRename = nil
  1592. end)
  1593.  
  1594. -- Move overlay
  1595. UI.MoveConfirm.MouseButton1Click:Connect(function()
  1596. local targetSlot = tonumber(UI.MoveInput.Text)
  1597. if Logic.slotToMove and targetSlot and targetSlot >= 1 and targetSlot <= Config.MAX_SAVES then
  1598. Logic:swapPositions(Logic.slotToMove, targetSlot)
  1599. Logic:updateSlotsList()
  1600. UI.MoveOverlay.Visible = false
  1601. Logic.slotToMove = nil
  1602. else
  1603. UI.MoveInput.Text = ""
  1604. UI.MoveInput.PlaceholderText = "❌ Inválido!"
  1605. task.wait(1)
  1606. UI.MoveInput.PlaceholderText = "1-50"
  1607. end
  1608. end)
  1609.  
  1610. UI.MoveCancel.MouseButton1Click:Connect(function()
  1611. UI.MoveOverlay.Visible = false
  1612. Logic.slotToMove = nil
  1613. end)
  1614.  
  1615. -- Botão de posição principal
  1616. UI.MainPosBtn.MouseButton1Click:Connect(function()
  1617. if State.mainPosition then
  1618. local success = Teleport:execute(State.mainPosition.position)
  1619. if success then
  1620. UI.MainPosBtn.Text = "✅"
  1621. UI.MainPosBtn.BackgroundColor3 = Theme.Success
  1622. task.wait(1)
  1623. if UI.MainPosBtn.Parent then
  1624. UI.MainPosBtn.Text = "🚀"
  1625. Services.TweenService:Create(UI.MainPosBtn, Config.ANIMATION_INFO, {
  1626. BackgroundColor3 = Theme.Background
  1627. }):Play()
  1628. end
  1629. end
  1630. end
  1631. end)
  1632.  
  1633. -- Remover posição principal
  1634. UI.MainRemoveBtn.MouseButton1Click:Connect(function()
  1635. UI.ConfirmLabel.Text = "Remover posição principal?"
  1636. UI.ConfirmYes.Text = "✓ Remover"
  1637. Logic.onConfirmCallback = function()
  1638. Logic:removeMainPosition()
  1639. Logic:updateSlotsList()
  1640. end
  1641. UI.ConfirmationOverlay.Visible = true
  1642. end)
  1643. end
  1644.  
  1645. --==============================================================================
  1646. -- [13] INICIALIZAÇÃO E GESTÃO DE CICLO DE VIDA
  1647. --==============================================================================
  1648. local function initialize()
  1649. -- Atualiza referências do personagem
  1650. Teleport:updateCharacterReferences()
  1651.  
  1652. -- Carrega dados salvos
  1653. Persistence:loadFromDisk()
  1654.  
  1655. -- Inicializa UI
  1656. UI:initialize()
  1657.  
  1658. -- Conecta eventos
  1659. connectUIEvents()
  1660.  
  1661. -- Atualiza interface inicial
  1662. Logic:selectNextSlot()
  1663. Logic:updateSlotsList()
  1664. Logic:updateMainPositionUI()
  1665.  
  1666. State.isInitialized = true
  1667.  
  1668. -- Log de inicialização
  1669. print("╔═══════════════════════════════════════════════════╗")
  1670. print("║ ✅ Save Locate (NickZ) v5.0 - Carregado! ║")
  1671. print("║ ║")
  1672. print("║ 📦 Total de Slots: 50 (5 Páginas de 10) ║")
  1673. print("║ 🚀 Sistema de Teleporte Anti-Bug Ativo ║")
  1674. print("║ 💾 Sistema de Persistência: " .. (FileSystem.hasFS and "✓ Ativo" or "✗ Inativo") .. " ║")
  1675. print("║ 🎨 Interface Moderna e Otimizada ║")
  1676. print("╚═══════════════════════════════════════════════════╝")
  1677. end
  1678.  
  1679. -- Gerenciamento de respawn do personagem
  1680. Player.instance.CharacterAdded:Connect(function(character)
  1681. Player.character = character
  1682. Player.humanoidRoot = character:WaitForChild("HumanoidRootPart", 10)
  1683. end)
  1684.  
  1685. -- Salvamento ao fechar o jogo
  1686. game:BindToClose(function()
  1687. if State.isInitialized then
  1688. Persistence:saveToDisk()
  1689. end
  1690. end)
  1691.  
  1692. -- Inicializa o sistema
  1693. initialize()
Add Comment
Please, Sign In to add comment