View difference between Paste ID: skmZLkwh and SUbmhjXE
SHOW: | | - or go back to the newest paste.
1
--game:GetService("StarterGui"):SetCoreGuiEnabled("Chat", false)
2
local NameColorDependsOnChatColor = true
3
local StrokeTransparency = 0.5 -- Number 0 to 1.  Lower stroke transparency is easier to read against colorful backgrounds.
4
5
while not _G.PlayerListAPI do wait() end
6
local PLAYERLIST_ADMINS, PLAYERLIST_CHATCOLORS, PLAYERLIST_ALIASES = _G.PlayerListAPI:GetChatData()
7
8
local forceChatGUI = false
9
10
-- Utility functions + Globals
11
local function WaitForChild(parent, childName)	
12
	while parent:FindFirstChild(childName) == nil do 
13
		parent.ChildAdded:wait(0.03)
14
	end 	
15
	return parent[childName]
16
end 
17
18
local function typedef(obj)
19
	return obj 
20
end 
21
22
local function IsPhone()
23
	local rGui = script.Parent
24
	if rGui.AbsoluteSize.Y < 600 then 
25
		return true 
26
	end 
27
	return false 
28
end
29
30
local export = {}
31
export.NameColorDependsOnChatColor = NameColorDependsOnChatColor
32
33
export.SetNameColorDependsOnChatColor = function(self, b)
34
	self.NameColorDependsOnChatColor = b
35
end
36
37
-- Users can use enough white spaces to spoof chatting as other players
38
-- This function removes trailing and leading white spaces
39
-- AFAIK, there is no reason for spam white spaces 
40
local function StringTrim(str)
41
	-- %S is whitespaces
42
	-- When we find the first non space character defined by ^%s 
43
	-- we yank out anything in between that and the end of the string 
44
	-- Everything else is replaced with %1 which is essentially nothing  	
45
	return (str:gsub("^%s*(.-)%s*$", "%1"))
46
end 
47
48
while Game.Players.LocalPlayer == nil do wait(0.03) end
49
50
local Player = Game.Players.LocalPlayer 
51
while Player.Character == nil do wait(0.03) end 
52
local RbxUtility = LoadLibrary('RbxUtility')
53
local Gui = typedef(RbxUtility) 
54
local Camera = Game.Workspace.CurrentCamera 
55
56
-- Services 
57
local CoreGuiService = Game:GetService('CoreGui')
58
local PlayersService = Game:GetService('Players')
59
local DebrisService=  Game:GetService('Debris')
60
local GuiService = Game:GetService('GuiService')
61
62
-- Lua Enums
63
local Enums do
64
	Enums = {}
65
	local EnumName = {} -- used as unique key for enum name
