-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcloudScript-constricted.txt
More file actions
170 lines (170 loc) · 74.9 KB
/
cloudScript-constricted.txt
File metadata and controls
170 lines (170 loc) · 74.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
function checkCarDataValidity(d,k){if(void 0==d.CustomData){try{var a={CarLvl:"1",EngineLvl:"0",ExhaustLvl:"0",GearboxLvl:"0",SuspensionLvl:"0"};server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:d.ItemInstanceId,Data:a});a={TiresLvl:"0",TurboLvl:"0",PaintId:"0",DecalId:"0",RimsId:"0"};server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:d.ItemInstanceId,Data:a});for(var b=0,e=0;e<k.Catalog.length;e++)if(k.Catalog[e].ItemId==d.ItemId){var c=
JSON.parse(k.Catalog[e].CustomData),b=parseInt(c.basePr);break}a={PlatesId:"0",WindshieldId:"0",Pr:b};server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:d.ItemInstanceId,Data:a})}catch(h){return"PlayFabError"}return{CarLvl:"1",EngineLvl:"0",ExhaustLvl:"0",GearboxLvl:"0",SuspensionLvl:"0",TiresLvl:"0",TurboLvl:"0",PaintId:"0",DecalId:"0",RimsId:"0",PlatesId:"0",WindshieldId:"0",Pr:b}}return"OK"}function generateFailObjCustom(d,k){return{Result:"Failed",propName:k}}
function generateFailObj(d){return{Result:"Failed",Message:d}}function generateErrObj(d){return{Result:"Error",Message:d}}
function CheckMaintenanceAndVersion(d){var k=!1,a="A.0.0.1";void 0!=d&&(k=d.debug,a=d.cVersion);if(void 0==a)return"update";d=server.GetTitleData({Key:["Maintenance","MinimumGameVersionActual_IOS","MinimumGameVersionActual"]});var b=d.Data.MinimumGameVersionActual,a=a.split(".");if(4!=a.length)return"maintenance";"ios"==a[0]&&(b=d.Data.MinimumGameVersionActual_IOS);if(void 0==b)return"maintenance";for(var e=!1,b=b.split("."),c=0;3>c;c++){var h=0;a.length>c+1&&(h=Number(a[c+1]));var g=0;b.length>c&&
(g=Number(b[c]));if(h!=g){h<g&&(e=!0);break}}return 1==e?"update":1==k?"OK":d.Data.Maintenance?"false"==d.Data.Maintenance?"OK":"maintenance":"maintenance"}function generateMaintenanceOrUpdateObj(d){return"maintenance"==d?{Result:"Maintenance",Message:"Servers are temporarily offline"}:{Result:"Update",Message:"Game needs to be updated"}}function generateInventoryChange(d,k){return{Result:"OK",Message:d,InventoryChange:k}}
function publishToLiveFeed(d,k,a){var b=server.GetTitleData({Keys:["LiveFeedDictionary"]});if(void 0!=b.Data.LiveFeedDictionary){var e=JSON.parse(b.Data.LiveFeedDictionary),c=b=0,h=1,g=1,f=k,l=a,m=0,t=0,v=!1,u={};u.ts=(new Date).getTime();try{m=Number(e.MetaData.HealthDecayPerMinute),t=Number(e.MetaData.MaxFeedHistory)}catch(w){log.debug("invalid metadata");return}try{var b=b+Number(e.ActorData.Base.health),c=c+Number(e.ActorData.Base.damage),y=server.GetPlayerStatistics({PlayFabId:d,StatisticNames:["IAPValue",
"Trophies"]}).Statistics,A=Number(GetValueFromStatistics(y,"IAPValue",0)),B=Number(GetValueFromStatistics(y,"Trophies",0)),b=b+Number(e.ActorData.IAPValue.health)*A,c=c+Number(e.ActorData.IAPValue.damage)*A,b=b+Number(e.ActorData.Trophies.health)*B,c=c+Number(e.ActorData.Trophies.damage)*B}catch(w){log.debug("error at liveFeed actor: "+w);return}try{void 0!=e.ActionsData[k]&&(b+=Number(e.ActionsData[k].health),c+=Number(e.ActionsData[k].damage),f=e.ActionsData[k].id,"true"==e.ActionsData[k].isUnique&&
(v=!0),e.ActionsData[k].valMultiplier&&(h=Number(e.ActionsData[k].valMultiplier.health),g=Number(e.ActionsData[k].valMultiplier.damage)))}catch(w){log.debug("error at liveFeed action: "+w);return}try{1==isNaN(a)?void 0!=e.DirectObjectData[a]&&(b+=Number(e.DirectObjectData[a].health),c+=Number(e.DirectObjectData[a].damage),l=e.DirectObjectData[a].id):(b+=h*Number(a),c+=g*Number(a),l=a)}catch(w){log.debug("error at liveFeed object: "+w);return}k=server.GetPlayerCombinedInfo({PlayFabId:d,InfoRequestParameters:{GetUserAccountInfo:!0}});
var n;try{n=k.InfoResultPayload.AccountInfo.TitleInfo.DisplayName}catch(w){log.debug("error at liveFeed nameget: "+w);return}log.debug("10");u.health=b;u.currentHealth=b;u.UserId=d;u.UserName=n;u.Action=f;u.Object=l;d=server.GetTitleInternalData({Keys:["LiveFeed"]});if(void 0!=d.Data.LiveFeed&&(d=JSON.parse(d.Data.LiveFeed),"OK"==ApplyDamageOverTimeToFeed(d,m))){var q;try{if(Number(t)<=Number(d.length)||1==v){q=Array(d.length);for(var m=!1,p=0;p<d.length;p++)if(d[p].Action==f&&1==v||d[p].currentHealth<
c&&0==v){m=!0;d.splice(p,1);break}0==m&&d.splice(q.length-1,1);for(p=0;p<d.length;p++)if(d[p].currentHealth<b){d.splice(p,0,u);q=d;break}}else for(q=Array(d.length+1),q[d.length]=u,p=0;p<d.length;p++)if(q[p]=d[p],d[p].currentHealth<b&&0==v||d[p].Action==f&&1==v){for(q[p]=u;p<d.length;p++)q[p+1]=d[p];break}}catch(w){log.debug("found error at feed replace/add: "+w);return}for(p=0;p<q.length;p++)if(null==q[p])return;q=JSON.stringify(q);server.SetTitleInternalData({Key:"LiveFeed",Value:q})}}}
function ApplyDamageOverTimeToFeed(d,k){if(void 0==d.length)return"Error";for(var a=(new Date).getTime(),b=0,e=0;e<d.length;e++)try{b=Math.abs(Number(d[e].ts)-Number(a))*Number(k),b/=6E4,b=Math.floor(b),d[e].currentHealth=Math.max(Number(d[e].health)-Number(b),0)}catch(c){d.splice(e,1)}return"OK"}
function updateUserProfileInfo(d,k){var a={};a.CarData=k;log.debug("carInfo is: "+k);var b=[];b.push({Key:"UserProfileInfo",Value:JSON.stringify(a)});a=server.UpdateUserReadOnlyData({PlayFabId:d,Data:b,Permission:"Public"});log.debug("playerData is: "+a)}
function updateCurrencySpentStatistic(d,k){var a=[],b,e=0,c=Number(k);if(!(isNaN(c)||0>=c)&&("SC"==d&&(b="MoneySpent"),"HC"==d&&(b="GoldSpent"),void 0!=b)){var h=server.GetPlayerStatistics({PlayFabId:currentPlayerId,StatisticNames:[b]});0<h.Statistics.length&&(e=Number(h.Statistics[0].Value));a.push({StatisticName:b,Version:"0",Value:e+c});server.UpdatePlayerStatistics({PlayFabId:currentPlayerId,Statistics:a})}}
function checkBalance(d,k,a,b){if("SC"==d){if(a<k)return generateFailObj("NotEnoughSC")}else if(b<k)return generateFailObj("NotEnoughHC");return"OK"}
function calculateLeague(d){var k=server.GetTitleData({Keys:["LeagueSubdivisions","SubdivisionTrophyRanges"]});if(void 0==k.Data.LeagueSubdivisions||void 0==k.Data.SubdivisionTrophyRanges)return 1;for(var a=JSON.parse(k.Data.LeagueSubdivisions).leagues,k=JSON.parse(k.Data.SubdivisionTrophyRanges).subdivisions,b=0;b<a.length;b++)if(!(Number(d)>Number(k[a[b]])))return b;return a.length-1}
function recalculateCarPr(d,k,a,b){var e=0,c;c=void 0===a?server.GetCatalogItems({CatalogVersion:"CarCards"}):a;for(a=0;a<c.Catalog.length;a++)if(c.Catalog[a].ItemId==k){e=JSON.parse(c.Catalog[a].CustomData);e=parseInt(e.basePr)+getObjectValueFromLevel(e,"prPerLvl",d.CarLvl);break}b=void 0===b?server.GetCatalogItems({CatalogVersion:"PartCards"}):b;d={Exhaust:d.ExhaustLvl,Engine:d.EngineLvl,Gearbox:d.GearboxLvl,Suspension:d.SuspensionLvl,Tires:d.TiresLvl,Turbo:d.TurboLvl};for(a=0;a<b.Catalog.length;a++)k=
JSON.parse(b.Catalog[a].CustomData),e+=getObjectValueFromLevel(k,"prPerLvl",Number(d[b.Catalog[a].ItemId]));return e}
function GenerateBlackMarket(d){var k=1,a=server.GetPlayerStatistics({PlayFabId:d,StatisticNames:["League"]});0!=a.Statistics.length&&(k=a.Statistics[0].Value.toString());0>=Number(k)&&(k=1);for(var b=server.GetCatalogItems({CatalogVersion:"PartCards"}),a=server.GetTitleData({PlayFabId:d,Keys:["BlackMarketResetMinutes","BlackMarketRarityBias"]}),e=JSON.parse(a.Data.BlackMarketRarityBias),c,h=[],g=[],f=[],l=0;l<b.Catalog.length;l++){c=JSON.parse(b.Catalog[l].CustomData);if(void 0==c)return generateErrObj("Part card "+
b.Catalog[l].ItemId+" has no custom data.");0==c.rarity&&h.push(b.Catalog[l].ItemId+"_"+c.BMCurrType+"_"+c.BMbasePrice+"_0_"+c.BMpriceIncrPerBuy);1==c.rarity&&g.push(b.Catalog[l].ItemId+"_"+c.BMCurrType+"_"+c.BMbasePrice+"_0_"+c.BMpriceIncrPerBuy);2==c.rarity&&f.push(b.Catalog[l].ItemId+"_"+c.BMCurrType+"_"+c.BMbasePrice+"_0_"+c.BMpriceIncrPerBuy)}b={};b.BMTime=(new Date).getTime();l=Math.floor(Math.random()*h.length);b.BMItem0=h[l];2<=h.length&&h.splice(l,1);Math.floor(100*Math.random())<Number(e.parts[2])?
h=f:(l=Number(e.parts[0])+Number(e.parts[1]),Math.floor(Math.random()*l)>=Number(e.parts[0])&&(h=g));b.BMItem1=h[Math.floor(Math.random()*h.length)];c=server.GetCatalogItems({CatalogVersion:"CarCards"});for(var m,h=[],g=[],f=[],l=0;l<c.Catalog.length;l++){m=JSON.parse(c.Catalog[l].CustomData);if(void 0==m)return generateErrObj("Car card "+c.Catalog[l].ItemId+" has no custom data.");Number(m.unlockedAtRank)>=Number(k)+1||("0"==m.rarity&&h.push(c.Catalog[l].ItemId+"_"+m.BMCurrType+"_"+m.BMbasePrice+
"_0_"+m.BMpriceIncrPerBuy),"1"==m.rarity&&g.push(c.Catalog[l].ItemId+"_"+m.BMCurrType+"_"+m.BMbasePrice+"_0_"+m.BMpriceIncrPerBuy),"2"==m.rarity&&f.push(c.Catalog[l].ItemId+"_"+m.BMCurrType+"_"+m.BMbasePrice+"_0_"+m.BMpriceIncrPerBuy))}k=Math.floor(Math.random()*h.length);b.BMItem2=h[k];2<=h.length&&h.splice(k,1);0>=g.length&&(0>=f.length?f=g=h:g=f);0>=f.length&&(f=g);Math.floor(100*Math.random())<Number(e.cars[2])?h=f:(l=Number(e.cars[0])+Number(e.cars[1]),Math.floor(Math.random()*l)>=Number(e.cars[0])&&
(h=g));k=Math.floor(Math.random()*h.length);b.BMItem3=h[k];server.UpdateUserInternalData({PlayFabId:d,Data:b});b.BMTime=60*parseInt(a.Data.BlackMarketResetMinutes);return b}function GetCurrentBlackMarket(d,k){var a={},b=new Date,e=[];e.push("BlackMarketResetMinutes");e=server.GetTitleData({PlayFabId:d,Keys:e});a.BMTime=60*parseInt(e.Data.BlackMarketResetMinutes)-Math.floor((b.getTime()-k.Data.BMTime.Value)/1E3);for(b=0;4>b;b++)a["BMItem"+b]=k.Data["BMItem"+b].Value;return a}
function GetValueFromStatistics(d,k,a){for(var b,e=0;e<d.length;e++)d[e].StatisticName===k&&(b=d[e]);return void 0===b?void 0!==a?a:0:Number(b.Value)}function GetVersionFromStatistics(d,k,a){for(var b,e=0;e<d.length;e++)d[e].StatisticName===k&&(b=d[e]);return void 0===b?void 0!==a?a:0:Number(b.Version)}function getCatalogItem(d,k){for(var a=server.GetCatalogItems({CatalogVersion:d}),b=0;b<a.Catalog.length;b++)if(a.Catalog[b].ItemId===k)return a.Catalog[b]}
function getObjectValueFromLevel(d,k,a,b){b||(b=0);if(!d[k]||!d[k].length)return b;var e=Number(d[k].length);a>=e&&(a=e-1);return Number(d[k][a])||b}function GiveUserPart(d,k,a,b){GiveUserCard(d,"PartsCards",k,a,b)}function GiveUserCarCard(d,k,a,b){GiveUserCard(d,"CarCards",k,a,b)}
function GiveUserCard(d,k,a,b,e){a=Number(a)<Number(b)?Number(a)+Math.floor(Math.random()*(Number(b)-Number(a))):Number(a);log.debug("cardsAmount: "+a);var c,h;for(b=0;b<e.Inventory.length;b++)if(e.Inventory[b].ItemId==d&&e.Inventory[b].CatalogVersion==k){c=e.Inventory[b].ItemInstanceId;h=void 0==e.Inventory[b].CustomData?a:void 0==e.Inventory[b].CustomData.Amount?a:isNaN(Number(e.Inventory[b].CustomData.Amount))?a:Number(e.Inventory[b].CustomData.Amount)+Number(h);break}if(void 0==c&&(h=a,c=[],c.push(d),
c=server.GrantItemsToUser({CatalogVersion:k,PlayFabId:e.PlayFabId,ItemIds:c}).ItemGrantResults[0].ItemInstanceId,void 0===c))return generateErrObj("grantRequest denied");a={Amount:h};log.debug("new amount is: "+h);server.UpdateUserInventoryItemCustomData({PlayFabId:e.PlayFabId,ItemInstanceId:c,Data:a});return{ItemId:d,CatalogVersion:k,CustomData:a}}function GetRandomCard(d,k){return void 0==d||void 0==d.length||0>=d.length?"ERROR":d[Math.floor(Math.random()*d.length)]}
function AddCardToListOfStacks(d,k,a,b){if(void 0==k)return k=[{ItemId:a,CatalogVersion:d,CustomData:{Amount:1}}];for(var e=0;e<k.length;e++)if(k[e].ItemId==a)return k[e].CustomData.Amount=Number(k[e].CustomData.Amount)+1,k;1==b?k.push({ItemId:a,CatalogVersion:d,CustomData:{Amount:1}}):k[Math.floor(Math.random()*k.length)].CustomData.Amount=Number(k[Math.floor(Math.random()*k.length)].CustomData.Amount)+1;return k}
function WeightedRandom(d,k){try{for(var a=0,b=0;b<d.length;b++)a+=Number(d[b]);for(var e=Math.floor(Math.random()*Number(a)),b=0;b<d.length;b++){if(e<=Number(d[b]))return b;e-=Number(d[b])}return 0}catch(c){return log.debug(c),0}}
handlers.buyChest=function(d,k){var a=CheckMaintenanceAndVersion(d);if("OK"!=a)return generateMaintenanceOrUpdateObj(a);a=server.GetUserInventory({PlayFabId:currentPlayerId});if("OK"!=checkBalance(d.curr,d.cost,a.VirtualCurrency.SC,a.VirtualCurrency.HC))return generateFailObj("not enough money");if(0<d.cost){a=server.SubtractUserVirtualCurrency({PlayFabId:currentPlayerId,VirtualCurrency:d.curr,Amount:d.cost});updateCurrencySpentStatistic(d.curr,d.cost);var b={};b[a.VirtualCurrency]=a.Balance;return generateInventoryChange("ChestBought",
{VirtualCurrency:b})}return generateInventoryChange("ChestBought",{})};
handlers.buyPremiumChest=function(d,k){var a=CheckMaintenanceAndVersion(d);if("OK"!=a)return generateMaintenanceOrUpdateObj(a);var a=server.GetPlayerStatistics({PlayFabId:currentPlayerId,StatisticNames:["TrophyCount"]}),b=0;0!=a.Statistics.length&&(b=a.Statistics[0].Value);for(var b=Number(b),a=Number(calculateLeague(b)),b=server.GetCatalogItems({CatalogVersion:"Chests"}),e,c,h=0;h<b.Catalog.length;h++)if(b.Catalog[h].ItemId==d.chestId){e=JSON.parse(b.Catalog[h].CustomData);c=b.Catalog[h].VirtualCurrencyPrices.HC;
if(void 0==c)return generateErrObj("Chest has INVALID PRICE TAG");break}if(void 0==e)return generateErrObj("Could not find chest with id: "+d.chestId+" in the Chests catalog, or this chest's custom data is undefined");b=server.GetUserInventory({PlayFabId:currentPlayerId});if(Number(c)>Number(b.VirtualCurrency.HC))return generateErrObj("Not enough HC.");server.SubtractUserVirtualCurrency({PlayFabId:currentPlayerId,VirtualCurrency:"HC",Amount:Number(c)});updateCurrencySpentStatistic("HC",c);e=GenerateChestBounty(currentPlayerId,
d.chestId,a,e);c=server.GetUserInventory({PlayFabId:currentPlayerId});a=UpdateExperience("Chests",d.chestId,"xpGain",0,!0);c.Experience=a;e={Result:"OK",ChestBounty:e,InventoryChange:c};publishToLiveFeed(currentPlayerId,"unlockedChest",d.chestId);return e};
handlers.claimDailyMission=function(d,k){var a=CheckMaintenanceAndVersion(d);if("OK"!=a)return generateMaintenanceOrUpdateObj(a);var a=Number(d.mIdx),b=server.GetUserInternalData({PlayFabId:currentPlayerId,Keys:["DailyMissionStatus"]});if(void 0==b.Data.DailyMissionStatus)return generateErrObj("No daily mission data found on server");var e=server.GetTitleData({PlayFabId:currentPlayerId,Keys:["DailyMissionData"]}),e=JSON.parse(e.Data.DailyMissionData),c=e.missionData[a].split("_"),b=JSON.parse(b.Data.DailyMissionStatus.Value),
h=b.dailyMissionClaimStatus;if(a>=h.length)return generateErrObj("Unlock index is out of bounds of playerData claim mission status array");if(1==h[a])return generateFailObj("Mission already claimed");h[a]=1;b={DailyMissionStatus:JSON.stringify({DailyStatus:b.DailyStatus,dailyMissionClaimStatus:h,timeStamp:b.timeStamp})};server.UpdateUserInternalData({PlayFabId:currentPlayerId,Data:b});if(a>=e.missionData.length)return generateErrObj("Unlock index is out of bounds of titleData claim mission reward array");
a=server.AddUserVirtualCurrency({PlayFabId:currentPlayerId,VirtualCurrency:c[1],Amount:Number(c[2])});e={};e[a.VirtualCurrency]=a.Balance;return generateInventoryChange("MissionClaimed",{VirtualCurrency:e})};
handlers.endDaily=function(d,k){var a=CheckMaintenanceAndVersion(d);if("OK"!=a)return generateMaintenanceOrUpdateObj(a);a=server.GetUserInternalData({PlayFabId:currentPlayerId,Keys:["DailyMissionStatus"]});if(void 0==a.Data.DailyMissionStatus)return generateErrObj("No daily mission data found on server");var b=server.GetTitleData({PlayFabId:currentPlayerId,Keys:["DailyMissionData"]}),e;tParsed=JSON.parse(b.Data.DailyMissionData);e=Number(tParsed.minutesToRefresh);for(var c=JSON.parse(a.Data.DailyMissionStatus.Value),
a=c.dailyMissionClaimStatus,h,b=-1,g=0;g<tParsed.missionData.length;g++)h=tParsed.missionData[g].split("_"),4>h.length&&generateErrObj("Title data is invalid!"),"OFF"==h[3]&&(a[g]=-1);for(g=0;g<c.dailyMissionClaimStatus.length;g++)if(-1!=a[g]&&0==a[g])return generateErrObj("Not all missions were claimed!");a=[0,0,0,0,0,0,0,0];g=new Date;g.getTime()-Number(c.timeStamp)>6E4*Number(e)?(h=2,e=g.getTime()):(h=0,b=60*Number(e)-Math.floor((g.getTime()-Number(c.timeStamp))/1E3),e=c.timeStamp);e={DailyMissionStatus:JSON.stringify({DailyStatus:h,
dailyMissionClaimStatus:a,timeStamp:e})};server.UpdateUserInternalData({PlayFabId:currentPlayerId,Data:e});e=server.GetPlayerStatistics({PlayFabId:currentPlayerId,StatisticNames:["TrophyCount"]});g=0;0!=e.Statistics.length&&(g=e.Statistics[0].Value);g=Number(g);e=Number(calculateLeague(g));for(var c=server.GetCatalogItems({CatalogVersion:"Chests"}),f,g=0;g<c.Catalog.length;g++)if("DailyMissionChest"==c.Catalog[g].ItemId){f=JSON.parse(c.Catalog[g].CustomData);break}if(void 0==f)return generateErrObj("Could not find chest with id: DailyMissionChest in the Chests catalog, or this chest's custom data is undefined");
f=GenerateChestBounty(currentPlayerId,"DailyMissionChest",e,f);e=server.GetUserInventory({PlayFabId:currentPlayerId});return{Result:"OK",Message:"DailyCompleted",ChestBounty:f,InventoryChange:e,DailyStatus:{status:h,claimStatus:a,timeRemaining:b}}};
handlers.endGame=function(d,k){var a=CheckMaintenanceAndVersion(d);if("OK"!=a)return generateMaintenanceOrUpdateObj(a);var b=server.GetTitleData({Key:["LeagueSubdivisions","SubdivisionTrophyRanges","RecUploadLock"]}),a=0,e,c=server.GetPlayerStatistics({PlayFabId:currentPlayerId,StatisticNames:["TrophyCount"]});0!=c.Statistics.length&&(a=c.Statistics[0].Value,1==d.debug&&log.debug("getting trophy count "+c.Statistics[0].Value));e=a=Number(a);var h=server.GetUserInternalData({PlayFabId:currentPlayerId,
Keys:["trophyLose","trophyWin","LastGameOutcome","LatestStreak"]}),c=void 0==h.Data.trophyLose||void 0==h.Data.trophyWin?45:Number(h.Data.trophyLose.Value)+Number(h.Data.trophyWin.Value),g=0,f="Loss";void 0!=h.Data.LatestStreak&&(g=Number(h.Data.LatestStreak.Value));1==isNaN(g)&&(g=0);void 0!=h.Data.LatestStreak&&(f=h.Data.LastGameOutcome.Value);void 0==f&&(f="Loss");h={quitLastGame:"false",LastGameOutcome:"Loss"};"rWin"==d.outcome&&(a+=c,h.LastGameOutcome="Win","Loss"==f?g=1:g++,ldata=server.GetLeaderboard({StatisticName:"TrophyCount",
StartPosition:0,MaxResultsCount:1}),null!=ldata.Leaderboard&&(1==d.debug&&log.debug("leaderboardData: "+ldata.Leaderboard[0]),ldata.Leaderboard[0].PlayFabId==currentPlayerId?1==d.debug&&log.debug("ALREADY IN FIRST PLACE IN LEADERBOARD"):(1==d.debug&&log.debug("WASN'T FIRST PLACE"),Number(ldata.Leaderboard[0].StatValue)<a&&(1==d.debug&&log.debug("BUT HE IS NOW!"),publishToLiveFeed(currentPlayerId,"topPlayer",a)),1==d.debug&&log.debug("DIFF: "+Number(ldata.Leaderboard[0].StatValue)+" vs "+a))));h.LatestStreak=
g;server.UpdateUserInternalData({PlayFabId:currentPlayerId,Data:h});var f=JSON.parse(d.recordingHeader),l=server.GetPlayerStatistics({PlayFabId:currentPlayerId,StatisticNames:"Wins TotalGamesCompleted LongestWinStreak BestDriftScore HighestLeagueReached TotalGames".split(" ")}).Statistics,c=calculateLeague(a),h=GetValueFromStatistics(l,"TotalGamesCompleted",0),m=!1,t=GetValueFromStatistics(l,"TotalGames",0);1>=Number(t)&&(m=!0);h=Number(h)+1;t=GetValueFromStatistics(l,"Wins",0);"rWin"==d.outcome&&
(t=Number(t)+1);var v=GetValueFromStatistics(l,"LongestWinStreak",0);GetVersionFromStatistics(l,"LongestWinStreak",0);Number(v)<g&&(v=g,2<c&&(10==Number(v)&&publishToLiveFeed(currentPlayerId,"winStreak",10),15==Number(v)&&publishToLiveFeed(currentPlayerId,"winStreak",15),20==Number(v)&&publishToLiveFeed(currentPlayerId,"winStreak",20)));g=GetValueFromStatistics(l,"BestDriftScore",0);Number(f.Score)>g&&(g=Number(f.Score));l=GetValueFromStatistics(l,"HighestLeagueReached",1);Number(c)>Number(l)&&(l=
c,2<l&&publishToLiveFeed(currentPlayerId,"arenaUnlocked",Number(c)));var u=[];u.push({StatisticName:"TrophyCount",Value:a});u.push({StatisticName:"League",Value:c});u.push({StatisticName:"Wins",Value:t});u.push({StatisticName:"TotalGamesCompleted",Value:h});u.push({StatisticName:"LongestWinStreak",Value:v});u.push({StatisticName:"BestDriftScore",Value:g});u.push({StatisticName:"HighestLeagueReached",Value:l});server.UpdatePlayerStatistics({PlayFabId:currentPlayerId,Statistics:u});"rWin"==d.outcome&&
0==m&&(4<Number(h)?grantUserChest(currentPlayerId,"endGameNormal"):grantUserChest(currentPlayerId,"endGameFreeWin"));var h=!1,y;void 0!=b.Data.RecUploadLock&&(y=JSON.parse(b.Data.RecUploadLock));if(void 0!=y)for(g=0;g<y.length;g++)if(d.cVersion==y[g]){h=!0;break}if(100>=Number(f.Score)||1==h)return 1==d.debug&&log.debug("this recording will not be stored, but endgame stats still apply. clientVersion: "+d.cVersion+". upload lock: "+h),a={TrophyCount:a,League:c},{Result:a};b=JSON.parse(b.Data.SubdivisionTrophyRanges);
y=43;for(g=0;g<b.subdivisions.length;g++)if(e<b.subdivisions[g]){y=g;break}e=[];e.push({Key:d.envIndex+"_"+d.courseIndex+"_RecPos",Value:d.recordingPos});e.push({Key:d.envIndex+"_"+d.courseIndex+"_RecRot",Value:d.recordingRot});e.push({Key:d.envIndex+"_"+d.courseIndex+"_RecHeader",Value:d.recordingHeader});server.UpdateUserReadOnlyData({PlayFabId:currentPlayerId,Data:e});e=server.GetTitleInternalData({Key:"RecSubDivision"+y}).Data["RecSubDivision"+y];if(void 0==e)e=[],b={e:d.envIndex,c:d.courseIndex,
uId:currentPlayerId},e.push(b);else{e=JSON.parse(e);b={e:d.envIndex,c:d.courseIndex,uId:currentPlayerId};f=!1;for(g=h=0;g<e.length;g++)e[g].uId==currentPlayerId&&h++;if(2<h)return a={TrophyCount:a,League:c},{Result:a};for(g=0;g<e.length;g++)e[g].e==d.envIndex&&e[g].c==d.courseIndex&&(f=!0,e[g]=b);0==f&&e.push(b)}e=JSON.stringify(e);server.SetTitleInternalData({Key:"RecSubDivision"+y,Value:e});a={TrophyCount:a,League:c};return{Result:a}};
handlers.endSeasonTitle=function(d,k){log.debug("context: "+JSON.stringify(k));try{var a=server.GetTitleData({Keys:["EndSezonObject"]}),b;log.debug("1: "+a);b=JSON.parse(a.Data.EndSezonObject);log.debug("2: "+b);b.endSezonTimestamp=Math.floor((new Date).getTime()/1E3)+3600;log.debug("3: "+b);server.SetTitleData({Key:"EndSezonObject",Value:JSON.stringify(b)});log.debug("4: "+b)}catch(e){log.debug("err: "+e)}};
handlers.logLegendRank=function(d,k){try{var a=server.GetTitleData({Keys:["EndSezonObject"]}),b,e;try{b=JSON.parse(a.Data.EndSezonObject),e=b.endSezonRewards}catch(h){log.debug("err: "+h);return}var c=server.GetLeaderboardAroundUser({StatisticName:"TrophyCount",PlayFabId:currentPlayerId,MaxResultsCount:1}).Leaderboard[0].Position;c<e.length&&server.UpdateUserReadOnlyData({PlayFabId:currentPlayerId,Data:{EndSeasonChest:e[Number(c)]}});c=Number(c)+1;server.UpdateUserReadOnlyData({PlayFabId:currentPlayerId,
Data:{RankLastSeason:c}})}catch(h){log.debug("err: "+h)}};
handlers.endSeasonUser=function(d,k){var a={didClaim:!0,scReceived:0,hcReceived:0,previousTrophies:0,currentTrophies:0},b=server.GetTitleData({Keys:["EndSezonObject","SubdivisionTrophyRanges"]});try{var e=JSON.parse(b.Data.EndSezonObject),c=server.GetPlayerStatistics({PlayFabId:currentPlayerId,StatisticNames:["TrophyCount"]}).Statistics,h=Number(c[0].Value);JSON.parse(b.Data.SubdivisionTrophyRanges);var g=Math.ceil(Number(e.scConversionRate)*(h-3001)),f=Math.ceil(Number(e.hcConversionRate)*(h-3001)),
a={didClaim:!1,scReceived:g,hcReceived:f,previousTrophies:h,currentTrophies:3001};server.UpdatePlayerStatistics({PlayFabId:currentPlayerId,Statistics:[{StatisticName:"TrophyCount",Value:3001}]});0<g&&server.AddUserVirtualCurrency({PlayFabId:currentPlayerId,VirtualCurrency:"SC",Amount:g});0<f&&server.AddUserVirtualCurrency({PlayFabId:currentPlayerId,VirtualCurrency:"HC",Amount:f})}catch(l){log.debug("err: "+l)}server.UpdateUserReadOnlyData({PlayFabId:currentPlayerId,Data:{EndSeasonReward:JSON.stringify(a)}})};
handlers.claimEndSeasonReward=function(d,k){try{var a=server.GetUserReadOnlyData({PlayFabId:currentPlayerId,Keys:["EndSeasonReward","EndSeasonChest"]});if(void 0==a.Data.EndSeasonReward)return generateFailObj("Nothing to claim");var b=JSON.parse(a.Data.EndSeasonReward.Value);b.didClaim=!0;server.UpdateUserReadOnlyData({PlayFabId:currentPlayerId,Data:{EndSeasonReward:JSON.stringify(b)}});if(void 0==a.Data.EndSeasonChest)return{Result:"OK",Message:"noChest"};var e=a.Data.EndSeasonChest.Value;if(null==
e)return{Result:"OK",Message:"noChest"};for(var c=server.GetCatalogItems({CatalogVersion:"Chests"}),h,a=0;a<c.Catalog.length;a++)if(c.Catalog[a].ItemId==e){h=JSON.parse(c.Catalog[a].CustomData);break}if(void 0==h)return generateErrObj("Could not find chest with id: "+e+" in the Chests catalog, or this chest's custom data is undefined");log.debug("generatung: "+e);var g=GenerateChestBounty(currentPlayerId,e,7,h),f=server.GetUserInventory({PlayFabId:currentPlayerId});server.UpdateUserReadOnlyData({PlayFabId:currentPlayerId,
Data:{EndSeasonChest:null}});return{Result:"OK",InventoryChange:f,ChestBounty:g}}catch(l){return log.debug("err: "+l),generateErrObj("something went wrong: "+l)}};
function UpdateExperience(d,k,a,b,e,c){d=JSON.parse(getCatalogItem(d,k).CustomData)[a];k=JSON.parse(getCatalogItem("Balancing","BalancingItem").CustomData).LevelThresholds;k=k[k.length-1];c=c||server.GetPlayerStatistics({PlayFabId:currentPlayerId,StatisticNames:["Experience"]}).Statistics;c=GetValueFromStatistics(c,"Experience",0);if(c>=k)return k;if(isNaN(Number(d)))a=Number(d.length),b>=a&&(b=a-1),b=Number(d[b]);else if(b=Number(d),0===b)return c;c=Math.min(c+b,k);if(!e)return c;server.UpdatePlayerStatistics({PlayFabId:currentPlayerId,
Statistics:[{StatisticName:"Experience",Version:"0",Value:c}]});return c}
handlers.generateDaily=function(d,k){var a,b=new Date;a=server.GetUserInternalData({PlayFabId:currentPlayerId,Keys:["DailyMissionStatus"]});if(void 0!=a.Data.DailyMissionStatus){var e=JSON.parse(a.Data.DailyMissionStatus.Value);a=Number(e.DailyStatus);if(0==a){var b=server.GetTitleData({PlayFabId:currentPlayerId,Keys:["DailyMissionData"]}),c;tParsed=JSON.parse(b.Data.DailyMissionData);c=Number(tParsed.minutesToRefresh);b=new Date;b.getTime()-Number(e.timeStamp)>6E4*Number(c)&&(a=1)}if(1!=a)return generateErrObj("DailyStatus is: "+
a+". Should be 1")}a=2;b=b.getTime();a={DailyMissionStatus:JSON.stringify({DailyStatus:a,dailyMissionClaimStatus:[0,0,0,0,0,0,0,0],timeStamp:b})};server.UpdateUserInternalData({PlayFabId:currentPlayerId,Data:a});return{Result:"OK"}};
handlers.getChestSlotsStatus=function(d,k){var a=CheckMaintenanceAndVersion(d);if("OK"!=a)return generateMaintenanceOrUpdateObj(a);var a=server.GetUserInternalData({PlayFabId:currentPlayerId,Keys:["ChestFreeStatus","ChestSlotsStatus"]}),b;if(void 0==a.Data.ChestFreeStatus){for(var e=server.GetCatalogItems({CatalogVersion:"Chests"}),c=0;c<e.Catalog.length;c++)if("FreeChest"==e.Catalog[c].ItemId){b=JSON.parse(e.Catalog[c].CustomData);break}if(void 0==b)return generateErrObj("Chest catalog has no freechestinfo");
b=Number(b.hoursToOpen.split(",")[0]);if(isNaN(b))return generateErrObj("FreeChest open time info is invalid");e=Math.floor(Number((new Date).getTime())/1E3);b=[{status:0,TimeUntilArrival:Math.floor(e+3600*b)},{status:1,TimeUntilArrival:0}];b=JSON.stringify(b);server.UpdateUserInternalData({PlayFabId:currentPlayerId,Data:{ChestFreeStatus:b}})}else b=a.Data.ChestFreeStatus.Value;void 0==a.Data.ChestSlotsStatus?(a=[{chestId:null,chestLeague:0,status:"Empty",orderTimeStamp:0,arrivalTimeStamp:0},{chestId:null,
chestLeague:0,status:"Empty",orderTimeStamp:0,arrivalTimeStamp:0},{chestId:null,chestLeague:0,status:"Empty",orderTimeStamp:0,arrivalTimeStamp:0},{chestId:null,chestLeague:0,status:"Empty",orderTimeStamp:0,arrivalTimeStamp:0}],c=server.GetPlayerStatistics({PlayFabId:currentPlayerId,StatisticNames:["ChestsOpened","TrophyCount"]}).Statistics,e=GetValueFromStatistics(c,"ChestsOpened",0),c=GetValueFromStatistics(c,"TrophyCount",0),c=calculateLeague(c),15<Number(e)&&(a[0].chestId="GoldChest",a[0].chestLeague=
c,a[0].status="Arrived",a[0].arrivalTimeStamp=0,a[0].orderTimeStamp=1),a=JSON.stringify(a),server.UpdateUserInternalData({PlayFabId:currentPlayerId,Data:{ChestSlotsStatus:a}})):a=a.Data.ChestSlotsStatus.Value;return{Result:"OK",ChestSlotInfo:JSON.parse(a),FreeSlotsInfo:JSON.parse(b)}};
handlers.getDailyMissionStatus=function(d,k){var a=CheckMaintenanceAndVersion(d);if("OK"!=a)return generateMaintenanceOrUpdateObj(a);var b,a=[0,0,0,0,0,0,0,0],e=-1;b=server.GetUserInternalData({PlayFabId:currentPlayerId,Keys:["DailyMissionStatus"]});if(void 0!=b.Data.DailyMissionStatus){var c=JSON.parse(b.Data.DailyMissionStatus.Value);b=Number(c.DailyStatus);var h=a.length;h>c.dailyMissionClaimStatus.length&&(h=c.dailyMissionClaimStatus.length);for(var g=0;g<h;g++)a[g]=c.dailyMissionClaimStatus[g];
0==b&&(h=server.GetTitleData({PlayFabId:currentPlayerId,Keys:["DailyMissionData"]}),tParsed=JSON.parse(h.Data.DailyMissionData),h=Number(tParsed.minutesToRefresh),g=new Date,g.getTime()-Number(c.timeStamp)>6E4*Number(h)?(b=2,a=[0,0,0,0,0,0,0,0],c=g.getTime(),c={DailyStatus:b,dailyMissionClaimStatus:a,timeStamp:c},c=JSON.stringify(c),c={DailyMissionStatus:c},server.UpdateUserInternalData({PlayFabId:currentPlayerId,Data:c})):e=60*Number(h)-Math.floor((g.getTime()-Number(c.timeStamp))/1E3))}else b=2,
g=new Date,c=g.getTime(),c={DailyStatus:b,dailyMissionClaimStatus:a,timeStamp:c},c=JSON.stringify(c),c={DailyMissionStatus:c},server.UpdateUserInternalData({PlayFabId:currentPlayerId,Data:c});return{Result:"OK",Message:" ",DailyStatus:{status:b,claimStatus:a,timeRemaining:e}}};
handlers.getLiveFeed=function(d,k){var a=CheckMaintenanceAndVersion(d);if("OK"!=a)return generateMaintenanceOrUpdateObj(a);a=server.GetTitleInternalData({Keys:"LiveFeed"});return void 0==a||void 0==a.Data.LiveFeed?generateErrObj("No LivefeedFound"):{Result:"OK",Feed:JSON.parse(a.Data.LiveFeed)}};handlers.getServerTime=function(d,k){return{time:new Date}};
handlers.iapMade=function(d,k){var a=server.GetPlayerStatistics({PlayFabId:currentPlayerId,StatisticNames:["IAPValue"]}).Statistics,b=Number(GetValueFromStatistics(a,"IAPValue",0));switch(d.bundle){case "co.tamatem.downshiftdrift.gold01":b+=99;break;case "co.tamatem.downshiftdrift.gold02":b+=499;break;case "co.tamatem.downshiftdrift.gold03":b+=2499;break;case "co.tamatem.downshiftdrift.gold04":b+=2499;break;case "co.tamatem.downshiftdrift.gold05":b+=4999;break;case "co.tamatem.downshiftdrift.gold06":b+=
9999;break;case "co.tamatem.downshiftdrift.bundle01":var b=b+599,e=server.GetUserInventory({PlayFabId:currentPlayerId}),c=server.GetCatalogItems({CatalogVersion:"BMBundleInfo"}),a=server.GetPlayerStatistics({PlayFabId:currentPlayerId,StatisticNames:["HighestLeagueReached"]}).Statistics,a=Number(GetValueFromStatistics(a,"HighestLeagueReached",1)),h="bundle01league",h=10>a?h+"0"+a:h+a;1==d.debug&&log.debug("consuming: "+h);for(var g,a=0;a<c.Catalog.length;a++)if(c.Catalog[a].ItemId==h){g=JSON.parse(c.Catalog[a].CustomData);
break}if(void 0==g)return generateErrObj("Catalog item: "+h+" not found");for(a=0;a<e.Inventory.length;a++)if(e.Inventory[a].ItemId==d.bundle){try{server.ConsumeItem({PlayFabId:currentPlayerId,ItemInstanceId:e.Inventory[a].ItemInstanceId,ConsumeCount:1})}catch(m){return generateErrObj("err: "+m)}var f;f=[];var l={};if(void 0!=g.HCRange){1==d.debug&&log.debug("found HCRange: "+g.HCRange);c=g.HCRange.split(",");if(2<=c.length)c=Number(c[0])<Number(c[1])?Number(c[0])+Math.floor(Math.random()*(Number(c[1])-
Number(c[0]))):Number(c[0]);else return generateErrObj("Catalog data corrupt");0<c&&(addUserCurrencyResult=server.AddUserVirtualCurrency({PlayFabId:currentPlayerId,VirtualCurrency:"HC",Amount:c}),l[addUserCurrencyResult.VirtualCurrency]=addUserCurrencyResult.Balance)}if(void 0!=g.SCRange){1==d.debug&&log.debug("found SCRange: "+g.SCRange);c=g.SCRange.split(",");if(2<=c.length)c=Number(c[0])<Number(c[1])?Number(c[0])+Math.floor(Math.random()*(Number(c[1])-Number(c[0]))):Number(c[0]);else return generateErrObj("Catalog data corrupt");
0<c&&(addUserCurrencyResult=server.AddUserVirtualCurrency({PlayFabId:currentPlayerId,VirtualCurrency:"SC",Amount:c}),l[addUserCurrencyResult.VirtualCurrency]=addUserCurrencyResult.Balance)}if(void 0!=g.Engine)if(1==d.debug&&log.debug("found Engine: "+g.Engine),c=g.Engine.split(","),2<=c.length)c=GiveUserPart("Engine",c[0],c[1],e),f.push(c);else return generateErrObj("Catalog data corrupt");if(void 0!=g.Exhaust)if(1==d.debug&&log.debug("found Exhaust: "+g.Exhaust),c=g.Exhaust.split(","),2<=c.length)c=
GiveUserPart("Exhaust",c[0],c[1],e),f.push(c);else return generateErrObj("Catalog data corrupt");if(void 0!=g.Gearbox)if(1==d.debug&&log.debug("found Gearbox: "+g.Gearbox),c=g.Gearbox.split(","),2<=c.length)c=GiveUserPart("Gearbox",c[0],c[1],e),f.push(c);else return generateErrObj("Catalog data corrupt");if(void 0!=g.Suspension)if(1==d.debug&&log.debug("found Suspension: "+g.Suspension),c=g.Suspension.split(","),2<=c.length)c=GiveUserPart("Suspension",c[0],c[1],e),f.push(c);else return generateErrObj("Catalog data corrupt");
if(void 0!=g.Tires)if(1==d.debug&&log.debug("found Tires: "+g.Tires),c=g.Tires.split(","),2<=c.length)c=GiveUserPart("Tires",c[0],c[1],e),f.push(c);else return generateErrObj("Catalog data corrupt");if(void 0!=g.Turbo)if(1==d.debug&&log.debug("found Turbo: "+g.Turbo),c=g.Turbo.split(","),2<=c.length)c=GiveUserPart("Turbo",c[0],c[1],e),f.push(c);else return generateErrObj("Catalog data corrupt");if(void 0!=g.CarCard&&(1==d.debug&&log.debug("found CarCard: "+g.CarCard),void 0!=g.CarCardAmount))if(1==
d.debug&&log.debug("found CarCardAmount: "+g.CarCardAmount),c=g.CarCardAmount.split(","),2<=c.length)c=GiveUserCarCard(g.CarCard,c[0],c[1],e),f.push(c);else return generateErrObj("Catalog data corrupt");void 0!=g.ChestModel&&1==d.debug&&log.debug("found ChestModel: "+g.ChestModel)}e=[];b={StatisticName:"IAPValue",Value:b};e.push(b);server.UpdatePlayerStatistics({PlayFabId:currentPlayerId,Statistics:e});f={Inventory:f,VirtualCurrency:l};return{Result:"OK",Message:"InventoryUpdate",InventoryChange:f};
default:1==d.debug&&log.debug("InvalidPurchaseParameter")}e=[];b={StatisticName:"IAPValue",Value:b};e.push(b);server.UpdatePlayerStatistics({PlayFabId:currentPlayerId,Statistics:e});publishToLiveFeed(currentPlayerId,"boughtIAP",d.bundle)};
handlers.initServerData=function(d){d=[];var k={StatisticName:"TrophyCount",Version:"0",Value:"0"};d.push(k);k={StatisticName:"League",Version:"0",Value:"0"};d.push(k);server.UpdatePlayerStatistics({PlayFabId:currentPlayerId,Statistics:d});d=server.GrantItemsToUser({CatalogVersion:"Customization",PlayFabId:currentPlayerId,ItemIds:["Decals","PaintJobs","Plates","Rims","WindshieldText"]});for(var k={0:"Owned"},a=0;a<d.ItemGrantResults.length;a++)server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,
ItemInstanceId:d.ItemGrantResults[a].ItemInstanceId,Data:k});d=[];d.push("FordFocus");d=server.GrantItemsToUser({CatalogVersion:"CarsProgress",PlayFabId:currentPlayerId,ItemIds:d});k={CarLvl:"1",EngineLvl:"0",ExhaustLvl:"0",GearboxLvl:"0",SuspensionLvl:"0"};server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:d.ItemGrantResults[0].ItemInstanceId,Data:k});k={TiresLvl:"0",TurboLvl:"0",PaintId:"0",DecalId:"0",RimsId:"0"};server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,
ItemInstanceId:d.ItemGrantResults[0].ItemInstanceId,Data:k});k={PlatesId:"0",WindshieldId:"0",Pr:"10"};server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:d.ItemGrantResults[0].ItemInstanceId,Data:k});k=[];k.push("Engine");k=server.GrantItemsToUser({CatalogVersion:"PartCards",PlayFabId:currentPlayerId,ItemIds:k});server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:k.ItemGrantResults[0].ItemInstanceId,Data:{Amount:"5"}});k={CarLvl:"1",EngineLvl:"0",
ExhaustLvl:"0",GearboxLvl:"0",SuspensionLvl:"0"};server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:d.ItemGrantResults[0].ItemInstanceId,Data:k})};
handlers.levelUp=function(d,k){var a=d.level,b=0,e=server.GetUserReadOnlyData({PlayFabId:currentPlayerId,Keys:["LastLevelReward"]}),c={LastLevelReward:0};void 0==e.Data.LastLevelReward?server.UpdateUserReadOnlyData({PlayFabId:currentPlayerId,Data:c}):b=e.Data.LastLevelReward.Value;var e=JSON.parse(getCatalogItem("Balancing","BalancingItem").CustomData).LevelThresholds,h=server.GetPlayerStatistics({PlayFabId:currentPlayerId,StatisticNames:["Experience"]}).Statistics,g=GetValueFromStatistics(h,"Experience",
0);0==g&&(h=[],h.push({StatisticName:"Experience",Version:"0",Value:0}),server.UpdatePlayerStatistics({PlayFabId:currentPlayerId,Statistics:h}));for(var h=e.length,f=0;f<e.length;f++)if(!(g>=e[f])){h=f;break}if(Number(a)<=Number(b))return generateFailObj("already got reward for level: "+b);if(Number(a)<=Number(h))b=Number(a),c.LastLevelReward=b,server.UpdateUserReadOnlyData({PlayFabId:currentPlayerId,Data:c}),a=""+b,a="000".substring(0,3-a.length)+a,server.GrantItemsToUser({CatalogVersion:"LevelUpRewards",
PlayFabId:currentPlayerId,ItemIds:a}),2<Number(h)&&publishToLiveFeed(currentPlayerId,"levelUp",Number(h));else return generateFailObj("You haven't reached this level yet");a=server.GetUserInventory({PlayFabId:currentPlayerId});return generateInventoryChange("InventoryUpdated",a)};
handlers.openChest=function(d,k){var a=CheckMaintenanceAndVersion(d);if("OK"!=a)return generateMaintenanceOrUpdateObj(a);server.GetUserInventory({PlayFabId:currentPlayerId});for(var b in d.currencyReq)0<d.currencyReq[b]&&server.AddUserVirtualCurrency({PlayFabId:currentPlayerId,VirtualCurrency:b,Amount:d.currencyReq[b]});a=server.GetUserInventory({PlayFabId:currentPlayerId});return generateInventoryChange("InventoryUpdated",a)};
handlers.openFreeChest=function(d,k){var a=CheckMaintenanceAndVersion(d);if("OK"!=a)return generateMaintenanceOrUpdateObj(a);var b=server.GetUserInternalData({PlayFabId:currentPlayerId,Keys:["ChestFreeStatus"]});if(void 0==b.Data.ChestFreeStatus)return generateErrObj("No Chest Data found!");for(var a=JSON.parse(b.Data.ChestFreeStatus.Value),e=-1,c=a.length-1;0<=c;c--)if(1==a[c].status||Number(a[c].TimeUntilArrival)<=Math.floor((new Date).getTime()/1E3)){log.debug("we found a free chest");e=c;break}if(-1==
e)return generateFailObjCustom("FreeSlotsInfo",JSON.parse(b.Data.ChestFreeStatus.Value));b=server.GetPlayerStatistics({PlayFabId:currentPlayerId,StatisticNames:["TrophyCount"]});c=0;0!=b.Statistics.length&&(c=b.Statistics[0].Value);for(var c=Number(c),b=Number(calculateLeague(c)),h=server.GetCatalogItems({CatalogVersion:"Chests"}),g,c=0;c<h.Catalog.length;c++)if("FreeChest"==h.Catalog[c].ItemId){g=JSON.parse(h.Catalog[c].CustomData);break}if(void 0==g)return generateErrObj("Could not find chest with id: FreeChest in the Chests catalog, or this chest's custom data is undefined");
h=Number(g.hoursToOpen.split(",")[0]);if(isNaN(h))return generateErrObj("FreeChest open time info is invalid");for(var f=Math.floor(Number((new Date).getTime())/1E3),c=0;c<a.length;c++)f<a[c].TimeUntilArrival&&(f=a[c].TimeUntilArrival);c=Math.floor(f+3600*h);a[e].status=0;a[e].TimeUntilArrival=c;e=JSON.stringify(a);server.UpdateUserInternalData({PlayFabId:currentPlayerId,Data:{ChestFreeStatus:e}});g=GenerateChestBounty(currentPlayerId,"FreeChest",b,g);e=server.GetUserInventory({PlayFabId:currentPlayerId});
return{Result:"OK",ChestBounty:g,FreeSlotsInfo:a,InventoryChange:e}};
handlers.purchaseBMItem=function(d,k){var a=CheckMaintenanceAndVersion(d);if("OK"!=a)return generateMaintenanceOrUpdateObj(a);if(0>d.itemId||3<d.itemId)return generateFailObj("invalid item index");a=[];a.push("BMItem"+d.itemId);var a=server.GetUserInternalData({PlayFabId:currentPlayerId,Keys:a}),b=server.GetUserInventory({PlayFabId:currentPlayerId}),a=a.Data["BMItem"+d.itemId].Value.split("_"),e=b.VirtualCurrency[a[1]];5!=a.length&&generateErrObj("User Black Market corrupted. Try again tomorrow");
var c;c=2>d.itemId?"PartCards":"CarCards";var h=parseInt(a[2])+parseInt(a[3])*parseInt(a[4]),e=checkBalance(a[1],h,e,e);if("OK"!=e)return e;for(var g,f,e=0;e<b.Inventory.length;e++)if(b.Inventory[e].ItemId==a[0]&&b.Inventory[e].CatalogVersion==c){g=b.Inventory[e].ItemInstanceId;void 0===b.Inventory[e].CustomData?f={Amount:1}:void 0===b.Inventory[e].CustomData.Amount?f={Amount:1}:(f=Number(b.Inventory[e].CustomData.Amount)+1,isNaN(f)&&(f=1),f={Amount:f});server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,
ItemInstanceId:g,Data:f});break}void 0===g&&(g=[],g.push(a[0]),g=server.GrantItemsToUser({CatalogVersion:c,PlayFabId:currentPlayerId,ItemIds:g}).ItemGrantResults[0].ItemInstanceId,void 0===g?generateErrObj("grantRequest denied"):(f={Amount:1},server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:g,Data:f})));g=server.SubtractUserVirtualCurrency({PlayFabId:currentPlayerId,VirtualCurrency:a[1],Amount:h});updateCurrencySpentStatistic(a[1],h);h=a[0]+"_"+a[1]+"_"+a[2]+"_"+
(parseInt(a[3])+1)+"_"+a[4];b={};b["BMItem"+d.itemId]=h;server.UpdateUserInternalData({PlayFabId:currentPlayerId,Data:b});f=[{ItemId:a[0],CatalogVersion:c,CustomData:f}];c={};c[g.VirtualCurrency]=g.Balance;a=d.itemId+"_"+a[2]+"_"+(parseInt(a[3])+1)+"_"+a[4];e={Inventory:f,VirtualCurrency:c};return{Result:"OK",Message:"InventoryUpdate",InventoryChange:e,BMItemChange:a}};
handlers.purchaseItems=function(d,k){var a=CheckMaintenanceAndVersion(d);if("OK"!=a)return generateMaintenanceOrUpdateObj(a);var b=server.GetUserInventory({PlayFabId:currentPlayerId}),e=b.VirtualCurrency.SC,c=b.VirtualCurrency.HC;switch(d.purchaseType){case "carUpgrade":return upgradeCar(d,k,b,e,c);case "partUpgrade":return upgradePart(d,k,b,e,c);case "custPurchase":for(var h=server.GetCatalogItems({CatalogVersion:"Customization"}),g,f=0,a="SC",l=0;l<h.Catalog.length;l++)if(h.Catalog[l].ItemId==d.custId){g=
h.Catalog[l];cardInfo=JSON.parse(h.Catalog[l].CustomData);f=d.custVal+",Cost";a=cardInfo[d.custVal+",Curr"];f=cardInfo[f];c=checkBalance(a,f,e,c);if("OK"!=c)return c;break}if(void 0==g)return generateErrObj("Customization does not exist in catalog.");for(var m,t,l=0;l<b.Inventory.length;l++)if(b.Inventory[l].ItemId==d.custId){m=b.Inventory[l];t=b.Inventory[l].ItemInstanceId;if(void 0!=m.CustomData&&String(d.custVal)in m.CustomData)return generateFailObj("User already has this customization.");break}if(void 0==
m){log.info("user doesn't have customization category. Granting ... ");c=[];c.push(d.custId);c=server.GrantItemsToUser({CatalogVersion:"Customization",PlayFabId:currentPlayerId,ItemIds:c});if(0==c.ItemGrantResults[0].Result)return generateErrObj("something went wrong while granting user customization class object.");t=c.ItemGrantResults[0].ItemInstanceId}c={};c[String(d.custVal)]="Owned";server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:t,Data:c});t=[{ItemId:d.custId,
CatalogVersion:"Customization",CustomData:c}];0<f?(c=server.SubtractUserVirtualCurrency({PlayFabId:currentPlayerId,VirtualCurrency:a,Amount:f}),updateCurrencySpentStatistic(a,f),a={},a[c.VirtualCurrency]=c.Balance,l={Inventory:t,VirtualCurrency:a}):l={Inventory:t};return generateInventoryChange("InventoryUpdateNewCustomization",l);case "softCurrencyPurchase":f=server.GetCatalogItems({CatalogVersion:"SoftCurrencyStore"});t=!1;for(l=a=0;l<f.Catalog.length;l++)if(f.Catalog[l].ItemId==d.packId){a=f.Catalog[l].VirtualCurrencyPrices.HC;
cardInfo=JSON.parse(f.Catalog[l].CustomData);t=!0;break}if(0==t)return generateErrObj("pack with ID: "+d.packId+" not found in catalog.");if(0>=a)return generateErrObj("pack with ID: "+d.packId+" shouldn't have negative cost.");if(a>c)return generateFailObj("Not enough HC.");c=server.SubtractUserVirtualCurrency({PlayFabId:currentPlayerId,VirtualCurrency:"HC",Amount:a});updateCurrencySpentStatistic("HC",a);f=server.AddUserVirtualCurrency({PlayFabId:currentPlayerId,VirtualCurrency:"SC",Amount:cardInfo.quantity});
a={};a[f.VirtualCurrency]=f.Balance;a[c.VirtualCurrency]=c.Balance;return generateInventoryChange("SoftCurrencyPurchased",{VirtualCurrency:a});default:log.debug("invalid purchase parameter")}};handlers.requestCurrency=function(d){d=CheckMaintenanceAndVersion(d);return"OK"!=d?generateMaintenanceOrUpdateObj(d):{VirtualCurrency:server.GetUserInventory({PlayFabId:currentPlayerId}).VirtualCurrency}};
handlers.requestInventory=function(d){d=server.GetUserInventory({PlayFabId:currentPlayerId});var k=Number(d.VirtualCurrency.SC);if(isNaN(k)||0>k)k=0;var a=Number(d.VirtualCurrency.HC);if(isNaN(a)||0>a)a=0;var b=[];b.push({StatisticName:"CurrentMoney",Version:"0",Value:k});b.push({StatisticName:"CurrentGold",Version:"0",Value:a});server.UpdatePlayerStatistics({PlayFabId:currentPlayerId,Statistics:b});for(var k=server.GetCatalogItems({CatalogVersion:"CarCards"}),a=server.GetCatalogItems({CatalogVersion:"PartCards"}),
b=!1,e=0;e<d.Inventory.length;e++)if("CarsProgress"==d.Inventory[e].CatalogVersion){var b=!0,c=checkCarDataValidity(d.Inventory[e],k);if("PlayFabError"==c||void 0===c)return generateErrObj("PlayfabError");"OK"==c?log.debug("Data for "+d.Inventory[e].ItemId+" OK"):d.Inventory[e].CustomData=c;d.Inventory[e].CustomData.Pr=recalculateCarPr(d.Inventory[e].CustomData,d.Inventory[e].ItemId,k,a);c={};c.Pr=d.Inventory[e].CustomData.Pr;server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:d.Inventory[e].ItemInstanceId,
Data:c})}return!1===b?(d=[],d.push("FordFocus"),d=server.GrantItemsToUser({CatalogVersion:"CarsProgress",PlayFabId:currentPlayerId,ItemIds:d}),k={CarLvl:"1",EngineLvl:"0",ExhaustLvl:"0",GearboxLvl:"0",SuspensionLvl:"0"},server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:d.ItemGrantResults[0].ItemInstanceId,Data:k}),k={TiresLvl:"0",TurboLvl:"0",PaintId:"0",DecalId:"0",RimsId:"0"},server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:d.ItemGrantResults[0].ItemInstanceId,
Data:k}),k={PlatesId:"0",WindshieldId:"0",Pr:"10"},server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:d.ItemGrantResults[0].ItemInstanceId,Data:k}),generateErrObj("UserHasNoCars ... reiniting")):d};
handlers.retrieveBlackMarket=function(d,k){var a=CheckMaintenanceAndVersion(d);if(!0===d.reset&&"OK"!=a)return generateMaintenanceOrUpdateObj(a);var b=[];b.push("BMTime");for(var e=0;4>e;e++)b.push("BMItem"+e);e=server.GetUserInternalData({PlayFabId:currentPlayerId,Keys:b});if(void 0===e.Data.BMTime)return GenerateBlackMarket(currentPlayerId);var b=new Date,c=[];c.push("BlackMarketResetMinutes");c=server.GetTitleData({PlayFabId:currentPlayerId,Keys:c});if(!0===d.reset){a="HC";e=200;b=server.GetTitleData({Keys:["BlackMarketResetCost"]});
void 0!==b.Data.BlackMarketResetCost&&(e=b.Data.BlackMarketResetCost.split("_"),a=e[0],e=Number(e[1]));if(0<e){b=server.GetUserInventory({PlayFabId:currentPlayerId});if("OK"!=checkBalance(a,e,b.VirtualCurrency.SC,b.VirtualCurrency.HC))return generateFailObj("not enough money");b=server.SubtractUserVirtualCurrency({PlayFabId:currentPlayerId,VirtualCurrency:a,Amount:e});updateCurrencySpentStatistic(a,e);a=GenerateBlackMarket(currentPlayerId);e={};e[b.VirtualCurrency]=b.Balance;e={VirtualCurrency:e};
a.InventoryChange=e;return a}return GenerateBlackMarket(currentPlayerId)}return b.getTime()-parseInt(e.Data.BMTime.Value)>6E4*parseInt(c.Data.BlackMarketResetMinutes)?("OK"!=a&&GetCurrentBlackMarket(currentPlayerId,e),GenerateBlackMarket(currentPlayerId)):GetCurrentBlackMarket(currentPlayerId,e)};
handlers.rewardUsers=function(d,k){var a=server.GetPlayerStatistics({PlayFabId:currentPlayerId,StatisticNames:["Experience","TrophyCount"]}).Statistics,b=GetValueFromStatistics(a,"Experience",0),a=GetValueFromStatistics(a,"TrophyCount",0),e=0;0>=b&&(a=Number(a)/3E3,e=Number(Math.floor(800*a)));b=Number(b)+e;server.UpdatePlayerStatistics({PlayFabId:currentPlayerId,Statistics:[{StatisticName:"Experience",Version:"0",Value:b}]});return b};
handlers.setMainCar=function(d,k){var a=CheckMaintenanceAndVersion(d);if("OK"!=a)return generateMaintenanceOrUpdateObj(a);for(var a=server.GetUserInventory({PlayFabId:currentPlayerId}),b={},e=0;e<a.Inventory.length;e++)if(a.Inventory[e].ItemId==d.carId&&"CarsProgress"==a.Inventory[e].CatalogVersion){b.carId=a.Inventory[e].ItemId;b.carData=a.Inventory[e].CustomData;updateUserProfileInfo(currentPlayerId,b);break}};
function updateProfileCar(d,k,a){a=server.GetUserReadOnlyData({PlayFabId:a,Keys:["UserProfileInfo"]});void 0!=a.Data&&void 0!=a.Data.UserProfileInfo&&void 0!=a.Data.UserProfileInfo.Value&&JSON.parse(a.Data.UserProfileInfo.Value).CarData.carId==d.carId&&handlers.setMainCar(d,k)}
handlers.skipTutorial=function(d,k){var a=CheckMaintenanceAndVersion(d);if("OK"!=a)return generateMaintenanceOrUpdateObj(a);var b=server.GetPlayerStatistics({PlayFabId:currentPlayerId,StatisticNames:["TrophyCount"]}),a=0;0!=b.Statistics.length&&(a=b.Statistics[0].Value);a=Number(a);0>=a&&(a=1);b=[];b.push({StatisticName:"TrophyCount",Value:a});server.UpdatePlayerStatistics({PlayFabId:currentPlayerId,Statistics:b});return{trophies:a}};
handlers.slotChestOperation=function(d,k){var a=server.GetUserInternalData({PlayFabId:currentPlayerId,Keys:["ChestSlotsStatus"]});if(void 0==a.Data.ChestSlotsStatus)return generateErrObj("No Chest Data found!");var b=JSON.parse(a.Data.ChestSlotsStatus.Value);if(Number(d.slotIndex)>=b.length||0>Number(d.slotIndex))return generateErrObj("Invalid slot index");var e=d.operation;if("Empty"==b[Number(d.slotIndex)].status)return generateFailObjCustom("ChestSlotInfo",JSON.parse(a.Data.ChestSlotsStatus.Value));
var c=server.GetCatalogItems({CatalogVersion:"Chests"});switch(e){case "order":for(e=0;e<b.length;e++)if("Incoming"==b[e].status&&b[e].arrivalTimeStamp>Math.floor((new Date).getTime()/1E3))return generateFailObjCustom("ChestSlotInfo",JSON.parse(a.Data.ChestSlotsStatus.Value));if("Occupied"!=b[Number(d.slotIndex)].status)return generateFailObjCustom("ChestSlotInfo",JSON.parse(a.Data.ChestSlotsStatus.Value));b[Number(d.slotIndex)].status="Incoming";a=new Date;b[Number(d.slotIndex)].orderTimeStamp=Math.floor(Number(a.getTime())/
1E3);for(var h,g,e=0;e<c.Catalog.length;e++)c.Catalog[e].ItemId==b[Number(d.slotIndex)].chestId&&(g=JSON.parse(c.Catalog[e].CustomData),a=g.hoursToOpen.split(","),h="0"==b[Number(d.slotIndex)].chestLeague?Number(a[0]):Number(a[Math.min(Number(b[Number(d.slotIndex)].chestLeague)-1,a.length-1)]));log.debug("hoursToOpen: "+h);b[Number(d.slotIndex)].arrivalTimeStamp=Number(b[Number(d.slotIndex)].orderTimeStamp)+Math.floor(3600*h);if(void 0==g)return generateErrObj("Could not find chest with id: "+b[Number(d.slotIndex)].chestId+
" in the Chests catalog, or this chest's custom data is undefined");c=JSON.stringify(b);server.UpdateUserInternalData({PlayFabId:currentPlayerId,Data:{ChestSlotsStatus:c}});return g={Result:"OK",ChestSlotInfo:b};case "rush":if("Arrived"==b[Number(d.slotIndex)].status)return generateFailObjCustom("ChestSlotInfo",JSON.parse(a.Data.ChestSlotsStatus.Value));for(var f,e=0;e<c.Catalog.length;e++)c.Catalog[e].ItemId==b[Number(d.slotIndex)].chestId&&(g=JSON.parse(c.Catalog[e].CustomData),f=Number(g.priceToUnlock),
a=g.hoursToOpen.split(","),h=0==b[Number(d.slotIndex)].chestLeague?Number(a[0]):Number(a[Math.min(Number(b[Number(d.slotIndex)].chestLeague),a.length-1)]));a=new Date;c="Occupied"==b[Number(d.slotIndex)].status?1:(Number(b[Number(d.slotIndex)].arrivalTimeStamp)-Math.floor(Number(a.getTime())/1E3))/(3600*h);log.debug("interpolator: "+c);if(0>=c)b[Number(d.slotIndex)].status="Arrived",b[Number(d.slotIndex)].arrivalTimeStamp=0,g={Result:"OK",ChestSlotInfo:b};else{c=Math.floor(1+c*(f-1));log.debug("rushPrice: "+
c);g=server.GetUserInventory({PlayFabId:currentPlayerId});if(c>g.VirtualCurrency.HC)return generateErrObj("Not enough HC.");b[Number(d.slotIndex)].status="Arrived";b[Number(d.slotIndex)].arrivalTimeStamp=0;b[Number(d.slotIndex)].orderTimeStamp=1;g=server.SubtractUserVirtualCurrency({PlayFabId:currentPlayerId,VirtualCurrency:"HC",Amount:c});updateCurrencySpentStatistic("HC",c);c={};c[g.VirtualCurrency]=g.Balance;e={VirtualCurrency:c};g={Result:"OK",InventoryChange:e,ChestSlotInfo:b}}c=JSON.stringify(b);
server.UpdateUserInternalData({PlayFabId:currentPlayerId,Data:{ChestSlotsStatus:c}});return g;case "open":f=Number(d.slotIndex);for(e=0;e<c.Catalog.length;e++)if(c.Catalog[e].ItemId==b[Number(d.slotIndex)].chestId){g=JSON.parse(c.Catalog[e].CustomData);break}if(void 0==g)return generateErrObj("Could not find chest with id: "+b[Number(d.slotIndex)].chestId+" in the Chests catalog, or this chest's custom data is undefined");if("Empty"==b[f].status||"Occupied"==b[f].status||"Incoming"==b[f].status&&
b[f].arrivalTimeStamp>Math.floor((new Date).getTime()/1E3))return generateFailObjCustom("ChestSlotInfo",JSON.parse(a.Data.ChestSlotsStatus.Value));c=GenerateChestBounty(currentPlayerId,b[f].chestId,b[f].chestLeague,g);g=server.GetUserInventory({PlayFabId:currentPlayerId});a=UpdateExperience("Chests",b[f].chestId,"xpGain",0,!0);g.Experience=a;g={Result:"OK",InventoryChange:g,ChestBounty:c};b[f].chestId=null;b[f].chestLeague=0;b[f].status="Empty";b[f].orderTimeStamp=0;b[f].arrivalTimeStamp=0;c=JSON.stringify(b);
server.UpdateUserInternalData({PlayFabId:currentPlayerId,Data:{ChestSlotsStatus:c}});return g}};
function GenerateChestBounty(d,k,a,b){var e=Number(a)+Number(b.arenasAdvance),c=e;void 0!=b.leaguesBehind&&(c=Number(a)-Number(b.leaguesBehind));var c=Math.min(Math.max(c,1),e),h=0,g=Number(b.maxCardStacks);k={};var f;f=b.guaranteedSC.split(",");switch(f.length){case 1:f=Number(f[0]);break;case 2:f=Number(f[0])+Math.floor(Math.random()*Math.abs(Number(f[1])-Number(f[0])));break;default:f=0}0<f&&(k.SC=f,h++);f=b.guaranteedHC.split(",");switch(f.length){case 1:f=Number(f[0]);break;case 2:f=Number(f[0])+
Math.floor(Math.random()*Math.abs(Number(f[1])-Number(f[0])));break;default:f=0}0<f&&(k.HC=f,h++);var l=server.GetCatalogItems({CatalogVersion:"CarCards"}),m=server.GetCatalogItems({CatalogVersion:"PartCards"}),t,v=[],u=[],y=[];for(f=0;f<l.Catalog.length;f++)if(t=JSON.parse(l.Catalog[f].CustomData),void 0!=t&&void 0!=t.unlockedAtRank&&!(Number(t.unlockedAtRank)>Number(e)||Number(t.unlockedAtRank)<Number(c)||void 0==t.rarity))switch(Number(t.rarity)){case 0:v.push(l.Catalog[f].ItemId);break;case 1:u.push(l.Catalog[f].ItemId);
break;case 2:y.push(l.Catalog[f].ItemId);break;default:y.push(l.Catalog[f].ItemId)}var A,c=[],l=[];t=[];for(f=0;f<m.Catalog.length;f++)if(A=JSON.parse(m.Catalog[f].CustomData),void 0!=A.rarity)switch(Number(A.rarity)){case 0:c.push(m.Catalog[f].ItemId);break;case 1:l.push(m.Catalog[f].ItemId);break;case 2:t.push(m.Catalog[f].ItemId);break;default:t.push(m.Catalog[f].ItemId)}log.debug(" === Parts Arrats: Common Ln "+c.length+" Rare Ln "+l.length+" Epic Ln "+t.length);m=!1;A=0;var B=b.guaranteedCarsPerRarity.split(",");
for(f=0;f<B.length;f++)A+=Number(B[f]);0<Number(A)&&(m=!0);var n,q,p,w,x,C;if(1==m){var z=Number(Math.floor(.55*(g-h)));0>=z&&(z=1);for(var r=0;3>r;r++)if(!(0>=Number(B[r]))){var G=Math.floor(Number(B[r])/A*z);0>=G&&(G=1);for(f=0;f<Number(B[r]);f++){var F;switch(r){case 0:m=void 0==n?0:Number(n.length);void 0==m&&(m=0);m=m<G;F=GetRandomCard(v,e);"ERROR"!=F&&(n=AddCardToListOfStacks("CarCards",n,F,m));break;case 1:m=void 0==q?0:Number(q.length);void 0==m&&(m=0);m=m<G;F=GetRandomCard(u,e);"ERROR"!=
F&&(q=AddCardToListOfStacks("CarCards",q,F,m));break;case 2:m=void 0==p?0:Number(p.length),void 0==m&&(m=0),m=m<G,F=GetRandomCard(y,e),"ERROR"!=F&&(p=AddCardToListOfStacks("CarCards",p,F,m))}}}}void 0!=n&&(h+=n.length);void 0!=q&&(h+=q.length);void 0!=p&&(h+=p.length);log.debug("== part rarity droprates: "+b.partRarityDroprates);A=b.partRarityDroprates.split(",");for(f=0;f<A.length;f++)log.debug("== part rarity droprate["+f+"]"+A[f]);B=b.carRarityDroprates.split(",");for(f=0;f<B.length;f++);for(f=
0;f<Number(b.randomCardsReward);f++)if(m=h<g,70>Math.floor(100*Math.random()))switch(z=WeightedRandom(A),z){case 0:z=GetRandomCard(c,e);"ERROR"!=z&&(r=void 0==w?0:w.length,void 0==r&&(r=0),w=AddCardToListOfStacks("PartCards",w,z,m),w.length>r&&h++);break;case 1:z=GetRandomCard(l,e);"ERROR"!=z&&(r=void 0==x?0:x.length,void 0==r&&(r=0),x=AddCardToListOfStacks("PartCards",x,z,m),x.length>r&&h++);break;case 2:z=GetRandomCard(t,e),"ERROR"!=z&&(r=void 0==C?0:C.length,void 0==r&&(r=0),C=AddCardToListOfStacks("PartCards",
C,z,m),C.length>r&&h++)}else switch(z=WeightedRandom(B),z){case 0:z=GetRandomCard(v,e);"ERROR"!=z&&(r=void 0==n?0:n.length,void 0==r&&(r=0),n=AddCardToListOfStacks("CarCards",n,z,m),n.length>r&&h++);break;case 1:z=GetRandomCard(u,e);"ERROR"!=z&&(r=void 0==q?0:q.length,void 0==r&&(r=0),q=AddCardToListOfStacks("CarCards",q,z,m),q.length>r&&h++);break;case 2:z=GetRandomCard(y,e),"ERROR"!=z&&(r=void 0==p?0:p.length,void 0==r&&(r=0),p=AddCardToListOfStacks("CarCards",p,z,m),p.length>r&&h++)}b=[];void 0!=
n&&(b=b.concat(n));void 0!=q&&(b=b.concat(q));void 0!=p&&(b=b.concat(p));void 0!=w&&(b=b.concat(w));void 0!=x&&(b=b.concat(x));void 0!=C&&(b=b.concat(C));f=server.GetCatalogItems({CatalogVersion:"Balancing"});f=JSON.parse(f.Catalog[0].CustomData);a=Number(f.ArenaBonuses[Math.min(Number(a),10)]);if(0<a)for(f=0;f<b.length;f++)b[f].CustomData.Amount=Math.floor(Number(b[f].CustomData.Amount)+a/100*Number(b[f].CustomData.Amount));void 0!=k.HC&&(k.HC=Math.floor(Number(k.HC)+a/100*Number(k.HC)),0<Number(k.HC)&&
server.AddUserVirtualCurrency({PlayFabId:d,VirtualCurrency:"HC",Amount:Number(k.HC)}));void 0!=k.SC&&(k.SC=Math.floor(Number(k.SC)+a/100*Number(k.SC)),0<Number(k.SC)&&server.AddUserVirtualCurrency({PlayFabId:d,VirtualCurrency:"SC",Amount:Number(k.SC)}));a=server.GetUserInventory({PlayFabId:d});n=!1;for(f=0;f<b.length;f++){for(p=0;p<a.Inventory.length;p++)if(n=!1,a.Inventory[p].ItemId==b[f].ItemId&&a.Inventory[p].CatalogVersion==b[f].CatalogVersion){n=void 0==a.Inventory[p].CustomData?Number(b[f].CustomData.Amount):
void 0==a.Inventory[p].CustomData.Amount?Number(b[f].CustomData.Amount):isNaN(Number(a.Inventory[p].CustomData.Amount))?Number(b[f].CustomData.Amount):Number(a.Inventory[p].CustomData.Amount)+Number(b[f].CustomData.Amount);q={Amount:n};server.UpdateUserInventoryItemCustomData({PlayFabId:d,ItemInstanceId:a.Inventory[p].ItemInstanceId,Data:q});n=!0;break}0==n&&(p=server.GrantItemsToUser({CatalogVersion:b[f].CatalogVersion,PlayFabId:d,ItemIds:[b[f].ItemId]}),q={Amount:b[f].CustomData.Amount},server.UpdateUserInventoryItemCustomData({PlayFabId:d,
ItemInstanceId:p.ItemGrantResults[0].ItemInstanceId,Data:q}))}return{Inventory:b,VirtualCurrency:k}}
function grantUserChest(d,k){var a=server.GetCatalogItems({CatalogVersion:"Chests"}),b=server.GetUserInternalData({PlayFabId:d,Keys:["ChestSlotsStatus"]});if(void 0==b.Data.ChestSlotsStatus)return generateErrObj("No Chest Data found!");for(var b=JSON.parse(b.Data.ChestSlotsStatus.Value),e=-1,c=0;c<b.length;c++)if("Empty"==b[c].status){e=c;break}if(!(0>e)){log.debug("emptySlotFound: "+e);var c=server.GetPlayerStatistics({PlayFabId:d,StatisticNames:["TrophyCount"]}),h=0;0!=c.Statistics.length&&(h=c.Statistics[0].Value);
h=Number(h);h=Number(calculateLeague(h));switch(k){case "endGameNormal":for(var g,f=0,l=0,m=[],c=0;c<a.Catalog.length;c++)g=JSON.parse(a.Catalog[c].CustomData),0>=Number(g.dropChance)||(f+=10*Number(g.dropChance),g=l,l=f,m.push({chestId:a.Catalog[c].ItemId,leftRange:g,rightRange:l}));if(0>=m.length)b[e].chestId="SilverChest";else{a=Math.floor(Math.random()*f);f="SilverChest";for(c=0;c<m.length;c++)if(!(Number(m[c].rightRange)<=Number(a)||Number(m[c].leftRange)>Number(a))){f=m[c].chestId;break}b[e].chestId=
f}b[e].chestLeague=h;b[e].status="Occupied";b[e].orderTimeStamp=0;b[e].arrivalTimeStamp=0;break;case "endGameFreeWin":b[e].chestId="QuickChest";b[e].chestLeague=h;b[e].status="Occupied";b[e].orderTimeStamp=0;b[e].arrivalTimeStamp=0;break;case "tutorial":b[e].chestId="QuickChest";b[e].chestLeague=1;b[e].status="Occupied";b[e].orderTimeStamp=0;b[e].arrivalTimeStamp=0;break;default:log.debug("unexpected source, returning from grantChest");return}b=JSON.stringify(b);log.debug("updating ChestSlotsStatus: "+
b);server.UpdateUserInternalData({PlayFabId:d,Data:{ChestSlotsStatus:b}})}}
handlers.startGame=function(d,k){var a=CheckMaintenanceAndVersion(d);if("OK"!=a)return generateMaintenanceOrUpdateObj(a);var b=server.GetTitleData({Key:"LeagueSubdivisions SubdivisionTrophyRanges TrophyGainRange TrophyLoseRange SubdivisionPrRanges TrophyDifferenceLimit".split(" ")}),a=server.GetPlayerStatistics({PlayFabId:currentPlayerId,StatisticNames:["TotalGames"]}).Statistics,a=GetValueFromStatistics(a,"TotalGames",0),a=Number(a)+1;1==d.debug&&log.debug("totalGamesStartedIs: "+a);var e=server.GetPlayerStatistics({PlayFabId:currentPlayerId,
StatisticNames:["TrophyCount"]}),c=0;0!=e.Statistics.length&&(c=e.Statistics[0].Value);for(var c=Number(c),h=JSON.parse(b.Data.SubdivisionTrophyRanges),g=JSON.parse(b.Data.LeagueSubdivisions),f=JSON.parse(b.Data.SubdivisionPrRanges),e=JSON.parse(b.Data.TrophyDifferenceLimit),l=Number(e.trophyReadjustRange),m=Number(e.maxDifference),t=e.subDivisionsToExclude,v=43,u=43,y,A=b.Data.TrophyGainRange.split("_"),B=b.Data.TrophyLoseRange.split("_"),e=Number(A[0]),b=Number(A[1]),A=Number(B[0]),B=Number(B[1]),
n=0;n<h.subdivisions.length;n++)if(c<Number(h.subdivisions[n])){v=n;n<h.subdivisions.length-1&&(u=n+1);break}y=Number(h.subdivisions[u])-Number(h.subdivisions[v]);0>=y&&(y=400);var q=server.GetTitleInternalData({Keys:"RecSubDivision"+v}).Data["RecSubDivision"+v],p=!1;void 0==q&&(p=!0);var w,x,C,z="noop",r="noop",n=server.GetUserInternalData({PlayFabId:currentPlayerId,Keys:["lastOpp","quitLastGame"]});x="false;";void 0!=n.Data.quitLastGame&&(x=n.Data.quitLastGame.Value);u=!1;void 0==x&&(x="false");
"true"==x&&(u=!0);if(void 0==n.Data||void 0==n.Data.lastOpp)r=z="noop";else for(x=n.Data.lastOpp.Value.split(","),n=0;n<x.length;n++)0==n&&(z=x[n]),1==n&&(r=x[n]);w=0==p?JSON.parse(q):[];var G=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];30>w.length&&(p=!0);var F=Array(w.length),H=0,q=Array(w.length);x=0;C=Array(w.length);for(var I=0,n=0;n<w.length;n++)1==p&&(G[5*Number(w[n].e)+Number(w[n].c)]=1),w[n].uId!=currentPlayerId&&(F[H]=w[n],H++,w[n].uId!=z&&(q[x]=w[n],x++,w[n].uId!=r&&(C[I]=
w[n],I++)));if(1==p){p=[];for(n=0;n<G.length;n++)0==G[n]&&p.push(n);p=p[Math.floor(Math.random()*p.length)];n=Math.floor(p/5);p%=5;r=server.GetTitleData({Keys:"MasterUser"});if(void 0!=r.Data.MasterUser&&(r=server.GetUserReadOnlyData({PlayFabId:r.Data.MasterUser,Keys:[n+"_"+p+"_RecPos",n+"_"+p+"_RecRot",n+"_"+p+"_RecHeader"]}),void 0!=r.Data&&void 0!=r.Data[n+"_"+p+"_RecPos"]&&void 0!=r.Data[n+"_"+p+"_RecRot"]&&void 0!=r.Data[n+"_"+p+"_RecHeader"])){g=!0;0==c?(grantUserChest(currentPlayerId,"tutorial"),
c=b,g=!1):c-=A;1>=c&&(c=1);var D=[],c={StatisticName:"TrophyCount",Value:c};D.push(c);c={StatisticName:"League",Value:E};D.push(c);c={StatisticName:"TotalGames",Value:a};D.push(c);server.UpdatePlayerStatistics({PlayFabId:currentPlayerId,Statistics:D});a={trophyWin:Math.floor((Number(b)+Number(e))/2),trophyLose:Math.floor((Number(B)+Number(A))/2),quitLastGame:"true"};0==g&&(a.trophyWin=0,a.trophyLose=0);1==u&&(a.LastGameOutcome="Loss");server.UpdateUserInternalData({PlayFabId:currentPlayerId,Data:a});
return{Result:"OK",RecType:"TheStig",PosData:r.Data[n+"_"+p+"_RecPos"].Value,RotData:r.Data[n+"_"+p+"_RecRot"].Value,HeaderData:r.Data[n+"_"+p+"_RecHeader"].Value,TrophyLose:A,TrophyWin:b,Opp:"TheStig",PicTexture:null}}}if(0==H)return generateErrObj("no valid recording found for this subdivision");E=F;0<x&&(H=x,E=q);0<I&&(H=I,E=C);q=Math.floor(Math.random()*H);q>=H&&(q=H-1);x=Math.min(H,3);C=Array(x);for(n=0;n<x;n++)C[n]=0>=q?E[n]:q>=H-1?E[H-1-n]:E[q-Math.floor(x/2)+n];E=Math.floor(Math.random()*
x);x=C[E].uId;q=C[E].e;C=C[E].c;I=server.GetUserReadOnlyData({PlayFabId:x,Keys:[q+"_"+C+"_RecPos",q+"_"+C+"_RecRot",q+"_"+C+"_RecHeader"]});if(void 0==I)return generateErrObj("Did not find recording for this user: "+x);var H=server.GetPlayerCombinedInfo({PlayFabId:x,InfoRequestParameters:{GetUserAccountInfo:!0,GetUserInventory:!1,GetUserVirtualCurrency:!1,GetUserData:!1,GetUserReadOnlyData:!1,GetCharacterInventories:!1,GetCharacterList:!1,GetTitleData:!1,GetPlayerStatistics:!1}}),F=server.GetUserData({PlayFabId:x,
Keys:["PicTexture"]}).Data.PicTexture,F=void 0==F?null:F.Value,r=c,E=Number(calculateLeague(c)),p="UserGenerated",G=0<E?Number(h.subdivisions[g.leagues[E-1]]):0;w=E>=g.leagues.length-1?2*G:Number(h.subdivisions[g.leagues[E]]);1==d.debug&&log.debug("I bet it will crash after this");h=JSON.parse(I.Data[q+"_"+C+"_RecHeader"].Value);1==d.debug&&log.debug("or not");void 0!=h&&(D=h.Trophies);var D=Number(D),J=!0;1==d.debug&&log.debug("Adjusting trophies");if(void 0!=t)for(1==d.debug&&log.debug("excludedSubdivisionsFromTrophyAdjustment: "+
t),n=0;n<t.length;n++)if(v==Number(t[n])){1==d.debug&&log.debug("in excluded subdivision: "+v);J=!1;break}1==J&&Number(Math.abs(r-D))>=m&&(1==d.debug&&log.debug("generating new trophies. Reason: user trophies: "+r+" vs opponent trophies: "+D),D=r-l+Math.floor(Math.random()*l*2),h.Trophies=D,1==d.debug&&log.debug("performing stringify on recordingData header"),I.Data[q+"_"+C+"_RecHeader"].Value=JSON.stringify(h));0>=w-G?(l=B,m=e):Number(Math.abs(r-D))>Number(y)?(l=Math.floor((A+B)/2)-1+Math.floor(3*
Math.random()),m=Math.floor((b+e)/2)-1+Math.floor(3*Math.random())):(l=A+Math.floor((B-A)/2*((r-D)/(w-G)+1)),m=e+Math.floor((b-e)/2*((D-r)/(w-G)+1)));1==d.debug&&log.debug("Opponent's PR is TOO DAMN HIGH! "+h.Pr+" vs "+Number(f.subdivisions[Number(g.leagues[E-1])+1])+". You are in subdivision: "+Number(g.leagues[E-1]+1));h.Pr>Number(f.subdivisions[Number(g.leagues[E-1])+1])&&(l=Math.floor((A+B)/2)-1+Math.floor(3*Math.random()),m=Math.floor((b+e)/2)-1+Math.floor(3*Math.random()),p="MobyDick");e=!0;
0==c?(grantUserChest(currentPlayerId,"tutorial"),e=!1,c=b):(c-=Number(l),1>=c&&(c=1));D=[];c={StatisticName:"TrophyCount",Value:c};D.push(c);c={StatisticName:"League",Value:E};D.push(c);c={StatisticName:"TotalGames",Value:a};D.push(c);server.UpdatePlayerStatistics({PlayFabId:currentPlayerId,Statistics:D});a={trophyWin:m,trophyLose:l,lastOpp:x+","+z,quitLastGame:"true"};0==e&&(a.trophyWin=0,a.trophyLose=0);1==u&&(a.LastGameOutcome="Loss");server.UpdateUserInternalData({PlayFabId:currentPlayerId,Data:a});
return{Result:"OK",RecType:p,PosData:I.Data[q+"_"+C+"_RecPos"].Value,RotData:I.Data[q+"_"+C+"_RecRot"].Value,HeaderData:I.Data[q+"_"+C+"_RecHeader"].Value,TrophyLose:l,TrophyWin:m,Opp:H.InfoResultPayload.AccountInfo.TitleInfo.DisplayName,PicTexture:F}};
handlers.updateCarCust=function(d,k){var a=CheckMaintenanceAndVersion(d);if("OK"!=a)return generateMaintenanceOrUpdateObj(a);for(var b=server.GetUserInventory({PlayFabId:currentPlayerId}),e=[],c="-1",h={},g={PaintJobs:{itemOwned:"no",itemCustData:d.paintId,carItemId:"PaintId"},Decals:{itemOwned:"no",itemCustData:d.decalId,carItemId:"DecalId"},Plates:{itemOwned:"no",itemCustData:d.platesId,carItemId:"PlatesId"},Rims:{itemOwned:"no",itemCustData:d.rimsId,carItemId:"RimsId"},WindshieldText:{itemOwned:"no",
itemCustData:d.wsId,carItemId:"WindshieldId"}},a=0;a<b.Inventory.length;a++)b.Inventory[a].ItemId==d.carId&&"CarsProgress"==b.Inventory[a].CatalogVersion&&(c=b.Inventory[a].ItemInstanceId),b.Inventory[a].ItemId in g&&(g[b.Inventory[a].ItemId].itemOwned="yes",g[b.Inventory[a].ItemId].itemCustData in b.Inventory[a].CustomData?h[g[b.Inventory[a].ItemId].carItemId]=g[b.Inventory[a].ItemId].itemCustData:log.debug("user doesn't own: "+b.Inventory[a].ItemId+" "+g[b.Inventory[a].ItemId].itemCustData));if("-1"==
c)return generateFailObj("User does not own car with id: "+d.carId);for(var f in g)g.hasOwnProperty(f)&&"no"==g[f].itemOwned&&e.push(f);if(h=={})return generateFailObj("User doesn't own any of those customizations");server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:c,Data:h});updateProfileCar(d,k,currentPlayerId);f=[{ItemId:d.carId,CatalogVersion:"CarsProgress",CustomData:h}];if(0<e.length)for(e=server.GrantItemsToUser({CatalogVersion:"Customization",PlayFabId:currentPlayerId,
ItemIds:e}),b={0:"Owned"},a=0;a<e.ItemGrantResults.length;a++)server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:e.ItemGrantResults[a].ItemInstanceId,Data:b});return{Result:"OK",Message:"InventoryUpdate",InventoryChange:{Inventory:f}}};
function upgradeCar(d,k,a,b,e){for(var c=server.GetCatalogItems({CatalogVersion:"CarCards"}),h=!1,g,f=0;f<a.Inventory.length;f++)if(a.Inventory[f].ItemId==d.carId&&"CarsProgress"==a.Inventory[f].CatalogVersion){h=!0;g=a.Inventory[f];break}for(var l,f=0;f<c.Catalog.length;f++)if(c.Catalog[f].ItemId==d.carId){l=JSON.parse(c.Catalog[f].CustomData);break}if(void 0===l)return generateErrObj("CardNotFoundForCarwithID: "+d.carId+". It is possible that the carCard ID and the Car ID do not coincide. Check Playfab catalog data.");
if(!0===h){var m=parseInt(g.CustomData.CarLvl)+1;if(m>=Number(l.prPerLvl.length))return generateFailObj("Maximum pr level was reached!");var t=getObjectValueFromLevel(l,"currCostPerLvl",m),f=checkBalance(l.currType,t,b,e);if("OK"!=f)return f;b=getObjectValueFromLevel(l,"cardCostPerLvl",m);g.CustomData.CarLvl=m;for(var h=!1,v,f=0;f<a.Inventory.length;f++)if(a.Inventory[f].ItemId==d.carId&&"CarCards"==a.Inventory[f].CatalogVersion){h=!0;try{if(void 0===a.Inventory[f].CustomData)return generateFailObj("Insufficient cards, CusotmData undefined");
if(void 0===a.Inventory[f].CustomData.Amount)return generateFailObj("Insufficient cards, CusotmData.Amount udnefined");if(Number(a.Inventory[f].CustomData.Amount)>=b)a.Inventory[f].CustomData.Amount-=b,v={Amount:a.Inventory[f].CustomData.Amount},server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:a.Inventory[f].ItemInstanceId,Data:v});else return generateFailObj("Insufficient cards for real: "+a.Inventory[f].CustomData.Amount+" vs "+b)}catch(y){return generateFailObj("Insufficient cards")}break}if(!1===
h)return generateFailObj("No cards found");a=recalculateCarPr(g.CustomData,g.ItemId,c,void 0);f={CarLvl:m,Pr:a};server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:g.ItemInstanceId,Data:f});updateProfileCar(d,k,currentPlayerId);var u;0<t&&(u=server.SubtractUserVirtualCurrency({PlayFabId:currentPlayerId,VirtualCurrency:l.currType,Amount:t}),updateCurrencySpentStatistic(l.currType,t));v=[{ItemId:d.carId,CatalogVersion:"CarCards",CustomData:v},{ItemId:d.carId,CatalogVersion:"CarsProgress",
CustomData:f}];a={};f={Inventory:v};void 0!=u&&(a[u.VirtualCurrency]=u.Balance,f.VirtualCurrency=a);f.Experience=UpdateExperience("Balancing","BalancingItem","Car_"+l.rarity,m,!0);return generateInventoryChange("InventoryUpdate",f)}h=!1;for(f=0;f<a.Inventory.length;f++)if(a.Inventory[f].ItemId==d.carId&&"CarCards"==a.Inventory[f].CatalogVersion){h=!0;try{if(void 0===a.Inventory[f].CustomData)return generateFailObj("Insufficient cards, CustomData null");if(void 0===a.Inventory[f].CustomData.Amount)return generateFailObj("Insufficient cards, CustomData.Amount null");
if(Number(a.Inventory[f].CustomData.Amount)>=Number(l.cardCostPerLvl[1]))t=a.Inventory[f].ItemInstanceId,a.Inventory[f].CustomData.Amount-=l.cardCostPerLvl[1],v={Amount:a.Inventory[f].CustomData.Amount};else return generateFailObj("Insufficient cards: "+a.Inventory[f].CustomData.Amount+" vs "+l.cardCostPerLvl[1]+".")}catch(y){return generateFailObj("Insufficient cards: "+y)}break}if(0==h)return generateFailObj("No cards found");f=checkBalance(l.currType,l.currCostPerLvl[1],b,e);if("OK"!=f)return f;
g=[];g.push(d.carId);g=server.GrantItemsToUser({CatalogVersion:"CarsProgress",PlayFabId:currentPlayerId,ItemIds:g});if(!1===g.ItemGrantResults[0].Result)return log.error("Something went wrong while giving user the item, refunding cards"),generateFailObj("Something went wrong while giving user the item, refunding cards.");server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:t,Data:v});0<l.currCostPerLvl[1]&&(u=server.SubtractUserVirtualCurrency({PlayFabId:currentPlayerId,
VirtualCurrency:l.currType,Amount:l.currCostPerLvl[1]}),updateCurrencySpentStatistic(l.currType,l.currCostPerLvl[1]));f={CarLvl:"1",EngineLvl:"0",ExhaustLvl:"0",GearboxLvl:"0",SuspensionLvl:"0"};server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:g.ItemGrantResults[0].ItemInstanceId,Data:f});f={TiresLvl:"0",TurboLvl:"0",PaintId:l.defaultPaintID,DecalId:"0",RimsId:"0"};server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:g.ItemGrantResults[0].ItemInstanceId,
Data:f});f={PlatesId:"0",WindshieldId:"0",Pr:Number(l.basePr)+l.prPerLvl[1]};server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:g.ItemGrantResults[0].ItemInstanceId,Data:f});c=g=!1;for(f=0;f<a.Inventory.length;f++)if("PaintJobs"==a.Inventory[f].ItemId){c=!0;void 0!=a.Inventory[f].CustomData?l.defaultPaintID in a.Inventory[f].CustomData?g=!0:(m={},m[l.defaultPaintID]="Owned"):(m={},m[l.defaultPaintID]="Owned");void 0!=m&&server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,
ItemInstanceId:a.Inventory[f].ItemInstanceId,Data:m});break}0==c&&(paintToGive=[],paintToGive.push("PaintJobs"),a=server.GrantItemsToUser({CatalogVersion:"Customization",PlayFabId:currentPlayerId,ItemIds:paintToGive}),m={},m[l.defaultPaintID]="Owned",server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:a.ItemGrantResults[0].ItemInstanceId,Data:m}));f={CarLvl:"1",EngineLvl:"0",ExhaustLvl:"0",GearboxLvl:"0",SuspensionLvl:"0",TiresLvl:"0",TurboLvl:"0",PaintId:l.defaultPaintID,
DecalId:"0",RimsId:"0",PlatesId:"0",WindshieldId:"0",Pr:Number(l.basePr)+l.prPerLvl[1]};v=[{ItemId:d.carId,CatalogVersion:"CarCards",CustomData:v},{ItemId:d.carId,CatalogVersion:"CarsProgress",CustomData:f}];0==g&&(a={},a[l.defaultPaintID]="Owned",v.push({ItemId:"PaintJobs",CatalogVersion:"Customization",CustomData:a}));a={};f={Inventory:v};void 0!=u&&(a[u.VirtualCurrency]=u.Balance,f.VirtualCurrency=a);updateProfileCar(d,k,currentPlayerId);f.Experience=UpdateExperience("Balancing","BalancingItem",
"Car_"+l.rarity,1,!0);return generateInventoryChange("InventoryUpdateNewCar",f)}
function upgradePart(d,k,a,b,e){for(var c=server.GetCatalogItems({CatalogVersion:"CarsProgress"}),h=!1,g=0;g<c.Catalog.length;g++)if(c.Catalog[g].ItemId==d.carId){h=!0;break}if(!1===h)return generateErrObj("car with ID: "+d.carId+" not found in catalog.");for(var c=server.GetCatalogItems({CatalogVersion:"PartCards"}),h=!1,f,g=0;g<c.Catalog.length;g++)if(c.Catalog[g].ItemId==d.partId){f=JSON.parse(c.Catalog[g].CustomData);h=!0;break}if(0==h)return generateErrObj("part with ID: "+d.partId+" not found in catalog.");
for(var h=!1,l,g=0;g<a.Inventory.length;g++)if(a.Inventory[g].ItemId==d.carId&&"CarsProgress"==a.Inventory[g].CatalogVersion){h=!0;l=a.Inventory[g];break}if(!1===h)return generateFailObj("car with ID: "+d.carId+" not found in user inventory.");for(var m=!1,h=0,t={},g=0;g<a.Inventory.length;g++)if(a.Inventory[g].ItemId==d.partId&&"PartCards"==a.Inventory[g].CatalogVersion){var m=!0,v={Exhaust:"ExhaustLvl",Engine:"EngineLvl",Gearbox:"GearboxLvl",Suspension:"SuspensionLvl",Tires:"TiresLvl",Turbo:"TurboLvl"},
h=parseInt(l.CustomData[v[d.partId]])+1;if(h>=Number(f.prPerLvl.length))return generateFailObj("Maximum pr level was reached!");var u=getObjectValueFromLevel(f,"cardCostPerLvl",h),y=getObjectValueFromLevel(f,"currCostPerLvl",h);t[v[d.partId]]=h;l.CustomData[v[d.partId]]=h;var A;b=checkBalance(f.currType,y,b,e);if("OK"!=b)return b;try{if(void 0!==a.Inventory[g].CustomData&&void 0!==a.Inventory[g].CustomData.Amount&&a.Inventory[g].CustomData.Amount>=u)a.Inventory[g].CustomData.Amount-=u,A={Amount:a.Inventory[g].CustomData.Amount},
server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,ItemInstanceId:a.Inventory[g].ItemInstanceId,Data:A});else return generateFailObj("Insufficient cards")}catch(n){return generateFailObj("Insufficient cards")}break}if(0==m)return generateFailObj("Part not found");var B;0<y&&(B=server.SubtractUserVirtualCurrency({PlayFabId:currentPlayerId,VirtualCurrency:f.currType,Amount:y}),updateCurrencySpentStatistic(f.currType,y));g=recalculateCarPr(l.CustomData,l.ItemId,void 0,c);t.Pr=g;server.UpdateUserInventoryItemCustomData({PlayFabId:currentPlayerId,
ItemInstanceId:l.ItemInstanceId,Data:t});l={};g={Inventory:[{ItemId:d.partId,CatalogVersion:"PartCards",CustomData:A},{ItemId:d.carId,CatalogVersion:"CarsProgress",CustomData:t}]};void 0!==B&&(l[B.VirtualCurrency]=B.Balance,g.VirtualCurrency=l);updateProfileCar(d,k,currentPlayerId);g.Experience=UpdateExperience("Balancing","BalancingItem","Parts_"+f.rarity,h,!0);return generateInventoryChange("InventoryUpdatePart",g)}
handlers.worthlessScript=function(d,k){var a=server.GetUserData({PlayFabId:"B730B2C5BD143660",Keys:["PicTexture"]}).Data.PicTexture.Value,b=server.GetTitleInternalData({Keys:["RecSubDivision1"]}).Data.RecSubDivision1;log.debug("recPool: "+b);for(var b=JSON.parse(b),e=0;e<b.length;e++)server.UpdateUserData({PlayFabId:b[e].uId,Data:{PicTexture:a},Permission:"Public"})};