--[[ // FileName: Topbar.lua // Written by: SolarCrane // Description: Code for lua side Top Menu items in ROBLOX. ]] --[[ CONSTANTS ]] local TOPBAR_THICKNESS = 36 local USERNAME_CONTAINER_WIDTH = 170 local COLUMN_WIDTH = 75 local NAME_LEADERBOARD_SEP_WIDTH = 2 local FONT_COLOR = Color3.new(1,1,1) local TOPBAR_BACKGROUND_COLOR = Color3.new(31/255,31/255,31/255) local TOPBAR_OPAQUE_TRANSPARENCY = 0 local TOPBAR_TRANSLUCENT_TRANSPARENCY = 0.5 local HEALTH_BACKGROUND_COLOR = Color3.new(228/255, 236/255, 246/255) local HEALTH_RED_COLOR = Color3.new(226/255, 73/255, 41/255) local HEALTH_YELLOW_COLOR = Color3.new(250/255, 235/255, 0) local HEALTH_GREEN_COLOR = Color3.new(27/255, 252/255, 107/255) local HEALTH_PERCANTAGE_FOR_OVERLAY = 5 / 100 local HURT_OVERLAY_IMAGE = "http://www.roblox.com/asset/?id=34854607" --[[ END OF CONSTANTS ]] --[[ FFLAG VALUES ]] local newSettingsSuccess, newSettingsFlagValue = pcall(function() return settings():GetFFlag("NewMenuSettingsScript") end) local useNewSettings = newSettingsSuccess and newSettingsFlagValue local backPackSuccess, backpackFlagValue = pcall(function() return settings():GetFFlag("NewBackpackScript") end) local useNewBackpack = (backPackSuccess and backpackFlagValue) local playerListSuccess, playerListFlagValue = pcall(function() return settings():GetFFlag("NewPlayerListScript") end) local useNewPlayerlist = (playerListSuccess and playerListFlagValue) local function GetBubbleChatbarFlag() local bubbleChatbarSuccess, bubbleChatbarFlagValue = pcall(function() return settings():GetFFlag("BubbleChatbarDocksAtTop") end) return bubbleChatbarSuccess and bubbleChatbarFlagValue == true end --[[ END OF FFLAG VALUES ]] --[[ SERVICES ]] local CoreGuiService = game:GetService('CoreGui') local PlayersService = game:GetService('Players') local GuiService = game:GetService('GuiService') local InputService = game:GetService('UserInputService') local StarterGui = game:GetService('StarterGui') --[[ END OF SERVICES ]] local GameSettings = UserSettings().GameSettings local Player = PlayersService.LocalPlayer while Player == nil do wait() Player = PlayersService.LocalPlayer end local GuiRoot = CoreGuiService:WaitForChild('RobloxGui') local Util = {} do -- Check if we are running on a touch device function Util.IsTouchDevice() return InputService.TouchEnabled end function Util.Create(instanceType) return function(data) local obj = Instance.new(instanceType) for k, v in pairs(data) do if type(k) == 'number' then v.Parent = obj else obj[k] = v end end return obj end end function Util.Clamp(low, high, input) return math.max(low, math.min(high, input)) end function Util.DisconnectEvent(conn) if conn then conn:disconnect() end return nil end function Util.SetGUIInsetBounds(x1, y1, x2, y2) GuiService:SetGlobalGuiInset(x1, y1, x2, y2) end local humanoidCache = {} function Util.FindPlayerHumanoid(player) local character = player and player.Character if character then local resultHumanoid = humanoidCache[player] if resultHumanoid and resultHumanoid.Parent == character then return resultHumanoid else humanoidCache[player] = nil -- Bust Old Cache for _, child in pairs(character:GetChildren()) do if child:IsA('Humanoid') then humanoidCache[player] = child return child end end end end end end local function CreateTopBar() local this = {} local playerGuiChangedConn = nil local topbarContainer = Util.Create'Frame'{ Name = "TopBarContainer"; Size = UDim2.new(1, 0, 0, TOPBAR_THICKNESS); Position = UDim2.new(0, 0, 0, -TOPBAR_THICKNESS); BackgroundTransparency = TOPBAR_OPAQUE_TRANSPARENCY; BackgroundColor3 = TOPBAR_BACKGROUND_COLOR; BorderSizePixel = 0; Active = true; Parent = GuiRoot; }; local topbarShadow = Util.Create'ImageLabel'{ Name = "TopBarShadow"; Size = UDim2.new(1, 0, 0, 3); Position = UDim2.new(0, 0, 1, 0); Image = "rbxasset://textures/ui/TopBar/dropshadow.png"; BackgroundTransparency = 1; Active = false; Visible = false; Parent = topbarContainer; }; local function UpdateBackgroundTransparency() local playerGui = Player:FindFirstChild('PlayerGui') if playerGui then pcall(function() topbarContainer.BackgroundTransparency = playerGui:GetTopbarTransparency() end) topbarShadow.Visible = (topbarContainer.BackgroundTransparency == 0) end end function this:GetInstance() return topbarContainer end function this:SetTopbarDisplayMode(opaque) topbarContainer.BackgroundTransparency = opaque and TOPBAR_OPAQUE_TRANSPARENCY or TOPBAR_TRANSLUCENT_TRANSPARENCY topbarShadow.Visible = not opaque UpdateBackgroundTransparency() end spawn(function() local playerGui = Player:WaitForChild('PlayerGui') playerGuiChangedConn = Util.DisconnectEvent(playerGuiChangedConn) pcall(function() playerGuiChangedConn = playerGui.TopbarTransparencyChangedSignal:connect(UpdateBackgroundTransparency) end) UpdateBackgroundTransparency() end) return this end local function CreateMenuBar(barAlignment) local this = {} local thickness = TOPBAR_THICKNESS local alignment = (barAlignment == 'Right' and 'Right' or 'Left') local items = {} local propertyChangedConnections = {} local dock = nil local function ArrangeItems() local totalWidth = 0 for i, item in pairs(items) do local width = item:GetWidth() if alignment == 'Left' then item.Position = UDim2.new(0, totalWidth, 0, 0) else -- Right item.Position = UDim2.new(1, -totalWidth - width, 0, 0) end totalWidth = totalWidth + width end end function this:GetThickness() return thickness end function this:GetNumberOfItems() return #items end function this:SetDock(newDock) dock = newDock for _, item in pairs(items) do item.Parent = dock end end function this:IndexOfItem(searchItem) for index, item in pairs(items) do if item == searchItem then return index end end return nil end function this:ItemAtIndex(index) return items[index] end function this:AddItem(item, index) local numItems = self:GetNumberOfItems() index = Util.Clamp(1, numItems + 1, (index or numItems + 1)) local alreadyFoundIndex = self:IndexOfItem(item) if alreadyFoundIndex then return item, index end table.insert(items, index, item) Util.DisconnectEvent(propertyChangedConnections[item]) propertyChangedConnections[item] = item.Changed:connect(function(property) if property == 'AbsoluteSize' then ArrangeItems() end end) ArrangeItems() if dock then item.Parent = dock end return item, index end function this:RemoveItem(item) local index = self:IndexOfItem(item) if index then local removedItem = table.remove(items, index) removedItem.Parent = nil Util.DisconnectEvent(propertyChangedConnections[removedItem]) ArrangeItems() return removedItem, index end end return this end local function CreateMenuItem(origInstance) local this = {} local instance = origInstance function this:SetInstance(newInstance) if not instance then instance = newInstance else print("Trying to set an Instance of a Menu Item that already has an instance; doing nothing.") end end function this:GetWidth() return self.Size.X.Offset end -- We are extending a regular instance. do local mt = { __index = function (t, k) return instance[k] end; __newindex = function (t, k, v) --if instance[k] ~= nil then instance[k] = v --else -- rawset(t, k, v) --end end; } setmetatable(this, mt) end return this end ----- HEALTH ----- local function CreateUsernameHealthMenuItem() local container = Util.Create'ImageButton' { Name = "NameHealthContainer"; Size = UDim2.new(0, USERNAME_CONTAINER_WIDTH, 1, 0); AutoButtonColor = false; Image = ""; BackgroundTransparency = 1; } local username = Util.Create'TextLabel'{ Name = "Username"; Text = Player.Name; Size = UDim2.new(1, -14, 0, 22); Position = UDim2.new(0, 7, 0, 0); Font = Enum.Font.SourceSansBold; FontSize = Enum.FontSize.Size14; BackgroundTransparency = 1; TextColor3 = FONT_COLOR; TextYAlignment = Enum.TextYAlignment.Bottom; TextXAlignment = Enum.TextXAlignment.Left; Parent = container; }; local healthContainer = Util.Create'Frame'{ Name = "HealthContainer"; Size = UDim2.new(1, -14, 0, 3); Position = UDim2.new(0, 7, 1, -9); BorderSizePixel = 0; BackgroundColor3 = HEALTH_BACKGROUND_COLOR; Parent = container; }; local healthFill = Util.Create'Frame'{ Name = "HealthFill"; Size = UDim2.new(1, 0, 1, 0); BorderSizePixel = 0; BackgroundColor3 = HEALTH_GREEN_COLOR; Parent = healthContainer; }; local hurtOverlay = Util.Create'ImageLabel' { Name = "HurtOverlay"; BackgroundTransparency = 1; Image = HURT_OVERLAY_IMAGE; Position = UDim2.new(-10,0,-10,0); Size = UDim2.new(20,0,20,0); Visible = false; Parent = GuiRoot; }; local this = CreateMenuItem(container) --- EVENTS --- local humanoidChangedConn, childAddedConn, childRemovedConn = nil -------------- local function AnimateHurtOverlay() if hurtOverlay then local newSize = UDim2.new(20, 0, 20, 0) local newPos = UDim2.new(-10, 0, -10, 0) if hurtOverlay:IsDescendantOf(game) then -- stop any tweens on overlay hurtOverlay:TweenSizeAndPosition(newSize, newPos, Enum.EasingDirection.Out, Enum.EasingStyle.Linear, 0, true, function() -- show the gui hurtOverlay.Size = UDim2.new(1,0,1,0) hurtOverlay.Position = UDim2.new(0,0,0,0) hurtOverlay.Visible = true -- now tween the hide if hurtOverlay:IsDescendantOf(game) then hurtOverlay:TweenSizeAndPosition(newSize, newPos, Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 10, false, function() hurtOverlay.Visible = false end) else hurtOverlay.Size = newSize hurtOverlay.Position = newPos end end) else hurtOverlay.Size = newSize hurtOverlay.Position = newPos end end end local healthColorToPosition = { [Vector3.new(HEALTH_RED_COLOR.r, HEALTH_RED_COLOR.g, HEALTH_RED_COLOR.b)] = 0.1; [Vector3.new(HEALTH_YELLOW_COLOR.r, HEALTH_YELLOW_COLOR.g, HEALTH_YELLOW_COLOR.b)] = 0.5; [Vector3.new(HEALTH_GREEN_COLOR.r, HEALTH_GREEN_COLOR.g, HEALTH_GREEN_COLOR.b)] = 0.8; } local min = 0.1 local minColor = HEALTH_RED_COLOR local max = 0.8 local maxColor = HEALTH_GREEN_COLOR local function HealthbarColorTransferFunction(healthPercent) if healthPercent < min then return minColor elseif healthPercent > max then return maxColor end -- Shepard's Interpolation local numeratorSum = Vector3.new(0,0,0) local denominatorSum = 0 for colorSampleValue, samplePoint in pairs(healthColorToPosition) do local distance = healthPercent - samplePoint if distance == 0 then -- If we are exactly on an existing sample value then we don't need to interpolate return Color3.new(colorSampleValue.x, colorSampleValue.y, colorSampleValue.z) else local wi = 1 / (distance*distance) numeratorSum = numeratorSum + wi * colorSampleValue denominatorSum = denominatorSum + wi end end local result = numeratorSum / denominatorSum return Color3.new(result.x, result.y, result.z) end local function OnHumanoidAdded(humanoid) local lastHealth = humanoid.Health local function OnHumanoidHealthChanged(health) if humanoid then local healthDelta = lastHealth - health local healthPercent = health / humanoid.MaxHealth if humanoid.MaxHealth <= 0 then healthPercent = 0 end healthPercent = Util.Clamp(0, 1, healthPercent) local healthColor = HealthbarColorTransferFunction(healthPercent) local thresholdForHurtOverlay = humanoid.MaxHealth * HEALTH_PERCANTAGE_FOR_OVERLAY if healthDelta >= thresholdForHurtOverlay and health ~= humanoid.MaxHealth then AnimateHurtOverlay() end healthFill.BackgroundColor3 = healthColor healthFill.Size = UDim2.new(healthPercent, 0, 1, 0) lastHealth = health end end Util.DisconnectEvent(humanoidChangedConn) humanoidChangedConn = humanoid.HealthChanged:connect(OnHumanoidHealthChanged) OnHumanoidHealthChanged(lastHealth) end local function OnCharacterAdded(character) local humanoid = Util.FindPlayerHumanoid(Player) if humanoid then OnHumanoidAdded(humanoid) end local function onChildAddedOrRemoved() local tempHumanoid = Util.FindPlayerHumanoid(Player) if tempHumanoid and tempHumanoid ~= humanoid then humanoid = tempHumanoid OnHumanoidAdded(humanoid) end end Util.DisconnectEvent(childAddedConn) Util.DisconnectEvent(childRemovedConn) childAddedConn = character.ChildAdded:connect(onChildAddedOrRemoved) childRemovedConn = character.ChildRemoved:connect(onChildAddedOrRemoved) end local mtStore = getmetatable(this) setmetatable(this, {}) function this:SetHealthbarEnabled(enabled) healthContainer.Visible = enabled if enabled then username.Size = UDim2.new(1, -14, 0, 22); username.TextYAlignment = Enum.TextYAlignment.Bottom; else username.Size = UDim2.new(1, -14, 1, 0); username.TextYAlignment = Enum.TextYAlignment.Center; end end function this:SetNameVisible(visible) username.Visible = visible end setmetatable(this, mtStore) -- Don't need to disconnect this one because we never reconnect it. Player.CharacterAdded:connect(OnCharacterAdded) if Player.Character then OnCharacterAdded(Player.Character) end if useNewPlayerlist then local PlayerlistModule = require(GuiRoot.Modules.PlayerlistModule) container.MouseButton1Click:connect(function() PlayerlistModule.ToggleVisibility() end) end return this end ----- END OF HEALTH ----- ----- LEADERSTATS ----- local function CreateLeaderstatsMenuItem() local PlayerlistModule = require(GuiRoot.Modules.PlayerlistModule) local leaderstatsContainer = Util.Create'ImageButton' { Name = "LeaderstatsContainer"; Size = UDim2.new(0, 0, 1, 0); AutoButtonColor = false; Image = ""; BackgroundTransparency = 1; }; local this = CreateMenuItem(leaderstatsContainer) local columns = {} local mtStore = getmetatable(this) setmetatable(this, {}) function this:SetColumns(columnsList) -- Should we handle is the screen dimensions change and it is no longer a small touch device after we set columns? local isSmallTouchDevice = Util.IsTouchDevice() and Game:GetService("GuiService"):GetScreenResolution().Y < 500 local numColumns = #columnsList -- Destroy old columns for _, oldColumn in pairs(columns) do oldColumn:Destroy() end columns = {} -- End destroy old columns local count = 0 for index, columnData in pairs(columnsList) do -- i = 1, numColumns do if not isSmallTouchDevice or index <= 1 then local columnName = columnData.Name local columnValue = columnData.Text local columnframe = Util.Create'Frame' { Name = "Column" .. tostring(index); Size = UDim2.new(0, COLUMN_WIDTH + (index == numColumns and 0 or NAME_LEADERBOARD_SEP_WIDTH), 1, 0); Position = UDim2.new(0, NAME_LEADERBOARD_SEP_WIDTH + (COLUMN_WIDTH + NAME_LEADERBOARD_SEP_WIDTH) * (index-1), 0, 0); BackgroundTransparency = 1; Parent = leaderstatsContainer; Util.Create'TextLabel' { Name = "ColumnName"; Text = columnName; Size = UDim2.new(1, 0, 0, 10); Position = UDim2.new(0, 0, 0, 4); Font = Enum.Font.SourceSans; FontSize = Enum.FontSize.Size14; BorderSizePixel = 0; BackgroundTransparency = 1; TextColor3 = FONT_COLOR; TextYAlignment = Enum.TextYAlignment.Center; TextXAlignment = Enum.TextXAlignment.Center; }; Util.Create'TextLabel' { Name = "ColumnValue"; Text = columnValue; Size = UDim2.new(1, 0, 0, 10); Position = UDim2.new(0, 0, 0, 19); Font = Enum.Font.SourceSansBold; FontSize = Enum.FontSize.Size14; BorderSizePixel = 0; BackgroundTransparency = 1; TextColor3 = FONT_COLOR; TextYAlignment = Enum.TextYAlignment.Center; TextXAlignment = Enum.TextXAlignment.Center; }; }; columns[columnName] = columnframe count = count + 1 end end leaderstatsContainer.Size = UDim2.new(0, COLUMN_WIDTH * count + NAME_LEADERBOARD_SEP_WIDTH * count, 1, 0) end function this:UpdateColumnValue(columnName, value) local column = columns[columnName] local columnValue = column and column:FindFirstChild('ColumnValue') if columnValue then columnValue.Text = tostring(value) end end setmetatable(this, mtStore) this:SetColumns(PlayerlistModule.GetStats()) PlayerlistModule.OnLeaderstatsChanged.Event:connect(function(newStatColumns) this:SetColumns(newStatColumns) end) PlayerlistModule.OnStatChanged.Event:connect(function(statName, statValueAsString) this:UpdateColumnValue(statName, statValueAsString) end) leaderstatsContainer.MouseButton1Click:connect(function() PlayerlistModule.ToggleVisibility() end) return this end ----- END OF LEADERSTATS ----- --- SETTINGS --- local function CreateSettingsIcon() local MenuModule = require(game.CoreGui.RobloxGui.Modules.Settings2) local settingsIconButton = Util.Create'ImageButton' { Name = "Settings"; Size = UDim2.new(0, 50, 0, TOPBAR_THICKNESS); Image = ""; AutoButtonColor = false; BackgroundTransparency = 1; } local settingsIconImage = Util.Create'ImageLabel' { Name = "SettingsIcon"; Size = UDim2.new(0, 32, 0, 25); Position = UDim2.new(0.5, -16, 0.5, -12); BackgroundTransparency = 1; Image = "rbxasset://textures/ui/Menu/Hamburger.png"; Parent = settingsIconButton; }; local settingsActive = false local function UpdateHamburgerIcon() if settingsActive then settingsIconImage.Image = "rbxasset://textures/ui/Menu/HamburgerDown.png"; else settingsIconImage.Image = "rbxasset://textures/ui/Menu/Hamburger.png"; end end function toggleSettings() if settingsActive == false then settingsActive = true else settingsActive = false end MenuModule:ToggleVisibility(settingsActive) UpdateHamburgerIcon() return settingsActive end settingsIconButton.MouseButton1Click:connect(function() toggleSettings() end) MenuModule.SettingsShowSignal:connect(function(active) settingsActive = active UpdateHamburgerIcon() end) return CreateMenuItem(settingsIconButton) end ------------ --- CHAT --- local function CreateChatIcon() local ChatModule = require(GuiRoot.Modules.Chat) local chatIconButton = Util.Create'ImageButton' { Name = "Chat"; Size = UDim2.new(0, 50, 0, TOPBAR_THICKNESS); Image = ""; AutoButtonColor = false; BackgroundTransparency = 1; }; local chatIconImage = Util.Create'ImageLabel' { Name = "ChatIcon"; Size = UDim2.new(0, 28, 0, 27); Position = UDim2.new(0.5, -14, 0.5, -13); BackgroundTransparency = 1; Image = "rbxasset://textures/ui/Chat/Chat.png"; Parent = chatIconButton; }; local chatCounter = Util.Create'ImageLabel' { Name = "ChatCounter"; Size = UDim2.new(0, 18, 0, 18); Position = UDim2.new(1, -12, 0, -4); BackgroundTransparency = 1; Image = "rbxasset://textures/ui/Chat/MessageCounter.png"; Visible = false; Parent = chatIconImage; }; local chatCountText = Util.Create'TextLabel' { Name = "ChatCounterText"; Text = ''; Size = UDim2.new(0, 13, 0, 9); Position = UDim2.new(0.5, -7, 0.5, -7); Font = Enum.Font.SourceSansBold; FontSize = Enum.FontSize.Size14; BorderSizePixel = 0; BackgroundTransparency = 1; TextColor3 = FONT_COLOR; TextYAlignment = Enum.TextYAlignment.Center; TextXAlignment = Enum.TextXAlignment.Center; Parent = chatCounter; }; local bubbleChatIsOn = not PlayersService.ClassicChat and PlayersService.BubbleChat local DEBOUNCE_TIME = 0.25 local chatActive = false local debounce = 0 local lastMessageCount = 0 local function OnUnreadMessagesChanged(count) if chatActive then lastMessageCount = count end local unreadCount = count - lastMessageCount if unreadCount <= 0 then chatCountText.Text = "" chatCounter.Visible = false else if unreadCount < 100 then chatCountText.Text = tostring(unreadCount) else chatCountText.Text = "!" end chatCounter.Visible = true end end local function updateIcon(down) if down then chatIconImage.Image = "rbxasset://textures/ui/Chat/ChatDown.png"; else chatIconImage.Image = "rbxasset://textures/ui/Chat/Chat.png"; end end local function onChatStateChanged(visible) chatActive = visible if not Util.IsTouchDevice() then updateIcon(chatActive) end OnUnreadMessagesChanged(ChatModule:GetMessageCount()) end function toggleChat() if Util.IsTouchDevice() or (GetBubbleChatbarFlag() and bubbleChatIsOn) then if debounce + DEBOUNCE_TIME < tick() then ChatModule:FocusChatBar() end else ChatModule:ToggleVisibility() end end chatIconButton.MouseButton1Click:connect(function() toggleChat() end) if ChatModule.MessagesChanged then ChatModule.MessagesChanged:connect(OnUnreadMessagesChanged) end if Util.IsTouchDevice() or (GetBubbleChatbarFlag() and bubbleChatIsOn) then if ChatModule.ChatBarFocusChanged then ChatModule.ChatBarFocusChanged:connect(function(isFocused) updateIcon(isFocused) debounce = tick() end) end updateIcon(false) end if ChatModule.VisibilityStateChanged then ChatModule.VisibilityStateChanged:connect(onChatStateChanged) end onChatStateChanged(ChatModule:GetVisibility()) OnUnreadMessagesChanged(ChatModule:GetMessageCount()) ChatModule:ToggleVisibility(true) return CreateMenuItem(chatIconButton) end ----------- --- Backpack --- local function CreateBackpackIcon() local BackpackModule = require(GuiRoot.Modules.BackpackScript) local backpackIconButton = Util.Create'ImageButton' { Name = "Backpack"; Size = UDim2.new(0, 50, 0, TOPBAR_THICKNESS); Image = ""; AutoButtonColor = false; BackgroundTransparency = 1; }; local backpackIconImage = Util.Create'ImageLabel' { Name = "BackpackIcon"; Size = UDim2.new(0, 22, 0, 28); Position = UDim2.new(0.5, -11, 0.5, -14); BackgroundTransparency = 1; Image = "rbxasset://textures/ui/Backpack/Backpack.png"; Parent = backpackIconButton; }; local function onBackpackStateChanged(open) if open then backpackIconImage.Image = "rbxasset://textures/ui/Backpack/Backpack_Down.png"; else backpackIconImage.Image = "rbxasset://textures/ui/Backpack/Backpack.png"; end end BackpackModule.StateChanged.Event:connect(onBackpackStateChanged) function toggleBackpack() BackpackModule:OpenClose() end backpackIconButton.MouseButton1Click:connect(function() BackpackModule:OpenClose() end) return CreateMenuItem(backpackIconButton) end -------------- ----- Stop Recording -- local function CreateStopRecordIcon() local stopRecordIconButton = Util.Create'ImageButton' { Name = "StopRecording"; Size = UDim2.new(0, 50, 0, TOPBAR_THICKNESS); Image = ""; Visible = true; BackgroundTransparency = 1; }; stopRecordIconButton:SetVerb("RecordToggle") local stopRecordIconLabel = Util.Create'ImageLabel' { Name = "StopRecordingIcon"; Size = UDim2.new(0, 28, 0, 28); Position = UDim2.new(0.5, -14, 0.5, -14); BackgroundTransparency = 1; Image = "rbxasset://textures/ui/RecordDown.png"; Parent = stopRecordIconButton; }; return CreateMenuItem(stopRecordIconButton) end ----------------------- ----- Shift Lock ------ local function CreateShiftLockIcon() local shiftlockIconButton = Util.Create'ImageButton' { Name = "ShiftLock"; Size = UDim2.new(0, 50, 0, TOPBAR_THICKNESS); AutoButtonColor = false; Image = ""; BackgroundTransparency = 1; }; local shiftlockIconLabel = Util.Create'ImageLabel' { Name = "ShiftlockIcon"; Size = UDim2.new(0, 31, 0, 31); Position = UDim2.new(0.5, -15, 0.5, -15); BackgroundTransparency = 1; Image = "rbxasset://textures/ui/ShiftLock/ShiftLock.png"; Parent = shiftlockIconButton; }; local shiftlockActive = false shiftlockIconButton.MouseButton1Click:connect(function() if shiftlockActive == false then shiftlockActive = true shiftlockIconLabel.Image = "rbxasset://textures/ui/ShiftLock/ShiftLockDown.png"; else shiftlockActive = false shiftlockIconLabel.Image = "rbxasset://textures/ui/ShiftLock/ShiftLock.png"; end end) return CreateMenuItem(shiftlockIconButton) end ---------------------- local settingsIcon = useNewSettings and CreateSettingsIcon() local chatIcon = CreateChatIcon() local backpackIcon = useNewBackpack and CreateBackpackIcon() --local shiftlockIcon = CreateShiftLockIcon() local nameAndHealthMenuItem = CreateUsernameHealthMenuItem() local leaderstatsMenuItem = useNewPlayerlist and CreateLeaderstatsMenuItem() local stopRecordingIcon = CreateStopRecordIcon() local LeftMenubar = CreateMenuBar('Left') local RightMenubar = CreateMenuBar('Right') -- Set Item Orders local LEFT_ITEM_ORDER = {} if settingsIcon then LEFT_ITEM_ORDER[settingsIcon] = 1 end if chatIcon then LEFT_ITEM_ORDER[chatIcon] = 2 end if backpackIcon then LEFT_ITEM_ORDER[backpackIcon] = 3 end if shiftlockIcon then LEFT_ITEM_ORDER[shiftlockIcon] = 4 end LEFT_ITEM_ORDER[stopRecordingIcon] = 5 local RIGHT_ITEM_ORDER = {} if leaderstatsMenuItem then RIGHT_ITEM_ORDER[leaderstatsMenuItem] = 1 end if nameAndHealthMenuItem then RIGHT_ITEM_ORDER[nameAndHealthMenuItem] = 2 end ------------------------- local TopBar = CreateTopBar() local function AddItemInOrder(Bar, Item, ItemOrder) local index = 1 while ItemOrder[Bar:ItemAtIndex(index)] and ItemOrder[Bar:ItemAtIndex(index)] < ItemOrder[Item] do index = index + 1 end Bar:AddItem(Item, index) end local function RobloxClientScreenSizeChanged(newSize) if container then -- Portait Phone if newSize.X <= 400 then -- Phone elseif newSize.X <= 640 then -- Tablet elseif newSize.X <= 1024 then -- Desktop else end end end local function OnCoreGuiChanged(coreGuiType, enabled) if coreGuiType == Enum.CoreGuiType.PlayerList or coreGuiType == Enum.CoreGuiType.All then if leaderstatsMenuItem then if enabled then AddItemInOrder(RightMenubar, leaderstatsMenuItem, RIGHT_ITEM_ORDER) else RightMenubar:RemoveItem(leaderstatsMenuItem) end end end if coreGuiType == Enum.CoreGuiType.Health or coreGuiType == Enum.CoreGuiType.All then if nameAndHealthMenuItem then nameAndHealthMenuItem:SetHealthbarEnabled(enabled) end end if coreGuiType == Enum.CoreGuiType.Backpack or coreGuiType == Enum.CoreGuiType.All then if backpackIcon then if enabled then AddItemInOrder(LeftMenubar, backpackIcon, LEFT_ITEM_ORDER) else LeftMenubar:RemoveItem(backpackIcon) end end end if coreGuiType == Enum.CoreGuiType.Chat or coreGuiType == Enum.CoreGuiType.All then if chatIcon then if enabled and Player.ChatMode == Enum.ChatMode.TextAndMenu then AddItemInOrder(LeftMenubar, chatIcon, LEFT_ITEM_ORDER) else LeftMenubar:RemoveItem(chatIcon) end end end if nameAndHealthMenuItem then local playerListOn = StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.PlayerList) local healthbarOn = StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Health) -- Left-align the player's name if either playerlist or healthbar is shown nameAndHealthMenuItem:SetNameVisible(playerListOn or healthbarOn) end end local function IsShiftLockModeEnabled() return GameSettings.ControlMode == Enum.ControlMode.MouseLockSwitch and GameSettings.ComputerMovementMode ~= Enum.ComputerMovementMode.ClickToMove and Player.DevEnableMouseLock and Player.DevComputerMovementMode ~= Enum.DevComputerMovementMode.Scriptable and Player.DevComputerMovementMode ~= Enum.DevComputerMovementMode.ClickToMove and Util.IsTouchDevice() == false end local function CheckShiftLockMode() if shiftlockIcon then if IsShiftLockModeEnabled() then AddItemInOrder(LeftMenubar, shiftlockIcon, LEFT_ITEM_ORDER) else LeftMenubar:RemoveItem(shiftlockIcon) end end end local function OnGameSettingsChanged(property) if property == 'ControlMode' or property == 'ComputerMovementMode' then CheckShiftLockMode() end end local function OnPlayerChanged(property) if property == 'DevEnableMouseLock' or property == 'DevComputerMovementMode' then CheckShiftLockMode() end end TopBar:SetTopbarDisplayMode(false) LeftMenubar:SetDock(TopBar:GetInstance()) RightMenubar:SetDock(TopBar:GetInstance()) Util.SetGUIInsetBounds(0, TOPBAR_THICKNESS, 0, 0) if settingsIcon then AddItemInOrder(LeftMenubar, settingsIcon, LEFT_ITEM_ORDER) end if nameAndHealthMenuItem then AddItemInOrder(RightMenubar, nameAndHealthMenuItem, RIGHT_ITEM_ORDER) end local gameOptions = settings():FindFirstChild("Game Options") if gameOptions then local success, result = pcall(function() gameOptions.VideoRecordingChangeRequest:connect(function(recording) if recording then AddItemInOrder(LeftMenubar, stopRecordingIcon, LEFT_ITEM_ORDER) else LeftMenubar:RemoveItem(stopRecordingIcon) end end) end) end -- Hook-up coregui changing StarterGui.CoreGuiChangedSignal:connect(OnCoreGuiChanged) for _, enumItem in pairs(Enum.CoreGuiType:GetEnumItems()) do OnCoreGuiChanged(enumItem, StarterGui:GetCoreGuiEnabled(enumItem)) end -- Hook up Shiftlock detection GameSettings.Changed:connect(OnGameSettingsChanged) Player.Changed:connect(OnPlayerChanged) CheckShiftLockMode() GuiRoot.Changed:connect(function(prop) if prop == "AbsoluteSize" then RobloxClientScreenSizeChanged(GuiRoot.AbsoluteSize) end end) RobloxClientScreenSizeChanged(GuiRoot.AbsoluteSize)