Files
LawinServer/structure/mcp.js
2022-02-16 01:46:52 +00:00

5454 lines
208 KiB
JavaScript

const Express = require("express");
const express = Express.Router();
const fs = require("fs");
const path = require("path");
const iniparser = require("ini");
const config = iniparser.parse(fs.readFileSync(path.join(__dirname, "..", "Config", "config.ini")).toString());
const functions = require("./functions.js");
const catalog = functions.getItemShop();
const memory = require("./../memory.json");
// Set support a creator code
express.post("/fortnite/api/game/v2/profile/*/client/SetAffiliateName", async (req, res) => {
const profile = require("./../profiles/common_core.json");
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
const SupportedCodes = require("./../responses/SAC.json");
SupportedCodes.forEach(code => {
if (req.body.affiliateName.toLowerCase() == code.toLowerCase() || req.body.affiliateName == "") {
profile.stats.attributes.mtx_affiliate_set_time = new Date().toISOString();
profile.stats.attributes.mtx_affiliate = req.body.affiliateName;
StatChanged = true;
}
})
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "mtx_affiliate_set_time",
"value": profile.stats.attributes.mtx_affiliate_set_time
})
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "mtx_affiliate",
"value": profile.stats.attributes.mtx_affiliate
})
fs.writeFileSync("./profiles/common_core.json", JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": "common_core",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Set STW banner
express.post("/fortnite/api/game/v2/profile/*/client/SetHomebaseBanner", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "profile0"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.homebaseBannerIconId && req.body.homebaseBannerColorId) {
switch (req.query.profileId) {
case "profile0":
profile.stats.attributes.homebase.bannerIconId = req.body.homebaseBannerIconId;
profile.stats.attributes.homebase.bannerColorId = req.body.homebaseBannerColorId;
StatChanged = true;
break;
case "common_public":
profile.stats.attributes.banner_icon = req.body.homebaseBannerIconId;
profile.stats.attributes.banner_color = req.body.homebaseBannerColorId;
StatChanged = true;
break;
}
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
if (req.query.profileId == "profile0") {
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "homebase",
"value": profile.stats.attributes.homebase
})
}
if (req.query.profileId == "common_public") {
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "banner_icon",
"value": profile.stats.attributes.banner_icon
})
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "banner_color",
"value": profile.stats.attributes.banner_color
})
}
fs.writeFileSync(`./profiles/${req.query.profileId || "profile0"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "profile0",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Buy skill tree perk STW
express.post("/fortnite/api/game/v2/profile/*/client/PurchaseHomebaseNode", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "profile0"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
const ID = functions.MakeID();
if (req.body.nodeId) {
profile.items[ID] = {
"templateId": `HomebaseNode:${req.body.nodeId}`,
"attributes": {
"item_seen": true
},
"quantity": 1
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": profile.items[ID]
})
fs.writeFileSync(`./profiles/${req.query.profileId || "profile0"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "profile0",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Open Winterfest presents (11.31 & 19.01)
express.post("/fortnite/api/game/v2/profile/*/client/UnlockRewardNode", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "athena"}.json`);
const common_core = require("./../profiles/common_core.json");
const WinterFestIDS = require("./../responses/winterfestrewards.json");
functions.GetVersionInfo(req, memory);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var MultiUpdate = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
var Season = "Season" + memory.season;
const ID = functions.MakeID();
const GiftID = functions.MakeID();
if (req.body.nodeId && req.body.rewardGraphId) {
if (WinterFestIDS[Season][req.body.nodeId].toLowerCase().startsWith("homebasebannericon:")) {
MultiUpdate.push({
"profileRevision": common_core.rvn || 0,
"profileId": "common_core",
"profileChangesBaseRevision": common_core.rvn || 0,
"profileChanges": [],
"profileCommandRevision": common_core.commandRevision || 0,
})
common_core.items[ID] = {
"templateId": WinterFestIDS[Season][req.body.nodeId],
"attributes": {
"max_level_bonus": 0,
"level": 1,
"item_seen": false,
"xp": 0,
"variants": [],
"favorite": false
},
"quantity": 1
};
MultiUpdate[0].profileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": common_core.items[ID]
})
common_core.rvn += 1;
common_core.commandRevision += 1;
MultiUpdate[0].profileRevision = common_core.rvn || 0;
MultiUpdate[0].profileCommandRevision = common_core.commandRevision || 0;
}
if (!WinterFestIDS[Season][req.body.nodeId].toLowerCase().startsWith("homebasebannericon:")) {
profile.items[ID] = {
"templateId": WinterFestIDS[Season][req.body.nodeId],
"attributes": {
"max_level_bonus": 0,
"level": 1,
"item_seen": false,
"xp": 0,
"variants": [],
"favorite": false
},
"quantity": 1
};
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": profile.items[ID]
})
}
profile.items[GiftID] = {"templateId":"GiftBox:gb_winterfestreward","attributes":{"max_level_bonus":0,"fromAccountId":"","lootList":[{"itemType":WinterFestIDS[Season][req.body.nodeId],"itemGuid":ID,"itemProfile":"athena","attributes":{"creation_time":new Date().toISOString()},"quantity":1}],"level":1,"item_seen":false,"xp":0,"giftedOn":new Date().toISOString(),"params":{"SubGame":"Athena","winterfestGift":"true"},"favorite":false},"quantity":1};
profile.items[req.body.rewardGraphId].attributes.reward_keys[0].unlock_keys_used += 1;
profile.items[req.body.rewardGraphId].attributes.reward_nodes_claimed.push(req.body.nodeId);
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": GiftID,
"item": profile.items[GiftID]
})
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.rewardGraphId,
"attributeName": "reward_keys",
"attributeValue": profile.items[req.body.rewardGraphId].attributes.reward_keys
})
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.rewardGraphId,
"attributeName": "reward_nodes_claimed",
"attributeValue": profile.items[req.body.rewardGraphId].attributes.reward_nodes_claimed
})
fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2));
fs.writeFileSync("./profiles/common_core.json", JSON.stringify(common_core, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "athena",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"multiUpdate": MultiUpdate,
"responseVersion": 1
})
res.end();
});
// Remove gift box
express.post("/fortnite/api/game/v2/profile/*/client/RemoveGiftBox", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "athena"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
// Gift box ID on 11.31
if (req.body.giftBoxItemId) {
var id = req.body.giftBoxItemId;
delete profile.items[id];
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": id
})
StatChanged = true;
}
// Gift box ID on 19.01
if (req.body.giftBoxItemIds) {
for (var i in req.body.giftBoxItemIds) {
var id = req.body.giftBoxItemIds[i];
delete profile.items[id];
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": id
})
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "athena",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Set pinned STW quests
express.post("/fortnite/api/game/v2/profile/*/client/SetPinnedQuests", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.pinnedQuestIds) {
profile.stats.attributes.client_settings.pinnedQuestInstances = req.body.pinnedQuestIds;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "client_settings",
"value": profile.stats.attributes.client_settings
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Replace Daily Quests
express.post("/fortnite/api/game/v2/profile/*/client/FortRerollDailyQuest", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "athena"}.json`);
var DailyQuestIDS = JSON.parse(JSON.stringify(require("./../responses/quests.json")));
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var Notifications = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.query.profileId == "profile0" || req.query.profileId == "campaign") {
DailyQuestIDS = DailyQuestIDS.SaveTheWorld.Daily
}
if (req.query.profileId == "athena") {
DailyQuestIDS = DailyQuestIDS.BattleRoyale.Daily
}
const NewQuestID = functions.MakeID();
var randomNumber = Math.floor(Math.random() * DailyQuestIDS.length);
for (var key in profile.items) {
while (DailyQuestIDS[randomNumber].templateId.toLowerCase() == profile.items[key].templateId.toLowerCase()) {
randomNumber = Math.floor(Math.random() * DailyQuestIDS.length);
}
}
if (req.body.questId && profile.stats.attributes.quest_manager.dailyQuestRerolls >= 1) {
profile.stats.attributes.quest_manager.dailyQuestRerolls -= 1;
delete profile.items[req.body.questId];
profile.items[NewQuestID] = {
"templateId": DailyQuestIDS[randomNumber].templateId,
"attributes": {
"creation_time": new Date().toISOString(),
"level": -1,
"item_seen": false,
"playlists": [],
"sent_new_notification": false,
"challenge_bundle_id": "",
"xp_reward_scalar": 1,
"challenge_linked_quest_given": "",
"quest_pool": "",
"quest_state": "Active",
"bucket": "",
"last_state_change_time": new Date().toISOString(),
"challenge_linked_quest_parent": "",
"max_level_bonus": 0,
"xp": 0,
"quest_rarity": "uncommon",
"favorite": false
},
"quantity": 1
};
for (var i in DailyQuestIDS[randomNumber].objectives) {
profile.items[NewQuestID].attributes[`completion_${DailyQuestIDS[randomNumber].objectives[i]}`] = 0
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "quest_manager",
"value": profile.stats.attributes.quest_manager
})
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": NewQuestID,
"item": profile.items[NewQuestID]
})
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": req.body.questId
})
Notifications.push({
"type": "dailyQuestReroll",
"primary": true,
"newQuestId": DailyQuestIDS[randomNumber].templateId
})
fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "athena",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"notifications": Notifications,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Mark New Quest Notification Sent
express.post("/fortnite/api/game/v2/profile/*/client/MarkNewQuestNotificationSent", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "athena"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.itemIds) {
for (var i in req.body.itemIds) {
var id = req.body.itemIds[i];
profile.items[id].attributes.sent_new_notification = true
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": id,
"attributeName": "sent_new_notification",
"attributeValue": true
})
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "athena",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Check for new quests
express.post("/fortnite/api/game/v2/profile/*/client/ClientQuestLogin", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "athena"}.json`);
var QuestIDS = JSON.parse(JSON.stringify(require("./../responses/quests.json")));
functions.GetVersionInfo(req, memory);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
var QuestCount = 0;
var ShouldGiveQuest = true;
var DateFormat = (new Date().toISOString()).split("T")[0];
var DailyQuestIDS;
var SeasonQuestIDS;
try {
if (req.query.profileId == "profile0" || req.query.profileId == "campaign") {
DailyQuestIDS = QuestIDS.SaveTheWorld.Daily
for (var key in profile.items) {
if (profile.items[key].templateId.toLowerCase().startsWith("quest:daily")) {
QuestCount += 1;
}
}
}
if (req.query.profileId == "athena") {
DailyQuestIDS = QuestIDS.BattleRoyale.Daily
if (QuestIDS.BattleRoyale.hasOwnProperty(`Season${memory.season}`)) {
SeasonQuestIDS = QuestIDS.BattleRoyale[`Season${memory.season}`]
}
for (var key in profile.items) {
if (profile.items[key].templateId.toLowerCase().startsWith("quest:athenadaily")) {
QuestCount += 1;
}
if (key.split("")[0] == "S" && (Number.isInteger(Number(key.split("")[1]))) && (key.split("")[2] == "-" || (Number.isInteger(Number(key.split("")[2])) && key.split("")[3] == "-"))) {
if (!key.startsWith(`S${memory.season}-`)) {
delete profile.items[key];
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": key
})
StatChanged = true;
}
}
}
}
if (profile.stats.attributes.hasOwnProperty("quest_manager")) {
if (profile.stats.attributes.quest_manager.hasOwnProperty("dailyLoginInterval")) {
if (profile.stats.attributes.quest_manager.dailyLoginInterval.includes("T")) {
var DailyLoginDate = (profile.stats.attributes.quest_manager.dailyLoginInterval).split("T")[0];
if (DailyLoginDate == DateFormat) {
ShouldGiveQuest = false;
} else {
ShouldGiveQuest = true;
if (profile.stats.attributes.quest_manager.dailyQuestRerolls <= 0) {
profile.stats.attributes.quest_manager.dailyQuestRerolls += 1;
}
}
}
}
}
if (QuestCount < 3 && ShouldGiveQuest == true) {
const NewQuestID = functions.MakeID();
var randomNumber = Math.floor(Math.random() * DailyQuestIDS.length);
for (var key in profile.items) {
while (DailyQuestIDS[randomNumber].templateId.toLowerCase() == profile.items[key].templateId.toLowerCase()) {
randomNumber = Math.floor(Math.random() * DailyQuestIDS.length);
}
}
profile.items[NewQuestID] = {
"templateId": DailyQuestIDS[randomNumber].templateId,
"attributes": {
"creation_time": new Date().toISOString(),
"level": -1,
"item_seen": false,
"playlists": [],
"sent_new_notification": false,
"challenge_bundle_id": "",
"xp_reward_scalar": 1,
"challenge_linked_quest_given": "",
"quest_pool": "",
"quest_state": "Active",
"bucket": "",
"last_state_change_time": new Date().toISOString(),
"challenge_linked_quest_parent": "",
"max_level_bonus": 0,
"xp": 0,
"quest_rarity": "uncommon",
"favorite": false
},
"quantity": 1
};
for (var i in DailyQuestIDS[randomNumber].objectives) {
profile.items[NewQuestID].attributes[`completion_${DailyQuestIDS[randomNumber].objectives[i]}`] = 0
}
profile.stats.attributes.quest_manager.dailyLoginInterval = new Date().toISOString();
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": NewQuestID,
"item": profile.items[NewQuestID]
})
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "quest_manager",
"value": profile.stats.attributes.quest_manager
})
StatChanged = true;
}
} catch (err) {}
if (SeasonQuestIDS) {
for (var ChallengeBundleSchedule in SeasonQuestIDS.ChallengeBundleSchedules) {
if (profile.items.hasOwnProperty(ChallengeBundleSchedule.itemGuid)) {
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": ChallengeBundleSchedule.itemGuid
})
}
ChallengeBundleSchedule = SeasonQuestIDS.ChallengeBundleSchedules[ChallengeBundleSchedule];
profile.items[ChallengeBundleSchedule.itemGuid] = {
"templateId": ChallengeBundleSchedule.templateId,
"attributes": {
"unlock_epoch": "2018-01-31T00:00:00.000Z",
"max_level_bonus": 0,
"level": 1,
"item_seen": true,
"xp": 0,
"favorite": false,
"granted_bundles": ChallengeBundleSchedule.granted_bundles
},
"quantity": 1
}
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": ChallengeBundleSchedule.itemGuid,
"item": profile.items[ChallengeBundleSchedule.itemGuid]
})
StatChanged = true;
}
for (var ChallengeBundle in SeasonQuestIDS.ChallengeBundles) {
if (profile.items.hasOwnProperty(ChallengeBundle.itemGuid)) {
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": ChallengeBundle.itemGuid
})
}
ChallengeBundle = SeasonQuestIDS.ChallengeBundles[ChallengeBundle];
if (config.Profile.bCompletedSeasonalQuests == true && ChallengeBundle.hasOwnProperty("questStages")) {
ChallengeBundle.grantedquestinstanceids = ChallengeBundle.grantedquestinstanceids.concat(ChallengeBundle.questStages);
}
profile.items[ChallengeBundle.itemGuid] = {
"templateId": ChallengeBundle.templateId,
"attributes": {
"has_unlock_by_completion": false,
"num_quests_completed": 0,
"level": 0,
"grantedquestinstanceids": ChallengeBundle.grantedquestinstanceids,
"item_seen": true,
"max_allowed_bundle_level": 0,
"num_granted_bundle_quests": 0,
"max_level_bonus": 0,
"challenge_bundle_schedule_id": ChallengeBundle.challenge_bundle_schedule_id,
"num_progress_quests_completed": 0,
"xp": 0,
"favorite": false
},
"quantity": 1
}
profile.items[ChallengeBundle.itemGuid].attributes.num_granted_bundle_quests = ChallengeBundle.grantedquestinstanceids.length;
if (config.Profile.bCompletedSeasonalQuests == true) {
profile.items[ChallengeBundle.itemGuid].attributes.num_quests_completed = ChallengeBundle.grantedquestinstanceids.length;
profile.items[ChallengeBundle.itemGuid].attributes.num_progress_quests_completed = ChallengeBundle.grantedquestinstanceids.length;
}
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": ChallengeBundle.itemGuid,
"item": profile.items[ChallengeBundle.itemGuid]
})
StatChanged = true;
}
for (var Quest in SeasonQuestIDS.Quests) {
if (profile.items.hasOwnProperty(Quest.itemGuid)) {
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": Quest.itemGuid
})
}
Quest = SeasonQuestIDS.Quests[Quest];
profile.items[Quest.itemGuid] = {
"templateId": Quest.templateId,
"attributes": {
"creation_time": "2018-01-31T00:00:00.000Z",
"level": -1,
"item_seen": true,
"playlists": [],
"sent_new_notification": true,
"challenge_bundle_id": Quest.challenge_bundle_id,
"xp_reward_scalar": 1,
"challenge_linked_quest_given": "",
"quest_pool": "",
"quest_state": "Active",
"bucket": "",
"last_state_change_time": "2018-01-31T00:00:00.000Z",
"challenge_linked_quest_parent": "",
"max_level_bonus": 0,
"xp": 0,
"quest_rarity": "uncommon",
"favorite": false
},
"quantity": 1
}
if (config.Profile.bCompletedSeasonalQuests == true) {
profile.items[Quest.itemGuid].attributes.quest_state = "Claimed";
}
for (var i in Quest.objectives) {
if (config.Profile.bCompletedSeasonalQuests == true) {
profile.items[Quest.itemGuid].attributes[`completion_${Quest.objectives[i].name}`] = Quest.objectives[i].count;
} else {
profile.items[Quest.itemGuid].attributes[`completion_${Quest.objectives[i].name}`] = 0;
}
}
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": Quest.itemGuid,
"item": profile.items[Quest.itemGuid]
})
StatChanged = true;
}
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "athena",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Refund V-Bucks purchase
express.post("/fortnite/api/game/v2/profile/*/client/RefundMtxPurchase", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "common_core"}.json`);
const ItemProfile = require("./../profiles/athena.json");
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var MultiUpdate = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
var ItemGuids = [];
if (req.body.purchaseId) {
MultiUpdate.push({
"profileRevision": ItemProfile.rvn || 0,
"profileId": "athena",
"profileChangesBaseRevision": ItemProfile.rvn || 0,
"profileChanges": [],
"profileCommandRevision": ItemProfile.commandRevision || 0,
})
profile.stats.attributes.mtx_purchase_history.refundsUsed += 1;
profile.stats.attributes.mtx_purchase_history.refundCredits -= 1;
for (var i in profile.stats.attributes.mtx_purchase_history.purchases) {
if (profile.stats.attributes.mtx_purchase_history.purchases[i].purchaseId == req.body.purchaseId) {
for (var x in profile.stats.attributes.mtx_purchase_history.purchases[i].lootResult) {
ItemGuids.push(profile.stats.attributes.mtx_purchase_history.purchases[i].lootResult[x].itemGuid)
}
profile.stats.attributes.mtx_purchase_history.purchases[i].refundDate = new Date().toISOString();
for (var key in profile.items) {
if (profile.items[key].templateId.toLowerCase().startsWith("currency:mtx")) {
if (profile.items[key].attributes.platform.toLowerCase() == profile.stats.attributes.current_mtx_platform.toLowerCase() || profile.items[key].attributes.platform.toLowerCase() == "shared") {
profile.items[key].quantity += profile.stats.attributes.mtx_purchase_history.purchases[i].totalMtxPaid;
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": key,
"quantity": profile.items[key].quantity
})
break;
}
}
}
}
}
for (var i in ItemGuids) {
try {
delete ItemProfile.items[ItemGuids[i]]
MultiUpdate[0].profileChanges.push({
"changeType": "itemRemoved",
"itemId": ItemGuids[i]
})
} catch (err) {}
}
ItemProfile.rvn += 1;
ItemProfile.commandRevision += 1;
profile.rvn += 1;
profile.commandRevision += 1;
StatChanged = true;
}
if (StatChanged == true) {
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "mtx_purchase_history",
"value": profile.stats.attributes.mtx_purchase_history
})
MultiUpdate[0].profileRevision = ItemProfile.rvn || 0;
MultiUpdate[0].profileCommandRevision = ItemProfile.commandRevision || 0;
fs.writeFileSync(`./profiles/${req.query.profileId || "common_core"}.json`, JSON.stringify(profile, null, 2));
fs.writeFileSync(`./profiles/athena.json`, JSON.stringify(ItemProfile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "common_core",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"multiUpdate": MultiUpdate,
"responseVersion": 1
})
res.end();
});
// Claim STW daily reward
express.post("/fortnite/api/game/v2/profile/*/client/ClaimLoginReward", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
var DateFormat = (new Date().toISOString()).split("T")[0] + "T00:00:00.000Z";
if (profile.stats.attributes.daily_rewards.lastClaimDate != DateFormat) {
profile.stats.attributes.daily_rewards.nextDefaultReward += 1;
profile.stats.attributes.daily_rewards.totalDaysLoggedIn += 1;
profile.stats.attributes.daily_rewards.lastClaimDate = DateFormat;
profile.stats.attributes.daily_rewards.additionalSchedules.founderspackdailyrewardtoken.rewardsClaimed += 1;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "daily_rewards",
"value": profile.stats.attributes.daily_rewards
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Equip team perk STW
express.post("/fortnite/api/game/v2/profile/*/client/AssignTeamPerkToLoadout", async (req, res) => {
const profile = require("./../profiles/campaign.json");
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.loadoutId) {
profile.items[req.body.loadoutId].attributes.team_perk = req.body.teamPerkId || "";
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.loadoutId,
"attributeName": "team_perk",
"attributeValue": profile.items[req.body.loadoutId].attributes.team_perk
})
fs.writeFileSync("./profiles/campaign.json", JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Equip gadget STW
express.post("/fortnite/api/game/v2/profile/*/client/AssignGadgetToLoadout", async (req, res) => {
const profile = require("./../profiles/campaign.json");
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.loadoutId) {
switch (req.body.slotIndex) {
case 0:
if (req.body.gadgetId.toLowerCase() == profile.items[req.body.loadoutId].attributes.gadgets[1].gadget.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.gadgets[1].gadget = "";
}
profile.items[req.body.loadoutId].attributes.gadgets[req.body.slotIndex].gadget = req.body.gadgetId || "";
StatChanged = true;
break;
case 1:
if (req.body.gadgetId.toLowerCase() == profile.items[req.body.loadoutId].attributes.gadgets[0].gadget.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.gadgets[0].gadget = "";
}
profile.items[req.body.loadoutId].attributes.gadgets[req.body.slotIndex].gadget = req.body.gadgetId || "";
StatChanged = true;
break;
}
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.loadoutId,
"attributeName": "gadgets",
"attributeValue": profile.items[req.body.loadoutId].attributes.gadgets
})
fs.writeFileSync("./profiles/campaign.json", JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Assign worker to squad STW
express.post("/fortnite/api/game/v2/profile/*/client/AssignWorkerToSquad", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "profile0"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.characterId) {
for (var key in profile.items) {
if (profile.items[key].hasOwnProperty('attributes')) {
if (profile.items[key].attributes.hasOwnProperty('squad_id') && profile.items[key].attributes.hasOwnProperty('squad_slot_idx')) {
if (profile.items[key].attributes.squad_id != "" && profile.items[key].attributes.squad_slot_idx != -1) {
if (profile.items[key].attributes.squad_id.toLowerCase() == req.body.squadId.toLowerCase() && profile.items[key].attributes.squad_slot_idx == req.body.slotIndex) {
profile.items[key].attributes.squad_id = "";
profile.items[key].attributes.squad_slot_idx = 0;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": key,
"attributeName": "squad_id",
"attributeValue": profile.items[key].attributes.squad_id
})
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": key,
"attributeName": "squad_slot_idx",
"attributeValue": profile.items[key].attributes.squad_slot_idx
})
}
}
}
}
}
}
if (req.body.characterId) {
profile.items[req.body.characterId].attributes.squad_id = req.body.squadId || "";
profile.items[req.body.characterId].attributes.squad_slot_idx = req.body.slotIndex || 0;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.characterId,
"attributeName": "squad_id",
"attributeValue": profile.items[req.body.characterId].attributes.squad_id
})
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.characterId,
"attributeName": "squad_slot_idx",
"attributeValue": profile.items[req.body.characterId].attributes.squad_slot_idx
})
fs.writeFileSync(`./profiles/${req.query.profileId || "profile0"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "profile0",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Assign multiple workers to squad STW
express.post("/fortnite/api/game/v2/profile/*/client/AssignWorkerToSquadBatch", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "profile0"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.characterIds && req.body.squadIds && req.body.slotIndices) {
for (var i in req.body.characterIds) {
for (var key in profile.items) {
if (profile.items[key].hasOwnProperty('attributes')) {
if (profile.items[key].attributes.hasOwnProperty('squad_id') && profile.items[key].attributes.hasOwnProperty('squad_slot_idx')) {
if (profile.items[key].attributes.squad_id != "" && profile.items[key].attributes.squad_slot_idx != -1) {
if (profile.items[key].attributes.squad_id.toLowerCase() == req.body.squadIds[i].toLowerCase() && profile.items[key].attributes.squad_slot_idx == req.body.slotIndices[i]) {
profile.items[key].attributes.squad_id = "";
profile.items[key].attributes.squad_slot_idx = 0;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": key,
"attributeName": "squad_id",
"attributeValue": profile.items[key].attributes.squad_id
})
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": key,
"attributeName": "squad_slot_idx",
"attributeValue": profile.items[key].attributes.squad_slot_idx
})
}
}
}
}
}
profile.items[req.body.characterIds[i]].attributes.squad_id = req.body.squadIds[i] || "";
profile.items[req.body.characterIds[i]].attributes.squad_slot_idx = req.body.slotIndices[i] || 0;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.characterIds[i],
"attributeName": "squad_id",
"attributeValue": profile.items[req.body.characterIds[i]].attributes.squad_id
})
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.characterIds[i],
"attributeName": "squad_slot_idx",
"attributeValue": profile.items[req.body.characterIds[i]].attributes.squad_slot_idx
})
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
fs.writeFileSync(`./profiles/${req.query.profileId || "profile0"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "profile0",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Claim STW quest reward
express.post("/fortnite/api/game/v2/profile/*/client/ClaimQuestReward", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.questId) {
profile.items[req.body.questId].attributes.quest_state = "Claimed";
profile.items[req.body.questId].attributes.last_state_change_time = new Date().toISOString();
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.questId,
"attributeName": "quest_state",
"attributeValue": profile.items[req.body.questId].attributes.quest_state
})
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.questId,
"attributeName": "last_state_change_time",
"attributeValue": profile.items[req.body.questId].attributes.last_state_change_time
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Level item up STW 1
express.post("/fortnite/api/game/v2/profile/*/client/UpgradeItem", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.targetItemId) {
profile.items[req.body.targetItemId].attributes.level += 1;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.targetItemId,
"attributeName": "level",
"attributeValue": profile.items[req.body.targetItemId].attributes.level
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Level slotted item up STW
express.post("/fortnite/api/game/v2/profile/*/client/UpgradeSlottedItem", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "collection_book_people0"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.targetItemId) {
if (req.body.desiredLevel) {
var new_level = Number(req.body.desiredLevel);
profile.items[req.body.targetItemId].attributes.level = new_level;
} else {
profile.items[req.body.targetItemId].attributes.level += 1;
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.targetItemId,
"attributeName": "level",
"attributeValue": profile.items[req.body.targetItemId].attributes.level
})
fs.writeFileSync(`./profiles/${req.query.profileId || "collection_book_people0"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "collection_book_people0",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Level item up STW 2
express.post("/fortnite/api/game/v2/profile/*/client/UpgradeItemBulk", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.targetItemId) {
var new_level = Number(req.body.desiredLevel);
profile.items[req.body.targetItemId].attributes.level = new_level;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.targetItemId,
"attributeName": "level",
"attributeValue": profile.items[req.body.targetItemId].attributes.level
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Evolve item STW
express.post("/fortnite/api/game/v2/profile/*/client/ConvertItem", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var Notifications = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.targetItemId) {
if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("t04")) {
profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/t04/ig, "T05");
}
if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("t03")) {
profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/t03/ig, "T04");
}
if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("t02")) {
profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/t02/ig, "T03");
}
if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("t01")) {
profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/t01/ig, "T02");
}
// Conversion Index: 0 = Ore, 1 = Crystal
if (req.body.conversionIndex == 1) {
profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/ore/ig, "Crystal");
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
const ID = functions.MakeID();
profile.items[ID] = profile.items[req.body.targetItemId];
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": profile.items[ID]
})
delete profile.items[req.body.targetItemId]
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": req.body.targetItemId
})
Notifications.push({
"type": "conversionResult",
"primary": true,
"itemsGranted": [
{
"itemType": profile.items[ID].templateId,
"itemGuid": ID,
"itemProfile": req.query.profileId || "campaign",
"attributes": {
"level": profile.items[ID].attributes.level,
"alterations": profile.items[ID].attributes.alterations || []
},
"quantity": 1
}
]
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"notifications": Notifications,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Evolve slotted item STW
express.post("/fortnite/api/game/v2/profile/*/client/ConvertSlottedItem", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "collection_book_people0"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var Notifications = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.targetItemId) {
if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("t04")) {
profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/t04/ig, "T05");
}
if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("t03")) {
profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/t03/ig, "T04");
}
if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("t02")) {
profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/t02/ig, "T03");
}
if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("t01")) {
profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/t01/ig, "T02");
}
// Conversion Index: 0 = Ore, 1 = Crystal
if (req.body.conversionIndex == 1) {
profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/ore/ig, "Crystal");
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
const ID = functions.MakeID();
profile.items[ID] = profile.items[req.body.targetItemId];
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": profile.items[ID]
})
delete profile.items[req.body.targetItemId]
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": req.body.targetItemId
})
Notifications.push({
"type": "conversionResult",
"primary": true,
"itemsGranted": [
{
"itemType": profile.items[ID].templateId,
"itemGuid": ID,
"itemProfile": req.query.profileId || "collection_book_people0",
"attributes": {
"level": profile.items[ID].attributes.level,
"alterations": profile.items[ID].attributes.alterations || []
},
"quantity": 1
}
]
})
fs.writeFileSync(`./profiles/${req.query.profileId || "collection_book_people0"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "collection_book_people0",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"notifications": Notifications,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Upgrade item rarity STW
express.post("/fortnite/api/game/v2/profile/*/client/UpgradeItemRarity", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var Notifications = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.targetItemId) {
if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("_vr_")) {
profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/_vr_/ig, "_SR_");
}
if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("_r_")) {
profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/_r_/ig, "_VR_");
}
if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("_uc_")) {
profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/_uc_/ig, "_R_");
}
if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("_c_")) {
profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/_c_/ig, "_UC_");
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
const ID = functions.MakeID();
profile.items[ID] = profile.items[req.body.targetItemId];
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": profile.items[ID]
})
delete profile.items[req.body.targetItemId]
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": req.body.targetItemId
})
Notifications.push([{
"type": "upgradeItemRarityNotification",
"primary": true,
"itemsGranted": [
{
"itemType": profile.items[ID].templateId,
"itemGuid": ID,
"itemProfile": req.query.profileId || "campaign",
"attributes": {
"level": profile.items[ID].attributes.level,
"alterations": profile.items[ID].attributes.alterations || []
},
"quantity": 1
}
]
}])
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"notifications": Notifications,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Super charge item STW
express.post("/fortnite/api/game/v2/profile/*/client/PromoteItem", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.targetItemId) {
profile.items[req.body.targetItemId].attributes.level += 2;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.targetItemId,
"attributeName": "level",
"attributeValue": profile.items[req.body.targetItemId].attributes.level
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Craft item STW (Guns, melees and traps only)
express.post("/fortnite/api/game/v2/profile/*/client/CraftWorldItem", async (req, res) => {
functions.GetVersionInfo(req, memory);
const profile = require(`./../profiles/${req.query.profileId || "theater0"}.json`);
var schematic_profile;
// do not change this
var chosen_profile = false;
if (4 <= memory.season || memory.build == 3.5 || memory.build == 3.6 && chosen_profile == false) {
schematic_profile = require("./../profiles/campaign.json");
chosen_profile = true;
}
if (3 >= memory.season && chosen_profile == false) {
schematic_profile = require("./../profiles/profile0.json");
chosen_profile = true;
}
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var Notifications = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
var Item;
const ID = functions.MakeID();
if (req.body.targetSchematicItemId) {
var Body = '';
Body += JSON.stringify(schematic_profile.items[req.body.targetSchematicItemId]);
Item = JSON.parse(Body);
var ItemType = 'Weapon:';
var ItemIDType = 'WID';
if (Item.templateId.split("_")[1].split("_")[0].toLowerCase() == "wall") {
ItemType = "Trap:";
ItemIDType = "TID";
}
if (Item.templateId.split("_")[1].split("_")[0].toLowerCase() == "floor") {
ItemType = "Trap:";
ItemIDType = "TID";
}
if (Item.templateId.split("_")[1].split("_")[0].toLowerCase() == "ceiling") {
ItemType = "Trap:";
ItemIDType = "TID";
}
Item.quantity = req.body.numTimesToCraft || 1;
Item.templateId = Item.templateId.replace(/schematic:/ig, ItemType);
Item.templateId = Item.templateId.replace(/sid/ig, ItemIDType);
if (req.body.targetSchematicTier) {
switch (req.body.targetSchematicTier.toLowerCase()) {
case "i":
if (!Item.templateId.toLowerCase().includes("t01")) {
Item.attributes.level = 10;
}
Item.templateId = Item.templateId.substring(0, Item.templateId.length-3) + "T01"
Item.templateId = Item.templateId.replace(/crystal/ig, "Ore")
break;
case "ii":
if (!Item.templateId.toLowerCase().includes("t02")) {
Item.attributes.level = 20;
}
Item.templateId = Item.templateId.substring(0, Item.templateId.length-3) + "T02"
Item.templateId = Item.templateId.replace(/crystal/ig, "Ore")
break;
case "iii":
if (!Item.templateId.toLowerCase().includes("t03")) {
Item.attributes.level = 30;
}
Item.templateId = Item.templateId.substring(0, Item.templateId.length-3) + "T03"
Item.templateId = Item.templateId.replace(/crystal/ig, "Ore")
break;
case "iv":
if (!Item.templateId.toLowerCase().includes("t04")) {
Item.attributes.level = 40;
}
Item.templateId = Item.templateId.substring(0, Item.templateId.length-3) + "T04"
break;
case "v":
Item.templateId = Item.templateId.substring(0, Item.templateId.length-3) + "T05"
break;
}
}
Item.attributes = {
"clipSizeScale": 0,
"loadedAmmo": 999,
"level": Item.attributes.level || 1,
"alterationDefinitions": Item.attributes.alterations || [],
"baseClipSize": 999,
"durability": 375,
"itemSource": ""
};
profile.items[ID] = Item;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": profile.items[ID]
});
Notifications.push({
"type": "craftingResult",
"primary": true,
"itemsCrafted": [
{
"itemType": profile.items[ID].templateId,
"itemGuid": ID,
"itemProfile": req.query.profileId || "theater0",
"attributes": {
"loadedAmmo": profile.items[ID].attributes.loadedAmmo,
"level": profile.items[ID].attributes.level,
"alterationDefinitions": profile.items[ID].attributes.alterationDefinitions,
"durability": profile.items[ID].attributes.durability
},
"quantity": profile.items[ID].quantity
}
]
})
fs.writeFileSync(`./profiles/${req.query.profileId || "theater0"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "theater0",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"notifications": Notifications,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Destroy item STW
express.post("/fortnite/api/game/v2/profile/*/client/DestroyWorldItems", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "theater0"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.itemIds) {
for (var i in req.body.itemIds) {
var id = req.body.itemIds[i];
delete profile.items[id]
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": id
})
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
fs.writeFileSync(`./profiles/${req.query.profileId || "theater0"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "theater0",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Disassemble items STW
express.post("/fortnite/api/game/v2/profile/*/client/DisassembleWorldItems", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "theater0"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.targetItemIdAndQuantityPairs) {
for (var i in req.body.targetItemIdAndQuantityPairs) {
var id = req.body.targetItemIdAndQuantityPairs[i].itemId;
var quantity = Number(req.body.targetItemIdAndQuantityPairs[i].quantity);
var orig_quantity = Number(profile.items[id].quantity);
if (quantity >= orig_quantity) {
delete profile.items[id]
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": id
})
}
if (quantity < orig_quantity) {
profile.items[id].quantity -= quantity;
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": profile.items[id].quantity
})
}
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
fs.writeFileSync(`./profiles/${req.query.profileId || "theater0"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "theater0",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Storage transfer STW
express.post("/fortnite/api/game/v2/profile/*/client/StorageTransfer", async (req, res) => {
const theater0 = require("./../profiles/theater0.json");
const outpost0 = require("./../profiles/outpost0.json");
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var MultiUpdate = [];
var BaseRevision = theater0.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.transferOperations) {
MultiUpdate.push({
"profileRevision": outpost0.rvn || 0,
"profileId": "outpost0",
"profileChangesBaseRevision": outpost0.rvn || 0,
"profileChanges": [],
"profileCommandRevision": outpost0.commandRevision || 0,
})
for (var i in req.body.transferOperations) {
if (req.body.transferOperations[i].toStorage == false) {
let id = req.body.transferOperations[i].itemId;
let body_quantity = Number(req.body.transferOperations[i].quantity);
if (outpost0.items[id]) {
var outpost0_quantity = Number(outpost0.items[id].quantity);
} else {
var outpost0_quantity = "Unknown";
}
if (theater0.items[id]) {
var theater0_quantity = Number(theater0.items[id].quantity);
} else {
var theater0_quantity = "Unknown";
}
if (theater0.items[id] && outpost0.items[id]) {
if (outpost0_quantity > body_quantity) {
theater0.items[id].quantity += body_quantity;
outpost0.items[id].quantity -= body_quantity;
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": theater0.items[id].quantity
});
MultiUpdate[0].profileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": outpost0.items[id].quantity
})
}
if (outpost0_quantity <= body_quantity) {
theater0.items[id].quantity += body_quantity;
delete outpost0.items[id]
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": theater0.items[id].quantity
});
MultiUpdate[0].profileChanges.push({
"changeType": "itemRemoved",
"itemId": id
});
}
}
if (!theater0.items[id] && outpost0.items[id]) {
const Item = JSON.parse(JSON.stringify(outpost0.items[id]));
if (outpost0_quantity > body_quantity) {
outpost0.items[id].quantity -= body_quantity;
Item.quantity = body_quantity;
theater0.items[id] = Item;
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": id,
"item": Item
})
MultiUpdate[0].profileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": outpost0.items[id].quantity
});
}
if (outpost0_quantity <= body_quantity) {
theater0.items[id] = Item;
delete outpost0.items[id]
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": id,
"item": Item
})
MultiUpdate[0].profileChanges.push({
"changeType": "itemRemoved",
"itemId": id
})
}
}
}
if (req.body.transferOperations[i].toStorage == true) {
let id = req.body.transferOperations[i].itemId;
let body_quantity = Number(req.body.transferOperations[i].quantity);
if (outpost0.items[id]) {
var outpost0_quantity = Number(outpost0.items[id].quantity);
} else {
var outpost0_quantity = "Unknown";
}
if (theater0.items[id]) {
var theater0_quantity = Number(theater0.items[id].quantity);
} else {
var theater0_quantity = "Unknown";
}
if (outpost0.items[id] && theater0.items[id]) {
if (theater0_quantity > body_quantity) {
outpost0.items[id].quantity += body_quantity;
theater0.items[id].quantity -= body_quantity;
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": theater0.items[id].quantity
});
MultiUpdate[0].profileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": outpost0.items[id].quantity
})
}
if (theater0_quantity <= body_quantity) {
outpost0.items[id].quantity += body_quantity;
delete theater0.items[id]
MultiUpdate[0].profileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": outpost0.items[id].quantity
});
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": id
});
}
}
if (!outpost0.items[id] && theater0.items[id]) {
const Item = JSON.parse(JSON.stringify(theater0.items[id]));
if (theater0_quantity > body_quantity) {
theater0.items[id].quantity -= body_quantity;
Item.quantity = body_quantity;
outpost0.items[id] = Item;
MultiUpdate[0].profileChanges.push({
"changeType": "itemAdded",
"itemId": id,
"item": Item
})
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": theater0.items[id].quantity
});
}
if (theater0_quantity <= body_quantity) {
outpost0.items[id] = Item;
delete theater0.items[id]
MultiUpdate[0].profileChanges.push({
"changeType": "itemAdded",
"itemId": id,
"item": Item
})
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": id,
})
}
}
}
}
StatChanged = true;
}
if (req.body.theaterToOutpostItems && req.body.outpostToTheaterItems) {
MultiUpdate.push({
"profileRevision": outpost0.rvn || 0,
"profileId": "outpost0",
"profileChangesBaseRevision": outpost0.rvn || 0,
"profileChanges": [],
"profileCommandRevision": outpost0.commandRevision || 0,
})
for (var i in req.body.theaterToOutpostItems) {
let id = req.body.theaterToOutpostItems[i].itemId;
let body_quantity = Number(req.body.theaterToOutpostItems[i].quantity);
if (outpost0.items[id]) {
var outpost0_quantity = Number(outpost0.items[id].quantity);
} else {
var outpost0_quantity = "Unknown";
}
if (theater0.items[id]) {
var theater0_quantity = Number(theater0.items[id].quantity);
} else {
var theater0_quantity = "Unknown";
}
if (outpost0.items[id] && theater0.items[id]) {
if (theater0_quantity > body_quantity) {
outpost0.items[id].quantity += body_quantity;
theater0.items[id].quantity -= body_quantity;
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": theater0.items[id].quantity
});
MultiUpdate[0].profileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": outpost0.items[id].quantity
})
}
if (theater0_quantity <= body_quantity) {
outpost0.items[id].quantity += body_quantity;
delete theater0.items[id]
MultiUpdate[0].profileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": outpost0.items[id].quantity
});
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": id
});
}
}
if (!outpost0.items[id] && theater0.items[id]) {
const Item = JSON.parse(JSON.stringify(theater0.items[id]));
if (theater0_quantity > body_quantity) {
theater0.items[id].quantity -= body_quantity;
Item.quantity = body_quantity;
outpost0.items[id] = Item;
MultiUpdate[0].profileChanges.push({
"changeType": "itemAdded",
"itemId": id,
"item": Item
})
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": theater0.items[id].quantity
});
}
if (theater0_quantity <= body_quantity) {
outpost0.items[id] = Item;
delete theater0.items[id]
MultiUpdate[0].profileChanges.push({
"changeType": "itemAdded",
"itemId": id,
"item": Item
})
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": id,
})
}
}
}
for (var i in req.body.outpostToTheaterItems) {
let id = req.body.outpostToTheaterItems[i].itemId;
let body_quantity = Number(req.body.outpostToTheaterItems[i].quantity);
if (outpost0.items[id]) {
var outpost0_quantity = Number(outpost0.items[id].quantity);
} else {
var outpost0_quantity = "Unknown";
}
if (theater0.items[id]) {
var theater0_quantity = Number(theater0.items[id].quantity);
} else {
var theater0_quantity = "Unknown";
}
if (theater0.items[id] && outpost0.items[id]) {
if (outpost0_quantity > body_quantity) {
theater0.items[id].quantity += body_quantity;
outpost0.items[id].quantity -= body_quantity;
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": theater0.items[id].quantity
});
MultiUpdate[0].profileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": outpost0.items[id].quantity
})
}
if (outpost0_quantity <= body_quantity) {
theater0.items[id].quantity += body_quantity;
delete outpost0.items[id]
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": theater0.items[id].quantity
});
MultiUpdate[0].profileChanges.push({
"changeType": "itemRemoved",
"itemId": id
});
}
}
if (!theater0.items[id] && outpost0.items[id]) {
const Item = JSON.parse(JSON.stringify(outpost0.items[id]));
if (outpost0_quantity > body_quantity) {
outpost0.items[id].quantity -= body_quantity;
Item.quantity = body_quantity;
theater0.items[id] = Item;
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": id,
"item": Item
})
MultiUpdate[0].profileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": id,
"quantity": outpost0.items[id].quantity
});
}
if (outpost0_quantity <= body_quantity) {
theater0.items[id] = Item;
delete outpost0.items[id]
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": id,
"item": Item
})
MultiUpdate[0].profileChanges.push({
"changeType": "itemRemoved",
"itemId": id
})
}
}
}
StatChanged = true;
}
if (StatChanged == true) {
theater0.rvn += 1;
theater0.commandRevision += 1;
outpost0.rvn += 1;
outpost0.commandRevision += 1;
MultiUpdate[0].profileRevision = outpost0.rvn || 0;
MultiUpdate[0].profileCommandRevision = outpost0.commandRevision || 0;
fs.writeFileSync("./profiles/theater0.json", JSON.stringify(theater0, null, 2));
fs.writeFileSync("./profiles/outpost0.json", JSON.stringify(outpost0, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": theater0
}];
}
res.json({
"profileRevision": theater0.rvn || 0,
"profileId": "theater0",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": theater0.commandRevision || 0,
"serverTime": new Date().toISOString(),
"multiUpdate": MultiUpdate,
"responseVersion": 1
})
res.end();
});
// Modify quickbar STW
express.post("/fortnite/api/game/v2/profile/*/client/ModifyQuickbar", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "theater0"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.primaryQuickbarChoices) {
for (var i in req.body.primaryQuickbarChoices) {
let a = Number(i) + 1;
var value = [req.body.primaryQuickbarChoices[i].replace(/-/ig, "").toUpperCase()];
if (req.body.primaryQuickbarChoices[i] == "") {
value = [];
}
profile.stats.attributes.player_loadout.primaryQuickBarRecord.slots[a].items = value;
}
StatChanged = true;
}
if (typeof req.body.secondaryQuickbarChoice == "string") {
var value = [req.body.secondaryQuickbarChoice.replace(/-/ig, "").toUpperCase()];
if (req.body.secondaryQuickbarChoice == "") {
value = [];
}
profile.stats.attributes.player_loadout.secondaryQuickBarRecord.slots[5].items = value;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "player_loadout",
"value": profile.stats.attributes.player_loadout
})
fs.writeFileSync(`./profiles/${req.query.profileId || "theater0"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "theater0",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Hero equipping STW
express.post("/fortnite/api/game/v2/profile/*/client/AssignHeroToLoadout", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.loadoutId && req.body.slotName) {
switch (req.body.slotName) {
case "CommanderSlot":
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot1.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot1 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot2.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot2 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot3.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot3 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot4.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot4 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot5.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot5 = "";
}
profile.items[req.body.loadoutId].attributes.crew_members.commanderslot = req.body.heroId || "";
StatChanged = true;
break;
case "FollowerSlot1":
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.commanderslot.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.commanderslot = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot2.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot2 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot3.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot3 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot4.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot4 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot5.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot5 = "";
}
profile.items[req.body.loadoutId].attributes.crew_members.followerslot1 = req.body.heroId || "";
StatChanged = true;
break;
case "FollowerSlot2":
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot1.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot1 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.commanderslot.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.commanderslot = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot3.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot3 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot4.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot4 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot5.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot5 = "";
}
profile.items[req.body.loadoutId].attributes.crew_members.followerslot2 = req.body.heroId || "";
StatChanged = true;
break;
case "FollowerSlot3":
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot1.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot1 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot2.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot2 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.commanderslot.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.commanderslot = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot4.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot4 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot5.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot5 = "";
}
profile.items[req.body.loadoutId].attributes.crew_members.followerslot3 = req.body.heroId || "";
StatChanged = true;
break;
case "FollowerSlot4":
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot1.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot1 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot2.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot2 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot3.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot3 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.commanderslot.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.commanderslot = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot5.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot5 = "";
}
profile.items[req.body.loadoutId].attributes.crew_members.followerslot4 = req.body.heroId || "";
StatChanged = true;
break;
case "FollowerSlot5":
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot1.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot1 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot2.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot2 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot3.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot3 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot4.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.followerslot4 = "";
}
if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.commanderslot.toLowerCase()) {
profile.items[req.body.loadoutId].attributes.crew_members.commanderslot = "";
}
profile.items[req.body.loadoutId].attributes.crew_members.followerslot5 = req.body.heroId || "";
StatChanged = true;
break;
}
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.loadoutId,
"attributeName": "crew_members",
"attributeValue": profile.items[req.body.loadoutId].attributes.crew_members
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Clear hero loadout STW
express.post("/fortnite/api/game/v2/profile/*/client/ClearHeroLoadout", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.loadoutId) {
profile.items[req.body.loadoutId].attributes = {
"team_perk": "",
"loadout_name": profile.items[req.body.loadoutId].attributes.loadout_name,
"crew_members": {
"followerslot5": "",
"followerslot4": "",
"followerslot3": "",
"followerslot2": "",
"followerslot1": "",
"commanderslot": profile.items[req.body.loadoutId].attributes.crew_members.commanderslot
},
"loadout_index": profile.items[req.body.loadoutId].attributes.loadout_index,
"gadgets": [
{
"gadget": "",
"slot_index": 0
},
{
"gadget": "",
"slot_index": 1
}
]
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.loadoutId,
"attributeName": "team_perk",
"attributeValue": profile.items[req.body.loadoutId].attributes.team_perk
})
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.loadoutId,
"attributeName": "crew_members",
"attributeValue": profile.items[req.body.loadoutId].attributes.crew_members
})
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.loadoutId,
"attributeName": "gadgets",
"attributeValue": profile.items[req.body.loadoutId].attributes.gadgets
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Recycle items STW
express.post("/fortnite/api/game/v2/profile/*/client/RecycleItemBatch", async (req, res) => {
functions.GetVersionInfo(req, memory);
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var MultiUpdate = [];
var Notifications = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
var ItemExists = false;
if (req.body.targetItemIds) {
for (var i in req.body.targetItemIds) {
let id = req.body.targetItemIds[i];
if (memory.season > 11 || memory.build == 11.30 || memory.build == 11.31 || memory.build == 11.40 || memory.build == 11.50) {
var collection_book_profile = require("./../profiles/collection_book_people0.json");
if (profile.items[id].templateId.toLowerCase().startsWith("schematic:")) {
collection_book_profile = require("./../profiles/collection_book_schematics0.json");
}
if (MultiUpdate.length == 0) {
MultiUpdate.push({
"profileRevision": collection_book_profile.rvn || 0,
"profileId": collection_book_profile.profileId || "collection_book_people0",
"profileChangesBaseRevision": collection_book_profile.rvn || 0,
"profileChanges": [],
"profileCommandRevision": collection_book_profile.commandRevision || 0,
})
}
for (var key in collection_book_profile.items) {
const Template1 = profile.items[id].templateId;
const Template2 = collection_book_profile.items[key].templateId;
if (Template1.substring(0, Template1.length - 4).toLowerCase() == Template2.substring(0, Template2.length - 4).toLowerCase()) {
if (Template1.toLowerCase().startsWith("worker:") && Template2.toLowerCase().startsWith("worker:")) {
if (profile.items[id].attributes.hasOwnProperty("personality") && collection_book_profile.items[key].attributes.hasOwnProperty("personality")) {
const Personality1 = profile.items[id].attributes.personality;
const Personality2 = collection_book_profile.items[key].attributes.personality;
if (Personality1.toLowerCase() == Personality2.toLowerCase()) {
if (profile.items[id].attributes.level > collection_book_profile.items[key].attributes.level) {
delete collection_book_profile.items[key];
MultiUpdate[0].profileChanges.push({
"changeType": "itemRemoved",
"itemId": key
})
ItemExists = false;
} else {
ItemExists = true;
}
}
}
} else {
if (profile.items[id].attributes.level > collection_book_profile.items[key].attributes.level) {
delete collection_book_profile.items[key];
MultiUpdate[0].profileChanges.push({
"changeType": "itemRemoved",
"itemId": key
})
ItemExists = false;
} else {
ItemExists = true;
}
}
}
}
if (ItemExists == false) {
collection_book_profile.items[id] = profile.items[id];
MultiUpdate[0].profileChanges.push({
"changeType": "itemAdded",
"itemId": id,
"item": collection_book_profile.items[id]
})
Notifications.push({
"type": "slotItemResult",
"primary": true,
"slottedItemId": id
})
}
delete profile.items[id];
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": id
})
collection_book_profile.rvn += 1;
collection_book_profile.commandRevision += 1;
MultiUpdate[0].profileRevision = collection_book_profile.rvn;
MultiUpdate[0].profileCommandRevision = collection_book_profile.commandRevision;
fs.writeFileSync(`./profiles/${collection_book_profile.profileId || "collection_book_people0"}.json`, JSON.stringify(collection_book_profile, null, 2));
} else {
delete profile.items[id];
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": id
})
}
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"notifications": Notifications,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"multiUpdate": MultiUpdate,
"responseVersion": 1
})
res.end();
});
// Add item from collection book STW
express.post("/fortnite/api/game/v2/profile/*/client/ResearchItemFromCollectionBook", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
const ID = functions.MakeID();
if (req.body.templateId) {
profile.items[ID] = {
"templateId": req.body.templateId,
"attributes": {
"last_state_change_time": "2017-08-29T21:05:57.087Z",
"max_level_bonus": 0,
"level": 1,
"item_seen": false,
"xp": 0,
"sent_new_notification": true,
"favorite": false
},
"quantity": 1
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": profile.items[ID]
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Slot item in collection book STW
express.post("/fortnite/api/game/v2/profile/*/client/SlotItemInCollectionBook", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var MultiUpdate = [];
var Notifications = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
var collection_book_profile = require("./../profiles/collection_book_people0.json");
if (profile.items[req.body.itemId].templateId.toLowerCase().startsWith("schematic:")) {
collection_book_profile = require("./../profiles/collection_book_schematics0.json");
}
if (req.body.itemId) {
MultiUpdate.push({
"profileRevision": collection_book_profile.rvn || 0,
"profileId": collection_book_profile.profileId || "collection_book_people0",
"profileChangesBaseRevision": collection_book_profile.rvn || 0,
"profileChanges": [],
"profileCommandRevision": collection_book_profile.commandRevision || 0,
})
for (var key in collection_book_profile.items) {
const Template1 = profile.items[req.body.itemId].templateId;
const Template2 = collection_book_profile.items[key].templateId;
if (Template1.substring(0, Template1.length-4).toLowerCase() == Template2.substring(0, Template2.length-4).toLowerCase()) {
if (Template1.toLowerCase().startsWith("worker:") && Template2.toLowerCase().startsWith("worker:")) {
if (profile.items[req.body.itemId].attributes.hasOwnProperty("personality") && collection_book_profile.items[key].attributes.hasOwnProperty("personality")) {
const Personality1 = profile.items[req.body.itemId].attributes.personality;
const Personality2 = collection_book_profile.items[key].attributes.personality;
if (Personality1.toLowerCase() == Personality2.toLowerCase()) {
delete collection_book_profile.items[key];
MultiUpdate[0].profileChanges.push({
"changeType": "itemRemoved",
"itemId": key
})
}
}
} else {
delete collection_book_profile.items[key];
MultiUpdate[0].profileChanges.push({
"changeType": "itemRemoved",
"itemId": key
})
}
}
}
collection_book_profile.items[req.body.itemId] = profile.items[req.body.itemId];
delete profile.items[req.body.itemId];
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
collection_book_profile.rvn += 1;
collection_book_profile.commandRevision += 1;
MultiUpdate[0].profileRevision = collection_book_profile.rvn || 0;
MultiUpdate[0].profileCommandRevision = collection_book_profile.commandRevision || 0;
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": req.body.itemId
})
MultiUpdate[0].profileChanges.push({
"changeType": "itemAdded",
"itemId": req.body.itemId,
"item": collection_book_profile.items[req.body.itemId]
})
Notifications.push({
"type": "slotItemResult",
"primary": true,
"slottedItemId": req.body.itemId
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
fs.writeFileSync(`./profiles/${collection_book_profile.profileId || "collection_book_people0"}.json`, JSON.stringify(collection_book_profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"notifications": Notifications,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"multiUpdate": MultiUpdate,
"responseVersion": 1
})
res.end();
});
// Unslot item from collection book STW
express.post("/fortnite/api/game/v2/profile/*/client/UnslotItemFromCollectionBook", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var MultiUpdate = [];
var Notifications = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
var collection_book_profile = require("./../profiles/collection_book_people0.json");
if (req.body.templateId.toLowerCase().startsWith("schematic:")) {
collection_book_profile = require("./../profiles/collection_book_schematics0.json");
}
const ID = functions.MakeID();
MultiUpdate.push({
"profileRevision": collection_book_profile.rvn || 0,
"profileId": collection_book_profile.profileId || "collection_book_people0",
"profileChangesBaseRevision": collection_book_profile.rvn || 0,
"profileChanges": [],
"profileCommandRevision": collection_book_profile.commandRevision || 0,
})
if (profile.items[req.body.itemId]) {
profile.items[ID] = collection_book_profile.items[req.body.itemId];
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": profile.items[ID]
})
delete collection_book_profile.items[req.body.itemId];
MultiUpdate[0].profileChanges.push({
"changeType": "itemRemoved",
"itemId": req.body.itemId
})
StatChanged = true;
}
if (!profile.items[req.body.itemId]) {
profile.items[req.body.itemId] = collection_book_profile.items[req.body.itemId];
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": req.body.itemId,
"item": profile.items[req.body.itemId]
})
delete collection_book_profile.items[req.body.itemId];
MultiUpdate[0].profileChanges.push({
"changeType": "itemRemoved",
"itemId": req.body.itemId
})
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
collection_book_profile.rvn += 1;
collection_book_profile.commandRevision += 1;
MultiUpdate[0].profileRevision = collection_book_profile.rvn || 0;
MultiUpdate[0].profileCommandRevision = collection_book_profile.commandRevision || 0;
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
fs.writeFileSync(`./profiles/${collection_book_profile.profileId || "collection_book_people0"}.json`, JSON.stringify(collection_book_profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"notifications": Notifications,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"multiUpdate": MultiUpdate,
"responseVersion": 1
})
res.end();
});
// Claim collection book rewards STW
express.post("/fortnite/api/game/v2/profile/*/client/ClaimCollectionBookRewards", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.requiredXp) {
profile.stats.attributes.collection_book.maxBookXpLevelAchieved += 1;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "collection_book",
"value": profile.stats.attributes.collection_book
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Modify schematic perk STW
express.post("/fortnite/api/game/v2/profile/*/client/RespecAlteration", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.targetItemId && req.body.alterationId) {
if (!profile.items[req.body.targetItemId].attributes.alterations) {
profile.items[req.body.targetItemId].attributes.alterations = ["","","","","",""];
}
profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot] = req.body.alterationId;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.targetItemId,
"attributeName": "alterations",
"attributeValue": profile.items[req.body.targetItemId].attributes.alterations
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Upgrade schematic perk STW
express.post("/fortnite/api/game/v2/profile/*/client/UpgradeAlteration", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.targetItemId) {
if (profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot].toLowerCase().includes("t04")) {
profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot] = profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot].replace(/t04/ig, "T05");
}
if (profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot].toLowerCase().includes("t03")) {
profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot] = profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot].replace(/t03/ig, "T04");
}
if (profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot].toLowerCase().includes("t02")) {
profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot] = profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot].replace(/t02/ig, "T03");
}
if (profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot].toLowerCase().includes("t01")) {
profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot] = profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot].replace(/t01/ig, "T02");
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.targetItemId,
"attributeName": "alterations",
"attributeValue": profile.items[req.body.targetItemId].attributes.alterations
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Reset research levels STW
express.post("/fortnite/api/game/v2/profile/*/client/RespecResearch", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (profile.stats.attributes.research_levels) {
profile.stats.attributes.research_levels.technology = 0;
profile.stats.attributes.research_levels.fortitude = 0;
profile.stats.attributes.research_levels.offense = 0;
profile.stats.attributes.research_levels.resistance = 0;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "research_levels",
"value": profile.stats.attributes.research_levels
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Reset upgrade levels STW
express.post("/fortnite/api/game/v2/profile/*/client/RespecUpgrades", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
for (var key in profile.items) {
if (profile.items[key].templateId.toLowerCase().startsWith("homebasenode:skilltree_")) {
profile.items[key].quantity = 0;
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": key,
"quantity": profile.items[key].quantity
})
}
}
StatChanged = true;
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Upgrade research levels STW
express.post("/fortnite/api/game/v2/profile/*/client/PurchaseResearchStatUpgrade", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (profile.stats.attributes.research_levels && req.body.statId) {
profile.stats.attributes.research_levels[req.body.statId] += 1;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "research_levels",
"value": profile.stats.attributes.research_levels
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Upgrade levels STW
express.post("/fortnite/api/game/v2/profile/*/client/PurchaseOrUpgradeHomebaseNode", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
var CreateHomebaseNode = true;
if (req.body.nodeId) {
for (var key in profile.items) {
if (profile.items[key].templateId.toLowerCase() == req.body.nodeId.toLowerCase()) {
profile.items[key].quantity += 1;
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": key,
"quantity": profile.items[key].quantity
})
CreateHomebaseNode = false;
}
}
if (CreateHomebaseNode == true) {
const ID = functions.MakeID();
profile.items[ID] = {
"templateId": req.body.nodeId,
"attributes": {
"item_seen": false
},
"quantity": 1
}
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": profile.items[ID]
})
}
}
StatChanged = true;
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Set active hero loadout STW
express.post("/fortnite/api/game/v2/profile/*/client/SetActiveHeroLoadout", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.selectedLoadout) {
profile.stats.attributes.selected_hero_loadout = req.body.selectedLoadout;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "selected_hero_loadout",
"value": profile.stats.attributes.selected_hero_loadout
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Activate consumable STW
express.post("/fortnite/api/game/v2/profile/*/client/ActivateConsumable", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
var XPBoost;
if (req.body.targetItemId) {
profile.items[req.body.targetItemId].quantity -= 1;
for (var key in profile.items) {
if (profile.items[key].templateId == "Token:xpboost") {
var randomNumber = Math.floor(Math.random() * 1250000);
if (randomNumber < 1000000) {
randomNumber += 1000000
}
profile.items[key].quantity += randomNumber;
XPBoost = key;
}
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": req.body.targetItemId,
"quantity": profile.items[req.body.targetItemId].quantity
})
if (XPBoost) {
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": XPBoost,
"quantity": profile.items[XPBoost].quantity
})
}
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Unassign all squads STW
express.post("/fortnite/api/game/v2/profile/*/client/UnassignAllSquads", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.squadIds) {
for (var i in req.body.squadIds) {
let id = req.body.squadIds[i];
for (var key in profile.items) {
if (profile.items[key].attributes.hasOwnProperty('squad_id')) {
if (profile.items[key].attributes.squad_id.toLowerCase() == id.toLowerCase()) {
profile.items[key].attributes.squad_id = "";
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": key,
"attributeName": "squad_id",
"attributeValue": profile.items[key].attributes.squad_id
})
}
}
}
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Open llama STW
express.post("/fortnite/api/game/v2/profile/*/client/OpenCardPack", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
const ItemIDS = require("./../responses/ItemIDS.json");
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var Notifications = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.cardPackItemId) {
Notifications.push({
"type": "cardPackResult",
"primary": true,
"lootGranted": {
"tierGroupName": profile.items[req.body.cardPackItemId].templateId.split(":")[1],
"items": []
},
"displayLevel": 0
})
for (var i = 0; i < 10; i++) {
const randomNumber = Math.floor(Math.random() * ItemIDS.length);
const ID = functions.MakeID();
var Item = {"templateId":ItemIDS[randomNumber],"attributes":{"legacy_alterations":[],"max_level_bonus":0,"level":1,"refund_legacy_item":false,"item_seen":false,"alterations":["","","","","",""],"xp":0,"refundable":false,"alteration_base_rarities":[],"favorite":false},"quantity":1};
profile.items[ID] = Item
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": Item
})
Notifications[0].lootGranted.items.push({
"itemType": ItemIDS[randomNumber],
"itemGuid": ID,
"itemProfile": req.query.profileId,
"attributes": Item.attributes,
"quantity": 1
})
}
if (profile.items[req.body.cardPackItemId].quantity <= 1) {
delete profile.items[req.body.cardPackItemId]
ApplyProfileChanges.push({
"changeType": "itemRemoved",
"itemId": req.body.cardPackItemId
})
}
try {
profile.items[req.body.cardPackItemId].quantity -= 1;
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": req.body.cardPackItemId,
"quantity": profile.items[req.body.cardPackItemId].quantity
})
} catch (err) {}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"notifications": Notifications,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Add items to StW X-Ray Llamas
express.post("/fortnite/api/game/v2/profile/*/client/PopulatePrerolledOffers", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
const ItemIDS = require("./../responses/ItemIDS.json");
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
var date = new Date().toISOString();
for (var key in profile.items) {
if (profile.items[key].templateId.toLowerCase() == "prerolldata:preroll_basic") {
if (date > profile.items[key].attributes.expiration) {
profile.items[key].attributes.items = [];
for (var i = 0; i < 10; i++) {
const randomNumber = Math.floor(Math.random() * ItemIDS.length);
profile.items[key].attributes.items.push({"itemType":ItemIDS[randomNumber],"attributes":{"legacy_alterations":[],"max_level_bonus":0,"level":1,"refund_legacy_item":false,"item_seen":false,"alterations":["","","","","",""],"xp":0,"refundable":false,"alteration_base_rarities":[],"favorite":false},"quantity":1})
}
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": key,
"attributeName": "items",
"attributeValue": profile.items[key].attributes.items
})
profile.items[key].attributes.expiration = new Date().toISOString().split("T")[0] + "T23:59:59.999Z";
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": key,
"attributeName": "expiration",
"attributeValue": profile.items[key].attributes.expiration
})
StatChanged = true;
}
}
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Purchase item
express.post("/fortnite/api/game/v2/profile/*/client/PurchaseCatalogEntry", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "profile0"}.json`);
const campaign = require("./../profiles/campaign.json");
const athena = require("./../profiles/athena.json");
const ItemIDS = require("./../responses/ItemIDS.json");
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var MultiUpdate = [];
var Notifications = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var PurchasedLlama = false;
var AthenaModified = false;
var ItemExists = false;
if (req.body.offerId && profile.profileId == "profile0" && PurchasedLlama == false) {
catalog.storefronts.forEach(function(value, a) {
if (value.name.toLowerCase().startsWith("cardpack")) {
catalog.storefronts[a].catalogEntries.forEach(function(value, b) {
if (value.offerId == req.body.offerId) {
var Quantity = 0;
catalog.storefronts[a].catalogEntries[b].itemGrants.forEach(function(value, c) {
Quantity = req.body.purchaseQuantity || 1;
const Item = {
"templateId": value.templateId,
"attributes": {
"is_loot_tier_overridden": false,
"max_level_bonus": 0,
"level": 1391,
"pack_source": "Schedule",
"item_seen": false,
"xp": 0,
"favorite": false,
"override_loot_tier": 0
},
"quantity": 1
};
for (var i = 0; i < Quantity; i++) {
var ID = functions.MakeID();
profile.items[ID] = Item
ApplyProfileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": profile.items[ID]
})
}
})
// Vbucks spending
if (catalog.storefronts[a].catalogEntries[b].prices[0].currencyType.toLowerCase() == "mtxcurrency") {
for (var key in profile.items) {
if (profile.items[key].templateId.toLowerCase().startsWith("currency:mtx")) {
if (profile.items[key].attributes.platform.toLowerCase() == profile.stats.attributes.current_mtx_platform.toLowerCase() || profile.items[key].attributes.platform.toLowerCase() == "shared") {
profile.items[key].quantity -= (catalog.storefronts[a].catalogEntries[b].prices[0].finalPrice) * Quantity;
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": key,
"quantity": profile.items[key].quantity
})
profile.rvn += 1;
profile.commandRevision += 1;
break;
}
}
}
}
}
})
}
if (value.name.startsWith("BR")) {
catalog.storefronts[a].catalogEntries.forEach(function(value, b) {
if (value.offerId == req.body.offerId) {
catalog.storefronts[a].catalogEntries[b].itemGrants.forEach(function(value, c) {
const ID = value.templateId;
for (var key in athena.items) {
if (value.templateId.toLowerCase() == athena.items[key].templateId.toLowerCase()) {
ItemExists = true;
}
}
if (ItemExists == false) {
if (MultiUpdate.length == 0) {
MultiUpdate.push({
"profileRevision": athena.rvn || 0,
"profileId": "athena",
"profileChangesBaseRevision": athena.rvn || 0,
"profileChanges": [],
"profileCommandRevision": athena.commandRevision || 0,
})
}
if (Notifications.length == 0) {
Notifications.push({
"type": "CatalogPurchase",
"primary": true,
"lootResult": {
"items": []
}
})
}
const Item = {
"templateId": value.templateId,
"attributes": {
"max_level_bonus": 0,
"level": 1,
"item_seen": false,
"xp": 0,
"variants": [],
"favorite": false
},
"quantity": 1
};
athena.items[ID] = Item;
MultiUpdate[0].profileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": athena.items[ID]
})
Notifications[0].lootResult.items.push({
"itemType": value.templateId,
"itemGuid": ID,
"itemProfile": "athena",
"quantity": value.quantity
})
AthenaModified = true;
}
ItemExists = false;
})
// Vbucks spending
if (catalog.storefronts[a].catalogEntries[b].prices[0].currencyType.toLowerCase() == "mtxcurrency") {
for (var key in profile.items) {
if (profile.items[key].templateId.toLowerCase().startsWith("currency:mtx")) {
if (profile.items[key].attributes.platform.toLowerCase() == profile.stats.attributes.current_mtx_platform.toLowerCase() || profile.items[key].attributes.platform.toLowerCase() == "shared") {
profile.items[key].quantity -= catalog.storefronts[a].catalogEntries[b].prices[0].finalPrice;
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": key,
"quantity": profile.items[key].quantity
})
profile.rvn += 1;
profile.commandRevision += 1;
break;
}
}
}
}
}
})
}
})
PurchasedLlama = true;
if (AthenaModified == true) {
athena.rvn += 1;
athena.commandRevision += 1;
MultiUpdate[0].profileRevision = athena.rvn || 0;
MultiUpdate[0].profileCommandRevision = athena.commandRevision || 0;
fs.writeFileSync("./profiles/athena.json", JSON.stringify(athena, null, 2));
fs.writeFileSync(`./profiles/${req.query.profileId || "profile0"}.json`, JSON.stringify(profile, null, 2));
}
if (AthenaModified == false) {
profile.rvn += 1;
profile.commandRevision += 1;
fs.writeFileSync(`./profiles/${req.query.profileId || "profile0"}.json`, JSON.stringify(profile, null, 2));
}
}
if (req.body.offerId && profile.profileId == "common_core") {
catalog.storefronts.forEach(function(value, a) {
if (value.name.toLowerCase().startsWith("cardpack")) {
catalog.storefronts[a].catalogEntries.forEach(function(value, b) {
if (value.offerId == req.body.offerId) {
var Quantity = 0;
catalog.storefronts[a].catalogEntries[b].itemGrants.forEach(function(value, c) {
functions.GetVersionInfo(req, memory);
if (4 >= memory.season && PurchasedLlama == false) {
if (MultiUpdate.length == 0) {
MultiUpdate.push({
"profileRevision": campaign.rvn || 0,
"profileId": "campaign",
"profileChangesBaseRevision": campaign.rvn || 0,
"profileChanges": [],
"profileCommandRevision": campaign.commandRevision || 0,
})
}
Quantity = req.body.purchaseQuantity || 1;
const Item = {
"templateId": value.templateId,
"attributes": {
"is_loot_tier_overridden": false,
"max_level_bonus": 0,
"level": 1391,
"pack_source": "Schedule",
"item_seen": false,
"xp": 0,
"favorite": false,
"override_loot_tier": 0
},
"quantity": 1
};
for (var i = 0; i < Quantity; i++) {
var ID = functions.MakeID();
campaign.items[ID] = Item
MultiUpdate[0].profileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": campaign.items[ID]
})
}
PurchasedLlama = true;
}
if (memory.build >= 5 && memory.build <= 7.20 && PurchasedLlama == false) {
if (MultiUpdate.length == 0) {
MultiUpdate.push({
"profileRevision": campaign.rvn || 0,
"profileId": "campaign",
"profileChangesBaseRevision": campaign.rvn || 0,
"profileChanges": [],
"profileCommandRevision": campaign.commandRevision || 0,
})
}
Quantity = req.body.purchaseQuantity || 1;
const Item = {
"templateId": value.templateId,
"attributes": {
"is_loot_tier_overridden": false,
"max_level_bonus": 0,
"level": 1391,
"pack_source": "Schedule",
"item_seen": false,
"xp": 0,
"favorite": false,
"override_loot_tier": 0
},
"quantity": 1
};
for (var i = 0; i < Quantity; i++) {
var ID = functions.MakeID();
campaign.items[ID] = Item
MultiUpdate[0].profileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": campaign.items[ID]
})
}
Notifications.push({
"type": "cardPackResult",
"primary": true,
"lootGranted": {
"tierGroupName": "",
"items": []
},
"displayLevel": 0
})
PurchasedLlama = true;
}
if (6 < memory.season && PurchasedLlama == false) {
if (MultiUpdate.length == 0) {
MultiUpdate.push({
"profileRevision": campaign.rvn || 0,
"profileId": "campaign",
"profileChangesBaseRevision": campaign.rvn || 0,
"profileChanges": [],
"profileCommandRevision": campaign.commandRevision || 0,
})
}
Quantity = req.body.purchaseQuantity || 1;
var LlamaItemIDS = [];
var Item = {
"templateId": value.templateId,
"attributes": {
"is_loot_tier_overridden": false,
"max_level_bonus": 0,
"level": 1391,
"pack_source": "Schedule",
"item_seen": false,
"xp": 0,
"favorite": false,
"override_loot_tier": 0
},
"quantity": 1
};
for (var i = 0; i < Quantity; i++) {
var ID = functions.MakeID();
campaign.items[ID] = Item
MultiUpdate[0].profileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": campaign.items[ID]
})
LlamaItemIDS.push(ID);
}
Notifications.push({
"type": "CatalogPurchase",
"primary": true,
"lootResult": {
"items": []
}
})
if (req.body.currencySubType.toLowerCase() == "accountresource:voucher_basicpack") {
Notifications[0].lootResult.items.push({
"itemType": value.templateId,
"itemGuid": ID,
"itemProfile": "campaign",
"attributes": {
"pack_source": "Store"
},
"quantity": 1
})
} else {
for (var x = 0; x < Quantity; x++) {
for (var key in campaign.items) {
if (campaign.items[key].templateId.toLowerCase() == "prerolldata:preroll_basic") {
if (campaign.items[key].attributes.offerId == req.body.offerId) {
for (var item in campaign.items[key].attributes.items) {
const id = functions.MakeID();
var Item = {"templateId":campaign.items[key].attributes.items[item].itemType,"attributes":campaign.items[key].attributes.items[item].attributes,"quantity":campaign.items[key].attributes.items[item].quantity};
campaign.items[id] = Item;
MultiUpdate[0].profileChanges.push({
"changeType": "itemAdded",
"itemId": id,
"item": Item
})
Notifications[0].lootResult.items.push({
"itemType": campaign.items[key].attributes.items[item].itemType,
"itemGuid": id,
"itemProfile": "campaign",
"attributes": Item.attributes,
"quantity": 1
})
}
campaign.items[key].attributes.items = [];
for (var i = 0; i < 10; i++) {
const randomNumber = Math.floor(Math.random() * ItemIDS.length);
campaign.items[key].attributes.items.push({"itemType":ItemIDS[randomNumber],"attributes":{"legacy_alterations":[],"max_level_bonus":0,"level":1,"refund_legacy_item":false,"item_seen":false,"alterations":["","","","","",""],"xp":0,"refundable":false,"alteration_base_rarities":[],"favorite":false},"quantity":1})
}
MultiUpdate[0].profileChanges.push({
"changeType": "itemAttrChanged",
"itemId": key,
"attributeName": "items",
"attributeValue": campaign.items[key].attributes.items
})
}
}
}
}
}
try {
for (var i in LlamaItemIDS) {
var id = LlamaItemIDS[i];
delete campaign.items[id];
MultiUpdate[0].profileChanges.push({
"changeType": "itemRemoved",
"itemId": id
})
}
} catch (err) {}
PurchasedLlama = true;
}
})
// Vbucks spending
if (catalog.storefronts[a].catalogEntries[b].prices[0].currencyType.toLowerCase() == "mtxcurrency") {
for (var key in profile.items) {
if (profile.items[key].templateId.toLowerCase().startsWith("currency:mtx")) {
if (profile.items[key].attributes.platform.toLowerCase() == profile.stats.attributes.current_mtx_platform.toLowerCase() || profile.items[key].attributes.platform.toLowerCase() == "shared") {
profile.items[key].quantity -= (catalog.storefronts[a].catalogEntries[b].prices[0].finalPrice) * Quantity;
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": key,
"quantity": profile.items[key].quantity
})
profile.rvn += 1;
profile.commandRevision += 1;
break;
}
}
}
}
}
})
}
if (value.name.startsWith("BR")) {
catalog.storefronts[a].catalogEntries.forEach(function(value, b) {
if (value.offerId == req.body.offerId) {
catalog.storefronts[a].catalogEntries[b].itemGrants.forEach(function(value, c) {
const ID = value.templateId;
for (var key in athena.items) {
if (value.templateId.toLowerCase() == athena.items[key].templateId.toLowerCase()) {
ItemExists = true;
}
}
if (ItemExists == false) {
if (MultiUpdate.length == 0) {
MultiUpdate.push({
"profileRevision": athena.rvn || 0,
"profileId": "athena",
"profileChangesBaseRevision": athena.rvn || 0,
"profileChanges": [],
"profileCommandRevision": athena.commandRevision || 0,
})
}
if (Notifications.length == 0) {
Notifications.push({
"type": "CatalogPurchase",
"primary": true,
"lootResult": {
"items": []
}
})
}
const Item = {
"templateId": value.templateId,
"attributes": {
"max_level_bonus": 0,
"level": 1,
"item_seen": false,
"xp": 0,
"variants": [],
"favorite": false
},
"quantity": 1
};
athena.items[ID] = Item;
MultiUpdate[0].profileChanges.push({
"changeType": "itemAdded",
"itemId": ID,
"item": Item
})
Notifications[0].lootResult.items.push({
"itemType": value.templateId,
"itemGuid": ID,
"itemProfile": "athena",
"quantity": value.quantity
})
AthenaModified = true;
}
ItemExists = false;
})
// Vbucks spending
if (catalog.storefronts[a].catalogEntries[b].prices[0].currencyType.toLowerCase() == "mtxcurrency") {
for (var key in profile.items) {
if (profile.items[key].templateId.toLowerCase().startsWith("currency:mtx")) {
if (profile.items[key].attributes.platform.toLowerCase() == profile.stats.attributes.current_mtx_platform.toLowerCase() || profile.items[key].attributes.platform.toLowerCase() == "shared") {
profile.items[key].quantity -= catalog.storefronts[a].catalogEntries[b].prices[0].finalPrice;
ApplyProfileChanges.push({
"changeType": "itemQuantityChanged",
"itemId": key,
"quantity": profile.items[key].quantity
})
break;
}
}
}
}
// Add to refunding tab
var purchaseId = functions.MakeID();
profile.stats.attributes.mtx_purchase_history.purchases.push({"purchaseId":purchaseId,"offerId":`v2:/${purchaseId}`,"purchaseDate":"9999-12-31T00:00:00.000Z","freeRefundEligible":false,"fulfillments":[],"lootResult":Notifications[0].lootResult.items,"totalMtxPaid":catalog.storefronts[a].catalogEntries[b].prices[0].finalPrice,"metadata":{},"gameContext":""})
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "mtx_purchase_history",
"value": profile.stats.attributes.mtx_purchase_history
})
profile.rvn += 1;
profile.commandRevision += 1;
}
})
}
})
if (AthenaModified == true) {
athena.rvn += 1;
athena.commandRevision += 1;
MultiUpdate[0].profileRevision = athena.rvn || 0;
MultiUpdate[0].profileCommandRevision = athena.commandRevision || 0;
fs.writeFileSync("./profiles/athena.json", JSON.stringify(athena, null, 2));
fs.writeFileSync(`./profiles/${req.query.profileId || "profile0"}.json`, JSON.stringify(profile, null, 2));
}
if (AthenaModified == false) {
campaign.rvn += 1;
campaign.commandRevision += 1;
MultiUpdate[0].profileRevision = campaign.rvn || 0;
MultiUpdate[0].profileCommandRevision = campaign.commandRevision || 0;
fs.writeFileSync("./profiles/campaign.json", JSON.stringify(campaign, null, 2));
}
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "profile0",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"notifications": Notifications,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"multiUpdate": MultiUpdate,
"responseVersion": 1
})
res.end();
});
// Set multiple items favorite
express.post("/fortnite/api/game/v2/profile/*/client/SetItemFavoriteStatusBatch", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "athena"}.json`);
if (profile.profileId == "athena") {
functions.GetVersionInfo(req, memory);
profile.stats.attributes.season_num = memory.season;
if (memory.season == 2) {
profile.stats.attributes.book_level = 70;
} else {
profile.stats.attributes.book_level = 100;
}
}
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.itemIds) {
for (var i in req.body.itemIds) {
profile.items[req.body.itemIds[i]].attributes.favorite = req.body.itemFavStatus[i] || false;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.itemIds[i],
"attributeName": "favorite",
"attributeValue": profile.items[req.body.itemIds[i]].attributes.favorite
})
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "athena",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Set favorite on item
express.post("/fortnite/api/game/v2/profile/*/client/SetItemFavoriteStatus", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "athena"}.json`);
if (profile.profileId == "athena") {
functions.GetVersionInfo(req, memory);
profile.stats.attributes.season_num = memory.season;
if (memory.season == 2) {
profile.stats.attributes.book_level = 70;
} else {
profile.stats.attributes.book_level = 100;
}
}
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.targetItemId) {
profile.items[req.body.targetItemId].attributes.favorite = req.body.bFavorite || false;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.targetItemId,
"attributeName": "favorite",
"attributeValue": profile.items[req.body.targetItemId].attributes.favorite
})
fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "athena",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Mark item as seen
express.post("/fortnite/api/game/v2/profile/*/client/MarkItemSeen", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "athena"}.json`);
if (profile.profileId == "athena") {
functions.GetVersionInfo(req, memory);
profile.stats.attributes.season_num = memory.season;
if (memory.season == 2) {
profile.stats.attributes.book_level = 70;
} else {
profile.stats.attributes.book_level = 100;
}
}
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.itemIds) {
for (var i in req.body.itemIds) {
profile.items[req.body.itemIds[i]].attributes.item_seen = true;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.itemIds[i],
"attributeName": "item_seen",
"attributeValue": profile.items[req.body.itemIds[i]].attributes.item_seen
})
}
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "athena",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Equip BR Locker 1
express.post("/fortnite/api/game/v2/profile/*/client/EquipBattleRoyaleCustomization", async (req, res) => {
const profile = require("./../profiles/athena.json");
functions.GetVersionInfo(req, memory);
profile.stats.attributes.season_num = memory.season;
if (memory.season == 2) {
profile.stats.attributes.book_level = 70;
} else {
profile.stats.attributes.book_level = 100;
}
try {
if (!profile.stats.attributes.favorite_dance) {
profile.stats.attributes.favorite_dance = ["","","","","",""];
}
if (!profile.stats.attributes.favorite_itemwraps) {
profile.stats.attributes.favorite_itemwraps = ["","","","","","",""];
}
} catch (err) {}
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
var VariantChanged = false;
try {
const ReturnVariantsAsString = JSON.stringify(req.body.variantUpdates || [])
if (ReturnVariantsAsString.includes("active")) {
if (profile.items[req.body.itemToSlot].attributes.variants.length == 0) {
profile.items[req.body.itemToSlot].attributes.variants = req.body.variantUpdates || [];
}
for (var i in profile.items[req.body.itemToSlot].attributes.variants) {
profile.items[req.body.itemToSlot].attributes.variants[i].active = req.body.variantUpdates[i].active || "";
}
VariantChanged = true;
}
} catch (err) {}
if (req.body.slotName) {
switch (req.body.slotName) {
case "Character":
profile.stats.attributes.favorite_character = req.body.itemToSlot || "";
StatChanged = true;
break;
case "Backpack":
profile.stats.attributes.favorite_backpack = req.body.itemToSlot || "";
StatChanged = true;
break;
case "Pickaxe":
profile.stats.attributes.favorite_pickaxe = req.body.itemToSlot || "";
StatChanged = true;
break;
case "Glider":
profile.stats.attributes.favorite_glider = req.body.itemToSlot || "";
StatChanged = true;
break;
case "SkyDiveContrail":
profile.stats.attributes.favorite_skydivecontrail = req.body.itemToSlot || "";
StatChanged = true;
break;
case "MusicPack":
profile.stats.attributes.favorite_musicpack = req.body.itemToSlot || "";
StatChanged = true;
break;
case "LoadingScreen":
profile.stats.attributes.favorite_loadingscreen = req.body.itemToSlot || "";
StatChanged = true;
break;
case "Dance":
var indexwithinslot = req.body.indexWithinSlot || 0;
if (Math.sign(indexwithinslot) == 1 || Math.sign(indexwithinslot) == 0) {
profile.stats.attributes.favorite_dance[indexwithinslot] = req.body.itemToSlot || "";
}
StatChanged = true;
break;
case "ItemWrap":
var indexwithinslot = req.body.indexWithinSlot || 0;
switch (Math.sign(indexwithinslot)) {
case 0:
profile.stats.attributes.favorite_itemwraps[indexwithinslot] = req.body.itemToSlot || "";
break;
case 1:
profile.stats.attributes.favorite_itemwraps[indexwithinslot] = req.body.itemToSlot || "";
break;
case -1:
for (var i = 0; i < 7; i++) {
profile.stats.attributes.favorite_itemwraps[i] = req.body.itemToSlot || "";
}
break;
}
StatChanged = true;
break;
}
}
if (StatChanged == true) {
var Category = (`favorite_${req.body.slotName || "character"}`).toLowerCase()
if (Category == "favorite_itemwrap") {
Category += "s"
}
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "statModified",
"name": Category,
"value": profile.stats.attributes[Category]
})
if (VariantChanged == true) {
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.itemToSlot,
"attributeName": "variants",
"attributeValue": profile.items[req.body.itemToSlot].attributes.variants
})
}
fs.writeFileSync("./profiles/athena.json", JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": "athena",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Set BR Banner 1
express.post("/fortnite/api/game/v2/profile/*/client/SetBattleRoyaleBanner", async (req, res) => {
const profile = require("./../profiles/athena.json");
functions.GetVersionInfo(req, memory);
profile.stats.attributes.season_num = memory.season;
if (memory.season == 2) {
profile.stats.attributes.book_level = 70;
} else {
profile.stats.attributes.book_level = 100;
}
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.homebaseBannerIconId && req.body.homebaseBannerColorId) {
profile.stats.attributes.banner_icon = req.body.homebaseBannerIconId;
profile.stats.attributes.banner_color = req.body.homebaseBannerColorId;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "banner_icon",
"value": profile.stats.attributes.banner_icon
})
ApplyProfileChanges.push({
"changeType": "statModified",
"name": "banner_color",
"value": profile.stats.attributes.banner_color
})
fs.writeFileSync("./profiles/athena.json", JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": "athena",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Set BR Banner 2
express.post("/fortnite/api/game/v2/profile/*/client/SetCosmeticLockerBanner", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "athena"}.json`);
if (profile.profileId == "athena") {
functions.GetVersionInfo(req, memory);
profile.stats.attributes.season_num = memory.season;
if (memory.season == 2) {
profile.stats.attributes.book_level = 70;
} else {
profile.stats.attributes.book_level = 100;
}
}
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.bannerIconTemplateName && req.body.bannerColorTemplateName && req.body.lockerItem) {
profile.items[req.body.lockerItem].attributes.banner_icon_template = req.body.bannerIconTemplateName;
profile.items[req.body.lockerItem].attributes.banner_color_template = req.body.bannerColorTemplateName;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.lockerItem,
"attributeName": "banner_icon_template",
"attributeValue": profile.items[req.body.lockerItem].attributes.banner_icon_template
})
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.lockerItem,
"attributeName": "banner_color_template",
"attributeValue": profile.items[req.body.lockerItem].attributes.banner_color_template
})
fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "athena",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Set BR Locker 2
express.post("/fortnite/api/game/v2/profile/*/client/SetCosmeticLockerSlot", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "athena"}.json`);
if (profile.profileId == "athena") {
functions.GetVersionInfo(req, memory);
profile.stats.attributes.season_num = memory.season;
if (memory.season == 2) {
profile.stats.attributes.book_level = 70;
} else {
profile.stats.attributes.book_level = 100;
}
}
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
try {
const ReturnVariantsAsString = JSON.stringify(req.body.variantUpdates || [])
if (ReturnVariantsAsString.includes("active")) {
var new_variants = [
{
"variants": []
}
];
if (profile.profileId == "athena") {
if (profile.items[req.body.itemToSlot].attributes.variants.length == 0) {
profile.items[req.body.itemToSlot].attributes.variants = req.body.variantUpdates || [];
}
for (var i in profile.items[req.body.itemToSlot].attributes.variants) {
profile.items[req.body.itemToSlot].attributes.variants[i].active = req.body.variantUpdates[i].active || "";
}
}
for (var i in req.body.variantUpdates) {
new_variants[0].variants.push({
"channel": req.body.variantUpdates[i].channel,
"active": req.body.variantUpdates[i].active
})
profile.items[req.body.lockerItem].attributes.locker_slots_data.slots[req.body.category].activeVariants = new_variants;
}
}
} catch (err) {}
if (req.body.category && req.body.lockerItem) {
switch (req.body.category) {
case "Character":
profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.Character.items = [req.body.itemToSlot || ""];
StatChanged = true;
break;
case "Backpack":
profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.Backpack.items = [req.body.itemToSlot || ""];
StatChanged = true;
break;
case "Pickaxe":
profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.Pickaxe.items = [req.body.itemToSlot || ""];
StatChanged = true;
break;
case "Glider":
profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.Glider.items = [req.body.itemToSlot || ""];
StatChanged = true;
break;
case "SkyDiveContrail":
profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.SkyDiveContrail.items = [req.body.itemToSlot || ""];
StatChanged = true;
break;
case "MusicPack":
profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.MusicPack.items = [req.body.itemToSlot || ""];
StatChanged = true;
break;
case "LoadingScreen":
profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.LoadingScreen.items = [req.body.itemToSlot || ""];
StatChanged = true;
break;
case "Dance":
var indexwithinslot = req.body.slotIndex || 0;
if (Math.sign(indexwithinslot) == 1 || Math.sign(indexwithinslot) == 0) {
profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.Dance.items[indexwithinslot] = req.body.itemToSlot || "";
}
StatChanged = true;
break;
case "ItemWrap":
var indexwithinslot = req.body.slotIndex || 0;
switch (Math.sign(indexwithinslot)) {
case 0:
profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.ItemWrap.items[indexwithinslot] = req.body.itemToSlot || "";
break;
case 1:
profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.ItemWrap.items[indexwithinslot] = req.body.itemToSlot || "";
break;
case -1:
for (var i = 0; i < 7; i++) {
profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.ItemWrap.items[i] = req.body.itemToSlot || "";
}
break;
}
StatChanged = true;
break;
}
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.lockerItem,
"attributeName": "locker_slots_data",
"attributeValue": profile.items[req.body.lockerItem].attributes.locker_slots_data
})
fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "athena",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// Set hero variants STW
express.post("/fortnite/api/game/v2/profile/*/client/SetHeroCosmeticVariants", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "campaign"}.json`);
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
var StatChanged = false;
if (req.body.outfitVariants && req.body.backblingVariants && req.body.heroItem) {
profile.items[req.body.heroItem].attributes.outfitvariants = req.body.outfitVariants;
profile.items[req.body.heroItem].attributes.backblingvariants = req.body.backblingVariants;
StatChanged = true;
}
if (StatChanged == true) {
profile.rvn += 1;
profile.commandRevision += 1;
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.heroItem,
"attributeName": "outfitvariants",
"attributeValue": profile.items[req.body.heroItem].attributes.outfitvariants
})
ApplyProfileChanges.push({
"changeType": "itemAttrChanged",
"itemId": req.body.heroItem,
"attributeName": "backblingvariants",
"attributeValue": profile.items[req.body.heroItem].attributes.backblingvariants
})
fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2));
}
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "campaign",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
// any mcp request that doesn't have something assigned to it
express.post("/fortnite/api/game/v2/profile/*/client/*", async (req, res) => {
const profile = require(`./../profiles/${req.query.profileId || "athena"}.json`);
if (profile.profileId == "athena") {
functions.GetVersionInfo(req, memory);
profile.stats.attributes.season_num = memory.season;
if (memory.season == 2) {
profile.stats.attributes.book_level = 70;
} else {
profile.stats.attributes.book_level = 100;
}
}
// do not change any of these or you will end up breaking it
var ApplyProfileChanges = [];
var BaseRevision = profile.rvn || 0;
var QueryRevision = req.query.rvn || -1;
// this doesn't work properly on version v12.20 and above but whatever
if (QueryRevision != BaseRevision) {
ApplyProfileChanges = [{
"changeType": "fullProfileUpdate",
"profile": profile
}];
}
res.json({
"profileRevision": profile.rvn || 0,
"profileId": req.query.profileId || "athena",
"profileChangesBaseRevision": BaseRevision,
"profileChanges": ApplyProfileChanges,
"profileCommandRevision": profile.commandRevision || 0,
"serverTime": new Date().toISOString(),
"responseVersion": 1
})
res.end();
});
module.exports = express;