Merge branch 'main' of https://onlyg.it/OpenWF/SpaceNinjaServer
This commit is contained in:
commit
8a01e4649b
8
package-lock.json
generated
8
package-lock.json
generated
@ -12,7 +12,7 @@
|
|||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
"express": "^5",
|
"express": "^5",
|
||||||
"mongoose": "^8.9.4",
|
"mongoose": "^8.9.4",
|
||||||
"warframe-public-export-plus": "^0.5.27",
|
"warframe-public-export-plus": "^0.5.29",
|
||||||
"warframe-riven-info": "^0.1.2",
|
"warframe-riven-info": "^0.1.2",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.17.0",
|
||||||
"winston-daily-rotate-file": "^5.0.0"
|
"winston-daily-rotate-file": "^5.0.0"
|
||||||
@ -4093,9 +4093,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/warframe-public-export-plus": {
|
"node_modules/warframe-public-export-plus": {
|
||||||
"version": "0.5.27",
|
"version": "0.5.29",
|
||||||
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.27.tgz",
|
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.29.tgz",
|
||||||
"integrity": "sha512-fdFfvvhIXAPE7hTGLRsRJZ036vV8Jbd5vhu9STbZykdVLRXt9zeilo+sQThNy+2GchO+QhtTcETCjn1ntJhXZw=="
|
"integrity": "sha512-D61CFiJTr/LIQCvyZ03DgudUBpJDqrOTdNPNeB0kY21lmPHw1auDg4CNW2T1JaG0nL5K1hu9ypvnfXzno2omMA=="
|
||||||
},
|
},
|
||||||
"node_modules/warframe-riven-info": {
|
"node_modules/warframe-riven-info": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
"express": "^5",
|
"express": "^5",
|
||||||
"mongoose": "^8.9.4",
|
"mongoose": "^8.9.4",
|
||||||
"warframe-public-export-plus": "^0.5.27",
|
"warframe-public-export-plus": "^0.5.29",
|
||||||
"warframe-riven-info": "^0.1.2",
|
"warframe-riven-info": "^0.1.2",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.17.0",
|
||||||
"winston-daily-rotate-file": "^5.0.0"
|
"winston-daily-rotate-file": "^5.0.0"
|
||||||
|
@ -31,12 +31,12 @@ fs.readdirSync("../static/webui/translations").forEach(file => {
|
|||||||
if (Object.keys(strings).length > 0) {
|
if (Object.keys(strings).length > 0) {
|
||||||
Object.entries(strings).forEach(([key, value]) => {
|
Object.entries(strings).forEach(([key, value]) => {
|
||||||
if (targetStrings.hasOwnProperty(key)) {
|
if (targetStrings.hasOwnProperty(key)) {
|
||||||
fs.writeSync(fileHandle, `\t${key}: \`${targetStrings[key]}\`,\n`);
|
fs.writeSync(fileHandle, ` ${key}: \`${targetStrings[key]}\`,\n`);
|
||||||
} else {
|
} else {
|
||||||
fs.writeSync(fileHandle, `\t${key}: \`[UNTRANSLATED] ${value}\`,\n`);
|
fs.writeSync(fileHandle, ` ${key}: \`[UNTRANSLATED] ${value}\`,\n`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else if (line.length) {
|
||||||
fs.writeSync(fileHandle, line + "\n");
|
fs.writeSync(fileHandle, line + "\n");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
90
src/controllers/api/changeDojoRootController.ts
Normal file
90
src/controllers/api/changeDojoRootController.ts
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { getDojoClient, getGuildForRequest } from "@/src/services/guildService";
|
||||||
|
import { logger } from "@/src/utils/logger";
|
||||||
|
import { IDojoComponentDatabase } from "@/src/types/guildTypes";
|
||||||
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
|
export const changeDojoRootController: RequestHandler = async (req, res) => {
|
||||||
|
const guild = await getGuildForRequest(req);
|
||||||
|
// At this point, we know that a member of the guild is making this request. Assuming they are allowed to change the root.
|
||||||
|
|
||||||
|
const idToNode: Record<string, INode> = {};
|
||||||
|
guild.DojoComponents!.forEach(x => {
|
||||||
|
idToNode[x._id.toString()] = {
|
||||||
|
component: x,
|
||||||
|
parent: undefined,
|
||||||
|
children: []
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
let oldRoot: INode | undefined;
|
||||||
|
guild.DojoComponents!.forEach(x => {
|
||||||
|
const node = idToNode[x._id.toString()];
|
||||||
|
if (x.pi) {
|
||||||
|
idToNode[x.pi.toString()].children.push(node);
|
||||||
|
node.parent = idToNode[x.pi.toString()];
|
||||||
|
} else {
|
||||||
|
oldRoot = node;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
logger.debug("Old tree:\n" + treeToString(oldRoot!));
|
||||||
|
|
||||||
|
const newRoot = idToNode[req.query.newRoot as string];
|
||||||
|
recursivelyTurnParentsIntoChildren(newRoot);
|
||||||
|
newRoot.component.pi = undefined;
|
||||||
|
newRoot.component.op = undefined;
|
||||||
|
newRoot.component.pp = undefined;
|
||||||
|
newRoot.parent = undefined;
|
||||||
|
|
||||||
|
// Don't even ask me why this is needed because I don't know either
|
||||||
|
const stack: INode[] = [newRoot];
|
||||||
|
let i = 0;
|
||||||
|
const idMap: Record<string, Types.ObjectId> = {};
|
||||||
|
while (stack.length != 0) {
|
||||||
|
const top = stack.shift()!;
|
||||||
|
idMap[top.component._id.toString()] = new Types.ObjectId(
|
||||||
|
(++i).toString(16).padStart(8, "0") + top.component._id.toString().substr(8)
|
||||||
|
);
|
||||||
|
top.children.forEach(x => stack.push(x));
|
||||||
|
}
|
||||||
|
guild.DojoComponents!.forEach(x => {
|
||||||
|
x._id = idMap[x._id.toString()];
|
||||||
|
if (x.pi) {
|
||||||
|
x.pi = idMap[x.pi.toString()];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.debug("New tree:\n" + treeToString(newRoot));
|
||||||
|
|
||||||
|
await guild.save();
|
||||||
|
|
||||||
|
res.json(getDojoClient(guild, 0));
|
||||||
|
};
|
||||||
|
|
||||||
|
interface INode {
|
||||||
|
component: IDojoComponentDatabase;
|
||||||
|
parent: INode | undefined;
|
||||||
|
children: INode[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const treeToString = (root: INode, depth: number = 0): string => {
|
||||||
|
let str = " ".repeat(depth * 4) + root.component.pf + " (" + root.component._id.toString() + ")\n";
|
||||||
|
root.children.forEach(x => {
|
||||||
|
str += treeToString(x, depth + 1);
|
||||||
|
});
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
|
||||||
|
const recursivelyTurnParentsIntoChildren = (node: INode): void => {
|
||||||
|
if (node.parent!.parent) {
|
||||||
|
recursivelyTurnParentsIntoChildren(node.parent!);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.parent!.component.pi = node.component._id;
|
||||||
|
node.parent!.component.op = node.component.pp;
|
||||||
|
node.parent!.component.pp = node.component.op;
|
||||||
|
|
||||||
|
node.parent!.parent = node;
|
||||||
|
node.parent!.children.splice(node.parent!.children.indexOf(node), 1);
|
||||||
|
node.children.push(node.parent!);
|
||||||
|
};
|
@ -1,8 +1,7 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { Guild } from "@/src/models/guildModel";
|
import { Guild } from "@/src/models/guildModel";
|
||||||
import { IDojoClient, IDojoComponentClient } from "@/src/types/guildTypes";
|
import { getDojoClient } from "@/src/services/guildService";
|
||||||
import { toOid, toMongoDate } from "@/src/helpers/inventoryHelpers";
|
|
||||||
|
|
||||||
export const getGuildDojoController: RequestHandler = async (req, res) => {
|
export const getGuildDojoController: RequestHandler = async (req, res) => {
|
||||||
const guildId = req.query.guildId as string;
|
const guildId = req.query.guildId as string;
|
||||||
@ -26,34 +25,5 @@ export const getGuildDojoController: RequestHandler = async (req, res) => {
|
|||||||
await guild.save();
|
await guild.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
const dojo: IDojoClient = {
|
res.json(getDojoClient(guild, 0));
|
||||||
_id: { $oid: guildId },
|
|
||||||
Name: guild.Name,
|
|
||||||
Tier: 1,
|
|
||||||
FixedContributions: true,
|
|
||||||
DojoRevision: 1,
|
|
||||||
RevisionTime: Math.round(Date.now() / 1000),
|
|
||||||
Energy: guild.DojoEnergy,
|
|
||||||
Capacity: guild.DojoCapacity,
|
|
||||||
DojoRequestStatus: 0,
|
|
||||||
DojoComponents: []
|
|
||||||
};
|
|
||||||
guild.DojoComponents.forEach(dojoComponent => {
|
|
||||||
const clientComponent: IDojoComponentClient = {
|
|
||||||
id: toOid(dojoComponent._id),
|
|
||||||
pf: dojoComponent.pf,
|
|
||||||
ppf: dojoComponent.ppf,
|
|
||||||
DecoCapacity: 600
|
|
||||||
};
|
|
||||||
if (dojoComponent.pi) {
|
|
||||||
clientComponent.pi = toOid(dojoComponent.pi);
|
|
||||||
clientComponent.op = dojoComponent.op!;
|
|
||||||
clientComponent.pp = dojoComponent.pp!;
|
|
||||||
}
|
|
||||||
if (dojoComponent.CompletionTime) {
|
|
||||||
clientComponent.CompletionTime = toMongoDate(dojoComponent.CompletionTime);
|
|
||||||
}
|
|
||||||
dojo.DojoComponents.push(clientComponent);
|
|
||||||
});
|
|
||||||
res.json(dojo);
|
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { getGuildForRequest } from "@/src/services/guildService";
|
import { getDojoClient, getGuildForRequest } from "@/src/services/guildService";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
||||||
|
|
||||||
@ -15,7 +15,5 @@ export const queueDojoComponentDestructionController: RequestHandler = async (re
|
|||||||
guild.DojoEnergy -= room.energy;
|
guild.DojoEnergy -= room.energy;
|
||||||
}
|
}
|
||||||
await guild.save();
|
await guild.save();
|
||||||
res.json({
|
res.json(getDojoClient(guild, 1));
|
||||||
DojoRequestStatus: 1
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
18
src/controllers/api/setDojoComponentMessageController.ts
Normal file
18
src/controllers/api/setDojoComponentMessageController.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { getDojoClient, getGuildForRequest } from "@/src/services/guildService";
|
||||||
|
|
||||||
|
export const setDojoComponentMessageController: RequestHandler = async (req, res) => {
|
||||||
|
const guild = await getGuildForRequest(req);
|
||||||
|
// At this point, we know that a member of the guild is making this request. Assuming they are allowed to change the message.
|
||||||
|
const component = guild.DojoComponents!.find(x => x._id.equals(req.query.componentId as string))!;
|
||||||
|
const payload = JSON.parse(String(req.body)) as SetDojoComponentMessageRequest;
|
||||||
|
if ("Name" in payload) {
|
||||||
|
component.Name = payload.Name;
|
||||||
|
} else {
|
||||||
|
component.Message = payload.Message;
|
||||||
|
}
|
||||||
|
await guild.save();
|
||||||
|
res.json(getDojoClient(guild, 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
type SetDojoComponentMessageRequest = { Name: string } | { Message: string };
|
@ -1,6 +1,6 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { IDojoComponentClient } from "@/src/types/guildTypes";
|
import { IDojoComponentClient } from "@/src/types/guildTypes";
|
||||||
import { getGuildForRequest } from "@/src/services/guildService";
|
import { getDojoClient, getGuildForRequest } from "@/src/services/guildService";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
||||||
|
|
||||||
@ -30,7 +30,5 @@ export const startDojoRecipeController: RequestHandler = async (req, res) => {
|
|||||||
CompletionTime: new Date(Date.now()) // TOOD: Omit this field & handle the "Collecting Materials" state.
|
CompletionTime: new Date(Date.now()) // TOOD: Omit this field & handle the "Collecting Materials" state.
|
||||||
});
|
});
|
||||||
await guild.save();
|
await guild.save();
|
||||||
res.json({
|
res.json(getDojoClient(guild, 0));
|
||||||
DojoRequestStatus: 0
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getStats, uploadStats } from "@/src/services/statsService";
|
import { getStats, updateStats } from "@/src/services/statsService";
|
||||||
import { IStatsUpload } from "@/src/types/statTypes";
|
import { IStatsUpdate } from "@/src/types/statTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
const uploadController: RequestHandler = async (req, res) => {
|
const uploadController: RequestHandler = async (req, res) => {
|
||||||
const payload = getJSONfromString<IStatsUpload>(String(req.body));
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const { PS, ...payload } = getJSONfromString<IStatsUpdate>(String(req.body));
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const playerStats = await getStats(accountId);
|
const playerStats = await getStats(accountId);
|
||||||
await uploadStats(playerStats, payload);
|
await updateStats(playerStats, payload);
|
||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,14 +5,14 @@ import allScans from "@/static/fixed_responses/allScans.json";
|
|||||||
import { ExportEnemies } from "warframe-public-export-plus";
|
import { ExportEnemies } from "warframe-public-export-plus";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getStats } from "@/src/services/statsService";
|
import { getStats } from "@/src/services/statsService";
|
||||||
import { IStatsView } from "@/src/types/statTypes";
|
import { IStatsClient } from "@/src/types/statTypes";
|
||||||
|
|
||||||
const viewController: RequestHandler = async (req, res) => {
|
const viewController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(accountId, "XPInfo");
|
const inventory = await getInventory(accountId, "XPInfo");
|
||||||
const playerStats = await getStats(accountId);
|
const playerStats = await getStats(accountId);
|
||||||
|
|
||||||
const responseJson: IStatsView = playerStats.toJSON();
|
const responseJson = playerStats.toJSON() as IStatsClient;
|
||||||
responseJson.Weapons ??= [];
|
responseJson.Weapons ??= [];
|
||||||
for (const item of inventory.XPInfo) {
|
for (const item of inventory.XPInfo) {
|
||||||
const weaponIndex = responseJson.Weapons.findIndex(element => element.type == item.ItemType);
|
const weaponIndex = responseJson.Weapons.findIndex(element => element.type == item.ItemType);
|
||||||
|
@ -14,6 +14,8 @@ const dojoComponentSchema = new Schema<IDojoComponentDatabase>({
|
|||||||
pi: Schema.Types.ObjectId,
|
pi: Schema.Types.ObjectId,
|
||||||
op: String,
|
op: String,
|
||||||
pp: String,
|
pp: String,
|
||||||
|
Name: String,
|
||||||
|
Message: String,
|
||||||
CompletionTime: Date
|
CompletionTime: Date
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Document, Schema, Types, model } from "mongoose";
|
import { Document, Schema, Types, model } from "mongoose";
|
||||||
import { IEnemy, IMission, IScan, ITutorial, IAbility, IWeapon, IStatsDatabase } from "@/src/types/statTypes";
|
import { IEnemy, IMission, IScan, ITutorial, IAbility, IWeapon, IStatsDatabase, IRace } from "@/src/types/statTypes";
|
||||||
|
|
||||||
const abilitySchema = new Schema<IAbility>(
|
const abilitySchema = new Schema<IAbility>(
|
||||||
{
|
{
|
||||||
@ -58,6 +58,13 @@ const weaponSchema = new Schema<IWeapon>(
|
|||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const raceSchema = new Schema<IRace>(
|
||||||
|
{
|
||||||
|
highScore: Number
|
||||||
|
},
|
||||||
|
{ _id: false }
|
||||||
|
);
|
||||||
|
|
||||||
const statsSchema = new Schema<IStatsDatabase>({
|
const statsSchema = new Schema<IStatsDatabase>({
|
||||||
accountOwnerId: { type: Schema.Types.ObjectId, required: true },
|
accountOwnerId: { type: Schema.Types.ObjectId, required: true },
|
||||||
CiphersSolved: Number,
|
CiphersSolved: Number,
|
||||||
@ -69,6 +76,8 @@ const statsSchema = new Schema<IStatsDatabase>({
|
|||||||
MissionsCompleted: Number,
|
MissionsCompleted: Number,
|
||||||
MissionsQuit: Number,
|
MissionsQuit: Number,
|
||||||
MissionsFailed: Number,
|
MissionsFailed: Number,
|
||||||
|
MissionsInterrupted: Number,
|
||||||
|
MissionsDumped: Number,
|
||||||
TimePlayedSec: Number,
|
TimePlayedSec: Number,
|
||||||
PickupCount: Number,
|
PickupCount: Number,
|
||||||
Tutorial: { type: Map, of: tutorialSchema, default: {} },
|
Tutorial: { type: Map, of: tutorialSchema, default: {} },
|
||||||
@ -81,7 +90,8 @@ const statsSchema = new Schema<IStatsDatabase>({
|
|||||||
Missions: { type: [missionSchema], default: [] },
|
Missions: { type: [missionSchema], default: [] },
|
||||||
Deaths: Number,
|
Deaths: Number,
|
||||||
HealCount: Number,
|
HealCount: Number,
|
||||||
ReviveCount: Number
|
ReviveCount: Number,
|
||||||
|
Races: { type: Map, of: raceSchema, default: {} }
|
||||||
});
|
});
|
||||||
|
|
||||||
statsSchema.set("toJSON", {
|
statsSchema.set("toJSON", {
|
||||||
|
@ -4,6 +4,7 @@ import { addFriendImageController } from "@/src/controllers/api/addFriendImageCo
|
|||||||
import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController";
|
import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController";
|
||||||
import { archonFusionController } from "@/src/controllers/api/archonFusionController";
|
import { archonFusionController } from "@/src/controllers/api/archonFusionController";
|
||||||
import { artifactsController } from "../controllers/api/artifactsController";
|
import { artifactsController } from "../controllers/api/artifactsController";
|
||||||
|
import { changeDojoRootController } from "../controllers/api/changeDojoRootController";
|
||||||
import { checkDailyMissionBonusController } from "@/src/controllers/api/checkDailyMissionBonusController";
|
import { checkDailyMissionBonusController } from "@/src/controllers/api/checkDailyMissionBonusController";
|
||||||
import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController";
|
import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController";
|
||||||
import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController";
|
import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController";
|
||||||
@ -32,6 +33,8 @@ import { getVendorInfoController } from "@/src/controllers/api/getVendorInfoCont
|
|||||||
import { getVoidProjectionRewardsController } from "@/src/controllers/api/getVoidProjectionRewardsController";
|
import { getVoidProjectionRewardsController } from "@/src/controllers/api/getVoidProjectionRewardsController";
|
||||||
import { gildWeaponController } from "@/src/controllers/api/gildWeaponController";
|
import { gildWeaponController } from "@/src/controllers/api/gildWeaponController";
|
||||||
import { giveKeyChainTriggeredItemsController } from "@/src/controllers/api/giveKeyChainTriggeredItemsController";
|
import { giveKeyChainTriggeredItemsController } from "@/src/controllers/api/giveKeyChainTriggeredItemsController";
|
||||||
|
import { giveKeyChainTriggeredMessageController } from "@/src/controllers/api/giveKeyChainTriggeredMessageController";
|
||||||
|
import { giveQuestKeyRewardController } from "@/src/controllers/api/giveQuestKey";
|
||||||
import { guildTechController } from "../controllers/api/guildTechController";
|
import { guildTechController } from "../controllers/api/guildTechController";
|
||||||
import { hostSessionController } from "@/src/controllers/api/hostSessionController";
|
import { hostSessionController } from "@/src/controllers/api/hostSessionController";
|
||||||
import { hubController } from "@/src/controllers/api/hubController";
|
import { hubController } from "@/src/controllers/api/hubController";
|
||||||
@ -60,6 +63,7 @@ import { sellController } from "@/src/controllers/api/sellController";
|
|||||||
import { setActiveQuestController } from "@/src/controllers/api/setActiveQuestController";
|
import { setActiveQuestController } from "@/src/controllers/api/setActiveQuestController";
|
||||||
import { setActiveShipController } from "@/src/controllers/api/setActiveShipController";
|
import { setActiveShipController } from "@/src/controllers/api/setActiveShipController";
|
||||||
import { setBootLocationController } from "@/src/controllers/api/setBootLocationController";
|
import { setBootLocationController } from "@/src/controllers/api/setBootLocationController";
|
||||||
|
import { setDojoComponentMessageController } from "@/src/controllers/api/setDojoComponentMessageController";
|
||||||
import { setEquippedInstrumentController } from "@/src/controllers/api/setEquippedInstrumentController";
|
import { setEquippedInstrumentController } from "@/src/controllers/api/setEquippedInstrumentController";
|
||||||
import { setPlacedDecoInfoController } from "@/src/controllers/api/setPlacedDecoInfoController";
|
import { setPlacedDecoInfoController } from "@/src/controllers/api/setPlacedDecoInfoController";
|
||||||
import { setShipCustomizationsController } from "@/src/controllers/api/setShipCustomizationsController";
|
import { setShipCustomizationsController } from "@/src/controllers/api/setShipCustomizationsController";
|
||||||
@ -82,8 +86,6 @@ import { updateQuestController } from "@/src/controllers/api/updateQuestControll
|
|||||||
import { updateSessionGetController, updateSessionPostController } from "@/src/controllers/api/updateSessionController";
|
import { updateSessionGetController, updateSessionPostController } from "@/src/controllers/api/updateSessionController";
|
||||||
import { updateThemeController } from "../controllers/api/updateThemeController";
|
import { updateThemeController } from "../controllers/api/updateThemeController";
|
||||||
import { upgradesController } from "@/src/controllers/api/upgradesController";
|
import { upgradesController } from "@/src/controllers/api/upgradesController";
|
||||||
import { giveKeyChainTriggeredMessageController } from "@/src/controllers/api/giveKeyChainTriggeredMessageController";
|
|
||||||
import { giveQuestKeyRewardController } from "@/src/controllers/api/giveQuestKey";
|
|
||||||
|
|
||||||
const apiRouter = express.Router();
|
const apiRouter = express.Router();
|
||||||
|
|
||||||
@ -126,6 +128,7 @@ apiRouter.post("/addFriendImage.php", addFriendImageController);
|
|||||||
apiRouter.post("/arcaneCommon.php", arcaneCommonController);
|
apiRouter.post("/arcaneCommon.php", arcaneCommonController);
|
||||||
apiRouter.post("/archonFusion.php", archonFusionController);
|
apiRouter.post("/archonFusion.php", archonFusionController);
|
||||||
apiRouter.post("/artifacts.php", artifactsController);
|
apiRouter.post("/artifacts.php", artifactsController);
|
||||||
|
apiRouter.post("/changeDojoRoot.php", changeDojoRootController);
|
||||||
apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
|
apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
|
||||||
apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);
|
apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);
|
||||||
apiRouter.post("/createGuild.php", createGuildController);
|
apiRouter.post("/createGuild.php", createGuildController);
|
||||||
@ -158,6 +161,7 @@ apiRouter.post("/rerollRandomMod.php", rerollRandomModController);
|
|||||||
apiRouter.post("/saveDialogue.php", saveDialogueController);
|
apiRouter.post("/saveDialogue.php", saveDialogueController);
|
||||||
apiRouter.post("/saveLoadout.php", saveLoadoutController);
|
apiRouter.post("/saveLoadout.php", saveLoadoutController);
|
||||||
apiRouter.post("/sell.php", sellController);
|
apiRouter.post("/sell.php", sellController);
|
||||||
|
apiRouter.post("/setDojoComponentMessage.php", setDojoComponentMessageController);
|
||||||
apiRouter.post("/setEquippedInstrument.php", setEquippedInstrumentController);
|
apiRouter.post("/setEquippedInstrument.php", setEquippedInstrumentController);
|
||||||
apiRouter.post("/setPlacedDecoInfo.php", setPlacedDecoInfoController);
|
apiRouter.post("/setPlacedDecoInfo.php", setPlacedDecoInfoController);
|
||||||
apiRouter.post("/setShipCustomizations.php", setShipCustomizationsController);
|
apiRouter.post("/setShipCustomizations.php", setShipCustomizationsController);
|
||||||
@ -174,9 +178,9 @@ apiRouter.post("/trainingResult.php", trainingResultController);
|
|||||||
apiRouter.post("/unlockShipFeature.php", unlockShipFeatureController);
|
apiRouter.post("/unlockShipFeature.php", unlockShipFeatureController);
|
||||||
apiRouter.post("/updateChallengeProgress.php", updateChallengeProgressController);
|
apiRouter.post("/updateChallengeProgress.php", updateChallengeProgressController);
|
||||||
apiRouter.post("/updateNodeIntros.php", genericUpdateController);
|
apiRouter.post("/updateNodeIntros.php", genericUpdateController);
|
||||||
|
apiRouter.post("/updateQuest.php", updateQuestController);
|
||||||
apiRouter.post("/updateSession.php", updateSessionPostController);
|
apiRouter.post("/updateSession.php", updateSessionPostController);
|
||||||
apiRouter.post("/updateTheme.php", updateThemeController);
|
apiRouter.post("/updateTheme.php", updateThemeController);
|
||||||
apiRouter.post("/updateQuest.php", updateQuestController);
|
|
||||||
apiRouter.post("/upgrades.php", upgradesController);
|
apiRouter.post("/upgrades.php", upgradesController);
|
||||||
|
|
||||||
export { apiRouter };
|
export { apiRouter };
|
||||||
|
@ -3,14 +3,20 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
|
|||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { Guild } from "@/src/models/guildModel";
|
import { Guild } from "@/src/models/guildModel";
|
||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
|
import { IDojoClient, IDojoComponentClient, IGuildDatabase } from "@/src/types/guildTypes";
|
||||||
|
import { Document, Types } from "mongoose";
|
||||||
|
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
|
|
||||||
export const getGuildForRequest = async (req: Request) => {
|
export const getGuildForRequest = async (req: Request): Promise<TGuildDatabaseDocument> => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
return await getGuildForRequestEx(req, inventory);
|
return await getGuildForRequestEx(req, inventory);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getGuildForRequestEx = async (req: Request, inventory: TInventoryDatabaseDocument) => {
|
export const getGuildForRequestEx = async (
|
||||||
|
req: Request,
|
||||||
|
inventory: TInventoryDatabaseDocument
|
||||||
|
): Promise<TGuildDatabaseDocument> => {
|
||||||
const guildId = req.query.guildId as string;
|
const guildId = req.query.guildId as string;
|
||||||
if (!inventory.GuildId || inventory.GuildId.toString() != guildId) {
|
if (!inventory.GuildId || inventory.GuildId.toString() != guildId) {
|
||||||
throw new Error("Account is not in the guild that it has sent a request for");
|
throw new Error("Account is not in the guild that it has sent a request for");
|
||||||
@ -21,3 +27,47 @@ export const getGuildForRequestEx = async (req: Request, inventory: TInventoryDa
|
|||||||
}
|
}
|
||||||
return guild;
|
return guild;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getDojoClient = (guild: TGuildDatabaseDocument, status: number): IDojoClient => {
|
||||||
|
const dojo: IDojoClient = {
|
||||||
|
_id: { $oid: guild._id.toString() },
|
||||||
|
Name: guild.Name,
|
||||||
|
Tier: 1,
|
||||||
|
FixedContributions: true,
|
||||||
|
DojoRevision: 1,
|
||||||
|
RevisionTime: Math.round(Date.now() / 1000),
|
||||||
|
Energy: guild.DojoEnergy,
|
||||||
|
Capacity: guild.DojoCapacity,
|
||||||
|
DojoRequestStatus: status,
|
||||||
|
DojoComponents: []
|
||||||
|
};
|
||||||
|
guild.DojoComponents!.forEach(dojoComponent => {
|
||||||
|
const clientComponent: IDojoComponentClient = {
|
||||||
|
id: toOid(dojoComponent._id),
|
||||||
|
pf: dojoComponent.pf,
|
||||||
|
ppf: dojoComponent.ppf,
|
||||||
|
Name: dojoComponent.Name,
|
||||||
|
Message: dojoComponent.Message,
|
||||||
|
DecoCapacity: 600
|
||||||
|
};
|
||||||
|
if (dojoComponent.pi) {
|
||||||
|
clientComponent.pi = toOid(dojoComponent.pi);
|
||||||
|
clientComponent.op = dojoComponent.op!;
|
||||||
|
clientComponent.pp = dojoComponent.pp!;
|
||||||
|
}
|
||||||
|
if (dojoComponent.CompletionTime) {
|
||||||
|
clientComponent.CompletionTime = toMongoDate(dojoComponent.CompletionTime);
|
||||||
|
}
|
||||||
|
dojo.DojoComponents.push(clientComponent);
|
||||||
|
});
|
||||||
|
return dojo;
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
|
export type TGuildDatabaseDocument = Document<unknown, {}, IGuildDatabase> &
|
||||||
|
IGuildDatabase &
|
||||||
|
Required<{
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
}> & {
|
||||||
|
__v: number;
|
||||||
|
};
|
||||||
|
@ -415,8 +415,9 @@ export const addItem = async (
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "Upgrades": {
|
case "Upgrades": {
|
||||||
if (typeName.substr(1).split("/")[2] == "CosmeticEnhancers") {
|
switch (typeName.substr(1).split("/")[2]) {
|
||||||
// Needed to add Traumatic Peculiar
|
case "Mods": // Legendary Core
|
||||||
|
case "CosmeticEnhancers": // Traumatic Peculiar
|
||||||
const changes = [
|
const changes = [
|
||||||
{
|
{
|
||||||
ItemType: typeName,
|
ItemType: typeName,
|
||||||
|
@ -21,7 +21,7 @@ import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSal
|
|||||||
import OstronFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronFishmongerVendorManifest.json";
|
import OstronFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronFishmongerVendorManifest.json";
|
||||||
import OstronPetVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronPetVendorManifest.json";
|
import OstronPetVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronPetVendorManifest.json";
|
||||||
import OstronProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronProspectorVendorManifest.json";
|
import OstronProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronProspectorVendorManifest.json";
|
||||||
import RadioLegionIntermission11VendorManifest from "@/static/fixed_responses/getVendorInfo/RadioLegionIntermission11VendorManifest.json";
|
import RadioLegionIntermission12VendorManifest from "@/static/fixed_responses/getVendorInfo/RadioLegionIntermission12VendorManifest.json";
|
||||||
import SolarisDebtTokenVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorManifest.json";
|
import SolarisDebtTokenVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorManifest.json";
|
||||||
import SolarisDebtTokenVendorRepossessionsManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorRepossessionsManifest.json";
|
import SolarisDebtTokenVendorRepossessionsManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorRepossessionsManifest.json";
|
||||||
import SolarisFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisFishmongerVendorManifest.json";
|
import SolarisFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisFishmongerVendorManifest.json";
|
||||||
@ -70,7 +70,7 @@ const vendorManifests: IVendorManifest[] = [
|
|||||||
OstronFishmongerVendorManifest,
|
OstronFishmongerVendorManifest,
|
||||||
OstronPetVendorManifest,
|
OstronPetVendorManifest,
|
||||||
OstronProspectorVendorManifest,
|
OstronProspectorVendorManifest,
|
||||||
RadioLegionIntermission11VendorManifest,
|
RadioLegionIntermission12VendorManifest,
|
||||||
SolarisDebtTokenVendorManifest,
|
SolarisDebtTokenVendorManifest,
|
||||||
SolarisDebtTokenVendorRepossessionsManifest,
|
SolarisDebtTokenVendorRepossessionsManifest,
|
||||||
SolarisFishmongerVendorManifest,
|
SolarisFishmongerVendorManifest,
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
import { Stats, TStatsDatabaseDocument } from "@/src/models/statsModel";
|
import { Stats, TStatsDatabaseDocument } from "@/src/models/statsModel";
|
||||||
import { IStatsUpload } from "@/src/types/statTypes";
|
import {
|
||||||
|
IEnemy,
|
||||||
|
IStatsAdd,
|
||||||
|
IStatsMax,
|
||||||
|
IStatsSet,
|
||||||
|
IStatsTimers,
|
||||||
|
IStatsUpdate,
|
||||||
|
IUploadEntry,
|
||||||
|
IWeapon
|
||||||
|
} from "@/src/types/statTypes";
|
||||||
|
import { logger } from "../utils/logger";
|
||||||
|
|
||||||
export const createStats = async (accountId: string): Promise<TStatsDatabaseDocument> => {
|
export const createStats = async (accountId: string): Promise<TStatsDatabaseDocument> => {
|
||||||
const stats = new Stats({ accountOwnerId: accountId });
|
const stats = new Stats({ accountOwnerId: accountId });
|
||||||
@ -15,28 +25,16 @@ export const getStats = async (accountOwnerId: string): Promise<TStatsDatabaseDo
|
|||||||
return stats;
|
return stats;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const uploadStats = async (playerStats: TStatsDatabaseDocument, payload: IStatsUpload): Promise<void> => {
|
export const updateStats = async (playerStats: TStatsDatabaseDocument, payload: IStatsUpdate): Promise<void> => {
|
||||||
if (payload.add) {
|
const unknownCategories: Record<string, string[]> = {};
|
||||||
const {
|
|
||||||
MISSION_COMPLETE,
|
|
||||||
PICKUP_ITEM,
|
|
||||||
SCAN,
|
|
||||||
USE_ABILITY,
|
|
||||||
FIRE_WEAPON,
|
|
||||||
HIT_ENTITY_ITEM,
|
|
||||||
HEADSHOT_ITEM,
|
|
||||||
KILL_ENEMY_ITEM,
|
|
||||||
KILL_ENEMY,
|
|
||||||
EXECUTE_ENEMY,
|
|
||||||
HEADSHOT,
|
|
||||||
DIE,
|
|
||||||
MELEE_KILL,
|
|
||||||
INCOME,
|
|
||||||
CIPHER
|
|
||||||
} = payload.add;
|
|
||||||
|
|
||||||
if (MISSION_COMPLETE) {
|
for (const [action, actionData] of Object.entries(payload)) {
|
||||||
for (const [key, value] of Object.entries(MISSION_COMPLETE)) {
|
switch (action) {
|
||||||
|
case "add":
|
||||||
|
for (const [category, data] of Object.entries(actionData as IStatsAdd)) {
|
||||||
|
switch (category) {
|
||||||
|
case "MISSION_COMPLETE":
|
||||||
|
for (const [key, value] of Object.entries(data as IUploadEntry)) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "GS_SUCCESS":
|
case "GS_SUCCESS":
|
||||||
playerStats.MissionsCompleted ??= 0;
|
playerStats.MissionsCompleted ??= 0;
|
||||||
@ -50,234 +48,360 @@ export const uploadStats = async (playerStats: TStatsDatabaseDocument, payload:
|
|||||||
playerStats.MissionsFailed ??= 0;
|
playerStats.MissionsFailed ??= 0;
|
||||||
playerStats.MissionsFailed += value;
|
playerStats.MissionsFailed += value;
|
||||||
break;
|
break;
|
||||||
|
case "GS_INTERRUPTED":
|
||||||
|
playerStats.MissionsInterrupted ??= 0;
|
||||||
|
playerStats.MissionsInterrupted += value;
|
||||||
|
break;
|
||||||
|
case "GS_DUMPED":
|
||||||
|
playerStats.MissionsDumped ??= 0;
|
||||||
|
playerStats.MissionsDumped += value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!ignoredCategories.includes(category)) {
|
||||||
|
if (!unknownCategories[action]) {
|
||||||
|
unknownCategories[action] = [];
|
||||||
|
}
|
||||||
|
unknownCategories[action].push(category);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
|
|
||||||
if (PICKUP_ITEM) {
|
case "PICKUP_ITEM":
|
||||||
for (const value of Object.values(PICKUP_ITEM)) {
|
|
||||||
playerStats.PickupCount ??= 0;
|
playerStats.PickupCount ??= 0;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
for (const [_key, value] of Object.entries(data as IUploadEntry)) {
|
||||||
playerStats.PickupCount += value;
|
playerStats.PickupCount += value;
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
|
|
||||||
if (SCAN) {
|
case "SCAN":
|
||||||
playerStats.Scans ??= [];
|
playerStats.Scans ??= [];
|
||||||
for (const [key, scans] of Object.entries(SCAN)) {
|
for (const [type, scans] of Object.entries(data as IUploadEntry)) {
|
||||||
const scan = playerStats.Scans.find(element => element.type === key);
|
const scan = playerStats.Scans.find(element => element.type === type);
|
||||||
if (scan) {
|
if (scan) {
|
||||||
scan.scans ??= 0;
|
scan.scans ??= 0;
|
||||||
scan.scans += scans;
|
scan.scans += scans;
|
||||||
} else {
|
} else {
|
||||||
playerStats.Scans.push({ type: key, scans });
|
playerStats.Scans.push({ type: type, scans });
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if (USE_ABILITY) {
|
case "USE_ABILITY":
|
||||||
playerStats.Abilities ??= [];
|
playerStats.Abilities ??= [];
|
||||||
for (const [key, used] of Object.entries(USE_ABILITY)) {
|
for (const [type, used] of Object.entries(data as IUploadEntry)) {
|
||||||
const ability = playerStats.Abilities.find(element => element.type === key);
|
const ability = playerStats.Abilities.find(element => element.type === type);
|
||||||
if (ability) {
|
if (ability) {
|
||||||
ability.used ??= 0;
|
ability.used ??= 0;
|
||||||
ability.used += used;
|
ability.used += used;
|
||||||
} else {
|
} else {
|
||||||
playerStats.Abilities.push({ type: key, used });
|
playerStats.Abilities.push({ type: type, used });
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if (FIRE_WEAPON) {
|
case "FIRE_WEAPON":
|
||||||
|
case "HIT_ENTITY_ITEM":
|
||||||
|
case "HEADSHOT_ITEM":
|
||||||
|
case "KILL_ENEMY_ITEM":
|
||||||
playerStats.Weapons ??= [];
|
playerStats.Weapons ??= [];
|
||||||
for (const [key, fired] of Object.entries(FIRE_WEAPON)) {
|
const statKey = {
|
||||||
const weapon = playerStats.Weapons.find(element => element.type === key);
|
FIRE_WEAPON: "fired",
|
||||||
if (weapon) {
|
HIT_ENTITY_ITEM: "hits",
|
||||||
weapon.fired ??= 0;
|
HEADSHOT_ITEM: "headshots",
|
||||||
weapon.fired += fired;
|
KILL_ENEMY_ITEM: "kills"
|
||||||
} else {
|
}[category] as "fired" | "hits" | "headshots" | "kills";
|
||||||
playerStats.Weapons.push({ type: key, fired });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HIT_ENTITY_ITEM) {
|
for (const [type, count] of Object.entries(data as IUploadEntry)) {
|
||||||
playerStats.Weapons ??= [];
|
const weapon = playerStats.Weapons.find(element => element.type === type);
|
||||||
for (const [key, hits] of Object.entries(HIT_ENTITY_ITEM)) {
|
|
||||||
const weapon = playerStats.Weapons.find(element => element.type === key);
|
|
||||||
if (weapon) {
|
if (weapon) {
|
||||||
weapon.hits ??= 0;
|
weapon[statKey] ??= 0;
|
||||||
weapon.hits += hits;
|
weapon[statKey] += count;
|
||||||
} else {
|
} else {
|
||||||
playerStats.Weapons.push({ type: key, hits });
|
const newWeapon: IWeapon = { type: type };
|
||||||
}
|
newWeapon[statKey] = count;
|
||||||
|
playerStats.Weapons.push(newWeapon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if (HEADSHOT_ITEM) {
|
case "KILL_ENEMY":
|
||||||
playerStats.Weapons ??= [];
|
case "EXECUTE_ENEMY":
|
||||||
for (const [key, headshots] of Object.entries(HEADSHOT_ITEM)) {
|
case "HEADSHOT":
|
||||||
const weapon = playerStats.Weapons.find(element => element.type === key);
|
|
||||||
if (weapon) {
|
|
||||||
weapon.headshots ??= 0;
|
|
||||||
weapon.headshots += headshots;
|
|
||||||
} else {
|
|
||||||
playerStats.Weapons.push({ type: key, headshots });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (KILL_ENEMY_ITEM) {
|
|
||||||
playerStats.Weapons ??= [];
|
|
||||||
for (const [key, kills] of Object.entries(KILL_ENEMY_ITEM)) {
|
|
||||||
const weapon = playerStats.Weapons.find(element => element.type === key);
|
|
||||||
if (weapon) {
|
|
||||||
weapon.kills ??= 0;
|
|
||||||
weapon.kills += kills;
|
|
||||||
} else {
|
|
||||||
playerStats.Weapons.push({ type: key, kills });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (KILL_ENEMY) {
|
|
||||||
playerStats.Enemies ??= [];
|
playerStats.Enemies ??= [];
|
||||||
for (const [key, kills] of Object.entries(KILL_ENEMY)) {
|
const enemyStatKey = {
|
||||||
const enemy = playerStats.Enemies.find(element => element.type === key);
|
KILL_ENEMY: "kills",
|
||||||
|
EXECUTE_ENEMY: "executions",
|
||||||
|
HEADSHOT: "headshots"
|
||||||
|
}[category] as "kills" | "executions" | "headshots";
|
||||||
|
|
||||||
|
for (const [type, count] of Object.entries(data as IUploadEntry)) {
|
||||||
|
const enemy = playerStats.Enemies.find(element => element.type === type);
|
||||||
if (enemy) {
|
if (enemy) {
|
||||||
enemy.kills ??= 0;
|
enemy[enemyStatKey] ??= 0;
|
||||||
enemy.kills += kills;
|
enemy[enemyStatKey] += count;
|
||||||
} else {
|
} else {
|
||||||
playerStats.Enemies.push({ type: key, kills });
|
const newEnemy: IEnemy = { type: type };
|
||||||
}
|
newEnemy[enemyStatKey] = count;
|
||||||
|
playerStats.Enemies.push(newEnemy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if (EXECUTE_ENEMY) {
|
case "DIE":
|
||||||
playerStats.Enemies ??= [];
|
playerStats.Enemies ??= [];
|
||||||
for (const [key, executions] of Object.entries(EXECUTE_ENEMY)) {
|
|
||||||
const enemy = playerStats.Enemies.find(element => element.type === key);
|
|
||||||
if (enemy) {
|
|
||||||
enemy.executions ??= 0;
|
|
||||||
enemy.executions += executions;
|
|
||||||
} else {
|
|
||||||
playerStats.Enemies.push({ type: key, executions });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HEADSHOT) {
|
|
||||||
playerStats.Enemies ??= [];
|
|
||||||
for (const [key, headshots] of Object.entries(HEADSHOT)) {
|
|
||||||
const enemy = playerStats.Enemies.find(element => element.type === key);
|
|
||||||
if (enemy) {
|
|
||||||
enemy.headshots ??= 0;
|
|
||||||
enemy.headshots += headshots;
|
|
||||||
} else {
|
|
||||||
playerStats.Enemies.push({ type: key, headshots });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DIE) {
|
|
||||||
playerStats.Enemies ??= [];
|
|
||||||
for (const [key, deaths] of Object.entries(DIE)) {
|
|
||||||
playerStats.Deaths ??= 0;
|
playerStats.Deaths ??= 0;
|
||||||
|
for (const [type, deaths] of Object.entries(data as IUploadEntry)) {
|
||||||
playerStats.Deaths += deaths;
|
playerStats.Deaths += deaths;
|
||||||
const enemy = playerStats.Enemies.find(element => element.type === key);
|
const enemy = playerStats.Enemies.find(element => element.type === type);
|
||||||
if (enemy) {
|
if (enemy) {
|
||||||
enemy.deaths ??= 0;
|
enemy.deaths ??= 0;
|
||||||
enemy.deaths += deaths;
|
enemy.deaths += deaths;
|
||||||
} else {
|
} else {
|
||||||
playerStats.Enemies.push({ type: key, deaths });
|
playerStats.Enemies.push({ type: type, deaths });
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if (MELEE_KILL) {
|
case "MELEE_KILL":
|
||||||
playerStats.MeleeKills ??= 0;
|
playerStats.MeleeKills ??= 0;
|
||||||
for (const kills of Object.values(MELEE_KILL)) {
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
for (const [_key, kills] of Object.entries(data as IUploadEntry)) {
|
||||||
playerStats.MeleeKills += kills;
|
playerStats.MeleeKills += kills;
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
|
|
||||||
if (INCOME) {
|
case "INCOME":
|
||||||
playerStats.Income ??= 0;
|
playerStats.Income ??= 0;
|
||||||
playerStats.Income += INCOME;
|
playerStats.Income += data;
|
||||||
}
|
break;
|
||||||
|
|
||||||
if (CIPHER) {
|
case "CIPHER":
|
||||||
if (CIPHER["0"] > 0) {
|
if (data["0"] > 0) {
|
||||||
playerStats.CiphersFailed ??= 0;
|
playerStats.CiphersFailed ??= 0;
|
||||||
playerStats.CiphersFailed += CIPHER["0"];
|
playerStats.CiphersFailed += data["0"];
|
||||||
}
|
}
|
||||||
if (CIPHER["1"] > 0) {
|
if (data["1"] > 0) {
|
||||||
playerStats.CiphersSolved ??= 0;
|
playerStats.CiphersSolved ??= 0;
|
||||||
playerStats.CiphersSolved += CIPHER["1"];
|
playerStats.CiphersSolved += data["1"];
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if (payload.timers) {
|
default:
|
||||||
const { EQUIP_WEAPON, CURRENT_MISSION_TIME, CIPHER_TIME } = payload.timers;
|
if (!ignoredCategories.includes(category)) {
|
||||||
|
if (!unknownCategories[action]) {
|
||||||
|
unknownCategories[action] = [];
|
||||||
|
}
|
||||||
|
unknownCategories[action].push(category);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if (EQUIP_WEAPON) {
|
case "timers":
|
||||||
|
for (const [category, data] of Object.entries(actionData as IStatsTimers)) {
|
||||||
|
switch (category) {
|
||||||
|
case "EQUIP_WEAPON":
|
||||||
playerStats.Weapons ??= [];
|
playerStats.Weapons ??= [];
|
||||||
for (const [key, equipTime] of Object.entries(EQUIP_WEAPON)) {
|
for (const [type, equipTime] of Object.entries(data as IUploadEntry)) {
|
||||||
const weapon = playerStats.Weapons.find(element => element.type === key);
|
const weapon = playerStats.Weapons.find(element => element.type === type);
|
||||||
if (weapon) {
|
if (weapon) {
|
||||||
weapon.equipTime ??= 0;
|
weapon.equipTime ??= 0;
|
||||||
weapon.equipTime += equipTime;
|
weapon.equipTime += equipTime;
|
||||||
} else {
|
} else {
|
||||||
playerStats.Weapons.push({ type: key, equipTime });
|
playerStats.Weapons.push({ type: type, equipTime });
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if (CURRENT_MISSION_TIME) {
|
case "CURRENT_MISSION_TIME":
|
||||||
playerStats.TimePlayedSec ??= 0;
|
playerStats.TimePlayedSec ??= 0;
|
||||||
playerStats.TimePlayedSec += CURRENT_MISSION_TIME;
|
playerStats.TimePlayedSec += data;
|
||||||
}
|
break;
|
||||||
|
|
||||||
if (CIPHER_TIME) {
|
case "CIPHER_TIME":
|
||||||
playerStats.CipherTime ??= 0;
|
playerStats.CipherTime ??= 0;
|
||||||
playerStats.CipherTime += CIPHER_TIME;
|
playerStats.CipherTime += data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (!ignoredCategories.includes(category)) {
|
||||||
|
if (!unknownCategories[action]) {
|
||||||
|
unknownCategories[action] = [];
|
||||||
|
}
|
||||||
|
unknownCategories[action].push(category);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if (payload.max) {
|
case "max":
|
||||||
const { WEAPON_XP, MISSION_SCORE } = payload.max;
|
for (const [category, data] of Object.entries(actionData as IStatsMax)) {
|
||||||
|
switch (category) {
|
||||||
if (WEAPON_XP) {
|
case "WEAPON_XP":
|
||||||
playerStats.Weapons ??= [];
|
playerStats.Weapons ??= [];
|
||||||
for (const [key, xp] of Object.entries(WEAPON_XP)) {
|
for (const [type, xp] of Object.entries(data as IUploadEntry)) {
|
||||||
const weapon = playerStats.Weapons.find(element => element.type === key);
|
const weapon = playerStats.Weapons.find(element => element.type === type);
|
||||||
if (weapon) {
|
if (weapon) {
|
||||||
|
if (xp > (weapon.xp ?? 0)) {
|
||||||
weapon.xp = xp;
|
weapon.xp = xp;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
playerStats.Weapons.push({ type: key, xp });
|
playerStats.Weapons.push({ type: type, xp });
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if (MISSION_SCORE) {
|
case "MISSION_SCORE":
|
||||||
playerStats.Missions ??= [];
|
playerStats.Missions ??= [];
|
||||||
for (const [key, highScore] of Object.entries(MISSION_SCORE)) {
|
for (const [type, highScore] of Object.entries(data as IUploadEntry)) {
|
||||||
const mission = playerStats.Missions.find(element => element.type === key);
|
const mission = playerStats.Missions.find(element => element.type === type);
|
||||||
if (mission) {
|
if (mission) {
|
||||||
|
if (highScore > mission.highScore) {
|
||||||
mission.highScore = highScore;
|
mission.highScore = highScore;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
playerStats.Missions.push({ type: key, highScore });
|
playerStats.Missions.push({ type: type, highScore });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "RACE_SCORE":
|
||||||
|
playerStats.Races ??= new Map();
|
||||||
|
|
||||||
|
for (const [race, highScore] of Object.entries(data as Record<string, number>)) {
|
||||||
|
const currentRace = playerStats.Races.get(race);
|
||||||
|
|
||||||
|
if (currentRace) {
|
||||||
|
if (highScore > currentRace.highScore) {
|
||||||
|
playerStats.Races.set(race, { highScore });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
playerStats.Races.set(race, { highScore });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (payload.set) {
|
break;
|
||||||
const { ELO_RATING, RANK, PLAYER_LEVEL } = payload.set;
|
|
||||||
if (ELO_RATING) playerStats.Rating = ELO_RATING;
|
default:
|
||||||
if (RANK) playerStats.Rank = RANK;
|
if (!ignoredCategories.includes(category)) {
|
||||||
if (PLAYER_LEVEL) playerStats.PlayerLevel = PLAYER_LEVEL;
|
if (!unknownCategories[action]) {
|
||||||
|
unknownCategories[action] = [];
|
||||||
|
}
|
||||||
|
unknownCategories[action].push(category);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "set":
|
||||||
|
for (const [category, value] of Object.entries(actionData as IStatsSet)) {
|
||||||
|
switch (category) {
|
||||||
|
case "ELO_RATING":
|
||||||
|
playerStats.Rating = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "RANK":
|
||||||
|
playerStats.Rank = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "PLAYER_LEVEL":
|
||||||
|
playerStats.PlayerLevel = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (!ignoredCategories.includes(category)) {
|
||||||
|
if (!unknownCategories[action]) {
|
||||||
|
unknownCategories[action] = [];
|
||||||
|
}
|
||||||
|
unknownCategories[action].push(category);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "displayName":
|
||||||
|
case "guildId":
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
logger.debug(`Unknown updateStats action: ${action}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [action, categories] of Object.entries(unknownCategories)) {
|
||||||
|
logger.debug(`Unknown updateStats ${action} action categories: ${categories.join(", ")}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
await playerStats.save();
|
await playerStats.save();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ignoredCategories = [
|
||||||
|
//add action
|
||||||
|
"MISSION_STARTED",
|
||||||
|
"HOST_OS",
|
||||||
|
"CPU_CORES",
|
||||||
|
"CPU_MODEL",
|
||||||
|
"CPU_VENDOR",
|
||||||
|
"GPU_CLASS",
|
||||||
|
"GFX_DRIVER",
|
||||||
|
"GFX_RESOLUTION",
|
||||||
|
"GFX_ASPECT",
|
||||||
|
"GFX_WINDOW",
|
||||||
|
"GPU_VENDOR",
|
||||||
|
"GFX_HDR",
|
||||||
|
"SPEAKER_COUNT",
|
||||||
|
"MISSION_MATCHMAKING",
|
||||||
|
"PLAYER_COUNT",
|
||||||
|
"HOST_MIGRATION",
|
||||||
|
"DESTROY_DECORATION",
|
||||||
|
"MOVEMENT",
|
||||||
|
"RECEIVE_UPGRADE",
|
||||||
|
"EQUIP_COSMETIC",
|
||||||
|
"EQUIP_UPGRADE",
|
||||||
|
"MISSION_TYPE",
|
||||||
|
"MISSION_FACTION",
|
||||||
|
"MISSION_PLAYED",
|
||||||
|
"MISSION_PLAYED_TIME",
|
||||||
|
"CPU_CLOCK",
|
||||||
|
"CPU_FEATURE",
|
||||||
|
"RAM",
|
||||||
|
"ADDR_SPACE",
|
||||||
|
"GFX_SCALE",
|
||||||
|
"LOGINS",
|
||||||
|
"GPU_MODEL",
|
||||||
|
"MEDALS_TOP",
|
||||||
|
"STATS_TIMERS_RESET",
|
||||||
|
"INPUT_ACTIVITY_TIME",
|
||||||
|
"LOGINS_ITEM",
|
||||||
|
"TAKE_DAMAGE",
|
||||||
|
"SQUAD_KILL_ENEMY",
|
||||||
|
"SQUAD_HEADSHOT",
|
||||||
|
"SQUAD_MELEE_KILL",
|
||||||
|
"MELEE_KILL_ITEM",
|
||||||
|
"TAKE_DAMAGE_ITEM",
|
||||||
|
"SQUAD_KILL_ENEMY_ITEM",
|
||||||
|
"SQUAD_HEADSHOT_ITEM",
|
||||||
|
"SQUAD_MELEE_KILL_ITEM",
|
||||||
|
"PRE_DIE",
|
||||||
|
"PRE_DIE_ITEM",
|
||||||
|
"GEAR_USED",
|
||||||
|
"DIE_ITEM",
|
||||||
|
|
||||||
|
// timers action
|
||||||
|
"IN_SHIP_TIME",
|
||||||
|
"IN_SHIP_VIEW_TIME",
|
||||||
|
"MISSION_LOAD_TIME",
|
||||||
|
"MISSION_TIME",
|
||||||
|
"REGION_TIME",
|
||||||
|
"PLATFORM_TIME",
|
||||||
|
"PRE_DIE_TIME",
|
||||||
|
"VEHICLE_TIME"
|
||||||
|
];
|
||||||
|
@ -32,8 +32,10 @@ export interface IDojoComponentClient {
|
|||||||
pf: string; // Prefab (.level)
|
pf: string; // Prefab (.level)
|
||||||
ppf: string;
|
ppf: string;
|
||||||
pi?: IOid; // Parent ID. N/A to root.
|
pi?: IOid; // Parent ID. N/A to root.
|
||||||
op?: string; // "Open Portal"? N/A to root.
|
op?: string; // Name of the door within this room that leads to its parent. N/A to root.
|
||||||
pp?: string; // "Parent Portal"? N/A to root.
|
pp?: string; // Name of the door within the parent that leads to this room. N/A to root.
|
||||||
|
Name?: string;
|
||||||
|
Message?: string;
|
||||||
RegularCredits?: number; // "Collecting Materials" state: Number of credits that were donated.
|
RegularCredits?: number; // "Collecting Materials" state: Number of credits that were donated.
|
||||||
MiscItems?: IMiscItem[]; // "Collecting Materials" state: Resources that were donated.
|
MiscItems?: IMiscItem[]; // "Collecting Materials" state: Resources that were donated.
|
||||||
CompletionTime?: IMongoDate;
|
CompletionTime?: IMongoDate;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
export interface IStatsView {
|
export interface IStatsClient {
|
||||||
CiphersSolved?: number;
|
CiphersSolved?: number;
|
||||||
CiphersFailed?: number;
|
CiphersFailed?: number;
|
||||||
CipherTime?: number;
|
CipherTime?: number;
|
||||||
@ -10,9 +10,11 @@ export interface IStatsView {
|
|||||||
MissionsCompleted?: number;
|
MissionsCompleted?: number;
|
||||||
MissionsQuit?: number;
|
MissionsQuit?: number;
|
||||||
MissionsFailed?: number;
|
MissionsFailed?: number;
|
||||||
|
MissionsInterrupted?: number;
|
||||||
|
MissionsDumped?: number;
|
||||||
TimePlayedSec?: number;
|
TimePlayedSec?: number;
|
||||||
PickupCount?: number;
|
PickupCount?: number;
|
||||||
Tutorial?: { [key: string]: ITutorial };
|
Tutorial?: Map<string, ITutorial>;
|
||||||
Abilities?: IAbility[];
|
Abilities?: IAbility[];
|
||||||
Rating?: number;
|
Rating?: number;
|
||||||
Income?: number;
|
Income?: number;
|
||||||
@ -23,9 +25,10 @@ export interface IStatsView {
|
|||||||
Deaths?: number;
|
Deaths?: number;
|
||||||
HealCount?: number;
|
HealCount?: number;
|
||||||
ReviveCount?: number;
|
ReviveCount?: number;
|
||||||
|
Races?: Map<string, IRace>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IStatsDatabase extends IStatsView {
|
export interface IStatsDatabase extends IStatsClient {
|
||||||
accountOwnerId: Types.ObjectId;
|
accountOwnerId: Types.ObjectId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +71,11 @@ export interface IWeapon {
|
|||||||
fired?: number;
|
fired?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IStatsUpload {
|
export interface IRace {
|
||||||
|
highScore: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IStatsUpdate {
|
||||||
displayName: string;
|
displayName: string;
|
||||||
guildId?: string;
|
guildId?: string;
|
||||||
PS?: string;
|
PS?: string;
|
||||||
@ -128,6 +135,7 @@ export interface IUploadEntry {
|
|||||||
export interface IStatsMax {
|
export interface IStatsMax {
|
||||||
WEAPON_XP?: IUploadEntry;
|
WEAPON_XP?: IUploadEntry;
|
||||||
MISSION_SCORE?: IUploadEntry;
|
MISSION_SCORE?: IUploadEntry;
|
||||||
|
RACE_SCORE?: IUploadEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IStatsSet {
|
export interface IStatsSet {
|
||||||
|
@ -1,559 +0,0 @@
|
|||||||
{
|
|
||||||
"VendorInfo": {
|
|
||||||
"_id": { "$oid": "66d538400000000000000000" },
|
|
||||||
"TypeName": "/Lotus/Types/Game/VendorManifests/Events/RadioLegionIntermission11VendorManifest",
|
|
||||||
"ItemManifest": [
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrapperChassisBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 25, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000049" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrapperSystemsBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 25, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000050" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrapperHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 25, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000051" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/OrokinCatalyst",
|
|
||||||
"ItemPrices": [{ "ItemCount": 75, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000052" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/OrokinReactor",
|
|
||||||
"ItemPrices": [{ "ItemCount": 75, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000053" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/Alertium",
|
|
||||||
"ItemPrices": [{ "ItemCount": 15, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 5,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000054" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/Kuva",
|
|
||||||
"ItemPrices": [{ "ItemCount": 50, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_3",
|
|
||||||
"QuantityMultiplier": 10000,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000055" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Nightwave/GlassmakerShipDeco",
|
|
||||||
"ItemPrices": [{ "ItemCount": 60, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"Id": { "$oid": "001400140000000000000056" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/ProteaAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000941" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/StyanaxAltDHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000942" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/Skins/GramSolsticeSkinBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000943" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/PriestAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000944" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Upgrades/Skins/Hoverboard/HoverboardStickerWolf",
|
|
||||||
"ItemPrices": [{ "ItemCount": 30, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000945" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/StatlessExcaliburAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000946" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/StatlessVaubanAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000947" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/PirateAltBHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000948" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/StatlessBansheeAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000949" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/HarlequinAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000950" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/NovaSlipstreamHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000951" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/NekrosShroudHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000952" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/GlassAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000953" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/Skins/TatsuSolsticeSkinBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000954" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/StatlessNyxAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000955" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/Skins/AtomosSolsticeSkinBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000956" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/StatlessTrinityAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000957" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/DanteAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000958" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/StatlessV2EmberAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000959" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/VaubanHelmetSoldierBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000960" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/StatlessV2FrostAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000961" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/StatlessSarynAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000962" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/ValkyrBastetHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000963" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/MirageAltBHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000964" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/OberonAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000965" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/StatlessV2TrinityAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000966" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/FairyAltTwoHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000967" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/DragonAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000968" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Helmets/JadeAltHelmetBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 35, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000969" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/Aura/PlayerSniperDamageAuraMod",
|
|
||||||
"ItemPrices": [{ "ItemCount": 20, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000970" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/Aura/PlayerSprintAuraMod",
|
|
||||||
"ItemPrices": [{ "ItemCount": 20, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000971" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/Rifle/Event/Arbitration/InfCrpShockSwarmRifleArbitrationMod",
|
|
||||||
"ItemPrices": [{ "ItemCount": 20, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000972" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/Aura/PlayerEnemyRadarAuraMod",
|
|
||||||
"ItemPrices": [{ "ItemCount": 20, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000973" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/Nightwave/MagnusNightwaveMod",
|
|
||||||
"ItemPrices": [{ "ItemCount": 20, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000974" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/Aura/PlayerEnergyHealthRegenAuraMod",
|
|
||||||
"ItemPrices": [{ "ItemCount": 20, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000975" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/Aura/PlayerRifleAmmoAuraMod",
|
|
||||||
"ItemPrices": [{ "ItemCount": 20, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000976" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/Aura/InfestationSpeedReductionAuraMod",
|
|
||||||
"ItemPrices": [{ "ItemCount": 20, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000977" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/Rifle/Event/Nightwave/NightwaveTiberonAugmentMod",
|
|
||||||
"ItemPrices": [{ "ItemCount": 20, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000978" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/Aura/PlayerHealthAuraMod",
|
|
||||||
"ItemPrices": [{ "ItemCount": 20, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000979" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/Skins/GrnHammerBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 30, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_2",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000980" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/Skins/GrnAxeBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 30, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_2",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000981" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/Skins/DesertGrinlokSkinBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 30, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_2",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000982" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/Skins/DaggerAxeBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 30, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_2",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000983" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/Skins/ShockPlinxSkinBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 30, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_3",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000984" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Upgrades/Skins/Clan/GlassmakerEmblemItem",
|
|
||||||
"ItemPrices": [{ "ItemCount": 30, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_3",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000985" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Upgrades/Skins/Sigils/NoraSeasonTwoSigil",
|
|
||||||
"ItemPrices": [{ "ItemCount": 30, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_3",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000986" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/PhotoboothTileWolfSixPrison",
|
|
||||||
"ItemPrices": [{ "ItemCount": 45, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_3",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000987" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/Skins/ShockExergisSkinBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 30, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_3",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000988" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/HeatDaggerBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 50, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_3",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000989" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/CeramicDaggerBlueprint",
|
|
||||||
"ItemPrices": [{ "ItemCount": 50, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_3",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000990" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/PvPMods/Rifle/GrakataUnlimitedAmmo",
|
|
||||||
"ItemPrices": [{ "ItemCount": 20, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_4",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000991" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/PvPMods/Rifle/SupraHigherAccuracyAiming",
|
|
||||||
"ItemPrices": [{ "ItemCount": 20, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_4",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000992" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Powersuits/Ranger/RangerQuiverPvPAugmentCard",
|
|
||||||
"ItemPrices": [{ "ItemCount": 20, "ItemType": "/Lotus/Types/Items/MiscItems/NoraIntermissionElevenCreds", "ProductCategory": "MiscItems" }],
|
|
||||||
"Bin": "BIN_4",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } },
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": { "$oid": "001400140000000000000993" }
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2051240400000" } }
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -150,6 +150,14 @@
|
|||||||
"Seed": 353,
|
"Seed": 353,
|
||||||
"Nodes": []
|
"Nodes": []
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"_id": { "$oid": "663a4fc5ba6f84724fa48060" },
|
||||||
|
"Activation": { "$date": { "$numberLong": "1715097541439" } },
|
||||||
|
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
|
||||||
|
"Tag": "RadioLegionIntermission12Syndicate",
|
||||||
|
"Seed": 353,
|
||||||
|
"Nodes": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"_id": { "$oid": "663a4fc5ba6f84724fa48057" },
|
"_id": { "$oid": "663a4fc5ba6f84724fa48057" },
|
||||||
"Activation": { "$date": { "$numberLong": "1715097541439" } },
|
"Activation": { "$date": { "$numberLong": "1715097541439" } },
|
||||||
@ -1115,8 +1123,8 @@
|
|||||||
"SeasonInfo": {
|
"SeasonInfo": {
|
||||||
"Activation": { "$date": { "$numberLong": "1715796000000" } },
|
"Activation": { "$date": { "$numberLong": "1715796000000" } },
|
||||||
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
|
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
|
||||||
"AffiliationTag": "RadioLegionIntermission11Syndicate",
|
"AffiliationTag": "RadioLegionIntermission12Syndicate",
|
||||||
"Season": 13,
|
"Season": 14,
|
||||||
"Phase": 0,
|
"Phase": 0,
|
||||||
"Params": "",
|
"Params": "",
|
||||||
"ActiveChallenges": [
|
"ActiveChallenges": [
|
||||||
|
@ -101,7 +101,7 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="card-text" id="RegularCredits-owned"></p>
|
<p class="card-text" id="RegularCredits-owned"></p>
|
||||||
<form class="input-group" onsubmit="doAddCurrency('RegularCredits');return false;">
|
<form class="input-group" onsubmit="doAddCurrency('RegularCredits');return false;">
|
||||||
<input class="form-control" id="RegularCredits-delta" type="number" value="1000000" step="1000000" />
|
<input class="form-control" id="RegularCredits-delta" type="number" value="1000000" />
|
||||||
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -113,7 +113,7 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="card-text" id="PremiumCredits-owned"></p>
|
<p class="card-text" id="PremiumCredits-owned"></p>
|
||||||
<form class="input-group" onsubmit="doAddCurrency('PremiumCredits');return false;">
|
<form class="input-group" onsubmit="doAddCurrency('PremiumCredits');return false;">
|
||||||
<input class="form-control" id="PremiumCredits-delta" type="number" value="100" step="100" />
|
<input class="form-control" id="PremiumCredits-delta" type="number" value="100" />
|
||||||
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -125,7 +125,7 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="card-text" id="FusionPoints-owned"></p>
|
<p class="card-text" id="FusionPoints-owned"></p>
|
||||||
<form class="input-group" onsubmit="doAddCurrency('FusionPoints');return false;">
|
<form class="input-group" onsubmit="doAddCurrency('FusionPoints');return false;">
|
||||||
<input class="form-control" id="FusionPoints-delta" type="number" value="1000" step="1000" />
|
<input class="form-control" id="FusionPoints-delta" type="number" value="1000" />
|
||||||
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -137,7 +137,7 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="card-text" id="PrimeTokens-owned"></p>
|
<p class="card-text" id="PrimeTokens-owned"></p>
|
||||||
<form class="input-group" onsubmit="doAddCurrency('PrimeTokens');return false;">
|
<form class="input-group" onsubmit="doAddCurrency('PrimeTokens');return false;">
|
||||||
<input class="form-control" id="PrimeTokens-delta" type="number" value="1" step="1" />
|
<input class="form-control" id="PrimeTokens-delta" type="number" value="1" />
|
||||||
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1037,6 +1037,7 @@ function doAddAllMods() {
|
|||||||
for (const child of document.getElementById("datalist-mods").children) {
|
for (const child of document.getElementById("datalist-mods").children) {
|
||||||
modsAll.add(child.getAttribute("data-key"));
|
modsAll.add(child.getAttribute("data-key"));
|
||||||
}
|
}
|
||||||
|
modsAll.delete("/Lotus/Upgrades/Mods/Fusers/LegendaryModFuser");
|
||||||
|
|
||||||
revalidateAuthz(() => {
|
revalidateAuthz(() => {
|
||||||
const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1");
|
const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user