66
	local enum_mt = {
67
		__call = function(self,value)
68
			return self[value] or self[tonumber(value)]
69
		end;
70
		__index = {
71
			GetEnumItems = function(self)
72
				local t = {}
73
				for i,item in pairs(self) do
74
					if type(i) == 'number' then
75
						t[#t+1] = item
76
					end
77
				end
78
				table.sort(t,function(a,b) return a.Value < b.Value end)
79
				return t
80
			end;
81
		};
82
		__tostring = function(self)
83
			return "Enum." .. self[EnumName]
84
		end;
85
	}
86
	local item_mt = {
87
		__call = function(self,value)
88
			return value == self or value == self.Name or value == self.Value
89
		end;
90
		__tostring = function(self)
91
			return "Enum." .. self[EnumName] .. "." .. self.Name
92
		end;
93
	}
94
	function CreateEnum(enumName)
95
		return function(t)
96
			local e = {[EnumName] = enumName}
97
			for i,name in pairs(t) do
98
				local item = setmetatable({Name=name,Value=i,Enum=e,[EnumName]=enumName},item_mt)
99
				e[i] = item
100
				e[name] = item
101
				e[item] = item
102
			end
103
			Enums[enumName] = e
104
			return setmetatable(e, enum_mt)
105
		end
106
	end
107
end
108
---------------------------------------------------
109
------------------ Input class -------------------- 
110
local Input = {
111
						Mouse = Player:GetMouse(),
112
						Speed = 0,
113
						Simulating = false, 
114
115
						Configuration = {
116
											DefaultSpeed = 1
117
										},
118
						UserIsScrolling = false
119
					}
120
121
---------------------------------------------------
122
------------------ Chat class --------------------
123
local Chat = { 
124
125
			ChatColors = {
126
							BrickColor.new("Bright red"),
127
							BrickColor.new("Bright blue"),
128
							BrickColor.new("Earth green"),
129
							BrickColor.new("Bright violet"),
130
							BrickColor.new("Bright orange"),
131
							BrickColor.new("Bright yellow"),
132
							BrickColor.new("Light reddish violet"),
133
							BrickColor.new("Brick yellow"),
134
						},
135
136
			Gui = nil,
137
			Frame = nil,
138
			RenderFrame = nil,
139
			TapToChatLabel = nil,
140
			ClickToChatButton = nil,
141
142
			ScrollingLock = false,
143
			EventListener = nil, 
144
145
			-- This is actually a ring buffer
146
			-- Meaning at hitting the historyLength it wraps around 
147
			-- Reuses the text objects, so chat atmost uses 100 text objects
148
			MessageQueue = {}, 
149
150
			-- Stores all the values for configuring chat 
151
			Configuration = {								
152
								FontSize = Enum.FontSize.Size12, -- 10 is good 				
153
								-- Also change this when you are changing the above, this is suboptimal but so is our interface to find FontSize				
154
								NumFontSize = 12, 
155
								HistoryLength = 20, -- stores up to 50 of the last chat messages for you to scroll through,
156
								Size = UDim2.new(0.38, 0, 0.20, 0),
157
								MessageColor = Color3.new(1, 1, 1),
158
								AdminMessageColor = Color3.new(1, 215/255, 0),								
159
								XScale = 0.025,	
160
								LifeTime = 45,		
161
								Position = UDim2.new(0, 2, 0.05, 0),
162
								DefaultTweenSpeed = 0.15,								
163
							},
164
165
			-- This could be redone by just using the previous and next fields of the Queue
166
			-- But the iterators cause issues, will be optimized later 
167
			SlotPositions_List = {},	
168
			-- To precompute and store all player null strings since its an expensive process 
169
			CachedSpaceStrings_List = {},	
170
			MouseOnFrame = false,
171
			GotFocus = false,
172
173
			Messages_List = {},
174
			MessageThread = nil,
175
176
			Admins_List = PLAYERLIST_ADMINS,
177
178
			SafeChat_List = {
179
								['Use the Chat menu to talk to me.'] = {'/sc 0', true},
180
								['I can only see menu chats.'] = {'/sc 1', true},
181
								['Hello'] = {	
182
												['Hi'] = {'/sc 2_0', true, ['Hi there!'] = true, ['Hi everyone'] = true}, 
183
												['Howdy'] = {'/sc 2_1', true, ['Howdy partner!'] = true},
184
												['Greetings'] = {'/sc 2_2', true, ['Greetings everyone'] = true, ['Greetings Robloxians!'] = true, ['Seasons greetings!'] = true},
185
												['Welcome'] = {'/sc 2_3', true, ['Welcome to my place'] = true, ['Welcome to my barbeque'] = true, ['Welcome to our base'] = true},
186
												['Hey there!'] = {'/sc 2_4', true},
187
												['What\'s up?'] = {'/sc 2_5', true, ['How are you doing?'] = true, ['How\'s it going?'] = true, ['What\'s new?'] = true},
188
												['Good day'] = {'/sc 2_6', true, ['Good morning'] = true, ['Good evening'] = true, ['Good afternoon'] = true, ['Good night'] = true},
189
												['Silly'] = {'/sc 2_7', true, ['Waaaaaaaz up?!'] = true, ['Hullo!'] = true, ['Behold greatness, mortals!'] = true, ['Pardon me, is this Sparta?'] = true, ['THIS IS SPARTAAAA!'] = true},
190
												['Happy Holidays!'] = {'/sc 2_8', true, ['Happy New Year!'] = true, 
191
																	      ['Happy Valentine\'s Day!'] = true, 
192
																	      ['Beware the Ides of March!'] = true, 
193
																	      ['Happy St. Patrick\'s Day!'] = true, 
194
																	      ['Happy Easter!'] = true, 
195
																	      ['Happy Earth Day!'] = true, 
196
																	      ['Happy 4th of July!'] = true, 
197
																	      ['Happy Thanksgiving!'] = true, 
198
																	      ['Happy Halloween!'] = true, 
199
																	      ['Happy Hanukkah!'] = true, 
200
																	      ['Merry Christmas!'] = true, 
201
																	      ['Happy Halloween!'] = true, 
202
																	      ['Happy Earth Day!'] = true, 
203
																	      ['Happy May Day!'] = true, 
204
																	      ['Happy Towel Day!'] = true, 
205
																	      ['Happy ROBLOX Day!'] = true, 
206
																	      ['Happy LOL Day!'] = true },
207
208
												[1] = '/sc 2'
209
											},
210
								['Goodbye'] = {
211
												['Good Night']= {'/sc 3_0', true, 
212
																  ['Sweet dreams'] = true, 
213
															      ['Go to sleep!'] = true, 
214
															      ['Lights out!'] = true, 
215
															      ['Bedtime'] = true, 
216
															      ['Going to bed now'] = true},
217
218
												['Later']= {'/sc 3_1', true,
219
												 			  ['See ya later'] = true, 
220
														      ['Later gator!'] = true, 
221
														      ['See you tomorrow'] = true},
222
223
												['Bye'] = {'/sc 3_2', true, ['Hasta la bye bye!'] = true},
224
												['I\'ll be right back'] = {'/sc 3_3', true},
225
												['I have to go'] = {'/sc 3_4', true},
226
												['Farewell'] = {'/sc 3_5', true, ['Take care'] = true, ['Have a nice day'] = true, ['Goodluck!'] = true, ['Ta-ta for now!'] = true},
227
												['Peace'] = {'/sc 3_6', true, ['Peace out!'] = true, ['Peace dudes!'] = true, ['Rest in pieces!'] = true},
228
												['Silly'] = {'/sc 3_7', true, 
229
												  ['To the batcave!'] = true, 
230
											      ['Over and out!'] = true, 
231
											      ['Happy trails!'] = true, 
232
											      ['I\'ve got to book it!'] = true, 
233
											      ['Tootles!'] = true, 
234
											      ['Smell you later!'] = true, 
235
											      ['GG!'] = true, 
236
											      ['My house is on fire! gtg.'] = true},
237
												[1] = '/sc 3'
238
											},
239
								['Friend'] ={
240
												['Wanna be friends?'] = {'/sc 4_0', true},
241
												['Follow me'] = {'/sc 4_1', true,  ['Come to my place!'] = true, ['Come to my base!'] = true, ['Follow me, team!'] = true, ['Follow me'] = true},
242
												['Your place is cool'] = {'/sc 4_2', true,  ['Your place is fun'] = true, ['Your place is awesome'] = true, ['Your place looks good'] = true, ['This place is awesome!'] = true},
243
												['Thank you'] = {'/sc 4_3', true,  ['Thanks for playing'] = true, ['Thanks for visiting'] = true, ['Thanks for everything'] = true, ['No, thank you'] = true, ['Thanx'] = true},
244
												['No problem'] = {'/sc 4_4', true,  ['Don\'t worry'] = true, ['That\'s ok'] = true, ['np'] = true},
245
												['You are ...'] = {'/sc 4_5', true,  
246
																	['You are great!'] = true, 
247
																      ['You are good!'] = true, 
248
																      ['You are cool!'] = true, 
249
																      ['You are funny!'] = true, 
250
																      ['You are silly!'] = true, 
251
																      ['You are awesome!'] = true, 
252
																      ['You are doing something I don\'t like, please stop'] = true
253
																   },
254
												['I like ...'] = {'/sc 4_6', true, ['I like your name'] = true, ['I like your shirt'] = true, ['I like your place'] = true, ['I like your style'] = true, 
255
      																['I like you'] = true, ['I like items'] = true, ['I like money'] = true},
256
												['Sorry'] = {'/sc 4_7', true, ['My bad!'] = true, ['I\'m sorry'] = true, ['Whoops!'] = true, ['Please forgive me.'] = true, ['I forgive you.'] = true, 
257
      														['I didn\'t mean to do that.'] = true, ['Sorry, I\'ll stop now.'] = true},
258
												[1] = '/sc 4'
259
											},
260
								['Questions'] = {
261
													['Who?'] = {'/sc 5_0', true,  ['Who wants to be my friend?'] = true, ['Who wants to be on my team?'] = true, ['Who made this brilliant game?'] = true},
262
													['What?'] = {'/sc 5_1', true,  ['What is your favorite animal?'] = true, ['What is your favorite game?'] = true, ['What is your favorite movie?'] = true, 
263
															      ['What is your favorite TV show?'] = true, ['What is your favorite music?'] = true, ['What are your hobbies?'] = true, ['LOLWUT?'] = true},
264
													['When?'] = {'/sc 5_2', true, ['When are you online?'] = true, ['When is the new version coming out?'] = true, ['When can we play again?'] = true, ['When will your place be done?'] = true},
265
													['Where?'] = {'/sc 5_3', true, ['Where do you want to go?'] = true, ['Where are you going?'] = true, ['Where am I?!'] = true, ['Where did you go?'] = true},
266
													['How?'] = {'/sc 5_4', true, ['How are you today?'] = true, ['How did you make this cool place?'] = true, ['LOLHOW?'] = true},
267
													['Can I...'] = {'/sc 5_5', true, ['Can I have a tour?'] = true, ['Can I be on your team?'] = true, ['Can I be your friend?'] = true, ['Can I try something?'] = true, 
268
																	['Can I have that please?'] = true, ['Can I have that back please?'] = true, ['Can I have borrow your hat?'] = true, ['Can I have borrow your gear?'] = true},
269
													[1] = '/sc 5'
270
												},
271
								['Answers'] = {
272
												['You need help?'] = {'/sc 6_0', true, ['Check out the news section'] = true, ['Check out the help section'] = true, ['Read the wiki!'] = true, 
273
																		['All the answers are in the wiki!'] = true, ['I will help you with this.'] = true},
274
												['Some people ...'] = {'/sc 6_1', true, ['Me'] = true, ['Not me'] = true, ['You'] = true, ['All of us'] = true, ['Everyone but you'] = true, ['Builderman!'] = true, 
275
      																	['Telamon!'] = true, ['My team'] = true, ['My group'] = true, ['Mom'] = true, ['Dad'] = true, ['Sister'] = true, ['Brother'] = true, ['Cousin'] = true, 
276
      																	['Grandparent'] = true, ['Friend'] = true},
277
												['Time ...'] = {'/sc 6_2', true,  ['In the morning'] = true, ['In the afternoon'] = true, ['At night'] = true, ['Tomorrow'] = true, ['This week'] = true, ['This month'] = true, 
278
      															['Sometime'] = true, ['Sometimes'] = true, ['Whenever you want'] = true, ['Never'] = true, ['After this'] = true, ['In 10 minutes'] = true, ['In a couple hours'] = true, 
279
      															['In a couple days'] = true},
280
												['Animals'] = {'/sc 6_3', true, 
281
																['Cats'] = {['Lion'] = true, ['Tiger'] = true, ['Leopard'] = true, ['Cheetah'] = true},
282
																['Dogs'] = {['Wolves'] = true, ['Beagle'] = true, ['Collie'] = true, ['Dalmatian'] = true, ['Poodle'] = true, ['Spaniel'] = true, 
283
        																		['Shepherd'] = true, ['Terrier'] = true, ['Retriever'] = true},
284
        														['Horses'] = {['Ponies'] = true, ['Stallions'] = true, ['Pwnyz'] = true},
285
        														['Reptiles'] = {['Dinosaurs'] = true, ['Lizards'] = true, ['Snakes'] = true, ['Turtles!'] = true},
286
        														['Hamster'] = true, 
287
      															['Monkey'] = true, 
288
      															['Bears'] = true,
289
      															['Fish'] = {['Goldfish'] = true, ['Sharks'] = true, ['Sea Bass'] = true, ['Halibut'] = true, ['Tropical Fish'] = true},
290
      															['Birds'] = {['Eagles'] = true, ['Penguins'] = true, ['Parakeets'] = true, ['Owls'] = true, ['Hawks'] = true, ['Pidgeons'] = true},
291
      															['Elephants'] = true, 
292
      															['Mythical Beasts'] = {['Dragons'] = true, ['Unicorns'] = true, ['Sea Serpents'] = true, ['Sphinx'] = true, ['Cyclops'] = true, 
293
        																				['Minotaurs'] = true, ['Goblins'] = true, ['Honest Politicians'] = true, ['Ghosts'] = true, ['Scylla and Charybdis'] = true}
294
															},
295
												['Games'] = {'/sc 6_4', true,
296
																['Action'] = true, ['Puzzle'] = true, ['Strategy'] = true, ['Racing'] = true, ['RPG'] = true, ['Obstacle Course'] = true, ['Tycoon'] = true, 
297
																['Roblox'] = { ['BrickBattle'] = true, ['Community Building'] = true, ['Roblox Minigames'] = true, ['Contest Place'] = true},
298
																['Board games'] = { ['Chess'] = true, ['Checkers'] = true, ['Settlers of Catan'] = true, ['Tigris and Euphrates'] = true, ['El Grande'] = true, 
299
        																			['Stratego'] = true, ['Carcassonne'] = true}
300
															},
301
												['Sports'] = {'/sc 6_5', true, ['Hockey'] = true, ['Soccer'] = true, ['Football'] = true, ['Baseball'] = true, ['Basketball'] = true, 
302
																 ['Volleyball'] = true, ['Tennis'] = true, ['Sports team practice'] = true,
303
																 ['Watersports'] = { ['Surfing'] = true,['Swimming'] = true, ['Water Polo'] = true},
304
																 ['Winter sports'] = { ['Skiing'] = true, ['Snowboarding'] = true, ['Sledding'] = true, ['Skating'] = true},
305
																 ['Adventure'] = {['Rock climbing'] = true, ['Hiking'] = true, ['Fishing'] = true, ['Horseback riding'] = true},
306
																 ['Wacky'] = {['Foosball'] = true, ['Calvinball'] = true, ['Croquet'] = true, ['Cricket'] = true, ['Dodgeball'] = true, 
307
        																		['Squash'] = true, 	['Trampoline'] = true}
308
															 },
309
												['Movies/TV'] = {'/sc 6_6', true, ['Science Fiction'] = true, ['Animated'] = {['Anime'] = true}, ['Comedy'] = true, ['Romantic'] = true, 
310
      																['Action'] = true, ['Fantasy'] = true},
311
												['Music'] = {'/sc 6_7', true, ['Country'] = true, ['Jazz'] = true, ['Rap'] = true, ['Hip-hop'] = true, ['Techno'] = true, ['Classical'] = true, 
312
      														['Pop'] = true, ['Rock'] = true},
313
												['Hobbies'] = {'/sc 6_8', true,
314
																['Computers'] = { ['Building computers'] = true, ['Videogames'] = true, ['Coding'] = true, ['Hacking'] = true},
315
																['The Internet'] = { ['lol. teh internets!'] = true, ['Watching vids'] = true},
316
																 ['Dance'] = true, ['Gymnastics'] = true, ['Listening to music'] = true, ['Arts and crafts'] = true,
317
																 ['Martial Arts'] = {['Karate'] = true, ['Judo'] = true, ['Taikwon Do'] = true, ['Wushu'] = true, ['Street fighting'] = true},
318
																 ['Music lessons'] = {['Playing in my band'] = true, ['Playing piano'] = true, ['Playing guitar'] = true, 
319
        																				['Playing violin'] = true, ['Playing drums'] = true, ['Playing a weird instrument'] = true}
320
																},
321
												['Location'] = {'/sc 6_9', true,
322
																	['USA'] = {
323
																					['West'] = { ['Alaska'] = true, ['Arizona'] = true, ['California'] = true, ['Colorado'] = true, ['Hawaii'] = true, 
324
          																						['Idaho'] = true, ['Montana'] = true, ['Nevada'] = true, ['New Mexico'] = true, ['Oregon'] = true, 
325
          																						['Utah'] = true, ['Washington'] = true, ['Wyoming'] = true
326
          																						},
327
          																			['South'] = { ['Alabama'] = true, ['Arkansas'] = true, ['Florida'] = true, ['Georgia'] = true, ['Kentucky'] = true, 
328
          																							['Louisiana'] = true, ['Mississippi'] = true, ['North Carolina'] = true, ['Oklahoma'] = true, 
329
          																							['South Carolina'] = true, ['Tennessee'] = true, ['Texas'] = true, ['Virginia'] = true, ['West Virginia'] = true
330
          																						},
331
          																			['Northeast'] = {['Connecticut'] = true, ['Delaware'] = true, ['Maine'] = true, ['Maryland'] = true, ['Massachusetts'] = true, 
332
          																							['New Hampshire'] = true, ['New Jersey'] = true, ['New York'] = true,  ['Pennsylvania'] = true, ['Rhode Island'] = true, 
333
          																							['Vermont'] = true
334
          																						},
335
          																			['Midwest'] = {['Illinois'] = true, ['Indiana'] = true, ['Iowa'] = true, ['Kansas'] = true, ['Michigan'] = true, ['Minnesota'] = true, 
336
          																							['Missouri'] = true, ['Nebraska'] = true, ['North Dakota'] = true, ['Ohio'] = true, ['South Dakota'] = true,  ['Wisconsin'] = true}
337
																				},
338
																	['Canada'] = {['Alberta'] = true, ['British Columbia'] = true, ['Manitoba'] = true, ['New Brunswick'] = true, ['Newfoundland'] = true, 
339
        																			['Northwest Territories'] = true, ['Nova Scotia'] = true, ['Nunavut'] = true, ['Ontario'] = true, ['Prince Edward Island'] = true, 
340
        																			['Quebec'] = true, ['Saskatchewan'] = true, ['Yukon'] = true},
341
        															['Mexico'] = true,
342
        															['Central America'] = true,
343
        															['Europe'] = {['France'] = true, ['Germany'] = true, ['Spain'] = true, ['Italy'] = true, ['Poland'] = true, ['Switzerland'] = true, 
344
        																			['Greece'] = true, ['Romania'] = true, ['Netherlands'] = true,
345
        																			['Great Britain'] = {['England'] = true, ['Scotland'] = true, ['Wales'] = true, ['Northern Ireland'] = true}
346
        																		},
347
        															['Asia'] = { ['China'] = true, ['India'] = true, ['Japan'] = true, ['Korea'] = true, ['Russia'] = true, ['Vietnam'] = true},
348
        															['South America'] = { ['Argentina'] = true, ['Brazil'] = true},
349
        															['Africa'] = { ['Eygpt'] = true, ['Swaziland'] = true},
350
        															['Australia'] = true, ['Middle East'] = true, ['Antarctica'] = true, ['New Zealand'] = true
351
																},
352
												['Age'] = {'/sc 6_10', true, ['Rugrat'] = true, ['Kid'] = true, ['Tween'] = true, ['Teen'] = true, ['Twenties'] = true, 
353
      														['Old'] = true, ['Ancient'] = true, ['Mesozoic'] = true, ['I don\'t want to say my age. Don\'t ask.'] = true},
354
												['Mood'] = {'/sc 6_11', true,  ['Good'] = true, ['Great!'] = true, ['Not bad'] = true, ['Sad'] = true, ['Hyper'] = true, 
355
      														['Chill'] = true, ['Happy'] = true, ['Kind of mad'] = true},
356
												['Boy'] = {'/sc 6_12', true},
357
												['Girl'] = {'/sc 6_13', true},
358
												['I don\'t want to say boy or girl. Don\'t ask.'] = {'/sc 6_14', true},
359
												[1] = '/sc 6'
360
											}, 
361
								['Game'] = {
362
												['Let\'s build'] = {'/sc 7_0', true},
363
												['Let\'s battle'] = {'/sc 7_1', true},
364
												['Nice one!'] = {'/sc 7_2', true},
365
												['So far so good'] = {'/sc 7_3', true},
366
												['Lucky shot!'] = {'/sc 7_4', true},
367
												['Oh man!'] = {'/sc 7_5', true},
368
												['I challenge you to a fight!'] = {'/sc 7_6', true},
369
												['Help me with this'] = {'/sc 7_7', true},
370
												['Let\'s go to your game'] = {'/sc 7_8', true},
371
												['Can you show me how do to that?'] = {'/sc 7_9', true},
372
												['Backflip!'] = {'/sc 7_10', true},
373
												['Frontflip!'] = {'/sc 7_11', true},							
374
												['Dance!'] = {'/sc 7_12', true},
375
												['I\'m on your side!'] = {'/sc 7_13', true},
376
												['Game Commands'] = {'/sc 7_14', true, ['regen'] = true, ['reset'] = true, ['go'] = true, ['fix'] = true, ['respawn'] = true},
377
												[1] = '/sc 7'
378
											};
379
								['Silly'] = {
380
												['Muahahahaha!'] = true,
381
												['all your base are belong to me!'] = true,
382
												['GET OFF MAH LAWN'] = true,
383
												['TEH EPIK DUCK IS COMING!!!'] = true,
384
												['ROFL'] = true,
385
												['1337'] = {true, ['i r teh pwnz0r!'] = true, ['w00t!'] = true, ['z0mg h4x!'] = true, ['ub3rR0xXorzage!'] = true}
386
											},
387
								['Yes'] = {
388
											['Absolutely!'] = true,
389
											['Rock on!'] = true,
390
											['Totally!'] = true,
391
											['Juice!'] = true,
392
											['Yay!'] = true,
393
											['Yesh'] = true
394
										},
395
								['No'] = {
396
											['Ummm. No.'] = true,
397
											['...'] = true,
398
											['Stop!'] = true,
399
											['Go away!'] = true,
400
											['Don\'t do that'] = true,
401
											['Stop breaking the rules'] = true,
402
											['I don\'t want to'] = true
403
										},
404
								['Ok'] = {
405
											['Well... ok'] = true,
406
											['Sure'] = true
407
										},
408
								['Uncertain'] = {
409
													['Maybe'] = true,
410
													['I don\'t know'] = true,
411
													['idk'] = true,
412
													['I can\'t decide'] = true,
413
													['Hmm...'] = true
414
												},
415
								[':-)'] = {
416
											[':-('] = true, 
417
										    [':D'] = true, 
418
										    [':-O'] = true, 
419
										    ['lol'] = true, 
420
										    ['=D'] = true, 
421
										    ['D='] = true, 
422
										    ['XD'] = true, 
423
										    [';D'] = true, 
424
										    [';)'] = true, 
425
										    ['O_O'] = true, 
426
										    ['=)'] = true, 
427
										    ['@_@'] = true, 
428
										    ['&gt;_&lt;'] = true, 
429
										    ['T_T'] = true, 
430
										    ['^_^'] = true,
431
											['<(0_0<) <(0_0)> (>0_0)> KIRBY DANCE'] = true,
432
											[')\';'] = true, 
433
											[':3'] = true
434
										},
435
								['Ratings'] = {
436
												['Rate it!'] = true,
437
												['I give it a 1 out of 10'] = true,
438
												['I give it a 2 out of 10'] = true,
439
												['I give it a 3 out of 10'] = true,
440
												['I give it a 4 out of 10'] = true,
441
												['I give it a 5 out of 10'] = true,
442
												['I give it a 6 out of 10'] = true,
443
												['I give it a 7 out of 10'] = true,
444
												['I give it a 8 out of 10'] = true,
445
												['I give it a 9 out of 10'] = true,
446
												['I give it a 10 out of 10!'] = true,
447
											}
448
							},			
449
			CreateEnum('SafeChat'){'Level1', 'Level2', 'Level3'},
450
			SafeChatTree = {},
451
			TempSpaceLabel = nil
452
		}
453
---------------------------------------------------
454
455
local function GetNameValue(pName)
456
	local value = 0
457
	for index = 1, #pName do 
458
		local cValue = string.byte(string.sub(pName, index, index))
459
		local reverseIndex = #pName - index + 1
460
		if #pName%2 == 1 then 
461
			reverseIndex = reverseIndex - 1			
462
		end
463
		if reverseIndex%4 >= 2 then 
464
			cValue = -cValue 			
465
		end 
466
		value = value + cValue 
467
	end 
468
	return value%8
469
end 
470
471
function Chat:ComputeChatColor(pName)
472
	if export.NameColorDependsOnChatColor then
473
		return PLAYERLIST_CHATCOLORS[pName:lower()] or self.ChatColors[GetNameValue(pName) + 1].Color
474
	else
475
		return self.ChatColors[GetNameValue(pName) + 1].Color
476
	end
477
end 
478
479
-- This is context based scrolling 
480
function Chat:EnableScrolling(toggle)
481
	-- Genius idea gone to fail, if we switch the camera type we can effectively lock the 
482
	-- camera and do no click scrolling 
483
	self.MouseOnFrame = false  
484
	if self.RenderFrame then 
485
		self.RenderFrame.MouseEnter:connect(function()			
486
			local character = Player.Character 
487
			local torso = WaitForChild(character, 'Torso')
488
			local humanoid = WaitForChild(character, 'Humanoid')
489
			local head = WaitForChild(character, 'Head')
490
			if toggle then 
491
				self.MouseOnFrame = true 
492
				Camera.CameraType = 'Scriptable'
493
				-- Get relative position of camera and keep to it 
494
				Spawn(function()	
495
					local currentRelativePos = Camera.CoordinateFrame.p - torso.Position
496
					while Chat.MouseOnFrame do
497
						Camera.CoordinateFrame = CFrame.new(torso.Position + currentRelativePos, head.Position)
498
						wait(0.015)  
499
					end 
500
				end)
501
			end 
502
		end)
503
504
		self.RenderFrame.MouseLeave:connect(function()
505
			Camera.CameraType = 'Custom'
506
			self.MouseOnFrame = false 
507
		end)
508
	end 	
509
end 
510
511
-- TODO: Scrolling using Mouse wheel 
512
function Chat:OnScroll(speed)
513
	if self.MouseOnFrame then 
514
		-- 
515
	end 
516
end 
517
518
-- Check if we are running on a touch device 
519
function Chat:IsTouchDevice()
520
	local touchEnabled = false 
521
	pcall(function() touchEnabled = Game:GetService('UserInputService').TouchEnabled end)	
522
	return touchEnabled 
523
end
524
525
-- Scrolling
526
function Chat:ScrollQueue(value)	 
527
	--[[for i = 1, #self.MessageQueue do 
528
		if self.MessageQueue[i] then 
529
			for _, label in pairs(self.MessageQueue[i]) do 
530
				local next = self.MessageQueue[i].Next
531
				local previous = self.MessageQueue[i].Previous 
532
				if label and label:IsA('TextLabel') or label:IsA('TextButton') then 							
533
					if value > 0 and previous and previous['Message'] then 						
534
						label.Position = previous['Message'].Position
535
					elseif value < 1 and next['Message'] then 
536
						label.Position = previous['Message'].Position
537
					end 
538
				end 
539
			end 
540
		end 
541
	end ]]
542
end
543
544
-- Handles the rendering of the text objects in their appropriate places
545
function Chat:UpdateQueue(field, diff)	
546
	-- Have to do some sort of correction here 				
547
	for i = #self.MessageQueue, 1, -1 do 			
548
		if self.MessageQueue[i] then 						
549
			for _, label in pairs(self.MessageQueue[i]) do
550
				if label and type(label) ~= 'table' and type(label) ~= 'number' then					
551
					if label:IsA('TextLabel') or label:IsA('TextButton') then 	
552
						if diff then 
553
							label.Position = label.Position - UDim2.new(0, 0, diff, 0) 
554
						else											
555
							if field == self.MessageQueue[i] then 						
556
								label.Position = UDim2.new(self.Configuration.XScale, 0, label.Position.Y.Scale - field['Message'].Size.Y.Scale , 0)
557
								-- Just to show up popping effect for the latest message in chat 
558
								coroutine.resume(coroutine.create(function()
559
									wait(0.05)							
560
									
561
									local t = 0.1
562
									local start = tick()
563
									
564
									while tick() - start < t do
565
										local alpha = (tick() - start) / t
566
										
567
										label.TextTransparency = 1-alpha
568
										wait() 
569
									end 
570
									label.TextTransparency = 0
571
									
572
									if label == field['Message'] then 
573
										label.TextStrokeTransparency = StrokeTransparency
574
									else 
575
										label.TextStrokeTransparency = StrokeTransparency
576
									end 		
577
								end))
578
							else 							
579
								label.Position = UDim2.new(self.Configuration.XScale, 0, label.Position.Y.Scale - field['Message'].Size.Y.Scale, 0)							
580
							end  
581
							if label.Position.Y.Scale < -0.01 then 							
582
								-- NOTE: Remove this fix when Textbounds is fixed
583
								label.Visible = false 						
584
								label:Destroy() 
585
							end 
586
						end 
587
					end 
588
				end 						
589
			end
590
		end 
591
	end	
592
end 
593
594
function Chat:CreateScrollBar()
595
	-- Code for scrolling is in here, partially, but scroll bar drawing isn't drawn 
596
	-- TODO: Implement 
597
end
598
599
-- For scrolling, to see if we hit the bounds so that we can stop it from scrolling anymore 
600
function Chat:CheckIfInBounds(value)
601
	if #Chat.MessageQueue < 3 then 
602
		return true  
603
	end 
604
605
	if value > 0 and Chat.MessageQueue[1] and Chat.MessageQueue[1]['Player'] and Chat.MessageQueue[1]['Player'].Position.Y.Scale == 0 then 
606
		return true 
607
	elseif value < 0  and Chat.MessageQueue[1] and Chat.MessageQueue[1]['Player'] and Chat.MessageQueue[1]['Player'].Position.Y.Scale < 0 then 
608
		return true 
609
	else 
610
		return false 
611
	end 
612
	return false
613
end 
614
615
-- This is to precompute all playerName space strings
616
-- This is used to offset the message by exactly this + 2 spacestrings
617
function Chat:ComputeSpaceString(pLabel)
618
	local nString = " "
619
	if not self.TempSpaceLabel then 
620
		self.TempSpaceLabel  = Gui.Create'TextButton'
621
								{
622
									Size = UDim2.new(0, pLabel.AbsoluteSize.X, 0, pLabel.AbsoluteSize.Y); 
623
									FontSize = self.Configuration.FontSize; 
624
									Parent = self.RenderFrame; 
625
									BackgroundTransparency = 1.0; 
626
									Text = nString;
627
									Name = 'SpaceButton'
628
								};
629
	else
630
		self.TempSpaceLabel.Text = nString
631
	end 
632
	
633
	while self.TempSpaceLabel.TextBounds.X < pLabel.TextBounds.X do 
634
		nString = nString .. " "
635
		self.TempSpaceLabel.Text = nString 				
636
	end 
637
	nString = nString .. " "
638
	self.CachedSpaceStrings_List[pLabel.Text] = nString 
639
	self.TempSpaceLabel.Text = ""
640
	return nString	
641
end
642
643
-- When the playerChatted event fires 
644
-- The message is what the player chatted 
645
function Chat:UpdateChat(cPlayer, message)
646
	local messageField = {
647
							['Player'] = cPlayer,
648
							['Message'] = message
649
						}	
650
	if Chat.MessageThread == nil or coroutine.status(Chat.MessageThread) == 'dead' then 		
651
		--Chat.Messages_List = {}		
652
		table.insert(Chat.Messages_List, messageField)				
653
		Chat.MessageThread = coroutine.create(function()
654
									for i = 1, #Chat.Messages_List do 	
655
										local field = Chat.Messages_List[i]																														
656
										Chat:CreateMessage(field['Player'], field['Message']) 						
657
									end 
658
									Chat.Messages_List = {}									
659
								end)
660
		coroutine.resume(Chat.MessageThread)
661
	else 
662
		table.insert(Chat.Messages_List, messageField)
663
	end 
664
end 
665
666
function Chat:RecalculateSpacing()
667
	--[[for i = 1, #self.MessageQueue do 
668
		local pLabel = self.MessageQueue[i]['Player']
669
		local mLabel = self.MessageQueue[i]['Message']		
670
671
		local prevYScale = mLabel.Size.Y.Scale
672
		local prevText = mLabel.Text
673
		mLabel.Text = prevText
674
675
		local heightField = mLabel.TextBounds.Y	
676
677
		mLabel.Size = UDim2.new(1, 0, heightField/self.RenderFrame.AbsoluteSize.Y, 0)	
678
		pLabel.Size = mLabel.Size
679
680
		local diff = mLabel.Size.Y.Scale - prevYScale
681
682
		Chat:UpdateQueue(self.MessageQueue[i], diff)
683
	end ]]
684
end 
685
686
function Chat:ApplyFilter(str)
687
	--[[for _, word in pair(self.Filter_List) do 
688
		if string.find(str, word) then 
689
			str:gsub(word, '@#$^')
690
		end 
691
	end ]]	
692
end
693
694
export.SendChat = function(self, name, message, custom_color, do_not_add_to_history)
695
	local old_color = PLAYERLIST_CHATCOLORS[name:lower()]
696
	if custom_color ~= nil then
697
		PLAYERLIST_CHATCOLORS[name:lower()] = custom_color
698
	end
699
	print(old_color, PLAYERLIST_CHATCOLORS[name:lower()])
700
	
701
	local player = game.Players:FindFirstChild(name) or {
702
		Name = name,
703
		Neutral = true,
704
		TeamColor = Color3.new(1,1,1)
705
	}
706
	
707
	Chat:CreateMessage(player, message, do_not_add_to_history)
708
--	if do_not_add_to_history ~= true then
709
--		AddToChatHistory(player, message)
710
--	end
711
	
712
	wait()
713
	PLAYERLIST_CHATCOLORS[name:lower()] = old_color or nil
714
end
715
716
-- NOTE: Temporarily disabled ring buffer to allow for chat to always wrap around 
717
function Chat:CreateMessage(cPlayer, message, do_not_add_to_history)
718
	if do_not_add_to_history ~= true then
719
		AddToChatHistory(cPlayer, message)
720
	end
721
	
722
	local pName
723
	if not cPlayer then 
724
		pName = ''
725
	else 
726
		pName = cPlayer.Name			
727
	end 	
728
	message = StringTrim(message)		
729
	local pLabel
730
	local mLabel 
731
	-- Our history stores upto 50 messages that is 100 textlabels 
732
	-- If we ever hit the mark, which would be in every popular game btw 
733
	-- we wrap around and reuse the labels 
734
	if #self.MessageQueue > self.Configuration.HistoryLength then 
735
		--[[pLabel = self.MessageQueue[#self.MessageQueue]['Player']
736
		mLabel = self.MessageQueue[#self.MessageQueue]['Message']
737
738
		pLabel.Text = pName .. ':'
739
		pLabel.Name = pName
740
741
		local pColor 
742
		if cPlayer.Neutral then  
743
			pLabel.TextColor3 = Chat:ComputeChatColor(pName)
744
		else 
745
			pLabel.TextColor3 = cPlayer.TeamColor.Color 
746
		end 
747
748
		local nString 
749
750
		if not self.CachedSpaceStrings_List[pName] then 
751
			nString = Chat:ComputeSpaceString(pLabel)
752
		else 
753
			nString = self.CachedSpaceStrings_List[pName]
754
		end 	
755
756
		mLabel.Text = "" 
757
		mLabel.Name = pName .. " - message"
758
		mLabel.Text = nString .. message; 
759
760
		mLabel.Parent = nil 
761
		mLabel.Parent = self.RenderFrame		
762
763
		mLabel.Position = UDim2.new(0, 0, 1, 0);
764
		pLabel.Position = UDim2.new(0, 0, 1, 0);]]
765
766
		-- Reinserted at the beginning, ring buffer 
767
		self.MessageQueue[#self.MessageQueue] = nil 
768
	end
769
	--else 
770
		-- Haven't hit the mark yet, so keep creating 
771
		pLabel = Gui.Create'TextLabel' 
772
					{
773
						Name = pName;
774
						Text = (PLAYERLIST_ALIASES[pName:lower()] or pName) .. ":";
775
						TextColor3 = PLAYERLIST_CHATCOLORS[pName:lower()] or pColor;
776
						FontSize = Chat.Configuration.FontSize;
777
						TextXAlignment = Enum.TextXAlignment.Left;
778
						TextYAlignment = Enum.TextYAlignment.Top;
779
						Parent = self.RenderFrame;
780
						TextWrapped = false;
781
						Size = UDim2.new(1, 0, 0.1, 0);
782
						BackgroundTransparency = 1.0;
783
						TextTransparency = 1.0;	
784
						Position = UDim2.new(0, 0, 1, 0);
785
						BorderSizePixel = 0.0; 
786
						TextStrokeColor3 = Color3.new(0, 0, 0);
787
						TextStrokeTransparency = StrokeTransparency;
788
						--Active = false;
789
					};					
790
		local pColor 
791
		if cPlayer.Neutral then  
792
			pLabel.TextColor3 = Chat:ComputeChatColor(pName)
793
		else 
794
			pLabel.TextColor3 = cPlayer.TeamColor.Color 
795
		end 
796
797
		local nString 
798
799
		if not self.CachedSpaceStrings_List[pName] then 
800
			nString = Chat:ComputeSpaceString(pLabel)
801
		else 
802
			nString = self.CachedSpaceStrings_List[pName]
803
		end 		
804
805
		mLabel = Gui.Create'TextLabel' 
806
						{
807
							Name = pName .. ' - message';
808
							-- Max is 3 lines
809
							Size = UDim2.new(1, 0, 0.5, 0);							
810
							TextColor3 = Chat.Configuration.MessageColor;
811
							FontSize = Chat.Configuration.FontSize;
812
							TextXAlignment = Enum.TextXAlignment.Left;	
813
							TextYAlignment = Enum.TextYAlignment.Top;						
814
							Text = ""; -- this is to stop when the engine reverts the swear words to default, which is button, ugh
815
							Parent = self.RenderFrame;			
816
							TextWrapped = true;			
817
							BackgroundTransparency = 1.0;						
818
							TextTransparency = 1.0;
819
							Position = UDim2.new(0, 0, 1, 0);
820
							BorderSizePixel = 0.0;
821
							TextStrokeColor3 = Color3.new(0, 0, 0);
822
							--TextStrokeTransparency = 0.8;
823
							--Active = false;
824
						};
825
		mLabel.Text = nString .. message;
826
827
		if not pName then 
828
			pLabel.Text = '' 
829
			mLabel.TextColor3 = Color3.new(0, 0.4, 1.0)
830
		end 
831
	--end 
832
833
	if self.Admins_List[pName:lower()] then
834
		mLabel.TextColor3 = PLAYERLIST_CHATCOLORS[pName:lower()] or self.Configuration.AdminMessageColor
835
	end
836
837
	pLabel.Visible = true
838
	mLabel.Visible = true 
839
	
840
	-- This will give beautiful multilines as well 
841
	local heightField = mLabel.TextBounds.Y	
842
843
	mLabel.Size = UDim2.new(1, 0, heightField/self.RenderFrame.AbsoluteSize.Y, 0)	
844
	pLabel.Size = mLabel.Size
845
846
	local yPixels = self.RenderFrame.AbsoluteSize.Y
847
	local yFieldSize = mLabel.TextBounds.Y
848
849
	local queueField = {}	
850
	queueField['Player'] = pLabel 
851
	queueField['Message'] = mLabel 
852
	queueField['SpawnTime'] = tick() -- Used for identifying when to make the message invisible 
853
854
	table.insert(self.MessageQueue, 1, queueField)		
855
	Chat:UpdateQueue(queueField)
856
end
857
858
function Chat:ScreenSizeChanged() 	
859
	wait()
860
	while self.Frame.AbsoluteSize.Y > 120 do 
861
		self.Frame.Size = self.Frame.Size - UDim2.new(0, 0, 0.005, 0)
862
	end 
863
	Chat:RecalculateSpacing()
864
end 
865
866
867
function Chat:FindButtonTree(scButton, rootList)	
868
	local list = {}
869
	rootList = rootList or self.SafeChatTree 	
870
	for button, _ in pairs(rootList) do 		
871
		if button == scButton then 			
872
			list = rootList[button]
873
		elseif type(rootList[button]) == 'table' then 
874
			list = Chat:FindButtonTree(scButton, rootList[button])
875
		end 
876
	end 		
877
	return list 
878
end 
879
880
function Chat:ToggleSafeChatMenu(scButton)
881
	local list = Chat:FindButtonTree(scButton, self.SafeChatTree)		
882
	if list then 
883
		for button, _ in pairs(list) do 
884
			if button:IsA('TextButton') or button:IsA('ImageButton') then 
885
				button.Visible = not button.Visible 
886
			end 
887
		end 
888
		return true
889
	end 
890
	return false 
891
end
892
893
function Chat:CreateSafeChatOptions(list, rootButton)
894
	local text_List = {}
895
	level = level or 0
896
	local count = 0
897
	text_List[rootButton] = {}
898
	text_List[rootButton][1] = list[1]
899
	rootButton = rootButton or self.SafeChatButton 
900
	for msg, _ in pairs(list) do 
901
		if type(msg) == 'string' then 
902
			local chatText = Gui.Create'TextButton'
903
							{
904
								Name = msg;
905
								Text = msg;
906
								Size = UDim2.new(0, 100, 0, 20);
907
								TextXAlignment = Enum.TextXAlignment.Center;
908
								TextColor3 = Color3.new(0.2, 0.1, 0.1);
909
								BackgroundTransparency = 0.5;
910
								BackgroundColor3 = Color3.new(1, 1, 1);
911
								Parent = self.SafeChatFrame;
912
								Visible = false;
913
								Position = UDim2.new(0, rootButton.Position.X.Scale + 105, 0, rootButton.Position.Y.Scale - ((count - 3) * 100));
914
							};
915
916
			count = count + 1
917
918
			if type(list[msg]) == 'table' then 								
919
				text_List[rootButton][chatText] = Chat:CreateSafeChatOptions(list[msg], chatText)				
920
			else 
921
				--table.insert(text_List[chatText], true)
922
			end 
923
			chatText.MouseEnter:connect(function()
924
				Chat:ToggleSafeChatMenu(chatText)
925
			end)
926
927
			chatText.MouseLeave:connect(function()
928
				Chat:ToggleSafeChatMenu(chatText)
929
			end)
930
931
			chatText.MouseButton1Click:connect(function()									
932
				local lList = Chat:FindButtonTree(chatText)
933
				if lList then 					
934
					for i, v in pairs(lList) do 						
935
					end 
936
				else 					
937
				end 
938
				pcall(function() PlayersService:Chat(lList[1])	end)
939
			end)
940
		end 
941
	end 
942
	return text_List
943
end
944
945
function Chat:CreateSafeChatGui()
946
	self.SafeChatFrame = Gui.Create'Frame' 
947
						{
948
							Name = 'SafeChatFrame';
949
							Size = UDim2.new(1, 0, 1, 0);
950
							Parent = self.Gui;
951
							BackgroundTransparency = 1.0;
952
953
							Gui.Create'ImageButton'
954
							{
955
								Name = 'SafeChatButton';
956
								Size = UDim2.new(0, 44, 0, 31);
957
								Position = UDim2.new(0, 1, 0.35, 0);
958
								BackgroundTransparency = 1.0;
959
								Image = 'http://www.roblox.com/asset/?id=97080365';
960
							};
961
						}
962
963
	self.SafeChatButton = self.SafeChatFrame.SafeChatButton
964
	-- safe chat button is the root of this tree 
965
	self.SafeChatTree[self.SafeChatButton] = Chat:CreateSafeChatOptions(self.SafeChat_List, self.SafeChatButton)
966
967
	self.SafeChatButton.MouseButton1Click:connect(function()		
968
		Chat:ToggleSafeChatMenu(self.SafeChatButton)
969
	end)
970
end
971
972
973
function Chat:FocusOnChatBar()
974
	if self.ClickToChatButton then 
975
		self.ClickToChatButton.Visible = false 	
976
	end 
977
978
	self.GotFocus = true
979
	if self.Frame['Background'] then 
980
		self.Frame.Background.Visible = false 
981
	end
982
	self.ChatBar:CaptureFocus()
983
end
984
985
-- For touch devices we create a button instead 
986
function Chat:CreateTouchButton()	
987
	self.ChatTouchFrame = Gui.Create'Frame'
988
						{
989
							Name = 'ChatTouchFrame';
990
							Size = UDim2.new(0, 128, 0, 32);
991
							Position = UDim2.new(0, 88, 0, 0);
992
							BackgroundTransparency = 1.0;
993
							Parent = self.Gui;
994
995
							Gui.Create'ImageButton'
996
							{
997
								Name = 'ChatLabel';
998
								Size = UDim2.new(0, 74, 0, 28);
999
								Position = UDim2.new(0, 0, 0, 0);
1000
								BackgroundTransparency = 1.0;								
1001
								ZIndex = 2.0;								
1002
							};		
1003
							Gui.Create'ImageLabel'
1004
							{
1005
								Name = 'Background';
1006
								Size = UDim2.new(1, 0, 1, 0);
1007
								Position = UDim2.new(0, 0, 0, 0);
1008
								BackgroundTransparency = 1.0;
1009
								Image = 'http://www.roblox.com/asset/?id=97078724'
1010
							};
1011
1012
						}
1013
	self.TapToChatLabel = self.ChatTouchFrame.ChatLabel	
1014
	self.TouchLabelBackground = self.ChatTouchFrame.Background
1015
1016
	self.ChatBar = Gui.Create'TextBox'
1017
					{
1018
						Name = 'ChatBar';
1019
						Size = UDim2.new(1, 0, 0.2, 0);
1020
						Position = UDim2.new(0, 0, 0.8, 800);
1021
						Text = "";
1022
						ZIndex = 1.0;
1023
						BackgroundTransparency = 1.0;
1024
						Parent = self.Frame;		
1025
						TextXAlignment = Enum.TextXAlignment.Left;
1026
						TextColor3 = Color3.new(1, 1, 1);		
1027
						ClearTextOnFocus = false;											
1028
					};	
1029
1030
	self.TapToChatLabel.MouseButton1Click:connect(function()
1031
		self.TapToChatLabel.Visible = false
1032
		--self.ChatBar.Visible = true 
1033
		--self.Frame.Background.Visible = true			
1034
		self.ChatBar:CaptureFocus() 
1035
		self.GotFocus = true 
1036
		if self.TouchLabelBackground then 
1037
			self.TouchLabelBackground.Visible = false 
1038
		end 
1039
	end)
1040
end
1041
1042
-- Non touch devices, create the bottom chat bar 
1043
function Chat:CreateChatBar()
1044
	-- okay now we do 
1045
--	local status, result = pcall(function() return GuiService.UseLuaChat end)	
1046
--	if forceChatGUI or (status and result) then 	
1047
--		self.ClickToChatButton = Gui.Create'TextButton'
1048
--								{
1049
--									Name = 'ClickToChat';
1050
--									Size = UDim2.new(1, 0, 0, 20);
1051
--									BackgroundTransparency = 1.0;
1052
--									ZIndex = 2.0;
1053
--									Parent = self.Gui;
1054
--									Text = "To chat click here or press \"/\" key";
1055
--									TextColor3 = Color3.new(1, 1, 0.9);
1056
--									Position = UDim2.new(0, 0, 1, 0);
1057
--									TextXAlignment = Enum.TextXAlignment.Left;
1058
--									FontSize = Enum.FontSize.Size12;
1059
--								}
1060
--
1061
--		self.ChatBar = Gui.Create'TextBox'
1062
--							{
1063
--								Name = 'ChatBar';
1064
--								Size = UDim2.new(1, 0, 0, 20);
1065
--								Position = UDim2.new(0, 0, 1, 0);
1066
--								Text = "";
1067
--								ZIndex = 1.0;
1068
--								BackgroundColor3 = Color3.new(0, 0, 0);
1069
--								BackgroundTransparency = 0.25;
1070
--								Parent = self.Gui;		
1071
--								TextXAlignment = Enum.TextXAlignment.Left;
1072
--								TextColor3 = Color3.new(1, 1, 1);	
1073
--								FontSize = Enum.FontSize.Size12;	
1074
--								ClearTextOnFocus = false;
1075
--								Text = '';							
1076
--							};	
1077
--
1078
--		-- Engine has code to offset the entire world, so if we do it by -20 pixels nothing gets in our chat's way
1079
--		--GuiService:SetGlobalSizeOffsetPixel(0, -20)
1080
--		local success, error = pcall(function() GuiService:SetGlobalGuiInset(0, 0, 0, 20) end) 
1081
--		if not success then 
1082
--			GuiService:SetGlobalSizeOffsetPixel(0, -20)
1083
--		end
1084
--		-- CHatHotKey is '/'
1085
--		GuiService:AddSpecialKey(Enum.SpecialKey.ChatHotkey)
1086
--		GuiService.SpecialKeyPressed:connect(function(key) 
1087
--			if key == Enum.SpecialKey.ChatHotkey then 
1088
--				Chat:FocusOnChatBar()
1089
--			end 
1090
--		end)	
1091
--
1092
--		self.ClickToChatButton.MouseButton1Click:connect(function()
1093
--			Chat:FocusOnChatBar()
1094
--		end)	
1095
--	end
1096
end
1097
1098
-- Create the initial Chat stuff 
1099
-- Done only once 
1100
function Chat:CreateGui()
1101
	self.Gui = script.Parent
1102
	self.Frame = Gui.Create'Frame'
1103
				{	
1104
					Name = 'ChatFrame';
1105
					--Size = self.Configuration.Size;
1106
					Size = UDim2.new(0, 500, 0, 120);
1107
					Position = UDim2.new(0, 0, 0, 5);
1108
					BackgroundTransparency = 1.0;
1109
					--ClipsDescendants = true;
1110
					ZIndex = 0.0;
1111
					Parent = self.Gui;
1112
					Active = false; 
1113
1114
					Gui.Create'ImageLabel'
1115
					{
1116
						Name = 'Background';
1117
						Image = 'http://www.roblox.com/asset/?id=97120937'; --96551212';
1118
						Size = UDim2.new(1.3, 0, 1.64, 0);
1119
						Position = UDim2.new(0, 0, 0, 0);
1120
						BackgroundTransparency = 1.0;								
1121
						ZIndex = 0.0;
1122
						Visible = false 
1123
					};
1124
1125
					Gui.Create'Frame'
1126
					{
1127
						Name = 'Border';
1128
						Size = UDim2.new(1, 0, 0, 1);
1129
						Position = UDim2.new(0, 0, 0.8, 0);
1130
						BackgroundTransparency = 0.0;
1131
						BackgroundColor3 = Color3.new(236/255, 236/255, 236/255);
1132
						BorderSizePixel = 0.0;
1133
						Visible = false;
1134
					};
1135
1136
					Gui.Create'Frame'
1137
					{
1138
						Name = 'ChatRenderFrame';
1139
						Size = UDim2.new(1.02, 0, 1.01, 0);
1140
						Position = UDim2.new(0, 0, 0, 0);						
1141
						BackgroundTransparency = 1.0;
1142
						--ClipsDescendants = true;
1143
						ZIndex = 0.0;		
1144
						Active = false;	
1145
1146
					};					
1147
				};		
1148
1149
	Spawn(function()
1150
		wait(0.5)
1151
		if IsPhone() then 
1152
			self.Frame.Size = UDim2.new(0, 280, 0, 120)
1153
		end 
1154
	end)					
1155
	
1156
	self.RenderFrame = self.Frame.ChatRenderFrame 		
1157
	if Chat:IsTouchDevice() then 
1158
		self.Frame.Position = self.Configuration.Position;
1159
		self.RenderFrame.Size = UDim2.new(1, 0, 1, 0)
1160
	elseif self.Frame.AbsoluteSize.Y > 120 then 
1161
		Chat:ScreenSizeChanged() 
1162
		self.Gui.Changed:connect(function(property)
1163
			if property == 'AbsoluteSize' then 
1164
				Chat:ScreenSizeChanged()
1165
			end 
1166
		end)
1167
	end 		
1168
1169
	if forceChatGUI or true then 			
1170
		if Chat:IsTouchDevice() then   
1171
			Chat:CreateTouchButton() 	
1172
		else 
1173
			Chat:CreateChatBar()
1174
			--Chat:CreateSafeChatGui()
1175
		end 
1176
1177
		if self.ChatBar then 
1178
			self.ChatBar.FocusLost:connect(function(enterPressed)
1179
				Chat.GotFocus = false 
1180
				if Chat:IsTouchDevice() then 
1181
 					self.ChatBar.Visible = false 
1182
					self.TapToChatLabel.Visible = true 
1183
1184
					if self.TouchLabelBackground then 
1185
						self.TouchLabelBackground.Visible = true 
1186
					end 
1187
				end 
1188
				if enterPressed and self.ChatBar.Text ~= "" then 
1189
				
1190
					local cText = self.ChatBar.Text
1191
					if string.sub(self.ChatBar.Text, 1, 1)  == '%' then 
1192
						cText = '(TEAM) ' .. string.sub(cText, 2, #cText)
1193
						pcall(function() PlayersService:TeamChat(cText) end)						
1194
					else 
1195
						pcall(function() PlayersService:Chat(cText) end)						
1196
					end 					
1197
					
1198
					if self.ClickToChatButton then 
1199
						self.ClickToChatButton.Visible = true 
1200
					end 
1201
					self.ChatBar.Text = ""								
1202
				end 
1203
				Spawn(function()
1204
					wait(5.0)
1205
					if not Chat.GotFocus then 						
1206
						Chat.Frame.Background.Visible = false 
1207
					end 
1208
				end)		
1209
			end)	
1210
		end 
1211
	end 
1212
end
1213
1214
-- Scrolling function
1215
-- Applies a speed(velocity) to have nice scrolling effect
1216
function Input:OnMouseScroll()
1217
	Spawn(function()
1218
		-- How long should the speed last? 
1219
		while Input.Speed ~=0 do 
1220
			if Input.Speed > 1 then 
1221
				while Input.Speed > 0 do 			
1222
					Input.Speed = Input.Speed - 1 
1223
					wait(0.25)
1224
				end 
1225
			elseif Input.Speed < 0 then 				
1226
				while Input.Speed < 0 do 			
1227
					Input.Speed = Input.Speed + 1
1228
					wait(0.25)
1229
				end 
1230
			end 
1231
			wait(0.03)
1232
		end 
1233
	end)
1234
	if Chat:CheckIfInBounds(Input.Speed) then 
1235
		return 
1236
	end 
1237
	Chat:ScrollQueue()
1238
end
1239
1240
function Input:ApplySpeed(value)
1241
	Input.Speed = Input.Speed + value
1242
	if not self.Simulating then 
1243
		Input:OnMouseScroll()
1244
	end
1245
end
1246
1247
function Input:Initialize()
1248
	self.Mouse.WheelBackward:connect(function()
1249
		Input:ApplySpeed(self.Configuration.DefaultSpeed)
1250
	end)
1251
1252
	self.Mouse.WheelForward:connect(function()
1253
		Input:ApplySpeed(self.Configuration.DefaultSpeed)
1254
	end)
1255
end
1256
1257
function Chat:FindMessageInSafeChat(message, list)
1258
	local foundMessage =  false 
1259
	for msg, _ in pairs(list) do 		
1260
		if msg == message then 			
1261
			return true
1262
		end 
1263
		if type(list[msg]) == 'table' then 
1264
			foundMessage = Chat:FindMessageInSafeChat(message, list[msg])
1265
			if foundMessage then 
1266
				return true 
1267
			end 
1268
		end 
1269
	end 
1270
	return foundMessage
1271
end
1272
1273
-- Just a wrapper around our PlayerChatted event 
1274
function Chat:PlayerChatted(...)	
1275
	local args = {...}
1276
	local argCount = select('#', ...)
1277
	local player
1278
	local message 
1279
	-- This doesn't look very good, but what else to do?
1280
	if args[2] then 
1281
		player = args[2]
1282
	end
1283
	if args[3] then 
1284
		message = args[3]
1285
		if string.sub(message, 1, 1) == '%' then 
1286
			message = '(TEAM) ' .. string.sub(message, 2, #message)
1287
		end 
1288
	end 
1289
1290
--	if PlayersService.ClassicChat then 			
1291
		if string.sub(message, 1, 3) == '/e ' or string.sub(message, 1, 7) == '/emote ' then 	
1292
			-- don't do anything right now
1293
		elseif forceChatGUI or true then 
1294
			Chat:UpdateChat(player, message) 
1295
		elseif true and string.sub(message, 1, 3) == '/sc' then 			
1296
			Chat:UpdateChat(player, message)			
1297
		else 
1298
			if Chat:FindMessageInSafeChat(message, self.SafeChat_List) then 
1299
				Chat:UpdateChat(player, message)
1300
			end 
1301
		end 
1302
--	end 
1303
end
1304
1305
-- After Chat.Configuration.Lifetime seconds of existence, the labels become invisible 
1306
-- Runs only every 5 seconds and has to loop through 50 values
1307
-- Shouldn't be too expensive 
1308
function Chat:CullThread()
1309
	while true do 
1310
		if #self.MessageQueue > 0 then 
1311
			for _, field in pairs(self.MessageQueue) do 				
1312
				if field['SpawnTime'] and field['Player'] and field['Message'] and tick() - field['SpawnTime'] > self.Configuration.LifeTime then 
1313
					field['Player'].Visible = false 
1314
					field['Message'].Visible = false 
1315
				end 
1316
			end 
1317
		end 
1318
		wait(5.0)
1319
	end
1320
end
1321
1322
-- RobloxLock everything so users can't delete them(?) 
1323
function Chat:LockAllFields(gui)
1324
	local children = gui:GetChildren()
1325
	for i = 1, #children do 
1326
		children[i].RobloxLocked = true 
1327
		if #children[i]:GetChildren() > 0 then 
1328
			Chat:LockAllFields(children[i])
1329
		end 
1330
	end 
1331
end
1332
1333
function Chat:CoreGuiChanged(coreGuiType,enabled)
1334
	if coreGuiType == Enum.CoreGuiType.Chat or coreGuiType == Enum.CoreGuiType.All then
1335
		if self.Frame then self.Frame.Visible = enabled end
1336
1337
		if not Chat:IsTouchDevice() and self.ChatBar then 
1338
			self.ChatBar.Visible = enabled 
1339
			if enabled then
1340
				GuiService:SetGlobalGuiInset(0, 0, 0, 20)
1341
			else
1342
				GuiService:SetGlobalGuiInset(0, 0, 0, 0)
1343
			end
1344
		end
1345
	end
1346
end
1347
1348
_G.ChatHistory = _G.ChatHistory or {}
1349
function RunChatHistory(max)
1350
	for i=#_G.ChatHistory-max, #_G.ChatHistory do
1351
		local player, message = unpack(_G.ChatHistory[i] or {})
1352
		
1353
		if player ~= nil and message ~= nil then
1354
			export:SendChat(player.Name, message, nil, true)
1355
		end
1356
1357
	end
1358
end
1359
1360
function AddToChatHistory(player, message)
1361
	table.insert(_G.ChatHistory, {player, message})
1362
end
1363
1364
-- Constructor 
1365
-- This function initializes everything 
1366
function Chat:Initialize()			
1367
1368
	Chat:CreateGui()
1369
	
1370
	function PlayerChatted(...)
1371
		Chat:PlayerChatted(...)
1372
	end
1373
	
1374
	function OnPlayer(p)
1375
		if p:IsA 'Player' then
1376
			p.Chatted:connect(function(chat)
1377
				PlayerChatted(
1378
					Enum.PlayerChatType.All,
1379
					p,
1380
					chat,
1381
					nil
1382
				)
1383
			end)
1384
		end
1385
	end
1386
	
1387
	for _,p in pairs(game.Players:GetPlayers()) do
1388
		OnPlayer(p)
1389
	end
1390
	
1391
	game.Players.ChildAdded:connect(OnPlayer)
1392
1393
	self.EventListener = script.ChildAdded:connect(function(...) 	
1394
		-- This event has 4 callback arguments 
1395
		-- Enum.PlayerChatType.All, chatPlayer, message, targetPlayer 
1396
		-- Chat:PlayerChatted(...)
1397
		
1398
	end)
1399
1400
	-- Initialize input for us 
1401
--	Input:Initialize() 	
1402
	-- Eww, everytime a player is added, you have to redo the connection
1403
	-- Seems this is not automatic
1404
--	-- NOTE: PlayerAdded only fires on the server, hence ChildAdded is used here 
1405
--	PlayersService.ChildAdded:connect(function()
1406
--		Chat.EventListener:disconnect()  
1407
--		self.EventListener = PlayersService.PlayerChatted:connect(function(...) 	
1408
--			-- This event has 4 callback arguments 
1409
--			-- Enum.PlayerChatType.All, chatPlayer, message, targetPlayer 
1410
--			Chat:PlayerChatted(...)
1411
--		end)
1412
--	end)
1413
1414
	Spawn(function()
1415
		Chat:CullThread() 
1416
	end)
1417
 
1418
--	Chat:LockAllFields(self.Frame)
1419
--	self.Frame.DescendantAdded:connect(function(descendant)
1420
----		Chat:LockAllFields(descendant)
1421
--	end)	
1422
end
1423
1424
Chat:Initialize()
1425
1426
RunChatHistory(10)
1427
1428
_G.ChatAPI = export