· 8 years ago · Dec 27, 2017, 02:16 AM
1local function WaitForChild(parent, instance)
2 while parent:FindFirstChild(instance) == nil do
3 wait()
4 end
5 return parent[instance]
6end
7
8-- Global vars -----
9--- CONSTANTS ----
10local FRAME_X_MARGIN_SIZE = 20
11local FRAME_Y_OFFSET = 160
12local PLAYER_LIST_START_Y_OFFSET = 43
13local PIXELS_Y_BETWEEN_PLAYER_ROWS = 20
14local PIXELS_X_BETWEEN_STAT_COLUMNS = 65
15local PLAYERS_X_PADDING_PIXELS = 10
16
17
18local DARK_FONT_COLOR = Color3.new(0, 0, 0)
19local LIGHT_FONT_COLOR = Color3.new(1, 1, 1)
20local TOGGLES = false
21
22local PlayersService = game.Players
23local MainGui = script.Parent
24local LeaderboardFrame = WaitForChild(MainGui, "LeaderboardFrame")
25local LeaderboardButton = WaitForChild(MainGui, 'LeaderboardButton')
26local TeamsService = game:GetService("Teams")
27local DebrisService = game:GetService("Debris")
28--local MyMouse = PlayersService.localPlayer:GetMouse()
29local PlayerFieldsList = {} -- This one stores all the fields to help in removal
30local Gui = {} -- Class, that contains functions to create various gui objects
31
32-- This variable tells us if atleast one team exists
33local TeamsExist = false
34-- In here we store a parallel representation of the leaderboard gui heirarchy in the data model
35local TeamFramesList = {}
36-- This table lets us index a TeamColor to the GUI for that team
37local TeamColorToTeamFrame = {}
38
39local StatTextLabel = Instance.new("TextLabel")
40StatTextLabel.Font = Enum.Font.Legacy
41StatTextLabel.FontSize = Enum.FontSize.Size10
42StatTextLabel.BackgroundTransparency = 1.0
43StatTextLabel.Size = UDim2.new(0, 0, 0, 0)
44StatTextLabel.TextXAlignment = Enum.TextXAlignment.Right
45StatTextLabel.ZIndex = 10
46StatTextLabel.TextColor3 = LIGHT_FONT_COLOR
47
48
49local PlayerTextLabel = Instance.new("TextLabel")
50PlayerTextLabel.BackgroundTransparency = 1.0
51PlayerTextLabel.Font = Enum.Font.Arial
52PlayerTextLabel.FontSize = Enum.FontSize.Size18
53PlayerTextLabel.Size = UDim2.new(0, 0, 0, 0)
54PlayerTextLabel.TextXAlignment = Enum.TextXAlignment.Left
55PlayerTextLabel.ZIndex = 10
56PlayerTextLabel.TextColor3 = LIGHT_FONT_COLOR
57
58
59-- For luminance calculation formula look at: http://en.wikipedia.org/wiki/Grayscale
60local function IsDark(color)
61 local cieLuminance = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b
62 return cieLuminance < 0.5
63end
64
65local function CreateTeamFrames()
66 local numberOfTeams = #TeamsService:GetTeams()
67 local sizeOfTeamFrame = math.min(1 / 3, 1 / numberOfTeams)
68 local templateFrame = LeaderboardFrame:FindFirstChild('TemplateFrame')
69 for teamNumber, team in pairs(TeamsService:GetTeams()) do
70 if templateFrame then
71 local newTeamFrame = templateFrame:Clone()
72 newTeamFrame.Name = team.Name
73 newTeamFrame.Visible = true
74 newTeamFrame.BackgroundColor3 = team.TeamColor.Color
75 newTeamFrame.Parent = LeaderboardFrame
76 newTeamFrame.Position = UDim2.new(sizeOfTeamFrame * (teamNumber - 1), FRAME_X_MARGIN_SIZE, 0, FRAME_Y_OFFSET)
77 -- This special case is needed because we math.min the size of the frame
78 if numberOfTeams == 1 then
79 newTeamFrame.Position = UDim2.new(0.25, 20, 0, 160)
80 sizeOfTeamFrame = 0.5
81 elseif numberOfTeams == 2 then
82 newTeamFrame.Position = UDim2.new((1 - (2 / 3)) / 2 + 1 / 3 * (teamNumber - 1), FRAME_X_MARGIN_SIZE, 0, FRAME_Y_OFFSET)
83 end
84 newTeamFrame.Size = UDim2.new(sizeOfTeamFrame, -2 * FRAME_X_MARGIN_SIZE, 0.5, 0)
85 if newTeamFrame:FindFirstChild('Team') then
86 newTeamFrame:FindFirstChild('Team').Text = team.Name
87 end
88 TeamColorToTeamFrame[team.TeamColor.Name] = newTeamFrame
89 end
90 end
91end
92
93local function CreateNeutralTeamFrame()
94 local templateFrame = LeaderboardFrame:FindFirstChild('TemplateFrame')
95 if templateFrame then
96 local newTeamFrame = templateFrame:Clone()
97 newTeamFrame.Name = "TeamlessFrame"
98 newTeamFrame.Visible = true
99 newTeamFrame.BackgroundColor3 = BrickColor.new("Black").Color
100 newTeamFrame.Parent = LeaderboardFrame
101 newTeamFrame.Position = UDim2.new(0.25, 0, 0, FRAME_Y_OFFSET)
102 newTeamFrame.Size = UDim2.new(1 / 2, 0, 0.7, 0)
103 if newTeamFrame:FindFirstChild('Team') then
104 newTeamFrame:FindFirstChild('Team').Text = "Scores"
105 end
106 end
107end
108
109--[[
110
111 // Here is the thing - if the Leaderboard frame is split into multiple frames
112 // we assume that each of those frames represent different teams and
113 // that they are positioned correctly
114]]
115
116local function MirrorTemplateFrame()
117 -- The team color thing is annoying, ideally I want the frames
118 -- to be named by the team names instead of ridiculous team color things
119 -- But in this case, the frames are named after the brick color string
120 local TeamFrames = LeaderboardFrame:GetChildren()
121 for i = 1, #TeamFrames do
122 if TeamFrames[i] then
123 TeamsExist = true
124 local t = {}
125 local CurrentTeamFrame = TeamFrames[i]
126 t[CurrentTeamFrame] = {}
127 local CurrentTeamElements = TeamFrames[i]:GetChildren()
128 for j = 1, #CurrentTeamElements do
129 table.insert(t[CurrentTeamFrame], CurrentTeamElements[j])
130 end
131 table.insert(TeamFramesList, t)
132 end
133 end
134end
135
136local function ClearLeaderboardFrame()
137 -- Clear the entire leaderboard so that we can repopulate it with new info
138 LeaderboardFrame:ClearAllChildren()
139 for _, t in pairs(TeamFramesList) do
140 for frame, children in pairs(t) do
141 frame.Parent = LeaderboardFrame
142 for i = 1, #children do
143 children[i].Parent = frame
144 end
145 frame.Parent = LeaderboardFrame
146 end
147 end
148end
149
150-- Currently we are clearing the leaderboard and recreating it so
151-- that it will stay up to date no matter what kinds of stat changes
152-- player joins/leaves occur
153local function PopulateLeaderboard()
154 -- First clear the leaderboard
155 if TeamsExist then
156 ClearLeaderboardFrame()
157 end
158
159 -- Add the labels for the stat columns
160 if PlayersService.LocalPlayer ~= nil then
161 for _, t in pairs(TeamFramesList) do
162 for frame, children in pairs(t) do
163 -- Update each teams scores by finding the team that corresponds to this frame
164 local frameTeamColor
165 for _, team in pairs(TeamsService:GetTeams()) do
166 if team.Name == frame.Name then
167 frameTeamColor = team.TeamColor
168 if frame:FindFirstChild('TeamScore') ~= nil then
169 frame:FindFirstChild('TeamScore').Text = team.Score
170 end
171 end
172 end
173 -- Get the leaderstats object
174 local leaderstats = WaitForChild(PlayersService.LocalPlayer, "leaderstats")
175 local leaderstatsList = leaderstats:GetChildren()
176 local counter = 0
177 for _, stat in pairs(leaderstatsList) do
178 -- For each stat we create a label for the column
179 if stat:IsA("IntValue") or stat:IsA("NumberValue") or stat:IsA("StringValue") then
180 local stat_TextLabel = StatTextLabel:Clone()
181 stat_TextLabel.Name = stat.Name
182 stat_TextLabel.Text = stat.Name
183 stat_TextLabel.Position = UDim2.new(1, (-PIXELS_X_BETWEEN_STAT_COLUMNS * counter) - PLAYERS_X_PADDING_PIXELS, 0, 15)
184 stat_TextLabel.Parent = frame
185
186 counter = counter + 1
187 -- For each stat create a sum label at the bottom
188 local sum = 0
189 for _, player in pairs(PlayersService:GetPlayers()) do
190 if frameTeamColor and player.TeamColor == frameTeamColor and player:FindFirstChild('leaderstats') then
191 local currStat = player:FindFirstChild('leaderstats'):FindFirstChild(stat.Name)
192 if currStat:IsA('IntValue') or currStat:IsA('NumberValue') or currStat:IsA('IntConstrainedValue') then
193 sum = sum + currStat.Value
194 end
195 end
196 end
197 local stat_SumLabel = stat_TextLabel:Clone()
198 stat_SumLabel.Name = "Team" .. stat_TextLabel.Name
199 stat_SumLabel.Text = sum
200 stat_SumLabel.Position = UDim2.new(stat_TextLabel.Position.X.Scale, stat_TextLabel.Position.X.Offset, 1, -20)
201 stat_SumLabel.Parent = frame
202 end
203 end
204 end
205 end
206 end
207
208 -- This variable will keep track of how many players are in each team's frame
209 -- so we now how far down to put the next player in the score list
210 local numberOfPlayersInTeamSoFar = {}
211
212 local players = PlayersService:GetPlayers()
213 for i = 1, #players do
214 if players[i] then
215 local xOffset = 0
216 local yOffset = 0
217 -- Get the leaderstats object
218 local leaderstats = WaitForChild(players[i], "leaderstats")
219 local leaderstatsList = leaderstats:GetChildren()
220 -- Create the player name
221 local playerName_TextLabel = PlayerTextLabel:Clone()
222 playerName_TextLabel.Name = players[i].Name
223 playerName_TextLabel.Text = players[i].Name
224
225 -- If we have frames for each team, then encapsulate the score inside their team's frame
226 if TeamsExist and TeamColorToTeamFrame[players[i].TeamColor.Name] ~= nil then
227 local teamFrame = TeamColorToTeamFrame[players[i].TeamColor.Name]
228 -- Create or increment the player count
229 if not numberOfPlayersInTeamSoFar[players[i].TeamColor.Name] then
230 numberOfPlayersInTeamSoFar[players[i].TeamColor.Name] = 1
231 else
232 numberOfPlayersInTeamSoFar[players[i].TeamColor.Name] = numberOfPlayersInTeamSoFar[players[i].TeamColor.Name] + 1
233 end
234 playerName_TextLabel.Parent = teamFrame
235 yOffset = PLAYER_LIST_START_Y_OFFSET +
236 (numberOfPlayersInTeamSoFar[players[i].TeamColor.Name] - 1) * PIXELS_Y_BETWEEN_PLAYER_ROWS
237 playerName_TextLabel.Position = UDim2.new(0, PLAYERS_X_PADDING_PIXELS, 0, yOffset)
238 elseif #TeamsService:GetTeams() == 0 then -- Otherwise we will fallback to putting the score inside the root of leaderboard
239 if not LeaderboardFrame:FindFirstChild('TeamlessFrame') then CreateNeutralTeamFrame() end
240 local teamlessFrame = LeaderboardFrame:FindFirstChild('TeamlessFrame')
241 if not numberOfPlayersInTeamSoFar['Neutral'] then
242 numberOfPlayersInTeamSoFar['Neutral'] = 1
243 else
244 numberOfPlayersInTeamSoFar['Neutral'] = numberOfPlayersInTeamSoFar['Neutral'] + 1
245 end
246 playerName_TextLabel.Parent = teamlessFrame
247 yOffset = PLAYER_LIST_START_Y_OFFSET +
248 (numberOfPlayersInTeamSoFar['Neutral'] - 1) * PIXELS_Y_BETWEEN_PLAYER_ROWS
249 playerName_TextLabel.Position = UDim2.new(0, PLAYERS_X_PADDING_PIXELS, 0, yOffset)
250 end
251
252 -- For this player we will incrementally place their leaderstats to the right of their name
253 local counter = 0
254 for _, stat in pairs(leaderstatsList) do
255 if stat:IsA("IntValue") or stat:IsA("NumberValue") or stat:IsA("StringValue") then
256 local stat_TextLabel = playerName_TextLabel:Clone()
257 stat_TextLabel.Text = stat.Value
258 stat_TextLabel.Position = UDim2.new(1, -PIXELS_X_BETWEEN_STAT_COLUMNS * counter - PLAYERS_X_PADDING_PIXELS, 0, yOffset)
259 stat_TextLabel.TextXAlignment = Enum.TextXAlignment.Right
260 stat_TextLabel.Parent = playerName_TextLabel.Parent
261
262 counter = counter + 1
263 -- If this player isn't on a team then we can add up their points in the neutral team window
264 if not TeamsExist or TeamColorToTeamFrame[players[i].TeamColor.Name] == nil then
265 local teamlessFrame = LeaderboardFrame:FindFirstChild('TeamlessFrame')
266 if teamlessFrame and teamlessFrame:FindFirstChild("Team" .. stat.Name) then
267 local statLabel = teamlessFrame:FindFirstChild("Team" .. stat.Name)
268 -- Make sure that statlabel's value can be turned into a number
269 if tonumber(statLabel.Text) then statLabel.Text = tonumber(statLabel.Text) + stat.Value end
270 else
271 print("No teamlessframe")
272 end
273 end
274
275 end
276 end
277 end
278 end
279 -- Change all the text and color within the frame to contrast with the background
280 for _, frame in pairs(TeamColorToTeamFrame) do
281 local textColor = DARK_FONT_COLOR
282 if IsDark(frame.BackgroundColor3) then
283 textColor = LIGHT_FONT_COLOR
284 end
285 for _, item in pairs(frame:GetChildren()) do
286 if item.Name == 'Team' or item.Name == 'TeamScore' then
287 --skip
288 elseif item:IsA('TextLabel') then
289 item.TextColor3 = textColor
290 elseif item:IsA('Frame') then
291 item.BorderColor3 = textColor
292 end
293 end
294 end
295end
296
297--[[MyMouse.KeyDown:connect(function(key)
298 if string.lower(key) == 'q' then
299 if LeaderboardFrame then
300 if TOGGLES then
301 LeaderboardFrame.Visible = not LeaderboardFrame.Visible
302 else
303 LeaderboardFrame.Visible = true
304 end
305 end
306 end
307end)]]
308
309--[[MyMouse.KeyUp:connect(function(key)
310 if string.lower(key) == 'q' then
311 if LeaderboardFrame then
312 if not TOGGLES then
313 LeaderboardFrame.Visible = false
314 end
315 end
316 end
317end)]]
318
319LeaderboardButton.MouseButton1Click:connect(function()
320 LeaderboardFrame.Visible = not LeaderboardFrame.Visible
321end)
322
323
324CreateTeamFrames()
325MirrorTemplateFrame()
326PopulateLeaderboard()
327Spawn(function() while true do
328 PopulateLeaderboard()
329 wait(3)
330 end
331end)