· 9 years ago · Jan 08, 2017, 06:28 PM
1--module for return
2local module = {}
3
4--default data model
5local defaultData = {level = 1, nextLevel = 500, xp = 0, kills = 0, deaths = 0, skins = {"Default Sword"}, selectedSkin = "Default Sword", selectedPerk = nil, permanentPerks = {}, coins = 10, premiumCoins = 0, musicMuted = false}
6
7--hold data for the current session
8_G.sessionData = {}
9_G.tradeOffers = {}
10
11--datastore variable
12local DataStoreService = game:GetService('DataStoreService')
13local playerData = DataStoreService:GetDataStore('PlayerData')
14
15--points service
16local PointsService = game:GetService('PointsService')
17
18--safely setup google analytics
19local GA = nil
20spawn(function()
21 GA = require(153590792)
22 GA.Init("UA-89031413-1", {DoNotReportScriptErrors = true; DoNotTrackServerStart = true; DoNotTrackVists = true;})
23end)
24
25--set to true to reset all data completely
26local resetData = false
27
28--loads player data into the session data or creates new data if none previously existed
29function module:LoadPlayerData(player)
30 local data = playerData:GetAsync(player.UserId)
31 if not data or resetData then
32 --if data doesnt exist, we need to create new data for the player
33 data = defaultData
34 playerData:SetAsync(player.UserId, data)
35 end
36 --check for data added later that the player might not have
37 if data['coins'] == nil then
38 data['coins'] = 10
39 end
40 if data['premiumCoins'] == nil then
41 data['premiumCoins'] = 0
42 end
43 if data['musicMuted'] == nil then
44 data['musicMuted'] = false
45 end
46 local ownsElite = false
47 pcall(function() ownsElite = game.MarketplaceService:PlayerOwnsAsset(player, 582887234) end)
48 if data['elite'] == nil and ownsElite then
49 --make the data elite
50 data['elite'] = true
51 --give player elite sword
52 table.insert(data['skins'], "Elite Sword")
53 end
54
55 --set the players data in the sessionData
56 _G.sessionData[player] = data
57
58 --setup player trades
59 _G.tradeOffers[player] = {}
60end
61
62--saves and unloads player data from session data
63function module:UnloadPlayerData(player)
64 playerData:SetAsync(player.UserId, _G.sessionData[player])
65 _G.sessionData[player] = nil
66
67 --remove player from tradeoffers data
68 _G.tradeOffers[player] = nil
69end
70
71--saves the data to the server
72function module:SaveData(player)
73 playerData:SetAsync(player.UserId, _G.sessionData[player])
74end
75
76--checks if data is loaded
77function module:IsDataReady(player)
78 return _G.sessionData[player] ~= nil
79end
80
81--saves all player data loaded
82function module:SaveAll()
83 for player, data in pairs(_G.sessionData) do
84 module:SaveData(player)
85 end
86end
87
88--adds a kill to the players stats
89function module:AddKill(player)
90 _G.sessionData[player]['kills'] = _G.sessionData[player]['kills'] + 1
91end
92
93--gets the players kill stats
94function module:GetKills(player)
95 return _G.sessionData[player]['kills']
96end
97
98--adds a death to the players stats
99function module:AddDeath(player)
100 _G.sessionData[player]['deaths'] = _G.sessionData[player]['deaths'] + 1
101end
102
103--gets the players death stats
104function module:GetDeaths(player)
105 return _G.sessionData[player]['deaths']
106end
107
108--adds an amount of xp to the players current amount of xp
109function module:AddXp(player, amount)
110 local data = _G.sessionData[player]
111 local actualAmount = amount
112 if data['elite'] ~= nil then
113 actualAmount = actualAmount*2
114 end
115 --add the amount to the xp
116 data['xp'] = data['xp'] + actualAmount
117
118 --add coins
119 module:AddCoins(player, math.floor(actualAmount/100))
120
121 --notify player of xp
122 workspace.RemoteFunctions.XpGain:FireClient(player, actualAmount)
123
124 --add points to the players points
125 pcall(function() PointsService:AwardPoints(player.UserId, actualAmount) end)
126
127 --check to see if the player leveled up
128 if data['xp'] >= data['nextLevel'] and data['level'] ~= 40 then
129 --player leveled up, increase level
130 data['level'] = data['level'] + 1
131
132 --let player know they leveled
133 workspace.RemoteFunctions.LevelUp:FireClient(player)
134
135 --calculate next level xp
136 data['nextLevel'] = (350 * math.pow(data['level']+1, 2)) - (550 * (data['level']+1)) + 200
137
138 --update leaderboard
139 game.Players[player].leaderstats.Level.Value = data['level']
140 end
141end
142
143--returns a tuple, the first value is the percentage til the next level, the second is the xp value of the next level, third is the current xp value
144function module:PercentToNextLevel(player)
145 local data = _G.sessionData[player]
146 local prevLevel = (350 * math.pow(data['level'], 2)) - (550 * (data['level'])) + 200
147 local nextLevel = (350 * math.pow(data['level']+1, 2)) - (550 * (data['level']+1)) + 200
148
149 return (data['xp'] - prevLevel)/(nextLevel - prevLevel), nextLevel - prevLevel, data['xp'] - prevLevel
150end
151
152--returns the players total xp
153function module:GetXp(player)
154 return _G.sessionData[player]['xp']
155end
156
157--returns the players level
158function module:GetLevel(player)
159 return _G.sessionData[player]['level']
160end
161
162--returns the total xp needed for the next level
163function module:GetNextLevel(player)
164 return _G.sessionData[player]['nextLevel']
165end
166
167--gets the amount of xp til the player next levels
168function module:GetXpToLevel(player)
169 local data = _G.sessionData[player]
170 return data.nextLevel - data['xp']
171end
172
173--adds a skin to the players inventory
174function module:AddSkin(player, skinId, source)
175 table.insert(_G.sessionData[player]['skins'], skinId)
176
177 --send data to the client
178 pcall(function() GA.ReportEvent("Skins", "SkinAdded", source .. ": " .. player.UserId .. ", " .. skinId, 1) end)
179end
180
181--removes an array of skins from the players inventory
182function module:RemoveSkins(player, skinList)
183 for _,skin in ipairs(skinList) do
184 for i,v in ipairs(_G.sessionData[player]['skins']) do
185 if v == skin then
186 --remove this skin
187 table.remove(_G.sessionData[player]['skins'], i)
188 break
189 end
190 end
191
192 if skin == _G.sessionData[player]['selectedSkin'] then
193 _G.sessionData[player]['selectedSkin'] = "Default Sword"
194 end
195 end
196
197 return skinList
198end
199
200--adds an array of skins to the players inventory
201function module:AddSkins(player, skinList)
202 for _,skin in ipairs(skinList) do
203 table.insert(_G.sessionData[player]['skins'], skin)
204 end
205end
206
207--returns a table of all of a players skins
208function module:GetSkins(player)
209 --get the data for the player from the session
210 local sessionArray = _G.sessionData[player]['skins']
211 if sessionArray ~= nil then
212 --if this data isn't nil then return the data
213 return sessionArray
214 end
215
216 --the data doesn't exist, this is most likely due to the game being tested in offline mode. return a default skin setup
217 return {"Default Sword"}
218end
219
220--gets all the tradable skins of a player
221function module:GetTradableSkins(player)
222 local tradableSkins = {}
223
224 for _, v in ipairs(_G.sessionData[player]['skins']) do
225 if game.ReplicatedStorage.Skins[v].Tradable.Value then
226 table.insert(tradableSkins, v)
227 end
228 end
229
230 return tradableSkins
231end
232
233--gets the currently selected skin of the player
234function module:GetCurrentSkin(player)
235 --get the data for the player from the session
236 local sessionSkin = _G.sessionData[player]['selectedSkin']
237 if sessionSkin ~= nil then
238 --player has a skin equipped, return value
239 return sessionSkin
240 end
241
242 --the data is not there likely to it being offline, return default sword
243 return "Default Sword"
244end
245
246--set the current skin
247function module:SetCurrentSkin(player, skin)
248 if module:PlayerHasSkin(player, skin) then
249 _G.sessionData[player]['selectedSkin'] = skin
250 end
251end
252
253--checks if a player has a skin
254function module:PlayerHasSkin(player, skin)
255 local hasSkin = false
256 for i,v in ipairs(_G.sessionData[player]['skins']) do
257 if v == skin then
258 hasSkin = true
259 break
260 end
261 end
262
263 return hasSkin
264end
265
266--sets the players current active perk if they have it unlocked, returns true if the perk was equipped and false if it wasnt
267function module:SetActivePerk(player, perk)
268 local data = _G.sessionData[player]
269
270 --loop and check if the player has this perk
271 local unlocked = false
272 for _,v in ipairs(data['permanentPerks']) do
273 if v == perk then
274 unlocked = true
275 end
276 end
277
278 --check to see what perk we're trying to equip
279 if (perk == "Steady Feet" and data['level'] >= 16) or (perk == "Steady Feet" and unlocked)
280 or (perk == "Ninja" and data['level'] >= 18) or (perk == "Ninja" and unlocked)
281 or (perk == "Super Strength" and data['level'] >= 26) or (perk == "Super Strength" and unlocked)
282 or (perk == "Vampire" and data['level'] >= 30) or (perk == "Vampire" and unlocked)
283 or (perk == "Sharpened Blade" and data['level'] >= 40) or (perk == "Sharpened Blade" and unlocked) then
284
285 --select perk and return true
286 _G.sessionData[player]['selectedPerk'] = perk
287 print(game:GetService('HttpService'):JSONEncode(_G.sessionData[playerId]))
288 return true
289 end
290
291 --if no perk was selected return false
292 return false
293end
294
295--returns a players current active perk
296function module:GetSelectedPerk(player)
297 return _G.sessionData[player]['selectedPerk']
298end
299
300--returns all of the players purchased permanent perks
301function module:GetPermanentPerks(player)
302 return _G.sessionData[player]['permanentPerks']
303end
304
305--checks if the player has a perk permanently unlocked
306function module:HasPermanentPerk(player, perk)
307 local data = _G.sessionData[player]['permanentPerks']
308 local has = false
309
310 for _,v in ipairs(data) do
311 if v == perk then
312 has = true
313 end
314 end
315
316 return has
317end
318
319--adds a permanent perk to the perk list
320function module:AddPermanentPerk(player, perk)
321 if not module:HasPermanentPerk(player, perk) then
322 table.insert(_G.sessionData[player]['permanentPerks'], 1, perk)
323 end
324end
325
326--checks the player for purchased perks and adds ones that have not been added
327function module:CheckPurchasedPerks(player)
328 local market = game:GetService('MarketplaceService')
329
330 if market:PlayerOwnsAsset(player, 574783611) then
331 module:AddPermanentPerk(player, "Steady Feet")
332 end
333
334 if market:PlayerOwnsAsset(player, 574783747) then
335 module:AddPermanentPerk(player, "Ninja")
336 end
337
338 if market:PlayerOwnsAsset(player, 574783928) then
339 module:AddPermanentPerk(player, "Super Strength")
340 end
341
342 if market:PlayerOwnsAsset(player, 574783847) then
343 module:AddPermanentPerk(player, "Vampire")
344 end
345
346 if market:PlayerOwnsAsset(player, 574784041) then
347 module:AddPermanentPerk(player, "Sharpened Blade")
348 end
349end
350
351--reports an event to google analytics
352function module:ReportEvent(category, action, label, value)
353 pcall(function() GA.ReportEvent(category, action, label, value) end)
354end
355
356--checks if the player has set to ignore the tutorial
357function module:IsTutorialComplete(player)
358 return _G.sessionData[player]['tutorialComplete']
359end
360
361--sets the tutorial complete for a player
362function module:SetTutorialComplete(player)
363 _G.sessionData[player]['tutorialComplete'] = true
364end
365
366--gets the players coin balance
367function module:GetCoins(player)
368 return _G.sessionData[player]['coins']
369end
370
371--adds a set amount of coins to the players balance
372function module:AddCoins(player, amount)
373 _G.sessionData[player]['coins'] = _G.sessionData[player]['coins'] + amount
374end
375
376--gets the players premium coin balance
377function module:GetPremiumCoins(player)
378 return _G.sessionData[player]['premiumCoins']
379end
380
381--adds premium coins to the players balance
382function module:AddPremiumCoins(player, amount)
383 _G.sessionData[player]['premiumCoins'] = _G.sessionData[player]['premiumCoins'] + amount
384end
385
386--mutes or unmutes music for the player
387function module:ToggleMute(player)
388 _G.sessionData[player]['musicMuted'] = not _G.sessionData[player]['musicMuted']
389end
390
391--returns true if music is muted, false if it isnt.
392function module:IsMusicMuted(player)
393 return _G.sessionData[player]['musicMuted']
394end
395
396--checks if a player has all of the skins in an array, returns true if they do, false if they dont
397function module:PlayerHasAllSkins(player, skinArray)
398 --create a temporary inventory
399 local inventory = {}
400 for _, v in ipairs(_G.sessionData[player]['skins']) do
401 table.insert(inventory, v)
402 end
403
404 local matched = 0
405 --begin checking each skin
406 for ci, check in ipairs(skinArray) do
407 --check if skin is tradable
408 if game.ReplicatedStorage.Skins:FindFirstChild(check).Tradable.Value then
409 --iterate through inventory
410 for i,v in ipairs(inventory) do
411 if v == check then
412 --this skin is the right skin, remove it from both inventories
413 table.remove(inventory, i)
414 matched = matched + 1
415 break
416 end
417 end
418 end
419 end
420
421 return #skinArray == matched
422end
423
424--attempts to post a trade offer to a player, returns whether or not the trade was able to be posted
425function module:SendTrade(playerFrom, playerTo, tradeData)
426 --first check if both players are ingame
427 if game.Players:FindFirstChild(playerFrom.Name) ~= nil and game.Players:FindFirstChild(playerTo.Name) ~= nil then
428 --players are both ingame, now check if both players have all the skins
429 if module:PlayerHasAllSkins(playerFrom, tradeData['offer']) and module:PlayerHasAllSkins(playerTo, tradeData['tradeFor']) then
430 --this offer can be sent! Place this offer in the trade array and send notifications
431 table.insert(_G.tradeOffers[playerTo], tradeData)
432
433 --TODO send notifications
434 workspace.RemoteFunctions.TradeOffer:FireClient(playerTo, playerFrom)
435 return true
436 end
437 end
438
439 return false
440end
441
442--returns all trade offers for this player
443function module:GetTradeOffers(player)
444 return _G.tradeOffers[player]
445end
446
447--attempts to accept a trade offer, if the trade was accepted this will return true
448function module:AcceptTradeOffer(player, offerInfo)
449 local function compareTables(table1, table2)
450 local offer = true
451 local tradeFor = true
452
453 for i,v in ipairs(table1['offer']) do
454 if v ~= table2['offer'][i] then
455 offer = false
456 end
457 end
458
459 for i,v in ipairs(table1['tradeFor']) do
460 if v ~= table2['tradeFor'][i] then
461 tradeFor = false
462 end
463 end
464
465 return offer and tradeFor and table1['from'] == table2['from']
466 end
467
468 --make sure the offer exists
469 for offerIndex,tradeOffer in ipairs(_G.tradeOffers[player]) do
470 if compareTables(tradeOffer, offerInfo) then
471 --this is the correct trade, remove trade from offer list
472 table.remove(_G.tradeOffers[player], offerIndex)
473
474 --check if both players are still online
475 if game.Players:FindFirstChild(player.Name) ~= nil and game.Players:FindFirstChild(offerInfo['from']) ~= nil then
476 --check if skins still exist in both inventories
477 if module:PlayerHasAllSkins(player, offerInfo['tradeFor']) and module:PlayerHasAllSkins(game.Players:FindFirstChild(offerInfo['from']), offerInfo['offer']) then
478 --trade is valid, we can now accept the offer and transfer skins
479 --add skins to this players inventory
480 module:AddSkins(player, module:RemoveSkins(game.Players[offerInfo['from']], offerInfo['offer']))
481 --add skins to other players inventory
482 module:AddSkins(game.Players[offerInfo['from']], module:RemoveSkins(player, offerInfo['tradeFor']))
483
484 --TODO send notifications
485 workspace.RemoteFunctions.AcceptTrade:FireClient(player, game.Players:FindFirstChild(offerInfo['from']))
486 workspace.RemoteFunctions.AcceptTrade:FireClient(game.Players[offerInfo['from']], player)
487 return true
488 end
489 end
490 end
491 end
492
493 return false
494end
495
496--declines a trade offer and removes it from the trade list
497function module:DeclineTradeOffer(player, offerInfo)
498 local function compareTables(table1, table2)
499 local offer = true
500 local tradeFor = true
501
502 for i,v in ipairs(table1['offer']) do
503 if v ~= table2['offer'][i] then
504 offer = false
505 end
506 end
507
508 for i,v in ipairs(table1['tradeFor']) do
509 if v ~= table2['tradeFor'][i] then
510 tradeFor = false
511 end
512 end
513
514 return offer and tradeFor and table1['from'] == table2['from']
515 end
516
517 for i,v in ipairs(_G.tradeOffers[player]) do
518 print(offerInfo)
519 if compareTables(v, offerInfo) then
520 print'same'
521 table.remove(_G.tradeOffers[player], i)
522 break
523 end
524 end
525end
526
527--unlocks elite for the player
528function module:UnlockElite(player)
529 --make the data elite
530 _G.sessionData[player]['elite'] = true
531 --give player elite sword
532 module:AddSkin(player, "Elite Sword")
533end
534
535--return the module
536return module