add
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user