2425 lines
71 KiB
Plaintext
2425 lines
71 KiB
Plaintext
local RbxGui
|
|
|
|
local localTesting = true
|
|
|
|
local screen = script.Parent
|
|
local screenResizeCon = nil
|
|
|
|
local friendWord = "Friend"
|
|
local friendWordLowercase = "friend"
|
|
|
|
local elementNames = {}
|
|
local elementNameToElement = {}
|
|
|
|
local privilegeOwner = 255
|
|
local privilegeAdmin = 240
|
|
local privilegeMember = 128
|
|
local privilegeVisitor = 10
|
|
local privilegeBanned = 0
|
|
|
|
local inContextMenu = false
|
|
local contextMenu3d = true
|
|
|
|
local bigEasingStyle = Enum.EasingStyle.Back
|
|
local smallEasingStyle = Enum.EasingStyle.Quart
|
|
|
|
local personalServerContextAdded = false
|
|
local personalServerPlace = false
|
|
local success = pcall(function() personalServerPlace = game.IsPersonalServer end)
|
|
if not success then
|
|
personalServerPlace = false
|
|
end
|
|
|
|
local friendRequestBlacklist = {}
|
|
local otherPlayerBlacklist = {}
|
|
|
|
local currentSortName = ""
|
|
|
|
local function waitForChild(instance, name)
|
|
while not instance:FindFirstChild(name) do
|
|
instance.ChildAdded:wait()
|
|
end
|
|
end
|
|
|
|
local function waitForProperty(instance, prop)
|
|
while not instance[prop] do
|
|
instance.Changed:wait()
|
|
end
|
|
end
|
|
|
|
local function Color3I(r,g,b)
|
|
return Color3.new(r/255,g/255,b/255)
|
|
end
|
|
|
|
function robloxLock(instance)
|
|
instance.RobloxLocked = true
|
|
children = instance:GetChildren()
|
|
if children then
|
|
for i, child in ipairs(children) do
|
|
robloxLock(child)
|
|
end
|
|
end
|
|
end
|
|
|
|
function ArrayRemove(t, obj)
|
|
for i, obj2 in ipairs(t) do
|
|
if obj == obj2 then
|
|
table.remove(t, i)
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function getPlayers()
|
|
local result = {}
|
|
local players = game:GetService("Players"):GetChildren()
|
|
if players then
|
|
for i, player in ipairs(players) do
|
|
if player:IsA("Player") then
|
|
table.insert(result, player)
|
|
end
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
local brickColorTable = {}
|
|
for i = 0, 63 do
|
|
brickColorTable[BrickColor.palette(i).Name] = BrickColor.palette(i).Color
|
|
end
|
|
|
|
local function remapColor(i, j)
|
|
brickColorTable[BrickColor.palette(i).Name] = BrickColor.palette(j).Color
|
|
end
|
|
|
|
remapColor(13, 12)
|
|
remapColor(14, 12)
|
|
remapColor(15, 12)
|
|
remapColor(61, 29)
|
|
remapColor(63, 62)
|
|
remapColor(56, 50)
|
|
remapColor(45, 53)
|
|
remapColor(51, 20)
|
|
remapColor(4, 20)
|
|
remapColor(59, 35)
|
|
remapColor(60, 29)
|
|
|
|
local function getColor(brickColor)
|
|
if brickColorTable[brickColor.Name] then
|
|
return brickColorTable[brickColor.Name]
|
|
else
|
|
return brickColor.Color;
|
|
end
|
|
end
|
|
|
|
|
|
|
|
local function getTeams()
|
|
local result = {}
|
|
local teams = game:GetService("Teams"):GetChildren()
|
|
for i, team in ipairs(teams) do
|
|
if team:IsA("Team") then
|
|
table.insert(result, team)
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
local supportFriends = true
|
|
local currentBoardType = "PlayerList"
|
|
local currentStatCount = 0
|
|
|
|
local createBoardsFunction = nil
|
|
|
|
|
|
local playerTable = {}
|
|
local teamTable = {}
|
|
local teamColorTable = {}
|
|
|
|
local removePlayerFunction = nil
|
|
local recreatePlayerFunction = nil
|
|
local addPlayerFunction = function(player)
|
|
if recreatePlayerFunction then
|
|
recreatePlayerFunction(player)
|
|
end
|
|
end
|
|
local sortPlayerListsFunction = nil
|
|
|
|
local minimizedState = nil
|
|
local bigWindowImposter = nil
|
|
local smallWindowPosition = UDim2.new(0, -20, 0,5)
|
|
local smallWindowSize = UDim2.new(1,0,1,0)
|
|
local bigWindowSize = UDim2.new(0.6,0,0.6,0)
|
|
local bigWindowPosition = UDim2.new(.2, 0, .2,0)
|
|
|
|
local smallWindowHeaderYSize = 32
|
|
|
|
local debounceTeamsChanged = false
|
|
|
|
local currentWindowState = "Small"
|
|
local previousWindowState = nil
|
|
local transitionWindowsFunction = nil
|
|
|
|
local container = nil
|
|
local topRightTrayContainer = nil
|
|
|
|
local playerContextMenu = nil
|
|
local contextMenuElements = {}
|
|
local updateContextMenuItems = nil
|
|
|
|
local function addContextMenuLabel(getText1, getText2, isVisible)
|
|
local t = {}
|
|
t.Type = "Label"
|
|
t.GetText1 = getText1
|
|
t.GetText2 = getText2
|
|
t.IsVisible = isVisible
|
|
table.insert(contextMenuElements, t)
|
|
end
|
|
local function addContextMenuButton(text, isVisible, isActive, doIt)
|
|
local t = {}
|
|
t.Text = text
|
|
t.Type = "Button"
|
|
t.IsVisible = isVisible
|
|
t.IsActive = isActive
|
|
t.DoIt = doIt
|
|
table.insert(contextMenuElements, t)
|
|
end
|
|
|
|
local function getFriendStatus(player)
|
|
if player == game.Players.LocalPlayer then
|
|
return Enum.FriendStatus.NotFriend
|
|
else
|
|
local success, result = pcall(function() return game.Players.LocalPlayer:GetFriendStatus(player) end)
|
|
if success then
|
|
return result
|
|
else
|
|
return Enum.FriendStatus.NotFriend
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local function getPrivilegeType(player)
|
|
local rank = player.PersonalServerRank
|
|
if rank >= privilegeOwner then
|
|
return privilegeOwner
|
|
elseif rank < privilegeOwner and rank >= privilegeAdmin then
|
|
return privilegeAdmin
|
|
elseif rank < privilegeAdmin and rank >= privilegeMember then
|
|
return privilegeMember
|
|
elseif rank < privilegeMember and rank >= privilegeVisitor then
|
|
return privilegeVisitor
|
|
else
|
|
return privilegeBanned
|
|
end
|
|
end
|
|
|
|
--Populate the ContextMenus
|
|
addContextMenuLabel(
|
|
--GetText1
|
|
function(player)
|
|
return "Loading..."
|
|
end,
|
|
--GetText2
|
|
nil,
|
|
--IsVisible
|
|
function(player)
|
|
return getFriendStatus(player) == Enum.FriendStatus.Unknown
|
|
end)
|
|
|
|
addContextMenuButton("Send " .. friendWord .. " Request",
|
|
--IsVisible
|
|
function(player)
|
|
return (not otherPlayerBlacklist[player]) and (getFriendStatus(player) == Enum.FriendStatus.NotFriend)
|
|
end,
|
|
--IsActive
|
|
function(player)
|
|
return true
|
|
end,
|
|
--DoIt?
|
|
function(player)
|
|
otherPlayerBlacklist[player] = true
|
|
return game.Players.LocalPlayer:RequestFriendship(player)
|
|
end
|
|
)
|
|
addContextMenuButton("Un" .. friendWordLowercase,
|
|
--IsVisible
|
|
function(player)
|
|
return getFriendStatus(player) == Enum.FriendStatus.Friend
|
|
end,
|
|
--IsActive
|
|
function(player)
|
|
return true
|
|
end,
|
|
--DoIt
|
|
function(player)
|
|
return game.Players.LocalPlayer:RevokeFriendship(player)
|
|
end
|
|
)
|
|
addContextMenuButton("Accept " .. friendWord .. " Request",
|
|
--IsVisible
|
|
function(player)
|
|
return (not friendRequestBlacklist[player]) and (getFriendStatus(player) == Enum.FriendStatus.FriendRequestReceived)
|
|
end,
|
|
--IsActive
|
|
function(player)
|
|
return true
|
|
end,
|
|
--DoIt
|
|
function(player)
|
|
return game.Players.LocalPlayer:RequestFriendship(player)
|
|
end
|
|
)
|
|
|
|
addContextMenuButton("Deny " .. friendWord .. " Request",
|
|
--IsVisible
|
|
function(player)
|
|
return getFriendStatus(player) == Enum.FriendStatus.FriendRequestReceived
|
|
end,
|
|
--IsActive
|
|
function(player)
|
|
return true
|
|
end,
|
|
--DoIt
|
|
function(player)
|
|
friendRequestBlacklist[player] = true
|
|
return game.Players.LocalPlayer:RevokeFriendship(player)
|
|
end
|
|
)
|
|
|
|
addContextMenuButton("Cancel " .. friendWord .. " Request",
|
|
--IsVisible
|
|
function(player)
|
|
return false -- disable cancel request for now (can lead to griefing)
|
|
--return getFriendStatus(player) == Enum.FriendStatus.FriendRequestSent
|
|
end,
|
|
--IsActive
|
|
function(player)
|
|
return true
|
|
end,
|
|
--DoIt
|
|
function(player)
|
|
otherPlayerBlacklist[player] = false
|
|
return game.Players.LocalPlayer:RevokeFriendship(player)
|
|
end
|
|
)
|
|
|
|
function addPersonalServerContext()
|
|
if personalServerContextAdded then return end
|
|
personalServerContextAdded = true
|
|
addContextMenuButton("Ban",
|
|
--IsVisible
|
|
function(player)
|
|
return ( getPrivilegeType(game.Players.LocalPlayer) >= privilegeAdmin and (getPrivilegeType(player) < privilegeAdmin) )
|
|
end,
|
|
--IsActive
|
|
function(player)
|
|
return true
|
|
end,
|
|
--DoIt
|
|
function(player)
|
|
player.PersonalServerRank = privilegeBanned
|
|
return true
|
|
end
|
|
)
|
|
addContextMenuButton("Promote to Visitor",
|
|
--IsVisible
|
|
function(player)
|
|
return ( getPrivilegeType(game.Players.LocalPlayer) >= privilegeAdmin ) and ( getPrivilegeType(player) == privilegeBanned )
|
|
end,
|
|
--IsActive
|
|
function(player)
|
|
return true
|
|
end,
|
|
--DoIt
|
|
function(player)
|
|
game:GetService("PersonalServerService"):Promote(player)
|
|
return true
|
|
end
|
|
)
|
|
addContextMenuButton("Promote to Member",
|
|
--IsVisible
|
|
function(player)
|
|
return ( getPrivilegeType(game.Players.LocalPlayer) >= privilegeAdmin ) and ( getPrivilegeType(player) == privilegeVisitor )
|
|
end,
|
|
--IsActive
|
|
function(player)
|
|
return true
|
|
end,
|
|
--DoIt
|
|
function(player)
|
|
game:GetService("PersonalServerService"):Promote(player)
|
|
return true
|
|
end
|
|
)
|
|
addContextMenuButton("Promote to Admin",
|
|
--IsVisible
|
|
function(player)
|
|
return ( getPrivilegeType(game.Players.LocalPlayer) == privilegeOwner ) and ( getPrivilegeType(player) == privilegeMember )
|
|
end,
|
|
--IsActive
|
|
function(player)
|
|
return true
|
|
end,
|
|
--DoIt
|
|
function(player)
|
|
game:GetService("PersonalServerService"):Promote(player)
|
|
return true
|
|
end
|
|
)
|
|
addContextMenuButton("Demote to Member",
|
|
--IsVisible
|
|
function(player)
|
|
return ( getPrivilegeType(game.Players.LocalPlayer) == privilegeOwner ) and ( getPrivilegeType(player) == privilegeAdmin )
|
|
end,
|
|
--IsActive
|
|
function(player)
|
|
return true
|
|
end,
|
|
--DoIt
|
|
function(player)
|
|
game:GetService("PersonalServerService"):Demote(player)
|
|
return true
|
|
end
|
|
)
|
|
addContextMenuButton("Demote to Visitor",
|
|
--IsVisible
|
|
function(player)
|
|
return ( getPrivilegeType(game.Players.LocalPlayer) >= privilegeAdmin ) and ( getPrivilegeType(player) == privilegeMember )
|
|
end,
|
|
--IsActive
|
|
function(player)
|
|
return true
|
|
end,
|
|
--DoIt
|
|
function(player)
|
|
game:GetService("PersonalServerService"):Demote(player)
|
|
return true
|
|
end
|
|
)
|
|
end
|
|
|
|
local function setupBuildToolManagement()
|
|
local buildToolManagerAssetId = 64164692
|
|
game:GetService("ScriptContext"):AddCoreScript(buildToolManagerAssetId,game.Players.LocalPlayer,"BuildToolManager")
|
|
end
|
|
|
|
|
|
local function getStatColumns(players)
|
|
for i, player in ipairs(players) do
|
|
local leaderstats = player:FindFirstChild("leaderstats")
|
|
if leaderstats then
|
|
local stats = {}
|
|
local children = leaderstats:GetChildren()
|
|
if children then
|
|
for i, stat in ipairs(children) do
|
|
if stat:IsA("IntValue") then
|
|
table.insert(stats, stat)
|
|
else
|
|
--TODO: This should check for IntValue only but current ScoreHud does not
|
|
table.insert(stats, stat)
|
|
end
|
|
end
|
|
end
|
|
return stats
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local function determineBoardType()
|
|
local players = getPlayers()
|
|
|
|
local foundLeaderstats = false
|
|
local numStats = 0
|
|
local foundTeam = false
|
|
|
|
local stats = getStatColumns(players)
|
|
if stats then
|
|
foundLeaderstats = true
|
|
numStats = #stats
|
|
end
|
|
|
|
for i, player in ipairs(players) do
|
|
if not foundTeam then
|
|
if not player.Neutral then
|
|
foundTeam = true
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
if foundLeaderstats and foundTeam then
|
|
return "TeamScore", numStats
|
|
elseif foundLeaderstats then
|
|
return "PlayerScore", numStats
|
|
elseif foundTeam then
|
|
return "TeamList", numStats
|
|
else
|
|
return "PlayerList", numStats
|
|
end
|
|
end
|
|
|
|
local function toggleBigWindow()
|
|
if container == nil then
|
|
return
|
|
end
|
|
|
|
if currentWindowState == "Big" then
|
|
--Hide it
|
|
if previousWindowState == nil or previousWindowState == "Big" or previousWindowState == "None" then
|
|
transitionWindowsFunction("None")
|
|
else
|
|
transitionWindowsFunction("Small")
|
|
end
|
|
else
|
|
previousWindowState = currentWindowState
|
|
transitionWindowsFunction("Big")
|
|
end
|
|
end
|
|
local previousBigPlayerList = nil
|
|
local function rebuildBoard(owner, boardType, numStats)
|
|
if topRightTrayContainer == nil then
|
|
topRightTrayContainer = owner:FindFirstChild("PlayerListTopRightFrame")
|
|
if topRightTrayContainer == nil then
|
|
topRightTrayContainer = Instance.new("Frame")
|
|
topRightTrayContainer.Name = "PlayerListTopRightFrame"
|
|
topRightTrayContainer.BackgroundTransparency = 1
|
|
topRightTrayContainer.Size = UDim2.new(0.2, 16, 0.42, 16)
|
|
topRightTrayContainer.Position = UDim2.new(0.8, 0, 0, 0)
|
|
topRightTrayContainer.Parent = container
|
|
end
|
|
end
|
|
if minimizedState == nil then
|
|
minimizedState = Instance.new("Frame")
|
|
minimizedState.Name = "MinimizedPlayerlist"
|
|
minimizedState.BackgroundTransparency = 1
|
|
minimizedState.Position = UDim2.new(1, -166, 0,0)
|
|
minimizedState.Size = UDim2.new(0, 151, 0, 30)
|
|
|
|
playerListButton = Instance.new("ImageButton")
|
|
playerListButton.Name = "GoSmallButton"
|
|
playerListButton.Image = "rbxasset://textures/ui/playerlist_hidden_small.png"
|
|
playerListButton.BackgroundTransparency = 1
|
|
playerListButton.Size = UDim2.new(0.0, 35, 0, 30)
|
|
playerListButton.Position = UDim2.new(1, -35, 0, 0)
|
|
playerListButton.MouseButton1Click:connect(
|
|
function()
|
|
transitionWindowsFunction("Small")
|
|
end)
|
|
playerListButton.Parent = minimizedState
|
|
|
|
minimizedState.Visible = false
|
|
robloxLock(minimizedState)
|
|
minimizedState.Parent = topRightTrayContainer
|
|
end
|
|
if bigWindowImposter == nil then
|
|
bigWindowImposter = owner:FindFirstChild("BigPlayerListWindowImposter")
|
|
if bigWindowImposter == nil then
|
|
bigWindowImposter = Instance.new("Frame")
|
|
bigWindowImposter.Name = "BigPlayerListWindowImposter"
|
|
bigWindowImposter.Visible = false
|
|
bigWindowImposter.BackgroundColor3 = Color3.new(0,0,0)
|
|
bigWindowImposter.BackgroundTransparency = 0.7
|
|
bigWindowImposter.BorderSizePixel = 0
|
|
bigWindowImposter.Size = UDim2.new(0.4, 7, 0.4, 7)
|
|
bigWindowImposter.Position = UDim2.new(0.3, 0, 0.3, 0)
|
|
robloxLock(bigWindowImposter)
|
|
bigWindowImposter.Parent = container
|
|
end
|
|
end
|
|
if container == nil or container ~= owner then
|
|
container = owner
|
|
|
|
topRightTrayContainer.Parent = container
|
|
bigWindowImposter.Parent = container
|
|
end
|
|
|
|
local smallVisible = true
|
|
local bigVisible = false
|
|
if container then
|
|
if topRightTrayContainer then
|
|
--Delete the old boards
|
|
if topRightTrayContainer:FindFirstChild("SmallPlayerlist") then
|
|
smallVisible = topRightTrayContainer.SmallPlayerlist.Visible
|
|
topRightTrayContainer.SmallPlayerlist.Parent = nil
|
|
end
|
|
end
|
|
if container:FindFirstChild("BigPlayerlist") then
|
|
bigVisible = container.BigPlayerlist.Visible or (previousBigPlayerList ~= nil)
|
|
container.BigPlayerlist.Parent = nil
|
|
if previousBigPlayerList ~= nil then
|
|
pcall(function() game.GuiService:RemoveCenterDialog(previousBigPlayerList) end)
|
|
previousBigPlayerList = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
local smallBoard, bigBoard = createBoardsFunction(boardType, numStats)
|
|
if smallBoard then
|
|
smallBoard.Visible = smallVisible
|
|
smallBoard.Parent = topRightTrayContainer
|
|
recalculateSmallPlayerListSize(smallBoard)
|
|
end
|
|
if bigBoard then
|
|
if bigVisible then
|
|
previousBigPlayerList = bigBoard
|
|
local centerDialogSupported, msg = pcall(function() game.GuiService:AddCenterDialog(previousBigPlayerList, Enum.CenterDialogType.PlayerInitiatedDialog,
|
|
function()
|
|
previousBigPlayerList.Visible = true
|
|
end,
|
|
function()
|
|
previousBigPlayerList.Visible = false
|
|
end)
|
|
end)
|
|
bigBoard.Visible = bigVisible
|
|
else
|
|
bigBoard.Visible = false
|
|
end
|
|
bigBoard.Parent = container
|
|
end
|
|
return container
|
|
end
|
|
|
|
function recalculateSmallPlayerListSize(smallPlayerList)
|
|
waitForChild(smallPlayerList,"ScrollingArea")
|
|
waitForChild(smallPlayerList.ScrollingArea, "ScrollingFrame")
|
|
local scrollingFrame = smallPlayerList.ScrollingArea.ScrollingFrame
|
|
local playerLines = scrollingFrame:GetChildren()
|
|
|
|
local totalPlayerListSize = 0
|
|
for i = 1, #playerLines do
|
|
totalPlayerListSize = totalPlayerListSize + playerLines[i].AbsoluteSize.Y
|
|
end
|
|
|
|
if not smallPlayerList.Parent then return end
|
|
|
|
local yOffset = math.max(0,(smallPlayerList.Size.Y.Scale * smallPlayerList.Parent.AbsoluteSize.Y) - totalPlayerListSize - smallWindowHeaderYSize)
|
|
smallPlayerList.Size = UDim2.new(smallPlayerList.Size.X.Scale,smallPlayerList.Size.X.Offset,smallPlayerList.Size.Y.Scale,-yOffset)
|
|
end
|
|
|
|
|
|
local function showBigPlayerWindow()
|
|
if container:FindFirstChild("BigPlayerlist") then
|
|
if container.BigPlayerlist.Visible then
|
|
return
|
|
end
|
|
end
|
|
|
|
bigWindowImposter.Visible = true
|
|
bigWindowImposter:TweenSizeAndPosition(bigWindowSize, bigWindowPosition, Enum.EasingDirection.Out, bigEasingStyle, 0.3, true,
|
|
function(state)
|
|
if state == Enum.TweenStatus.Completed then
|
|
bigWindowImposter.Visible = false
|
|
if container:FindFirstChild("BigPlayerlist") then
|
|
container.BigPlayerlist.Visible = true
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
|
|
local function hideBigPlayerWindow(completed)
|
|
if playerContextMenu then
|
|
playerContextMenu.Visible = false
|
|
end
|
|
|
|
if container:FindFirstChild("BigPlayerlist") then
|
|
if container.BigPlayerlist.Visible == false and bigWindowImposter.Visible == false then
|
|
if completed then
|
|
completed()
|
|
end
|
|
--Already completely hidden
|
|
return
|
|
end
|
|
container.BigPlayerlist.Visible = false
|
|
end
|
|
|
|
local completedFunction = completed
|
|
bigWindowImposter.Visible = true
|
|
bigWindowImposter:TweenSizeAndPosition(UDim2.new(0.4, 0, 0.4, 0), UDim2.new(0.3, 0, 0.3, 0), Enum.EasingDirection.In, Enum.EasingStyle.Quart, 0.15, true,
|
|
function(state)
|
|
if state == Enum.TweenStatus.Completed then
|
|
bigWindowImposter.Visible = false
|
|
if completedFunction then
|
|
completedFunction()
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
local function hideSmallPlayerWindow(completed)
|
|
if playerContextMenu then
|
|
playerContextMenu.Visible = false
|
|
end
|
|
if topRightTrayContainer:FindFirstChild("SmallPlayerlist") then
|
|
local completedFunction = completed
|
|
if topRightTrayContainer.SmallPlayerlist.Visible then
|
|
topRightTrayContainer.SmallPlayerlist:TweenPosition(UDim2.new(1,0,smallWindowPosition.Y.Scale, smallWindowPosition.Y.Offset), Enum.EasingDirection.Out, smallEasingStyle, 0.3, true,
|
|
function(state)
|
|
if state == Enum.TweenStatus.Completed then
|
|
if topRightTrayContainer:FindFirstChild("SmallPlayerlist") then
|
|
topRightTrayContainer.SmallPlayerlist.Visible = false
|
|
end
|
|
if completedFunction then
|
|
completedFunction()
|
|
end
|
|
end
|
|
end)
|
|
return
|
|
end
|
|
end
|
|
if completed then
|
|
completed()
|
|
end
|
|
end
|
|
|
|
|
|
transitionWindowsFunction = function(desiredState)
|
|
if desiredState == "Big" then
|
|
minimizedState.Visible = false
|
|
hideSmallPlayerWindow()
|
|
|
|
if previousBigPlayerList ~= nil then
|
|
if previousBigPlayerList ~= container:FindFirstChild("BigPlayerlist") then
|
|
pcall(function() game.GuiService:RemoveCenterDialog(previousBigPlayerList) end)
|
|
previousBigPlayerList = nil
|
|
previousBigPlayerList = container:FindFirstChild("BigPlayerlist")
|
|
end
|
|
else
|
|
previousBigPlayerList = container:FindFirstChild("BigPlayerlist")
|
|
end
|
|
|
|
if previousBigPlayerList then
|
|
local firstShow = false
|
|
local centerDialogSupported, msg = pcall(function() game.GuiService:AddCenterDialog(previousBigPlayerList, Enum.CenterDialogType.PlayerInitiatedDialog,
|
|
function()
|
|
if not firstShow then
|
|
showBigPlayerWindow()
|
|
firstShow = true
|
|
else
|
|
previousBigPlayerList.Visible = true
|
|
end
|
|
end,
|
|
function()
|
|
if previousBigPlayerList then
|
|
previousBigPlayerList.Visible = false
|
|
end
|
|
end)
|
|
end)
|
|
if centerDialogSupported == false then
|
|
print("Exception", msg)
|
|
showBigPlayerWindow()
|
|
end
|
|
else
|
|
showBigPlayerWindow()
|
|
end
|
|
currentWindowState = "Big"
|
|
elseif desiredState == "Small" then
|
|
minimizedState.Visible = false
|
|
if previousBigPlayerList ~= nil then
|
|
pcall(function() game.GuiService:RemoveCenterDialog(previousBigPlayerList) end)
|
|
previousBigPlayerList = nil
|
|
end
|
|
|
|
hideBigPlayerWindow()
|
|
if topRightTrayContainer:FindFirstChild("SmallPlayerlist") then
|
|
if not topRightTrayContainer.SmallPlayerlist.Visible or topRightTrayContainer.SmallPlayerlist.Position ~= smallWindowPosition then
|
|
topRightTrayContainer.SmallPlayerlist.Visible = true
|
|
topRightTrayContainer.SmallPlayerlist:TweenPosition(smallWindowPosition, Enum.EasingDirection.Out, smallEasingStyle, 0.3, true)
|
|
end
|
|
end
|
|
currentWindowState = "Small"
|
|
elseif desiredState == "None" then
|
|
if previousBigPlayerList ~= nil then
|
|
pcall(function() game.GuiService:RemoveCenterDialog(previousBigPlayerList) end)
|
|
previousBigPlayerList = nil
|
|
end
|
|
|
|
local smallDone = false
|
|
local bigDone = false
|
|
hideSmallPlayerWindow(
|
|
function()
|
|
smallDone = true
|
|
if bigDone and smallDone then
|
|
minimizedState.Visible = true
|
|
end
|
|
end)
|
|
hideBigPlayerWindow(
|
|
function()
|
|
bigDone = true
|
|
if bigDone and smallDone then
|
|
minimizedState.Visible = true
|
|
end
|
|
end)
|
|
currentWindowState = "None"
|
|
end
|
|
end
|
|
|
|
local function getStatValuesForPlayer(player)
|
|
local leaderstats = player:FindFirstChild("leaderstats")
|
|
if leaderstats then
|
|
local children = leaderstats:GetChildren()
|
|
if children then
|
|
local result = {}
|
|
--Just go based on position
|
|
for i, stat in ipairs(children) do
|
|
if stat:IsA("IntValue") then
|
|
table.insert(result, stat)
|
|
else
|
|
table.insert(result, 0)
|
|
end
|
|
end
|
|
|
|
return result, leaderstats
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
--ChildAdded on Player (if it's name is "leaderstats")
|
|
|
|
if UserSettings and LoadLibrary then
|
|
|
|
RbxGui,msg = LoadLibrary("RbxGui")
|
|
|
|
local function createTeamName(name, color)
|
|
local fontHeight = 20
|
|
local frame = Instance.new("Frame")
|
|
frame.Name = "Team-" .. name
|
|
frame.BorderSizePixel = 0
|
|
frame.BackgroundTransparency = 0.5
|
|
frame.BackgroundColor3 = Color3.new(1,1,1)
|
|
frame.Size = UDim2.new(1, 0, 0, fontHeight)
|
|
frame.Position = UDim2.new(0,0,0,0)
|
|
|
|
local label = Instance.new("TextLabel")
|
|
label.Name = "NameLabel"
|
|
label.Text = " " .. name
|
|
label.Font = Enum.Font.ArialBold
|
|
label.FontSize = Enum.FontSize.Size18
|
|
label.Position = UDim2.new(0,0,0,0)
|
|
label.Size = UDim2.new(1,0,1,0)
|
|
label.TextColor3 = Color3.new(1,1,1)
|
|
label.BackgroundTransparency = 0.5
|
|
label.BackgroundColor3 = getColor(color)
|
|
label.BorderSizePixel = 0
|
|
label.TextXAlignment = Enum.TextXAlignment.Left
|
|
|
|
local changeFunc = nil
|
|
label, changeFunc = RbxGui.AutoTruncateTextObject(label)
|
|
label.Parent = frame
|
|
|
|
return frame, changeFunc
|
|
end
|
|
|
|
local function getFriendStatusIcon(friendStatus)
|
|
if friendStatus == Enum.FriendStatus.Unknown or friendStatus == Enum.FriendStatus.NotFriend then
|
|
return nil
|
|
elseif friendStatus == Enum.FriendStatus.Friend then
|
|
return "rbxasset://textures/ui/PlayerlistFriendIcon.png"
|
|
elseif friendStatus == Enum.FriendStatus.FriendRequestSent then
|
|
return "rbxasset://textures/ui/PlayerlistFriendRequestSentIcon.png"
|
|
elseif friendStatus == Enum.FriendStatus.FriendRequestReceived then
|
|
return "rbxasset://textures/ui/PlayerlistFriendRequestReceivedIcon.png"
|
|
else
|
|
error("Unknown FriendStatus: " .. friendStatus)
|
|
end
|
|
end
|
|
|
|
local function getMembershipTypeIcon(membershipType)
|
|
if membershipType == Enum.MembershipType.None then
|
|
return ""
|
|
elseif membershipType == Enum.MembershipType.BuildersClub then
|
|
return "rbxasset://textures/ui/TinyBcIcon.png"
|
|
elseif membershipType == Enum.MembershipType.TurboBuildersClub then
|
|
return "rbxasset://textures/ui/TinyTbcIcon.png"
|
|
elseif membershipType == Enum.MembershipType.OutrageousBuildersClub then
|
|
return "rbxasset://textures/ui/TinyObcIcon.png"
|
|
else
|
|
error("Uknown membershipType" .. membershipType)
|
|
end
|
|
end
|
|
|
|
|
|
local function updatePlayerFriendStatus(nameObject, friendStatus)
|
|
local fontHeight = 20
|
|
|
|
local friendIconImage = getFriendStatusIcon(friendStatus)
|
|
nameObject.MembershipTypeLabel.FriendStatusLabel.Visible = (friendIconImage ~= nil)
|
|
|
|
if friendIconImage ~= nil then
|
|
--Show friend icon
|
|
nameObject.MembershipTypeLabel.FriendStatusLabel.Image = friendIconImage
|
|
nameObject.NameLabel.Position =UDim2.new(0,2*fontHeight,0,1)
|
|
nameObject.NameLabel.Size = UDim2.new(1,-2*fontHeight,1,-2)
|
|
else
|
|
--Hide the friend icon
|
|
nameObject.NameLabel.Position = UDim2.new(0,fontHeight+1,0,1)
|
|
nameObject.NameLabel.Size = UDim2.new(1,-(fontHeight+1),1,-2)
|
|
end
|
|
end
|
|
local function updatePlayerName(nameObject, membershipStatus, teamColor)
|
|
local fontHeight = 20
|
|
|
|
nameObject.Size = UDim2.new(1,0,0,fontHeight)
|
|
nameObject.MembershipTypeLabel.Image = getMembershipTypeIcon(membershipStatus)
|
|
end
|
|
|
|
|
|
local function updatePlayerNameColor(player, teamColor)
|
|
local function updatePlayerNameColorHelper(nameObject)
|
|
if teamColor ~= nil then
|
|
nameObject.NameLabel.TextColor3 = getColor(teamColor)
|
|
nameObject.NameLabel.FullNameLabel.TextColor3 = getColor(teamColor)
|
|
else
|
|
nameObject.NameLabel.TextColor3 = Color3.new(1,1,1)
|
|
nameObject.NameLabel.FullNameLabel.TextColor3 = Color3.new(1,1,1)
|
|
end
|
|
end
|
|
|
|
updatePlayerNameColorHelper(playerTable[player].NameObjectSmall)
|
|
updatePlayerNameColorHelper(playerTable[player].NameObjectBig)
|
|
end
|
|
|
|
|
|
local function createPlayerName(name, membershipStatus, teamColor, friendStatus)
|
|
local frame = Instance.new("Frame")
|
|
frame.Name = "Player_" .. name
|
|
frame.BackgroundColor3 = Color3.new(1,1,1)
|
|
frame.BackgroundTransparency = 0.5
|
|
frame.BorderSizePixel = 0
|
|
|
|
local membershipStatusLabel = Instance.new("ImageLabel")
|
|
membershipStatusLabel.Name = "MembershipTypeLabel"
|
|
membershipStatusLabel.BackgroundTransparency = 1
|
|
membershipStatusLabel.Size = UDim2.new(1,0,1,0)
|
|
membershipStatusLabel.Position = UDim2.new(0,0,0,0)
|
|
membershipStatusLabel.SizeConstraint = Enum.SizeConstraint.RelativeYY
|
|
membershipStatusLabel.Parent = frame
|
|
|
|
local friendStatusLabel = Instance.new("ImageLabel")
|
|
friendStatusLabel.Name = "FriendStatusLabel"
|
|
friendStatusLabel.Visible = false
|
|
friendStatusLabel.BackgroundTransparency = 1
|
|
friendStatusLabel.Size = UDim2.new(1,0,1,0)
|
|
friendStatusLabel.Position = UDim2.new(1,0,0,0)
|
|
friendStatusLabel.Parent = membershipStatusLabel
|
|
|
|
local changeNameFunction
|
|
local nameLabel = Instance.new("TextLabel")
|
|
nameLabel.Name = "NameLabel"
|
|
nameLabel.Text = name
|
|
nameLabel.Font = Enum.Font.ArialBold
|
|
nameLabel.FontSize = Enum.FontSize.Size14
|
|
nameLabel.TextColor3 = Color3.new(1,1,1)
|
|
nameLabel.BackgroundTransparency = 1
|
|
nameLabel.BackgroundColor3 = Color3.new(0,0,0)
|
|
nameLabel.TextXAlignment = Enum.TextXAlignment.Left
|
|
nameLabel, changeNameFunction = RbxGui.AutoTruncateTextObject(nameLabel)
|
|
nameLabel.Parent = frame
|
|
|
|
updatePlayerName(frame, membershipStatus, teamColor)
|
|
if supportFriends and not friendRequestBlacklist[game.Players:FindFirstChild(name)] then
|
|
updatePlayerFriendStatus(frame, friendStatus)
|
|
else
|
|
updatePlayerFriendStatus(frame, Enum.FriendStatus.NotFriend)
|
|
end
|
|
return frame, changeNameFunction
|
|
end
|
|
|
|
local function createStatColumn(i, numColumns, isTeam, color3, isHeader, stat)
|
|
local textLabel = Instance.new("TextButton")
|
|
textLabel.Name = "Stat" .. i
|
|
textLabel.AutoButtonColor = false
|
|
textLabel.TextColor3 = Color3.new(1,1,1)
|
|
textLabel.TextXAlignment = Enum.TextXAlignment.Right
|
|
textLabel.TextYAlignment = Enum.TextYAlignment.Center
|
|
textLabel.FontSize = Enum.FontSize.Size14
|
|
|
|
if isHeader then
|
|
textLabel.FontSize = Enum.FontSize.Size18
|
|
else
|
|
textLabel.FontSize = Enum.FontSize.Size14
|
|
end
|
|
if isHeader or isTeam then
|
|
textLabel.Font = Enum.Font.ArialBold
|
|
else
|
|
textLabel.Font = Enum.Font.Arial
|
|
end
|
|
|
|
if isTeam then
|
|
textLabel.BackgroundColor3 = color3
|
|
textLabel.Text = 0
|
|
else
|
|
textLabel.BackgroundColor3 = Color3.new(0,0,0)
|
|
textLabel.Text = ""
|
|
end
|
|
textLabel.BackgroundTransparency = 1
|
|
if i == numColumns then
|
|
textLabel.Size = UDim2.new(1/numColumns, -6, 1, 0)
|
|
else
|
|
textLabel.Size = UDim2.new(1/numColumns, -4, 1, 0)
|
|
end
|
|
|
|
textLabel.Position = UDim2.new((i-1) * (1/numColumns), 0, 0, 0)
|
|
|
|
local truncLabel, changer = RbxGui.AutoTruncateTextObject(textLabel)
|
|
|
|
if isHeader then
|
|
local mouseCon = {}
|
|
|
|
mouseCon[1] = truncLabel.MouseEnter:connect(function()
|
|
truncLabel.BackgroundTransparency = 0.2
|
|
end)
|
|
mouseCon[2] = truncLabel.MouseLeave:connect(function()
|
|
truncLabel.BackgroundTransparency = 1
|
|
end)
|
|
|
|
mouseCon[3] = truncLabel.MouseButton1Click:connect(function()
|
|
sortPlayerListsFunction(truncLabel:GetChildren()[1].Name, (currentSortName == truncLabel:GetChildren()[1].Name) )
|
|
truncLabel.BackgroundTransparency = 1
|
|
end)
|
|
|
|
mouseCon[4] = truncLabel:GetChildren()[1].MouseButton1Click:connect(function()
|
|
sortPlayerListsFunction(textLabel.Name, (currentSortName == truncLabel.Name) )
|
|
truncLabel.BackgroundTransparency = 1
|
|
end)
|
|
|
|
mouseCon[5] = nil
|
|
mouseCon[5] = truncLabel.AncestryChanged:connect(function(child,parent)
|
|
if parent == nil then
|
|
for i,connection in pairs(mouseCon) do
|
|
connection:disconnect()
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
|
|
return truncLabel, changer
|
|
end
|
|
|
|
local function createStatHeaders(stats, numColumns, isBig)
|
|
local frame = Instance.new("Frame")
|
|
frame.Name = "Headers"
|
|
frame.BorderSizePixel = 0
|
|
frame.BackgroundColor3 = Color3.new(0,0,0)
|
|
frame.BackgroundTransparency = 1
|
|
|
|
local nameSize
|
|
if isBig then
|
|
nameSize = 0.5
|
|
elseif numColumns == 1 then
|
|
nameSize = 0.7
|
|
elseif numColumns == 2 then
|
|
nameSize = 0.6
|
|
else
|
|
nameSize = 0.45
|
|
end
|
|
frame.Size = UDim2.new(1-nameSize, 0, 1,0)
|
|
if isBig then
|
|
frame.Position = UDim2.new(nameSize,-25, 0,0)
|
|
else
|
|
frame.Position = UDim2.new(nameSize,0, 0,0)
|
|
end
|
|
|
|
local i = 1
|
|
while i <= numColumns do
|
|
local headerColumn, changeText = createStatColumn(i, numColumns, false, nil, true,stats[i])
|
|
changeText(stats[i].Name)
|
|
headerColumn.Parent = frame
|
|
i = i + 1
|
|
end
|
|
return frame, textChangers
|
|
end
|
|
|
|
local function createStatColumns(nameObject, numColumns, isTeam, isBig)
|
|
local frame = Instance.new("Frame")
|
|
frame.Name = nameObject.Name .. "_WithStats"
|
|
frame.BorderSizePixel = 0
|
|
frame.BackgroundColor3 = nameObject.BackgroundColor3
|
|
frame.BackgroundTransparency = nameObject.BackgroundTransparency
|
|
frame.Size = nameObject.Size
|
|
frame.Position = nameObject.Position
|
|
|
|
nameObject.BackgroundTransparency = 1
|
|
|
|
if numColumns == 0 then
|
|
nameObject.Size = UDim2.new(1,0,1,0)
|
|
nameObject.Position = UDim2.new(0,0,0,0)
|
|
nameObject.Parent = frame
|
|
return frame
|
|
end
|
|
|
|
local statFrame = Instance.new("Frame")
|
|
statFrame.Name = "Stats"
|
|
if isTeam then
|
|
statFrame.BorderSizePixel = 0
|
|
statFrame.BackgroundColor3 = nameObject.NameLabel.BackgroundColor3
|
|
statFrame.BackgroundTransparency = nameObject.NameLabel.BackgroundTransparency
|
|
else
|
|
statFrame.BackgroundTransparency = 1
|
|
end
|
|
|
|
local nameSize
|
|
if isBig then
|
|
nameSize = 0.5
|
|
elseif numColumns == 1 then
|
|
nameSize = 0.7
|
|
elseif numColumns == 2 then
|
|
nameSize = 0.6
|
|
else
|
|
nameSize = 0.45
|
|
end
|
|
nameObject.Size = UDim2.new(nameSize, 0, 1, 0)
|
|
nameObject.Position = UDim2.new(0, 0, 0, 0)
|
|
statFrame.Size = UDim2.new(1-nameSize,0, 1,0)
|
|
statFrame.Position = UDim2.new(nameSize,0, 0,0)
|
|
|
|
nameObject.Parent = frame
|
|
statFrame.Parent = frame
|
|
|
|
local textChangers = {}
|
|
local i = 1
|
|
while i <= numColumns do
|
|
local statColumn, changeText = createStatColumn(i, numColumns, isTeam, statFrame.BackgroundColor3)
|
|
statColumn.Parent = statFrame
|
|
table.insert(textChangers, changeText)
|
|
|
|
i = i + 1
|
|
end
|
|
|
|
return frame, statFrame, textChangers
|
|
end
|
|
|
|
local function createAlternatingRows(objects)
|
|
for i, line in ipairs(objects) do
|
|
if i % 2 == 0 then
|
|
line.BackgroundTransparency = 1
|
|
else
|
|
line.BackgroundTransparency = 0.95
|
|
end
|
|
end
|
|
end
|
|
local removeFromTeam = nil
|
|
|
|
local function clearTableEntry(obj, tableInfo)
|
|
if tableInfo.MainObjectSmall then
|
|
tableInfo.MainObjectSmall.Parent = nil
|
|
tableInfo.MainObjectSmall = nil
|
|
end
|
|
if tableInfo.MainObjectBig then
|
|
tableInfo.MainObjectBig.Parent = nil
|
|
tableInfo.MainObjectBig = nil
|
|
end
|
|
if tableInfo.Connections then
|
|
for i, connection in ipairs(tableInfo.Connections) do
|
|
connection:disconnect()
|
|
end
|
|
tableInfo.Connections = nil
|
|
end
|
|
if tableInfo.LeaderStatConnections then
|
|
for i, connection in ipairs(tableInfo.LeaderStatConnections) do
|
|
connection:disconnect()
|
|
end
|
|
tableInfo.LeaderStatConnections = nil
|
|
end
|
|
if tableInfo.CurrentTeam then
|
|
removeFromTeam(obj)
|
|
tableInfo.CurrentTeam = nil
|
|
end
|
|
if tableInfo.Players then
|
|
for i, player in ipairs(tableInfo.Players) do
|
|
playerTable[player].CurrentTeam = nil
|
|
end
|
|
tableInfo.Players = {}
|
|
end
|
|
if tableInfo.StatValues then
|
|
tableInfo.StatValues = nil
|
|
end
|
|
end
|
|
|
|
local function resetPlayerTable()
|
|
for player, info in pairs(playerTable) do
|
|
clearTableEntry(player, info)
|
|
playerTable[player] = nil
|
|
end
|
|
playerTable = {}
|
|
end
|
|
|
|
local function resetTeamTable()
|
|
for team, info in pairs(teamTable) do
|
|
clearTableEntry(team, info)
|
|
teamTable[team] = nil
|
|
end
|
|
teamTable = {}
|
|
teamColorTable = {}
|
|
end
|
|
|
|
local function getBoardTypeInfo()
|
|
local isTeam = (currentBoardType == "TeamScore" or currentBoardType == "TeamList")
|
|
local isScore = (currentBoardType == "TeamScore" or currentBoardType == "PlayerScore")
|
|
return isTeam, isScore
|
|
end
|
|
|
|
|
|
local function recomputeTeamScore(team, column)
|
|
if not team or team == "Neutral" then
|
|
return
|
|
end
|
|
|
|
local function recomputeScoreHelper(statChangers)
|
|
if statChangers and column <= #statChangers then
|
|
local sum = 0
|
|
for i, p in ipairs(teamTable[team].Players) do
|
|
if playerTable[p].StatValues and column <= #playerTable[p].StatValues then
|
|
sum = sum + playerTable[p].StatValues[column].Value
|
|
end
|
|
end
|
|
statChangers[column](sum)
|
|
end
|
|
end
|
|
|
|
recomputeScoreHelper(teamTable[team].StatChangersSmall)
|
|
recomputeScoreHelper(teamTable[team].StatChangersBig)
|
|
end
|
|
local function recomputeCompleteTeamScore(team)
|
|
local col = 1
|
|
while col <= currentStatCount do
|
|
recomputeTeamScore(team, col)
|
|
col = col + 1
|
|
end
|
|
end
|
|
removeFromTeam = function(player)
|
|
if playerTable[player].CurrentTeam ~= nil and teamTable[playerTable[player].CurrentTeam] ~= nil then
|
|
ArrayRemove(teamTable[playerTable[player].CurrentTeam].Players, player)
|
|
recomputeCompleteTeamScore(playerTable[player].CurrentTeam)
|
|
playerTable[player].CurrentTeam = nil
|
|
end
|
|
end
|
|
|
|
local function assignToTeam(player)
|
|
local isTeam, isScore = getBoardTypeInfo()
|
|
|
|
if isTeam then
|
|
local newTeam = nil
|
|
|
|
if player.Neutral or teamColorTable[player.TeamColor.Name] == nil then
|
|
newTeam = "Neutral"
|
|
else
|
|
newTeam = teamColorTable[player.TeamColor.Name]
|
|
end
|
|
|
|
if playerTable[player].CurrentTeam == newTeam then
|
|
return
|
|
end
|
|
|
|
local oldTeam = playerTable[player].LastTeam
|
|
removeFromTeam(player)
|
|
|
|
playerTable[player].CurrentTeam = newTeam
|
|
|
|
if teamTable[oldTeam] and teamTable[oldTeam]["NameChangeFuncBig"] then
|
|
if #teamTable[oldTeam].Players < 1 then
|
|
teamTable[oldTeam]["NameChangeFuncBig"](" " .. oldTeam.Name)
|
|
else
|
|
teamTable[oldTeam]["NameChangeFuncBig"](" " .. oldTeam.Name .. " (" .. tostring(#teamTable[oldTeam].Players) ..")")
|
|
end
|
|
end
|
|
|
|
if teamTable[newTeam] then
|
|
table.insert(teamTable[newTeam].Players, player)
|
|
if newTeam["Name"] then
|
|
if teamTable[newTeam]["NameChangeFuncBig"] then
|
|
if #teamTable[newTeam].Players < 1 then
|
|
teamTable[newTeam]["NameChangeFuncBig"](" " .. newTeam.Name)
|
|
else
|
|
teamTable[newTeam]["NameChangeFuncBig"](" " .. newTeam.Name .. " (" .. tostring(#teamTable[newTeam].Players) ..")")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if newTeam == "Neutral" then
|
|
updatePlayerNameColor(player, nil)
|
|
else
|
|
updatePlayerNameColor(player, player.TeamColor)
|
|
end
|
|
|
|
playerTable[player].LastTeam = newTeam
|
|
|
|
recomputeCompleteTeamScore(newTeam)
|
|
|
|
--Relayout
|
|
if sortPlayerListsFunction then
|
|
sortPlayerListsFunction()
|
|
end
|
|
end
|
|
end
|
|
|
|
local function buildTeamObject(team, numStatColumns, suffix)
|
|
local isTeam, isScore = getBoardTypeInfo()
|
|
local teamObject, changeFunc = createTeamName(team.Name, team.TeamColor)
|
|
teamObject.NameLabel.Text = " " .. team.Name .. " (0)"
|
|
if not teamTable[team] then
|
|
teamTable[team] = {}
|
|
end
|
|
teamTable[team]["NameObject" .. suffix] = teamObject
|
|
teamTable[team]["NameChangeFunc" .. suffix] = changeFunc
|
|
if isScore then
|
|
local statObject
|
|
local textChangers
|
|
teamObject, statObject, textChangers = createStatColumns(teamObject, numStatColumns, true, suffix == "Big")
|
|
teamTable[team]["StatObject" .. suffix] = statObject
|
|
teamTable[team]["StatChangers" .. suffix] = textChangers
|
|
end
|
|
teamTable[team]["MainObject" .. suffix] = teamObject
|
|
changeFunc(" " .. team.Name)
|
|
if not teamTable[team].Players then
|
|
teamTable[team].Players = {}
|
|
else
|
|
if suffix ~= "Small" and #teamTable[team].Players > 0 then
|
|
changeFunc(" " .. team.Name .. " (" .. tostring(#teamTable[team].Players) ..")")
|
|
end
|
|
end
|
|
|
|
return teamObject
|
|
end
|
|
|
|
local currentContextMenuPlayer = nil
|
|
local function updatePlayerContextMenu(player,x,y)
|
|
currentContextMenuPlayer = player
|
|
local elementHeight = 18
|
|
local function highlight(button)
|
|
button.TextColor3 = Color3.new(0,0,0)
|
|
button.BackgroundColor3 = Color3.new(0.8,0.8,0.8)
|
|
end
|
|
local function clearHighlight(button)
|
|
button.TextColor3 = Color3.new(1,1,1)
|
|
button.BackgroundColor3 = Color3.new(0,0,0)
|
|
end
|
|
if playerContextMenu == nil then
|
|
elementNames = {}
|
|
elementNameToElement = {}
|
|
|
|
for i, contextElement in ipairs(contextMenuElements) do
|
|
table.insert(elementNames, contextElement.Text)
|
|
elementNameToElement[tostring(contextElement.Text)] = contextElement
|
|
end
|
|
|
|
playerContextMenu = Instance.new("TextButton")
|
|
playerContextMenu.Name = "PlayerListContextMenu"
|
|
playerContextMenu.Style = Enum.ButtonStyle.RobloxButton
|
|
playerContextMenu.Text = ""
|
|
playerContextMenu.Visible = false
|
|
playerContextMenu.ZIndex = 4
|
|
|
|
playerContextMenu.MouseLeave:connect(function()
|
|
local menuChildren = playerContextMenu:GetChildren()
|
|
for i = 1, #menuChildren do
|
|
if menuChildren[i].Name == "ChoiceButton" then
|
|
menuChildren[i].TextColor3 = Color3.new(1,1,1)
|
|
menuChildren[i].BackgroundTransparency = 1
|
|
end
|
|
end
|
|
playerContextMenu.Visible = false
|
|
inContextMenu = false
|
|
end)
|
|
|
|
playerContextMenu.MouseEnter:connect(function()
|
|
inContextMenu = true
|
|
end)
|
|
|
|
for i = 1, #elementNames do
|
|
local newElementButton = Instance.new("TextButton")
|
|
newElementButton.Name = "ChoiceButton"
|
|
newElementButton.Text = elementNames[i]
|
|
newElementButton.TextColor3 = Color3.new(1,1,1)
|
|
newElementButton.Font = Enum.Font.Arial
|
|
newElementButton.FontSize = Enum.FontSize.Size14
|
|
newElementButton.BackgroundTransparency = 1
|
|
newElementButton.TextWrap = true
|
|
newElementButton.Size = UDim2.new(1,0,0,elementHeight)
|
|
newElementButton.Position = UDim2.new(0,0,0,elementHeight * (i - 1))
|
|
newElementButton.ZIndex = playerContextMenu.ZIndex + 1
|
|
|
|
newElementButton.MouseEnter:connect(function()
|
|
newElementButton.TextColor3 = Color3.new(0,0,0)
|
|
newElementButton.BackgroundTransparency = 0
|
|
end)
|
|
|
|
newElementButton.MouseLeave:connect(function()
|
|
newElementButton.TextColor3 = Color3.new(1,1,1)
|
|
newElementButton.BackgroundTransparency = 1
|
|
end)
|
|
|
|
newElementButton.MouseButton1Click:connect(function()
|
|
local element = elementNameToElement[newElementButton.Text]
|
|
pcall(function() element.DoIt(currentContextMenuPlayer) end)
|
|
playerContextMenu.Visible = false
|
|
newElementButton.TextColor3 = Color3.new(1,1,1)
|
|
newElementButton.BackgroundTransparency = 1
|
|
end)
|
|
|
|
newElementButton.Parent = playerContextMenu
|
|
end
|
|
|
|
robloxLock(playerContextMenu)
|
|
playerContextMenu.Parent = script.Parent
|
|
|
|
end
|
|
|
|
local visibleElements = 0
|
|
for i, contextElement in ipairs(contextMenuElements) do
|
|
local isVisible = false
|
|
|
|
if contextElement.IsVisible then
|
|
local success, visible = pcall(function() return contextElement.IsVisible(currentContextMenuPlayer) end)
|
|
if success then
|
|
isVisible = visible
|
|
else
|
|
print("Error in IsVisible call: " .. visible)
|
|
end
|
|
end
|
|
|
|
if isVisible then
|
|
local foundElement = false
|
|
for i = 1, #elementNames do
|
|
if elementNames[i] == contextElement.Text then
|
|
foundElement = true
|
|
break
|
|
end
|
|
end
|
|
if not foundElement then
|
|
table.insert(elementNames,contextElement.Text)
|
|
end
|
|
visibleElements = visibleElements + 1
|
|
else
|
|
for i = 1, #elementNames do
|
|
if elementNames[i] == contextElement.Text then
|
|
table.remove(elementNames,i)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
playerContextMenu.Size = UDim2.new(0, 150, 0, elementHeight + (elementHeight * visibleElements) )
|
|
|
|
if x and y then
|
|
x = x - (playerContextMenu.AbsoluteSize.X/2)
|
|
if x + playerContextMenu.AbsoluteSize.X >= script.Parent.AbsoluteSize.X then
|
|
x = script.Parent.AbsoluteSize.X - playerContextMenu.AbsoluteSize.X
|
|
end
|
|
playerContextMenu.Position = UDim2.new(0, x, 0, y - 3)
|
|
end
|
|
|
|
local elementPos = 0
|
|
local contextChildren = playerContextMenu:GetChildren()
|
|
for i = 1, #contextChildren do
|
|
if contextChildren[i]:IsA("GuiObject") and contextChildren[i].Name == "ChoiceButton" then
|
|
contextChildren[i].Visible = false
|
|
for j = 1, #elementNames do
|
|
if elementNames[j] == contextChildren[i].Text then
|
|
contextChildren[i].Visible = true
|
|
contextChildren[i].Position = UDim2.new(0,0,0,elementPos * elementHeight)
|
|
elementPos = elementPos + 1
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function playerContextMenuHasItems()
|
|
if playerContextMenu then
|
|
local children = playerContextMenu:GetChildren()
|
|
for i = 1, #children do
|
|
if children[i]:IsA("GuiObject") and children[i].Name == "ChoiceButton" and children[i].Visible then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function showPlayerMenu(player, x, y)
|
|
updatePlayerContextMenu(player,x,y)
|
|
if not playerContextMenuHasItems() then return end -- don't show if we have nothing to show
|
|
playerContextMenu.Visible = true
|
|
end
|
|
|
|
local function buildPlayerObject(player, numStatColumns, suffix)
|
|
if not player then return nil end
|
|
|
|
local isTeam, isScore = getBoardTypeInfo()
|
|
|
|
local playerObject = nil
|
|
local changePlayerNameFunction = nil
|
|
local currentColor = nil
|
|
if isTeam and not player.Neutral then
|
|
currentColor = player.TeamColor.Color
|
|
else
|
|
currentColor = Color3.new(1,1,1)
|
|
end
|
|
playerObject, changePlayerNameFunction = createPlayerName(player.Name, player.MembershipType, currentColor, getFriendStatus(player))
|
|
|
|
if not playerTable[player] then
|
|
playerTable[player] = {}
|
|
end
|
|
if not playerTable[player].Connections then
|
|
playerTable[player].Connections = {}
|
|
end
|
|
if not playerTable[player].CurrentTeam then
|
|
playerTable[player].CurrentTeam = nil
|
|
end
|
|
if not playerTable[player].LastTeam then
|
|
playerTable[player].LastTeam = nil
|
|
end
|
|
playerTable[player]["NameObject" .. suffix] = playerObject
|
|
playerTable[player]["ChangeName" .. suffix] = changePlayerNameFunction
|
|
|
|
if isScore then
|
|
local statObject = nil
|
|
local textChangers = nil
|
|
playerObject, statObject, textChangers = createStatColumns(playerObject, numStatColumns, false, suffix == "Big")
|
|
playerTable[player]["StatObject" .. suffix]= statObject
|
|
playerTable[player]["StatChangers" .. suffix] = textChangers
|
|
|
|
local statValues, leaderstats = getStatValuesForPlayer(player)
|
|
if not statValues or #statValues < numStatColumns then
|
|
if not playerTable[player].LeaderStatConnections then
|
|
playerTable[player].LeaderStatConnections = {}
|
|
end
|
|
--Setup a listener to see when this data gets filled in
|
|
if not leaderstats then
|
|
--We don't even have a leaderstats child, wait for one
|
|
table.insert(playerTable[player].LeaderStatConnections,
|
|
player.ChildAdded:connect(
|
|
function(child)
|
|
if child.Name == "leaderstats" then
|
|
--Connections will be torn down
|
|
recreatePlayerFunction(player)
|
|
else
|
|
table.insert(playerTable[player].LeaderStatConnections,
|
|
child.Changed:connect(
|
|
function(prop)
|
|
if prop == "Name" and child.Name == "leaderstats" then
|
|
--Connections will be torn down
|
|
recreatePlayerFunction(player)
|
|
end
|
|
end))
|
|
end
|
|
end))
|
|
else
|
|
--We have a leaderstats, but not enough children, recreate if we get them
|
|
table.insert(playerTable[player].LeaderStatConnections,
|
|
leaderstats.ChildAdded:connect(
|
|
function(child)
|
|
--TODO only look for IntValue
|
|
recreatePlayerFunction(player)
|
|
end)
|
|
)
|
|
table.insert(playerTable[player].LeaderStatConnections,
|
|
leaderstats.AncestryChanged:connect(
|
|
function(child)
|
|
--We got deleted, try again
|
|
recreatePlayerFunction(player)
|
|
end)
|
|
)
|
|
end
|
|
end
|
|
if statValues then
|
|
if not playerTable[player].StatValues then
|
|
playerTable[player].StatValues = {}
|
|
end
|
|
local pos = 1
|
|
while pos <= numStatColumns and pos <= #statValues do
|
|
local currentColumn = pos
|
|
local statValue = statValues[pos]
|
|
local statChanger = textChangers[pos]
|
|
|
|
local updateStat = function(val)
|
|
statChanger(val)
|
|
if playerTable[player] ~= nil then recomputeTeamScore(playerTable[player].CurrentTeam, currentColumn) end
|
|
end
|
|
if pos > #playerTable[player].StatValues then
|
|
table.insert(playerTable[player].StatValues, statValue)
|
|
end
|
|
|
|
if type(statValue) ~= "number" and statValue["Changed"] then
|
|
table.insert(playerTable[player].Connections,
|
|
statValue.Changed:connect(updateStat)
|
|
)
|
|
end
|
|
|
|
table.insert(playerTable[player].Connections,
|
|
statValue.AncestryChanged:connect(
|
|
function()
|
|
recreatePlayerFunction(player)
|
|
end)
|
|
)
|
|
updateStat(statValue.Value)
|
|
pos = pos + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
if supportFriends and player ~= game.Players.LocalPlayer and player.userId > 0 and game.Players.LocalPlayer.userId > 0 then
|
|
local button = Instance.new("TextButton")
|
|
button.Name = playerObject.Name .. "Button"
|
|
button.Text = ""
|
|
button.Active = false
|
|
button.Size = playerObject.Size
|
|
button.Position = playerObject.Position
|
|
button.BackgroundColor3 = playerObject.BackgroundColor3
|
|
|
|
local secondButton = Instance.new("TextButton")
|
|
secondButton.Name = playerObject.Name .. "RealButton"
|
|
secondButton.Text = ""
|
|
secondButton.BackgroundTransparency = 1
|
|
secondButton.BackgroundColor3 = playerObject.BackgroundColor3
|
|
local theNameLabel = playerObject:findFirstChild("NameLabel",true)
|
|
if theNameLabel then
|
|
theNameLabel.TextColor3 = Color3.new(1,1,1)
|
|
secondButton.Parent = theNameLabel
|
|
end
|
|
secondButton.Parent.BackgroundTransparency = 1
|
|
secondButton.Parent.Visible = true
|
|
secondButton.ZIndex = 2
|
|
secondButton.Size = UDim2.new(1,0,1,0)
|
|
|
|
local previousTransparency = nil
|
|
table.insert(playerTable[player].Connections,
|
|
secondButton.MouseEnter:connect(
|
|
function(x,y)
|
|
if playerContextMenu and playerContextMenu.Visible then
|
|
return
|
|
end -- don't update if we currently see it
|
|
|
|
updatePlayerContextMenu(player,x,y)
|
|
if not playerContextMenuHasItems() then return end -- don't show if we have nothing to show
|
|
|
|
if previousTransparency == nil then
|
|
previousTransparency = secondButton.BackgroundTransparency
|
|
end
|
|
secondButton.Parent.BackgroundTransparency = 0
|
|
end))
|
|
table.insert(playerTable[player].Connections,
|
|
secondButton.MouseLeave:connect(
|
|
function()
|
|
if previousTransparency ~= nil then
|
|
previousTransparency = nil
|
|
end
|
|
delay(0.01,function()
|
|
if playerContextMenu and not inContextMenu then
|
|
playerContextMenu.Visible = false
|
|
end
|
|
end)
|
|
secondButton.Parent.BackgroundTransparency = 1
|
|
end))
|
|
|
|
local mouseDownX, mouseDownY
|
|
table.insert(playerTable[player].Connections,
|
|
secondButton.MouseButton1Down:connect(function(x,y)
|
|
mouseDownX = x
|
|
mouseDownY = y
|
|
end))
|
|
table.insert(playerTable[player].Connections,
|
|
secondButton.MouseButton1Click:connect(function()
|
|
showPlayerMenu(player, mouseDownX, secondButton.AbsolutePosition.Y + secondButton.AbsoluteSize.Y )
|
|
end))
|
|
playerObject.BackgroundTransparency = 1
|
|
playerObject.Size = UDim2.new(1,0,1,0)
|
|
playerObject.Position = UDim2.new(0,0,0,0)
|
|
playerObject.Parent = button
|
|
|
|
playerTable[player]["MainObject" .. suffix] = button
|
|
|
|
playerObject = button
|
|
else
|
|
playerTable[player]["MainObject" .. suffix] = playerObject
|
|
|
|
if player == game.Players.LocalPlayer and supportFriends then
|
|
table.insert(playerTable[player].Connections,
|
|
player.FriendStatusChanged:connect(
|
|
function(otherPlayer, friendStatus)
|
|
if friendRequestBlacklist[otherPlayer] then
|
|
updatePlayerFriendStatus(playerTable[otherPlayer]["NameObject" .. suffix], Enum.FriendStatus.NotFriend)
|
|
elseif playerTable[otherPlayer] then
|
|
updatePlayerFriendStatus(playerTable[otherPlayer]["NameObject" .. suffix], friendStatus)
|
|
end
|
|
end)
|
|
)
|
|
end
|
|
end
|
|
table.insert(playerTable[player].Connections,
|
|
player.Changed:connect(
|
|
function(prop)
|
|
if prop == "MembershipType" then
|
|
updatePlayerName(playerTable[player]["NameObject" .. suffix], player.MembershipType, currentColor)
|
|
elseif prop == "Name" then
|
|
playerTable[player]["ChangeName" .. suffix](player.Name)
|
|
elseif prop == "Neutral" or prop == "TeamColor" then
|
|
assignToTeam(player)
|
|
end
|
|
end)
|
|
)
|
|
return playerObject
|
|
end
|
|
|
|
local function doSort(tableToSort, objectName, order, startPos, sortType, ascending)
|
|
local orderedPlayerTable = {}
|
|
getLocalPlayer = false
|
|
for i, player in ipairs(tableToSort) do
|
|
if playerTable[player] then
|
|
if playerTable[player][objectName] ~= nil then
|
|
if player ~= game.Players.LocalPlayer then
|
|
table.insert(orderedPlayerTable,playerTable[player][objectName])
|
|
else
|
|
getLocalPlayer = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if sortType == nil then -- default back to alphabetical sort
|
|
table.sort(orderedPlayerTable,function(a,b)
|
|
return string.lower(a:FindFirstChild("FullNameLabel",true).Text) < string.lower(b:FindFirstChild("FullNameLabel",true).Text)
|
|
end)
|
|
else -- we are sorting by a value
|
|
table.sort(orderedPlayerTable,function(a,b)
|
|
if ascending then
|
|
currentSortName = ""
|
|
return tonumber(a:FindFirstChild(sortType,true).Text) > tonumber(b:FindFirstChild(sortType,true).Text)
|
|
else
|
|
currentSortName = sortType
|
|
return tonumber(a:FindFirstChild(sortType,true).Text) < tonumber(b:FindFirstChild(sortType,true).Text)
|
|
end
|
|
end)
|
|
end
|
|
if getLocalPlayer and playerTable[game.Players.LocalPlayer] and playerTable[game.Players.LocalPlayer][objectName] then
|
|
table.insert(orderedPlayerTable,1,playerTable[game.Players.LocalPlayer][objectName])
|
|
end
|
|
for i = 1, #orderedPlayerTable do
|
|
order[orderedPlayerTable[i]] = startPos
|
|
startPos = startPos + 1
|
|
end
|
|
|
|
return startPos
|
|
end
|
|
|
|
local function orderScrollList(scrollOrder, objectName, scrollFrame, sortType, ascending)
|
|
local pos = 0
|
|
local order = {}
|
|
local isTeam, isScore = getBoardTypeInfo()
|
|
for i, obj in ipairs(scrollOrder) do
|
|
order[obj] = 0
|
|
end
|
|
|
|
if isTeam then
|
|
local teams = getTeams()
|
|
for i, team in ipairs(teams) do
|
|
if teamTable[team][objectName] then
|
|
order[teamTable[team][objectName]] = pos
|
|
pos = pos + 1
|
|
end
|
|
pos = doSort(teamTable[team].Players, objectName, order, pos, sortType, ascending)
|
|
end
|
|
|
|
if #teamTable["Neutral"].Players > 0 then
|
|
teamTable["Neutral"][objectName].Parent = scrollFrame
|
|
order[teamTable["Neutral"][objectName]] = pos
|
|
pos = pos + 1
|
|
doSort(teamTable["Neutral"].Players, objectName, order, pos, sortType, ascending)
|
|
else
|
|
teamTable["Neutral"][objectName].Parent = nil
|
|
end
|
|
else
|
|
local players = getPlayers()
|
|
doSort(players, objectName, order, pos, sortType, ascending)
|
|
end
|
|
|
|
table.sort(scrollOrder,
|
|
function(a,b)
|
|
return order[a] < order[b]
|
|
end)
|
|
end
|
|
|
|
local function createPlayerListBasics(frame, isBig)
|
|
local headerFrame = Instance.new("Frame")
|
|
headerFrame.Name = "Header"
|
|
headerFrame.BackgroundTransparency = 1
|
|
headerFrame.Size = UDim2.new(1,-13,0,26)
|
|
headerFrame.Position = UDim2.new(0,0,0,0)
|
|
headerFrame.Parent = frame
|
|
|
|
local lowerPaneFrame = Instance.new("Frame")
|
|
lowerPaneFrame.Name = "ScrollingArea"
|
|
lowerPaneFrame.BackgroundTransparency = 1
|
|
lowerPaneFrame.Size = UDim2.new(1,-3,1,-26)
|
|
if not isBig then lowerPaneFrame.Size = UDim2.new(1,-3,1,-30) end
|
|
lowerPaneFrame.Position = UDim2.new(0,0,0,26)
|
|
lowerPaneFrame.Parent = frame
|
|
|
|
local scrollOrder = {}
|
|
local scrollFrame, scrollUp, scrollDown, recalculateScroll, scrollBar = RbxGui.CreateScrollingFrame(scrollOrder)
|
|
|
|
scrollBar.Size = UDim2.new(0, 17, 1, -36)
|
|
if isBig then scrollBar.Size = UDim2.new(0, 17, 1, -61) end
|
|
scrollBar.Parent = lowerPaneFrame
|
|
|
|
scrollFrame.Parent = lowerPaneFrame
|
|
scrollUp.Parent = lowerPaneFrame
|
|
scrollDown.Parent = lowerPaneFrame
|
|
|
|
if isBig then
|
|
scrollFrame.Position = UDim2.new(0,0,0,0)
|
|
scrollUp.Position = UDim2.new(1,-41,0,5)
|
|
scrollDown.Position = UDim2.new(1,-41,1,-35)
|
|
scrollBar.Position = UDim2.new(1, -41, 0, 24)
|
|
|
|
scrollFrame.Size = UDim2.new(1,-48,1,-16)
|
|
headerFrame.Size = UDim2.new(1,-20,0,26)
|
|
|
|
else
|
|
scrollBar.Position = UDim2.new(1, -15, 0, 14)
|
|
scrollBar.Size = UDim2.new(0,17,1,-36)
|
|
scrollFrame.Position = UDim2.new(0,1,0,0)
|
|
scrollUp.Position = UDim2.new(1,-15,0,-5)
|
|
scrollDown.Position = UDim2.new(1,-15,1,-20)
|
|
|
|
lowerPaneFrame.Position = UDim2.new(0,0,0,30)
|
|
|
|
local toggleScrollBar = function(visible)
|
|
if visible then
|
|
scrollFrame.Size = UDim2.new(1,-16,1,0)
|
|
headerFrame.Size = UDim2.new(1,-16,0,smallWindowHeaderYSize)
|
|
else
|
|
scrollFrame.Size = UDim2.new(1,0,1,0)
|
|
headerFrame.Size = UDim2.new(1,0,0,smallWindowHeaderYSize)
|
|
end
|
|
scrollUp.Visible = visible
|
|
scrollDown.Visible = visible
|
|
scrollBar.Visible = visible
|
|
end
|
|
scrollUp.Changed:connect(function(prop)
|
|
if prop == "Active" then
|
|
toggleScrollBar(scrollUp.Active or scrollDown.Active)
|
|
end
|
|
end)
|
|
|
|
scrollDown.Changed:connect(function(prop)
|
|
if prop == "Active" then
|
|
toggleScrollBar(scrollUp.Active or scrollDown.Active)
|
|
end
|
|
end)
|
|
|
|
toggleScrollBar(scrollUp.Active or scrollDown.Active)
|
|
end
|
|
return headerFrame, scrollFrame, recalculateScroll, scrollOrder
|
|
end
|
|
|
|
createBoardsFunction = function (boardType, numStatColumns)
|
|
local updatePlayerCount = function()
|
|
return #getPlayers()
|
|
end
|
|
|
|
local smallFrame = Instance.new("Frame")
|
|
smallFrame.Name = "SmallPlayerlist"
|
|
smallFrame.Position = smallWindowPosition
|
|
smallFrame.Active = false
|
|
smallFrame.Size = smallWindowSize
|
|
smallFrame.BackgroundColor3 = Color3.new(0,0,0)
|
|
smallFrame.BackgroundTransparency = 0.7
|
|
smallFrame.BorderSizePixel = 0
|
|
|
|
local bigFrame = Instance.new("Frame")
|
|
bigFrame.Name = "BigPlayerlist"
|
|
bigFrame.Size = bigWindowSize
|
|
bigFrame.Position = bigWindowPosition
|
|
bigFrame.BackgroundColor3 = Color3.new(0,0,0)
|
|
bigFrame.BackgroundTransparency = 0.7
|
|
bigFrame.BorderSizePixel = 0
|
|
bigFrame.Visible = false
|
|
|
|
local bigFrameWrapper = Instance.new("Frame")
|
|
bigFrameWrapper.Name = "Expander"
|
|
bigFrameWrapper.Size = UDim2.new(1,21,1,16)
|
|
bigFrameWrapper.Position = UDim2.new(0, 0, 0,0)
|
|
bigFrameWrapper.BackgroundTransparency = 1
|
|
bigFrameWrapper.Parent = bigFrame
|
|
|
|
local smallHeaderFrame, scrollFrameSmall, recalculateScrollSmall, scrollOrderSmall = createPlayerListBasics(smallFrame, false)
|
|
local bigHeaderFrame, scrollFrameBig, recalculateScrollBig, scrollOrderBig = createPlayerListBasics(bigFrameWrapper, true)
|
|
|
|
local playerListButton = Instance.new("ImageButton")
|
|
playerListButton.Name = "GoBigButton"
|
|
playerListButton.BackgroundTransparency = 1
|
|
playerListButton.Image = "rbxasset://textures/ui/playerlist_small_maximize.png"
|
|
playerListButton.Size = UDim2.new(0.0, 35, 0, 29)
|
|
playerListButton.Position = UDim2.new(0, 0, 0, 0)
|
|
playerListButton.MouseButton1Click:connect(
|
|
function()
|
|
toggleBigWindow()
|
|
end)
|
|
playerListButton.Parent = smallHeaderFrame
|
|
|
|
playerListButton = Instance.new("ImageButton")
|
|
playerListButton.Name = "CloseButton"
|
|
playerListButton.BackgroundTransparency = 1
|
|
playerListButton.Image = "rbxasset://textures/ui/playerlist_small_hide.png"
|
|
playerListButton.Size = UDim2.new(0.0, 38, 0, 29)
|
|
playerListButton.Position = UDim2.new(0, 35, 0, 0)
|
|
playerListButton.MouseButton1Click:connect(
|
|
function()
|
|
transitionWindowsFunction("None")
|
|
end)
|
|
playerListButton.Parent = smallHeaderFrame
|
|
|
|
playerListButton = Instance.new("ImageButton")
|
|
playerListButton.Name = "CloseButton"
|
|
playerListButton.Image = "rbxasset://textures/ui/playerlist_big_hide.png"
|
|
playerListButton.BackgroundTransparency = 1
|
|
playerListButton.Size = UDim2.new(0.0, 29, 0, 29)
|
|
playerListButton.Position = UDim2.new(1, -30, 0.5, -13)
|
|
playerListButton.MouseButton1Click:connect(
|
|
function()
|
|
toggleBigWindow()
|
|
end)
|
|
playerListButton.Parent = bigHeaderFrame
|
|
|
|
local placeName = Instance.new("TextButton")
|
|
placeName.Name = "PlaceName"
|
|
placeName.Text = " Players (" .. tostring(updatePlayerCount()) .. ")"
|
|
placeName.AutoButtonColor = false
|
|
placeName.FontSize = Enum.FontSize.Size24
|
|
placeName.TextXAlignment = Enum.TextXAlignment.Left
|
|
placeName.Font = Enum.Font.ArialBold
|
|
placeName.BorderSizePixel = 0
|
|
placeName.BackgroundColor3 = Color3.new(0,0,0)
|
|
placeName.BackgroundTransparency = 1
|
|
placeName.TextColor3 = Color3.new(1,1,1)
|
|
placeName.Size = UDim2.new(0.4, 0, 1, 0)
|
|
placeName.Position = UDim2.new(0, 0, 0.0, 0)
|
|
placeName = RbxGui.AutoTruncateTextObject(placeName)
|
|
placeName.Parent = bigHeaderFrame
|
|
|
|
placeName.MouseEnter:connect(function()
|
|
placeName.BackgroundTransparency = 0.2
|
|
end)
|
|
|
|
placeName.MouseLeave:connect(function()
|
|
placeName.BackgroundTransparency = 1
|
|
end)
|
|
|
|
placeName.MouseButton1Click:connect(function()
|
|
sortPlayerListsFunction()
|
|
end)
|
|
|
|
currentBoardType = boardType
|
|
currentStatCount = numStatColumns
|
|
local isTeam, isScore = getBoardTypeInfo()
|
|
local players = getPlayers()
|
|
|
|
if isScore then
|
|
local statColumns = getStatColumns(players)
|
|
numStatColumns = #statColumns
|
|
if numStatColumns > 3 then
|
|
numStatColumns = 3
|
|
end
|
|
createStatHeaders(statColumns, numStatColumns, false).Parent = smallHeaderFrame
|
|
createStatHeaders(statColumns, currentStatCount, true).Parent = bigHeaderFrame
|
|
end
|
|
|
|
--Clean up all old stuff
|
|
resetPlayerTable()
|
|
updatePlayerCount()
|
|
|
|
for i, player in ipairs(players) do
|
|
local playerObject = buildPlayerObject(player, numStatColumns, "Small")
|
|
table.insert(scrollOrderSmall, playerObject)
|
|
playerObject.Parent = scrollFrameSmall
|
|
|
|
playerObject = buildPlayerObject(player, currentStatCount, "Big")
|
|
table.insert(scrollOrderBig, playerObject)
|
|
playerObject.Parent = scrollFrameBig
|
|
end
|
|
|
|
--Clean up old stuff
|
|
resetTeamTable()
|
|
|
|
local teamStatObjects = {}
|
|
if isTeam then
|
|
local teams = getTeams()
|
|
local i = #teams
|
|
while i >= 1 do
|
|
--We go backwards so the "first" team color gets the team
|
|
local team = teams[i]
|
|
teamColorTable[team.TeamColor.Name] = team
|
|
i = i - 1
|
|
end
|
|
|
|
--Adding/Removing a Team causes a full invalidation of the board
|
|
for i, team in ipairs(teams) do
|
|
local teamObject = buildTeamObject(team, numStatColumns, "Small")
|
|
table.insert(scrollOrderSmall, teamObject)
|
|
teamObject.Parent = scrollFrameSmall
|
|
|
|
teamObject = buildTeamObject(team, currentStatCount, "Big")
|
|
table.insert(scrollOrderBig, teamObject)
|
|
teamObject.Parent = scrollFrameBig
|
|
end
|
|
|
|
teamTable["Neutral"] = {}
|
|
teamTable["Neutral"].Players = {}
|
|
|
|
local neutralTeamObject = createTeamName("Neutral", BrickColor.palette(8))
|
|
teamTable["Neutral"].NameObjectSmall = neutralTeamObject
|
|
teamTable["Neutral"].StatObjectSmall = nil
|
|
teamTable["Neutral"].MainObjectSmall = neutralTeamObject
|
|
table.insert(scrollOrderSmall, neutralTeamObject)
|
|
|
|
neutralTeamObject = createTeamName("Neutral", BrickColor.palette(8))
|
|
teamTable["Neutral"].NameObjectBig = neutralTeamObject
|
|
teamTable["Neutral"].StatObjectBig = nil
|
|
teamTable["Neutral"].MainObjectBig = neutralTeamObject
|
|
table.insert(scrollOrderBig, neutralTeamObject)
|
|
|
|
local neutralPlayers = {}
|
|
for i, player in ipairs(players) do
|
|
assignToTeam(player)
|
|
end
|
|
end
|
|
|
|
removePlayerFunction = function(player)
|
|
if playerTable[player] then
|
|
clearTableEntry(player, playerTable[player])
|
|
|
|
placeName.Text = " Players (" .. tostring(updatePlayerCount()) .. ")"
|
|
|
|
ArrayRemove(scrollOrderSmall, playerTable[player].MainObjectSmall)
|
|
ArrayRemove(scrollOrderBig, playerTable[player].MainObjectBig)
|
|
|
|
playerTable[player] = nil
|
|
recalculateSmallPlayerListSize(smallFrame)
|
|
end
|
|
end
|
|
recreatePlayerFunction = function(player)
|
|
placeName.Text = " Players (" .. tostring(updatePlayerCount()) .. ")"
|
|
|
|
removePlayerFunction(player)
|
|
|
|
local playerObject = buildPlayerObject(player, numStatColumns, "Small")
|
|
table.insert(scrollOrderSmall, playerObject)
|
|
robloxLock(playerObject)
|
|
playerObject.Parent = scrollFrameSmall
|
|
|
|
playerObject = buildPlayerObject(player, currentStatCount, "Big")
|
|
table.insert(scrollOrderBig, playerObject)
|
|
robloxLock(playerObject)
|
|
playerObject.Parent = scrollFrameBig
|
|
|
|
local isTeam, isScore = getBoardTypeInfo()
|
|
if isTeam then
|
|
assignToTeam(player)
|
|
end
|
|
|
|
sortPlayerListsFunction()
|
|
recalculateSmallPlayerListSize(smallFrame)
|
|
end
|
|
|
|
if screenResizeCon then screenResizeCon:disconnect() end
|
|
screenResizeCon = screen.Changed:connect(
|
|
function(prop)
|
|
if prop == "AbsoluteSize" then
|
|
wait()
|
|
recalculateSmallPlayerListSize(smallFrame)
|
|
end
|
|
end)
|
|
|
|
sortPlayerListsFunction = function(sortType, ascending)
|
|
orderScrollList(scrollOrderSmall, "MainObjectSmall", scrollFrameSmall, sortType, ascending)
|
|
recalculateScrollSmall()
|
|
createAlternatingRows(scrollOrderSmall)
|
|
|
|
orderScrollList(scrollOrderBig, "MainObjectBig", scrollFrameBig, sortType, ascending)
|
|
recalculateScrollBig()
|
|
createAlternatingRows(scrollOrderBig)
|
|
end
|
|
|
|
sortPlayerListsFunction()
|
|
|
|
robloxLock(smallFrame)
|
|
robloxLock(bigFrame)
|
|
return smallFrame, bigFrame
|
|
end
|
|
|
|
--Teams changing invalidates the whole board
|
|
local function teamsChanged()
|
|
if debounceTeamsChanged then
|
|
return
|
|
end
|
|
|
|
debounceTeamsChanged = true
|
|
wait()
|
|
rebuildBoard(script.Parent, determineBoardType())
|
|
debounceTeamsChanged = false
|
|
end
|
|
|
|
|
|
local checkIfBoardChanged = function()
|
|
local newBoardType, numStats = determineBoardType()
|
|
if newBoardType ~= currentBoardType or numStats ~= currentStatCount then
|
|
rebuildBoard(script.Parent, newBoardType, numStats)
|
|
end
|
|
end
|
|
|
|
local function buildPlayerList()
|
|
waitForChild(game, "Players")
|
|
waitForProperty(game.Players, "LocalPlayer")
|
|
|
|
local teams = game:GetService("Teams")
|
|
if teams then
|
|
local teamConnections = {}
|
|
|
|
teams.ChildAdded:connect(
|
|
function(child)
|
|
if child:IsA("Team") then
|
|
teamsChanged()
|
|
teamConnections[child] = child.Changed:connect(
|
|
function(prop)
|
|
if prop == "TeamColor" or prop == "Name" then
|
|
--Rebuild when things change
|
|
teamsChanged()
|
|
end
|
|
end)
|
|
end
|
|
end)
|
|
teams.ChildRemoved:connect(
|
|
function(child)
|
|
if child:IsA("Team") then
|
|
if teamConnections[child] then
|
|
teamConnections[child]:disconnect()
|
|
teamConnections[child] = nil
|
|
end
|
|
teamsChanged()
|
|
end
|
|
end)
|
|
end
|
|
|
|
game.Players.ChildAdded:connect(
|
|
function(player)
|
|
if player:IsA("Player") then
|
|
addPlayerFunction(player)
|
|
end
|
|
end)
|
|
|
|
game.Players.ChildRemoved:connect(
|
|
function(player)
|
|
if player:IsA("Player") then
|
|
if removePlayerFunction then
|
|
removePlayerFunction(player)
|
|
end
|
|
end
|
|
end)
|
|
|
|
rebuildBoard(script.Parent, determineBoardType())
|
|
game.GuiService.ShowLegacyPlayerList = false
|
|
|
|
game.GuiService:AddKey("\t")
|
|
local lastTime = nil
|
|
game.GuiService.KeyPressed:connect(
|
|
function(key)
|
|
if key == "\t" then
|
|
local modalCheck, isModal = pcall(function() return game.GuiService.IsModalDialog end)
|
|
if modalCheck == false or (modalCheck and isModal == false) then
|
|
local currentTime = time()
|
|
if lastTime == nil or currentTime - lastTime > 0.4 then
|
|
lastTime = currentTime
|
|
toggleBigWindow()
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|
|
delay(0,
|
|
function()
|
|
while true do
|
|
wait(5)
|
|
checkIfBoardChanged()
|
|
end
|
|
end)
|
|
end
|
|
|
|
if game.CoreGui.Version >= 2 then
|
|
buildPlayerList()
|
|
end
|
|
end
|
|
|
|
if not personalServerPlace then -- one more backup check
|
|
local theBool = game.Workspace:FindFirstChild("PSVariable")
|
|
if theBool and theBool:IsA("BoolValue") then
|
|
personalServerPlace = true
|
|
end
|
|
end
|
|
|
|
if personalServerPlace then
|
|
addPersonalServerContext()
|
|
setupBuildToolManagement()
|
|
else
|
|
local psVarCon = nil
|
|
psVarCon = game.Workspace.ChildAdded:connect(function(child)
|
|
if child:IsA("BoolValue") and child.Name == "PSVariable" then
|
|
psVarCon:disconnect()
|
|
personalServerPlace = true
|
|
addPersonalServerContext()
|
|
setupBuildToolManagement()
|
|
end
|
|
end)
|
|
end
|
|
|
|
|
|
---------------------------------- Start Player Hover Code ----------------------------------------
|
|
if contextMenu3d then
|
|
local inMenu = false
|
|
|
|
function waitForProperty(instance, name)
|
|
while not instance[name] do
|
|
instance.Changed:wait()
|
|
end
|
|
end
|
|
|
|
function makeNewActionButton()
|
|
local button = Instance.new("TextButton")
|
|
button.Name = "ActionButton"
|
|
button.Style = Enum.ButtonStyle.RobloxButtonDefault
|
|
button.BackgroundColor3 = Color3.new(0,0,0)
|
|
button.BorderColor3 = Color3.new(1,0,0)
|
|
button.BackgroundTransparency = 0.5
|
|
button.Size = UDim2.new(1,0,0,50)
|
|
button.Text = ""
|
|
button.Font = Enum.Font.ArialBold
|
|
button.FontSize = Enum.FontSize.Size18
|
|
button.TextColor3 = Color3.new(1,1,1)
|
|
button.ZIndex = 4
|
|
return button
|
|
end
|
|
|
|
function getContextElements(currentContextMenuPlayer)
|
|
local elements = {}
|
|
for i, contextElement in ipairs(contextMenuElements) do
|
|
local element = contextElement
|
|
|
|
local isVisible = false
|
|
|
|
if contextElement.IsVisible then
|
|
local success, visible = pcall(function() return contextElement.IsVisible(currentContextMenuPlayer) end)
|
|
if success then
|
|
isVisible = visible
|
|
else
|
|
print("Error in IsVisible call: " .. visible)
|
|
end
|
|
end
|
|
|
|
if element.Type == "Button" then
|
|
local button = makeNewActionButton()
|
|
button.Name = "ContextButton" .. i
|
|
button.Visible = isVisible
|
|
button.Text = contextElement.Text
|
|
button.MouseButton1Click:connect(function()
|
|
if button.Active then
|
|
local success, result = pcall(function() element.DoIt(currentContextMenuPlayer) end)
|
|
end
|
|
end)
|
|
|
|
contextElement.Button = button
|
|
contextElement.Element = button
|
|
|
|
table.insert(elements,contextElement)
|
|
end
|
|
end
|
|
|
|
return elements
|
|
end
|
|
|
|
function findContextElement(contextElements, button)
|
|
for i = 1, #contextElements do
|
|
if contextElements[i].Button == button then
|
|
return contextElements[i]
|
|
end
|
|
end
|
|
end
|
|
|
|
function populateActions(scrollFrame, nullFrame, recalcFunction, otherPlayer)
|
|
local elements = getContextElements(otherPlayer)
|
|
for i = 1, #elements do
|
|
if elements[i].Button.Visible then
|
|
elements[i].Button.Parent = scrollFrame
|
|
else
|
|
elements[i].Button.Parent = nullFrame
|
|
end
|
|
|
|
local actionButtonCon
|
|
actionButtonCon = elements[i].Button.MouseButton1Click:connect(function()
|
|
actionButtonCon:disconnect()
|
|
|
|
local nullFrameChildren = nullFrame:GetChildren()
|
|
for j = 1, #nullFrameChildren do
|
|
local contextElement = findContextElement(elements, nullFrameChildren[j])
|
|
pcall(function() nullFrameChildren[j].Visible = contextElement.IsVisible(otherPlayer) end)
|
|
if nullFrameChildren[j].Visible then
|
|
nullFrameChildren[j].Parent = scrollFrame
|
|
end
|
|
end
|
|
|
|
local scrollFrameChildren = scrollFrame:GetChildren()
|
|
for j = 1, #scrollFrameChildren do
|
|
local contextElement = findContextElement(elements, scrollFrameChildren[j])
|
|
pcall(function() scrollFrameChildren[j].Visible = contextElement.IsVisible(otherPlayer) end)
|
|
if not scrollFrameChildren[j].Visible then
|
|
scrollFrameChildren[j].Parent = nullFrame
|
|
end
|
|
end
|
|
|
|
elements[i].Button.Parent = nullFrame
|
|
recalcFunction()
|
|
end)
|
|
end
|
|
end
|
|
|
|
|
|
function createContextMenu(otherPlayer)
|
|
|
|
local frame = Instance.new("Frame")
|
|
frame.Name = "ContextMenuFrame"
|
|
frame.Style = Enum.FrameStyle.RobloxRound
|
|
frame.Size = UDim2.new(0,300,0,400)
|
|
frame.Position = UDim2.new(0.5,-150,0.5,-200)
|
|
frame.ZIndex = 2
|
|
|
|
local scrollFrame, scrollUpButton, scrollDownButton, recalc, scrollBar = RbxGui.CreateScrollingFrame()
|
|
|
|
scrollFrame.Name = "Actions"
|
|
scrollFrame.BackgroundTransparency = 1
|
|
scrollFrame.Position = UDim2.new(0,0,0,25)
|
|
scrollFrame.Size = UDim2.new(1,-20,1,-80)
|
|
scrollFrame.ZIndex = 3
|
|
scrollFrame.Parent = frame
|
|
|
|
local nullFrame = Instance.new("Frame")
|
|
nullFrame.Name = "NullFrame"
|
|
nullFrame.BackgroundTransparency = 1
|
|
nullFrame.Visible = false
|
|
nullFrame.Parent = frame
|
|
|
|
local scrollButtons = Instance.new("Frame")
|
|
scrollButtons.Name = "ScrollButtons"
|
|
scrollButtons.BackgroundTransparency = 1
|
|
scrollButtons.Position = UDim2.new(1,-17,0,25)
|
|
scrollButtons.Size = UDim2.new(0,17,1,-80)
|
|
scrollButtons.ZIndex = 3
|
|
scrollButtons.Parent = frame
|
|
|
|
scrollUpButton.ZIndex = 3
|
|
scrollUpButton.Parent = scrollButtons
|
|
scrollDownButton.Position = UDim2.new(0,0,1,-17)
|
|
scrollDownButton.ZIndex = 3
|
|
scrollDownButton.Parent = scrollButtons
|
|
|
|
scrollBar.Size = UDim2.new(1,0,1,-34)
|
|
scrollBar.Position = UDim2.new(0,0,0,17)
|
|
scrollBar.Parent = scrollButtons
|
|
|
|
local playerImage = Instance.new("ImageLabel")
|
|
playerImage.Name = "PlayerImage"
|
|
playerImage.BackgroundTransparency = 1
|
|
playerImage.Image = "http://www.roblox.com/thumbs/avatar.ashx?userId=" .. tostring(otherPlayer.userId) .. "&x=352&y=352"
|
|
playerImage.Position = UDim2.new(0.5,-150,0.5,-150)
|
|
playerImage.Size = UDim2.new(0,300,0,300)
|
|
playerImage.Parent = frame
|
|
|
|
local playerName = Instance.new("TextLabel")
|
|
playerName.Name = "PlayerName"
|
|
playerName.BackgroundTransparency = 1
|
|
playerName.Font = Enum.Font.ArialBold
|
|
playerName.FontSize = Enum.FontSize.Size24
|
|
playerName.Position = UDim2.new(0,-8,0,-6)
|
|
playerName.Size = UDim2.new(1,16,0,24)
|
|
playerName.Text = otherPlayer["Name"]
|
|
playerName.TextColor3 = Color3.new(1,1,1)
|
|
playerName.TextWrap = true
|
|
playerName.ZIndex = 3
|
|
playerName.Parent = frame
|
|
|
|
local doneButtonCon
|
|
|
|
local doneButton = Instance.new("TextButton")
|
|
doneButton.Name = "DoneButton"
|
|
doneButton.Style = Enum.ButtonStyle.RobloxButton
|
|
doneButton.Font = Enum.Font.ArialBold
|
|
doneButton.FontSize = Enum.FontSize.Size36
|
|
doneButton.Position = UDim2.new(0.25,0,1,-50)
|
|
doneButton.Size = UDim2.new(0.5,0,0,50)
|
|
doneButton.Text = "Done"
|
|
doneButton.TextColor3 = Color3.new(1,1,1)
|
|
doneButton.ZIndex = 3
|
|
doneButton.Parent = frame
|
|
doneButton.Modal = true
|
|
doneButtonCon = doneButton.MouseButton1Click:connect(function()
|
|
doneButtonCon:disconnect()
|
|
inMenu = false
|
|
game.GuiService:RemoveCenterDialog(frame)
|
|
frame:remove()
|
|
end)
|
|
|
|
populateActions(scrollFrame, nullFrame, recalc, otherPlayer)
|
|
recalc()
|
|
|
|
return frame
|
|
end
|
|
|
|
function makeContextInvisible(menu)
|
|
menu.Visible = false
|
|
end
|
|
|
|
function goToContextMenu(otherPlayer)
|
|
|
|
local menu = createContextMenu(otherPlayer)
|
|
|
|
game.GuiService:AddCenterDialog(menu, Enum.CenterDialogType.PlayerInitiatedDialog,
|
|
--ShowFunction
|
|
function()
|
|
menu.Visible = true
|
|
menu:TweenSize(UDim2.new(0,300,0,400),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,0.5,true)
|
|
end,
|
|
--HideFunction
|
|
function()
|
|
menu:TweenSize(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,0.5,true,function() makeContextInvisible(menu) end)
|
|
end)
|
|
menu.Parent = game.CoreGui.RobloxGui
|
|
|
|
inMenu = true
|
|
end
|
|
|
|
waitForProperty(game.Players, "LocalPlayer")
|
|
|
|
local currSelectedPlayer = nil
|
|
if game.Players.LocalPlayer["HoverOnPlayerChanged"] then
|
|
game.Players.LocalPlayer.HoverOnPlayerChanged:connect(function(otherPlayer)
|
|
if not inMenu then
|
|
if otherPlayer and otherPlayer.userId < 0 then return end -- we don't want this for guests
|
|
end
|
|
wait(0.5)
|
|
currSelectedPlayer = otherPlayer
|
|
end)
|
|
end
|
|
|
|
if game.Players.LocalPlayer["MouseDownOnPlayer"] then
|
|
game.Players.LocalPlayer.MouseDownOnPlayer:connect(function(otherPlayer)
|
|
if currSelectedPlayer ~= otherPlayer then return end
|
|
if not inMenu and otherPlayer.userId > 0 then
|
|
goToContextMenu(otherPlayer)
|
|
end
|
|
end)
|
|
end
|
|
end
|
|
---------------------------------- End Player Hover Code ---------------------------------------- |