This commit is contained in:
lx
2026-07-06 13:39:13 -04:00
commit 34bf440a8c
2694 changed files with 77580 additions and 0 deletions
@@ -0,0 +1,214 @@
-- This script is responsible for loading in all build tools for build mode
-- Script Globals
local buildTools = {}
local currentTools = {}
local BaseUrl = game:GetService("ContentProvider").BaseUrl:lower()
if BaseUrl:find("www.roblox.com") or BaseUrl:find("gametest1") then
DeleteToolID = 73089190
PartSelectionID = 73089166
CloneToolID = 73089204
RotateToolID = 73089214
ConfigToolID = 73089239
WiringToolID = 73089259
classicToolID = 58921588
elseif BaseUrl:find("gametest2") then
DeleteToolID = 70353317
PartSelectionID = 70353315
CloneToolID = 70353314
RotateToolID = 70353318
ConfigToolID = 70353319
WiringToolID = 70353320
classicToolID = 58921588
end
local player = nil
local backpack = nil
-- Basic Functions
local function waitForProperty(instance, name)
while not instance[name] do
instance.Changed:wait()
end
end
local function waitForChild(instance, name)
while not instance:FindFirstChild(name) do
instance.ChildAdded:wait()
end
end
waitForProperty(game:GetService("Players"),"LocalPlayer")
waitForProperty(game:GetService("Players").LocalPlayer,"userId")
-- we aren't in a true build mode session, don't give build tools and delete this script
if game:GetService("Players").LocalPlayer.userId < 1 then
script:Destroy()
return -- this is probably not necessesary, doing it just in case
end
-- Functions
function getLatestPlayer()
waitForProperty(game:GetService("Players"),"LocalPlayer")
player = game:GetService("Players").LocalPlayer
waitForChild(player,"Backpack")
backpack = player.Backpack
end
function waitForCharacterLoad()
local startTick = tick()
local playerLoaded = false
local success = pcall(function() playerLoaded = player.AppearanceDidLoad end) --TODO: remove pcall once this in client on prod
if not success then return false end
while not playerLoaded do
player.Changed:wait()
playerLoaded = player.AppearanceDidLoad
end
return true
end
function showBuildToolsTutorial()
local tutorialKey = "BuildToolsTutorial"
if UserSettings().GameSettings:GetTutorialState(tutorialKey) == true then return end --already have shown tutorial
local RbxGui = LoadLibrary("RbxGui")
local frame, showTutorial, dismissTutorial, gotoPage = RbxGui.CreateTutorial("Build", tutorialKey, false)
local firstPage = RbxGui.CreateImageTutorialPage(" ", "http://www.roblox.com/asset/?id=59162193", 359, 296, function() dismissTutorial() end, true)
RbxGui.AddTutorialPage(frame, firstPage)
frame.Parent = game:GetService("CoreGui"):FindFirstChild("RobloxGui")
game:GetService("GuiService"):AddCenterDialog(frame, Enum.CenterDialogType.UnsolicitedDialog,
--showFunction
function()
frame.Visible = true
showTutorial()
end,
--hideFunction
function()
frame.Visible = false
end
)
wait(1)
showTutorial()
end
function clearLoadout()
currentTools = {}
local backpackChildren = game:GetService("Players").LocalPlayer.Backpack:GetChildren()
for i = 1, #backpackChildren do
if backpackChildren[i]:IsA("Tool") or backpackChildren[i]:IsA("HopperBin") then
table.insert(currentTools,backpackChildren[i])
end
end
if game:GetService("Players").LocalPlayer["Character"] then
local characterChildren = game:GetService("Players").LocalPlayer.Character:GetChildren()
for i = 1, #characterChildren do
if characterChildren[i]:IsA("Tool") or characterChildren[i]:IsA("HopperBin") then
table.insert(currentTools,characterChildren[i])
end
end
end
for i = 1, #currentTools do
currentTools[i].Parent = nil
end
end
function giveToolsBack()
for i = 1, #currentTools do
currentTools[i].Parent = game:GetService("Players").LocalPlayer.Backpack
end
end
function backpackHasTool(tool)
local backpackChildren = backpack:GetChildren()
for i = 1, #backpackChildren do
if backpackChildren[i] == tool then
return true
end
end
return false
end
function getToolAssetID(assetID)
local newTool = game:GetService("InsertService"):LoadAsset(assetID)
local toolChildren = newTool:GetChildren()
for i = 1, #toolChildren do
if toolChildren[i]:IsA("Tool") then
return toolChildren[i]
end
end
return nil
end
-- remove legacy identifiers
-- todo: determine if we still need this
function removeBuildToolTag(tool)
if tool:FindFirstChild("RobloxBuildTool") then
tool.RobloxBuildTool:Destroy()
end
end
function giveAssetId(assetID,toolName)
local theTool = getToolAssetID(assetID,toolName)
if theTool and not backpackHasTool(theTool) then
removeBuildToolTag(theTool)
theTool.Parent = backpack
table.insert(buildTools,theTool)
end
end
function loadBuildTools()
giveAssetId(PartSelectionID)
giveAssetId(DeleteToolID)
giveAssetId(CloneToolID)
giveAssetId(RotateToolID)
giveAssetId(WiringToolID)
giveAssetId(ConfigToolID)
-- deprecated tools
giveAssetId(classicToolID)
end
function givePlayerBuildTools()
getLatestPlayer()
clearLoadout()
loadBuildTools()
giveToolsBack()
end
function takePlayerBuildTools()
for k,v in ipairs(buildTools) do
v.Parent = nil
end
buildTools = {}
end
-- Script start
getLatestPlayer()
waitForCharacterLoad()
givePlayerBuildTools()
-- If player dies, we make sure to give them build tools again
player.CharacterAdded:connect(function()
takePlayerBuildTools()
givePlayerBuildTools()
end)
showBuildToolsTutorial()
@@ -0,0 +1,206 @@
-- Personal Server Script
-----------------
--| Constants |--
-----------------
local CHANGES_PER_PLAYER = 100 -- Saving also occurs every time the number of edits reaches this number times the number of players
local SAVE_CHECK_INTERVAL = 1800 -- should be set in seconds, this is how long we wait to force a save, as long as at least one change has been made
local MIN_SAVE_TIME = 900 -- At least this many seconds will pass before saving again
-----------------
--| Variables |--
-----------------
local ContentProviderService = game:GetService('ContentProvider')
local PlayersService = game:GetService('Players')
local RunService = game:GetService("RunService")
local StartingPlayerRanks = {}
local RbxUtil = nil
local LastSaveTime = 0
local ChangeCount = 0
local TryingToSave = false
local NumberOfChangesBeforeSaveAbsolute = CHANGES_PER_PLAYER
local GameRunning = true
local WaitingToSave = false
local PlaceId = game.PlaceId
local Url = ContentProviderService.BaseUrl
local UrlBase = Url:match('^http://www\.(.-)/?$') -- Turns "http://www.gametest1.robloxlabs.com/" into "gametest1.robloxlabs.com"
local ApiProxyUrl = 'https://api.' .. UrlBase
local DataFarmProtocol = 'http'
local DataFarmUsesHttpsFlagExists, DataFarmUsesHttpsFlagValue = pcall(function () return settings():GetFFlag("DataFarmUsesHttps") end)
if DataFarmUsesHttpsFlagExists and DataFarmUsesHttpsFlagValue then
DataFarmProtocol = 'https'
end
local DataFarmUrl = DataFarmProtocol .. '://data.' .. UrlBase
-----------------
--| Functions |--
-----------------
function GetRbxUtil()
if not RbxUtil then
RbxUtil = LoadLibrary("RbxUtility")
end
return RbxUtil
end
-- Checks the full hierarchy of an instance for archivability
local function IsArchivable(instance)
if instance == workspace then
return true
elseif not instance.Archivable then
return false
else
return IsArchivable(instance.Parent)
end
end
local function UpdateSaveOnChangeAmount()
local players = PlayersService:GetPlayers()
NumberOfChangesBeforeSaveAbsolute = #players * CHANGES_PER_PLAYER
end
local function OnPlayerAdded(player)
if player:IsA('Player') then
local getRankUrl = ApiProxyUrl .. '/RoleSets/GetRoleSetForUser?placeId=' .. tostring(PlaceId) .. '&userId=' .. tostring(player.userId)
local serverRankTable = nil
pcall(function()
serverRankTable = GetRbxUtil().DecodeJSON(game:HttpGetAsync(getRankUrl))
end)
local playerRank = 0
if serverRankTable and type(serverRankTable) == 'table' then
for k, v in pairs(serverRankTable) do
if k == "data" then
if v["Rank"] then
playerRank = v["Rank"]
end
end
end
end
player.PersonalServerRank = playerRank
StartingPlayerRanks[player] = playerRank
UpdateSaveOnChangeAmount()
end
end
local function OnPlayerRemoved(player)
if player:IsA('Player') then
UpdateSaveOnChangeAmount()
if StartingPlayerRanks[player] then
local playerRank = player.PersonalServerRank
if StartingPlayerRanks[player] ~= playerRank then -- Don't need to make web call if rank is the same
local setRankUrl = ApiProxyUrl .. '/RoleSets/PrivilegedSetUserRoleSetRank?placeId=' .. tostring(PlaceId) .. '&userId=' .. tostring(player.userId) .. '&newRank=' .. tostring(playerRank)
ypcall(function() game:HttpPostAsync(setRankUrl, 'SetPersonalServerRank') end)
end
StartingPlayerRanks[player] = nil
end
end
end
local function DoSave()
if GameRunning then
ChangeCount = 0
LastSaveTime = tick()
game:ServerSave()
end
end
local function TrySave()
if not TryingToSave then
TryingToSave = true
local now = tick()
if now - LastSaveTime >= MIN_SAVE_TIME then
DoSave()
elseif not WaitingToSave then -- Save after cooldown
WaitingToSave = true
delay(LastSaveTime + MIN_SAVE_TIME - now, function()
DoSave()
WaitingToSave = false
end)
end
TryingToSave = false
end
end
-- Save based on number of edits to workspace
local function OnEdit(descendant)
if IsArchivable(descendant) then
ChangeCount = ChangeCount + 1
if ChangeCount >= NumberOfChangesBeforeSaveAbsolute then
TrySave()
end
end
end
-- Make sure we save every interval regardless of number of edits, so long as there is one
local function CheckForSaveOnInterval()
while true do
wait(SAVE_CHECK_INTERVAL)
if tick() - LastSaveTime >= SAVE_CHECK_INTERVAL and ChangeCount > 0 then
TrySave()
end
end
end
--------------------
--| Script Logic |--
--------------------
game:WaitForChild('Workspace')
pcall(function()
game.IsPersonalServer = true
if not workspace:FindFirstChild("PSVariable") then
local psVar = Instance.new("BoolValue")
psVar.Name = "PSVariable"
psVar.Archivable = false
psVar.Parent = workspace
end
end)
PlayersService.PlayerAdded:connect(OnPlayerAdded)
PlayersService.ChildRemoved:connect(OnPlayerRemoved)
for _, player in pairs(PlayersService:GetPlayers()) do
OnPlayerAdded(player)
end
local useSubdomainsFlagExists, useSubdomainsFlagValue = pcall(function () return settings():GetFFlag("UseNewSubdomainsInCoreScripts") end)
local saveUrlBase = Url
if(useSubdomainsFlagExists and useSubdomainsFlagValue and DataFarmUrl~=nil) then
saveUrlBase = DataFarmUrl
end
if saveUrlBase~=nil then
game:SetServerSaveUrl(saveUrlBase .. "/Data/AutoSave.ashx?assetId=" .. PlaceId)
end
if pcall(function()
game.Close:connect(
function()
GameRunning = false
game:ServerSave()
end)
end) == false then
print("!Error in Game.Close:connect")
end
RunService:Run()
game:GetService("Workspace").DescendantAdded:connect(OnEdit)
game:GetService("Workspace").DescendantRemoving:connect(OnEdit)
spawn(CheckForSaveOnInterval)
@@ -0,0 +1,268 @@
-- ContextActionTouch.lua
-- Copyright ROBLOX 2014, created by Ben Tkacheff
-- this script controls ui and firing of lua functions that are bound in ContextActionService for touch inputs
-- Essentially a user can bind a lua function to a key code, input type (mousebutton1 etc.) and this
-- Variables
local contextActionService = game:GetService("ContextActionService")
local userInputService = game:GetService("UserInputService")
local isTouchDevice = userInputService.TouchEnabled
local functionTable = {}
local buttonVector = {}
local buttonScreenGui = nil
local buttonFrame = nil
local ContextDownImage = "http://www.roblox.com/asset/?id=97166756"
local ContextUpImage = "http://www.roblox.com/asset/?id=97166444"
local oldTouches = {}
local buttonPositionTable = {
[1] = UDim2.new(0,123,0,70),
[2] = UDim2.new(0,30,0,60),
[3] = UDim2.new(0,180,0,160),
[4] = UDim2.new(0,85,0,-25),
[5] = UDim2.new(0,185,0,-25),
[6] = UDim2.new(0,185,0,260),
[7] = UDim2.new(0,216,0,65)
}
local maxButtons = #buttonPositionTable
-- Preload images
game:GetService("ContentProvider"):Preload(ContextDownImage)
game:GetService("ContentProvider"):Preload(ContextUpImage)
repeat wait() until game:GetService("Players").LocalPlayer
local localPlayer = game:GetService("Players").LocalPlayer
function createContextActionGui()
if not buttonScreenGui and isTouchDevice then
buttonScreenGui = Instance.new("ScreenGui")
buttonScreenGui.Name = "ContextActionGui"
buttonFrame = Instance.new("Frame")
buttonFrame.BackgroundTransparency = 1
buttonFrame.Size = UDim2.new(0.3,0,0.5,0)
buttonFrame.Position = UDim2.new(0.7,0,0.5,0)
buttonFrame.Name = "ContextButtonFrame"
buttonFrame.Parent = buttonScreenGui
buttonFrame.Visible = not userInputService.ModalEnabled
userInputService.Changed:connect(function(property)
if property == "ModalEnabled" then
buttonFrame.Visible = not userInputService.ModalEnabled
end
end)
end
end
-- functions
function setButtonSizeAndPosition(object)
local buttonSize = 55
local xOffset = 10
local yOffset = 95
-- todo: better way to determine mobile sized screens
local onSmallScreen = (game:GetService("CoreGui").RobloxGui.AbsoluteSize.X < 600)
if not onSmallScreen then
buttonSize = 85
xOffset = 40
end
object.Size = UDim2.new(0,buttonSize,0,buttonSize)
end
function contextButtonDown(button, inputObject, actionName)
if inputObject.UserInputType == Enum.UserInputType.Touch then
button.Image = ContextDownImage
contextActionService:CallFunction(actionName, Enum.UserInputState.Begin, inputObject)
end
end
function contextButtonMoved(button, inputObject, actionName)
if inputObject.UserInputType == Enum.UserInputType.Touch then
button.Image = ContextDownImage
contextActionService:CallFunction(actionName, Enum.UserInputState.Change, inputObject)
end
end
function contextButtonUp(button, inputObject, actionName)
button.Image = ContextUpImage
if inputObject.UserInputType == Enum.UserInputType.Touch and inputObject.UserInputState == Enum.UserInputState.End then
contextActionService:CallFunction(actionName, Enum.UserInputState.End, inputObject)
end
end
function isSmallScreenDevice()
return game:GetService("GuiService"):GetScreenResolution().y <= 320
end
function createNewButton(actionName, functionInfoTable)
local contextButton = Instance.new("ImageButton")
contextButton.Name = "ContextActionButton"
contextButton.BackgroundTransparency = 1
contextButton.Size = UDim2.new(0,90,0,90)
contextButton.Active = true
if isSmallScreenDevice() then
contextButton.Size = UDim2.new(0,70,0,70)
end
contextButton.Image = ContextUpImage
contextButton.Parent = buttonFrame
local currentButtonTouch = nil
userInputService.InputEnded:connect(function ( inputObject )
oldTouches[inputObject] = nil
end)
contextButton.InputBegan:connect(function(inputObject)
if oldTouches[inputObject] then return end
if inputObject.UserInputState == Enum.UserInputState.Begin and currentButtonTouch == nil then
currentButtonTouch = inputObject
contextButtonDown(contextButton, inputObject, actionName)
end
end)
contextButton.InputChanged:connect(function(inputObject)
if oldTouches[inputObject] then return end
if currentButtonTouch ~= inputObject then return end
contextButtonMoved(contextButton, inputObject, actionName)
end)
contextButton.InputEnded:connect(function(inputObject)
if oldTouches[inputObject] then return end
if currentButtonTouch ~= inputObject then return end
currentButtonTouch = nil
oldTouches[inputObject] = true
contextButtonUp(contextButton, inputObject, actionName)
end)
local actionIcon = Instance.new("ImageLabel")
actionIcon.Name = "ActionIcon"
actionIcon.Position = UDim2.new(0.175, 0, 0.175, 0)
actionIcon.Size = UDim2.new(0.65, 0, 0.65, 0)
actionIcon.BackgroundTransparency = 1
if functionInfoTable["image"] and type(functionInfoTable["image"]) == "string" then
actionIcon.Image = functionInfoTable["image"]
end
actionIcon.Parent = contextButton
local actionTitle = Instance.new("TextLabel")
actionTitle.Name = "ActionTitle"
actionTitle.Size = UDim2.new(1,0,1,0)
actionTitle.BackgroundTransparency = 1
actionTitle.Font = Enum.Font.SourceSansBold
actionTitle.TextColor3 = Color3.new(1,1,1)
actionTitle.TextStrokeTransparency = 0
actionTitle.FontSize = Enum.FontSize.Size18
actionTitle.TextWrapped = true
actionTitle.Text = ""
if functionInfoTable["title"] and type(functionInfoTable["title"]) == "string" then
actionTitle.Text = functionInfoTable["title"]
end
actionTitle.Parent = contextButton
return contextButton
end
function createButton( actionName, functionInfoTable )
local button = createNewButton(actionName, functionInfoTable)
local position = nil
for i = 1,#buttonVector do
if buttonVector[i] == "empty" then
position = i
break
end
end
if not position then
position = #buttonVector + 1
end
if position > maxButtons then
return -- todo: let user know we have too many buttons already?
end
buttonVector[position] = button
functionTable[actionName]["button"] = button
button.Position = buttonPositionTable[position]
button.Parent = buttonFrame
if buttonScreenGui and buttonScreenGui.Parent == nil then
buttonScreenGui.Parent = localPlayer.PlayerGui
end
end
function removeAction(actionName)
if not functionTable[actionName] then return end
local actionButton = functionTable[actionName]["button"]
if actionButton then
actionButton.Parent = nil
for i = 1,#buttonVector do
if buttonVector[i] == actionButton then
buttonVector[i] = "empty"
break
end
end
actionButton:Destroy()
end
functionTable[actionName] = nil
end
function addAction(actionName,createTouchButton,functionInfoTable)
if functionTable[actionName] then
removeAction(actionName)
end
functionTable[actionName] = {functionInfoTable}
if createTouchButton and isTouchDevice then
createContextActionGui()
createButton(actionName, functionInfoTable)
end
end
-- Connections
contextActionService.BoundActionChanged:connect( function(actionName, changeName, changeTable)
if functionTable[actionName] and changeTable then
local button = functionTable[actionName]["button"]
if button then
if changeName == "image" then
button.ActionIcon.Image = changeTable[changeName]
elseif changeName == "title" then
button.ActionTitle.Text = changeTable[changeName]
elseif changeName == "description" then
-- todo: add description to menu
elseif changeName == "position" then
button.Position = changeTable[changeName]
end
end
end
end)
contextActionService.BoundActionAdded:connect( function(actionName, createTouchButton, functionInfoTable)
addAction(actionName, createTouchButton, functionInfoTable)
end)
contextActionService.BoundActionRemoved:connect( function(actionName, functionInfoTable)
removeAction(actionName)
end)
contextActionService.GetActionButtonEvent:connect( function(actionName)
if functionTable[actionName] then
contextActionService:FireActionButtonFoundSignal(actionName, functionTable[actionName]["button"])
end
end)
-- make sure any bound data before we setup connections is handled
local boundActions = contextActionService:GetAllBoundActionInfo()
for actionName, actionData in pairs(boundActions) do
addAction(actionName,actionData["createTouchButton"],actionData)
end
@@ -0,0 +1,693 @@
--[[
Filename: GamepadMenu.lua
Written by: jeditkacheff
Version 1.1
Description: Controls the radial menu that appears when pressing menu button on gamepad
--]]
--[[ SERVICES ]]
local GuiService = game:GetService('GuiService')
local CoreGuiService = game:GetService('CoreGui')
local InputService = game:GetService('UserInputService')
local ContextActionService = game:GetService('ContextActionService')
local HttpService = game:GetService('HttpService')
local StarterGui = game:GetService('StarterGui')
local GuiRoot = CoreGuiService:WaitForChild('RobloxGui')
--[[ END OF SERVICES ]]
--[[ MODULES ]]
local tenFootInterface = require(GuiRoot.Modules.TenFootInterface)
local utility = require(GuiRoot.Modules.Settings.Utility)
local recordPage = require(GuiRoot.Modules.Settings.Pages.Record)
--[[ VARIABLES ]]
local gamepadSettingsFrame = nil
local isVisible = false
local smallScreen = utility:IsSmallTouchScreen()
local isTenFootInterface = tenFootInterface:IsEnabled()
local radialButtons = {}
local lastInputChangedCon = nil
local function getButtonForCoreGuiType(coreGuiType)
if coreGuiType == Enum.CoreGuiType.All then
return radialButtons
else
for button, table in pairs(radialButtons) do
if table["CoreGuiType"] == coreGuiType then
return button
end
end
end
return nil
end
local function getImagesForSlot(slot)
if slot == 1 then return "rbxasset://textures/ui/Settings/Radial/Top.png", "rbxasset://textures/ui/Settings/Radial/TopSelected.png",
"rbxasset://textures/ui/Settings/Radial/Menu.png",
UDim2.new(0.5,-26,0,18), UDim2.new(0,52,0,41),
UDim2.new(0,150,0,100), UDim2.new(0.5,-75,0,0)
elseif slot == 2 then return "rbxasset://textures/ui/Settings/Radial/TopRight.png", "rbxasset://textures/ui/Settings/Radial/TopRightSelected.png",
"rbxasset://textures/ui/Settings/Radial/PlayerList.png",
UDim2.new(1,-90,0,90), UDim2.new(0,52,0,52),
UDim2.new(0,108,0,150), UDim2.new(1,-110,0,50)
elseif slot == 3 then return "rbxasset://textures/ui/Settings/Radial/BottomRight.png", "rbxasset://textures/ui/Settings/Radial/BottomRightSelected.png",
"rbxasset://textures/ui/Settings/Radial/Alert.png",
UDim2.new(1,-85,1,-150), UDim2.new(0,42,0,58),
UDim2.new(0,120,0,150), UDim2.new(1,-120,1,-200)
elseif slot == 4 then return "rbxasset://textures/ui/Settings/Radial/Bottom.png", "rbxasset://textures/ui/Settings/Radial/BottomSelected.png",
"rbxasset://textures/ui/Settings/Radial/Leave.png",
UDim2.new(0.5,-20,1,-62), UDim2.new(0,55,0,46),
UDim2.new(0,150,0,100), UDim2.new(0.5,-75,1,-100)
elseif slot == 5 then return "rbxasset://textures/ui/Settings/Radial/BottomLeft.png", "rbxasset://textures/ui/Settings/Radial/BottomLeftSelected.png",
"rbxasset://textures/ui/Settings/Radial/Backpack.png",
UDim2.new(0,40,1,-150), UDim2.new(0,44,0,56),
UDim2.new(0,110,0,150), UDim2.new(0,0,0,205)
elseif slot == 6 then return "rbxasset://textures/ui/Settings/Radial/TopLeft.png", "rbxasset://textures/ui/Settings/Radial/TopLeftSelected.png",
"rbxasset://textures/ui/Settings/Radial/Chat.png",
UDim2.new(0,35,0,100), UDim2.new(0,56,0,53),
UDim2.new(0,110,0,150), UDim2.new(0,0,0,50)
end
return "", "", UDim2.new(0,0,0,0), UDim2.new(0,0,0,0)
end
local function setSelectedRadialButton(selectedObject)
for button, buttonTable in pairs(radialButtons) do
local isVisible = (button == selectedObject)
button:FindFirstChild("Selected").Visible = isVisible
button:FindFirstChild("RadialLabel").Visible = isVisible
end
end
local function activateSelectedRadialButton()
for button, buttonTable in pairs(radialButtons) do
if button:FindFirstChild("Selected").Visible then
buttonTable["Function"]()
return true
end
end
return false
end
local function setButtonEnabled(button, enabled)
if radialButtons[button]["Disabled"] == not enabled then return end
if button:FindFirstChild("Selected").Visible == true then
setSelectedRadialButton(nil)
end
if enabled then
button.Image = string.gsub(button.Image, "rbxasset://textures/ui/Settings/Radial/Empty", "rbxasset://textures/ui/Settings/Radial/")
button.ImageTransparency = 0
button.RadialIcon.ImageTransparency = 0
else
button.Image = string.gsub(button.Image, "rbxasset://textures/ui/Settings/Radial/", "rbxasset://textures/ui/Settings/Radial/Empty")
button.ImageTransparency = 0
button.RadialIcon.ImageTransparency = 1
end
radialButtons[button]["Disabled"] = not enabled
end
local function setButtonVisible(button, visible)
button.Visible = visible
if not visible then
setButtonEnabled(button, false)
end
end
local function enableVR()
local visibleButtons = {
Settings = true, LeaveGame = true,
PlayerList = false, Notifications = false,
Backpack = false, Chat = false
}
for button, _ in pairs(radialButtons) do
if visibleButtons[button.Name] ~= nil then
setButtonVisible(button, visibleButtons[button.Name])
end
end
end
local emptySelectedImageObject = utility:Create'ImageLabel'
{
BackgroundTransparency = 1,
Size = UDim2.new(1,0,1,0),
Image = ""
};
local function createRadialButton(name, text, slot, disabled, coreGuiType, activateFunc)
local slotImage, selectedSlotImage, slotIcon,
slotIconPosition, slotIconSize, mouseFrameSize, mouseFramePos = getImagesForSlot(slot)
local radialButton = utility:Create'ImageButton'
{
Name = name,
Position = UDim2.new(0,0,0,0),
Size = UDim2.new(1,0,1,0),
BackgroundTransparency = 1,
Image = slotImage,
ZIndex = 2,
SelectionImageObject = emptySelectedImageObject,
Parent = gamepadSettingsFrame
};
if disabled then
radialButton.Image = string.gsub(radialButton.Image, "rbxasset://textures/ui/Settings/Radial/", "rbxasset://textures/ui/Settings/Radial/Empty")
end
local selectedRadial = utility:Create'ImageLabel'
{
Name = "Selected",
Position = UDim2.new(0,0,0,0),
Size = UDim2.new(1,0,1,0),
BackgroundTransparency = 1,
Image = selectedSlotImage,
ZIndex = 2,
Visible = false,
Parent = radialButton
};
local radialIcon = utility:Create'ImageLabel'
{
Name = "RadialIcon",
Position = slotIconPosition,
Size = slotIconSize,
BackgroundTransparency = 1,
Image = slotIcon,
ZIndex = 3,
ImageTransparency = disabled and 1 or 0,
Parent = radialButton
};
local nameLabel = utility:Create'TextLabel'
{
Size = UDim2.new(0,220,0,50),
Position = UDim2.new(0.5, -110, 0.5, -25),
BackgroundTransparency = 1,
Text = text,
Font = Enum.Font.SourceSansBold,
FontSize = Enum.FontSize.Size14,
TextColor3 = Color3.new(1,1,1),
Name = "RadialLabel",
Visible = false,
ZIndex = 2,
Parent = radialButton
};
if not smallScreen then
nameLabel.FontSize = Enum.FontSize.Size36
nameLabel.Size = UDim2.new(nameLabel.Size.X.Scale, nameLabel.Size.X.Offset, nameLabel.Size.Y.Scale, nameLabel.Size.Y.Offset + 4)
end
local nameBackgroundImage = utility:Create'ImageLabel'
{
Name = text .. "BackgroundImage",
Size = UDim2.new(1,0,1,0),
Position = UDim2.new(0,0,0,2),
BackgroundTransparency = 1,
Image = "rbxasset://textures/ui/Settings/Radial/RadialLabel@2x.png",
ScaleType = Enum.ScaleType.Slice,
SliceCenter = Rect.new(24,4,130,42),
ZIndex = 2,
Parent = nameLabel
};
local mouseFrame = utility:Create'ImageButton'
{
Name = "MouseFrame",
Position = mouseFramePos,
Size = mouseFrameSize,
ZIndex = 3,
BackgroundTransparency = 1,
SelectionImageObject = emptySelectedImageObject,
Parent = radialButton
};
mouseFrame.MouseEnter:connect(function()
if not radialButtons[radialButton]["Disabled"] then
setSelectedRadialButton(radialButton)
end
end)
mouseFrame.MouseLeave:connect(function()
setSelectedRadialButton(nil)
end)
mouseFrame.MouseButton1Click:connect(function()
if selectedRadial.Visible then
activateFunc()
end
end)
radialButtons[radialButton] = {["Function"] = activateFunc, ["Disabled"] = disabled, ["CoreGuiType"] = coreGuiType}
return radialButton
end
local function createGamepadMenuGui()
gamepadSettingsFrame = utility:Create'Frame'
{
Name = "GamepadSettingsFrame",
Position = UDim2.new(0.5,-51,0.5,-51),
BackgroundTransparency = 1,
BorderSizePixel = 0,
Size = UDim2.new(0,102,0,102),
Visible = false,
Parent = GuiRoot
};
---------------------------------
-------- Settings Menu ----------
local settingsFunc = function()
toggleCoreGuiRadial(true)
local MenuModule = require(GuiRoot.Modules.Settings.SettingsHub)
MenuModule:SetVisibility(true, nil, nil, true)
end
local settingsRadial = createRadialButton("Settings", "Settings", 1, false, nil, settingsFunc)
settingsRadial.Parent = gamepadSettingsFrame
---------------------------------
-------- Player List ------------
local playerListFunc = function()
toggleCoreGuiRadial(true)
local PlayerListModule = require(GuiRoot.Modules.PlayerlistModule)
if not PlayerListModule:IsOpen() then
PlayerListModule:ToggleVisibility()
end
end
local playerListRadial = createRadialButton("PlayerList", "Player List", 2, not StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.PlayerList), Enum.CoreGuiType.PlayerList, playerListFunc)
playerListRadial.Parent = gamepadSettingsFrame
---------------------------------
-------- Notifications ----------
local gamepadNotifications = Instance.new("BindableEvent")
gamepadNotifications.Name = "GamepadNotifications"
gamepadNotifications.Parent = script
local notificationsFunc = function()
toggleCoreGuiRadial()
gamepadNotifications:Fire(true)
end
local notificationsRadial = createRadialButton("Notifications", "Notifications", 3, false, nil, notificationsFunc)
if isTenFootInterface then
setButtonEnabled(notificationsRadial, false)
end
notificationsRadial.Parent = gamepadSettingsFrame
---------------------------------
---------- Leave Game -----------
local leaveGameFunc = function()
toggleCoreGuiRadial(true)
local MenuModule = require(GuiRoot.Modules.Settings.SettingsHub)
MenuModule:SetVisibility(true, false, require(GuiRoot.Modules.Settings.Pages.LeaveGame), true)
end
local leaveGameRadial = createRadialButton("LeaveGame", "Leave Game", 4, false, nil, leaveGameFunc)
leaveGameRadial.Parent = gamepadSettingsFrame
---------------------------------
---------- Backpack -------------
local backpackFunc = function()
toggleCoreGuiRadial(true)
local BackpackModule = require(GuiRoot.Modules.BackpackScript)
BackpackModule:OpenClose()
end
local backpackRadial = createRadialButton("Backpack", "Backpack", 5, not StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Backpack), Enum.CoreGuiType.Backpack, backpackFunc)
backpackRadial.Parent = gamepadSettingsFrame
---------------------------------
------------ Chat ---------------
local chatFunc = function()
toggleCoreGuiRadial()
local ChatModule = require(GuiRoot.Modules.Chat)
ChatModule:ToggleVisibility()
end
local chatRadial = createRadialButton("Chat", "Chat", 6, not StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Chat), Enum.CoreGuiType.Chat, chatFunc)
if isTenFootInterface then
setButtonEnabled(chatRadial, false)
end
chatRadial.Parent = gamepadSettingsFrame
---------------------------------
--------- Close Button ----------
local closeHintImage = utility:Create'ImageLabel'
{
Name = "CloseHint",
Position = UDim2.new(1,10,1,10),
Size = UDim2.new(0,60,0,60),
BackgroundTransparency = 1,
Image = "rbxasset://textures/ui/Settings/Help/BButtonDark.png",
Parent = gamepadSettingsFrame
}
if isTenFootInterface then
closeHintImage.Image = "rbxasset://textures/ui/Settings/Help/BButtonDark@2x.png"
closeHintImage.Size = UDim2.new(0,90,0,90)
end
local closeHintText = utility:Create'TextLabel'
{
Name = "closeHintText",
Position = UDim2.new(1,10,0.5,-12),
Size = UDim2.new(0,43,0,24),
Font = Enum.Font.SourceSansBold,
FontSize = Enum.FontSize.Size24,
BackgroundTransparency = 1,
Text = "Back",
TextColor3 = Color3.new(1,1,1),
TextXAlignment = Enum.TextXAlignment.Left,
Parent = closeHintImage
}
if isTenFootInterface then
closeHintText.FontSize = Enum.FontSize.Size36
end
------------------------------------------
--------- Stop Recording Button ----------
--todo: enable this when recording is not a verb
--[[local stopRecordingImage = utility:Create'ImageLabel'
{
Name = "StopRecordingHint",
Position = UDim2.new(0,-100,1,10),
Size = UDim2.new(0,61,0,61),
BackgroundTransparency = 1,
Image = "rbxasset://textures/ui/Settings/Help/YButtonDark.png",
Visible = recordPage:IsRecording(),
Parent = gamepadSettingsFrame
}
local stopRecordingText = utility:Create'TextLabel'
{
Name = "stopRecordingHintText",
Position = UDim2.new(1,10,0.5,-12),
Size = UDim2.new(0,43,0,24),
Font = Enum.Font.SourceSansBold,
FontSize = Enum.FontSize.Size24,
BackgroundTransparency = 1,
Text = "Stop Recording",
TextColor3 = Color3.new(1,1,1),
TextXAlignment = Enum.TextXAlignment.Left,
Parent = stopRecordingImage
}
recordPage.RecordingChanged:connect(function(isRecording)
stopRecordingImage.Visible = isRecording
end)]]
GuiService:AddSelectionParent(HttpService:GenerateGUID(false), gamepadSettingsFrame)
gamepadSettingsFrame.Changed:connect(function(prop)
if prop == "Visible" then
if not gamepadSettingsFrame.Visible then
unbindAllRadialActions()
end
end
end)
if InputService.VREnabled then
enableVR()
end
end
local function isCoreGuiDisabled()
for _, enumItem in pairs(Enum.CoreGuiType:GetEnumItems()) do
if StarterGui:GetCoreGuiEnabled(enumItem) then
return false
end
end
return true
end
local function setupGamepadControls()
local freezeControllerActionName = "doNothingAction"
local radialSelectActionName = "RadialSelectAction"
local thumbstick2RadialActionName = "Thumbstick2RadialAction"
local radialCancelActionName = "RadialSelectCancel"
local radialAcceptActionName = "RadialSelectAccept"
local toggleMenuActionName = "RBXToggleMenuAction"
local noOpFunc = function() end
local doGamepadMenuButton = nil
function unbindAllRadialActions()
local success = pcall(function() GuiService.CoreGuiNavigationEnabled = true end)
if not success then
GuiService.GuiNavigationEnabled = true
end
ContextActionService:UnbindCoreAction(radialSelectActionName)
ContextActionService:UnbindCoreAction(radialCancelActionName)
ContextActionService:UnbindCoreAction(radialAcceptActionName)
ContextActionService:UnbindCoreAction(freezeControllerActionName)
ContextActionService:UnbindCoreAction(thumbstick2RadialActionName)
end
local radialButtonLayout = { PlayerList = {
Range = { Begin = 36,
End = 96
}
},
Notifications = {
Range = { Begin = 96,
End = 156
}
},
LeaveGame = {
Range = { Begin = 156,
End = 216
}
},
Backpack = {
Range = { Begin = 216,
End = 276
}
},
Chat = {
Range = { Begin = 276,
End = 336
}
},
Settings = {
Range = { Begin = 336,
End = 36
}
},
}
local function getSelectedObjectFromAngle(angle, depth)
local closest = nil
local closestDistance = 30 -- threshold of 30 for selecting the closest radial button
for radialKey, buttonLayout in pairs(radialButtonLayout) do
if radialButtons[gamepadSettingsFrame[radialKey]]["Disabled"] == false then
--Check for exact match
if buttonLayout.Range.Begin < buttonLayout.Range.End then
if angle > buttonLayout.Range.Begin and angle <= buttonLayout.Range.End then
return gamepadSettingsFrame[radialKey]
end
else
if angle > buttonLayout.Range.Begin or angle <= buttonLayout.Range.End then
return gamepadSettingsFrame[radialKey]
end
end
--Check if this is the closest button so far
local distanceBegin = math.min(math.abs((buttonLayout.Range.Begin + 360) - angle), math.abs(buttonLayout.Range.Begin - angle))
local distanceEnd = math.min(math.abs((buttonLayout.Range.End + 360) - angle), math.abs(buttonLayout.Range.End - angle))
local distance = math.min(distanceBegin, distanceEnd)
if distance < closestDistance then
closestDistance = distance
closest = gamepadSettingsFrame[radialKey]
end
end
end
return closest
end
local radialSelect = function(name, state, input)
local inputVector = Vector2.new(0,0)
if input.KeyCode == Enum.KeyCode.Thumbstick1 then
inputVector = Vector2.new(input.Position.x, input.Position.y)
end
local selectedObject = nil
if inputVector.magnitude > 0.8 then
local angle = math.atan2(inputVector.X, inputVector.Y) * 180 / math.pi
if angle < 0 then
angle = angle + 360
end
selectedObject = getSelectedObjectFromAngle(angle)
setSelectedRadialButton(selectedObject)
end
end
local radialSelectAccept = function(name, state, input)
if gamepadSettingsFrame.Visible and state == Enum.UserInputState.Begin then
activateSelectedRadialButton()
end
end
local radialSelectCancel = function(name, state, input)
if gamepadSettingsFrame.Visible and state == Enum.UserInputState.Begin then
toggleCoreGuiRadial()
end
end
function setVisibility()
local children = gamepadSettingsFrame:GetChildren()
for i = 1, #children do
if children[i]:FindFirstChild("RadialIcon") then
children[i].RadialIcon.Visible = isVisible
end
if children[i]:FindFirstChild("RadialLabel") and not isVisible then
children[i].RadialLabel.Visible = isVisible
end
end
end
function setOverrideMouseIconBehavior()
pcall(function()
if InputService:GetLastInputType() == Enum.UserInputType.Gamepad1 then
InputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceHide
else
InputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceShow
end
end)
end
function toggleCoreGuiRadial(goingToSettings)
isVisible = not gamepadSettingsFrame.Visible
setVisibility()
if isVisible then
setOverrideMouseIconBehavior()
pcall(function() lastInputChangedCon = InputService.LastInputTypeChanged:connect(setOverrideMouseIconBehavior) end)
gamepadSettingsFrame.Visible = isVisible
local settingsChildren = gamepadSettingsFrame:GetChildren()
for i = 1, #settingsChildren do
if settingsChildren[i]:IsA("GuiButton") then
utility:TweenProperty(settingsChildren[i], "ImageTransparency", 1, 0, 0.1, utility:GetEaseOutQuad(), nil)
end
end
gamepadSettingsFrame:TweenSizeAndPosition(UDim2.new(0,408,0,408), UDim2.new(0.5,-204,0.5,-204),
Enum.EasingDirection.Out, Enum.EasingStyle.Back, 0.18, true,
function()
setVisibility()
end)
else
if lastInputChangedCon ~= nil then
lastInputChangedCon:disconnect()
lastInputChangedCon = nil
end
pcall(function() InputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.None end)
local settingsChildren = gamepadSettingsFrame:GetChildren()
for i = 1, #settingsChildren do
if settingsChildren[i]:IsA("GuiButton") then
utility:TweenProperty(settingsChildren[i], "ImageTransparency", 0, 1, 0.1, utility:GetEaseOutQuad(), nil)
end
end
gamepadSettingsFrame:TweenSizeAndPosition(UDim2.new(0,102,0,102), UDim2.new(0.5,-51,0.5,-51),
Enum.EasingDirection.Out, Enum.EasingStyle.Sine, 0.1, true,
function()
if not goingToSettings and not isVisible then GuiService:SetMenuIsOpen(false) end
gamepadSettingsFrame.Visible = isVisible
end)
end
if isVisible then
setSelectedRadialButton(nil)
local success = pcall(function() GuiService.CoreGuiNavigationEnabled = false end)
if not success then
GuiService.GuiNavigationEnabled = false
end
GuiService:SetMenuIsOpen(true)
ContextActionService:BindCoreAction(freezeControllerActionName, noOpFunc, false, Enum.UserInputType.Gamepad1)
ContextActionService:BindCoreAction(radialAcceptActionName, radialSelectAccept, false, Enum.KeyCode.ButtonA)
ContextActionService:BindCoreAction(radialCancelActionName, radialSelectCancel, false, Enum.KeyCode.ButtonB)
ContextActionService:BindCoreAction(radialSelectActionName, radialSelect, false, Enum.KeyCode.Thumbstick1)
ContextActionService:BindCoreAction(thumbstick2RadialActionName, noOpFunc, false, Enum.KeyCode.Thumbstick2)
ContextActionService:BindCoreAction(toggleMenuActionName, doGamepadMenuButton, false, Enum.KeyCode.ButtonStart)
else
unbindAllRadialActions()
end
return gamepadSettingsFrame.Visible
end
doGamepadMenuButton = function(name, state, input)
if state ~= Enum.UserInputState.Begin then return end
if game.IsLoaded then
if not toggleCoreGuiRadial() then
unbindAllRadialActions()
end
end
end
if InputService:GetGamepadConnected(Enum.UserInputType.Gamepad1) then
createGamepadMenuGui()
else
InputService.GamepadConnected:connect(function(gamepadEnum)
if gamepadEnum == Enum.UserInputType.Gamepad1 then
createGamepadMenuGui()
end
end)
end
local function setRadialButtonEnabled(coreGuiType, enabled)
local returnValue = getButtonForCoreGuiType(coreGuiType)
if not returnValue then return end
local buttonsToDisable = {}
if type(returnValue) == "table" then
for button, buttonTable in pairs(returnValue) do
if buttonTable["CoreGuiType"] then
if isTenFootInterface and buttonTable["CoreGuiType"] == Enum.CoreGuiType.Chat then
else
buttonsToDisable[#buttonsToDisable + 1] = button
end
end
end
else
if isTenFootInterface and returnValue.Name == "Chat" then
else
buttonsToDisable[1] = returnValue
end
end
for i = 1, #buttonsToDisable do
local button = buttonsToDisable[i]
setButtonEnabled(button, enabled)
end
end
local loadedConnection
local function enableRadialMenu()
ContextActionService:BindCoreAction(toggleMenuActionName, doGamepadMenuButton, false, Enum.KeyCode.ButtonStart)
loadedConnection:disconnect()
end
loadedConnection = game.Players.PlayerAdded:connect(function(plr)
if game.Players.LocalPlayer and plr == game.Players.LocalPlayer then
enableRadialMenu()
end
end)
if game.Players.LocalPlayer then
enableRadialMenu()
end
StarterGui.CoreGuiChangedSignal:connect(setRadialButtonEnabled)
end
-- hook up gamepad stuff
setupGamepadControls()
@@ -0,0 +1,316 @@
--[[
This script controls the gui the player sees in regards to his or her health.
Can be turned with Game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Health,false)
Copyright ROBLOX 2014. Written by Ben Tkacheff.
--]]
---------------------------------------------------------------------
-- Initialize/Variables
while not game do
wait(1/60)
end
while not game:GetService("Players") do
wait(1/60)
end
local useCoreHealthBar = false
local success = pcall(function() useCoreHealthBar = game:GetService("Players"):GetUseCoreScriptHealthBar() end)
if not success or not useCoreHealthBar then
return
end
local currentHumanoid = nil
local HealthGui = nil
local lastHealth = 100
local HealthPercentageForOverlay = 5
local maxBarTweenTime = 0.3
local greenColor = Color3.new(0.2, 1, 0.2)
local redColor = Color3.new(1, 0.2, 0.2)
local yellowColor = Color3.new(1, 1, 0.2)
local guiEnabled = false
local healthChangedConnection = nil
local humanoidDiedConnection = nil
local characterAddedConnection = nil
local greenBarImage = "rbxasset://textures/ui/Health-BKG-Center.png"
local greenBarImageLeft = "rbxasset://textures/ui/Health-BKG-Left-Cap.png"
local greenBarImageRight = "rbxasset://textures/ui/Health-BKG-Right-Cap.png"
local hurtOverlayImage = "http://www.roblox.com/asset/?id=34854607"
game:GetService("ContentProvider"):Preload(greenBarImage)
game:GetService("ContentProvider"):Preload(hurtOverlayImage)
while not game:GetService("Players").LocalPlayer do
wait(1/60)
end
---------------------------------------------------------------------
-- Functions
local capHeight = 15
local capWidth = 7
function CreateGui()
if HealthGui and #HealthGui:GetChildren() > 0 then
HealthGui.Parent = game:GetService("CoreGui").RobloxGui
return
end
local hurtOverlay = Instance.new("ImageLabel")
hurtOverlay.Name = "HurtOverlay"
hurtOverlay.BackgroundTransparency = 1
hurtOverlay.Image = hurtOverlayImage
hurtOverlay.Position = UDim2.new(-10,0,-10,0)
hurtOverlay.Size = UDim2.new(20,0,20,0)
hurtOverlay.Visible = false
hurtOverlay.Parent = HealthGui
local healthFrame = Instance.new("Frame")
healthFrame.Name = "HealthFrame"
healthFrame.BackgroundTransparency = 1
healthFrame.BackgroundColor3 = Color3.new(1,1,1)
healthFrame.BorderColor3 = Color3.new(0,0,0)
healthFrame.BorderSizePixel = 0
healthFrame.Position = UDim2.new(0.5,-85,1,-20)
healthFrame.Size = UDim2.new(0,170,0,capHeight)
healthFrame.Parent = HealthGui
local healthBarBackCenter = Instance.new("ImageLabel")
healthBarBackCenter.Name = "healthBarBackCenter"
healthBarBackCenter.BackgroundTransparency = 1
healthBarBackCenter.Image = greenBarImage
healthBarBackCenter.Size = UDim2.new(1,-capWidth*2,1,0)
healthBarBackCenter.Position = UDim2.new(0,capWidth,0,0)
healthBarBackCenter.Parent = healthFrame
healthBarBackCenter.ImageColor3 = Color3.new(1,1,1)
local healthBarBackLeft = Instance.new("ImageLabel")
healthBarBackLeft.Name = "healthBarBackLeft"
healthBarBackLeft.BackgroundTransparency = 1
healthBarBackLeft.Image = greenBarImageLeft
healthBarBackLeft.Size = UDim2.new(0,capWidth,1,0)
healthBarBackLeft.Position = UDim2.new(0,0,0,0)
healthBarBackLeft.Parent = healthFrame
healthBarBackLeft.ImageColor3 = Color3.new(1,1,1)
local healthBarBackRight = Instance.new("ImageLabel")
healthBarBackRight.Name = "healthBarBackRight"
healthBarBackRight.BackgroundTransparency = 1
healthBarBackRight.Image = greenBarImageRight
healthBarBackRight.Size = UDim2.new(0,capWidth,1,0)
healthBarBackRight.Position = UDim2.new(1,-capWidth,0,0)
healthBarBackRight.Parent = healthFrame
healthBarBackRight.ImageColor3 = Color3.new(1,1,1)
local healthBar = Instance.new("Frame")
healthBar.Name = "HealthBar"
healthBar.BackgroundTransparency = 1
healthBar.BackgroundColor3 = Color3.new(1,1,1)
healthBar.BorderColor3 = Color3.new(0,0,0)
healthBar.BorderSizePixel = 0
healthBar.ClipsDescendants = true
healthBar.Position = UDim2.new(0, 0, 0, 0)
healthBar.Size = UDim2.new(1,0,1,0)
healthBar.Parent = healthFrame
local healthBarCenter = Instance.new("ImageLabel")
healthBarCenter.Name = "healthBarCenter"
healthBarCenter.BackgroundTransparency = 1
healthBarCenter.Image = greenBarImage
healthBarCenter.Size = UDim2.new(1,-capWidth*2,1,0)
healthBarCenter.Position = UDim2.new(0,capWidth,0,0)
healthBarCenter.Parent = healthBar
healthBarCenter.ImageColor3 = greenColor
local healthBarLeft = Instance.new("ImageLabel")
healthBarLeft.Name = "healthBarLeft"
healthBarLeft.BackgroundTransparency = 1
healthBarLeft.Image = greenBarImageLeft
healthBarLeft.Size = UDim2.new(0,capWidth,1,0)
healthBarLeft.Position = UDim2.new(0,0,0,0)
healthBarLeft.Parent = healthBar
healthBarLeft.ImageColor3 = greenColor
local healthBarRight = Instance.new("ImageLabel")
healthBarRight.Name = "healthBarRight"
healthBarRight.BackgroundTransparency = 1
healthBarRight.Image = greenBarImageRight
healthBarRight.Size = UDim2.new(0,capWidth,1,0)
healthBarRight.Position = UDim2.new(1,-capWidth,0,0)
healthBarRight.Parent = healthBar
healthBarRight.ImageColor3 = greenColor
HealthGui.Parent = game:GetService("CoreGui").RobloxGui
end
function UpdateGui(health)
if not HealthGui then return end
local healthFrame = HealthGui:FindFirstChild("HealthFrame")
if not healthFrame then return end
local healthBar = healthFrame:FindFirstChild("HealthBar")
if not healthBar then return end
-- If more than 1/4 health, bar = green. Else, bar = red.
local percentHealth = (health/currentHumanoid.MaxHealth)
if percentHealth ~= percentHealth then
percentHealth = 1
healthBar.healthBarCenter.ImageColor3 = yellowColor
healthBar.healthBarRight.ImageColor3 = yellowColor
healthBar.healthBarLeft.ImageColor3 = yellowColor
elseif percentHealth > 0.25 then
healthBar.healthBarCenter.ImageColor3 = greenColor
healthBar.healthBarRight.ImageColor3 = greenColor
healthBar.healthBarLeft.ImageColor3 = greenColor
else
healthBar.healthBarCenter.ImageColor3 = redColor
healthBar.healthBarRight.ImageColor3 = redColor
healthBar.healthBarLeft.ImageColor3 = redColor
end
local width = (health / currentHumanoid.MaxHealth)
width = math.max(math.min(width,1),0) -- make sure width is between 0 and 1
if width ~= width then width = 1 end
local healthDelta = lastHealth - health
lastHealth = health
local percentOfTotalHealth = math.abs(healthDelta/currentHumanoid.MaxHealth)
percentOfTotalHealth = math.max(math.min(percentOfTotalHealth,1),0) -- make sure percentOfTotalHealth is between 0 and 1
if percentOfTotalHealth ~= percentOfTotalHealth then percentOfTotalHealth = 1 end
local newHealthSize = UDim2.new(width,0,1,0)
healthBar.Size = newHealthSize
local sizeX = healthBar.AbsoluteSize.X
if sizeX < capWidth then
healthBar.healthBarCenter.Visible = false
healthBar.healthBarRight.Visible = false
elseif sizeX < (2*capWidth + 1) then
healthBar.healthBarCenter.Visible = true
healthBar.healthBarCenter.Size = UDim2.new(0,sizeX - capWidth,1,0)
healthBar.healthBarRight.Visible = false
else
healthBar.healthBarCenter.Visible = true
healthBar.healthBarCenter.Size = UDim2.new(1,-capWidth*2,1,0)
healthBar.healthBarRight.Visible = true
end
local thresholdForHurtOverlay = currentHumanoid.MaxHealth * (HealthPercentageForOverlay/100)
if healthDelta >= thresholdForHurtOverlay and guiEnabled then
AnimateHurtOverlay()
end
end
function AnimateHurtOverlay()
if not HealthGui then return end
local overlay = HealthGui:FindFirstChild("HurtOverlay")
if not overlay then return end
local newSize = UDim2.new(20, 0, 20, 0)
local newPos = UDim2.new(-10, 0, -10, 0)
if overlay:IsDescendantOf(game) then
-- stop any tweens on overlay
overlay:TweenSizeAndPosition(newSize,newPos,Enum.EasingDirection.Out,Enum.EasingStyle.Linear,0,true,function()
-- show the gui
overlay.Size = UDim2.new(1,0,1,0)
overlay.Position = UDim2.new(0,0,0,0)
overlay.Visible = true
-- now tween the hide
if overlay:IsDescendantOf(game) then
overlay:TweenSizeAndPosition(newSize,newPos,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,10,false,function()
overlay.Visible = false
end)
else
overlay.Size = newSize
overlay.Position = newPos
end
end)
else
overlay.Size = newSize
overlay.Position = newPos
end
end
function humanoidDied()
UpdateGui(0)
end
function disconnectPlayerConnections()
if characterAddedConnection then characterAddedConnection:disconnect() end
if humanoidDiedConnection then humanoidDiedConnection:disconnect() end
if healthChangedConnection then healthChangedConnection:disconnect() end
end
function newPlayerCharacter()
disconnectPlayerConnections()
startGui()
end
function startGui()
characterAddedConnection = game:GetService("Players").LocalPlayer.CharacterAdded:connect(newPlayerCharacter)
local character = game:GetService("Players").LocalPlayer.Character
if not character then
return
end
currentHumanoid = character:WaitForChild("Humanoid")
if not currentHumanoid then
return
end
if not game:GetService("StarterGui"):GetCoreGuiEnabled(Enum.CoreGuiType.Health) then
return
end
healthChangedConnection = currentHumanoid.HealthChanged:connect(UpdateGui)
humanoidDiedConnection = currentHumanoid.Died:connect(humanoidDied)
UpdateGui(currentHumanoid.Health)
CreateGui()
end
---------------------------------------------------------------------
-- Start Script
HealthGui = Instance.new("Frame")
HealthGui.Name = "HealthGui"
HealthGui.BackgroundTransparency = 1
HealthGui.Size = UDim2.new(1,0,1,0)
game:GetService("StarterGui").CoreGuiChangedSignal:connect(function(coreGuiType,enabled)
if coreGuiType == Enum.CoreGuiType.Health or coreGuiType == Enum.CoreGuiType.All then
if guiEnabled and not enabled then
if HealthGui then
HealthGui.Parent = nil
end
disconnectPlayerConnections()
elseif not guiEnabled and enabled then
startGui()
end
guiEnabled = enabled
end
end)
if game:GetService("StarterGui"):GetCoreGuiEnabled(Enum.CoreGuiType.Health) then
guiEnabled = true
startGui()
end
@@ -0,0 +1,729 @@
local PURPOSE_DATA = {
[Enum.DialogPurpose.Quest] = {"rbxasset://textures/DialogQuest.png", Vector2.new(10, 34)},
[Enum.DialogPurpose.Help] = {"rbxasset://textures/DialogHelp.png", Vector2.new(20, 35)},
[Enum.DialogPurpose.Shop] = {"rbxasset://textures/ui/DialogShop.png", Vector2.new(22, 43)},
}
local TEXT_HEIGHT = 24 -- Pixel height of one row
local FONT_SIZE = Enum.FontSize.Size24
local BAR_THICKNESS = 6
local STYLE_PADDING = 17
local CHOICE_PADDING = 6 * 2 -- (Added to vertical height)
local PROMPT_SIZE = Vector2.new(80, 90)
local FRAME_WIDTH = 350
local WIDTH_BONUS = (STYLE_PADDING * 2) - BAR_THICKNESS
local XPOS_OFFSET = -(STYLE_PADDING - BAR_THICKNESS)
local contextActionService = game:GetService("ContextActionService")
local guiService = game:GetService("GuiService")
local YPOS_OFFSET = -math.floor(STYLE_PADDING / 2)
local usingGamepad = false
function setUsingGamepad(input, processed)
if input.UserInputType == Enum.UserInputType.Gamepad1 or input.UserInputType == Enum.UserInputType.Gamepad2 or
input.UserInputType == Enum.UserInputType.Gamepad3 or input.UserInputType == Enum.UserInputType.Gamepad4 then
usingGamepad = true
else
usingGamepad = false
end
end
game:GetService("UserInputService").InputBegan:connect(setUsingGamepad)
game:GetService("UserInputService").InputChanged:connect(setUsingGamepad)
function waitForProperty(instance, name)
while not instance[name] do
instance.Changed:wait()
end
end
function waitForChild(instance, name)
while not instance:FindFirstChild(name) do
instance.ChildAdded:wait()
end
end
local filteringEnabledFixFlagSuccess, filteringEnabledFixFlagValue = pcall(function() return settings():GetFFlag("FilteringEnabledDialogFix") end)
local filterEnabledFixActive = (filteringEnabledFixFlagSuccess and filteringEnabledFixFlagValue)
local goodbyeChoiceActiveFlagSuccess, goodbyeChoiceActiveFlagValue = pcall(function() return settings():GetFFlag("GoodbyeChoiceActiveProperty") end)
local goodbyeChoiceActiveFlag = (goodbyeChoiceActiveFlagSuccess and goodbyeChoiceActiveFlagValue)
local mainFrame
local choices = {}
local lastChoice
local choiceMap = {}
local currentConversationDialog
local currentConversationPartner
local currentAbortDialogScript
local coroutineMap = {}
local currentDialogTimeoutCoroutine = nil
local tooFarAwayMessage = "You are too far away to chat!"
local tooFarAwaySize = 300
local characterWanderedOffMessage = "Chat ended because you walked away"
local characterWanderedOffSize = 350
local conversationTimedOut = "Chat ended because you didn't reply"
local conversationTimedOutSize = 350
local RobloxReplicatedStorage = game:GetService('RobloxReplicatedStorage')
local setDialogInUseEvent = RobloxReplicatedStorage:WaitForChild("SetDialogInUse")
local player
local screenGui
local chatNotificationGui
local messageDialog
local timeoutScript
local reenableDialogScript
local dialogMap = {}
local dialogConnections = {}
local touchControlGui = nil
local gui = nil
waitForChild(game,"CoreGui")
waitForChild(game:GetService("CoreGui"),"RobloxGui")
game:GetService("CoreGui").RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface")
local isTenFootInterface = require(game:GetService("CoreGui").RobloxGui.Modules.TenFootInterface):IsEnabled()
local utility = require(game:GetService("CoreGui").RobloxGui.Modules.Settings.Utility)
local isSmallTouchScreen = utility:IsSmallTouchScreen()
if isTenFootInterface then
FONT_SIZE = Enum.FontSize.Size36
TEXT_HEIGHT = 36
FRAME_WIDTH = 500
elseif isSmallTouchScreen then
FONT_SIZE = Enum.FontSize.Size14
TEXT_HEIGHT = 14
FRAME_WIDTH = 250
end
if game:GetService("CoreGui").RobloxGui:FindFirstChild("ControlFrame") then
gui = game:GetService("CoreGui").RobloxGui.ControlFrame
else
gui = game:GetService("CoreGui").RobloxGui
end
local touchEnabled = game:GetService("UserInputService").TouchEnabled
function currentTone()
if currentConversationDialog then
return currentConversationDialog.Tone
else
return Enum.DialogTone.Neutral
end
end
function createChatNotificationGui()
chatNotificationGui = Instance.new("BillboardGui")
chatNotificationGui.Name = "ChatNotificationGui"
chatNotificationGui.ExtentsOffset = Vector3.new(0,1,0)
chatNotificationGui.Size = UDim2.new(PROMPT_SIZE.X / 31.5, 0, PROMPT_SIZE.Y / 31.5, 0)
chatNotificationGui.SizeOffset = Vector2.new(0,0)
chatNotificationGui.StudsOffset = Vector3.new(0, 3.7, 0)
chatNotificationGui.Enabled = true
chatNotificationGui.RobloxLocked = true
chatNotificationGui.Active = true
local button = Instance.new("ImageButton")
button.Name = "Background"
button.Active = false
button.BackgroundTransparency = 1
button.Position = UDim2.new(0, 0, 0, 0)
button.Size = UDim2.new(1, 0, 1, 0)
button.Image = ""
button.RobloxLocked = true
button.Parent = chatNotificationGui
local icon = Instance.new("ImageLabel")
icon.Name = "Icon"
icon.Position = UDim2.new(0, 0, 0, 0)
icon.Size = UDim2.new(1, 0, 1, 0)
icon.Image = ""
icon.BackgroundTransparency = 1
icon.RobloxLocked = true
icon.Parent = button
local activationButton = Instance.new("ImageLabel")
activationButton.Name = "ActivationButton"
activationButton.Position = UDim2.new(-0.3, 0, -0.4, 0)
activationButton.Size = UDim2.new(.8, 0, .8*(PROMPT_SIZE.X/PROMPT_SIZE.Y), 0)
activationButton.Image = "rbxasset://textures/ui/Settings/Help/XButtonDark.png"
activationButton.BackgroundTransparency = 1
activationButton.Visible = false
activationButton.RobloxLocked = true
activationButton.Parent = button
end
function getChatColor(tone)
if tone == Enum.DialogTone.Neutral then
return Enum.ChatColor.Blue
elseif tone == Enum.DialogTone.Friendly then
return Enum.ChatColor.Green
elseif tone == Enum.DialogTone.Enemy then
return Enum.ChatColor.Red
end
end
function styleChoices()
for _, obj in pairs(choices) do
obj.BackgroundTransparency = 1
end
lastChoice.BackgroundTransparency = 1
end
function styleMainFrame(tone)
if tone == Enum.DialogTone.Neutral then
mainFrame.Style = Enum.FrameStyle.ChatBlue
elseif tone == Enum.DialogTone.Friendly then
mainFrame.Style = Enum.FrameStyle.ChatGreen
elseif tone == Enum.DialogTone.Enemy then
mainFrame.Style = Enum.FrameStyle.ChatRed
end
styleChoices()
end
function setChatNotificationTone(gui, purpose, tone)
if tone == Enum.DialogTone.Neutral then
gui.Background.Image = "rbxasset://textures/ui/chatBubble_blue_notify_bkg.png"
elseif tone == Enum.DialogTone.Friendly then
gui.Background.Image = "rbxasset://textures/ui/chatBubble_green_notify_bkg.png"
elseif tone == Enum.DialogTone.Enemy then
gui.Background.Image = "rbxasset://textures/ui/chatBubble_red_notify_bkg.png"
end
local newIcon, size = unpack(PURPOSE_DATA[purpose])
local relativeSize = size / PROMPT_SIZE
gui.Background.Icon.Size = UDim2.new(relativeSize.X, 0, relativeSize.Y, 0)
gui.Background.Icon.Position = UDim2.new(0.5 - (relativeSize.X / 2), 0, 0.4 - (relativeSize.Y / 2), 0)
gui.Background.Icon.Image = newIcon
end
function createMessageDialog()
messageDialog = Instance.new("Frame");
messageDialog.Name = "DialogScriptMessage"
messageDialog.Style = Enum.FrameStyle.Custom
messageDialog.BackgroundTransparency = 0.5
messageDialog.BackgroundColor3 = Color3.new(31/255, 31/255, 31/255)
messageDialog.Visible = false
local text = Instance.new("TextLabel")
text.Name = "Text"
text.Position = UDim2.new(0,0,0,-1)
text.Size = UDim2.new(1,0,1,0)
text.FontSize = Enum.FontSize.Size14
text.BackgroundTransparency = 1
text.TextColor3 = Color3.new(1,1,1)
text.RobloxLocked = true
text.Parent = messageDialog
end
function showMessage(msg, size)
messageDialog.Text.Text = msg
messageDialog.Size = UDim2.new(0,size,0,40)
messageDialog.Position = UDim2.new(0.5, -size/2, 0.5, -40)
messageDialog.Visible = true
wait(2)
messageDialog.Visible = false
end
function variableDelay(str)
local length = math.min(string.len(str), 100)
wait(0.75 + ((length/75) * 1.5))
end
function resetColor(frame)
frame.BackgroundTransparency = 1
end
function wanderDialog()
mainFrame.Visible = false
endDialog()
showMessage(characterWanderedOffMessage, characterWanderedOffSize)
end
function timeoutDialog()
mainFrame.Visible = false
endDialog()
showMessage(conversationTimedOut, conversationTimedOutSize)
end
function normalEndDialog()
endDialog()
end
function endDialog()
if filterEnabledFixActive then
if currentDialogTimeoutCoroutine then
coroutineMap[currentDialogTimeoutCoroutine] = false
currentDialogTimeoutCoroutine = nil
end
else
if currentAbortDialogScript then
currentAbortDialogScript:Destroy()
currentAbortDialogScript = nil
end
end
local dialog = currentConversationDialog
currentConversationDialog = nil
if dialog and dialog.InUse then
if filterEnabledFixActive then
spawn(function()
wait(5)
setDialogInUseEvent:FireServer(dialog, false)
end)
else
local reenableScript = reenableDialogScript:Clone()
reenableScript.Archivable = false
reenableScript.Disabled = false
reenableScript.Parent = dialog
end
end
for dialog, gui in pairs(dialogMap) do
if dialog and gui then
gui.Enabled = not dialog.InUse
end
end
contextActionService:UnbindCoreAction("Nothing")
currentConversationPartner = nil
if touchControlGui then
touchControlGui.Visible = true
end
end
function sanitizeMessage(msg)
if string.len(msg) == 0 then
return "..."
else
return msg
end
end
function selectChoice(choice)
renewKillswitch(currentConversationDialog)
--First hide the Gui
mainFrame.Visible = false
if choice == lastChoice then
game:GetService("Chat"):Chat(game:GetService("Players").LocalPlayer.Character, lastChoice.UserPrompt.Text, getChatColor(currentTone()))
normalEndDialog()
else
local dialogChoice = choiceMap[choice]
game:GetService("Chat"):Chat(game:GetService("Players").LocalPlayer.Character, sanitizeMessage(dialogChoice.UserDialog), getChatColor(currentTone()))
wait(1)
currentConversationDialog:SignalDialogChoiceSelected(player, dialogChoice)
game:GetService("Chat"):Chat(currentConversationPartner, sanitizeMessage(dialogChoice.ResponseDialog), getChatColor(currentTone()))
variableDelay(dialogChoice.ResponseDialog)
presentDialogChoices(currentConversationPartner, dialogChoice:GetChildren(), dialogChoice)
end
end
function newChoice()
local dummyFrame = Instance.new("Frame")
dummyFrame.Visible = false
local frame = Instance.new("TextButton")
frame.BackgroundColor3 = Color3.new(227/255, 227/255, 227/255)
frame.BackgroundTransparency = 1
frame.AutoButtonColor = false
frame.BorderSizePixel = 0
frame.Text = ""
frame.MouseEnter:connect(function() frame.BackgroundTransparency = 0 end)
frame.MouseLeave:connect(function() frame.BackgroundTransparency = 1 end)
frame.SelectionImageObject = dummyFrame
frame.MouseButton1Click:connect(function() selectChoice(frame) end)
frame.RobloxLocked = true
local prompt = Instance.new("TextLabel")
prompt.Name = "UserPrompt"
prompt.BackgroundTransparency = 1
prompt.Font = Enum.Font.SourceSans
prompt.FontSize = FONT_SIZE
prompt.Position = UDim2.new(0, 40, 0, 0)
prompt.Size = UDim2.new(1, -32-40, 1, 0)
prompt.TextXAlignment = Enum.TextXAlignment.Left
prompt.TextYAlignment = Enum.TextYAlignment.Center
prompt.TextWrap = true
prompt.RobloxLocked = true
prompt.Parent = frame
local selectionButton = Instance.new("ImageLabel")
selectionButton.Name = "RBXchatDialogSelectionButton"
selectionButton.Position = UDim2.new(0, 0, 0.5, -33/2)
selectionButton.Size = UDim2.new(0, 33, 0, 33)
selectionButton.Image = "rbxasset://textures/ui/Settings/Help/AButtonLightSmall.png"
selectionButton.BackgroundTransparency = 1
selectionButton.Visible = false
selectionButton.RobloxLocked = true
selectionButton.Parent = frame
return frame
end
function initialize(parent)
choices[1] = newChoice()
choices[2] = newChoice()
choices[3] = newChoice()
choices[4] = newChoice()
lastChoice = newChoice()
lastChoice.UserPrompt.Text = "Goodbye!"
lastChoice.Size = UDim2.new(1, WIDTH_BONUS, 0, TEXT_HEIGHT + CHOICE_PADDING)
mainFrame = Instance.new("Frame")
mainFrame.Name = "UserDialogArea"
mainFrame.Size = UDim2.new(0, FRAME_WIDTH, 0, 200)
mainFrame.Style = Enum.FrameStyle.ChatBlue
mainFrame.Visible = false
for n, obj in pairs(choices) do
obj.RobloxLocked = true
obj.Parent = mainFrame
end
lastChoice.RobloxLocked = true
lastChoice.Parent = mainFrame
mainFrame.RobloxLocked = true
mainFrame.Parent = parent
end
function presentDialogChoices(talkingPart, dialogChoices, parentDialog)
if not currentConversationDialog then
return
end
currentConversationPartner = talkingPart
sortedDialogChoices = {}
for n, obj in pairs(dialogChoices) do
if obj:IsA("DialogChoice") then
table.insert(sortedDialogChoices, obj)
end
end
table.sort(sortedDialogChoices, function(a,b) return a.Name < b.Name end)
if #sortedDialogChoices == 0 then
normalEndDialog()
return
end
local pos = 1
local yPosition = 0
choiceMap = {}
for n, obj in pairs(choices) do
obj.Visible = false
end
for n, obj in pairs(sortedDialogChoices) do
if pos <= #choices then
--3 lines is the maximum, set it to that temporarily
choices[pos].Size = UDim2.new(1, WIDTH_BONUS, 0, TEXT_HEIGHT * 3)
choices[pos].UserPrompt.Text = obj.UserDialog
local height = (math.ceil(choices[pos].UserPrompt.TextBounds.Y / TEXT_HEIGHT) * TEXT_HEIGHT) + CHOICE_PADDING
choices[pos].Position = UDim2.new(0, XPOS_OFFSET, 0, YPOS_OFFSET + yPosition)
choices[pos].Size = UDim2.new(1, WIDTH_BONUS, 0, height)
choices[pos].Visible = true
choiceMap[choices[pos]] = obj
yPosition = yPosition + height + 1 -- The +1 makes highlights not overlap
pos = pos + 1
end
end
lastChoice.Size = UDim2.new(1, WIDTH_BONUS, 0, TEXT_HEIGHT * 3)
lastChoice.UserPrompt.Text = parentDialog.GoodbyeDialog == "" and "Goodbye!" or parentDialog.GoodbyeDialog
local height = (math.ceil(lastChoice.UserPrompt.TextBounds.Y / TEXT_HEIGHT) * TEXT_HEIGHT) + CHOICE_PADDING
lastChoice.Size = UDim2.new(1, WIDTH_BONUS, 0, height)
lastChoice.Position = UDim2.new(0, XPOS_OFFSET, 0, YPOS_OFFSET + yPosition)
lastChoice.Visible = true
if goodbyeChoiceActiveFlag and not parentDialog.GoodbyeChoiceActive then
lastChoice.Visible = false
mainFrame.Size = UDim2.new(0, FRAME_WIDTH, 0, yPosition + (STYLE_PADDING * 2) + (YPOS_OFFSET * 2))
else
mainFrame.Size = UDim2.new(0, FRAME_WIDTH, 0, yPosition + lastChoice.AbsoluteSize.Y + (STYLE_PADDING * 2) + (YPOS_OFFSET * 2))
end
mainFrame.Position = UDim2.new(0,20,1.0, -mainFrame.Size.Y.Offset-20)
if isSmallTouchScreen then
local touchScreenGui = game.Players.LocalPlayer.PlayerGui:FindFirstChild("TouchGui")
if touchScreenGui then
touchControlGui = touchScreenGui:FindFirstChild("TouchControlFrame")
if touchControlGui then
touchControlGui.Visible = false
end
end
mainFrame.Position = UDim2.new(0,10,1.0, -mainFrame.Size.Y.Offset)
end
styleMainFrame(currentTone())
mainFrame.Visible = true
if usingGamepad then
Game:GetService("GuiService").SelectedCoreObject = choices[1]
end
end
function doDialog(dialog)
if dialog.InUse then
return
else
dialog.InUse = true
if filterEnabledFixActive then
setDialogInUseEvent:FireServer(dialog, true)
end
end
currentConversationDialog = dialog
game:GetService("Chat"):Chat(dialog.Parent, dialog.InitialPrompt, getChatColor(dialog.Tone))
variableDelay(dialog.InitialPrompt)
presentDialogChoices(dialog.Parent, dialog:GetChildren(), dialog)
end
function renewKillswitch(dialog)
if filterEnabledFixActive then
if currentDialogTimeoutCoroutine then
coroutineMap[currentDialogTimeoutCoroutine] = false
currentDialogTimeoutCoroutine = nil
end
else
if currentAbortDialogScript then
currentAbortDialogScript:Destroy()
currentAbortDialogScript = nil
end
end
if filterEnabledFixActive then
currentDialogTimeoutCoroutine = coroutine.create(function(thisCoroutine)
wait(15)
if thisCoroutine ~= nil then
if coroutineMap[thisCoroutine] == nil then
setDialogInUseEvent:FireServer(dialog, false)
end
coroutineMap[thisCoroutine] = nil
end
end)
coroutine.resume(currentDialogTimeoutCoroutine, currentDialogTimeoutCoroutine)
else
currentAbortDialogScript = timeoutScript:Clone()
currentAbortDialogScript.Archivable = false
currentAbortDialogScript.Disabled = false
currentAbortDialogScript.Parent = dialog
end
end
function checkForLeaveArea()
while currentConversationDialog do
if currentConversationDialog.Parent and (player:DistanceFromCharacter(currentConversationDialog.Parent.Position) >= currentConversationDialog.ConversationDistance) then
wanderDialog()
end
wait(1)
end
end
function startDialog(dialog)
if dialog.Parent and dialog.Parent:IsA("BasePart") then
if player:DistanceFromCharacter(dialog.Parent.Position) >= dialog.ConversationDistance then
showMessage(tooFarAwayMessage, tooFarAwaySize)
return
end
for dialog, gui in pairs(dialogMap) do
if dialog and gui then
gui.Enabled = false
end
end
contextActionService:BindCoreAction("Nothing", function() end, false, Enum.UserInputType.Gamepad1, Enum.UserInputType.Gamepad2, Enum.UserInputType.Gamepad3, Enum.UserInputType.Gamepad4)
renewKillswitch(dialog)
delay(1, checkForLeaveArea)
doDialog(dialog)
end
end
function removeDialog(dialog)
if dialogMap[dialog] then
dialogMap[dialog]:Destroy()
dialogMap[dialog] = nil
end
if dialogConnections[dialog] then
dialogConnections[dialog]:disconnect()
dialogConnections[dialog] = nil
end
end
function addDialog(dialog)
if dialog.Parent then
if dialog.Parent:IsA("BasePart") then
local chatGui = chatNotificationGui:clone()
chatGui.Enabled = not dialog.InUse
chatGui.Adornee = dialog.Parent
chatGui.RobloxLocked = true
chatGui.Parent = game:GetService("CoreGui")
chatGui.Background.MouseButton1Click:connect(function() startDialog(dialog) end)
setChatNotificationTone(chatGui, dialog.Purpose, dialog.Tone)
dialogMap[dialog] = chatGui
dialogConnections[dialog] = dialog.Changed:connect(function(prop)
if prop == "Parent" and dialog.Parent then
--This handles the reparenting case, seperate from removal case
removeDialog(dialog)
addDialog(dialog)
elseif prop == "InUse" then
chatGui.Enabled = not currentConversationDialog and not dialog.InUse
if dialog == currentConversationDialog then
timeoutDialog()
end
elseif prop == "Tone" or prop == "Purpose" then
setChatNotificationTone(chatGui, dialog.Purpose, dialog.Tone)
end
end)
else -- still need to listen to parent changes even if current parent is not a BasePart
dialogConnections[dialog] = dialog.Changed:connect(function(prop)
if prop == "Parent" and dialog.Parent then
--This handles the reparenting case, seperate from removal case
removeDialog(dialog)
addDialog(dialog)
end
end)
end
end
end
function fetchScripts()
local model = game:GetService("InsertService"):LoadAsset(39226062)
if type(model) == "string" then -- load failed, lets try again
wait(0.1)
model = game:GetService("InsertService"):LoadAsset(39226062)
end
if type(model) == "string" then -- not going to work, lets bail
return
end
waitForChild(model,"TimeoutScript")
timeoutScript = model.TimeoutScript
waitForChild(model,"ReenableDialogScript")
reenableDialogScript = model.ReenableDialogScript
end
function onLoad()
waitForProperty(game:GetService("Players"), "LocalPlayer")
player = game:GetService("Players").LocalPlayer
waitForProperty(player, "Character")
--print("Creating Guis")
createChatNotificationGui()
--print("Creating MessageDialog")
createMessageDialog()
messageDialog.RobloxLocked = true
messageDialog.Parent = gui
if not filterEnabledFixActive then
fetchScripts()
end
--print("Waiting for BottomLeftControl")
waitForChild(gui, "BottomLeftControl")
--print("Initializing Frame")
local frame = Instance.new("Frame")
frame.Name = "DialogFrame"
frame.Position = UDim2.new(0,0,0,0)
frame.Size = UDim2.new(0,0,0,0)
frame.BackgroundTransparency = 1
frame.RobloxLocked = true
game:GetService("GuiService"):AddSelectionParent("RBXDialogGroup", frame)
if (touchEnabled and not isSmallTouchScreen) then
frame.Position = UDim2.new(0,20,0.5,0)
frame.Size = UDim2.new(0.25,0,0.1,0)
frame.Parent = gui
elseif isSmallTouchScreen then
frame.Position = UDim2.new(0,0,.9,-10)
frame.Size = UDim2.new(0.25,0,0.1,0)
frame.Parent = gui
else
frame.Parent = gui.BottomLeftControl
end
initialize(frame)
--print("Adding Dialogs")
game:GetService("CollectionService").ItemAdded:connect(function(obj) if obj:IsA("Dialog") then addDialog(obj) end end)
game:GetService("CollectionService").ItemRemoved:connect(function(obj) if obj:IsA("Dialog") then removeDialog(obj) end end)
for i, obj in pairs(game:GetService("CollectionService"):GetCollection("Dialog")) do
if obj:IsA("Dialog") then
addDialog(obj)
end
end
end
local lastClosestDialog = nil
local getClosestDialogToPosition = guiService.GetClosestDialogToPosition
game:GetService("RunService").Heartbeat:connect(function()
local closestDistance = math.huge
local closestDialog = nil
if usingGamepad == true then
if game.Players.LocalPlayer and game.Players.LocalPlayer.Character and game.Players.LocalPlayer.Character:FindFirstChild("HumanoidRootPart") then
local characterPosition = game.Players.LocalPlayer.Character:FindFirstChild("HumanoidRootPart").Position
closestDialog = getClosestDialogToPosition(guiService, characterPosition)
end
end
if closestDialog ~= lastClosestDialog then
if dialogMap[lastClosestDialog] then
dialogMap[lastClosestDialog].Background.ActivationButton.Visible = false
end
lastClosestDialog = closestDialog
contextActionService:UnbindCoreAction("StartDialogAction")
if closestDialog ~= nil then
contextActionService:BindCoreAction("StartDialogAction",
function(actionName, userInputState, inputObject)
if userInputState == Enum.UserInputState.Begin then
if closestDialog and closestDialog.Parent then
startDialog(closestDialog)
end
end
end,
false,
Enum.KeyCode.ButtonX)
if dialogMap[closestDialog] then
dialogMap[closestDialog].Background.ActivationButton.Visible = true
end
end
end
end)
local lastSelectedChoice = nil
guiService.Changed:connect(function(property)
if property == "SelectedCoreObject" then
if lastSelectedChoice and lastSelectedChoice:FindFirstChild("RBXchatDialogSelectionButton") then
lastSelectedChoice:FindFirstChild("RBXchatDialogSelectionButton").Visible = false
lastSelectedChoice.BackgroundTransparency = 1
end
lastSelectedChoice = guiService.SelectedCoreObject
if lastSelectedChoice and lastSelectedChoice:FindFirstChild("RBXchatDialogSelectionButton") then
lastSelectedChoice:FindFirstChild("RBXchatDialogSelectionButton").Visible = true
lastSelectedChoice.BackgroundTransparency = 0
end
end
end)
onLoad()
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,160 @@
--[[
// Filename: VehicleHud.lua
// Version 1.0
// Written by: jmargh
// Description: Implementation of the VehicleSeat HUD
// TODO:
Once this is live and stable, move to PlayerScripts as module
]]
local RunService = game:GetService('RunService')
local Players = game:GetService('Players')
while not Players.LocalPlayer do
wait()
end
local LocalPlayer = Players.LocalPlayer
local RobloxGui = script.Parent
local CurrentVehicleSeat = nil
local VehicleSeatRenderCn = nil
local VehicleSeatHUDChangedCn = nil
local RobloxGui = game:GetService("CoreGui"):WaitForChild("RobloxGui")
RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface")
local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled()
--[[ Images ]]--
local VEHICLE_HUD_BG = 'rbxasset://textures/ui/Vehicle/SpeedBarBKG.png'
local SPEED_BAR_EMPTY = 'rbxasset://textures/ui/Vehicle/SpeedBarEmpty.png'
local SPEED_BAR = 'rbxasset://textures/ui/Vehicle/SpeedBar.png'
--[[ Constants ]]--
local BOTTOM_OFFSET = (isTenFootInterface and 100 or 70)
--[[ Gui Creation ]]--
local function createImageLabel(name, size, position, image, parent)
local imageLabel = Instance.new('ImageLabel')
imageLabel.Name = name
imageLabel.Size = size
imageLabel.Position = position
imageLabel.BackgroundTransparency = 1
imageLabel.Image = image
imageLabel.Parent = parent
return imageLabel
end
local function createTextLabel(name, alignment, text, parent)
local textLabel = Instance.new('TextLabel')
textLabel.Name = name
textLabel.Size = UDim2.new(1, -4, 0, (isTenFootInterface and 50 or 20))
textLabel.Position = UDim2.new(0, 2, 0, (isTenFootInterface and -50 or -20))
textLabel.BackgroundTransparency = 1
textLabel.TextXAlignment = alignment
textLabel.Font = Enum.Font.SourceSans
textLabel.FontSize = (isTenFootInterface and Enum.FontSize.Size48 or Enum.FontSize.Size18)
textLabel.TextColor3 = Color3.new(1, 1, 1)
textLabel.TextStrokeTransparency = 0.5
textLabel.TextStrokeColor3 = Color3.new(49/255, 49/255, 49/255)
textLabel.Text = text
textLabel.Parent = parent
return textLabel
end
local VehicleHudFrame = Instance.new('Frame')
VehicleHudFrame.Name = "VehicleHudFrame"
VehicleHudFrame.Size = UDim2.new(0, (isTenFootInterface and 316 or 158), 0, (isTenFootInterface and 50 or 14))
VehicleHudFrame.Position = UDim2.new(0.5, -(VehicleHudFrame.Size.X.Offset/2), 1, -BOTTOM_OFFSET - VehicleHudFrame.Size.Y.Offset)
VehicleHudFrame.BackgroundTransparency = 1
VehicleHudFrame.Visible = false
VehicleHudFrame.Parent = RobloxGui
local speedBarClippingFrame = Instance.new("Frame")
speedBarClippingFrame.Name = "SpeedBarClippingFrame"
speedBarClippingFrame.Size = UDim2.new(0, 0, 0, (isTenFootInterface and 24 or 4))
speedBarClippingFrame.Position = UDim2.new(0.5, (isTenFootInterface and -142 or -71), 0.5, (isTenFootInterface and -13 or -2))
speedBarClippingFrame.BackgroundTransparency = 1
speedBarClippingFrame.ClipsDescendants = true
speedBarClippingFrame.Parent = VehicleHudFrame
local HudBG = createImageLabel("HudBG", UDim2.new(1, 0, 1, 0), UDim2.new(0, 0, 0, 1), VEHICLE_HUD_BG, VehicleHudFrame)
local SpeedBG = createImageLabel("SpeedBG", UDim2.new(0, (isTenFootInterface and 284 or 142), 0, (isTenFootInterface and 24 or 4)), UDim2.new(0.5, (isTenFootInterface and -142 or -71), 0.5, (isTenFootInterface and -13 or -2)), SPEED_BAR_EMPTY, VehicleHudFrame)
local SpeedBarImage = createImageLabel("SpeedBarImage", UDim2.new(0, (isTenFootInterface and 284 or 142), 1, 0), UDim2.new(0, 0, 0, 0), SPEED_BAR, speedBarClippingFrame)
SpeedBarImage.ZIndex = 2
local SpeedLabel = createTextLabel("SpeedLabel", Enum.TextXAlignment.Left, "Speed", VehicleHudFrame)
local SpeedText = createTextLabel("SpeedText", Enum.TextXAlignment.Right, "0", VehicleHudFrame)
--[[ Local Functions ]]--
local function getHumanoid()
local character = LocalPlayer and LocalPlayer.Character
if character then
for _,child in pairs(character:GetChildren()) do
if child:IsA('Humanoid') then
return child
end
end
end
end
local function onRenderStepped()
if CurrentVehicleSeat then
local speed = CurrentVehicleSeat.Velocity.magnitude
SpeedText.Text = tostring(math.min(math.floor(speed), 9999))
local drawSize = math.floor((speed / CurrentVehicleSeat.MaxSpeed) * SpeedBG.Size.X.Offset)
drawSize = math.min(drawSize, SpeedBG.Size.X.Offset)
speedBarClippingFrame.Size = UDim2.new(0, drawSize, 0, (isTenFootInterface and 24 or 4))
end
end
local function onVehicleSeatChanged(property)
if property == "HeadsUpDisplay" then
VehicleHudFrame.Visible = not VehicleHudFrame.Visible
end
end
local function onSeated(active, currentSeatPart)
if active then
-- TODO: Clean up when new API is live for a while
if currentSeatPart and currentSeatPart:IsA('VehicleSeat') then
CurrentVehicleSeat = currentSeatPart
else
local camSubject = workspace.CurrentCamera.CameraSubject
if camSubject and camSubject:IsA('VehicleSeat') then
CurrentVehicleSeat = camSubject
end
end
if CurrentVehicleSeat then
VehicleHudFrame.Visible = CurrentVehicleSeat.HeadsUpDisplay
VehicleSeatRenderCn = RunService.RenderStepped:connect(onRenderStepped)
VehicleSeatHUDChangedCn = CurrentVehicleSeat.Changed:connect(onVehicleSeatChanged)
end
else
if CurrentVehicleSeat then
VehicleHudFrame.Visible = false
CurrentVehicleSeat = nil
if VehicleSeatRenderCn then
VehicleSeatRenderCn:disconnect()
VehicleSeatRenderCn = nil
end
if VehicleSeatHUDChangedCn then
VehicleSeatHUDChangedCn:disconnect()
VehicleSeatHUDChangedCn = nil
end
end
end
end
local function connectSeated()
local humanoid = getHumanoid()
while not humanoid do
wait()
humanoid = getHumanoid()
end
humanoid.Seated:connect(onSeated)
end
connectSeated()
LocalPlayer.CharacterAdded:connect(function(character)
connectSeated()
end)