Compare commits
1 Commits
main
...
syndicate-
Author | SHA1 | Date | |
---|---|---|---|
8378797c36 |
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -1,4 +1,4 @@
|
|||||||
# Auto detect text files and perform LF normalization
|
# Auto detect text files and perform LF normalization
|
||||||
* text=auto eol=lf
|
* text=auto
|
||||||
|
|
||||||
static/webui/libs/ linguist-vendored
|
static/webui/libs/ linguist-vendored
|
||||||
|
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@ -15,12 +15,11 @@ jobs:
|
|||||||
- run: npm run verify
|
- run: npm run verify
|
||||||
- run: npm run lint:ci
|
- run: npm run lint:ci
|
||||||
- run: npm run prettier
|
- run: npm run prettier
|
||||||
- run: npm run update-translations
|
|
||||||
- name: Fail if there are uncommitted changes
|
- name: Fail if there are uncommitted changes
|
||||||
run: |
|
run: |
|
||||||
if [[ -n "$(git status --porcelain)" ]]; then
|
if [[ -n "$(git status --porcelain)" ]]; then
|
||||||
echo "Uncommitted changes detected:"
|
echo "Uncommitted changes detected:"
|
||||||
git status
|
git status
|
||||||
git --no-pager diff
|
git diff
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
@ -10,8 +10,6 @@ To get an idea of what functionality you can expect to be missing [have a look t
|
|||||||
|
|
||||||
## config.json
|
## config.json
|
||||||
|
|
||||||
SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [config.json.example](config.json.example), which has most cheats disabled.
|
|
||||||
|
|
||||||
- `logger.level` can be `fatal`, `error`, `warn`, `info`, `http`, `debug`, or `trace`.
|
- `logger.level` can be `fatal`, `error`, `warn`, `info`, `http`, `debug`, or `trace`.
|
||||||
- `myIrcAddresses` can be used to point to an IRC server. If not provided, defaults to `[ myAddress ]`.
|
- `myIrcAddresses` can be used to point to an IRC server. If not provided, defaults to `[ myAddress ]`.
|
||||||
- `worldState.lockTime` will lock the time provided in worldState if nonzero, e.g. `1743202800` for night in POE.
|
- `worldState.lockTime` will lock the time provided in worldState if nonzero, e.g. `1743202800` for night in POE.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
@echo off
|
@echo off
|
||||||
|
|
||||||
echo Updating SpaceNinjaServer...
|
echo Updating SpaceNinjaServer...
|
||||||
|
git config remote.origin.url https://openwf.io/SpaceNinjaServer.git
|
||||||
git fetch --prune
|
git fetch --prune
|
||||||
git stash
|
git stash
|
||||||
git reset --hard origin/main
|
git reset --hard origin/main
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
"infiniteEndo": false,
|
"infiniteEndo": false,
|
||||||
"infiniteRegalAya": false,
|
"infiniteRegalAya": false,
|
||||||
"infiniteHelminthMaterials": false,
|
"infiniteHelminthMaterials": false,
|
||||||
"dontSubtractConsumables": false,
|
|
||||||
"unlockAllShipFeatures": false,
|
"unlockAllShipFeatures": false,
|
||||||
"unlockAllShipDecorations": false,
|
"unlockAllShipDecorations": false,
|
||||||
"unlockAllFlavourItems": false,
|
"unlockAllFlavourItems": false,
|
||||||
@ -30,17 +29,11 @@
|
|||||||
"unlockExilusEverywhere": false,
|
"unlockExilusEverywhere": false,
|
||||||
"unlockArcanesEverywhere": false,
|
"unlockArcanesEverywhere": false,
|
||||||
"noDailyStandingLimits": false,
|
"noDailyStandingLimits": false,
|
||||||
"noDailyFocusLimit": false,
|
|
||||||
"noArgonCrystalDecay": false,
|
"noArgonCrystalDecay": false,
|
||||||
"noMasteryRankUpCooldown": false,
|
"noMasteryRankUpCooldown": false,
|
||||||
"noVendorPurchaseLimits": true,
|
"noVendorPurchaseLimits": true,
|
||||||
"noDeathMarks": false,
|
|
||||||
"noKimCooldowns": false,
|
|
||||||
"instantResourceExtractorDrones": false,
|
"instantResourceExtractorDrones": false,
|
||||||
"noResourceExtractorDronesDamage": false,
|
|
||||||
"skipClanKeyCrafting": false,
|
|
||||||
"noDojoRoomBuildStage": false,
|
"noDojoRoomBuildStage": false,
|
||||||
"noDecoBuildStage": false,
|
|
||||||
"fastDojoRoomDestruction": false,
|
"fastDojoRoomDestruction": false,
|
||||||
"noDojoResearchCosts": false,
|
"noDojoResearchCosts": false,
|
||||||
"noDojoResearchTime": false,
|
"noDojoResearchTime": false,
|
||||||
|
16
package-lock.json
generated
16
package-lock.json
generated
@ -17,8 +17,8 @@
|
|||||||
"mongoose": "^8.11.0",
|
"mongoose": "^8.11.0",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"ncp": "^2.0.0",
|
"ncp": "^2.0.0",
|
||||||
"typescript": "^5.5",
|
"typescript": ">=5.5 <5.6.0",
|
||||||
"warframe-public-export-plus": "^0.5.59",
|
"warframe-public-export-plus": "^0.5.52",
|
||||||
"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"
|
||||||
@ -3720,9 +3720,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.8.3",
|
"version": "5.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
|
||||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
@ -3789,9 +3789,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/warframe-public-export-plus": {
|
"node_modules/warframe-public-export-plus": {
|
||||||
"version": "0.5.59",
|
"version": "0.5.52",
|
||||||
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.59.tgz",
|
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.52.tgz",
|
||||||
"integrity": "sha512-/SUCVjngVDBz6gahz7CdVLywtHLODL6O5nmNtQcxFDUwrUGnF1lETcG8/UO+WLeGxBVAy4BDPbq+9ZWlYZM4uQ=="
|
"integrity": "sha512-mJyQbTFMDwgBSkhUYJzcfJg9qrMTrL1pyZuAxV/Dov68xUikK5zigQSYM3ZkKYbhwBtg0Bx/+7q9GAmPzGaRhA=="
|
||||||
},
|
},
|
||||||
"node_modules/warframe-riven-info": {
|
"node_modules/warframe-riven-info": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"description": "WF Emulator",
|
"description": "WF Emulator",
|
||||||
"main": "index.ts",
|
"main": "index.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node --enable-source-maps --import ./build/src/pathman.js build/src/index.js",
|
"start": "node --import ./build/src/pathman.js build/src/index.js",
|
||||||
"dev": "ts-node-dev --openssl-legacy-provider -r tsconfig-paths/register src/index.ts ",
|
"dev": "ts-node-dev --openssl-legacy-provider -r tsconfig-paths/register src/index.ts ",
|
||||||
"build": "tsc --incremental --sourceMap && ncp static/webui build/static/webui",
|
"build": "tsc --incremental --sourceMap && ncp static/webui build/static/webui",
|
||||||
"verify": "tsgo --noEmit",
|
"verify": "tsgo --noEmit",
|
||||||
@ -24,8 +24,8 @@
|
|||||||
"mongoose": "^8.11.0",
|
"mongoose": "^8.11.0",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"ncp": "^2.0.0",
|
"ncp": "^2.0.0",
|
||||||
"typescript": "^5.5",
|
"typescript": ">=5.5 <5.6.0",
|
||||||
"warframe-public-export-plus": "^0.5.59",
|
"warframe-public-export-plus": "^0.5.52",
|
||||||
"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"
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
|
||||||
function extractStrings(content) {
|
function extractStrings(content) {
|
||||||
const regex = /([a-zA-Z0-9_]+): `([^`]*)`,/g;
|
const regex = /([a-zA-Z_]+): `([^`]*)`,/g;
|
||||||
let matches;
|
let matches;
|
||||||
const strings = {};
|
const strings = {};
|
||||||
while ((matches = regex.exec(content)) !== null) {
|
while ((matches = regex.exec(content)) !== null) {
|
||||||
@ -15,7 +15,7 @@ function extractStrings(content) {
|
|||||||
|
|
||||||
const source = fs.readFileSync("../static/webui/translations/en.js", "utf8");
|
const source = fs.readFileSync("../static/webui/translations/en.js", "utf8");
|
||||||
const sourceStrings = extractStrings(source);
|
const sourceStrings = extractStrings(source);
|
||||||
const sourceLines = source.substring(0, source.length - 1).split("\n");
|
const sourceLines = source.split("\n");
|
||||||
|
|
||||||
fs.readdirSync("../static/webui/translations").forEach(file => {
|
fs.readdirSync("../static/webui/translations").forEach(file => {
|
||||||
if (fs.lstatSync(`../static/webui/translations/${file}`).isFile() && file !== "en.js") {
|
if (fs.lstatSync(`../static/webui/translations/${file}`).isFile() && file !== "en.js") {
|
||||||
@ -36,7 +36,7 @@ fs.readdirSync("../static/webui/translations").forEach(file => {
|
|||||||
fs.writeSync(fileHandle, ` ${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");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -16,9 +16,9 @@ import { webuiRouter } from "@/src/routes/webui";
|
|||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
app.use((req, _res, next) => {
|
app.use((req, _res, next) => {
|
||||||
// 38.5.0 introduced "ezip" for encrypted body blobs and "e" for request verification only (encrypted body blobs with no application data).
|
// 38.5.0 introduced "ezip" for encrypted body blobs.
|
||||||
// The bootstrapper decrypts it for us but having an unsupported Content-Encoding here would still be an issue for Express, so removing it.
|
// The bootstrapper decrypts it for us but having an unsupported Content-Encoding here would still be an issue for Express, so removing it.
|
||||||
if (req.headers["content-encoding"] == "ezip" || req.headers["content-encoding"] == "e") {
|
if (req.headers["content-encoding"] == "ezip") {
|
||||||
req.headers["content-encoding"] = undefined;
|
req.headers["content-encoding"] = undefined;
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
@ -26,7 +26,7 @@ app.use((req, _res, next) => {
|
|||||||
|
|
||||||
app.use(bodyParser.raw());
|
app.use(bodyParser.raw());
|
||||||
app.use(express.json({ limit: "4mb" }));
|
app.use(express.json({ limit: "4mb" }));
|
||||||
app.use(bodyParser.text({ limit: "4mb" }));
|
app.use(bodyParser.text());
|
||||||
app.use(requestLogger);
|
app.use(requestLogger);
|
||||||
|
|
||||||
app.use("/api", apiRouter);
|
app.use("/api", apiRouter);
|
||||||
|
@ -2,18 +2,15 @@ const millisecondsPerSecond = 1000;
|
|||||||
const secondsPerMinute = 60;
|
const secondsPerMinute = 60;
|
||||||
const minutesPerHour = 60;
|
const minutesPerHour = 60;
|
||||||
const hoursPerDay = 24;
|
const hoursPerDay = 24;
|
||||||
const daysPerWeek = 7;
|
|
||||||
|
|
||||||
const unixSecond = millisecondsPerSecond;
|
const unixSecond = millisecondsPerSecond;
|
||||||
const unixMinute = secondsPerMinute * millisecondsPerSecond;
|
const unixMinute = secondsPerMinute * millisecondsPerSecond;
|
||||||
const unixHour = unixMinute * minutesPerHour;
|
const unixHour = unixMinute * minutesPerHour;
|
||||||
const unixDay = hoursPerDay * unixHour;
|
const unixDay = hoursPerDay * unixHour;
|
||||||
const unixWeek = daysPerWeek * unixDay;
|
|
||||||
|
|
||||||
export const unixTimesInMs = {
|
export const unixTimesInMs = {
|
||||||
second: unixSecond,
|
second: unixSecond,
|
||||||
minute: unixMinute,
|
minute: unixMinute,
|
||||||
hour: unixHour,
|
hour: unixHour,
|
||||||
day: unixDay,
|
day: unixDay
|
||||||
week: unixWeek
|
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,7 @@ export const activateRandomModController: RequestHandler = async (req, res) => {
|
|||||||
ItemCount: -1
|
ItemCount: -1
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType])!;
|
const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType]);
|
||||||
const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
|
const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
|
||||||
const upgradeIndex =
|
const upgradeIndex =
|
||||||
inventory.Upgrades.push({
|
inventory.Upgrades.push({
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
import { toOid } from "@/src/helpers/inventoryHelpers";
|
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { Account, Ignore } from "@/src/models/loginModel";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { IFriendInfo } from "@/src/types/guildTypes";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const addIgnoredUserController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const data = getJSONfromString<IAddIgnoredUserRequest>(String(req.body));
|
|
||||||
const ignoreeAccount = await Account.findOne(
|
|
||||||
{ DisplayName: data.playerName.substring(0, data.playerName.length - 1) },
|
|
||||||
"_id"
|
|
||||||
);
|
|
||||||
if (ignoreeAccount) {
|
|
||||||
await Ignore.create({ ignorer: accountId, ignoree: ignoreeAccount._id });
|
|
||||||
res.json({
|
|
||||||
Ignored: {
|
|
||||||
_id: toOid(ignoreeAccount._id),
|
|
||||||
DisplayName: data.playerName
|
|
||||||
} satisfies IFriendInfo
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
res.status(400).end();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IAddIgnoredUserRequest {
|
|
||||||
playerName: string;
|
|
||||||
}
|
|
@ -28,7 +28,7 @@ export const artifactTransmutationController: RequestHandler = async (req, res)
|
|||||||
});
|
});
|
||||||
|
|
||||||
const rawRivenType = getRandomRawRivenType();
|
const rawRivenType = getRandomRawRivenType();
|
||||||
const rivenType = getRandomElement(rivenRawToRealWeighted[rawRivenType])!;
|
const rivenType = getRandomElement(rivenRawToRealWeighted[rawRivenType]);
|
||||||
const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
|
const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
|
||||||
|
|
||||||
const upgradeIndex =
|
const upgradeIndex =
|
||||||
@ -57,16 +57,12 @@ export const artifactTransmutationController: RequestHandler = async (req, res)
|
|||||||
payload.Consumed.forEach(upgrade => {
|
payload.Consumed.forEach(upgrade => {
|
||||||
const meta = ExportUpgrades[upgrade.ItemType];
|
const meta = ExportUpgrades[upgrade.ItemType];
|
||||||
counts[meta.rarity] += upgrade.ItemCount;
|
counts[meta.rarity] += upgrade.ItemCount;
|
||||||
if (upgrade.ItemId.$oid != "000000000000000000000000") {
|
|
||||||
inventory.Upgrades.pull({ _id: upgrade.ItemId.$oid });
|
|
||||||
} else {
|
|
||||||
addMods(inventory, [
|
addMods(inventory, [
|
||||||
{
|
{
|
||||||
ItemType: upgrade.ItemType,
|
ItemType: upgrade.ItemType,
|
||||||
ItemCount: upgrade.ItemCount * -1
|
ItemCount: upgrade.ItemCount * -1
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
}
|
|
||||||
if (upgrade.ItemType == "/Lotus/Upgrades/Mods/TransmuteCores/AttackTransmuteCore") {
|
if (upgrade.ItemType == "/Lotus/Upgrades/Mods/TransmuteCores/AttackTransmuteCore") {
|
||||||
forcedPolarity = "AP_ATTACK";
|
forcedPolarity = "AP_ATTACK";
|
||||||
} else if (upgrade.ItemType == "/Lotus/Upgrades/Mods/TransmuteCores/DefenseTransmuteCore") {
|
} else if (upgrade.ItemType == "/Lotus/Upgrades/Mods/TransmuteCores/DefenseTransmuteCore") {
|
||||||
@ -76,15 +72,6 @@ export const artifactTransmutationController: RequestHandler = async (req, res)
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let newModType: string | undefined;
|
|
||||||
for (const specialModSet of specialModSets) {
|
|
||||||
if (specialModSet.indexOf(payload.Consumed[0].ItemType) != -1) {
|
|
||||||
newModType = getRandomElement(specialModSet);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!newModType) {
|
|
||||||
// Based on the table on https://wiki.warframe.com/w/Transmutation
|
// Based on the table on https://wiki.warframe.com/w/Transmutation
|
||||||
const weights: Record<TRarity, number> = {
|
const weights: Record<TRarity, number> = {
|
||||||
COMMON: counts.COMMON * 95 + counts.UNCOMMON * 15 + counts.RARE * 4,
|
COMMON: counts.COMMON * 95 + counts.UNCOMMON * 15 + counts.RARE * 4,
|
||||||
@ -100,9 +87,7 @@ export const artifactTransmutationController: RequestHandler = async (req, res)
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
newModType = getRandomWeightedReward(options, weights)!.uniqueName;
|
const newModType = getRandomWeightedReward(options, weights)!.uniqueName;
|
||||||
}
|
|
||||||
|
|
||||||
addMods(inventory, [
|
addMods(inventory, [
|
||||||
{
|
{
|
||||||
ItemType: newModType,
|
ItemType: newModType,
|
||||||
@ -145,34 +130,3 @@ interface IAgnosticUpgradeClient {
|
|||||||
ItemCount: number;
|
ItemCount: number;
|
||||||
LastAdded: IOid;
|
LastAdded: IOid;
|
||||||
}
|
}
|
||||||
|
|
||||||
const specialModSets: string[][] = [
|
|
||||||
[
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalOneMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalTwoMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalThreeMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalFourMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalFiveMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalSixMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalSevenMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalEightMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalWildcardMod"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusOneMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusTwoMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusThreeMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusFourMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusFiveMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusSixMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusSevenMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusEightMod"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndSpeedOnUseMod",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndWeaponDamageOnUseMod",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusLargeOnSingleUseMod",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusOnUseMod",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusSmallOnSingleUseMod"
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
@ -15,12 +15,6 @@ export const changeDojoRootController: RequestHandler = async (req, res) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example POST body: {"pivot":[0, 0, -64],"components":"{\"670429301ca0a63848ccc467\":{\"R\":[0,0,0],\"P\":[0,3,32]},\"6704254a1ca0a63848ccb33c\":{\"R\":[0,0,0],\"P\":[0,9.25,-32]},\"670429461ca0a63848ccc731\":{\"R\":[-90,0,0],\"P\":[-47.999992370605,3,16]}}"}
|
|
||||||
if (req.body) {
|
|
||||||
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
|
||||||
throw new Error("dojo reparent operation should not need deco repositioning"); // because we always provide SortId
|
|
||||||
}
|
|
||||||
|
|
||||||
const idToNode: Record<string, INode> = {};
|
const idToNode: Record<string, INode> = {};
|
||||||
guild.DojoComponents.forEach(x => {
|
guild.DojoComponents.forEach(x => {
|
||||||
idToNode[x._id.toString()] = {
|
idToNode[x._id.toString()] = {
|
||||||
@ -49,13 +43,23 @@ export const changeDojoRootController: RequestHandler = async (req, res) => {
|
|||||||
newRoot.component.pp = undefined;
|
newRoot.component.pp = undefined;
|
||||||
newRoot.parent = undefined;
|
newRoot.parent = undefined;
|
||||||
|
|
||||||
// Set/update SortId in top-to-bottom order
|
// Don't even ask me why this is needed because I don't know either
|
||||||
const stack: INode[] = [newRoot];
|
const stack: INode[] = [newRoot];
|
||||||
|
let i = 0;
|
||||||
|
const idMap: Record<string, Types.ObjectId> = {};
|
||||||
while (stack.length != 0) {
|
while (stack.length != 0) {
|
||||||
const top = stack.shift()!;
|
const top = stack.shift()!;
|
||||||
top.component.SortId = new Types.ObjectId();
|
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));
|
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));
|
logger.debug("New tree:\n" + treeToString(newRoot));
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ import {
|
|||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { toOid } from "@/src/helpers/inventoryHelpers";
|
|
||||||
|
|
||||||
interface IClaimCompletedRecipeRequest {
|
interface IClaimCompletedRecipeRequest {
|
||||||
RecipeIds: IOid[];
|
RecipeIds: IOid[];
|
||||||
@ -81,7 +80,6 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
|
|||||||
} else {
|
} else {
|
||||||
logger.debug("Claiming Recipe", { recipe, pendingRecipe });
|
logger.debug("Claiming Recipe", { recipe, pendingRecipe });
|
||||||
|
|
||||||
let BrandedSuits: undefined | IOid[];
|
|
||||||
if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") {
|
if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") {
|
||||||
inventory.PendingSpectreLoadouts ??= [];
|
inventory.PendingSpectreLoadouts ??= [];
|
||||||
inventory.SpectreLoadouts ??= [];
|
inventory.SpectreLoadouts ??= [];
|
||||||
@ -106,10 +104,9 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
|
|||||||
inventory.BrandedSuits!.findIndex(x => x.equals(pendingRecipe.SuitToUnbrand)),
|
inventory.BrandedSuits!.findIndex(x => x.equals(pendingRecipe.SuitToUnbrand)),
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
BrandedSuits = [toOid(pendingRecipe.SuitToUnbrand!)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let InventoryChanges: IInventoryChanges = {};
|
let InventoryChanges = {};
|
||||||
if (recipe.consumeOnUse) {
|
if (recipe.consumeOnUse) {
|
||||||
addRecipes(inventory, [
|
addRecipes(inventory, [
|
||||||
{
|
{
|
||||||
@ -133,17 +130,10 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
|
|||||||
if (recipe.secretIngredientAction != "SIA_UNBRAND") {
|
if (recipe.secretIngredientAction != "SIA_UNBRAND") {
|
||||||
InventoryChanges = {
|
InventoryChanges = {
|
||||||
...InventoryChanges,
|
...InventoryChanges,
|
||||||
...(await addItem(
|
...(await addItem(inventory, recipe.resultType, recipe.num, false))
|
||||||
inventory,
|
|
||||||
recipe.resultType,
|
|
||||||
recipe.num,
|
|
||||||
false,
|
|
||||||
undefined,
|
|
||||||
pendingRecipe.TargetFingerprint
|
|
||||||
))
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({ InventoryChanges, BrandedSuits });
|
res.json({ InventoryChanges });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { addFusionPoints, getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ export const claimLibraryDailyTaskRewardController: RequestHandler = async (req,
|
|||||||
}
|
}
|
||||||
syndicate.Standing += rewardStanding;
|
syndicate.Standing += rewardStanding;
|
||||||
|
|
||||||
addFusionPoints(inventory, 80 * rewardQuantity);
|
inventory.FusionPoints += 80 * rewardQuantity;
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
import { getCalendarProgress, getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
|
||||||
import { getWorldState } from "@/src/services/worldStateService";
|
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
// GET request; query parameters: CompletedEventIdx=0&Iteration=4&Version=19&Season=CST_SUMMER
|
|
||||||
export const completeCalendarEventController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const calendarProgress = getCalendarProgress(inventory);
|
|
||||||
const currentSeason = getWorldState().KnownCalendarSeasons[0];
|
|
||||||
let inventoryChanges: IInventoryChanges = {};
|
|
||||||
let dayIndex = 0;
|
|
||||||
for (const day of currentSeason.Days) {
|
|
||||||
if (day.events.length == 0 || day.events[0].type != "CET_CHALLENGE") {
|
|
||||||
if (dayIndex == calendarProgress.SeasonProgress.LastCompletedDayIdx) {
|
|
||||||
if (day.events.length != 0) {
|
|
||||||
const selection = day.events[parseInt(req.query.CompletedEventIdx as string)];
|
|
||||||
if (selection.type == "CET_REWARD") {
|
|
||||||
inventoryChanges = (await handleStoreItemAcquisition(selection.reward!, inventory))
|
|
||||||
.InventoryChanges;
|
|
||||||
} else if (selection.type == "CET_UPGRADE") {
|
|
||||||
calendarProgress.YearProgress.Upgrades.push(selection.upgrade!);
|
|
||||||
} else if (selection.type != "CET_PLOT") {
|
|
||||||
throw new Error(`unexpected selection type: ${selection.type}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++dayIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
calendarProgress.SeasonProgress.LastCompletedDayIdx++;
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: inventoryChanges,
|
|
||||||
CalendarProgress: inventory.CalendarProgress
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,14 +1,8 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Guild, GuildMember } from "@/src/models/guildModel";
|
import { Guild, GuildMember } from "@/src/models/guildModel";
|
||||||
import { Account } from "@/src/models/loginModel";
|
import { Account } from "@/src/models/loginModel";
|
||||||
import {
|
import { deleteGuild, getGuildClient, hasGuildPermission, removeDojoKeyItems } from "@/src/services/guildService";
|
||||||
deleteGuild,
|
import { addRecipes, combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
|
||||||
getGuildClient,
|
|
||||||
giveClanKey,
|
|
||||||
hasGuildPermission,
|
|
||||||
removeDojoKeyItems
|
|
||||||
} from "@/src/services/guildService";
|
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountForRequest, getAccountIdForRequest, getSuffixedName } from "@/src/services/loginService";
|
import { getAccountForRequest, getAccountIdForRequest, getSuffixedName } from "@/src/services/loginService";
|
||||||
import { GuildPermission } from "@/src/types/guildTypes";
|
import { GuildPermission } from "@/src/types/guildTypes";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
@ -47,7 +41,14 @@ export const confirmGuildInvitationGetController: RequestHandler = async (req, r
|
|||||||
// Update inventory of new member
|
// Update inventory of new member
|
||||||
const inventory = await getInventory(account._id.toString(), "GuildId LevelKeys Recipes");
|
const inventory = await getInventory(account._id.toString(), "GuildId LevelKeys Recipes");
|
||||||
inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
|
inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
|
||||||
giveClanKey(inventory, inventoryChanges);
|
const recipeChanges = [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
addRecipes(inventory, recipeChanges);
|
||||||
|
combineInventoryChanges(inventoryChanges, { Recipes: recipeChanges });
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
const guild = (await Guild.findById(req.query.clanId as string))!;
|
const guild = (await Guild.findById(req.query.clanId as string))!;
|
||||||
@ -95,9 +96,14 @@ export const confirmGuildInvitationPostController: RequestHandler = async (req,
|
|||||||
await GuildMember.deleteMany({ accountId: guildMember.accountId, status: 1 });
|
await GuildMember.deleteMany({ accountId: guildMember.accountId, status: 1 });
|
||||||
|
|
||||||
// Update inventory of new member
|
// Update inventory of new member
|
||||||
const inventory = await getInventory(guildMember.accountId.toString(), "GuildId LevelKeys Recipes");
|
const inventory = await getInventory(guildMember.accountId.toString(), "GuildId Recipes");
|
||||||
inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
|
inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
|
||||||
giveClanKey(inventory);
|
addRecipes(inventory, [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
]);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
// Add join to clan log
|
// Add join to clan log
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
|
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Guild } from "@/src/models/guildModel";
|
import { Guild, GuildMember } from "@/src/models/guildModel";
|
||||||
import { checkClanAscensionHasRequiredContributors } from "@/src/services/guildService";
|
import { config } from "@/src/services/configService";
|
||||||
import { addFusionPoints, getInventory } from "@/src/services/inventoryService";
|
import { createMessage } from "@/src/services/inboxService";
|
||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
@ -30,13 +31,49 @@ export const contributeGuildClassController: RequestHandler = async (req, res) =
|
|||||||
|
|
||||||
guild.CeremonyContributors.push(new Types.ObjectId(accountId));
|
guild.CeremonyContributors.push(new Types.ObjectId(accountId));
|
||||||
|
|
||||||
await checkClanAscensionHasRequiredContributors(guild);
|
// Once required contributor count is hit, the class is committed and there's 72 hours to claim endo.
|
||||||
|
if (guild.CeremonyContributors.length == payload.RequiredContributors) {
|
||||||
|
guild.Class = guild.CeremonyClass!;
|
||||||
|
guild.CeremonyClass = undefined;
|
||||||
|
guild.CeremonyResetDate = new Date(Date.now() + (config.fastClanAscension ? 5_000 : 72 * 3600_000));
|
||||||
|
if (!config.fastClanAscension) {
|
||||||
|
// Send message to all active guild members
|
||||||
|
const members = await GuildMember.find({ guildId: payload.GuildId, status: 0 }, "accountId");
|
||||||
|
for (const member of members) {
|
||||||
|
// somewhat unfaithful as on live the "msg" is not a loctag, but since we don't have the string, we'll let the client fill it in with "arg".
|
||||||
|
await createMessage(member.accountId, [
|
||||||
|
{
|
||||||
|
sndr: guild.Name,
|
||||||
|
msg: "/Lotus/Language/Clan/Clan_AscensionCeremonyInProgressDetails",
|
||||||
|
arg: [
|
||||||
|
{
|
||||||
|
Key: "RESETDATE",
|
||||||
|
Tag:
|
||||||
|
guild.CeremonyResetDate.getUTCMonth() +
|
||||||
|
"/" +
|
||||||
|
guild.CeremonyResetDate.getUTCDate() +
|
||||||
|
"/" +
|
||||||
|
(guild.CeremonyResetDate.getUTCFullYear() % 100) +
|
||||||
|
" " +
|
||||||
|
guild.CeremonyResetDate.getUTCHours().toString().padStart(2, "0") +
|
||||||
|
":" +
|
||||||
|
guild.CeremonyResetDate.getUTCMinutes().toString().padStart(2, "0")
|
||||||
|
}
|
||||||
|
],
|
||||||
|
sub: "/Lotus/Language/Clan/Clan_AscensionCeremonyInProgress",
|
||||||
|
icon: "/Lotus/Interface/Graphics/ClanTileImages/ClanEnterDojo.png",
|
||||||
|
highPriority: true
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await guild.save();
|
await guild.save();
|
||||||
|
|
||||||
// Either way, endo is given to the contributor.
|
// Either way, endo is given to the contributor.
|
||||||
const inventory = await getInventory(accountId, "FusionPoints");
|
const inventory = await getInventory(accountId, "FusionPoints");
|
||||||
addFusionPoints(inventory, guild.CeremonyEndo!);
|
inventory.FusionPoints += guild.CeremonyEndo!;
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
|
@ -2,9 +2,8 @@ import { RequestHandler } from "express";
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Guild, GuildMember } from "@/src/models/guildModel";
|
import { Guild, GuildMember } from "@/src/models/guildModel";
|
||||||
import { createUniqueClanName, getGuildClient, giveClanKey } from "@/src/services/guildService";
|
import { createUniqueClanName, getGuildClient } from "@/src/services/guildService";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { addRecipes, getInventory } from "@/src/services/inventoryService";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
|
||||||
|
|
||||||
export const createGuildController: RequestHandler = async (req, res) => {
|
export const createGuildController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -27,15 +26,26 @@ export const createGuildController: RequestHandler = async (req, res) => {
|
|||||||
rank: 0
|
rank: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
const inventory = await getInventory(accountId, "GuildId LevelKeys Recipes");
|
const inventory = await getInventory(accountId, "GuildId Recipes");
|
||||||
inventory.GuildId = guild._id;
|
inventory.GuildId = guild._id;
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
addRecipes(inventory, [
|
||||||
giveClanKey(inventory, inventoryChanges);
|
{
|
||||||
|
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
]);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
...(await getGuildClient(guild, accountId)),
|
...(await getGuildClient(guild, accountId)),
|
||||||
InventoryChanges: inventoryChanges
|
InventoryChanges: {
|
||||||
|
Recipes: [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { ICrewMemberClient } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
import { Types } from "mongoose";
|
|
||||||
|
|
||||||
export const crewMembersController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId, "CrewMembers");
|
|
||||||
const data = getJSONfromString<ICrewMembersRequest>(String(req.body));
|
|
||||||
const dbCrewMember = inventory.CrewMembers.id(data.crewMember.ItemId.$oid)!;
|
|
||||||
dbCrewMember.AssignedRole = data.crewMember.AssignedRole;
|
|
||||||
dbCrewMember.SkillEfficiency = data.crewMember.SkillEfficiency;
|
|
||||||
dbCrewMember.WeaponConfigIdx = data.crewMember.WeaponConfigIdx;
|
|
||||||
dbCrewMember.WeaponId = new Types.ObjectId(data.crewMember.WeaponId.$oid);
|
|
||||||
dbCrewMember.Configs = data.crewMember.Configs;
|
|
||||||
dbCrewMember.SecondInCommand = data.crewMember.SecondInCommand;
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
crewMemberId: data.crewMember.ItemId.$oid,
|
|
||||||
NemesisFingerprint: data.crewMember.NemesisFingerprint
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ICrewMembersRequest {
|
|
||||||
crewMember: ICrewMemberClient;
|
|
||||||
}
|
|
@ -1,84 +0,0 @@
|
|||||||
import {
|
|
||||||
addCrewShipSalvagedWeaponSkin,
|
|
||||||
addCrewShipRawSalvage,
|
|
||||||
getInventory,
|
|
||||||
addEquipment
|
|
||||||
} from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
import { ICrewShipComponentFingerprint, IInnateDamageFingerprint } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { ExportCustoms, ExportRailjackWeapons, ExportUpgrades } from "warframe-public-export-plus";
|
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
|
||||||
import { getRandomInt } from "@/src/services/rngService";
|
|
||||||
import { IFingerprintStat } from "@/src/helpers/rivenHelper";
|
|
||||||
import { IEquipmentDatabase } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
|
||||||
|
|
||||||
export const crewShipIdentifySalvageController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(
|
|
||||||
accountId,
|
|
||||||
"CrewShipSalvagedWeaponSkins CrewShipSalvagedWeapons CrewShipRawSalvage"
|
|
||||||
);
|
|
||||||
const payload = getJSONfromString<ICrewShipIdentifySalvageRequest>(String(req.body));
|
|
||||||
|
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
|
||||||
if (payload.ItemType in ExportCustoms) {
|
|
||||||
const meta = ExportCustoms[payload.ItemType];
|
|
||||||
let upgradeFingerprint: ICrewShipComponentFingerprint = { compat: payload.ItemType, buffs: [] };
|
|
||||||
if (meta.subroutines) {
|
|
||||||
upgradeFingerprint = {
|
|
||||||
SubroutineIndex: getRandomInt(0, meta.subroutines.length - 1),
|
|
||||||
...upgradeFingerprint
|
|
||||||
};
|
|
||||||
}
|
|
||||||
for (const upgrade of meta.randomisedUpgrades!) {
|
|
||||||
upgradeFingerprint.buffs.push({ Tag: upgrade.tag, Value: Math.trunc(Math.random() * 0x40000000) });
|
|
||||||
}
|
|
||||||
addCrewShipSalvagedWeaponSkin(
|
|
||||||
inventory,
|
|
||||||
payload.ItemType,
|
|
||||||
JSON.stringify(upgradeFingerprint),
|
|
||||||
inventoryChanges
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const meta = ExportRailjackWeapons[payload.ItemType];
|
|
||||||
let defaultOverwrites: Partial<IEquipmentDatabase> | undefined;
|
|
||||||
if (meta.defaultUpgrades?.[0]) {
|
|
||||||
const upgradeType = meta.defaultUpgrades[0].ItemType;
|
|
||||||
const upgradeMeta = ExportUpgrades[upgradeType];
|
|
||||||
const buffs: IFingerprintStat[] = [];
|
|
||||||
for (const buff of upgradeMeta.upgradeEntries!) {
|
|
||||||
buffs.push({
|
|
||||||
Tag: buff.tag,
|
|
||||||
Value: Math.trunc(Math.random() * 0x40000000)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
defaultOverwrites = {
|
|
||||||
UpgradeType: upgradeType,
|
|
||||||
UpgradeFingerprint: JSON.stringify({
|
|
||||||
compat: payload.ItemType,
|
|
||||||
buffs
|
|
||||||
} satisfies IInnateDamageFingerprint)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
addEquipment(inventory, "CrewShipSalvagedWeapons", payload.ItemType, defaultOverwrites, inventoryChanges);
|
|
||||||
}
|
|
||||||
|
|
||||||
inventoryChanges.CrewShipRawSalvage = [
|
|
||||||
{
|
|
||||||
ItemType: payload.ItemType,
|
|
||||||
ItemCount: -1
|
|
||||||
}
|
|
||||||
];
|
|
||||||
addCrewShipRawSalvage(inventory, inventoryChanges.CrewShipRawSalvage);
|
|
||||||
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: inventoryChanges
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ICrewShipIdentifySalvageRequest {
|
|
||||||
ItemType: string;
|
|
||||||
}
|
|
@ -1,11 +1,5 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
// Arbiter Dojo endpoints, not really used by us as we don't provide a ContentURL.
|
|
||||||
|
|
||||||
export const dojoController: RequestHandler = (_req, res) => {
|
export const dojoController: RequestHandler = (_req, res) => {
|
||||||
res.json("-1"); // Tell client to use authorised request.
|
res.json("-1"); // Tell client to use authorised request.
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setDojoURLController: RequestHandler = (_req, res) => {
|
|
||||||
res.end();
|
|
||||||
};
|
|
||||||
|
@ -55,7 +55,7 @@ export const dronesController: RequestHandler = async (req, res) => {
|
|||||||
? new Date()
|
? new Date()
|
||||||
: new Date(Date.now() + getRandomInt(3 * 3600 * 1000, 4 * 3600 * 1000));
|
: new Date(Date.now() + getRandomInt(3 * 3600 * 1000, 4 * 3600 * 1000));
|
||||||
drone.PendingDamage =
|
drone.PendingDamage =
|
||||||
!config.noResourceExtractorDronesDamage && Math.random() < system.damageChance
|
Math.random() < system.damageChance
|
||||||
? getRandomInt(system.droneDamage.minValue, system.droneDamage.maxValue)
|
? getRandomInt(system.droneDamage.minValue, system.droneDamage.maxValue)
|
||||||
: 0;
|
: 0;
|
||||||
const resource = getRandomWeightedRewardUc(system.resources, droneMeta.probabilities)!;
|
const resource = getRandomWeightedRewardUc(system.resources, droneMeta.probabilities)!;
|
||||||
|
@ -21,12 +21,10 @@ export const entratiLabConquestModeController: RequestHandler = async (req, res)
|
|||||||
inventory.EntratiVaultCountResetDate = new Date(weekEnd);
|
inventory.EntratiVaultCountResetDate = new Date(weekEnd);
|
||||||
if (inventory.EntratiLabConquestUnlocked) {
|
if (inventory.EntratiLabConquestUnlocked) {
|
||||||
inventory.EntratiLabConquestUnlocked = 0;
|
inventory.EntratiLabConquestUnlocked = 0;
|
||||||
inventory.EntratiLabConquestCacheScoreMission = 0;
|
|
||||||
inventory.EntratiLabConquestActiveFrameVariants = [];
|
inventory.EntratiLabConquestActiveFrameVariants = [];
|
||||||
}
|
}
|
||||||
if (inventory.EchoesHexConquestUnlocked) {
|
if (inventory.EchoesHexConquestUnlocked) {
|
||||||
inventory.EchoesHexConquestUnlocked = 0;
|
inventory.EchoesHexConquestUnlocked = 0;
|
||||||
inventory.EchoesHexConquestCacheScoreMission = 0;
|
|
||||||
inventory.EchoesHexConquestActiveFrameVariants = [];
|
inventory.EchoesHexConquestActiveFrameVariants = [];
|
||||||
inventory.EchoesHexConquestActiveStickers = [];
|
inventory.EchoesHexConquestActiveStickers = [];
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { addMiscItems, addStanding, getInventory } from "@/src/services/inventoryService";
|
import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper";
|
||||||
|
import { addMiscItems, getInventory, getStandingLimit, updateStandingLimit } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { ExportResources } from "warframe-public-export-plus";
|
import { ExportResources, ExportSyndicates } from "warframe-public-export-plus";
|
||||||
|
|
||||||
export const fishmongerController: RequestHandler = async (req, res) => {
|
export const fishmongerController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -30,15 +31,32 @@ export const fishmongerController: RequestHandler = async (req, res) => {
|
|||||||
miscItemChanges.push({ ItemType: fish.ItemType, ItemCount: fish.ItemCount * -1 });
|
miscItemChanges.push({ ItemType: fish.ItemType, ItemCount: fish.ItemCount * -1 });
|
||||||
}
|
}
|
||||||
addMiscItems(inventory, miscItemChanges);
|
addMiscItems(inventory, miscItemChanges);
|
||||||
let affiliationMod;
|
if (gainedStanding && syndicateTag) {
|
||||||
if (gainedStanding && syndicateTag) affiliationMod = addStanding(inventory, syndicateTag, gainedStanding);
|
let syndicate = inventory.Affiliations.find(x => x.Tag == syndicateTag);
|
||||||
|
if (!syndicate) {
|
||||||
|
syndicate = inventory.Affiliations[inventory.Affiliations.push({ Tag: syndicateTag, Standing: 0 }) - 1];
|
||||||
|
}
|
||||||
|
const syndicateMeta = ExportSyndicates[syndicateTag];
|
||||||
|
|
||||||
|
const max = getMaxStanding(syndicateMeta, syndicate.Title ?? 0);
|
||||||
|
if (syndicate.Standing + gainedStanding > max) {
|
||||||
|
gainedStanding = max - syndicate.Standing;
|
||||||
|
}
|
||||||
|
if (gainedStanding > getStandingLimit(inventory, syndicateMeta.dailyLimitBin)) {
|
||||||
|
gainedStanding = getStandingLimit(inventory, syndicateMeta.dailyLimitBin);
|
||||||
|
}
|
||||||
|
|
||||||
|
syndicate.Standing += gainedStanding;
|
||||||
|
|
||||||
|
updateStandingLimit(inventory, syndicateMeta.dailyLimitBin, gainedStanding);
|
||||||
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
InventoryChanges: {
|
InventoryChanges: {
|
||||||
MiscItems: miscItemChanges
|
MiscItems: miscItemChanges
|
||||||
},
|
},
|
||||||
SyndicateTag: syndicateTag,
|
SyndicateTag: syndicateTag,
|
||||||
StandingChange: affiliationMod?.Standing || 0
|
StandingChange: gainedStanding
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -104,14 +104,13 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
case FocusOperation.SentTrainingAmplifier: {
|
case FocusOperation.SentTrainingAmplifier: {
|
||||||
const request = JSON.parse(String(req.body)) as ISentTrainingAmplifierRequest;
|
const request = JSON.parse(String(req.body)) as ISentTrainingAmplifierRequest;
|
||||||
const inventory = await getInventory(accountId);
|
const parts: string[] = [
|
||||||
const inventoryChanges = addEquipment(inventory, "OperatorAmps", request.StartingWeaponType, {
|
|
||||||
ModularParts: [
|
|
||||||
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingGrip",
|
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingGrip",
|
||||||
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingChassis",
|
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingChassis",
|
||||||
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingBarrel"
|
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingBarrel"
|
||||||
]
|
];
|
||||||
});
|
const inventory = await getInventory(accountId);
|
||||||
|
const inventoryChanges = addEquipment(inventory, "OperatorAmps", request.StartingWeaponType, parts);
|
||||||
occupySlot(inventory, InventorySlot.AMPS, false);
|
occupySlot(inventory, InventorySlot.AMPS, false);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json((inventoryChanges.OperatorAmps as IEquipmentClient[])[0]);
|
res.json((inventoryChanges.OperatorAmps as IEquipmentClient[])[0]);
|
||||||
|
@ -1,84 +0,0 @@
|
|||||||
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
|
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { addMiscItem, getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { toStoreItem } from "@/src/services/itemDataService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { createGarden, getPersonalRooms } from "@/src/services/personalRoomsService";
|
|
||||||
import { IMongoDate } from "@/src/types/commonTypes";
|
|
||||||
import { IMissionReward } from "@/src/types/missionTypes";
|
|
||||||
import { IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
|
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
|
||||||
import { IGardeningClient } from "@/src/types/shipTypes";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
import { dict_en, ExportResources } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
export const gardeningController: RequestHandler = async (req, res) => {
|
|
||||||
const data = getJSONfromString<IGardeningRequest>(String(req.body));
|
|
||||||
if (data.Mode != "HarvestAll") {
|
|
||||||
throw new Error(`unexpected gardening mode: ${data.Mode}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const [inventory, personalRooms] = await Promise.all([
|
|
||||||
getInventory(accountId, "MiscItems"),
|
|
||||||
getPersonalRooms(accountId, "Apartment")
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Harvest plants
|
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
|
||||||
const rewards: Record<string, IMissionReward[][]> = {};
|
|
||||||
for (const planter of personalRooms.Apartment.Gardening.Planters) {
|
|
||||||
rewards[planter.Name] = [];
|
|
||||||
for (const plant of planter.Plants) {
|
|
||||||
const itemType =
|
|
||||||
"/Lotus/Types/Gameplay/Duviri/Resource/DuviriPlantItem" +
|
|
||||||
plant.PlantType.substring(plant.PlantType.length - 1);
|
|
||||||
const itemCount = Math.random() < 0.775 ? 2 : 4;
|
|
||||||
|
|
||||||
addMiscItem(inventory, itemType, itemCount, inventoryChanges);
|
|
||||||
|
|
||||||
rewards[planter.Name].push([
|
|
||||||
{
|
|
||||||
StoreItem: toStoreItem(itemType),
|
|
||||||
TypeName: itemType,
|
|
||||||
ItemCount: itemCount,
|
|
||||||
DailyCooldown: false,
|
|
||||||
Rarity: itemCount == 2 ? 0.7743589743589744 : 0.22564102564102564,
|
|
||||||
TweetText: `${itemCount}x ${dict_en[ExportResources[itemType].name]} (Resource)`,
|
|
||||||
ProductCategory: "MiscItems"
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh garden
|
|
||||||
personalRooms.Apartment.Gardening = createGarden();
|
|
||||||
|
|
||||||
await Promise.all([inventory.save(), personalRooms.save()]);
|
|
||||||
|
|
||||||
const planter = personalRooms.Apartment.Gardening.Planters[personalRooms.Apartment.Gardening.Planters.length - 1];
|
|
||||||
const plant = planter.Plants[planter.Plants.length - 1];
|
|
||||||
res.json({
|
|
||||||
GardenTagName: planter.Name,
|
|
||||||
PlantType: plant.PlantType,
|
|
||||||
PlotIndex: plant.PlotIndex,
|
|
||||||
EndTime: toMongoDate(plant.EndTime),
|
|
||||||
InventoryChanges: inventoryChanges,
|
|
||||||
Gardening: personalRooms.toJSON<IPersonalRoomsClient>().Apartment.Gardening,
|
|
||||||
Rewards: rewards
|
|
||||||
} satisfies IGardeningResponse);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IGardeningRequest {
|
|
||||||
Mode: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IGardeningResponse {
|
|
||||||
GardenTagName: string;
|
|
||||||
PlantType: string;
|
|
||||||
PlotIndex: number;
|
|
||||||
EndTime: IMongoDate;
|
|
||||||
InventoryChanges: IInventoryChanges;
|
|
||||||
Gardening: IGardeningClient;
|
|
||||||
Rewards: Record<string, IMissionReward[][]>;
|
|
||||||
}
|
|
@ -1,20 +1,16 @@
|
|||||||
import { toOid } from "@/src/helpers/inventoryHelpers";
|
|
||||||
import { Account, Ignore } from "@/src/models/loginModel";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { IFriendInfo } from "@/src/types/guildTypes";
|
|
||||||
import { parallelForeach } from "@/src/utils/async-utils";
|
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const getIgnoredUsersController: RequestHandler = async (req, res) => {
|
const getIgnoredUsersController: RequestHandler = (_req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
res.writeHead(200, {
|
||||||
const ignores = await Ignore.find({ ignorer: accountId });
|
"Content-Type": "text/html",
|
||||||
const ignoredUsers: IFriendInfo[] = [];
|
"Content-Length": "3"
|
||||||
await parallelForeach(ignores, async ignore => {
|
|
||||||
const ignoreeAccount = (await Account.findById(ignore.ignoree, "DisplayName"))!;
|
|
||||||
ignoredUsers.push({
|
|
||||||
_id: toOid(ignore.ignoree),
|
|
||||||
DisplayName: ignoreeAccount.DisplayName + ""
|
|
||||||
});
|
});
|
||||||
});
|
res.end(
|
||||||
res.json({ IgnoredUsers: ignoredUsers });
|
Buffer.from([
|
||||||
|
0x7b, 0x22, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x38, 0x33, 0x30, 0x34, 0x30, 0x37, 0x37, 0x32, 0x32,
|
||||||
|
0x34, 0x30, 0x32, 0x32, 0x32, 0x36, 0x31, 0x35, 0x30, 0x31, 0x7d
|
||||||
|
])
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { getIgnoredUsersController };
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { generateRewardSeed } from "@/src/services/inventoryService";
|
import { generateRewardSeed } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { logger } from "@/src/utils/logger";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const getNewRewardSeedController: RequestHandler = async (req, res) => {
|
export const getNewRewardSeedController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|
||||||
const rewardSeed = generateRewardSeed();
|
const rewardSeed = generateRewardSeed();
|
||||||
|
logger.debug(`generated new reward seed: ${rewardSeed}`);
|
||||||
await Inventory.updateOne(
|
await Inventory.updateOne(
|
||||||
{
|
{
|
||||||
accountOwnerId: accountId
|
accountOwnerId: accountId
|
||||||
|
@ -2,24 +2,17 @@ import { RequestHandler } from "express";
|
|||||||
import { config } from "@/src/services/configService";
|
import { config } from "@/src/services/configService";
|
||||||
import allShipFeatures from "@/static/fixed_responses/allShipFeatures.json";
|
import allShipFeatures from "@/static/fixed_responses/allShipFeatures.json";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { createGarden, getPersonalRooms } from "@/src/services/personalRoomsService";
|
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
||||||
import { getShip } from "@/src/services/shipService";
|
import { getShip } from "@/src/services/shipService";
|
||||||
import { toOid } from "@/src/helpers/inventoryHelpers";
|
import { toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
import { IGetShipResponse } from "@/src/types/shipTypes";
|
import { IGetShipResponse } from "@/src/types/shipTypes";
|
||||||
import { IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
|
import { IPersonalRooms } from "@/src/types/personalRoomsTypes";
|
||||||
import { getLoadout } from "@/src/services/loadoutService";
|
import { getLoadout } from "@/src/services/loadoutService";
|
||||||
|
|
||||||
export const getShipController: RequestHandler = async (req, res) => {
|
export const getShipController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const personalRoomsDb = await getPersonalRooms(accountId);
|
const personalRoomsDb = await getPersonalRooms(accountId);
|
||||||
|
const personalRooms = personalRoomsDb.toJSON<IPersonalRooms>();
|
||||||
// Setup gardening if it's missing. Maybe should be done as part of some quest completion in the future.
|
|
||||||
if (personalRoomsDb.Apartment.Gardening.Planters.length == 0) {
|
|
||||||
personalRoomsDb.Apartment.Gardening = createGarden();
|
|
||||||
await personalRoomsDb.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
const personalRooms = personalRoomsDb.toJSON<IPersonalRoomsClient>();
|
|
||||||
const loadout = await getLoadout(accountId);
|
const loadout = await getLoadout(accountId);
|
||||||
const ship = await getShip(personalRoomsDb.activeShipId, "ShipAttachments SkinFlavourItem");
|
const ship = await getShip(personalRoomsDb.activeShipId, "ShipAttachments SkinFlavourItem");
|
||||||
|
|
||||||
@ -33,10 +26,7 @@ export const getShipController: RequestHandler = async (req, res) => {
|
|||||||
Colors: personalRooms.ShipInteriorColors,
|
Colors: personalRooms.ShipInteriorColors,
|
||||||
ShipAttachments: ship.ShipAttachments,
|
ShipAttachments: ship.ShipAttachments,
|
||||||
SkinFlavourItem: ship.SkinFlavourItem
|
SkinFlavourItem: ship.SkinFlavourItem
|
||||||
},
|
}
|
||||||
FavouriteLoadoutId: personalRooms.Ship.FavouriteLoadoutId
|
|
||||||
? toOid(personalRooms.Ship.FavouriteLoadoutId)
|
|
||||||
: undefined
|
|
||||||
},
|
},
|
||||||
Apartment: personalRooms.Apartment,
|
Apartment: personalRooms.Apartment,
|
||||||
TailorShop: personalRooms.TailorShop
|
TailorShop: personalRooms.TailorShop
|
||||||
|
@ -2,25 +2,36 @@ import { RequestHandler } from "express";
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
|
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
|
||||||
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { WeaponTypeInternal } from "@/src/services/itemDataService";
|
||||||
import { ArtifactPolarity, EquipmentFeatures, IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { ArtifactPolarity, EquipmentFeatures, IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { ExportRecipes } from "warframe-public-export-plus";
|
import { ExportRecipes } from "warframe-public-export-plus";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
|
|
||||||
|
const modularWeaponCategory: (WeaponTypeInternal | "Hoverboards")[] = [
|
||||||
|
"LongGuns",
|
||||||
|
"Pistols",
|
||||||
|
"Melee",
|
||||||
|
"OperatorAmps",
|
||||||
|
"Hoverboards"
|
||||||
|
];
|
||||||
|
|
||||||
interface IGildWeaponRequest {
|
interface IGildWeaponRequest {
|
||||||
ItemName: string;
|
ItemName: string;
|
||||||
Recipe: string; // e.g. /Lotus/Weapons/SolarisUnited/LotusGildKitgunBlueprint
|
Recipe: string; // e.g. /Lotus/Weapons/SolarisUnited/LotusGildKitgunBlueprint
|
||||||
PolarizeSlot?: number;
|
PolarizeSlot?: number;
|
||||||
PolarizeValue?: ArtifactPolarity;
|
PolarizeValue?: ArtifactPolarity;
|
||||||
ItemId: string;
|
ItemId: string;
|
||||||
Category: TEquipmentKey;
|
Category: WeaponTypeInternal | "Hoverboards";
|
||||||
}
|
}
|
||||||
|
|
||||||
export const gildWeaponController: RequestHandler = async (req, res) => {
|
export const gildWeaponController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const data = getJSONfromString<IGildWeaponRequest>(String(req.body));
|
const data = getJSONfromString<IGildWeaponRequest>(String(req.body));
|
||||||
data.ItemId = String(req.query.ItemId);
|
data.ItemId = String(req.query.ItemId);
|
||||||
data.Category = req.query.Category as TEquipmentKey;
|
if (!modularWeaponCategory.includes(req.query.Category as WeaponTypeInternal | "Hoverboards")) {
|
||||||
|
throw new Error(`Unknown modular weapon Category: ${String(req.query.Category)}`);
|
||||||
|
}
|
||||||
|
data.Category = req.query.Category as WeaponTypeInternal | "Hoverboards";
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
const weaponIndex = inventory[data.Category].findIndex(x => String(x._id) === data.ItemId);
|
const weaponIndex = inventory[data.Category].findIndex(x => String(x._id) === data.ItemId);
|
||||||
@ -31,10 +42,8 @@ export const gildWeaponController: RequestHandler = async (req, res) => {
|
|||||||
const weapon = inventory[data.Category][weaponIndex];
|
const weapon = inventory[data.Category][weaponIndex];
|
||||||
weapon.Features ??= 0;
|
weapon.Features ??= 0;
|
||||||
weapon.Features |= EquipmentFeatures.GILDED;
|
weapon.Features |= EquipmentFeatures.GILDED;
|
||||||
if (data.Recipe != "webui") {
|
|
||||||
weapon.ItemName = data.ItemName;
|
weapon.ItemName = data.ItemName;
|
||||||
weapon.XP = 0;
|
weapon.XP = 0;
|
||||||
}
|
|
||||||
if (data.Category != "OperatorAmps" && data.PolarizeSlot && data.PolarizeValue) {
|
if (data.Category != "OperatorAmps" && data.PolarizeSlot && data.PolarizeValue) {
|
||||||
weapon.Polarity = [
|
weapon.Polarity = [
|
||||||
{
|
{
|
||||||
@ -47,9 +56,6 @@ export const gildWeaponController: RequestHandler = async (req, res) => {
|
|||||||
const inventoryChanges: IInventoryChanges = {};
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
inventoryChanges[data.Category] = [weapon.toJSON<IEquipmentClient>()];
|
inventoryChanges[data.Category] = [weapon.toJSON<IEquipmentClient>()];
|
||||||
|
|
||||||
const affiliationMods = [];
|
|
||||||
|
|
||||||
if (data.Recipe != "webui") {
|
|
||||||
const recipe = ExportRecipes[data.Recipe];
|
const recipe = ExportRecipes[data.Recipe];
|
||||||
inventoryChanges.MiscItems = recipe.secretIngredients!.map(ingredient => ({
|
inventoryChanges.MiscItems = recipe.secretIngredients!.map(ingredient => ({
|
||||||
ItemType: ingredient.ItemType,
|
ItemType: ingredient.ItemType,
|
||||||
@ -57,6 +63,7 @@ export const gildWeaponController: RequestHandler = async (req, res) => {
|
|||||||
}));
|
}));
|
||||||
addMiscItems(inventory, inventoryChanges.MiscItems);
|
addMiscItems(inventory, inventoryChanges.MiscItems);
|
||||||
|
|
||||||
|
const affiliationMods = [];
|
||||||
if (recipe.syndicateStandingChange) {
|
if (recipe.syndicateStandingChange) {
|
||||||
const affiliation = inventory.Affiliations.find(x => x.Tag == recipe.syndicateStandingChange!.tag)!;
|
const affiliation = inventory.Affiliations.find(x => x.Tag == recipe.syndicateStandingChange!.tag)!;
|
||||||
affiliation.Standing += recipe.syndicateStandingChange.value;
|
affiliation.Standing += recipe.syndicateStandingChange.value;
|
||||||
@ -65,7 +72,6 @@ export const gildWeaponController: RequestHandler = async (req, res) => {
|
|||||||
Standing: recipe.syndicateStandingChange.value
|
Standing: recipe.syndicateStandingChange.value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
|
@ -16,7 +16,7 @@ export const giveQuestKeyRewardController: RequestHandler = async (req, res) =>
|
|||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
const inventoryChanges = await addItem(inventory, reward.ItemType, reward.Amount);
|
const inventoryChanges = await addItem(inventory, reward.ItemType, reward.Amount);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json(inventoryChanges);
|
res.json(inventoryChanges.InventoryChanges);
|
||||||
//TODO: consider whishlist changes
|
//TODO: consider whishlist changes
|
||||||
};
|
};
|
||||||
|
|
@ -1,20 +0,0 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { addLoreFragmentScans, addShipDecorations, getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { ILoreFragmentScan, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const giveShipDecoAndLoreFragmentController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId, "LoreFragmentScans ShipDecorations");
|
|
||||||
const data = getJSONfromString<IGiveShipDecoAndLoreFragmentRequest>(String(req.body));
|
|
||||||
addLoreFragmentScans(inventory, data.LoreFragmentScans);
|
|
||||||
addShipDecorations(inventory, data.ShipDecorations);
|
|
||||||
await inventory.save();
|
|
||||||
res.end();
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IGiveShipDecoAndLoreFragmentRequest {
|
|
||||||
LoreFragmentScans: ILoreFragmentScan[];
|
|
||||||
ShipDecorations: ITypeCount[];
|
|
||||||
}
|
|
@ -14,33 +14,29 @@ import {
|
|||||||
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import {
|
import {
|
||||||
addCrewShipWeaponSkin,
|
|
||||||
addEquipment,
|
|
||||||
addItem,
|
addItem,
|
||||||
addMiscItems,
|
addMiscItems,
|
||||||
addRecipes,
|
addRecipes,
|
||||||
combineInventoryChanges,
|
combineInventoryChanges,
|
||||||
getInventory,
|
getInventory,
|
||||||
occupySlot,
|
|
||||||
updateCurrency
|
updateCurrency
|
||||||
} from "@/src/services/inventoryService";
|
} from "@/src/services/inventoryService";
|
||||||
import { IMiscItem, InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { config } from "@/src/services/configService";
|
import { config } from "@/src/services/configService";
|
||||||
import { GuildPermission, ITechProjectClient } from "@/src/types/guildTypes";
|
import { GuildPermission, ITechProjectClient } from "@/src/types/guildTypes";
|
||||||
import { GuildMember } from "@/src/models/guildModel";
|
import { GuildMember } from "@/src/models/guildModel";
|
||||||
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
|
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
|
||||||
|
|
||||||
export const guildTechController: RequestHandler = async (req, res) => {
|
export const guildTechController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
|
const guild = await getGuildForRequestEx(req, inventory);
|
||||||
const data = JSON.parse(String(req.body)) as TGuildTechRequest;
|
const data = JSON.parse(String(req.body)) as TGuildTechRequest;
|
||||||
if (data.Action == "Sync") {
|
if (data.Action == "Sync") {
|
||||||
let needSave = false;
|
let needSave = false;
|
||||||
const techProjects: ITechProjectClient[] = [];
|
const techProjects: ITechProjectClient[] = [];
|
||||||
const guild = await getGuildForRequestEx(req, inventory);
|
|
||||||
if (guild.TechProjects) {
|
if (guild.TechProjects) {
|
||||||
for (const project of guild.TechProjects) {
|
for (const project of guild.TechProjects) {
|
||||||
const techProject: ITechProjectClient = {
|
const techProject: ITechProjectClient = {
|
||||||
@ -63,8 +59,6 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
res.json({ TechProjects: techProjects });
|
res.json({ TechProjects: techProjects });
|
||||||
} else if (data.Action == "Start") {
|
} else if (data.Action == "Start") {
|
||||||
if (data.Mode == "Guild") {
|
|
||||||
const guild = await getGuildForRequestEx(req, inventory);
|
|
||||||
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Tech))) {
|
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Tech))) {
|
||||||
res.status(400).send("-1").end();
|
res.status(400).send("-1").end();
|
||||||
return;
|
return;
|
||||||
@ -95,109 +89,38 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
await guild.save();
|
await guild.save();
|
||||||
res.end();
|
res.end();
|
||||||
} else {
|
|
||||||
const recipe = ExportDojoRecipes.research[data.RecipeType];
|
|
||||||
if (data.TechProductCategory) {
|
|
||||||
if (
|
|
||||||
data.TechProductCategory != "CrewShipWeapons" &&
|
|
||||||
data.TechProductCategory != "CrewShipWeaponSkins"
|
|
||||||
) {
|
|
||||||
throw new Error(`unexpected TechProductCategory: ${data.TechProductCategory}`);
|
|
||||||
}
|
|
||||||
if (!inventory[getSalvageCategory(data.TechProductCategory)].id(data.CategoryItemId)) {
|
|
||||||
throw new Error(
|
|
||||||
`no item with id ${data.CategoryItemId} in ${getSalvageCategory(data.TechProductCategory)} array`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const techProject =
|
|
||||||
inventory.PersonalTechProjects[
|
|
||||||
inventory.PersonalTechProjects.push({
|
|
||||||
State: 0,
|
|
||||||
ReqCredits: recipe.price,
|
|
||||||
ItemType: data.RecipeType,
|
|
||||||
ProductCategory: data.TechProductCategory,
|
|
||||||
CategoryItemId: data.CategoryItemId,
|
|
||||||
ReqItems: recipe.ingredients
|
|
||||||
}) - 1
|
|
||||||
];
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
isPersonal: true,
|
|
||||||
action: "Start",
|
|
||||||
personalTech: techProject.toJSON()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (data.Action == "Contribute") {
|
} else if (data.Action == "Contribute") {
|
||||||
if ((req.query.guildId as string) == "000000000000000000000000") {
|
|
||||||
const techProject = inventory.PersonalTechProjects.id(data.ResearchId)!;
|
|
||||||
|
|
||||||
techProject.ReqCredits -= data.RegularCredits;
|
|
||||||
const inventoryChanges: IInventoryChanges = updateCurrency(inventory, data.RegularCredits, false);
|
|
||||||
|
|
||||||
const miscItemChanges = [];
|
|
||||||
for (const miscItem of data.MiscItems) {
|
|
||||||
const reqItem = techProject.ReqItems.find(x => x.ItemType == miscItem.ItemType);
|
|
||||||
if (reqItem) {
|
|
||||||
if (miscItem.ItemCount > reqItem.ItemCount) {
|
|
||||||
miscItem.ItemCount = reqItem.ItemCount;
|
|
||||||
}
|
|
||||||
reqItem.ItemCount -= miscItem.ItemCount;
|
|
||||||
miscItemChanges.push({
|
|
||||||
ItemType: miscItem.ItemType,
|
|
||||||
ItemCount: miscItem.ItemCount * -1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addMiscItems(inventory, miscItemChanges);
|
|
||||||
inventoryChanges.MiscItems = miscItemChanges;
|
|
||||||
|
|
||||||
techProject.HasContributions = true;
|
|
||||||
|
|
||||||
if (techProject.ReqCredits == 0 && !techProject.ReqItems.find(x => x.ItemCount > 0)) {
|
|
||||||
techProject.State = 1;
|
|
||||||
const recipe = ExportDojoRecipes.research[techProject.ItemType];
|
|
||||||
techProject.CompletionDate = new Date(Date.now() + recipe.time * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: inventoryChanges,
|
|
||||||
PersonalResearch: { $oid: data.ResearchId },
|
|
||||||
PersonalResearchDate: techProject.CompletionDate ? toMongoDate(techProject.CompletionDate) : undefined
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (!hasAccessToDojo(inventory)) {
|
if (!hasAccessToDojo(inventory)) {
|
||||||
res.status(400).send("-1").end();
|
res.status(400).send("-1").end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const guild = await getGuildForRequestEx(req, inventory);
|
|
||||||
const guildMember = (await GuildMember.findOne(
|
const guildMember = (await GuildMember.findOne(
|
||||||
{ accountId, guildId: guild._id },
|
{ accountId, guildId: guild._id },
|
||||||
"RegularCreditsContributed MiscItemsContributed"
|
"RegularCreditsContributed MiscItemsContributed"
|
||||||
))!;
|
))!;
|
||||||
|
|
||||||
const techProject = guild.TechProjects!.find(x => x.ItemType == data.RecipeType)!;
|
const contributions = data;
|
||||||
|
const techProject = guild.TechProjects!.find(x => x.ItemType == contributions.RecipeType)!;
|
||||||
|
|
||||||
if (data.VaultCredits) {
|
if (contributions.VaultCredits) {
|
||||||
if (data.VaultCredits > techProject.ReqCredits) {
|
if (contributions.VaultCredits > techProject.ReqCredits) {
|
||||||
data.VaultCredits = techProject.ReqCredits;
|
contributions.VaultCredits = techProject.ReqCredits;
|
||||||
}
|
}
|
||||||
techProject.ReqCredits -= data.VaultCredits;
|
techProject.ReqCredits -= contributions.VaultCredits;
|
||||||
guild.VaultRegularCredits! -= data.VaultCredits;
|
guild.VaultRegularCredits! -= contributions.VaultCredits;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.RegularCredits > techProject.ReqCredits) {
|
if (contributions.RegularCredits > techProject.ReqCredits) {
|
||||||
data.RegularCredits = techProject.ReqCredits;
|
contributions.RegularCredits = techProject.ReqCredits;
|
||||||
}
|
}
|
||||||
techProject.ReqCredits -= data.RegularCredits;
|
techProject.ReqCredits -= contributions.RegularCredits;
|
||||||
|
|
||||||
guildMember.RegularCreditsContributed ??= 0;
|
guildMember.RegularCreditsContributed ??= 0;
|
||||||
guildMember.RegularCreditsContributed += data.RegularCredits;
|
guildMember.RegularCreditsContributed += contributions.RegularCredits;
|
||||||
|
|
||||||
if (data.VaultMiscItems.length) {
|
if (contributions.VaultMiscItems.length) {
|
||||||
for (const miscItem of data.VaultMiscItems) {
|
for (const miscItem of contributions.VaultMiscItems) {
|
||||||
const reqItem = techProject.ReqItems.find(x => x.ItemType == miscItem.ItemType);
|
const reqItem = techProject.ReqItems.find(x => x.ItemType == miscItem.ItemType);
|
||||||
if (reqItem) {
|
if (reqItem) {
|
||||||
if (miscItem.ItemCount > reqItem.ItemCount) {
|
if (miscItem.ItemCount > reqItem.ItemCount) {
|
||||||
@ -212,7 +135,7 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const miscItemChanges = [];
|
const miscItemChanges = [];
|
||||||
for (const miscItem of data.MiscItems) {
|
for (const miscItem of contributions.MiscItems) {
|
||||||
const reqItem = techProject.ReqItems.find(x => x.ItemType == miscItem.ItemType);
|
const reqItem = techProject.ReqItems.find(x => x.ItemType == miscItem.ItemType);
|
||||||
if (reqItem) {
|
if (reqItem) {
|
||||||
if (miscItem.ItemCount > reqItem.ItemCount) {
|
if (miscItem.ItemCount > reqItem.ItemCount) {
|
||||||
@ -228,7 +151,7 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
addMiscItems(inventory, miscItemChanges);
|
addMiscItems(inventory, miscItemChanges);
|
||||||
const inventoryChanges: IInventoryChanges = updateCurrency(inventory, data.RegularCredits, false);
|
const inventoryChanges: IInventoryChanges = updateCurrency(inventory, contributions.RegularCredits, false);
|
||||||
inventoryChanges.MiscItems = miscItemChanges;
|
inventoryChanges.MiscItems = miscItemChanges;
|
||||||
|
|
||||||
// Check if research is fully funded now.
|
// Check if research is fully funded now.
|
||||||
@ -239,18 +162,12 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
|||||||
InventoryChanges: inventoryChanges,
|
InventoryChanges: inventoryChanges,
|
||||||
Vault: getGuildVault(guild)
|
Vault: getGuildVault(guild)
|
||||||
});
|
});
|
||||||
}
|
|
||||||
} else if (data.Action.split(",")[0] == "Buy") {
|
} else if (data.Action.split(",")[0] == "Buy") {
|
||||||
const purchase = data as IGuildTechBuyRequest;
|
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Fabricator))) {
|
||||||
if (purchase.Mode == "Guild") {
|
|
||||||
const guild = await getGuildForRequestEx(req, inventory);
|
|
||||||
if (
|
|
||||||
!hasAccessToDojo(inventory) ||
|
|
||||||
!(await hasGuildPermission(guild, accountId, GuildPermission.Fabricator))
|
|
||||||
) {
|
|
||||||
res.status(400).send("-1").end();
|
res.status(400).send("-1").end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const purchase = data as IGuildTechBuyRequest;
|
||||||
const quantity = parseInt(data.Action.split(",")[1]);
|
const quantity = parseInt(data.Action.split(",")[1]);
|
||||||
const recipeChanges = [
|
const recipeChanges = [
|
||||||
{
|
{
|
||||||
@ -272,15 +189,7 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
|||||||
Recipes: recipeChanges
|
Recipes: recipeChanges
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
const inventoryChanges = claimSalvagedComponent(inventory, purchase.CategoryItemId!);
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
inventoryChanges: inventoryChanges
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (data.Action == "Fabricate") {
|
} else if (data.Action == "Fabricate") {
|
||||||
const guild = await getGuildForRequestEx(req, inventory);
|
|
||||||
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Fabricator))) {
|
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Fabricator))) {
|
||||||
res.status(400).send("-1").end();
|
res.status(400).send("-1").end();
|
||||||
return;
|
return;
|
||||||
@ -297,7 +206,6 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
|||||||
// Not a mistake: This response uses `inventoryChanges` instead of `InventoryChanges`.
|
// Not a mistake: This response uses `inventoryChanges` instead of `InventoryChanges`.
|
||||||
res.json({ inventoryChanges: inventoryChanges });
|
res.json({ inventoryChanges: inventoryChanges });
|
||||||
} else if (data.Action == "Pause") {
|
} else if (data.Action == "Pause") {
|
||||||
const guild = await getGuildForRequestEx(req, inventory);
|
|
||||||
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Tech))) {
|
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Tech))) {
|
||||||
res.status(400).send("-1").end();
|
res.status(400).send("-1").end();
|
||||||
return;
|
return;
|
||||||
@ -309,7 +217,6 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
|||||||
await removePigmentsFromGuildMembers(guild._id);
|
await removePigmentsFromGuildMembers(guild._id);
|
||||||
res.end();
|
res.end();
|
||||||
} else if (data.Action == "Unpause") {
|
} else if (data.Action == "Unpause") {
|
||||||
const guild = await getGuildForRequestEx(req, inventory);
|
|
||||||
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Tech))) {
|
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Tech))) {
|
||||||
res.status(400).send("-1").end();
|
res.status(400).send("-1").end();
|
||||||
return;
|
return;
|
||||||
@ -319,66 +226,9 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
|||||||
guild.ActiveDojoColorResearch = data.RecipeType;
|
guild.ActiveDojoColorResearch = data.RecipeType;
|
||||||
await guild.save();
|
await guild.save();
|
||||||
res.end();
|
res.end();
|
||||||
} else if (data.Action == "Cancel" && data.CategoryItemId) {
|
|
||||||
const personalTechProjectIndex = inventory.PersonalTechProjects.findIndex(x =>
|
|
||||||
x.CategoryItemId?.equals(data.CategoryItemId)
|
|
||||||
);
|
|
||||||
const personalTechProject = inventory.PersonalTechProjects[personalTechProjectIndex];
|
|
||||||
inventory.PersonalTechProjects.splice(personalTechProjectIndex, 1);
|
|
||||||
|
|
||||||
const meta = ExportDojoRecipes.research[personalTechProject.ItemType];
|
|
||||||
const contributedCredits = meta.price - personalTechProject.ReqCredits;
|
|
||||||
const inventoryChanges = updateCurrency(inventory, contributedCredits * -1, false);
|
|
||||||
inventoryChanges.MiscItems = [];
|
|
||||||
for (const ingredient of meta.ingredients) {
|
|
||||||
const reqItem = personalTechProject.ReqItems.find(x => x.ItemType == ingredient.ItemType);
|
|
||||||
if (reqItem) {
|
|
||||||
const contributedItems = ingredient.ItemCount - reqItem.ItemCount;
|
|
||||||
inventoryChanges.MiscItems.push({
|
|
||||||
ItemType: ingredient.ItemType,
|
|
||||||
ItemCount: contributedItems
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addMiscItems(inventory, inventoryChanges.MiscItems);
|
|
||||||
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
action: "Cancel",
|
|
||||||
isPersonal: true,
|
|
||||||
inventoryChanges: inventoryChanges,
|
|
||||||
personalTech: {
|
|
||||||
ItemId: toOid(personalTechProject._id)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (data.Action == "Rush" && data.CategoryItemId) {
|
|
||||||
const inventoryChanges: IInventoryChanges = {
|
|
||||||
...updateCurrency(inventory, 20, true),
|
|
||||||
...claimSalvagedComponent(inventory, data.CategoryItemId)
|
|
||||||
};
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
inventoryChanges: inventoryChanges
|
|
||||||
});
|
|
||||||
} else if (data.Action == "InstantFinish") {
|
|
||||||
if (data.TechProductCategory != "CrewShipWeapons" && data.TechProductCategory != "CrewShipWeaponSkins") {
|
|
||||||
throw new Error(`unexpected TechProductCategory: ${data.TechProductCategory}`);
|
|
||||||
}
|
|
||||||
const inventoryChanges = finishComponentRepair(inventory, data.TechProductCategory, data.CategoryItemId!);
|
|
||||||
inventoryChanges.MiscItems = [
|
|
||||||
{
|
|
||||||
ItemType: "/Lotus/Types/Items/MiscItems/InstantSalvageRepairItem",
|
|
||||||
ItemCount: -1
|
|
||||||
}
|
|
||||||
];
|
|
||||||
addMiscItems(inventory, inventoryChanges.MiscItems);
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
inventoryChanges: inventoryChanges
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
||||||
throw new Error(`unhandled guildTech request`);
|
throw new Error(`unknown guildTech action: ${data.Action}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -388,70 +238,23 @@ type TGuildTechRequest =
|
|||||||
| IGuildTechContributeRequest;
|
| IGuildTechContributeRequest;
|
||||||
|
|
||||||
interface IGuildTechBasicRequest {
|
interface IGuildTechBasicRequest {
|
||||||
Action: "Start" | "Fabricate" | "Pause" | "Unpause" | "Cancel" | "Rush" | "InstantFinish";
|
Action: "Start" | "Fabricate" | "Pause" | "Unpause";
|
||||||
Mode: "Guild" | "Personal";
|
Mode: "Guild";
|
||||||
RecipeType: string;
|
RecipeType: string;
|
||||||
TechProductCategory?: string;
|
|
||||||
CategoryItemId?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IGuildTechBuyRequest extends Omit<IGuildTechBasicRequest, "Action"> {
|
interface IGuildTechBuyRequest {
|
||||||
Action: string;
|
Action: string;
|
||||||
|
Mode: "Guild";
|
||||||
|
RecipeType: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IGuildTechContributeRequest {
|
interface IGuildTechContributeRequest {
|
||||||
Action: "Contribute";
|
Action: "Contribute";
|
||||||
ResearchId: string;
|
ResearchId: "";
|
||||||
RecipeType: string;
|
RecipeType: string;
|
||||||
RegularCredits: number;
|
RegularCredits: number;
|
||||||
MiscItems: IMiscItem[];
|
MiscItems: IMiscItem[];
|
||||||
VaultCredits: number;
|
VaultCredits: number;
|
||||||
VaultMiscItems: IMiscItem[];
|
VaultMiscItems: IMiscItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSalvageCategory = (
|
|
||||||
category: "CrewShipWeapons" | "CrewShipWeaponSkins"
|
|
||||||
): "CrewShipSalvagedWeapons" | "CrewShipSalvagedWeaponSkins" => {
|
|
||||||
return category == "CrewShipWeapons" ? "CrewShipSalvagedWeapons" : "CrewShipSalvagedWeaponSkins";
|
|
||||||
};
|
|
||||||
|
|
||||||
const claimSalvagedComponent = (inventory: TInventoryDatabaseDocument, itemId: string): IInventoryChanges => {
|
|
||||||
// delete personal tech project
|
|
||||||
const personalTechProjectIndex = inventory.PersonalTechProjects.findIndex(x => x.CategoryItemId?.equals(itemId));
|
|
||||||
const personalTechProject = inventory.PersonalTechProjects[personalTechProjectIndex];
|
|
||||||
inventory.PersonalTechProjects.splice(personalTechProjectIndex, 1);
|
|
||||||
|
|
||||||
const category = personalTechProject.ProductCategory! as "CrewShipWeapons" | "CrewShipWeaponSkins";
|
|
||||||
return finishComponentRepair(inventory, category, itemId);
|
|
||||||
};
|
|
||||||
|
|
||||||
const finishComponentRepair = (
|
|
||||||
inventory: TInventoryDatabaseDocument,
|
|
||||||
category: "CrewShipWeapons" | "CrewShipWeaponSkins",
|
|
||||||
itemId: string
|
|
||||||
): IInventoryChanges => {
|
|
||||||
const salvageCategory = getSalvageCategory(category);
|
|
||||||
|
|
||||||
// find salved part & delete it
|
|
||||||
const salvageIndex = inventory[salvageCategory].findIndex(x => x._id.equals(itemId));
|
|
||||||
const salvageItem = inventory[salvageCategory][salvageIndex];
|
|
||||||
inventory[salvageCategory].splice(salvageIndex, 1);
|
|
||||||
|
|
||||||
// add final item
|
|
||||||
const inventoryChanges = {
|
|
||||||
...(category == "CrewShipWeaponSkins"
|
|
||||||
? addCrewShipWeaponSkin(inventory, salvageItem.ItemType, salvageItem.UpgradeFingerprint)
|
|
||||||
: addEquipment(inventory, category, salvageItem.ItemType, {
|
|
||||||
UpgradeFingerprint: salvageItem.UpgradeFingerprint
|
|
||||||
})),
|
|
||||||
...occupySlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS, false)
|
|
||||||
};
|
|
||||||
|
|
||||||
inventoryChanges.RemovedIdItems = [
|
|
||||||
{
|
|
||||||
ItemId: { $oid: itemId }
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
return inventoryChanges;
|
|
||||||
};
|
|
||||||
|
@ -11,10 +11,8 @@ import {
|
|||||||
import { getAccountForRequest, getAccountFromSuffixedName, getSuffixedName } from "@/src/services/loginService";
|
import { getAccountForRequest, getAccountFromSuffixedName, getSuffixedName } from "@/src/services/loginService";
|
||||||
import { addItems, combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
|
import { addItems, combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { ExportFlavour } from "warframe-public-export-plus";
|
import { ExportFlavour, ExportGear } from "warframe-public-export-plus";
|
||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
||||||
import { fromStoreItem, isStoreItem } from "@/src/services/itemDataService";
|
|
||||||
import { IOid } from "@/src/types/commonTypes";
|
|
||||||
|
|
||||||
export const inboxController: RequestHandler = async (req, res) => {
|
export const inboxController: RequestHandler = async (req, res) => {
|
||||||
const { deleteId, lastMessage: latestClientMessageId, messageId } = req.query;
|
const { deleteId, lastMessage: latestClientMessageId, messageId } = req.query;
|
||||||
@ -29,10 +27,10 @@ export const inboxController: RequestHandler = async (req, res) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await deleteMessageRead(parseOid(deleteId as string));
|
await deleteMessageRead(deleteId as string);
|
||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
} else if (messageId) {
|
} else if (messageId) {
|
||||||
const message = await getMessage(parseOid(messageId as string));
|
const message = await getMessage(messageId as string);
|
||||||
message.r = true;
|
message.r = true;
|
||||||
await message.save();
|
await message.save();
|
||||||
|
|
||||||
@ -50,8 +48,8 @@ export const inboxController: RequestHandler = async (req, res) => {
|
|||||||
await addItems(
|
await addItems(
|
||||||
inventory,
|
inventory,
|
||||||
attachmentItems.map(attItem => ({
|
attachmentItems.map(attItem => ({
|
||||||
ItemType: isStoreItem(attItem) ? fromStoreItem(attItem) : attItem,
|
ItemType: attItem,
|
||||||
ItemCount: 1
|
ItemCount: attItem in ExportGear ? (ExportGear[attItem].purchaseQuantity ?? 1) : 1
|
||||||
})),
|
})),
|
||||||
inventoryChanges
|
inventoryChanges
|
||||||
);
|
);
|
||||||
@ -101,7 +99,7 @@ export const inboxController: RequestHandler = async (req, res) => {
|
|||||||
await createNewEventMessages(req);
|
await createNewEventMessages(req);
|
||||||
const messages = await Inbox.find({ ownerId: accountId }).sort({ date: 1 });
|
const messages = await Inbox.find({ ownerId: accountId }).sort({ date: 1 });
|
||||||
|
|
||||||
const latestClientMessage = messages.find(m => m._id.toString() === parseOid(latestClientMessageId as string));
|
const latestClientMessage = messages.find(m => m._id.toString() === latestClientMessageId);
|
||||||
|
|
||||||
if (!latestClientMessage) {
|
if (!latestClientMessage) {
|
||||||
logger.debug(`this should only happen after DeleteAllRead `);
|
logger.debug(`this should only happen after DeleteAllRead `);
|
||||||
@ -124,11 +122,3 @@ export const inboxController: RequestHandler = async (req, res) => {
|
|||||||
res.json({ Inbox: inbox });
|
res.json({ Inbox: inbox });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 33.6.0 has query arguments like lastMessage={"$oid":"68112baebf192e786d1502bb"} instead of lastMessage=68112baebf192e786d1502bb
|
|
||||||
const parseOid = (oid: string): string => {
|
|
||||||
if (oid[0] == "{") {
|
|
||||||
return (JSON.parse(oid) as IOid).$oid;
|
|
||||||
}
|
|
||||||
return oid;
|
|
||||||
};
|
|
||||||
|
@ -14,16 +14,9 @@ import {
|
|||||||
ExportVirtuals
|
ExportVirtuals
|
||||||
} from "warframe-public-export-plus";
|
} from "warframe-public-export-plus";
|
||||||
import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "@/src/services/infestedFoundryService";
|
import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "@/src/services/infestedFoundryService";
|
||||||
import {
|
import { addMiscItems, allDailyAffiliationKeys, createLibraryDailyTask } from "@/src/services/inventoryService";
|
||||||
addMiscItems,
|
|
||||||
allDailyAffiliationKeys,
|
|
||||||
cleanupInventory,
|
|
||||||
createLibraryDailyTask,
|
|
||||||
generateRewardSeed
|
|
||||||
} from "@/src/services/inventoryService";
|
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { catBreadHash } from "@/src/helpers/stringHelpers";
|
import { catBreadHash } from "@/src/helpers/stringHelpers";
|
||||||
import { Types } from "mongoose";
|
|
||||||
|
|
||||||
export const inventoryController: RequestHandler = async (request, response) => {
|
export const inventoryController: RequestHandler = async (request, response) => {
|
||||||
const accountId = await getAccountIdForRequest(request);
|
const accountId = await getAccountIdForRequest(request);
|
||||||
@ -86,10 +79,8 @@ export const inventoryController: RequestHandler = async (request, response) =>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanupInventory(inventory);
|
|
||||||
|
|
||||||
inventory.NextRefill = new Date((Math.trunc(Date.now() / 86400000) + 1) * 86400000);
|
inventory.NextRefill = new Date((Math.trunc(Date.now() / 86400000) + 1) * 86400000);
|
||||||
//await inventory.save();
|
await inventory.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -98,26 +89,8 @@ export const inventoryController: RequestHandler = async (request, response) =>
|
|||||||
new Date() >= inventory.InfestedFoundry.AbilityOverrideUnlockCooldown
|
new Date() >= inventory.InfestedFoundry.AbilityOverrideUnlockCooldown
|
||||||
) {
|
) {
|
||||||
handleSubsumeCompletion(inventory);
|
handleSubsumeCompletion(inventory);
|
||||||
//await inventory.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inventory.LastInventorySync) {
|
|
||||||
const lastSyncDuviriMood = Math.trunc(inventory.LastInventorySync.getTimestamp().getTime() / 7200000);
|
|
||||||
const currentDuviriMood = Math.trunc(Date.now() / 7200000);
|
|
||||||
if (lastSyncDuviriMood != currentDuviriMood) {
|
|
||||||
logger.debug(`refreshing duviri seed`);
|
|
||||||
if (!inventory.DuviriInfo) {
|
|
||||||
inventory.DuviriInfo = {
|
|
||||||
Seed: generateRewardSeed(),
|
|
||||||
NumCompletions: 0
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
inventory.DuviriInfo.Seed = generateRewardSeed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inventory.LastInventorySync = new Types.ObjectId();
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
}
|
||||||
|
|
||||||
response.json(await getInventoryResponse(inventory, "xpBasedLevelCapDisabled" in request.query));
|
response.json(await getInventoryResponse(inventory, "xpBasedLevelCapDisabled" in request.query));
|
||||||
};
|
};
|
||||||
@ -176,7 +149,7 @@ export const getInventoryResponse = async (
|
|||||||
inventoryResponse.ShipDecorations = [];
|
inventoryResponse.ShipDecorations = [];
|
||||||
for (const [uniqueName, item] of Object.entries(ExportResources)) {
|
for (const [uniqueName, item] of Object.entries(ExportResources)) {
|
||||||
if (item.productCategory == "ShipDecorations") {
|
if (item.productCategory == "ShipDecorations") {
|
||||||
inventoryResponse.ShipDecorations.push({ ItemType: uniqueName, ItemCount: 999_999 });
|
inventoryResponse.ShipDecorations.push({ ItemType: uniqueName, ItemCount: 1 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,8 +202,7 @@ export const getInventoryResponse = async (
|
|||||||
|
|
||||||
if (config.universalPolarityEverywhere) {
|
if (config.universalPolarityEverywhere) {
|
||||||
const Polarity: IPolarity[] = [];
|
const Polarity: IPolarity[] = [];
|
||||||
// 12 is needed for necramechs. 15 is needed for plexus/crewshipharness.
|
for (let i = 0; i != 12; ++i) {
|
||||||
for (let i = 0; i != 15; ++i) {
|
|
||||||
Polarity.push({
|
Polarity.push({
|
||||||
Slot: i,
|
Slot: i,
|
||||||
Value: ArtifactPolarity.Any
|
Value: ArtifactPolarity.Any
|
||||||
@ -285,16 +257,12 @@ export const getInventoryResponse = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.noDailyFocusLimit) {
|
|
||||||
inventoryResponse.DailyFocus = Math.max(999_999, 250000 + inventoryResponse.PlayerLevel * 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inventoryResponse.InfestedFoundry) {
|
if (inventoryResponse.InfestedFoundry) {
|
||||||
applyCheatsToInfestedFoundry(inventoryResponse.InfestedFoundry);
|
applyCheatsToInfestedFoundry(inventoryResponse.InfestedFoundry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Omitting this field so opening the navigation resyncs the inventory which is more desirable for typical usage.
|
// Omitting this field so opening the navigation resyncs the inventory which is more desirable for typical usage.
|
||||||
inventoryResponse.LastInventorySync = undefined;
|
//inventoryResponse.LastInventorySync = toOid(new Types.ObjectId());
|
||||||
|
|
||||||
// Set 2FA enabled so trading post can be used
|
// Set 2FA enabled so trading post can be used
|
||||||
inventoryResponse.HWIDProtectEnabled = true;
|
inventoryResponse.HWIDProtectEnabled = true;
|
||||||
|
@ -7,7 +7,6 @@ import { Account } from "@/src/models/loginModel";
|
|||||||
import { createAccount, isCorrectPassword, isNameTaken } from "@/src/services/loginService";
|
import { createAccount, isCorrectPassword, isNameTaken } from "@/src/services/loginService";
|
||||||
import { IDatabaseAccountJson, ILoginRequest, ILoginResponse } from "@/src/types/loginTypes";
|
import { IDatabaseAccountJson, ILoginRequest, ILoginResponse } from "@/src/types/loginTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { version_compare } from "@/src/services/worldStateService";
|
|
||||||
|
|
||||||
export const loginController: RequestHandler = async (request, response) => {
|
export const loginController: RequestHandler = async (request, response) => {
|
||||||
const loginRequest = JSON.parse(String(request.body)) as ILoginRequest; // parse octet stream of json data to json object
|
const loginRequest = JSON.parse(String(request.body)) as ILoginRequest; // parse octet stream of json data to json object
|
||||||
@ -22,11 +21,7 @@ export const loginController: RequestHandler = async (request, response) => {
|
|||||||
|
|
||||||
const myAddress = request.host.indexOf("warframe.com") == -1 ? request.host : config.myAddress;
|
const myAddress = request.host.indexOf("warframe.com") == -1 ? request.host : config.myAddress;
|
||||||
|
|
||||||
if (
|
if (!account && config.autoCreateAccount && loginRequest.ClientType != "webui") {
|
||||||
!account &&
|
|
||||||
((config.autoCreateAccount && loginRequest.ClientType != "webui") ||
|
|
||||||
loginRequest.ClientType == "webui-register")
|
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
const nameFromEmail = loginRequest.email.substring(0, loginRequest.email.indexOf("@"));
|
const nameFromEmail = loginRequest.email.substring(0, loginRequest.email.indexOf("@"));
|
||||||
let name = nameFromEmail || loginRequest.email.substring(1) || "SpaceNinja";
|
let name = nameFromEmail || loginRequest.email.substring(1) || "SpaceNinja";
|
||||||
@ -42,7 +37,7 @@ export const loginController: RequestHandler = async (request, response) => {
|
|||||||
password: loginRequest.password,
|
password: loginRequest.password,
|
||||||
DisplayName: name,
|
DisplayName: name,
|
||||||
CountryCode: loginRequest.lang.toUpperCase(),
|
CountryCode: loginRequest.lang.toUpperCase(),
|
||||||
ClientType: loginRequest.ClientType == "webui-register" ? "webui" : loginRequest.ClientType,
|
ClientType: loginRequest.ClientType,
|
||||||
CrossPlatformAllowed: true,
|
CrossPlatformAllowed: true,
|
||||||
ForceLogoutVersion: 0,
|
ForceLogoutVersion: 0,
|
||||||
ConsentNeeded: false,
|
ConsentNeeded: false,
|
||||||
@ -64,11 +59,6 @@ export const loginController: RequestHandler = async (request, response) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loginRequest.ClientType == "webui-register") {
|
|
||||||
response.status(400).json({ error: "account already exists" });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isCorrectPassword(loginRequest.password, account.password)) {
|
if (!isCorrectPassword(loginRequest.password, account.password)) {
|
||||||
response.status(400).json({ error: "incorrect login data" });
|
response.status(400).json({ error: "incorrect login data" });
|
||||||
return;
|
return;
|
||||||
@ -95,7 +85,7 @@ export const loginController: RequestHandler = async (request, response) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const createLoginResponse = (myAddress: string, account: IDatabaseAccountJson, buildLabel: string): ILoginResponse => {
|
const createLoginResponse = (myAddress: string, account: IDatabaseAccountJson, buildLabel: string): ILoginResponse => {
|
||||||
const resp: ILoginResponse = {
|
return {
|
||||||
id: account.id,
|
id: account.id,
|
||||||
DisplayName: account.DisplayName,
|
DisplayName: account.DisplayName,
|
||||||
CountryCode: account.CountryCode,
|
CountryCode: account.CountryCode,
|
||||||
@ -109,14 +99,11 @@ const createLoginResponse = (myAddress: string, account: IDatabaseAccountJson, b
|
|||||||
Nonce: account.Nonce,
|
Nonce: account.Nonce,
|
||||||
Groups: [],
|
Groups: [],
|
||||||
IRC: config.myIrcAddresses ?? [myAddress],
|
IRC: config.myIrcAddresses ?? [myAddress],
|
||||||
|
platformCDNs: [`https://${myAddress}/`],
|
||||||
HUB: `https://${myAddress}/api/`,
|
HUB: `https://${myAddress}/api/`,
|
||||||
NRS: config.NRS,
|
NRS: config.NRS,
|
||||||
DTLS: 99,
|
DTLS: 99,
|
||||||
BuildLabel: buildLabel,
|
BuildLabel: buildLabel,
|
||||||
MatchmakingBuildId: buildConfig.matchmakingBuildId
|
MatchmakingBuildId: buildConfig.matchmakingBuildId
|
||||||
};
|
};
|
||||||
if (version_compare(buildLabel, "2023.04.25.23.40") >= 0) {
|
|
||||||
resp.platformCDNs = [`https://${myAddress}/`];
|
|
||||||
}
|
|
||||||
return resp;
|
|
||||||
};
|
};
|
||||||
|
@ -3,10 +3,9 @@ import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IMissionInventoryUpdateRequest } from "@/src/types/requestTypes";
|
import { IMissionInventoryUpdateRequest } from "@/src/types/requestTypes";
|
||||||
import { addMissionInventoryUpdates, addMissionRewards } from "@/src/services/missionInventoryUpdateService";
|
import { addMissionInventoryUpdates, addMissionRewards } from "@/src/services/missionInventoryUpdateService";
|
||||||
import { generateRewardSeed, getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getInventoryResponse } from "./inventoryController";
|
import { getInventoryResponse } from "./inventoryController";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { IMissionInventoryUpdateResponse } from "@/src/types/missionTypes";
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
**** INPUT ****
|
**** INPUT ****
|
||||||
@ -54,16 +53,9 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
|
|||||||
logger.debug("mission report:", missionReport);
|
logger.debug("mission report:", missionReport);
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
const firstCompletion = missionReport.SortieId
|
|
||||||
? inventory.CompletedSorties.indexOf(missionReport.SortieId) == -1
|
|
||||||
: false;
|
|
||||||
const inventoryUpdates = await addMissionInventoryUpdates(inventory, missionReport);
|
const inventoryUpdates = await addMissionInventoryUpdates(inventory, missionReport);
|
||||||
|
|
||||||
if (
|
if (missionReport.MissionStatus !== "GS_SUCCESS") {
|
||||||
missionReport.MissionStatus !== "GS_SUCCESS" &&
|
|
||||||
!(missionReport.RewardInfo?.jobId || missionReport.RewardInfo?.challengeMissionId)
|
|
||||||
) {
|
|
||||||
inventory.RewardSeed = generateRewardSeed();
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
const inventoryResponse = await getInventoryResponse(inventory, true);
|
const inventoryResponse = await getInventoryResponse(inventory, true);
|
||||||
res.json({
|
res.json({
|
||||||
@ -73,16 +65,8 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const { MissionRewards, inventoryChanges, credits } = await addMissionRewards(inventory, missionReport);
|
||||||
MissionRewards,
|
|
||||||
inventoryChanges,
|
|
||||||
credits,
|
|
||||||
AffiliationMods,
|
|
||||||
SyndicateXPItemReward,
|
|
||||||
ConquestCompletedMissionsCount
|
|
||||||
} = await addMissionRewards(inventory, missionReport, firstCompletion);
|
|
||||||
|
|
||||||
inventory.RewardSeed = generateRewardSeed();
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
const inventoryResponse = await getInventoryResponse(inventory, true);
|
const inventoryResponse = await getInventoryResponse(inventory, true);
|
||||||
|
|
||||||
@ -93,11 +77,8 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
|
|||||||
MissionRewards,
|
MissionRewards,
|
||||||
...credits,
|
...credits,
|
||||||
...inventoryUpdates,
|
...inventoryUpdates,
|
||||||
//FusionPoints: inventoryChanges?.FusionPoints, // This in combination with InventoryJson or InventoryChanges seems to just double the number of endo shown, so unsure when this is needed.
|
FusionPoints: inventoryChanges?.FusionPoints
|
||||||
SyndicateXPItemReward,
|
});
|
||||||
AffiliationMods,
|
|
||||||
ConquestCompletedMissionsCount
|
|
||||||
} satisfies IMissionInventoryUpdateResponse);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -17,13 +17,12 @@ import { getDefaultUpgrades } from "@/src/services/itemDataService";
|
|||||||
import { modularWeaponTypes } from "@/src/helpers/modularWeaponHelper";
|
import { modularWeaponTypes } from "@/src/helpers/modularWeaponHelper";
|
||||||
import { IEquipmentDatabase } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IEquipmentDatabase } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { getRandomInt } from "@/src/services/rngService";
|
import { getRandomInt } from "@/src/services/rngService";
|
||||||
import { ExportSentinels, ExportWeapons, IDefaultUpgrade } from "warframe-public-export-plus";
|
import { ExportSentinels } from "warframe-public-export-plus";
|
||||||
import { Status } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { Status } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
|
||||||
interface IModularCraftRequest {
|
interface IModularCraftRequest {
|
||||||
WeaponType: string;
|
WeaponType: string;
|
||||||
Parts: string[];
|
Parts: string[];
|
||||||
isWebUi?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const modularWeaponCraftingController: RequestHandler = async (req, res) => {
|
export const modularWeaponCraftingController: RequestHandler = async (req, res) => {
|
||||||
@ -35,9 +34,9 @@ export const modularWeaponCraftingController: RequestHandler = async (req, res)
|
|||||||
const category = modularWeaponTypes[data.WeaponType];
|
const category = modularWeaponTypes[data.WeaponType];
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
|
|
||||||
let defaultUpgrades: IDefaultUpgrade[] | undefined;
|
const defaultUpgrades = getDefaultUpgrades(data.Parts);
|
||||||
const defaultOverwrites: Partial<IEquipmentDatabase> = {
|
const defaultOverwrites: Partial<IEquipmentDatabase> = {
|
||||||
ModularParts: data.Parts
|
Configs: applyDefaultUpgrades(inventory, defaultUpgrades)
|
||||||
};
|
};
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
if (category == "KubrowPets") {
|
if (category == "KubrowPets") {
|
||||||
@ -130,49 +129,25 @@ export const modularWeaponCraftingController: RequestHandler = async (req, res)
|
|||||||
// Only save mutagen & antigen in the ModularParts.
|
// Only save mutagen & antigen in the ModularParts.
|
||||||
defaultOverwrites.ModularParts = [data.Parts[1], data.Parts[2]];
|
defaultOverwrites.ModularParts = [data.Parts[1], data.Parts[2]];
|
||||||
|
|
||||||
const meta = ExportSentinels[data.WeaponType];
|
for (const specialItem of ExportSentinels[data.WeaponType].exalted!) {
|
||||||
|
|
||||||
for (const specialItem of meta.exalted!) {
|
|
||||||
addSpecialItem(inventory, specialItem, inventoryChanges);
|
addSpecialItem(inventory, specialItem, inventoryChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultUpgrades = meta.defaultUpgrades;
|
|
||||||
} else {
|
|
||||||
defaultUpgrades = getDefaultUpgrades(data.Parts);
|
|
||||||
}
|
}
|
||||||
|
addEquipment(inventory, category, data.WeaponType, data.Parts, inventoryChanges, defaultOverwrites);
|
||||||
if (category == "MoaPets") {
|
combineInventoryChanges(inventoryChanges, occupySlot(inventory, productCategoryToInventoryBin(category)!, false));
|
||||||
const weapon = ExportSentinels[data.WeaponType].defaultWeapon;
|
|
||||||
if (weapon) {
|
|
||||||
const category = ExportWeapons[weapon].productCategory;
|
|
||||||
addEquipment(inventory, category, weapon, undefined, inventoryChanges);
|
|
||||||
combineInventoryChanges(
|
|
||||||
inventoryChanges,
|
|
||||||
occupySlot(inventory, productCategoryToInventoryBin(category)!, !!data.isWebUi)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
defaultOverwrites.Configs = applyDefaultUpgrades(inventory, defaultUpgrades);
|
|
||||||
addEquipment(inventory, category, data.WeaponType, defaultOverwrites, inventoryChanges);
|
|
||||||
combineInventoryChanges(
|
|
||||||
inventoryChanges,
|
|
||||||
occupySlot(inventory, productCategoryToInventoryBin(category)!, !!data.isWebUi)
|
|
||||||
);
|
|
||||||
if (defaultUpgrades) {
|
if (defaultUpgrades) {
|
||||||
inventoryChanges.RawUpgrades = defaultUpgrades.map(x => ({ ItemType: x.ItemType, ItemCount: 1 }));
|
inventoryChanges.RawUpgrades = defaultUpgrades.map(x => ({ ItemType: x.ItemType, ItemCount: 1 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove credits & parts
|
// Remove credits & parts
|
||||||
const miscItemChanges = [];
|
const miscItemChanges = [];
|
||||||
let currencyChanges = {};
|
|
||||||
if (!data.isWebUi) {
|
|
||||||
for (const part of data.Parts) {
|
for (const part of data.Parts) {
|
||||||
miscItemChanges.push({
|
miscItemChanges.push({
|
||||||
ItemType: part,
|
ItemType: part,
|
||||||
ItemCount: -1
|
ItemCount: -1
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
currencyChanges = updateCurrency(
|
const currencyChanges = updateCurrency(
|
||||||
inventory,
|
inventory,
|
||||||
category == "Hoverboards" ||
|
category == "Hoverboards" ||
|
||||||
category == "MoaPets" ||
|
category == "MoaPets" ||
|
||||||
@ -184,9 +159,8 @@ export const modularWeaponCraftingController: RequestHandler = async (req, res)
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
addMiscItems(inventory, miscItemChanges);
|
addMiscItems(inventory, miscItemChanges);
|
||||||
}
|
|
||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
// Tell client what we did
|
// Tell client what we did
|
||||||
res.json({
|
res.json({
|
||||||
InventoryChanges: {
|
InventoryChanges: {
|
||||||
|
@ -21,11 +21,7 @@ import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
|||||||
export const modularWeaponSaleController: RequestHandler = async (req, res) => {
|
export const modularWeaponSaleController: RequestHandler = async (req, res) => {
|
||||||
const partTypeToParts: Record<string, string[]> = {};
|
const partTypeToParts: Record<string, string[]> = {};
|
||||||
for (const [uniqueName, data] of Object.entries(ExportWeapons)) {
|
for (const [uniqueName, data] of Object.entries(ExportWeapons)) {
|
||||||
if (
|
if (data.partType && data.premiumPrice) {
|
||||||
data.partType &&
|
|
||||||
data.premiumPrice &&
|
|
||||||
!data.excludeFromCodex // exclude pvp variants
|
|
||||||
) {
|
|
||||||
partTypeToParts[data.partType] ??= [];
|
partTypeToParts[data.partType] ??= [];
|
||||||
partTypeToParts[data.partType].push(uniqueName);
|
partTypeToParts[data.partType].push(uniqueName);
|
||||||
}
|
}
|
||||||
@ -45,18 +41,24 @@ export const modularWeaponSaleController: RequestHandler = async (req, res) => {
|
|||||||
const defaultUpgrades = getDefaultUpgrades(weaponInfo.ModularParts);
|
const defaultUpgrades = getDefaultUpgrades(weaponInfo.ModularParts);
|
||||||
const configs = applyDefaultUpgrades(inventory, defaultUpgrades);
|
const configs = applyDefaultUpgrades(inventory, defaultUpgrades);
|
||||||
const inventoryChanges: IInventoryChanges = {
|
const inventoryChanges: IInventoryChanges = {
|
||||||
...addEquipment(inventory, category, weaponInfo.ItemType, {
|
...addEquipment(
|
||||||
|
inventory,
|
||||||
|
category,
|
||||||
|
weaponInfo.ItemType,
|
||||||
|
weaponInfo.ModularParts,
|
||||||
|
{},
|
||||||
|
{
|
||||||
Features: EquipmentFeatures.DOUBLE_CAPACITY | EquipmentFeatures.GILDED,
|
Features: EquipmentFeatures.DOUBLE_CAPACITY | EquipmentFeatures.GILDED,
|
||||||
ItemName: payload.ItemName,
|
ItemName: payload.ItemName,
|
||||||
Configs: configs,
|
Configs: configs,
|
||||||
ModularParts: weaponInfo.ModularParts,
|
|
||||||
Polarity: [
|
Polarity: [
|
||||||
{
|
{
|
||||||
Slot: payload.PolarizeSlot,
|
Slot: payload.PolarizeSlot,
|
||||||
Value: payload.PolarizeValue
|
Value: payload.PolarizeValue
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}),
|
}
|
||||||
|
),
|
||||||
...occupySlot(inventory, productCategoryToInventoryBin(category)!, true),
|
...occupySlot(inventory, productCategoryToInventoryBin(category)!, true),
|
||||||
...updateCurrency(inventory, weaponInfo.PremiumPrice, true)
|
...updateCurrency(inventory, weaponInfo.PremiumPrice, true)
|
||||||
};
|
};
|
||||||
@ -141,7 +143,7 @@ const getModularWeaponSale = (
|
|||||||
getItemType: (parts: string[]) => string
|
getItemType: (parts: string[]) => string
|
||||||
): IModularWeaponSaleInfo => {
|
): IModularWeaponSaleInfo => {
|
||||||
const rng = new CRng(day);
|
const rng = new CRng(day);
|
||||||
const parts = partTypes.map(partType => rng.randomElement(partTypeToParts[partType])!);
|
const parts = partTypes.map(partType => rng.randomElement(partTypeToParts[partType]));
|
||||||
let partsCost = 0;
|
let partsCost = 0;
|
||||||
for (const part of parts) {
|
for (const part of parts) {
|
||||||
partsCost += ExportWeapons[part].premiumPrice!;
|
partsCost += ExportWeapons[part].premiumPrice!;
|
||||||
|
@ -1,31 +1,10 @@
|
|||||||
import {
|
import { getInfNodes, getNemesisPasscode } from "@/src/helpers/nemesisHelpers";
|
||||||
consumeModCharge,
|
|
||||||
encodeNemesisGuess,
|
|
||||||
getInfNodes,
|
|
||||||
getKnifeUpgrade,
|
|
||||||
getNemesisPasscode,
|
|
||||||
getNemesisPasscodeModTypes,
|
|
||||||
getWeaponsForManifest,
|
|
||||||
IKnifeResponse,
|
|
||||||
showdownNodes
|
|
||||||
} from "@/src/helpers/nemesisHelpers";
|
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
|
||||||
import { freeUpSlot, getInventory } from "@/src/services/inventoryService";
|
import { freeUpSlot, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { SRng } from "@/src/services/rngService";
|
import { SRng } from "@/src/services/rngService";
|
||||||
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IInnateDamageFingerprint, InventorySlot, TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import {
|
|
||||||
IInnateDamageFingerprint,
|
|
||||||
IInventoryClient,
|
|
||||||
INemesisClient,
|
|
||||||
InventorySlot,
|
|
||||||
IUpgradeClient,
|
|
||||||
IWeaponSkinClient,
|
|
||||||
LoadoutIndex,
|
|
||||||
TEquipmentKey
|
|
||||||
} from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
@ -70,7 +49,7 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
} else if ((req.query.mode as string) == "p") {
|
} else if ((req.query.mode as string) == "p") {
|
||||||
const inventory = await getInventory(accountId, "Nemesis");
|
const inventory = await getInventory(accountId, "Nemesis");
|
||||||
const body = getJSONfromString<INemesisPrespawnCheckRequest>(String(req.body));
|
const body = getJSONfromString<INemesisPrespawnCheckRequest>(String(req.body));
|
||||||
const passcode = getNemesisPasscode(inventory.Nemesis!);
|
const passcode = getNemesisPasscode(inventory.Nemesis!.fp, inventory.Nemesis!.Faction);
|
||||||
let guessResult = 0;
|
let guessResult = 0;
|
||||||
if (inventory.Nemesis!.Faction == "FC_INFESTATION") {
|
if (inventory.Nemesis!.Faction == "FC_INFESTATION") {
|
||||||
for (let i = 0; i != 3; ++i) {
|
for (let i = 0; i != 3; ++i) {
|
||||||
@ -87,83 +66,6 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
res.json({ GuessResult: guessResult });
|
res.json({ GuessResult: guessResult });
|
||||||
} else if (req.query.mode == "r") {
|
|
||||||
const inventory = await getInventory(
|
|
||||||
accountId,
|
|
||||||
"Nemesis LoadOutPresets CurrentLoadOutIds DataKnives Upgrades RawUpgrades"
|
|
||||||
);
|
|
||||||
const body = getJSONfromString<INemesisRequiemRequest>(String(req.body));
|
|
||||||
if (inventory.Nemesis!.Faction == "FC_INFESTATION") {
|
|
||||||
const guess: number[] = [body.guess & 0xf, (body.guess >> 4) & 0xf, (body.guess >> 8) & 0xf];
|
|
||||||
const passcode = getNemesisPasscode(inventory.Nemesis!)[0];
|
|
||||||
|
|
||||||
// Add to GuessHistory
|
|
||||||
const result1 = passcode == guess[0] ? 0 : 1;
|
|
||||||
const result2 = passcode == guess[1] ? 0 : 1;
|
|
||||||
const result3 = passcode == guess[2] ? 0 : 1;
|
|
||||||
inventory.Nemesis!.GuessHistory.push(
|
|
||||||
encodeNemesisGuess(guess[0], result1, guess[1], result2, guess[2], result3)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Increase antivirus if correct antivirus mod is installed
|
|
||||||
const response: IKnifeResponse = {};
|
|
||||||
if (result1 == 0 || result2 == 0 || result3 == 0) {
|
|
||||||
let antivirusGain = 5;
|
|
||||||
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!;
|
|
||||||
const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid);
|
|
||||||
const dataknifeConfigIndex = dataknifeLoadout?.s?.mod ?? 0;
|
|
||||||
const dataknifeUpgrades = inventory.DataKnives[0].Configs[dataknifeConfigIndex].Upgrades!;
|
|
||||||
for (const upgrade of body.knife!.AttachedUpgrades) {
|
|
||||||
switch (upgrade.ItemType) {
|
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndSpeedOnUseMod":
|
|
||||||
antivirusGain += 10;
|
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
|
||||||
break;
|
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndWeaponDamageOnUseMod":
|
|
||||||
antivirusGain += 10;
|
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
|
||||||
break;
|
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusLargeOnSingleUseMod": // Instant Secure
|
|
||||||
antivirusGain += 15;
|
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
|
||||||
break;
|
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusOnUseMod": // Immuno Shield
|
|
||||||
antivirusGain += 15;
|
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
|
||||||
break;
|
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusSmallOnSingleUseMod":
|
|
||||||
antivirusGain += 10;
|
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inventory.Nemesis!.HenchmenKilled += antivirusGain;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inventory.Nemesis!.HenchmenKilled >= 100) {
|
|
||||||
inventory.Nemesis!.HenchmenKilled = 100;
|
|
||||||
}
|
|
||||||
inventory.Nemesis!.InfNodes = getInfNodes("FC_INFESTATION", 0);
|
|
||||||
|
|
||||||
await inventory.save();
|
|
||||||
res.json(response);
|
|
||||||
} else {
|
|
||||||
const passcode = getNemesisPasscode(inventory.Nemesis!);
|
|
||||||
if (passcode[body.position] != body.guess) {
|
|
||||||
res.end();
|
|
||||||
} else {
|
|
||||||
inventory.Nemesis!.Rank += 1;
|
|
||||||
inventory.Nemesis!.InfNodes = getInfNodes(inventory.Nemesis!.Faction, inventory.Nemesis!.Rank);
|
|
||||||
await inventory.save();
|
|
||||||
res.json({ RankIncrease: 1 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ((req.query.mode as string) == "rs") {
|
|
||||||
// report spawn; POST but no application data in body
|
|
||||||
const inventory = await getInventory(accountId, "Nemesis");
|
|
||||||
inventory.Nemesis!.LastEnc = inventory.Nemesis!.MissionCount;
|
|
||||||
await inventory.save();
|
|
||||||
res.json({ LastEnc: inventory.Nemesis!.LastEnc });
|
|
||||||
} else if ((req.query.mode as string) == "s") {
|
} else if ((req.query.mode as string) == "s") {
|
||||||
const inventory = await getInventory(accountId, "Nemesis");
|
const inventory = await getInventory(accountId, "Nemesis");
|
||||||
const body = getJSONfromString<INemesisStartRequest>(String(req.body));
|
const body = getJSONfromString<INemesisStartRequest>(String(req.body));
|
||||||
@ -171,7 +73,18 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
|
|
||||||
let weaponIdx = -1;
|
let weaponIdx = -1;
|
||||||
if (body.target.Faction != "FC_INFESTATION") {
|
if (body.target.Faction != "FC_INFESTATION") {
|
||||||
const weapons = getWeaponsForManifest(body.target.manifest);
|
let weapons: readonly string[];
|
||||||
|
if (body.target.manifest == "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionSix") {
|
||||||
|
weapons = kuvaLichVersionSixWeapons;
|
||||||
|
} else if (
|
||||||
|
body.target.manifest == "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionFour" ||
|
||||||
|
body.target.manifest == "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionThree"
|
||||||
|
) {
|
||||||
|
weapons = corpusVersionThreeWeapons;
|
||||||
|
} else {
|
||||||
|
throw new Error(`unknown nemesis manifest: ${body.target.manifest}`);
|
||||||
|
}
|
||||||
|
|
||||||
const initialWeaponIdx = new SRng(body.target.fp).randomInt(0, weapons.length - 1);
|
const initialWeaponIdx = new SRng(body.target.fp).randomInt(0, weapons.length - 1);
|
||||||
weaponIdx = initialWeaponIdx;
|
weaponIdx = initialWeaponIdx;
|
||||||
do {
|
do {
|
||||||
@ -213,38 +126,6 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
res.json({
|
res.json({
|
||||||
target: inventory.toJSON().Nemesis
|
target: inventory.toJSON().Nemesis
|
||||||
});
|
});
|
||||||
} else if ((req.query.mode as string) == "w") {
|
|
||||||
const inventory = await getInventory(
|
|
||||||
accountId,
|
|
||||||
"Nemesis LoadOutPresets CurrentLoadOutIds DataKnives Upgrades RawUpgrades"
|
|
||||||
);
|
|
||||||
//const body = getJSONfromString<INemesisWeakenRequest>(String(req.body));
|
|
||||||
|
|
||||||
inventory.Nemesis!.InfNodes = [
|
|
||||||
{
|
|
||||||
Node: showdownNodes[inventory.Nemesis!.Faction],
|
|
||||||
Influence: 1
|
|
||||||
}
|
|
||||||
];
|
|
||||||
inventory.Nemesis!.Weakened = true;
|
|
||||||
|
|
||||||
const response: IKnifeResponse & { target: INemesisClient } = {
|
|
||||||
target: inventory.toJSON<IInventoryClient>().Nemesis!
|
|
||||||
};
|
|
||||||
|
|
||||||
// Consume charge of the correct requiem mod(s)
|
|
||||||
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!;
|
|
||||||
const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid);
|
|
||||||
const dataknifeConfigIndex = dataknifeLoadout?.s?.mod ?? 0;
|
|
||||||
const dataknifeUpgrades = inventory.DataKnives[0].Configs[dataknifeConfigIndex].Upgrades!;
|
|
||||||
const modTypes = getNemesisPasscodeModTypes(inventory.Nemesis!);
|
|
||||||
for (const modType of modTypes) {
|
|
||||||
const upgrade = getKnifeUpgrade(inventory, dataknifeUpgrades, modType);
|
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
|
||||||
}
|
|
||||||
|
|
||||||
await inventory.save();
|
|
||||||
res.json(response);
|
|
||||||
} else {
|
} else {
|
||||||
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
||||||
throw new Error(`unknown nemesis mode: ${String(req.query.mode)}`);
|
throw new Error(`unknown nemesis mode: ${String(req.query.mode)}`);
|
||||||
@ -292,23 +173,38 @@ interface INemesisPrespawnCheckRequest {
|
|||||||
potency?: number[];
|
potency?: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface INemesisRequiemRequest {
|
const kuvaLichVersionSixWeapons = [
|
||||||
guess: number; // grn/crp: 4 bits | coda: 3x 4 bits
|
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Drakgoon/KuvaDrakgoon",
|
||||||
position: number; // grn/crp: 0-2 | coda: 0
|
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Karak/KuvaKarak",
|
||||||
// knife field provided for coda only
|
"/Lotus/Weapons/Grineer/Melee/GrnKuvaLichScythe/GrnKuvaLichScytheWeapon",
|
||||||
knife?: IKnife;
|
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Kohm/KuvaKohm",
|
||||||
}
|
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Ogris/KuvaOgris",
|
||||||
|
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Quartakk/KuvaQuartakk",
|
||||||
|
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Tonkor/KuvaTonkor",
|
||||||
|
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Brakk/KuvaBrakk",
|
||||||
|
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Kraken/KuvaKraken",
|
||||||
|
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Seer/KuvaSeer",
|
||||||
|
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Stubba/KuvaStubba",
|
||||||
|
"/Lotus/Weapons/Grineer/HeavyWeapons/GrnHeavyGrenadeLauncher",
|
||||||
|
"/Lotus/Weapons/Grineer/LongGuns/GrnKuvaLichRifle/GrnKuvaLichRifleWeapon",
|
||||||
|
"/Lotus/Weapons/Grineer/Bows/GrnBow/GrnBowWeapon",
|
||||||
|
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hind/KuvaHind",
|
||||||
|
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Nukor/KuvaNukor",
|
||||||
|
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hek/KuvaHekWeapon",
|
||||||
|
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Zarr/KuvaZarr",
|
||||||
|
"/Lotus/Weapons/Grineer/KuvaLich/HeavyWeapons/Grattler/KuvaGrattler",
|
||||||
|
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Sobek/KuvaSobek"
|
||||||
|
];
|
||||||
|
|
||||||
// interface INemesisWeakenRequest {
|
const corpusVersionThreeWeapons = [
|
||||||
// target: INemesisClient;
|
"/Lotus/Weapons/Corpus/LongGuns/CrpBriefcaseLauncher/CrpBriefcaseLauncher",
|
||||||
// knife: IKnife;
|
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEArcaPlasmor/CrpBEArcaPlasmor",
|
||||||
// }
|
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEFluxRifle/CrpBEFluxRifle",
|
||||||
|
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBETetra/CrpBETetra",
|
||||||
interface IKnife {
|
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBECycron/CrpBECycron",
|
||||||
Item: IEquipmentClient;
|
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEDetron/CrpBEDetron",
|
||||||
Skins: IWeaponSkinClient[];
|
"/Lotus/Weapons/Corpus/Pistols/CrpIgniterPistol/CrpIgniterPistol",
|
||||||
ModSlot: number;
|
"/Lotus/Weapons/Corpus/Pistols/CrpBriefcaseAkimbo/CrpBriefcaseAkimboPistol",
|
||||||
CustSlot: number;
|
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEPlinx/CrpBEPlinxWeapon",
|
||||||
AttachedUpgrades: IUpgradeClient[];
|
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEGlaxion/CrpBEGlaxion"
|
||||||
HiddenWhenHolstered: boolean;
|
];
|
||||||
}
|
|
||||||
|
@ -13,7 +13,6 @@ import { GuildPermission } from "@/src/types/guildTypes";
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { ExportDojoRecipes, ExportResources } from "warframe-public-export-plus";
|
import { ExportDojoRecipes, ExportResources } from "warframe-public-export-plus";
|
||||||
import { config } from "@/src/services/configService";
|
|
||||||
|
|
||||||
export const placeDecoInComponentController: RequestHandler = async (req, res) => {
|
export const placeDecoInComponentController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -37,7 +36,6 @@ export const placeDecoInComponentController: RequestHandler = async (req, res) =
|
|||||||
const deco = component.Decos.find(x => x._id.equals(request.MoveId))!;
|
const deco = component.Decos.find(x => x._id.equals(request.MoveId))!;
|
||||||
deco.Pos = request.Pos;
|
deco.Pos = request.Pos;
|
||||||
deco.Rot = request.Rot;
|
deco.Rot = request.Rot;
|
||||||
deco.Scale = request.Scale;
|
|
||||||
} else {
|
} else {
|
||||||
const deco =
|
const deco =
|
||||||
component.Decos[
|
component.Decos[
|
||||||
@ -46,7 +44,6 @@ export const placeDecoInComponentController: RequestHandler = async (req, res) =
|
|||||||
Type: request.Type,
|
Type: request.Type,
|
||||||
Pos: request.Pos,
|
Pos: request.Pos,
|
||||||
Rot: request.Rot,
|
Rot: request.Rot,
|
||||||
Scale: request.Scale,
|
|
||||||
Name: request.Name,
|
Name: request.Name,
|
||||||
Sockets: request.Sockets
|
Sockets: request.Sockets
|
||||||
}) - 1
|
}) - 1
|
||||||
@ -65,13 +62,14 @@ export const placeDecoInComponentController: RequestHandler = async (req, res) =
|
|||||||
guild.VaultShipDecorations!.find(x => x.ItemType == itemType)!.ItemCount -= 1;
|
guild.VaultShipDecorations!.find(x => x.ItemType == itemType)!.ItemCount -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (deco.Type != "/Lotus/Objects/Tenno/Props/TnoPaintBotDojoDeco") {
|
if (!meta || (meta.price == 0 && meta.ingredients.length == 0)) {
|
||||||
if (!meta || (meta.price == 0 && meta.ingredients.length == 0) || config.noDojoDecoBuildStage) {
|
|
||||||
deco.CompletionTime = new Date();
|
deco.CompletionTime = new Date();
|
||||||
if (meta) {
|
} else if (
|
||||||
processDojoBuildMaterialsGathered(guild, meta);
|
guild.AutoContributeFromVault &&
|
||||||
}
|
guild.VaultRegularCredits &&
|
||||||
} else if (guild.AutoContributeFromVault && guild.VaultRegularCredits && guild.VaultMiscItems) {
|
guild.VaultMiscItems &&
|
||||||
|
deco.Type != "/Lotus/Objects/Tenno/Props/TnoPaintBotDojoDeco"
|
||||||
|
) {
|
||||||
if (guild.VaultRegularCredits >= scaleRequiredCount(guild.Tier, meta.price)) {
|
if (guild.VaultRegularCredits >= scaleRequiredCount(guild.Tier, meta.price)) {
|
||||||
let enoughMiscItems = true;
|
let enoughMiscItems = true;
|
||||||
for (const ingredient of meta.ingredients) {
|
for (const ingredient of meta.ingredients) {
|
||||||
@ -103,7 +101,6 @@ export const placeDecoInComponentController: RequestHandler = async (req, res) =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
await guild.save();
|
await guild.save();
|
||||||
res.json(await getDojoClient(guild, 0, component._id));
|
res.json(await getDojoClient(guild, 0, component._id));
|
||||||
@ -115,9 +112,9 @@ interface IPlaceDecoInComponentRequest {
|
|||||||
Type: string;
|
Type: string;
|
||||||
Pos: number[];
|
Pos: number[];
|
||||||
Rot: number[];
|
Rot: number[];
|
||||||
Scale?: number;
|
|
||||||
Name?: string;
|
Name?: string;
|
||||||
Sockets?: number;
|
Sockets?: number;
|
||||||
|
Scale?: number; // only provided alongside MoveId and seems to always be 1
|
||||||
MoveId?: string;
|
MoveId?: string;
|
||||||
ShipDeco?: boolean;
|
ShipDeco?: boolean;
|
||||||
VaultDeco?: boolean;
|
VaultDeco?: boolean;
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const playedParkourTutorialController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
await Inventory.updateOne({ accountOwnerId: accountId }, { PlayedParkourTutorial: true });
|
|
||||||
res.end();
|
|
||||||
};
|
|
@ -8,11 +8,7 @@ export const releasePetController: RequestHandler = async (req, res) => {
|
|||||||
const inventory = await getInventory(accountId, "RegularCredits KubrowPets");
|
const inventory = await getInventory(accountId, "RegularCredits KubrowPets");
|
||||||
const payload = getJSONfromString<IReleasePetRequest>(String(req.body));
|
const payload = getJSONfromString<IReleasePetRequest>(String(req.body));
|
||||||
|
|
||||||
const inventoryChanges = updateCurrency(
|
const inventoryChanges = updateCurrency(inventory, 25000, false);
|
||||||
inventory,
|
|
||||||
payload.recipeName == "/Lotus/Types/Game/KubrowPet/ReleasePetRecipe" ? 25000 : 0,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
inventoryChanges.RemovedIdItems = [{ ItemId: { $oid: payload.petId } }];
|
inventoryChanges.RemovedIdItems = [{ ItemId: { $oid: payload.petId } }];
|
||||||
inventory.KubrowPets.pull({ _id: payload.petId });
|
inventory.KubrowPets.pull({ _id: payload.petId });
|
||||||
@ -22,6 +18,6 @@ export const releasePetController: RequestHandler = async (req, res) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface IReleasePetRequest {
|
interface IReleasePetRequest {
|
||||||
recipeName: "/Lotus/Types/Game/KubrowPet/ReleasePetRecipe" | "webui";
|
recipeName: "/Lotus/Types/Game/KubrowPet/ReleasePetRecipe";
|
||||||
petId: string;
|
petId: string;
|
||||||
}
|
}
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { Account, Ignore } from "@/src/models/loginModel";
|
|
||||||
import { getAccountForRequest } from "@/src/services/loginService";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const removeIgnoredUserController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountForRequest(req);
|
|
||||||
const data = getJSONfromString<IRemoveIgnoredUserRequest>(String(req.body));
|
|
||||||
const ignoreeAccount = await Account.findOne(
|
|
||||||
{ DisplayName: data.playerName.substring(0, data.playerName.length - 1) },
|
|
||||||
"_id"
|
|
||||||
);
|
|
||||||
if (ignoreeAccount) {
|
|
||||||
await Ignore.deleteOne({ ignorer: accountId, ignoree: ignoreeAccount._id });
|
|
||||||
}
|
|
||||||
res.end();
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IRemoveIgnoredUserRequest {
|
|
||||||
playerName: string;
|
|
||||||
}
|
|
@ -1,29 +1,51 @@
|
|||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
import { addEmailItem, getInventory } from "@/src/services/inventoryService";
|
||||||
import { config } from "@/src/services/configService";
|
|
||||||
import { addEmailItem, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { ICompletedDialogue, IDialogueDatabase } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { ICompletedDialogue } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
|
import { logger } from "@/src/utils/logger";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const saveDialogueController: RequestHandler = async (req, res) => {
|
export const saveDialogueController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const request = JSON.parse(String(req.body)) as SaveDialogueRequest;
|
const request = JSON.parse(String(req.body)) as SaveDialogueRequest;
|
||||||
if ("YearIteration" in request) {
|
if ("YearIteration" in request) {
|
||||||
const inventory = await getInventory(accountId, "DialogueHistory");
|
const inventory = await getInventory(accountId);
|
||||||
inventory.DialogueHistory ??= {};
|
if (inventory.DialogueHistory) {
|
||||||
inventory.DialogueHistory.YearIteration = request.YearIteration;
|
inventory.DialogueHistory.YearIteration = request.YearIteration;
|
||||||
|
} else {
|
||||||
|
inventory.DialogueHistory = { YearIteration: request.YearIteration };
|
||||||
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.end();
|
res.end();
|
||||||
} else {
|
} else {
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
|
if (!inventory.DialogueHistory) {
|
||||||
|
throw new Error("bad inventory state");
|
||||||
|
}
|
||||||
|
if (request.OtherDialogueInfos.length != 0) {
|
||||||
|
logger.error(`saveDialogue request not fully handled: ${String(req.body)}`);
|
||||||
|
}
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
const tomorrowAt0Utc = config.noKimCooldowns
|
|
||||||
? Date.now()
|
|
||||||
: (Math.trunc(Date.now() / 86400_000) + 1) * 86400_000;
|
|
||||||
inventory.DialogueHistory ??= {};
|
|
||||||
inventory.DialogueHistory.Dialogues ??= [];
|
inventory.DialogueHistory.Dialogues ??= [];
|
||||||
const dialogue = getDialogue(inventory, request.DialogueName);
|
let dialogue = inventory.DialogueHistory.Dialogues.find(x => x.DialogueName == request.DialogueName);
|
||||||
|
if (!dialogue) {
|
||||||
|
dialogue =
|
||||||
|
inventory.DialogueHistory.Dialogues[
|
||||||
|
inventory.DialogueHistory.Dialogues.push({
|
||||||
|
Rank: 0,
|
||||||
|
Chemistry: 0,
|
||||||
|
AvailableDate: new Date(0),
|
||||||
|
AvailableGiftDate: new Date(0),
|
||||||
|
RankUpExpiry: new Date(0),
|
||||||
|
BountyChemExpiry: new Date(0),
|
||||||
|
QueuedDialogues: [],
|
||||||
|
Gifts: [],
|
||||||
|
Booleans: [],
|
||||||
|
Completed: [],
|
||||||
|
DialogueName: request.DialogueName
|
||||||
|
}) - 1
|
||||||
|
];
|
||||||
|
}
|
||||||
dialogue.Rank = request.Rank;
|
dialogue.Rank = request.Rank;
|
||||||
dialogue.Chemistry = request.Chemistry;
|
dialogue.Chemistry = request.Chemistry;
|
||||||
dialogue.QueuedDialogues = request.QueuedDialogues;
|
dialogue.QueuedDialogues = request.QueuedDialogues;
|
||||||
@ -43,38 +65,14 @@ export const saveDialogueController: RequestHandler = async (req, res) => {
|
|||||||
dialogue.Booleans.splice(index, 1);
|
dialogue.Booleans.splice(index, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const info of request.OtherDialogueInfos) {
|
|
||||||
const otherDialogue = getDialogue(inventory, info.Dialogue);
|
|
||||||
if (info.Tag != "") {
|
|
||||||
otherDialogue.QueuedDialogues.push(info.Tag);
|
|
||||||
}
|
|
||||||
otherDialogue.Chemistry += info.Value; // unsure
|
|
||||||
}
|
|
||||||
if (request.Data) {
|
|
||||||
dialogue.Completed.push(request.Data);
|
dialogue.Completed.push(request.Data);
|
||||||
|
const tomorrowAt0Utc = (Math.trunc(Date.now() / (86400 * 1000)) + 1) * 86400 * 1000;
|
||||||
dialogue.AvailableDate = new Date(tomorrowAt0Utc);
|
dialogue.AvailableDate = new Date(tomorrowAt0Utc);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
InventoryChanges: inventoryChanges,
|
InventoryChanges: inventoryChanges,
|
||||||
AvailableDate: { $date: { $numberLong: tomorrowAt0Utc.toString() } }
|
AvailableDate: { $date: { $numberLong: tomorrowAt0Utc.toString() } }
|
||||||
});
|
});
|
||||||
} else if (request.Gift) {
|
|
||||||
const inventoryChanges = updateCurrency(inventory, request.Gift.Cost, false);
|
|
||||||
const gift = dialogue.Gifts.find(x => x.Item == request.Gift!.Item);
|
|
||||||
if (gift) {
|
|
||||||
gift.GiftedQuantity += 1;
|
|
||||||
} else {
|
|
||||||
dialogue.Gifts.push({ Item: request.Gift.Item, GiftedQuantity: 1 });
|
|
||||||
}
|
|
||||||
dialogue.AvailableGiftDate = new Date(tomorrowAt0Utc);
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: inventoryChanges,
|
|
||||||
AvailableGiftDate: { $date: { $numberLong: tomorrowAt0Utc.toString() } }
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
res.end();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -90,16 +88,10 @@ interface SaveCompletedDialogueRequest {
|
|||||||
Chemistry: number;
|
Chemistry: number;
|
||||||
CompletionType: number;
|
CompletionType: number;
|
||||||
QueuedDialogues: string[];
|
QueuedDialogues: string[];
|
||||||
Gift?: {
|
|
||||||
Item: string;
|
|
||||||
GainedChemistry: number;
|
|
||||||
Cost: number;
|
|
||||||
GiftedQuantity: number;
|
|
||||||
};
|
|
||||||
Booleans: string[];
|
Booleans: string[];
|
||||||
ResetBooleans: string[];
|
ResetBooleans: string[];
|
||||||
Data?: ICompletedDialogue;
|
Data: ICompletedDialogue;
|
||||||
OtherDialogueInfos: IOtherDialogueInfo[];
|
OtherDialogueInfos: IOtherDialogueInfo[]; // unsure
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IOtherDialogueInfo {
|
interface IOtherDialogueInfo {
|
||||||
@ -107,26 +99,3 @@ interface IOtherDialogueInfo {
|
|||||||
Tag: string;
|
Tag: string;
|
||||||
Value: number;
|
Value: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDialogue = (inventory: TInventoryDatabaseDocument, dialogueName: string): IDialogueDatabase => {
|
|
||||||
let dialogue = inventory.DialogueHistory!.Dialogues!.find(x => x.DialogueName == dialogueName);
|
|
||||||
if (!dialogue) {
|
|
||||||
dialogue =
|
|
||||||
inventory.DialogueHistory!.Dialogues![
|
|
||||||
inventory.DialogueHistory!.Dialogues!.push({
|
|
||||||
Rank: 0,
|
|
||||||
Chemistry: 0,
|
|
||||||
AvailableDate: new Date(0),
|
|
||||||
AvailableGiftDate: new Date(0),
|
|
||||||
RankUpExpiry: new Date(0),
|
|
||||||
BountyChemExpiry: new Date(0),
|
|
||||||
QueuedDialogues: [],
|
|
||||||
Gifts: [],
|
|
||||||
Booleans: [],
|
|
||||||
Completed: [],
|
|
||||||
DialogueName: dialogueName
|
|
||||||
}) - 1
|
|
||||||
];
|
|
||||||
}
|
|
||||||
return dialogue;
|
|
||||||
};
|
|
||||||
|
32
src/controllers/api/saveLoadout.ts
Normal file
32
src/controllers/api/saveLoadout.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { ISaveLoadoutRequest } from "@/src/types/saveLoadoutTypes";
|
||||||
|
import { handleInventoryItemConfigChange } from "@/src/services/saveLoadoutService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { logger } from "@/src/utils/logger";
|
||||||
|
|
||||||
|
export const saveLoadoutController: RequestHandler = async (req, res) => {
|
||||||
|
//validate here
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const body: ISaveLoadoutRequest = JSON.parse(req.body as string) as ISaveLoadoutRequest;
|
||||||
|
// console.log(util.inspect(body, { showHidden: false, depth: null, colors: true }));
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const { UpgradeVer, ...equipmentChanges } = body;
|
||||||
|
const newLoadoutId = await handleInventoryItemConfigChange(equipmentChanges, accountId);
|
||||||
|
|
||||||
|
//send back new loadout id, if new loadout was added
|
||||||
|
if (newLoadoutId) {
|
||||||
|
res.send(newLoadoutId);
|
||||||
|
}
|
||||||
|
res.status(200).end();
|
||||||
|
} catch (error: unknown) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
logger.error(`error in saveLoadoutController: ${error.message}`);
|
||||||
|
res.status(400).json({ error: error.message });
|
||||||
|
} else {
|
||||||
|
res.status(400).json({ error: "unknown error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -1,21 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { ISaveLoadoutRequest } from "@/src/types/saveLoadoutTypes";
|
|
||||||
import { handleInventoryItemConfigChange } from "@/src/services/saveLoadoutService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
|
|
||||||
export const saveLoadoutController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
|
|
||||||
const body: ISaveLoadoutRequest = JSON.parse(req.body as string) as ISaveLoadoutRequest;
|
|
||||||
// console.log(util.inspect(body, { showHidden: false, depth: null, colors: true }));
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
const { UpgradeVer, ...equipmentChanges } = body;
|
|
||||||
const newLoadoutId = await handleInventoryItemConfigChange(equipmentChanges, accountId);
|
|
||||||
|
|
||||||
//send back new loadout id, if new loadout was added
|
|
||||||
if (newLoadoutId) {
|
|
||||||
res.send(newLoadoutId);
|
|
||||||
}
|
|
||||||
res.end();
|
|
||||||
};
|
|
@ -6,20 +6,14 @@ import {
|
|||||||
addRecipes,
|
addRecipes,
|
||||||
addMiscItems,
|
addMiscItems,
|
||||||
addConsumables,
|
addConsumables,
|
||||||
freeUpSlot,
|
freeUpSlot
|
||||||
combineInventoryChanges,
|
|
||||||
addCrewShipRawSalvage,
|
|
||||||
addFusionPoints
|
|
||||||
} from "@/src/services/inventoryService";
|
} from "@/src/services/inventoryService";
|
||||||
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
|
||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
|
||||||
|
|
||||||
export const sellController: RequestHandler = async (req, res) => {
|
export const sellController: RequestHandler = async (req, res) => {
|
||||||
const payload = JSON.parse(String(req.body)) as ISellRequest;
|
const payload = JSON.parse(String(req.body)) as ISellRequest;
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const requiredFields = new Set<keyof TInventoryDatabaseDocument>();
|
const requiredFields = new Set();
|
||||||
if (payload.SellCurrency == "SC_RegularCredits") {
|
if (payload.SellCurrency == "SC_RegularCredits") {
|
||||||
requiredFields.add("RegularCredits");
|
requiredFields.add("RegularCredits");
|
||||||
} else if (payload.SellCurrency == "SC_FusionPoints") {
|
} else if (payload.SellCurrency == "SC_FusionPoints") {
|
||||||
@ -28,7 +22,7 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
requiredFields.add("MiscItems");
|
requiredFields.add("MiscItems");
|
||||||
}
|
}
|
||||||
for (const key of Object.keys(payload.Items)) {
|
for (const key of Object.keys(payload.Items)) {
|
||||||
requiredFields.add(key as keyof TInventoryDatabaseDocument);
|
requiredFields.add(key);
|
||||||
}
|
}
|
||||||
if (requiredFields.has("Upgrades")) {
|
if (requiredFields.has("Upgrades")) {
|
||||||
requiredFields.add("RawUpgrades");
|
requiredFields.add("RawUpgrades");
|
||||||
@ -45,7 +39,7 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
if (payload.Items.SpaceGuns || payload.Items.SpaceMelee) {
|
if (payload.Items.SpaceGuns || payload.Items.SpaceMelee) {
|
||||||
requiredFields.add(InventorySlot.SPACEWEAPONS);
|
requiredFields.add(InventorySlot.SPACEWEAPONS);
|
||||||
}
|
}
|
||||||
if (payload.Items.Sentinels || payload.Items.SentinelWeapons || payload.Items.MoaPets) {
|
if (payload.Items.Sentinels || payload.Items.SentinelWeapons) {
|
||||||
requiredFields.add(InventorySlot.SENTINELS);
|
requiredFields.add(InventorySlot.SENTINELS);
|
||||||
}
|
}
|
||||||
if (payload.Items.OperatorAmps) {
|
if (payload.Items.OperatorAmps) {
|
||||||
@ -54,23 +48,13 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
if (payload.Items.Hoverboards) {
|
if (payload.Items.Hoverboards) {
|
||||||
requiredFields.add(InventorySlot.SPACESUITS);
|
requiredFields.add(InventorySlot.SPACESUITS);
|
||||||
}
|
}
|
||||||
if (payload.Items.CrewShipWeapons || payload.Items.CrewShipWeaponSkins) {
|
|
||||||
requiredFields.add(InventorySlot.RJ_COMPONENT_AND_ARMAMENTS);
|
|
||||||
requiredFields.add("CrewShipRawSalvage");
|
|
||||||
if (payload.Items.CrewShipWeapons) {
|
|
||||||
requiredFields.add("CrewShipSalvagedWeapons");
|
|
||||||
}
|
|
||||||
if (payload.Items.CrewShipWeaponSkins) {
|
|
||||||
requiredFields.add("CrewShipSalvagedWeaponSkins");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const inventory = await getInventory(accountId, Array.from(requiredFields).join(" "));
|
const inventory = await getInventory(accountId, Array.from(requiredFields).join(" "));
|
||||||
|
|
||||||
// Give currency
|
// Give currency
|
||||||
if (payload.SellCurrency == "SC_RegularCredits") {
|
if (payload.SellCurrency == "SC_RegularCredits") {
|
||||||
inventory.RegularCredits += payload.SellPrice;
|
inventory.RegularCredits += payload.SellPrice;
|
||||||
} else if (payload.SellCurrency == "SC_FusionPoints") {
|
} else if (payload.SellCurrency == "SC_FusionPoints") {
|
||||||
addFusionPoints(inventory, payload.SellPrice);
|
inventory.FusionPoints += payload.SellPrice;
|
||||||
} else if (payload.SellCurrency == "SC_PrimeBucks") {
|
} else if (payload.SellCurrency == "SC_PrimeBucks") {
|
||||||
addMiscItems(inventory, [
|
addMiscItems(inventory, [
|
||||||
{
|
{
|
||||||
@ -85,14 +69,10 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
ItemCount: payload.SellPrice
|
ItemCount: payload.SellPrice
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
} else if (payload.SellCurrency == "SC_Resources") {
|
|
||||||
// Will add appropriate MiscItems from CrewShipWeapons or CrewShipWeaponSkins
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Unknown SellCurrency: " + payload.SellCurrency);
|
throw new Error("Unknown SellCurrency: " + payload.SellCurrency);
|
||||||
}
|
}
|
||||||
|
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
|
||||||
|
|
||||||
// Remove item(s)
|
// Remove item(s)
|
||||||
if (payload.Items.Suits) {
|
if (payload.Items.Suits) {
|
||||||
payload.Items.Suits.forEach(sellItem => {
|
payload.Items.Suits.forEach(sellItem => {
|
||||||
@ -148,12 +128,6 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
freeUpSlot(inventory, InventorySlot.SENTINELS);
|
freeUpSlot(inventory, InventorySlot.SENTINELS);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (payload.Items.MoaPets) {
|
|
||||||
payload.Items.MoaPets.forEach(sellItem => {
|
|
||||||
inventory.MoaPets.pull({ _id: sellItem.String });
|
|
||||||
freeUpSlot(inventory, InventorySlot.SENTINELS);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (payload.Items.OperatorAmps) {
|
if (payload.Items.OperatorAmps) {
|
||||||
payload.Items.OperatorAmps.forEach(sellItem => {
|
payload.Items.OperatorAmps.forEach(sellItem => {
|
||||||
inventory.OperatorAmps.pull({ _id: sellItem.String });
|
inventory.OperatorAmps.pull({ _id: sellItem.String });
|
||||||
@ -171,56 +145,6 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
inventory.Drones.pull({ _id: sellItem.String });
|
inventory.Drones.pull({ _id: sellItem.String });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (payload.Items.CrewShipWeapons) {
|
|
||||||
payload.Items.CrewShipWeapons.forEach(sellItem => {
|
|
||||||
if (sellItem.String[0] == "/") {
|
|
||||||
addCrewShipRawSalvage(inventory, [
|
|
||||||
{
|
|
||||||
ItemType: sellItem.String,
|
|
||||||
ItemCount: sellItem.Count * -1
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
const index = inventory.CrewShipWeapons.findIndex(x => x._id.equals(sellItem.String));
|
|
||||||
if (index != -1) {
|
|
||||||
if (payload.SellCurrency == "SC_Resources") {
|
|
||||||
refundPartialBuildCosts(inventory, inventory.CrewShipWeapons[index].ItemType, inventoryChanges);
|
|
||||||
}
|
|
||||||
inventory.CrewShipWeapons.splice(index, 1);
|
|
||||||
freeUpSlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS);
|
|
||||||
} else {
|
|
||||||
inventory.CrewShipSalvagedWeapons.pull({ _id: sellItem.String });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (payload.Items.CrewShipWeaponSkins) {
|
|
||||||
payload.Items.CrewShipWeaponSkins.forEach(sellItem => {
|
|
||||||
if (sellItem.String[0] == "/") {
|
|
||||||
addCrewShipRawSalvage(inventory, [
|
|
||||||
{
|
|
||||||
ItemType: sellItem.String,
|
|
||||||
ItemCount: sellItem.Count * -1
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
const index = inventory.CrewShipWeaponSkins.findIndex(x => x._id.equals(sellItem.String));
|
|
||||||
if (index != -1) {
|
|
||||||
if (payload.SellCurrency == "SC_Resources") {
|
|
||||||
refundPartialBuildCosts(
|
|
||||||
inventory,
|
|
||||||
inventory.CrewShipWeaponSkins[index].ItemType,
|
|
||||||
inventoryChanges
|
|
||||||
);
|
|
||||||
}
|
|
||||||
inventory.CrewShipWeaponSkins.splice(index, 1);
|
|
||||||
freeUpSlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS);
|
|
||||||
} else {
|
|
||||||
inventory.CrewShipSalvagedWeaponSkins.pull({ _id: sellItem.String });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (payload.Items.Consumables) {
|
if (payload.Items.Consumables) {
|
||||||
const consumablesChanges = [];
|
const consumablesChanges = [];
|
||||||
for (const sellItem of payload.Items.Consumables) {
|
for (const sellItem of payload.Items.Consumables) {
|
||||||
@ -267,9 +191,7 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({});
|
||||||
inventoryChanges: inventoryChanges // "inventoryChanges" for this response instead of the usual "InventoryChanges"
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ISellRequest {
|
interface ISellRequest {
|
||||||
@ -287,12 +209,9 @@ interface ISellRequest {
|
|||||||
SpaceMelee?: ISellItem[];
|
SpaceMelee?: ISellItem[];
|
||||||
Sentinels?: ISellItem[];
|
Sentinels?: ISellItem[];
|
||||||
SentinelWeapons?: ISellItem[];
|
SentinelWeapons?: ISellItem[];
|
||||||
MoaPets?: ISellItem[];
|
|
||||||
OperatorAmps?: ISellItem[];
|
OperatorAmps?: ISellItem[];
|
||||||
Hoverboards?: ISellItem[];
|
Hoverboards?: ISellItem[];
|
||||||
Drones?: ISellItem[];
|
Drones?: ISellItem[];
|
||||||
CrewShipWeapons?: ISellItem[];
|
|
||||||
CrewShipWeaponSkins?: ISellItem[];
|
|
||||||
};
|
};
|
||||||
SellPrice: number;
|
SellPrice: number;
|
||||||
SellCurrency:
|
SellCurrency:
|
||||||
@ -309,33 +228,3 @@ interface ISellItem {
|
|||||||
String: string; // oid or uniqueName
|
String: string; // oid or uniqueName
|
||||||
Count: number;
|
Count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const refundPartialBuildCosts = (
|
|
||||||
inventory: TInventoryDatabaseDocument,
|
|
||||||
itemType: string,
|
|
||||||
inventoryChanges: IInventoryChanges
|
|
||||||
): void => {
|
|
||||||
// House versions
|
|
||||||
const research = Object.values(ExportDojoRecipes.research).find(x => x.resultType == itemType);
|
|
||||||
if (research) {
|
|
||||||
const miscItemChanges = research.ingredients.map(x => ({
|
|
||||||
ItemType: x.ItemType,
|
|
||||||
ItemCount: Math.trunc(x.ItemCount * 0.8)
|
|
||||||
}));
|
|
||||||
addMiscItems(inventory, miscItemChanges);
|
|
||||||
combineInventoryChanges(inventoryChanges, { MiscItems: miscItemChanges });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sigma versions
|
|
||||||
const recipe = Object.values(ExportDojoRecipes.fabrications).find(x => x.resultType == itemType);
|
|
||||||
if (recipe) {
|
|
||||||
const miscItemChanges = recipe.ingredients.map(x => ({
|
|
||||||
ItemType: x.ItemType,
|
|
||||||
ItemCount: Math.trunc(x.ItemCount * 0.8)
|
|
||||||
}));
|
|
||||||
addMiscItems(inventory, miscItemChanges);
|
|
||||||
combineInventoryChanges(inventoryChanges, { MiscItems: miscItemChanges });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { createMessage } from "@/src/services/inboxService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const sendMsgToInBoxController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const data = getJSONfromString<ISendMsgToInBoxRequest>(String(req.body));
|
|
||||||
await createMessage(accountId, [
|
|
||||||
{
|
|
||||||
sub: data.title,
|
|
||||||
msg: data.message,
|
|
||||||
sndr: data.sender ?? "/Lotus/Language/Bosses/Ordis",
|
|
||||||
icon: data.senderIcon,
|
|
||||||
highPriority: data.highPriority,
|
|
||||||
transmission: data.transmission,
|
|
||||||
att: data.attachments
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
res.end();
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ISendMsgToInBoxRequest {
|
|
||||||
title: string;
|
|
||||||
message: string;
|
|
||||||
sender?: string;
|
|
||||||
senderIcon?: string;
|
|
||||||
highPriority?: boolean;
|
|
||||||
transmission?: string;
|
|
||||||
attachments?: string[];
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { IHubNpcCustomization } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const setHubNpcCustomizationsController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId, "HubNpcCustomizations");
|
|
||||||
const upload = getJSONfromString<IHubNpcCustomization>(String(req.body));
|
|
||||||
inventory.HubNpcCustomizations ??= [];
|
|
||||||
const cust = inventory.HubNpcCustomizations.find(x => x.Tag == upload.Tag);
|
|
||||||
if (cust) {
|
|
||||||
cust.Colors = upload.Colors;
|
|
||||||
cust.Pattern = upload.Pattern;
|
|
||||||
} else {
|
|
||||||
inventory.HubNpcCustomizations.push(upload);
|
|
||||||
}
|
|
||||||
await inventory.save();
|
|
||||||
res.end();
|
|
||||||
};
|
|
@ -1,5 +1,5 @@
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IPictureFrameInfo, ISetPlacedDecoInfoRequest } from "@/src/types/shipTypes";
|
import { ISetPlacedDecoInfoRequest } from "@/src/types/shipTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { handleSetPlacedDecoInfo } from "@/src/services/shipCustomizationsService";
|
import { handleSetPlacedDecoInfo } from "@/src/services/shipCustomizationsService";
|
||||||
|
|
||||||
@ -7,17 +7,5 @@ export const setPlacedDecoInfoController: RequestHandler = async (req, res) => {
|
|||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const payload = JSON.parse(req.body as string) as ISetPlacedDecoInfoRequest;
|
const payload = JSON.parse(req.body as string) as ISetPlacedDecoInfoRequest;
|
||||||
await handleSetPlacedDecoInfo(accountId, payload);
|
await handleSetPlacedDecoInfo(accountId, payload);
|
||||||
res.json({
|
res.end();
|
||||||
DecoId: payload.DecoId,
|
|
||||||
IsPicture: true,
|
|
||||||
PictureFrameInfo: payload.PictureFrameInfo,
|
|
||||||
BootLocation: payload.BootLocation
|
|
||||||
} satisfies ISetPlacedDecoInfoResponse);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ISetPlacedDecoInfoResponse {
|
|
||||||
DecoId: string;
|
|
||||||
IsPicture: boolean;
|
|
||||||
PictureFrameInfo?: IPictureFrameInfo;
|
|
||||||
BootLocation?: string;
|
|
||||||
}
|
|
||||||
|
@ -3,40 +3,29 @@ import { RequestHandler } from "express";
|
|||||||
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
||||||
import { IOid } from "@/src/types/commonTypes";
|
import { IOid } from "@/src/types/commonTypes";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { IFavouriteLoadoutDatabase, TBootLocation } from "@/src/types/shipTypes";
|
|
||||||
|
|
||||||
export const setShipFavouriteLoadoutController: RequestHandler = async (req, res) => {
|
export const setShipFavouriteLoadoutController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const personalRooms = await getPersonalRooms(accountId);
|
const personalRooms = await getPersonalRooms(accountId);
|
||||||
const body = JSON.parse(String(req.body)) as ISetShipFavouriteLoadoutRequest;
|
const body = JSON.parse(String(req.body)) as ISetShipFavouriteLoadoutRequest;
|
||||||
if (body.BootLocation == "LISET") {
|
if (body.BootLocation != "SHOP") {
|
||||||
personalRooms.Ship.FavouriteLoadoutId = new Types.ObjectId(body.FavouriteLoadoutId.$oid);
|
|
||||||
} else if (body.BootLocation == "APARTMENT") {
|
|
||||||
updateTaggedDisplay(personalRooms.Apartment.FavouriteLoadouts, body);
|
|
||||||
} else if (body.BootLocation == "SHOP") {
|
|
||||||
updateTaggedDisplay(personalRooms.TailorShop.FavouriteLoadouts, body);
|
|
||||||
} else {
|
|
||||||
console.log(body);
|
|
||||||
throw new Error(`unexpected BootLocation: ${body.BootLocation}`);
|
throw new Error(`unexpected BootLocation: ${body.BootLocation}`);
|
||||||
}
|
}
|
||||||
await personalRooms.save();
|
const display = personalRooms.TailorShop.FavouriteLoadouts.find(x => x.Tag == body.TagName);
|
||||||
res.json(body);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ISetShipFavouriteLoadoutRequest {
|
|
||||||
BootLocation: TBootLocation;
|
|
||||||
FavouriteLoadoutId: IOid;
|
|
||||||
TagName?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateTaggedDisplay = (arr: IFavouriteLoadoutDatabase[], body: ISetShipFavouriteLoadoutRequest): void => {
|
|
||||||
const display = arr.find(x => x.Tag == body.TagName!);
|
|
||||||
if (display) {
|
if (display) {
|
||||||
display.LoadoutId = new Types.ObjectId(body.FavouriteLoadoutId.$oid);
|
display.LoadoutId = new Types.ObjectId(body.FavouriteLoadoutId.$oid);
|
||||||
} else {
|
} else {
|
||||||
arr.push({
|
personalRooms.TailorShop.FavouriteLoadouts.push({
|
||||||
Tag: body.TagName!,
|
Tag: body.TagName,
|
||||||
LoadoutId: new Types.ObjectId(body.FavouriteLoadoutId.$oid)
|
LoadoutId: new Types.ObjectId(body.FavouriteLoadoutId.$oid)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
await personalRooms.save();
|
||||||
|
res.json({});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface ISetShipFavouriteLoadoutRequest {
|
||||||
|
BootLocation: string;
|
||||||
|
FavouriteLoadoutId: IOid;
|
||||||
|
TagName: string;
|
||||||
|
}
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
import { addMiscItems, combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
|
||||||
import { logger } from "@/src/utils/logger";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const setShipVignetteController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId, "MiscItems");
|
|
||||||
const personalRooms = await getPersonalRooms(accountId);
|
|
||||||
const body = JSON.parse(String(req.body)) as ISetShipVignetteRequest;
|
|
||||||
personalRooms.Ship.Wallpaper = body.Wallpaper;
|
|
||||||
personalRooms.Ship.Vignette = body.Vignette;
|
|
||||||
personalRooms.Ship.VignetteFish ??= [];
|
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
|
||||||
for (let i = 0; i != body.Fish.length; ++i) {
|
|
||||||
if (body.Fish[i] && !personalRooms.Ship.VignetteFish[i]) {
|
|
||||||
logger.debug(`moving ${body.Fish[i]} from inventory to vignette slot ${i}`);
|
|
||||||
const miscItemsDelta = [{ ItemType: body.Fish[i], ItemCount: -1 }];
|
|
||||||
addMiscItems(inventory, miscItemsDelta);
|
|
||||||
combineInventoryChanges(inventoryChanges, { MiscItems: miscItemsDelta });
|
|
||||||
} else if (personalRooms.Ship.VignetteFish[i] && !body.Fish[i]) {
|
|
||||||
logger.debug(`moving ${personalRooms.Ship.VignetteFish[i]} from vignette slot ${i} to inventory`);
|
|
||||||
const miscItemsDelta = [{ ItemType: personalRooms.Ship.VignetteFish[i], ItemCount: +1 }];
|
|
||||||
addMiscItems(inventory, miscItemsDelta);
|
|
||||||
combineInventoryChanges(inventoryChanges, { MiscItems: miscItemsDelta });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
personalRooms.Ship.VignetteFish = body.Fish;
|
|
||||||
if (body.VignetteDecos.length) {
|
|
||||||
logger.error(`setShipVignette request not fully handled:`, body);
|
|
||||||
}
|
|
||||||
await Promise.all([inventory.save(), personalRooms.save()]);
|
|
||||||
res.json({
|
|
||||||
Wallpaper: body.Wallpaper,
|
|
||||||
Vignette: body.Vignette,
|
|
||||||
VignetteFish: body.Fish,
|
|
||||||
InventoryChanges: inventoryChanges
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ISetShipVignetteRequest {
|
|
||||||
Wallpaper: string;
|
|
||||||
Vignette: string;
|
|
||||||
Fish: string[];
|
|
||||||
VignetteDecos: unknown[];
|
|
||||||
}
|
|
@ -3,12 +3,15 @@ import { RequestHandler } from "express";
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { ExportNightwave, ExportSyndicates, ISyndicateSacrifice } from "warframe-public-export-plus";
|
import { ExportNightwave, ExportSyndicates, ISyndicateSacrifice } from "warframe-public-export-plus";
|
||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
||||||
import { addMiscItems, combineInventoryChanges, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
import {
|
||||||
|
addItem,
|
||||||
|
addMiscItems,
|
||||||
|
combineInventoryChanges,
|
||||||
|
getInventory,
|
||||||
|
updateCurrency
|
||||||
|
} from "@/src/services/inventoryService";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { isStoreItem, toStoreItem } from "@/src/services/itemDataService";
|
import { fromStoreItem, isStoreItem } from "@/src/services/itemDataService";
|
||||||
import { logger } from "@/src/utils/logger";
|
|
||||||
|
|
||||||
const nightwaveCredsItemType = ExportNightwave.rewards[ExportNightwave.rewards.length - 1].uniqueName;
|
|
||||||
|
|
||||||
export const syndicateSacrificeController: RequestHandler = async (request, response) => {
|
export const syndicateSacrificeController: RequestHandler = async (request, response) => {
|
||||||
const accountId = await getAccountIdForRequest(request);
|
const accountId = await getAccountIdForRequest(request);
|
||||||
@ -54,7 +57,7 @@ export const syndicateSacrificeController: RequestHandler = async (request, resp
|
|||||||
syndicate.Title ??= 0;
|
syndicate.Title ??= 0;
|
||||||
syndicate.Title += 1;
|
syndicate.Title += 1;
|
||||||
|
|
||||||
if (syndicate.Title > 0 && manifest.favours.find(x => x.rankUpReward && x.requiredLevel == syndicate.Title)) {
|
if (syndicate.Title > 0 && manifest.favours.length != 0) {
|
||||||
syndicate.FreeFavorsEarned ??= [];
|
syndicate.FreeFavorsEarned ??= [];
|
||||||
if (!syndicate.FreeFavorsEarned.includes(syndicate.Title)) {
|
if (!syndicate.FreeFavorsEarned.includes(syndicate.Title)) {
|
||||||
syndicate.FreeFavorsEarned.push(syndicate.Title);
|
syndicate.FreeFavorsEarned.push(syndicate.Title);
|
||||||
@ -74,17 +77,10 @@ export const syndicateSacrificeController: RequestHandler = async (request, resp
|
|||||||
res.NewEpisodeReward = true;
|
res.NewEpisodeReward = true;
|
||||||
const reward = ExportNightwave.rewards[index];
|
const reward = ExportNightwave.rewards[index];
|
||||||
let rewardType = reward.uniqueName;
|
let rewardType = reward.uniqueName;
|
||||||
if (!isStoreItem(rewardType)) {
|
if (isStoreItem(rewardType)) {
|
||||||
rewardType = toStoreItem(rewardType);
|
rewardType = fromStoreItem(rewardType);
|
||||||
}
|
}
|
||||||
const rewardInventoryChanges = (await handleStoreItemAcquisition(rewardType, inventory, reward.itemCount))
|
combineInventoryChanges(res.InventoryChanges, await addItem(inventory, rewardType, reward.itemCount ?? 1));
|
||||||
.InventoryChanges;
|
|
||||||
if (Object.keys(rewardInventoryChanges).length == 0) {
|
|
||||||
logger.debug(`nightwave rank up reward did not seem to get added, giving 50 creds instead`);
|
|
||||||
rewardInventoryChanges.MiscItems = [{ ItemType: nightwaveCredsItemType, ItemCount: 50 }];
|
|
||||||
addMiscItems(inventory, rewardInventoryChanges.MiscItems);
|
|
||||||
}
|
|
||||||
combineInventoryChanges(res.InventoryChanges, rewardInventoryChanges);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { addMiscItems, addStanding, freeUpSlot, getInventory } from "@/src/services/inventoryService";
|
import {
|
||||||
|
addMiscItems,
|
||||||
|
freeUpSlot,
|
||||||
|
getInventory,
|
||||||
|
getStandingLimit,
|
||||||
|
updateStandingLimit
|
||||||
|
} from "@/src/services/inventoryService";
|
||||||
import { IMiscItem, InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IMiscItem, InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { IOid } from "@/src/types/commonTypes";
|
import { IOid } from "@/src/types/commonTypes";
|
||||||
import { ExportSyndicates, ExportWeapons } from "warframe-public-export-plus";
|
import { ExportSyndicates, ExportWeapons } from "warframe-public-export-plus";
|
||||||
|
import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
@ -54,13 +61,38 @@ export const syndicateStandingBonusController: RequestHandler = async (req, res)
|
|||||||
inventoryChanges[slotBin] = { count: -1, platinum: 0, Slots: 1 };
|
inventoryChanges[slotBin] = { count: -1, platinum: 0, Slots: 1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
const affiliationMod = addStanding(inventory, request.Operation.AffiliationTag, gainedStanding, true);
|
let syndicate = inventory.Affiliations.find(x => x.Tag == request.Operation.AffiliationTag);
|
||||||
|
if (!syndicate) {
|
||||||
|
syndicate =
|
||||||
|
inventory.Affiliations[
|
||||||
|
inventory.Affiliations.push({ Tag: request.Operation.AffiliationTag, Standing: 0 }) - 1
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
const max = getMaxStanding(syndicateMeta, syndicate.Title ?? 0);
|
||||||
|
if (syndicate.Standing + gainedStanding > max) {
|
||||||
|
gainedStanding = max - syndicate.Standing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (syndicateMeta.medallionsCappedByDailyLimit) {
|
||||||
|
if (gainedStanding > getStandingLimit(inventory, syndicateMeta.dailyLimitBin)) {
|
||||||
|
gainedStanding = getStandingLimit(inventory, syndicateMeta.dailyLimitBin);
|
||||||
|
}
|
||||||
|
updateStandingLimit(inventory, syndicateMeta.dailyLimitBin, gainedStanding);
|
||||||
|
}
|
||||||
|
|
||||||
|
syndicate.Standing += gainedStanding;
|
||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
InventoryChanges: inventoryChanges,
|
InventoryChanges: inventoryChanges,
|
||||||
AffiliationMods: [affiliationMod]
|
AffiliationMods: [
|
||||||
|
{
|
||||||
|
Tag: request.Operation.AffiliationTag,
|
||||||
|
Standing: gainedStanding
|
||||||
|
}
|
||||||
|
]
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,13 +25,7 @@ export const upgradesController: RequestHandler = async (req, res) => {
|
|||||||
operation.UpgradeRequirement == "/Lotus/Types/Items/MiscItems/CustomizationSlotUnlocker"
|
operation.UpgradeRequirement == "/Lotus/Types/Items/MiscItems/CustomizationSlotUnlocker"
|
||||||
) {
|
) {
|
||||||
updateCurrency(inventory, 10, true);
|
updateCurrency(inventory, 10, true);
|
||||||
} else if (
|
} else if (operation.OperationType != "UOT_ABILITY_OVERRIDE") {
|
||||||
operation.OperationType != "UOT_SWAP_POLARITY" &&
|
|
||||||
operation.OperationType != "UOT_ABILITY_OVERRIDE"
|
|
||||||
) {
|
|
||||||
if (!operation.UpgradeRequirement) {
|
|
||||||
throw new Error(`${operation.OperationType} operation should be free?`);
|
|
||||||
}
|
|
||||||
addMiscItems(inventory, [
|
addMiscItems(inventory, [
|
||||||
{
|
{
|
||||||
ItemType: operation.UpgradeRequirement,
|
ItemType: operation.UpgradeRequirement,
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { addFusionPoints, getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
|
||||||
export const addCurrencyController: RequestHandler = async (req, res) => {
|
export const addCurrencyController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId);
|
||||||
const request = req.body as IAddCurrencyRequest;
|
const request = req.body as IAddCurrencyRequest;
|
||||||
const inventory = await getInventory(accountId, request.currency);
|
|
||||||
if (request.currency == "FusionPoints") {
|
|
||||||
addFusionPoints(inventory, request.delta);
|
|
||||||
} else {
|
|
||||||
inventory[request.currency] += request.delta;
|
inventory[request.currency] += request.delta;
|
||||||
}
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.end();
|
res.end();
|
||||||
};
|
};
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
import { ExportArcanes, ExportUpgrades } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
export const addMissingMaxRankModsController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId, "Upgrades");
|
|
||||||
|
|
||||||
const maxOwnedRanks: Record<string, number> = {};
|
|
||||||
for (const upgrade of inventory.Upgrades) {
|
|
||||||
const fingerprint = JSON.parse(upgrade.UpgradeFingerprint ?? "{}") as { lvl?: number };
|
|
||||||
if (fingerprint.lvl) {
|
|
||||||
maxOwnedRanks[upgrade.ItemType] ??= 0;
|
|
||||||
if (fingerprint.lvl > maxOwnedRanks[upgrade.ItemType]) {
|
|
||||||
maxOwnedRanks[upgrade.ItemType] = fingerprint.lvl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const [uniqueName, data] of Object.entries(ExportUpgrades)) {
|
|
||||||
if (data.fusionLimit != 0 && data.type != "PARAZON" && maxOwnedRanks[uniqueName] != data.fusionLimit) {
|
|
||||||
inventory.Upgrades.push({
|
|
||||||
ItemType: uniqueName,
|
|
||||||
UpgradeFingerprint: JSON.stringify({ lvl: data.fusionLimit })
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const [uniqueName, data] of Object.entries(ExportArcanes)) {
|
|
||||||
if (
|
|
||||||
data.name != "/Lotus/Language/Items/GenericCosmeticEnhancerName" &&
|
|
||||||
maxOwnedRanks[uniqueName] != data.fusionLimit
|
|
||||||
) {
|
|
||||||
inventory.Upgrades.push({
|
|
||||||
ItemType: uniqueName,
|
|
||||||
UpgradeFingerprint: JSON.stringify({ lvl: data.fusionLimit })
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await inventory.save();
|
|
||||||
res.end();
|
|
||||||
};
|
|
98
src/controllers/custom/addModularEquipmentController.ts
Normal file
98
src/controllers/custom/addModularEquipmentController.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import {
|
||||||
|
getInventory,
|
||||||
|
addEquipment,
|
||||||
|
occupySlot,
|
||||||
|
productCategoryToInventoryBin,
|
||||||
|
applyDefaultUpgrades
|
||||||
|
} from "@/src/services/inventoryService";
|
||||||
|
import { modularWeaponTypes } from "@/src/helpers/modularWeaponHelper";
|
||||||
|
import { getDefaultUpgrades } from "@/src/services/itemDataService";
|
||||||
|
import { IEquipmentDatabase } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
|
import { ExportWeapons } from "warframe-public-export-plus";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
export const addModularEquipmentController: RequestHandler = async (req, res) => {
|
||||||
|
const requiredFields = new Set();
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const request = req.body as IAddModularEquipmentRequest;
|
||||||
|
const category = modularWeaponTypes[request.ItemType];
|
||||||
|
const inventoryBin = productCategoryToInventoryBin(category)!;
|
||||||
|
requiredFields.add(category);
|
||||||
|
requiredFields.add(inventoryBin);
|
||||||
|
|
||||||
|
request.ModularParts.forEach(part => {
|
||||||
|
if (ExportWeapons[part].gunType) {
|
||||||
|
if (category == "LongGuns") {
|
||||||
|
request.ItemType = {
|
||||||
|
GT_RIFLE: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimary",
|
||||||
|
GT_SHOTGUN: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryShotgun",
|
||||||
|
GT_BEAM: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryBeam"
|
||||||
|
}[ExportWeapons[part].gunType];
|
||||||
|
} else {
|
||||||
|
request.ItemType = {
|
||||||
|
GT_RIFLE: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary",
|
||||||
|
GT_SHOTGUN: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryShotgun",
|
||||||
|
GT_BEAM: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryBeam"
|
||||||
|
}[ExportWeapons[part].gunType];
|
||||||
|
}
|
||||||
|
} else if (request.ItemType == "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetPowerSuit") {
|
||||||
|
if (part.includes("ZanukaPetPartHead")) {
|
||||||
|
request.ItemType = {
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadA":
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetAPowerSuit",
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadB":
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetBPowerSuit",
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadC":
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetCPowerSuit"
|
||||||
|
}[part]!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const defaultUpgrades = getDefaultUpgrades(request.ModularParts);
|
||||||
|
if (defaultUpgrades) {
|
||||||
|
requiredFields.add("RawUpgrades");
|
||||||
|
}
|
||||||
|
const defaultWeaponsMap: Record<string, string[]> = {
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetAPowerSuit": [
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetMeleeWeaponIP"
|
||||||
|
],
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetBPowerSuit": [
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetMeleeWeaponIS"
|
||||||
|
],
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetCPowerSuit": [
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetMeleeWeaponPS"
|
||||||
|
]
|
||||||
|
};
|
||||||
|
const defaultWeapons = defaultWeaponsMap[request.ItemType] as string[] | undefined;
|
||||||
|
if (defaultWeapons) {
|
||||||
|
for (const defaultWeapon of defaultWeapons) {
|
||||||
|
const category = ExportWeapons[defaultWeapon].productCategory;
|
||||||
|
requiredFields.add(category);
|
||||||
|
requiredFields.add(productCategoryToInventoryBin(category));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const inventory = await getInventory(accountId, Array.from(requiredFields).join(" "));
|
||||||
|
if (defaultWeapons) {
|
||||||
|
for (const defaultWeapon of defaultWeapons) {
|
||||||
|
const category = ExportWeapons[defaultWeapon].productCategory;
|
||||||
|
addEquipment(inventory, category, defaultWeapon);
|
||||||
|
occupySlot(inventory, productCategoryToInventoryBin(category)!, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultOverwrites: Partial<IEquipmentDatabase> = {
|
||||||
|
Configs: applyDefaultUpgrades(inventory, defaultUpgrades)
|
||||||
|
};
|
||||||
|
|
||||||
|
addEquipment(inventory, category, request.ItemType, request.ModularParts, undefined, defaultOverwrites);
|
||||||
|
occupySlot(inventory, inventoryBin, true);
|
||||||
|
await inventory.save();
|
||||||
|
res.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IAddModularEquipmentRequest {
|
||||||
|
ItemType: string;
|
||||||
|
ModularParts: string[];
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { applyClientEquipmentUpdates, getInventory } from "@/src/services/inventoryService";
|
import { addGearExpByCategory, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
@ -20,7 +20,7 @@ export const addXpController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
applyClientEquipmentUpdates(inventory, gear, category as TEquipmentKey);
|
addGearExpByCategory(inventory, gear, category as TEquipmentKey);
|
||||||
}
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.end();
|
res.end();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { Account, Ignore } from "@/src/models/loginModel";
|
import { Account } from "@/src/models/loginModel";
|
||||||
import { Inbox } from "@/src/models/inboxModel";
|
import { Inbox } from "@/src/models/inboxModel";
|
||||||
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
||||||
@ -23,8 +23,6 @@ export const deleteAccountController: RequestHandler = async (req, res) => {
|
|||||||
await Promise.all([
|
await Promise.all([
|
||||||
Account.deleteOne({ _id: accountId }),
|
Account.deleteOne({ _id: accountId }),
|
||||||
GuildMember.deleteMany({ accountId: accountId }),
|
GuildMember.deleteMany({ accountId: accountId }),
|
||||||
Ignore.deleteMany({ ignorer: accountId }),
|
|
||||||
Ignore.deleteMany({ ignoree: accountId }),
|
|
||||||
Inbox.deleteMany({ ownerId: accountId }),
|
Inbox.deleteMany({ ownerId: accountId }),
|
||||||
Inventory.deleteOne({ accountOwnerId: accountId }),
|
Inventory.deleteOne({ accountOwnerId: accountId }),
|
||||||
Leaderboard.deleteMany({ ownerId: accountId }),
|
Leaderboard.deleteMany({ ownerId: accountId }),
|
||||||
|
@ -3,7 +3,6 @@ import { getDict, getItemName, getString } from "@/src/services/itemDataService"
|
|||||||
import {
|
import {
|
||||||
ExportArcanes,
|
ExportArcanes,
|
||||||
ExportAvionics,
|
ExportAvionics,
|
||||||
ExportCustoms,
|
|
||||||
ExportDrones,
|
ExportDrones,
|
||||||
ExportGear,
|
ExportGear,
|
||||||
ExportKeys,
|
ExportKeys,
|
||||||
@ -20,7 +19,6 @@ import {
|
|||||||
TRelicQuality
|
TRelicQuality
|
||||||
} from "warframe-public-export-plus";
|
} from "warframe-public-export-plus";
|
||||||
import archonCrystalUpgrades from "@/static/fixed_responses/webuiArchonCrystalUpgrades.json";
|
import archonCrystalUpgrades from "@/static/fixed_responses/webuiArchonCrystalUpgrades.json";
|
||||||
import allIncarnons from "@/static/fixed_responses/allIncarnonList.json";
|
|
||||||
|
|
||||||
interface ListedItem {
|
interface ListedItem {
|
||||||
uniqueName: string;
|
uniqueName: string;
|
||||||
@ -30,30 +28,6 @@ interface ListedItem {
|
|||||||
badReason?: "starter" | "frivolous" | "notraw";
|
badReason?: "starter" | "frivolous" | "notraw";
|
||||||
partType?: string;
|
partType?: string;
|
||||||
chainLength?: number;
|
chainLength?: number;
|
||||||
parazon?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ItemLists {
|
|
||||||
archonCrystalUpgrades: Record<string, string>;
|
|
||||||
uniqueLevelCaps: Record<string, number>;
|
|
||||||
Suits: ListedItem[];
|
|
||||||
LongGuns: ListedItem[];
|
|
||||||
Melee: ListedItem[];
|
|
||||||
ModularParts: ListedItem[];
|
|
||||||
Pistols: ListedItem[];
|
|
||||||
Sentinels: ListedItem[];
|
|
||||||
SentinelWeapons: ListedItem[];
|
|
||||||
SpaceGuns: ListedItem[];
|
|
||||||
SpaceMelee: ListedItem[];
|
|
||||||
SpaceSuits: ListedItem[];
|
|
||||||
MechSuits: ListedItem[];
|
|
||||||
miscitems: ListedItem[];
|
|
||||||
Syndicates: ListedItem[];
|
|
||||||
OperatorAmps: ListedItem[];
|
|
||||||
QuestKeys: ListedItem[];
|
|
||||||
KubrowPets: ListedItem[];
|
|
||||||
EvolutionProgress: ListedItem[];
|
|
||||||
mods: ListedItem[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const relicQualitySuffixes: Record<TRelicQuality, string> = {
|
const relicQualitySuffixes: Record<TRelicQuality, string> = {
|
||||||
@ -65,28 +39,22 @@ const relicQualitySuffixes: Record<TRelicQuality, string> = {
|
|||||||
|
|
||||||
const getItemListsController: RequestHandler = (req, response) => {
|
const getItemListsController: RequestHandler = (req, response) => {
|
||||||
const lang = getDict(typeof req.query.lang == "string" ? req.query.lang : "en");
|
const lang = getDict(typeof req.query.lang == "string" ? req.query.lang : "en");
|
||||||
const res: ItemLists = {
|
const res: Record<string, ListedItem[]> = {};
|
||||||
archonCrystalUpgrades,
|
res.Suits = [];
|
||||||
uniqueLevelCaps: ExportMisc.uniqueLevelCaps,
|
res.LongGuns = [];
|
||||||
Suits: [],
|
res.Melee = [];
|
||||||
LongGuns: [],
|
res.ModularParts = [];
|
||||||
Melee: [],
|
res.Pistols = [];
|
||||||
ModularParts: [],
|
res.Sentinels = [];
|
||||||
Pistols: [],
|
res.SentinelWeapons = [];
|
||||||
Sentinels: [],
|
res.SpaceGuns = [];
|
||||||
SentinelWeapons: [],
|
res.SpaceMelee = [];
|
||||||
SpaceGuns: [],
|
res.SpaceSuits = [];
|
||||||
SpaceMelee: [],
|
res.MechSuits = [];
|
||||||
SpaceSuits: [],
|
res.miscitems = [];
|
||||||
MechSuits: [],
|
res.Syndicates = [];
|
||||||
miscitems: [],
|
res.OperatorAmps = [];
|
||||||
Syndicates: [],
|
res.QuestKeys = [];
|
||||||
OperatorAmps: [],
|
|
||||||
QuestKeys: [],
|
|
||||||
KubrowPets: [],
|
|
||||||
EvolutionProgress: [],
|
|
||||||
mods: []
|
|
||||||
};
|
|
||||||
for (const [uniqueName, item] of Object.entries(ExportWarframes)) {
|
for (const [uniqueName, item] of Object.entries(ExportWarframes)) {
|
||||||
res[item.productCategory].push({
|
res[item.productCategory].push({
|
||||||
uniqueName,
|
uniqueName,
|
||||||
@ -95,23 +63,20 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
for (const [uniqueName, item] of Object.entries(ExportSentinels)) {
|
for (const [uniqueName, item] of Object.entries(ExportSentinels)) {
|
||||||
if (item.productCategory == "Sentinels" || item.productCategory == "KubrowPets") {
|
if (item.productCategory == "Sentinels") {
|
||||||
res[item.productCategory].push({
|
res[item.productCategory].push({
|
||||||
uniqueName,
|
uniqueName,
|
||||||
name: getString(item.name, lang),
|
name: getString(item.name, lang)
|
||||||
exalted: item.exalted
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const [uniqueName, item] of Object.entries(ExportWeapons)) {
|
for (const [uniqueName, item] of Object.entries(ExportWeapons)) {
|
||||||
if (item.partType) {
|
if (item.partType) {
|
||||||
if (!uniqueName.startsWith("/Lotus/Types/Items/Deimos/")) {
|
|
||||||
res.ModularParts.push({
|
res.ModularParts.push({
|
||||||
uniqueName,
|
uniqueName,
|
||||||
name: getString(item.name, lang),
|
name: getString(item.name, lang),
|
||||||
partType: item.partType
|
partType: item.partType
|
||||||
});
|
});
|
||||||
}
|
|
||||||
if (uniqueName.split("/")[5] != "SentTrainingAmplifier") {
|
if (uniqueName.split("/")[5] != "SentTrainingAmplifier") {
|
||||||
res.miscitems.push({
|
res.miscitems.push({
|
||||||
uniqueName: uniqueName,
|
uniqueName: uniqueName,
|
||||||
@ -144,7 +109,6 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
let name = getString(item.name, lang);
|
let name = getString(item.name, lang);
|
||||||
if ("dissectionParts" in item) {
|
if ("dissectionParts" in item) {
|
||||||
name = getString("/Lotus/Language/Fish/FishDisplayName", lang).split("|FISH_NAME|").join(name);
|
name = getString("/Lotus/Language/Fish/FishDisplayName", lang).split("|FISH_NAME|").join(name);
|
||||||
if (item.syndicateTag == "CetusSyndicate") {
|
|
||||||
if (uniqueName.indexOf("Large") != -1) {
|
if (uniqueName.indexOf("Large") != -1) {
|
||||||
name = name.split("|FISH_SIZE|").join(getString("/Lotus/Language/Fish/FishSizeLargeAbbrev", lang));
|
name = name.split("|FISH_SIZE|").join(getString("/Lotus/Language/Fish/FishSizeLargeAbbrev", lang));
|
||||||
} else if (uniqueName.indexOf("Medium") != -1) {
|
} else if (uniqueName.indexOf("Medium") != -1) {
|
||||||
@ -152,21 +116,6 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
} else {
|
} else {
|
||||||
name = name.split("|FISH_SIZE|").join(getString("/Lotus/Language/Fish/FishSizeSmallAbbrev", lang));
|
name = name.split("|FISH_SIZE|").join(getString("/Lotus/Language/Fish/FishSizeSmallAbbrev", lang));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (uniqueName.indexOf("Large") != -1) {
|
|
||||||
name = name
|
|
||||||
.split("|FISH_SIZE|")
|
|
||||||
.join(getString("/Lotus/Language/SolarisVenus/RobofishAgeCategoryElderAbbrev", lang));
|
|
||||||
} else if (uniqueName.indexOf("Medium") != -1) {
|
|
||||||
name = name
|
|
||||||
.split("|FISH_SIZE|")
|
|
||||||
.join(getString("/Lotus/Language/SolarisVenus/RobofishAgeCategoryMatureAbbrev", lang));
|
|
||||||
} else {
|
|
||||||
name = name
|
|
||||||
.split("|FISH_SIZE|")
|
|
||||||
.join(getString("/Lotus/Language/SolarisVenus/RobofishAgeCategoryYoungAbbrev", lang));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
name &&
|
name &&
|
||||||
@ -222,13 +171,8 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
name: getString(item.name, lang)
|
name: getString(item.name, lang)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for (const [uniqueName, item] of Object.entries(ExportCustoms)) {
|
|
||||||
res.miscitems.push({
|
|
||||||
uniqueName: uniqueName,
|
|
||||||
name: getString(item.name, lang)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
res.mods = [];
|
||||||
for (const [uniqueName, upgrade] of Object.entries(ExportUpgrades)) {
|
for (const [uniqueName, upgrade] of Object.entries(ExportUpgrades)) {
|
||||||
const mod: ListedItem = {
|
const mod: ListedItem = {
|
||||||
uniqueName,
|
uniqueName,
|
||||||
@ -242,9 +186,6 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
} else if (upgrade.upgradeEntries) {
|
} else if (upgrade.upgradeEntries) {
|
||||||
mod.badReason = "notraw";
|
mod.badReason = "notraw";
|
||||||
}
|
}
|
||||||
if (upgrade.type == "PARAZON") {
|
|
||||||
mod.parazon = true;
|
|
||||||
}
|
|
||||||
res.mods.push(mod);
|
res.mods.push(mod);
|
||||||
}
|
}
|
||||||
for (const [uniqueName, upgrade] of Object.entries(ExportAvionics)) {
|
for (const [uniqueName, upgrade] of Object.entries(ExportAvionics)) {
|
||||||
@ -286,14 +227,12 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const uniqueName of allIncarnons) {
|
|
||||||
res.EvolutionProgress.push({
|
|
||||||
uniqueName,
|
|
||||||
name: getString(getItemName(uniqueName) || "", lang)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
response.json(res);
|
response.json({
|
||||||
|
archonCrystalUpgrades,
|
||||||
|
uniqueLevelCaps: ExportMisc.uniqueLevelCaps,
|
||||||
|
...res
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export { getItemListsController };
|
export { getItemListsController };
|
||||||
|
23
src/controllers/custom/gildEquipmentController.ts
Normal file
23
src/controllers/custom/gildEquipmentController.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
|
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
export const gildEquipmentController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const request = req.body as IGildEquipmentRequest;
|
||||||
|
const inventory = await getInventory(accountId, request.Category);
|
||||||
|
const weapon = inventory[request.Category].id(request.ItemId);
|
||||||
|
if (weapon) {
|
||||||
|
weapon.Features ??= 0;
|
||||||
|
weapon.Features |= EquipmentFeatures.GILDED;
|
||||||
|
await inventory.save();
|
||||||
|
}
|
||||||
|
res.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
type IGildEquipmentRequest = {
|
||||||
|
ItemId: string;
|
||||||
|
Category: TEquipmentKey;
|
||||||
|
};
|
@ -35,9 +35,11 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
|
|||||||
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case "completeAll": {
|
case "completeAll": {
|
||||||
|
if (allQuestKeys.includes(questItemType)) {
|
||||||
for (const questKey of inventory.QuestKeys) {
|
for (const questKey of inventory.QuestKeys) {
|
||||||
await completeQuest(inventory, questKey.ItemType);
|
await completeQuest(inventory, questKey.ItemType);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "resetAll": {
|
case "resetAll": {
|
||||||
@ -54,12 +56,15 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "deleteKey": {
|
case "deleteKey": {
|
||||||
|
if (allQuestKeys.includes(questItemType)) {
|
||||||
const questKey = inventory.QuestKeys.find(key => key.ItemType === questItemType);
|
const questKey = inventory.QuestKeys.find(key => key.ItemType === questItemType);
|
||||||
if (!questKey) {
|
if (!questKey) {
|
||||||
logger.error(`Quest key not found in inventory: ${questItemType}`);
|
logger.error(`Quest key not found in inventory: ${questItemType}`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
inventory.QuestKeys.pull({ ItemType: questItemType });
|
inventory.QuestKeys.pull({ ItemType: questItemType });
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "completeKey": {
|
case "completeKey": {
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const setEvolutionProgressController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const payload = req.body as ISetEvolutionProgressRequest;
|
|
||||||
|
|
||||||
inventory.EvolutionProgress ??= [];
|
|
||||||
payload.forEach(element => {
|
|
||||||
const entry = inventory.EvolutionProgress!.find(entry => entry.ItemType === element.ItemType);
|
|
||||||
|
|
||||||
if (entry) {
|
|
||||||
entry.Progress = 0;
|
|
||||||
entry.Rank = element.Rank;
|
|
||||||
} else {
|
|
||||||
inventory.EvolutionProgress!.push({
|
|
||||||
Progress: 0,
|
|
||||||
Rank: element.Rank,
|
|
||||||
ItemType: element.ItemType
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await inventory.save();
|
|
||||||
res.end();
|
|
||||||
};
|
|
||||||
|
|
||||||
type ISetEvolutionProgressRequest = {
|
|
||||||
ItemType: string;
|
|
||||||
Rank: number;
|
|
||||||
}[];
|
|
@ -1,6 +1,611 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getWorldState } from "@/src/services/worldStateService";
|
import staticWorldState from "@/static/fixed_responses/worldState/worldState.json";
|
||||||
|
import static1999FallDays from "@/static/fixed_responses/worldState/1999_fall_days.json";
|
||||||
|
import static1999SpringDays from "@/static/fixed_responses/worldState/1999_spring_days.json";
|
||||||
|
import static1999SummerDays from "@/static/fixed_responses/worldState/1999_summer_days.json";
|
||||||
|
import static1999WinterDays from "@/static/fixed_responses/worldState/1999_winter_days.json";
|
||||||
|
import { buildConfig } from "@/src/services/buildConfigService";
|
||||||
|
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
||||||
|
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
||||||
|
import { config } from "@/src/services/configService";
|
||||||
|
import { CRng } from "@/src/services/rngService";
|
||||||
|
import { ExportNightwave, ExportRegions } from "warframe-public-export-plus";
|
||||||
|
import {
|
||||||
|
EPOCH,
|
||||||
|
getSortieTime,
|
||||||
|
missionTags,
|
||||||
|
sortieBosses,
|
||||||
|
sortieBossNode,
|
||||||
|
sortieBossToFaction,
|
||||||
|
sortieFactionToFactionIndexes,
|
||||||
|
sortieFactionToSystemIndexes
|
||||||
|
} from "@/src/helpers/worlstateHelper";
|
||||||
|
|
||||||
export const worldStateController: RequestHandler = (req, res) => {
|
export const worldStateController: RequestHandler = (req, res) => {
|
||||||
res.json(getWorldState(req.query.buildLabel as string | undefined));
|
const day = Math.trunc((Date.now() - EPOCH) / 86400000);
|
||||||
|
const week = Math.trunc(day / 7);
|
||||||
|
const weekStart = EPOCH + week * 604800000;
|
||||||
|
const weekEnd = weekStart + 604800000;
|
||||||
|
|
||||||
|
const worldState: IWorldState = {
|
||||||
|
BuildLabel:
|
||||||
|
typeof req.query.buildLabel == "string"
|
||||||
|
? req.query.buildLabel.split(" ").join("+")
|
||||||
|
: buildConfig.buildLabel,
|
||||||
|
Time: config.worldState?.lockTime || Math.round(Date.now() / 1000),
|
||||||
|
Goals: [],
|
||||||
|
GlobalUpgrades: [],
|
||||||
|
Sorties: [],
|
||||||
|
LiteSorties: [],
|
||||||
|
EndlessXpChoices: [],
|
||||||
|
SeasonInfo: {
|
||||||
|
Activation: { $date: { $numberLong: "1715796000000" } },
|
||||||
|
Expiry: { $date: { $numberLong: "2000000000000" } },
|
||||||
|
AffiliationTag: "RadioLegionIntermission12Syndicate",
|
||||||
|
Season: 14,
|
||||||
|
Phase: 0,
|
||||||
|
Params: "",
|
||||||
|
ActiveChallenges: [
|
||||||
|
getSeasonDailyChallenge(day - 2),
|
||||||
|
getSeasonDailyChallenge(day - 1),
|
||||||
|
getSeasonDailyChallenge(day - 0),
|
||||||
|
getSeasonWeeklyChallenge(week, 0),
|
||||||
|
getSeasonWeeklyChallenge(week, 1),
|
||||||
|
getSeasonWeeklyHardChallenge(week, 2),
|
||||||
|
getSeasonWeeklyHardChallenge(week, 3),
|
||||||
|
{
|
||||||
|
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 0).toString().padStart(8, "0") },
|
||||||
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
|
Challenge:
|
||||||
|
"/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentCompleteMissions" + (week - 12)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 1).toString().padStart(8, "0") },
|
||||||
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
|
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEximus" + (week - 12)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 2).toString().padStart(8, "0") },
|
||||||
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
|
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEnemies" + (week - 12)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
...staticWorldState
|
||||||
|
};
|
||||||
|
|
||||||
|
if (config.worldState?.starDays) {
|
||||||
|
worldState.Goals.push({
|
||||||
|
_id: { $oid: "67a4dcce2a198564d62e1647" },
|
||||||
|
Activation: { $date: { $numberLong: "1738868400000" } },
|
||||||
|
Expiry: { $date: { $numberLong: "2000000000000" } },
|
||||||
|
Count: 0,
|
||||||
|
Goal: 0,
|
||||||
|
Success: 0,
|
||||||
|
Personal: true,
|
||||||
|
Desc: "/Lotus/Language/Events/ValentinesFortunaName",
|
||||||
|
ToolTip: "/Lotus/Language/Events/ValentinesFortunaName",
|
||||||
|
Icon: "/Lotus/Interface/Icons/WorldStatePanel/ValentinesEventIcon.png",
|
||||||
|
Tag: "FortunaValentines",
|
||||||
|
Node: "SolarisUnitedHub1"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Elite Sanctuary Onslaught cycling every week
|
||||||
|
worldState.NodeOverrides.find(x => x.Node == "SolNode802")!.Seed = week; // unfaithful
|
||||||
|
|
||||||
|
// Holdfast, Cavia, & Hex bounties cycling every 2.5 hours; unfaithful implementation
|
||||||
|
const bountyCycle = Math.trunc(Date.now() / 9000000);
|
||||||
|
const bountyCycleStart = bountyCycle * 9000000;
|
||||||
|
const bountyCycleEnd = bountyCycleStart + 9000000;
|
||||||
|
worldState.SyndicateMissions[worldState.SyndicateMissions.findIndex(x => x.Tag == "ZarimanSyndicate")] = {
|
||||||
|
_id: { $oid: Math.trunc(bountyCycleStart / 1000).toString(16) + "0000000000000029" },
|
||||||
|
Activation: { $date: { $numberLong: bountyCycleStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: bountyCycleEnd.toString() } },
|
||||||
|
Tag: "ZarimanSyndicate",
|
||||||
|
Seed: bountyCycle,
|
||||||
|
Nodes: []
|
||||||
|
};
|
||||||
|
worldState.SyndicateMissions[worldState.SyndicateMissions.findIndex(x => x.Tag == "EntratiLabSyndicate")] = {
|
||||||
|
_id: { $oid: Math.trunc(bountyCycleStart / 1000).toString(16) + "0000000000000004" },
|
||||||
|
Activation: { $date: { $numberLong: bountyCycleStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: bountyCycleEnd.toString() } },
|
||||||
|
Tag: "EntratiLabSyndicate",
|
||||||
|
Seed: bountyCycle,
|
||||||
|
Nodes: []
|
||||||
|
};
|
||||||
|
worldState.SyndicateMissions[worldState.SyndicateMissions.findIndex(x => x.Tag == "HexSyndicate")] = {
|
||||||
|
_id: { $oid: Math.trunc(bountyCycleStart / 1000).toString(16) + "0000000000000006" },
|
||||||
|
Activation: { $date: { $numberLong: bountyCycleStart.toString(10) } },
|
||||||
|
Expiry: { $date: { $numberLong: bountyCycleEnd.toString(10) } },
|
||||||
|
Tag: "HexSyndicate",
|
||||||
|
Seed: bountyCycle,
|
||||||
|
Nodes: []
|
||||||
|
};
|
||||||
|
|
||||||
|
if (config.worldState?.creditBoost) {
|
||||||
|
worldState.GlobalUpgrades.push({
|
||||||
|
_id: { $oid: "5b23106f283a555109666672" },
|
||||||
|
Activation: { $date: { $numberLong: "1740164400000" } },
|
||||||
|
ExpiryDate: { $date: { $numberLong: "2000000000000" } },
|
||||||
|
UpgradeType: "GAMEPLAY_MONEY_REWARD_AMOUNT",
|
||||||
|
OperationType: "MULTIPLY",
|
||||||
|
Value: 2,
|
||||||
|
LocalizeTag: "",
|
||||||
|
LocalizeDescTag: ""
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (config.worldState?.affinityBoost) {
|
||||||
|
worldState.GlobalUpgrades.push({
|
||||||
|
_id: { $oid: "5b23106f283a555109666673" },
|
||||||
|
Activation: { $date: { $numberLong: "1740164400000" } },
|
||||||
|
ExpiryDate: { $date: { $numberLong: "2000000000000" } },
|
||||||
|
UpgradeType: "GAMEPLAY_KILL_XP_AMOUNT",
|
||||||
|
OperationType: "MULTIPLY",
|
||||||
|
Value: 2,
|
||||||
|
LocalizeTag: "",
|
||||||
|
LocalizeDescTag: ""
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (config.worldState?.resourceBoost) {
|
||||||
|
worldState.GlobalUpgrades.push({
|
||||||
|
_id: { $oid: "5b23106f283a555109666674" },
|
||||||
|
Activation: { $date: { $numberLong: "1740164400000" } },
|
||||||
|
ExpiryDate: { $date: { $numberLong: "2000000000000" } },
|
||||||
|
UpgradeType: "GAMEPLAY_PICKUP_AMOUNT",
|
||||||
|
OperationType: "MULTIPLY",
|
||||||
|
Value: 2,
|
||||||
|
LocalizeTag: "",
|
||||||
|
LocalizeDescTag: ""
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sortie cycling every day
|
||||||
|
{
|
||||||
|
let genDay;
|
||||||
|
let dayStart;
|
||||||
|
let dayEnd;
|
||||||
|
const sortieRolloverToday = getSortieTime(day);
|
||||||
|
if (Date.now() < sortieRolloverToday) {
|
||||||
|
// Early in the day, generate sortie for `day - 1`, expiring at `sortieRolloverToday`.
|
||||||
|
genDay = day - 1;
|
||||||
|
dayStart = getSortieTime(genDay);
|
||||||
|
dayEnd = sortieRolloverToday;
|
||||||
|
} else {
|
||||||
|
// Late in the day, generate sortie for `day`, expiring at `getSortieTime(day + 1)`.
|
||||||
|
genDay = day;
|
||||||
|
dayStart = sortieRolloverToday;
|
||||||
|
dayEnd = getSortieTime(day + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const rng = new CRng(genDay);
|
||||||
|
|
||||||
|
const boss = rng.randomElement(sortieBosses);
|
||||||
|
|
||||||
|
const modifiers = [
|
||||||
|
"SORTIE_MODIFIER_LOW_ENERGY",
|
||||||
|
"SORTIE_MODIFIER_IMPACT",
|
||||||
|
"SORTIE_MODIFIER_SLASH",
|
||||||
|
"SORTIE_MODIFIER_PUNCTURE",
|
||||||
|
"SORTIE_MODIFIER_EXIMUS",
|
||||||
|
"SORTIE_MODIFIER_MAGNETIC",
|
||||||
|
"SORTIE_MODIFIER_CORROSIVE",
|
||||||
|
"SORTIE_MODIFIER_VIRAL",
|
||||||
|
"SORTIE_MODIFIER_ELECTRICITY",
|
||||||
|
"SORTIE_MODIFIER_RADIATION",
|
||||||
|
"SORTIE_MODIFIER_GAS",
|
||||||
|
"SORTIE_MODIFIER_FIRE",
|
||||||
|
"SORTIE_MODIFIER_EXPLOSION",
|
||||||
|
"SORTIE_MODIFIER_FREEZE",
|
||||||
|
"SORTIE_MODIFIER_TOXIN",
|
||||||
|
"SORTIE_MODIFIER_POISON",
|
||||||
|
"SORTIE_MODIFIER_HAZARD_RADIATION",
|
||||||
|
"SORTIE_MODIFIER_HAZARD_MAGNETIC",
|
||||||
|
"SORTIE_MODIFIER_HAZARD_FOG", // TODO: push this if the mission tileset is Grineer Forest
|
||||||
|
"SORTIE_MODIFIER_HAZARD_FIRE", // TODO: push this if the mission tileset is Corpus Ship or Grineer Galleon
|
||||||
|
"SORTIE_MODIFIER_HAZARD_ICE",
|
||||||
|
"SORTIE_MODIFIER_HAZARD_COLD",
|
||||||
|
"SORTIE_MODIFIER_SECONDARY_ONLY",
|
||||||
|
"SORTIE_MODIFIER_SHOTGUN_ONLY",
|
||||||
|
"SORTIE_MODIFIER_SNIPER_ONLY",
|
||||||
|
"SORTIE_MODIFIER_RIFLE_ONLY",
|
||||||
|
"SORTIE_MODIFIER_MELEE_ONLY",
|
||||||
|
"SORTIE_MODIFIER_BOW_ONLY"
|
||||||
|
];
|
||||||
|
|
||||||
|
if (sortieBossToFaction[boss] == "FC_CORPUS") modifiers.push("SORTIE_MODIFIER_SHIELDS");
|
||||||
|
if (sortieBossToFaction[boss] != "FC_CORPUS") modifiers.push("SORTIE_MODIFIER_ARMOR");
|
||||||
|
|
||||||
|
const nodes: string[] = [];
|
||||||
|
const availableMissionIndexes: number[] = [];
|
||||||
|
for (const [key, value] of Object.entries(ExportRegions)) {
|
||||||
|
if (
|
||||||
|
sortieFactionToSystemIndexes[sortieBossToFaction[boss]].includes(value.systemIndex) &&
|
||||||
|
sortieFactionToFactionIndexes[sortieBossToFaction[boss]].includes(value.factionIndex!) &&
|
||||||
|
value.name.indexOf("Archwing") == -1 &&
|
||||||
|
value.missionIndex != 0 && // Exclude MT_ASSASSINATION
|
||||||
|
value.missionIndex != 5 && // Exclude MT_CAPTURE
|
||||||
|
value.missionIndex != 21 && // Exclude MT_PURIFY
|
||||||
|
value.missionIndex != 23 && // Exclude MT_JUNCTION
|
||||||
|
value.missionIndex <= 28
|
||||||
|
) {
|
||||||
|
if (!availableMissionIndexes.includes(value.missionIndex)) {
|
||||||
|
availableMissionIndexes.push(value.missionIndex);
|
||||||
|
}
|
||||||
|
nodes.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedNodes: { missionType: string; modifierType: string; node: string }[] = [];
|
||||||
|
const missionTypes = new Set();
|
||||||
|
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
const randomIndex = rng.randomInt(0, nodes.length - 1);
|
||||||
|
const node = nodes[randomIndex];
|
||||||
|
let missionIndex = ExportRegions[node].missionIndex;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!["SolNode404", "SolNode411"].includes(node) && // for some reason the game doesn't like missionType changes for these missions
|
||||||
|
missionIndex != 28 &&
|
||||||
|
rng.randomInt(0, 2) == 2
|
||||||
|
) {
|
||||||
|
missionIndex = rng.randomElement(availableMissionIndexes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 2 && rng.randomInt(0, 2) == 2) {
|
||||||
|
const filteredModifiers = modifiers.filter(mod => mod !== "SORTIE_MODIFIER_MELEE_ONLY");
|
||||||
|
const modifierType = rng.randomElement(filteredModifiers);
|
||||||
|
|
||||||
|
if (boss == "SORTIE_BOSS_PHORID") {
|
||||||
|
selectedNodes.push({ missionType: "MT_ASSASSINATION", modifierType, node });
|
||||||
|
nodes.splice(randomIndex, 1);
|
||||||
|
continue;
|
||||||
|
} else if (sortieBossNode[boss]) {
|
||||||
|
selectedNodes.push({ missionType: "MT_ASSASSINATION", modifierType, node: sortieBossNode[boss] });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const missionType = missionTags[missionIndex];
|
||||||
|
|
||||||
|
if (missionTypes.has(missionType)) {
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filteredModifiers =
|
||||||
|
missionType === "MT_TERRITORY"
|
||||||
|
? modifiers.filter(mod => mod != "SORTIE_MODIFIER_HAZARD_RADIATION")
|
||||||
|
: modifiers;
|
||||||
|
|
||||||
|
const modifierType = rng.randomElement(filteredModifiers);
|
||||||
|
|
||||||
|
selectedNodes.push({ missionType, modifierType, node });
|
||||||
|
nodes.splice(randomIndex, 1);
|
||||||
|
missionTypes.add(missionType);
|
||||||
|
}
|
||||||
|
|
||||||
|
worldState.Sorties.push({
|
||||||
|
_id: { $oid: Math.trunc(dayStart / 1000).toString(16) + "d4d932c97c0a3acd" },
|
||||||
|
Activation: { $date: { $numberLong: dayStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: dayEnd.toString() } },
|
||||||
|
Reward: "/Lotus/Types/Game/MissionDecks/SortieRewards",
|
||||||
|
Seed: genDay,
|
||||||
|
Boss: boss,
|
||||||
|
Variants: selectedNodes
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Archon Hunt cycling every week
|
||||||
|
{
|
||||||
|
const boss = ["SORTIE_BOSS_AMAR", "SORTIE_BOSS_NIRA", "SORTIE_BOSS_BOREAL"][week % 3];
|
||||||
|
const showdownNode = ["SolNode99", "SolNode53", "SolNode24"][week % 3];
|
||||||
|
const systemIndex = [3, 4, 2][week % 3]; // Mars, Jupiter, Earth
|
||||||
|
|
||||||
|
const nodes: string[] = [];
|
||||||
|
for (const [key, value] of Object.entries(ExportRegions)) {
|
||||||
|
if (
|
||||||
|
value.systemIndex === systemIndex &&
|
||||||
|
value.factionIndex !== undefined &&
|
||||||
|
value.factionIndex < 2 &&
|
||||||
|
value.name.indexOf("Archwing") == -1 &&
|
||||||
|
value.missionIndex != 0 // Exclude MT_ASSASSINATION
|
||||||
|
) {
|
||||||
|
nodes.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const rng = new CRng(week);
|
||||||
|
const firstNodeIndex = rng.randomInt(0, nodes.length - 1);
|
||||||
|
const firstNode = nodes[firstNodeIndex];
|
||||||
|
nodes.splice(firstNodeIndex, 1);
|
||||||
|
worldState.LiteSorties.push({
|
||||||
|
_id: {
|
||||||
|
$oid: Math.trunc(weekStart / 1000).toString(16) + "5e23a244740a190c"
|
||||||
|
},
|
||||||
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
|
Reward: "/Lotus/Types/Game/MissionDecks/ArchonSortieRewards",
|
||||||
|
Seed: week,
|
||||||
|
Boss: boss,
|
||||||
|
Missions: [
|
||||||
|
{
|
||||||
|
missionType: rng.randomElement([
|
||||||
|
"MT_INTEL",
|
||||||
|
"MT_MOBILE_DEFENSE",
|
||||||
|
"MT_EXTERMINATION",
|
||||||
|
"MT_SABOTAGE",
|
||||||
|
"MT_RESCUE"
|
||||||
|
]),
|
||||||
|
node: firstNode
|
||||||
|
},
|
||||||
|
{
|
||||||
|
missionType: rng.randomElement([
|
||||||
|
"MT_DEFENSE",
|
||||||
|
"MT_TERRITORY",
|
||||||
|
"MT_ARTIFACT",
|
||||||
|
"MT_EXCAVATE",
|
||||||
|
"MT_SURVIVAL"
|
||||||
|
]),
|
||||||
|
node: rng.randomElement(nodes)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
missionType: "MT_ASSASSINATION",
|
||||||
|
node: showdownNode
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Circuit choices cycling every week
|
||||||
|
worldState.EndlessXpChoices.push({
|
||||||
|
Category: "EXC_NORMAL",
|
||||||
|
Choices: [
|
||||||
|
["Nidus", "Octavia", "Harrow"],
|
||||||
|
["Gara", "Khora", "Revenant"],
|
||||||
|
["Garuda", "Baruuk", "Hildryn"],
|
||||||
|
["Excalibur", "Trinity", "Ember"],
|
||||||
|
["Loki", "Mag", "Rhino"],
|
||||||
|
["Ash", "Frost", "Nyx"],
|
||||||
|
["Saryn", "Vauban", "Nova"],
|
||||||
|
["Nekros", "Valkyr", "Oberon"],
|
||||||
|
["Hydroid", "Mirage", "Limbo"],
|
||||||
|
["Mesa", "Chroma", "Atlas"],
|
||||||
|
["Ivara", "Inaros", "Titania"]
|
||||||
|
][week % 12]
|
||||||
|
});
|
||||||
|
worldState.EndlessXpChoices.push({
|
||||||
|
Category: "EXC_HARD",
|
||||||
|
Choices: [
|
||||||
|
["Boar", "Gammacor", "Angstrum", "Gorgon", "Anku"],
|
||||||
|
["Bo", "Latron", "Furis", "Furax", "Strun"],
|
||||||
|
["Lex", "Magistar", "Boltor", "Bronco", "CeramicDagger"],
|
||||||
|
["Torid", "DualToxocyst", "DualIchor", "Miter", "Atomos"],
|
||||||
|
["AckAndBrunt", "Soma", "Vasto", "NamiSolo", "Burston"],
|
||||||
|
["Zylok", "Sibear", "Dread", "Despair", "Hate"],
|
||||||
|
["Dera", "Sybaris", "Cestra", "Sicarus", "Okina"],
|
||||||
|
["Braton", "Lato", "Skana", "Paris", "Kunai"]
|
||||||
|
][week % 8]
|
||||||
|
});
|
||||||
|
|
||||||
|
// 1999 Calendar Season cycling every week + YearIteration every 4 weeks
|
||||||
|
worldState.KnownCalendarSeasons[0].Activation = { $date: { $numberLong: weekStart.toString() } };
|
||||||
|
worldState.KnownCalendarSeasons[0].Expiry = { $date: { $numberLong: weekEnd.toString() } };
|
||||||
|
worldState.KnownCalendarSeasons[0].Season = ["CST_WINTER", "CST_SPRING", "CST_SUMMER", "CST_FALL"][week % 4];
|
||||||
|
worldState.KnownCalendarSeasons[0].Days = [
|
||||||
|
static1999WinterDays,
|
||||||
|
static1999SpringDays,
|
||||||
|
static1999SummerDays,
|
||||||
|
static1999FallDays
|
||||||
|
][week % 4];
|
||||||
|
worldState.KnownCalendarSeasons[0].YearIteration = Math.trunc(week / 4);
|
||||||
|
|
||||||
|
// Sentient Anomaly cycling every 30 minutes
|
||||||
|
const halfHour = Math.trunc(Date.now() / (unixTimesInMs.hour / 2));
|
||||||
|
const tmp = {
|
||||||
|
cavabegin: "1690761600",
|
||||||
|
PurchasePlatformLockEnabled: true,
|
||||||
|
tcsn: true,
|
||||||
|
pgr: {
|
||||||
|
ts: "1732572900",
|
||||||
|
en: "CUSTOM DECALS @ ZEVILA",
|
||||||
|
fr: "DECALS CUSTOM @ ZEVILA",
|
||||||
|
it: "DECALCOMANIE PERSONALIZZATE @ ZEVILA",
|
||||||
|
de: "AUFKLEBER NACH WUNSCH @ ZEVILA",
|
||||||
|
es: "CALCOMANÍAS PERSONALIZADAS @ ZEVILA",
|
||||||
|
pt: "DECALQUES PERSONALIZADOS NA ZEVILA",
|
||||||
|
ru: "ПОЛЬЗОВАТЕЛЬСКИЕ НАКЛЕЙКИ @ ЗеВиЛа",
|
||||||
|
pl: "NOWE NAKLEJKI @ ZEVILA",
|
||||||
|
uk: "КОРИСТУВАЦЬКІ ДЕКОЛІ @ ЗІВІЛА",
|
||||||
|
tr: "ÖZEL ÇIKARTMALAR @ ZEVILA",
|
||||||
|
ja: "カスタムデカール @ ゼビラ",
|
||||||
|
zh: "定制贴花认准泽威拉",
|
||||||
|
ko: "커스텀 데칼 @ ZEVILA",
|
||||||
|
tc: "自訂貼花 @ ZEVILA",
|
||||||
|
th: "รูปลอกสั่งทำที่ ZEVILA"
|
||||||
|
},
|
||||||
|
ennnd: true,
|
||||||
|
mbrt: true,
|
||||||
|
sfn: [550, 553, 554, 555][halfHour % 4]
|
||||||
|
};
|
||||||
|
worldState.Tmp = JSON.stringify(tmp);
|
||||||
|
|
||||||
|
res.json(worldState);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IWorldState {
|
||||||
|
Version: number; // for goals
|
||||||
|
BuildLabel: string;
|
||||||
|
Time: number;
|
||||||
|
Goals: IGoal[];
|
||||||
|
SyndicateMissions: ISyndicateMission[];
|
||||||
|
GlobalUpgrades: IGlobalUpgrade[];
|
||||||
|
Sorties: ISortie[];
|
||||||
|
LiteSorties: ILiteSortie[];
|
||||||
|
NodeOverrides: INodeOverride[];
|
||||||
|
EndlessXpChoices: IEndlessXpChoice[];
|
||||||
|
SeasonInfo: {
|
||||||
|
Activation: IMongoDate;
|
||||||
|
Expiry: IMongoDate;
|
||||||
|
AffiliationTag: string;
|
||||||
|
Season: number;
|
||||||
|
Phase: number;
|
||||||
|
Params: string;
|
||||||
|
ActiveChallenges: ISeasonChallenge[];
|
||||||
|
};
|
||||||
|
KnownCalendarSeasons: ICalendarSeason[];
|
||||||
|
Tmp?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGoal {
|
||||||
|
_id: IOid;
|
||||||
|
Activation: IMongoDate;
|
||||||
|
Expiry: IMongoDate;
|
||||||
|
Count: number;
|
||||||
|
Goal: number;
|
||||||
|
Success: number;
|
||||||
|
Personal: boolean;
|
||||||
|
Desc: string;
|
||||||
|
ToolTip: string;
|
||||||
|
Icon: string;
|
||||||
|
Tag: string;
|
||||||
|
Node: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISyndicateMission {
|
||||||
|
_id: IOid;
|
||||||
|
Activation: IMongoDate;
|
||||||
|
Expiry: IMongoDate;
|
||||||
|
Tag: string;
|
||||||
|
Seed: number;
|
||||||
|
Nodes: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGlobalUpgrade {
|
||||||
|
_id: IOid;
|
||||||
|
Activation: IMongoDate;
|
||||||
|
ExpiryDate: IMongoDate;
|
||||||
|
UpgradeType: string;
|
||||||
|
OperationType: string;
|
||||||
|
Value: number;
|
||||||
|
LocalizeTag: string;
|
||||||
|
LocalizeDescTag: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface INodeOverride {
|
||||||
|
_id: IOid;
|
||||||
|
Activation?: IMongoDate;
|
||||||
|
Expiry?: IMongoDate;
|
||||||
|
Node: string;
|
||||||
|
Hide?: boolean;
|
||||||
|
Seed?: number;
|
||||||
|
LevelOverride?: string;
|
||||||
|
Faction?: string;
|
||||||
|
CustomNpcEncounters?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISortie {
|
||||||
|
_id: IOid;
|
||||||
|
Activation: IMongoDate;
|
||||||
|
Expiry: IMongoDate;
|
||||||
|
Reward: "/Lotus/Types/Game/MissionDecks/SortieRewards";
|
||||||
|
Seed: number;
|
||||||
|
Boss: string;
|
||||||
|
Variants: {
|
||||||
|
missionType: string;
|
||||||
|
modifierType: string;
|
||||||
|
node: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ILiteSortie {
|
||||||
|
_id: IOid;
|
||||||
|
Activation: IMongoDate;
|
||||||
|
Expiry: IMongoDate;
|
||||||
|
Reward: "/Lotus/Types/Game/MissionDecks/ArchonSortieRewards";
|
||||||
|
Seed: number;
|
||||||
|
Boss: string; // "SORTIE_BOSS_AMAR" | "SORTIE_BOSS_NIRA" | "SORTIE_BOSS_BOREAL"
|
||||||
|
Missions: {
|
||||||
|
missionType: string;
|
||||||
|
node: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IEndlessXpChoice {
|
||||||
|
Category: string;
|
||||||
|
Choices: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISeasonChallenge {
|
||||||
|
_id: IOid;
|
||||||
|
Daily?: boolean;
|
||||||
|
Activation: IMongoDate;
|
||||||
|
Expiry: IMongoDate;
|
||||||
|
Challenge: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ICalendarSeason {
|
||||||
|
Activation: IMongoDate;
|
||||||
|
Expiry: IMongoDate;
|
||||||
|
Season: string; // "CST_UNDEFINED" | "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL"
|
||||||
|
Days: {
|
||||||
|
day: number;
|
||||||
|
}[];
|
||||||
|
YearIteration: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dailyChallenges = Object.keys(ExportNightwave.challenges).filter(x =>
|
||||||
|
x.startsWith("/Lotus/Types/Challenges/Seasons/Daily/")
|
||||||
|
);
|
||||||
|
|
||||||
|
const getSeasonDailyChallenge = (day: number): ISeasonChallenge => {
|
||||||
|
const dayStart = EPOCH + day * 86400000;
|
||||||
|
const dayEnd = EPOCH + (day + 3) * 86400000;
|
||||||
|
const rng = new CRng(day);
|
||||||
|
return {
|
||||||
|
_id: { $oid: "67e1b5ca9d00cb47" + day.toString().padStart(8, "0") },
|
||||||
|
Daily: true,
|
||||||
|
Activation: { $date: { $numberLong: dayStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: dayEnd.toString() } },
|
||||||
|
Challenge: rng.randomElement(dailyChallenges)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const weeklyChallenges = Object.keys(ExportNightwave.challenges).filter(
|
||||||
|
x =>
|
||||||
|
x.startsWith("/Lotus/Types/Challenges/Seasons/Weekly/") &&
|
||||||
|
!x.startsWith("/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanent")
|
||||||
|
);
|
||||||
|
|
||||||
|
const getSeasonWeeklyChallenge = (week: number, id: number): ISeasonChallenge => {
|
||||||
|
const weekStart = EPOCH + week * 604800000;
|
||||||
|
const weekEnd = weekStart + 604800000;
|
||||||
|
const challengeId = week * 7 + id;
|
||||||
|
const rng = new CRng(challengeId);
|
||||||
|
return {
|
||||||
|
_id: { $oid: "67e1bb2d9d00cb47" + challengeId.toString().padStart(8, "0") },
|
||||||
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
|
Challenge: rng.randomElement(weeklyChallenges)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const weeklyHardChallenges = Object.keys(ExportNightwave.challenges).filter(x =>
|
||||||
|
x.startsWith("/Lotus/Types/Challenges/Seasons/WeeklyHard/")
|
||||||
|
);
|
||||||
|
|
||||||
|
const getSeasonWeeklyHardChallenge = (week: number, id: number): ISeasonChallenge => {
|
||||||
|
const weekStart = EPOCH + week * 604800000;
|
||||||
|
const weekEnd = weekStart + 604800000;
|
||||||
|
const challengeId = week * 7 + id;
|
||||||
|
const rng = new CRng(challengeId);
|
||||||
|
return {
|
||||||
|
_id: { $oid: "67e1bb2d9d00cb47" + challengeId.toString().padStart(8, "0") },
|
||||||
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
|
Challenge: rng.randomElement(weeklyHardChallenges)
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
@ -27,15 +27,7 @@ const viewController: RequestHandler = async (req, res) => {
|
|||||||
for (const type of Object.keys(ExportEnemies.avatars)) {
|
for (const type of Object.keys(ExportEnemies.avatars)) {
|
||||||
if (!scans.has(type)) scans.add(type);
|
if (!scans.has(type)) scans.add(type);
|
||||||
}
|
}
|
||||||
|
responseJson.Scans ??= [];
|
||||||
// Take any existing scans and also set them to 9999
|
|
||||||
if (responseJson.Scans) {
|
|
||||||
for (const scan of responseJson.Scans) {
|
|
||||||
scans.add(scan.type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
responseJson.Scans = [];
|
|
||||||
|
|
||||||
for (const type of scans) {
|
for (const type of scans) {
|
||||||
responseJson.Scans.push({ type: type, scans: 9999 });
|
responseJson.Scans.push({ type: type, scans: 9999 });
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { TRarity } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
export const toOid = (objectId: Types.ObjectId): IOid => {
|
export const toOid = (objectId: Types.ObjectId): IOid => {
|
||||||
return { $oid: objectId.toString() } satisfies IOid;
|
return { $oid: objectId.toString() } satisfies IOid;
|
||||||
@ -9,148 +8,3 @@ export const toOid = (objectId: Types.ObjectId): IOid => {
|
|||||||
export const toMongoDate = (date: Date): IMongoDate => {
|
export const toMongoDate = (date: Date): IMongoDate => {
|
||||||
return { $date: { $numberLong: date.getTime().toString() } };
|
return { $date: { $numberLong: date.getTime().toString() } };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fromMongoData = (date: IMongoDate): Date => {
|
|
||||||
return new Date(parseInt(date.$date.$numberLong));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const kubrowWeights: Record<TRarity, number> = {
|
|
||||||
COMMON: 6,
|
|
||||||
UNCOMMON: 4,
|
|
||||||
RARE: 2,
|
|
||||||
LEGENDARY: 1
|
|
||||||
};
|
|
||||||
|
|
||||||
export const kubrowFurPatternsWeights: Record<TRarity, number> = {
|
|
||||||
COMMON: 6,
|
|
||||||
UNCOMMON: 5,
|
|
||||||
RARE: 2,
|
|
||||||
LEGENDARY: 1
|
|
||||||
};
|
|
||||||
|
|
||||||
export const catbrowDetails = {
|
|
||||||
Colors: [
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseA", rarity: "COMMON" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseB", rarity: "COMMON" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseC", rarity: "COMMON" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseD", rarity: "COMMON" as TRarity },
|
|
||||||
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryA", rarity: "UNCOMMON" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryB", rarity: "UNCOMMON" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryC", rarity: "UNCOMMON" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryD", rarity: "UNCOMMON" as TRarity },
|
|
||||||
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryA", rarity: "RARE" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryB", rarity: "RARE" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryC", rarity: "RARE" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryD", rarity: "RARE" as TRarity },
|
|
||||||
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsA", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsB", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsC", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsD", rarity: "LEGENDARY" as TRarity }
|
|
||||||
],
|
|
||||||
|
|
||||||
EyeColors: [
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesA", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesB", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesC", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesD", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesE", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesF", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesG", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesH", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesI", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesJ", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesK", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesL", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesM", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesN", rarity: "LEGENDARY" as TRarity }
|
|
||||||
],
|
|
||||||
|
|
||||||
FurPatterns: [{ type: "/Lotus/Types/Game/CatbrowPet/Patterns/CatbrowPetPatternA", rarity: "COMMON" as TRarity }],
|
|
||||||
|
|
||||||
BodyTypes: [
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetRegularBodyType", rarity: "UNCOMMON" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetRegularBodyType", rarity: "LEGENDARY" as TRarity }
|
|
||||||
],
|
|
||||||
|
|
||||||
Heads: [
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadA", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadB", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadC", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadD", rarity: "LEGENDARY" as TRarity }
|
|
||||||
],
|
|
||||||
|
|
||||||
Tails: [
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailA", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailB", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailC", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailD", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailE", rarity: "LEGENDARY" as TRarity }
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
export const kubrowDetails = {
|
|
||||||
Colors: [
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneA", rarity: "UNCOMMON" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneB", rarity: "UNCOMMON" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneC", rarity: "UNCOMMON" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneD", rarity: "UNCOMMON" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneE", rarity: "UNCOMMON" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneF", rarity: "UNCOMMON" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneG", rarity: "UNCOMMON" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneH", rarity: "UNCOMMON" as TRarity },
|
|
||||||
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidA", rarity: "RARE" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidB", rarity: "RARE" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidC", rarity: "RARE" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidD", rarity: "RARE" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidE", rarity: "RARE" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidF", rarity: "RARE" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidG", rarity: "RARE" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidH", rarity: "RARE" as TRarity },
|
|
||||||
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantA", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantB", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantC", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantD", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantE", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantF", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantG", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantH", rarity: "LEGENDARY" as TRarity }
|
|
||||||
],
|
|
||||||
|
|
||||||
EyeColors: [
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesA", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesB", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesC", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesD", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesE", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesF", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesG", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesH", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesI", rarity: "LEGENDARY" as TRarity }
|
|
||||||
],
|
|
||||||
|
|
||||||
FurPatterns: [
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternB", rarity: "UNCOMMON" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternA", rarity: "UNCOMMON" as TRarity },
|
|
||||||
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternC", rarity: "RARE" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternD", rarity: "RARE" as TRarity },
|
|
||||||
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternE", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternF", rarity: "LEGENDARY" as TRarity }
|
|
||||||
],
|
|
||||||
|
|
||||||
BodyTypes: [
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetRegularBodyType", rarity: "UNCOMMON" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetHeavyBodyType", rarity: "LEGENDARY" as TRarity },
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetThinBodyType", rarity: "LEGENDARY" as TRarity }
|
|
||||||
],
|
|
||||||
|
|
||||||
Heads: [],
|
|
||||||
|
|
||||||
Tails: []
|
|
||||||
};
|
|
||||||
|
@ -1,14 +1,6 @@
|
|||||||
import { ExportRegions, ExportWarframes } from "warframe-public-export-plus";
|
import { ExportRegions } from "warframe-public-export-plus";
|
||||||
import { IInfNode, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IInfNode } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { getRewardAtPercentage, SRng } from "@/src/services/rngService";
|
import { SRng } from "@/src/services/rngService";
|
||||||
import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel";
|
|
||||||
import { logger } from "../utils/logger";
|
|
||||||
import { IOid } from "../types/commonTypes";
|
|
||||||
import { Types } from "mongoose";
|
|
||||||
import { addMods, generateRewardSeed } from "../services/inventoryService";
|
|
||||||
import { isArchwingMission } from "../services/worldStateService";
|
|
||||||
import { fromStoreItem, toStoreItem } from "../services/itemDataService";
|
|
||||||
import { createMessage } from "../services/inboxService";
|
|
||||||
|
|
||||||
export const getInfNodes = (faction: string, rank: number): IInfNode[] => {
|
export const getInfNodes = (faction: string, rank: number): IInfNode[] => {
|
||||||
const infNodes = [];
|
const infNodes = [];
|
||||||
@ -25,7 +17,7 @@ export const getInfNodes = (faction: string, rank: number): IInfNode[] => {
|
|||||||
value.missionIndex != 42 && // not face off
|
value.missionIndex != 42 && // not face off
|
||||||
value.name.indexOf("1999NodeI") == -1 && // not stage defence
|
value.name.indexOf("1999NodeI") == -1 && // not stage defence
|
||||||
value.name.indexOf("1999NodeJ") == -1 && // not lich bounty
|
value.name.indexOf("1999NodeJ") == -1 && // not lich bounty
|
||||||
!isArchwingMission(value)
|
value.name.indexOf("Archwing") == -1
|
||||||
) {
|
) {
|
||||||
//console.log(dict_en[value.name]);
|
//console.log(dict_en[value.name]);
|
||||||
infNodes.push({ Node: key, Influence: 1 });
|
infNodes.push({ Node: key, Influence: 1 });
|
||||||
@ -40,339 +32,13 @@ const systemIndexes: Record<string, number[]> = {
|
|||||||
FC_INFESTATION: [23]
|
FC_INFESTATION: [23]
|
||||||
};
|
};
|
||||||
|
|
||||||
export const showdownNodes: Record<string, string> = {
|
|
||||||
FC_GRINEER: "CrewBattleNode557",
|
|
||||||
FC_CORPUS: "CrewBattleNode558",
|
|
||||||
FC_INFESTATION: "CrewBattleNode559"
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get a parazon 'passcode' based on the nemesis fingerprint so it's always the same for the same nemesis.
|
// Get a parazon 'passcode' based on the nemesis fingerprint so it's always the same for the same nemesis.
|
||||||
export const getNemesisPasscode = (nemesis: { fp: bigint; Faction: string }): number[] => {
|
export const getNemesisPasscode = (fp: bigint, faction: string): number[] => {
|
||||||
const rng = new SRng(nemesis.fp);
|
const rng = new SRng(fp);
|
||||||
const choices = [0, 1, 2, 3, 5, 6, 7];
|
const passcode = [rng.randomInt(0, 7)];
|
||||||
let choiceIndex = rng.randomInt(0, choices.length - 1);
|
if (faction != "FC_INFESTATION") {
|
||||||
const passcode = [choices[choiceIndex]];
|
passcode.push(rng.randomInt(0, 7));
|
||||||
if (nemesis.Faction != "FC_INFESTATION") {
|
passcode.push(rng.randomInt(0, 7));
|
||||||
choices.splice(choiceIndex, 1);
|
|
||||||
choiceIndex = rng.randomInt(0, choices.length - 1);
|
|
||||||
passcode.push(choices[choiceIndex]);
|
|
||||||
|
|
||||||
choices.splice(choiceIndex, 1);
|
|
||||||
choiceIndex = rng.randomInt(0, choices.length - 1);
|
|
||||||
passcode.push(choices[choiceIndex]);
|
|
||||||
}
|
}
|
||||||
return passcode;
|
return passcode;
|
||||||
};
|
};
|
||||||
|
|
||||||
const reqiuemMods: readonly string[] = [
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalOneMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalTwoMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalThreeMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalFourMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalFiveMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalSixMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalSevenMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalEightMod"
|
|
||||||
];
|
|
||||||
|
|
||||||
const antivirusMods: readonly string[] = [
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusOneMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusTwoMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusThreeMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusFourMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusFiveMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusSixMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusSevenMod",
|
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusEightMod"
|
|
||||||
];
|
|
||||||
|
|
||||||
export const getNemesisPasscodeModTypes = (nemesis: { fp: bigint; Faction: string }): string[] => {
|
|
||||||
const passcode = getNemesisPasscode(nemesis);
|
|
||||||
return nemesis.Faction == "FC_INFESTATION"
|
|
||||||
? passcode.map(i => antivirusMods[i])
|
|
||||||
: passcode.map(i => reqiuemMods[i]);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const encodeNemesisGuess = (
|
|
||||||
symbol1: number,
|
|
||||||
result1: number,
|
|
||||||
symbol2: number,
|
|
||||||
result2: number,
|
|
||||||
symbol3: number,
|
|
||||||
result3: number
|
|
||||||
): number => {
|
|
||||||
return (
|
|
||||||
(symbol1 & 0xf) |
|
|
||||||
((result1 & 3) << 12) |
|
|
||||||
((symbol2 << 4) & 0xff) |
|
|
||||||
((result2 << 14) & 0xffff) |
|
|
||||||
((symbol3 & 0xf) << 8) |
|
|
||||||
((result3 & 3) << 16)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const decodeNemesisGuess = (val: number): number[] => {
|
|
||||||
return [val & 0xf, (val >> 12) & 3, (val & 0xff) >> 4, (val & 0xffff) >> 14, (val >> 8) & 0xf, (val >> 16) & 3];
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface IKnifeResponse {
|
|
||||||
UpgradeIds?: string[];
|
|
||||||
UpgradeTypes?: string[];
|
|
||||||
UpgradeFingerprints?: { lvl: number }[];
|
|
||||||
UpgradeNew?: boolean[];
|
|
||||||
HasKnife?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getKnifeUpgrade = (
|
|
||||||
inventory: TInventoryDatabaseDocument,
|
|
||||||
dataknifeUpgrades: string[],
|
|
||||||
type: string
|
|
||||||
): { ItemId: IOid; ItemType: string } => {
|
|
||||||
if (dataknifeUpgrades.indexOf(type) != -1) {
|
|
||||||
return {
|
|
||||||
ItemId: { $oid: "000000000000000000000000" },
|
|
||||||
ItemType: type
|
|
||||||
};
|
|
||||||
}
|
|
||||||
for (const upgradeId of dataknifeUpgrades) {
|
|
||||||
if (upgradeId.length == 24) {
|
|
||||||
const upgrade = inventory.Upgrades.id(upgradeId);
|
|
||||||
if (upgrade && upgrade.ItemType == type) {
|
|
||||||
return {
|
|
||||||
ItemId: { $oid: upgradeId },
|
|
||||||
ItemType: type
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new Error(`${type} does not seem to be installed on parazon?!`);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const consumeModCharge = (
|
|
||||||
response: IKnifeResponse,
|
|
||||||
inventory: TInventoryDatabaseDocument,
|
|
||||||
upgrade: { ItemId: IOid; ItemType: string },
|
|
||||||
dataknifeUpgrades: string[]
|
|
||||||
): void => {
|
|
||||||
response.UpgradeIds ??= [];
|
|
||||||
response.UpgradeTypes ??= [];
|
|
||||||
response.UpgradeFingerprints ??= [];
|
|
||||||
response.UpgradeNew ??= [];
|
|
||||||
response.HasKnife = true;
|
|
||||||
|
|
||||||
if (upgrade.ItemId.$oid != "000000000000000000000000") {
|
|
||||||
const dbUpgrade = inventory.Upgrades.id(upgrade.ItemId.$oid)!;
|
|
||||||
const fingerprint = JSON.parse(dbUpgrade.UpgradeFingerprint!) as { lvl: number };
|
|
||||||
fingerprint.lvl += 1;
|
|
||||||
dbUpgrade.UpgradeFingerprint = JSON.stringify(fingerprint);
|
|
||||||
|
|
||||||
response.UpgradeIds.push(upgrade.ItemId.$oid);
|
|
||||||
response.UpgradeTypes.push(upgrade.ItemType);
|
|
||||||
response.UpgradeFingerprints.push(fingerprint);
|
|
||||||
response.UpgradeNew.push(false);
|
|
||||||
} else {
|
|
||||||
const id = new Types.ObjectId();
|
|
||||||
inventory.Upgrades.push({
|
|
||||||
_id: id,
|
|
||||||
ItemType: upgrade.ItemType,
|
|
||||||
UpgradeFingerprint: `{"lvl":1}`
|
|
||||||
});
|
|
||||||
|
|
||||||
addMods(inventory, [
|
|
||||||
{
|
|
||||||
ItemType: upgrade.ItemType,
|
|
||||||
ItemCount: -1
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
const dataknifeRawUpgradeIndex = dataknifeUpgrades.indexOf(upgrade.ItemType);
|
|
||||||
if (dataknifeRawUpgradeIndex != -1) {
|
|
||||||
dataknifeUpgrades[dataknifeRawUpgradeIndex] = id.toString();
|
|
||||||
} else {
|
|
||||||
logger.warn(`${upgrade.ItemType} not found in dataknife config`);
|
|
||||||
}
|
|
||||||
|
|
||||||
response.UpgradeIds.push(id.toString());
|
|
||||||
response.UpgradeTypes.push(upgrade.ItemType);
|
|
||||||
response.UpgradeFingerprints.push({ lvl: 1 });
|
|
||||||
response.UpgradeNew.push(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const kuvaLichVersionSixWeapons = [
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Drakgoon/KuvaDrakgoon",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Karak/KuvaKarak",
|
|
||||||
"/Lotus/Weapons/Grineer/Melee/GrnKuvaLichScythe/GrnKuvaLichScytheWeapon",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Kohm/KuvaKohm",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Ogris/KuvaOgris",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Quartakk/KuvaQuartakk",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Tonkor/KuvaTonkor",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Brakk/KuvaBrakk",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Kraken/KuvaKraken",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Seer/KuvaSeer",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Stubba/KuvaStubba",
|
|
||||||
"/Lotus/Weapons/Grineer/HeavyWeapons/GrnHeavyGrenadeLauncher",
|
|
||||||
"/Lotus/Weapons/Grineer/LongGuns/GrnKuvaLichRifle/GrnKuvaLichRifleWeapon",
|
|
||||||
"/Lotus/Weapons/Grineer/Bows/GrnBow/GrnBowWeapon",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hind/KuvaHind",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Nukor/KuvaNukor",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hek/KuvaHekWeapon",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Zarr/KuvaZarr",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/HeavyWeapons/Grattler/KuvaGrattler",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Sobek/KuvaSobek"
|
|
||||||
];
|
|
||||||
|
|
||||||
const corpusVersionThreeWeapons = [
|
|
||||||
"/Lotus/Weapons/Corpus/LongGuns/CrpBriefcaseLauncher/CrpBriefcaseLauncher",
|
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEArcaPlasmor/CrpBEArcaPlasmor",
|
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEFluxRifle/CrpBEFluxRifle",
|
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBETetra/CrpBETetra",
|
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBECycron/CrpBECycron",
|
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEDetron/CrpBEDetron",
|
|
||||||
"/Lotus/Weapons/Corpus/Pistols/CrpIgniterPistol/CrpIgniterPistol",
|
|
||||||
"/Lotus/Weapons/Corpus/Pistols/CrpBriefcaseAkimbo/CrpBriefcaseAkimboPistol",
|
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEPlinx/CrpBEPlinxWeapon",
|
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEGlaxion/CrpBEGlaxion"
|
|
||||||
];
|
|
||||||
|
|
||||||
export const getWeaponsForManifest = (manifest: string): readonly string[] => {
|
|
||||||
switch (manifest) {
|
|
||||||
case "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionSix":
|
|
||||||
return kuvaLichVersionSixWeapons;
|
|
||||||
case "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionThree":
|
|
||||||
case "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionFour":
|
|
||||||
return corpusVersionThreeWeapons;
|
|
||||||
}
|
|
||||||
throw new Error(`unknown nemesis manifest: ${manifest}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getInnateDamageTag = (
|
|
||||||
KillingSuit: string
|
|
||||||
):
|
|
||||||
| "InnateElectricityDamage"
|
|
||||||
| "InnateFreezeDamage"
|
|
||||||
| "InnateHeatDamage"
|
|
||||||
| "InnateImpactDamage"
|
|
||||||
| "InnateMagDamage"
|
|
||||||
| "InnateRadDamage"
|
|
||||||
| "InnateToxinDamage" => {
|
|
||||||
return ExportWarframes[KillingSuit].nemesisUpgradeTag!;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: For -1399275245665749231n, the value should be 75306944, but we're off by 59 with 75307003.
|
|
||||||
export const getInnateDamageValue = (fp: bigint): number => {
|
|
||||||
const rng = new SRng(fp);
|
|
||||||
rng.randomFloat(); // used for the weapon index
|
|
||||||
const WeaponUpgradeValueAttenuationExponent = 2.25;
|
|
||||||
let value = Math.pow(rng.randomFloat(), WeaponUpgradeValueAttenuationExponent);
|
|
||||||
if (value >= 0.941428) {
|
|
||||||
value = 1;
|
|
||||||
}
|
|
||||||
return Math.trunc(value * 0x40000000);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getKillTokenRewardCount = (fp: bigint): number => {
|
|
||||||
const rng = new SRng(fp);
|
|
||||||
return rng.randomInt(10, 15);
|
|
||||||
};
|
|
||||||
|
|
||||||
// /Lotus/Types/Enemies/InfestedLich/InfestedLichRewardManifest
|
|
||||||
const infestedLichRotA = [
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDJRomHuman", probability: 0.046 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDJRomInfested", probability: 0.045 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDrillbitHuman", probability: 0.046 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDrillbitInfested", probability: 0.045 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyHarddriveHuman", probability: 0.046 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyHarddriveInfested", probability: 0.045 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyPacketHuman", probability: 0.046 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyPacketInfested", probability: 0.045 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyZekeHuman", probability: 0.046 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyZekeInfested", probability: 0.045 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandBillboardPosterA", probability: 0.045 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandBillboardPosterB", probability: 0.046 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandDespairPoster", probability: 0.045 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandGridPoster", probability: 0.046 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandHuddlePoster", probability: 0.045 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandJumpPoster", probability: 0.046 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandLimoPoster", probability: 0.045 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandLookingDownPosterDay", probability: 0.046 },
|
|
||||||
{
|
|
||||||
type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandLookingDownPosterNight",
|
|
||||||
probability: 0.045
|
|
||||||
},
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandSillyPoster", probability: 0.046 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandWhiteBluePoster", probability: 0.045 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandWhitePinkPoster", probability: 0.045 }
|
|
||||||
];
|
|
||||||
const infestedLichRotB = [
|
|
||||||
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraA", probability: 0.072 },
|
|
||||||
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraB", probability: 0.071 },
|
|
||||||
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraC", probability: 0.072 },
|
|
||||||
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraD", probability: 0.071 },
|
|
||||||
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraE", probability: 0.072 },
|
|
||||||
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraF", probability: 0.071 },
|
|
||||||
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraG", probability: 0.071 },
|
|
||||||
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraH", probability: 0.072 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/Emotes/DanceDJRomHype", probability: 0.071 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/Emotes/DancePacketWindmillShuffle", probability: 0.072 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/Emotes/DanceHarddrivePony", probability: 0.071 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/Emotes/DanceDrillbitCrisscross", probability: 0.072 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/Emotes/DanceZekeCanthavethis", probability: 0.071 },
|
|
||||||
{ type: "/Lotus/StoreItems/Types/Items/PhotoBooth/PhotoboothTileRJLasXStadiumBossArena", probability: 0.071 }
|
|
||||||
];
|
|
||||||
export const getInfestedLichItemRewards = (fp: bigint): string[] => {
|
|
||||||
const rng = new SRng(fp);
|
|
||||||
const rotAReward = getRewardAtPercentage(infestedLichRotA, rng.randomFloat())!.type;
|
|
||||||
rng.randomFloat(); // unused afaict
|
|
||||||
const rotBReward = getRewardAtPercentage(infestedLichRotB, rng.randomFloat())!.type;
|
|
||||||
return [rotAReward, rotBReward];
|
|
||||||
};
|
|
||||||
|
|
||||||
export const sendCodaFinishedMessage = async (
|
|
||||||
inventory: TInventoryDatabaseDocument,
|
|
||||||
fp: bigint = generateRewardSeed(),
|
|
||||||
name: string = "ZEKE_BEATWOMAN_TM.1999",
|
|
||||||
killed: boolean = true
|
|
||||||
): Promise<void> => {
|
|
||||||
const att: string[] = [];
|
|
||||||
|
|
||||||
// First vanquish/convert gives a sigil
|
|
||||||
const sigil = killed
|
|
||||||
? "/Lotus/Upgrades/Skins/Sigils/InfLichVanquishedSigil"
|
|
||||||
: "/Lotus/Upgrades/Skins/Sigils/InfLichConvertedSigil";
|
|
||||||
if (!inventory.WeaponSkins.find(x => x.ItemType == sigil)) {
|
|
||||||
att.push(toStoreItem(sigil));
|
|
||||||
}
|
|
||||||
|
|
||||||
const [rotAReward, rotBReward] = getInfestedLichItemRewards(fp);
|
|
||||||
att.push(fromStoreItem(rotAReward));
|
|
||||||
att.push(fromStoreItem(rotBReward));
|
|
||||||
|
|
||||||
let countedAtt: ITypeCount[] | undefined;
|
|
||||||
if (killed) {
|
|
||||||
countedAtt = [
|
|
||||||
{
|
|
||||||
ItemType: "/Lotus/Types/Items/MiscItems/CodaWeaponBucks",
|
|
||||||
ItemCount: getKillTokenRewardCount(fp)
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
await createMessage(inventory.accountOwnerId, [
|
|
||||||
{
|
|
||||||
sndr: "/Lotus/Language/Bosses/Ordis",
|
|
||||||
msg: "/Lotus/Language/Inbox/VanquishBandMsgBody",
|
|
||||||
arg: [
|
|
||||||
{
|
|
||||||
Key: "LICH_NAME",
|
|
||||||
Tag: name
|
|
||||||
}
|
|
||||||
],
|
|
||||||
att: att,
|
|
||||||
countedAtt: countedAtt,
|
|
||||||
sub: "/Lotus/Language/Inbox/VanquishBandMsgTitle",
|
|
||||||
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
|
|
||||||
highPriority: true
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
@ -31,7 +31,7 @@ export interface IFingerprintStat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const createVeiledRivenFingerprint = (meta: IUpgrade): IVeiledRivenFingerprint => {
|
export const createVeiledRivenFingerprint = (meta: IUpgrade): IVeiledRivenFingerprint => {
|
||||||
const challenge = getRandomElement(meta.availableChallenges!)!;
|
const challenge = getRandomElement(meta.availableChallenges!);
|
||||||
const fingerprintChallenge: IRivenChallenge = {
|
const fingerprintChallenge: IRivenChallenge = {
|
||||||
Type: challenge.fullName,
|
Type: challenge.fullName,
|
||||||
Progress: 0,
|
Progress: 0,
|
||||||
@ -54,11 +54,11 @@ export const createVeiledRivenFingerprint = (meta: IUpgrade): IVeiledRivenFinger
|
|||||||
|
|
||||||
export const createUnveiledRivenFingerprint = (meta: IUpgrade): IUnveiledRivenFingerprint => {
|
export const createUnveiledRivenFingerprint = (meta: IUpgrade): IUnveiledRivenFingerprint => {
|
||||||
const fingerprint: IUnveiledRivenFingerprint = {
|
const fingerprint: IUnveiledRivenFingerprint = {
|
||||||
compat: getRandomElement(meta.compatibleItems!)!,
|
compat: getRandomElement(meta.compatibleItems!),
|
||||||
lim: 0,
|
lim: 0,
|
||||||
lvl: 0,
|
lvl: 0,
|
||||||
lvlReq: getRandomInt(8, 16),
|
lvlReq: getRandomInt(8, 16),
|
||||||
pol: getRandomElement(["AP_ATTACK", "AP_DEFENSE", "AP_TACTIC"])!,
|
pol: getRandomElement(["AP_ATTACK", "AP_DEFENSE", "AP_TACTIC"]),
|
||||||
buffs: [],
|
buffs: [],
|
||||||
curses: []
|
curses: []
|
||||||
};
|
};
|
||||||
@ -81,7 +81,7 @@ export const randomiseRivenStats = (meta: IUpgrade, fingerprint: IUnveiledRivenF
|
|||||||
if (Math.random() < 0.5) {
|
if (Math.random() < 0.5) {
|
||||||
const entry = getRandomElement(
|
const entry = getRandomElement(
|
||||||
meta.upgradeEntries!.filter(x => x.canBeCurse && !fingerprint.buffs.find(y => y.Tag == x.tag))
|
meta.upgradeEntries!.filter(x => x.canBeCurse && !fingerprint.buffs.find(y => y.Tag == x.tag))
|
||||||
)!;
|
);
|
||||||
fingerprint.curses.push({ Tag: entry.tag, Value: Math.trunc(Math.random() * 0x40000000) });
|
fingerprint.curses.push({ Tag: entry.tag, Value: Math.trunc(Math.random() * 0x40000000) });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
130
src/helpers/worlstateHelper.ts
Normal file
130
src/helpers/worlstateHelper.ts
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
export const missionTags = [
|
||||||
|
"MT_ASSASSINATION",
|
||||||
|
"MT_EXTERMINATION",
|
||||||
|
"MT_SURVIVAL",
|
||||||
|
"MT_RESCUE",
|
||||||
|
"MT_SABOTAGE",
|
||||||
|
"MT_CAPTURE",
|
||||||
|
"MT_COUNTER_INTEL",
|
||||||
|
"MT_INTEL",
|
||||||
|
"MT_DEFENSE",
|
||||||
|
"MT_MOBILE_DEFENSE",
|
||||||
|
"MT_PVP",
|
||||||
|
"MT_MASTERY",
|
||||||
|
"MT_RECOVERY",
|
||||||
|
"MT_TERRITORY",
|
||||||
|
"MT_RETRIEVAL",
|
||||||
|
"MT_HIVE",
|
||||||
|
"MT_SALVAGE",
|
||||||
|
"MT_EXCAVATE",
|
||||||
|
"MT_RAID",
|
||||||
|
"MT_PURGE",
|
||||||
|
"MT_GENERIC",
|
||||||
|
"MT_PURIFY",
|
||||||
|
"MT_ARENA",
|
||||||
|
"MT_JUNCTION",
|
||||||
|
"MT_PURSUIT",
|
||||||
|
"MT_RACE",
|
||||||
|
"MT_ASSAULT",
|
||||||
|
"MT_EVACUATION",
|
||||||
|
"MT_LANDSCAPE",
|
||||||
|
"MT_RESOURCE_THEFT",
|
||||||
|
"MT_ENDLESS_EXTERMINATION",
|
||||||
|
"MT_ENDLESS_DUVIRI",
|
||||||
|
"MT_RAILJACK",
|
||||||
|
"MT_ARTIFACT",
|
||||||
|
"MT_CORRUPTION",
|
||||||
|
"MT_VOID_CASCADE",
|
||||||
|
"MT_ARMAGEDDON",
|
||||||
|
"MT_VAULTS",
|
||||||
|
"MT_ALCHEMY",
|
||||||
|
"MT_ASCENSION",
|
||||||
|
"MT_ENDLESS_CAPTURE",
|
||||||
|
"MT_OFFERING",
|
||||||
|
"MT_PVPVE"
|
||||||
|
];
|
||||||
|
|
||||||
|
export const sortieBosses = [
|
||||||
|
"SORTIE_BOSS_HYENA",
|
||||||
|
"SORTIE_BOSS_KELA",
|
||||||
|
"SORTIE_BOSS_VOR",
|
||||||
|
"SORTIE_BOSS_RUK",
|
||||||
|
"SORTIE_BOSS_HEK",
|
||||||
|
"SORTIE_BOSS_KRIL",
|
||||||
|
"SORTIE_BOSS_TYL",
|
||||||
|
"SORTIE_BOSS_JACKAL",
|
||||||
|
"SORTIE_BOSS_ALAD",
|
||||||
|
"SORTIE_BOSS_AMBULAS",
|
||||||
|
"SORTIE_BOSS_NEF",
|
||||||
|
"SORTIE_BOSS_RAPTOR",
|
||||||
|
"SORTIE_BOSS_PHORID",
|
||||||
|
"SORTIE_BOSS_LEPHANTIS",
|
||||||
|
"SORTIE_BOSS_INFALAD",
|
||||||
|
"SORTIE_BOSS_CORRUPTED_VOR"
|
||||||
|
];
|
||||||
|
|
||||||
|
export const sortieBossToFaction: Record<string, string> = {
|
||||||
|
SORTIE_BOSS_HYENA: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_KELA: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_VOR: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_RUK: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_HEK: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_KRIL: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_TYL: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_JACKAL: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_ALAD: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_AMBULAS: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_NEF: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_RAPTOR: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_PHORID: "FC_INFESTATION",
|
||||||
|
SORTIE_BOSS_LEPHANTIS: "FC_INFESTATION",
|
||||||
|
SORTIE_BOSS_INFALAD: "FC_INFESTATION",
|
||||||
|
SORTIE_BOSS_CORRUPTED_VOR: "FC_CORRUPTED"
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sortieFactionToSystemIndexes: Record<string, number[]> = {
|
||||||
|
FC_GRINEER: [0, 2, 3, 5, 6, 9, 11, 18],
|
||||||
|
FC_CORPUS: [1, 4, 7, 8, 12, 15],
|
||||||
|
FC_INFESTATION: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15],
|
||||||
|
FC_CORRUPTED: [14]
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sortieFactionToFactionIndexes: Record<string, number[]> = {
|
||||||
|
FC_GRINEER: [0],
|
||||||
|
FC_CORPUS: [1],
|
||||||
|
FC_INFESTATION: [0, 1, 2],
|
||||||
|
FC_CORRUPTED: [3]
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sortieBossNode: Record<string, string> = {
|
||||||
|
SORTIE_BOSS_HYENA: "SolNode127",
|
||||||
|
SORTIE_BOSS_KELA: "SolNode193",
|
||||||
|
SORTIE_BOSS_VOR: "SolNode108",
|
||||||
|
SORTIE_BOSS_RUK: "SolNode32",
|
||||||
|
SORTIE_BOSS_HEK: "SolNode24",
|
||||||
|
SORTIE_BOSS_KRIL: "SolNode99",
|
||||||
|
SORTIE_BOSS_TYL: "SolNode105",
|
||||||
|
SORTIE_BOSS_JACKAL: "SolNode104",
|
||||||
|
SORTIE_BOSS_ALAD: "SolNode53",
|
||||||
|
SORTIE_BOSS_AMBULAS: "SolNode51",
|
||||||
|
SORTIE_BOSS_NEF: "SettlementNode20",
|
||||||
|
SORTIE_BOSS_RAPTOR: "SolNode210",
|
||||||
|
SORTIE_BOSS_LEPHANTIS: "SolNode712",
|
||||||
|
SORTIE_BOSS_INFALAD: "SolNode705"
|
||||||
|
};
|
||||||
|
|
||||||
|
export const EPOCH = 1734307200 * 1000; // Monday, Dec 16, 2024 @ 00:00 UTC+0; should logically be winter in 1999 iteration 0
|
||||||
|
|
||||||
|
export const getSortieTime = (day: number): number => {
|
||||||
|
const dayStart = EPOCH + day * 86400000;
|
||||||
|
const date = new Date(dayStart);
|
||||||
|
date.setUTCHours(12);
|
||||||
|
const isDst = new Intl.DateTimeFormat("en-US", {
|
||||||
|
timeZone: "America/Toronto",
|
||||||
|
timeZoneName: "short"
|
||||||
|
})
|
||||||
|
.formatToParts(date)
|
||||||
|
.find(part => part.type === "timeZoneName")!
|
||||||
|
.value.includes("DT");
|
||||||
|
return dayStart + (isDst ? 16 : 17) * 3600000;
|
||||||
|
};
|
@ -23,7 +23,6 @@ const dojoDecoSchema = new Schema<IDojoDecoDatabase>({
|
|||||||
Type: String,
|
Type: String,
|
||||||
Pos: [Number],
|
Pos: [Number],
|
||||||
Rot: [Number],
|
Rot: [Number],
|
||||||
Scale: Number,
|
|
||||||
Name: String,
|
Name: String,
|
||||||
Sockets: Number,
|
Sockets: Number,
|
||||||
RegularCredits: Number,
|
RegularCredits: Number,
|
||||||
@ -44,7 +43,6 @@ const dojoLeaderboardEntrySchema = new Schema<IDojoLeaderboardEntry>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const dojoComponentSchema = new Schema<IDojoComponentDatabase>({
|
const dojoComponentSchema = new Schema<IDojoComponentDatabase>({
|
||||||
SortId: Schema.Types.ObjectId,
|
|
||||||
pf: { type: String, required: true },
|
pf: { type: String, required: true },
|
||||||
ppf: String,
|
ppf: String,
|
||||||
pi: Schema.Types.ObjectId,
|
pi: Schema.Types.ObjectId,
|
||||||
@ -192,7 +190,6 @@ const guildSchema = new Schema<IGuildDatabase>(
|
|||||||
VaultMiscItems: { type: [typeCountSchema], default: undefined },
|
VaultMiscItems: { type: [typeCountSchema], default: undefined },
|
||||||
VaultShipDecorations: { type: [typeCountSchema], default: undefined },
|
VaultShipDecorations: { type: [typeCountSchema], default: undefined },
|
||||||
VaultFusionTreasures: { type: [fusionTreasuresSchema], default: undefined },
|
VaultFusionTreasures: { type: [fusionTreasuresSchema], default: undefined },
|
||||||
VaultDecoRecipes: { type: [typeCountSchema], default: undefined },
|
|
||||||
TechProjects: { type: [techProjectSchema], default: undefined },
|
TechProjects: { type: [techProjectSchema], default: undefined },
|
||||||
ActiveDojoColorResearch: { type: String, default: "" },
|
ActiveDojoColorResearch: { type: String, default: "" },
|
||||||
Class: { type: Number, default: 0 },
|
Class: { type: Number, default: 0 },
|
||||||
|
@ -5,7 +5,7 @@ import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
|||||||
import { ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
|
||||||
export interface IMessageClient
|
export interface IMessageClient
|
||||||
extends Omit<IMessageDatabase, "_id" | "date" | "startDate" | "endDate" | "ownerId" | "attVisualOnly" | "expiry"> {
|
extends Omit<IMessageDatabase, "_id" | "date" | "startDate" | "endDate" | "ownerId" | "attVisualOnly"> {
|
||||||
_id?: IOid;
|
_id?: IOid;
|
||||||
date: IMongoDate;
|
date: IMongoDate;
|
||||||
startDate?: IMongoDate;
|
startDate?: IMongoDate;
|
||||||
@ -16,8 +16,6 @@ export interface IMessageClient
|
|||||||
export interface IMessageDatabase extends IMessage {
|
export interface IMessageDatabase extends IMessage {
|
||||||
ownerId: Types.ObjectId;
|
ownerId: Types.ObjectId;
|
||||||
date: Date; //created at
|
date: Date; //created at
|
||||||
attVisualOnly?: boolean;
|
|
||||||
expiry?: Date;
|
|
||||||
_id: Types.ObjectId;
|
_id: Types.ObjectId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,6 +30,7 @@ export interface IMessage {
|
|||||||
endDate?: Date;
|
endDate?: Date;
|
||||||
att?: string[];
|
att?: string[];
|
||||||
countedAtt?: ITypeCount[];
|
countedAtt?: ITypeCount[];
|
||||||
|
attVisualOnly?: boolean;
|
||||||
transmission?: string;
|
transmission?: string;
|
||||||
arg?: Arg[];
|
arg?: Arg[];
|
||||||
gifts?: IGift[];
|
gifts?: IGift[];
|
||||||
@ -138,14 +137,14 @@ messageSchema.virtual("messageId").get(function (this: IMessageDatabase) {
|
|||||||
messageSchema.set("toJSON", {
|
messageSchema.set("toJSON", {
|
||||||
virtuals: true,
|
virtuals: true,
|
||||||
transform(_document, returnedObject) {
|
transform(_document, returnedObject) {
|
||||||
|
delete returnedObject.ownerId;
|
||||||
|
|
||||||
const messageDatabase = returnedObject as IMessageDatabase;
|
const messageDatabase = returnedObject as IMessageDatabase;
|
||||||
const messageClient = returnedObject as IMessageClient;
|
const messageClient = returnedObject as IMessageClient;
|
||||||
|
|
||||||
delete returnedObject._id;
|
delete returnedObject._id;
|
||||||
delete returnedObject.__v;
|
delete returnedObject.__v;
|
||||||
delete returnedObject.ownerId;
|
|
||||||
delete returnedObject.attVisualOnly;
|
delete returnedObject.attVisualOnly;
|
||||||
delete returnedObject.expiry;
|
|
||||||
|
|
||||||
messageClient.date = toMongoDate(messageDatabase.date);
|
messageClient.date = toMongoDate(messageDatabase.date);
|
||||||
|
|
||||||
@ -158,6 +157,5 @@ messageSchema.set("toJSON", {
|
|||||||
});
|
});
|
||||||
|
|
||||||
messageSchema.index({ ownerId: 1 });
|
messageSchema.index({ ownerId: 1 });
|
||||||
messageSchema.index({ expiry: 1 }, { expireAfterSeconds: 0 });
|
|
||||||
|
|
||||||
export const Inbox = model<IMessageDatabase>("Inbox", messageSchema, "inbox");
|
export const Inbox = model<IMessageDatabase>("Inbox", messageSchema, "inbox");
|
||||||
|
@ -39,9 +39,10 @@ import {
|
|||||||
ILoreFragmentScan,
|
ILoreFragmentScan,
|
||||||
IEvolutionProgress,
|
IEvolutionProgress,
|
||||||
IEndlessXpProgress,
|
IEndlessXpProgress,
|
||||||
|
ICrewShipPortGuns,
|
||||||
ICrewShipCustomization,
|
ICrewShipCustomization,
|
||||||
ICrewShipWeapon,
|
ICrewShipWeapon,
|
||||||
ICrewShipWeaponEmplacements,
|
ICrewShipPilotWeapon,
|
||||||
IShipExterior,
|
IShipExterior,
|
||||||
IHelminthFoodRecord,
|
IHelminthFoodRecord,
|
||||||
ICrewShipMembersDatabase,
|
ICrewShipMembersDatabase,
|
||||||
@ -83,21 +84,7 @@ import {
|
|||||||
IInfNode,
|
IInfNode,
|
||||||
IDiscoveredMarker,
|
IDiscoveredMarker,
|
||||||
IWeeklyMission,
|
IWeeklyMission,
|
||||||
ILockedWeaponGroupDatabase,
|
ILockedWeaponGroupDatabase
|
||||||
IPersonalTechProjectDatabase,
|
|
||||||
IPersonalTechProjectClient,
|
|
||||||
ILastSortieRewardDatabase,
|
|
||||||
ILastSortieRewardClient,
|
|
||||||
ICrewMemberSkill,
|
|
||||||
ICrewMemberSkillEfficiency,
|
|
||||||
ICrewMemberDatabase,
|
|
||||||
ICrewMemberClient,
|
|
||||||
ISortieRewardAttenuation,
|
|
||||||
IInvasionProgressDatabase,
|
|
||||||
IInvasionProgressClient,
|
|
||||||
IAccolades,
|
|
||||||
IHubNpcCustomization,
|
|
||||||
ILotusCustomization
|
|
||||||
} from "../../types/inventoryTypes/inventoryTypes";
|
} from "../../types/inventoryTypes/inventoryTypes";
|
||||||
import { IOid } from "../../types/commonTypes";
|
import { IOid } from "../../types/commonTypes";
|
||||||
import {
|
import {
|
||||||
@ -111,7 +98,7 @@ import {
|
|||||||
IEquipmentClient
|
IEquipmentClient
|
||||||
} from "@/src/types/inventoryTypes/commonInventoryTypes";
|
} from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
|
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
import { EquipmentSelectionSchema, oidSchema } from "./loadoutModel";
|
import { EquipmentSelectionSchema } from "./loadoutModel";
|
||||||
|
|
||||||
export const typeCountSchema = new Schema<ITypeCount>({ ItemType: String, ItemCount: Number }, { _id: false });
|
export const typeCountSchema = new Schema<ITypeCount>({ ItemType: String, ItemCount: Number }, { _id: false });
|
||||||
|
|
||||||
@ -303,55 +290,6 @@ upgradeSchema.set("toJSON", {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const crewMemberSkillSchema = new Schema<ICrewMemberSkill>(
|
|
||||||
{
|
|
||||||
Assigned: Number
|
|
||||||
},
|
|
||||||
{ _id: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
const crewMemberSkillEfficiencySchema = new Schema<ICrewMemberSkillEfficiency>(
|
|
||||||
{
|
|
||||||
PILOTING: crewMemberSkillSchema,
|
|
||||||
GUNNERY: crewMemberSkillSchema,
|
|
||||||
ENGINEERING: crewMemberSkillSchema,
|
|
||||||
COMBAT: crewMemberSkillSchema,
|
|
||||||
SURVIVABILITY: crewMemberSkillSchema
|
|
||||||
},
|
|
||||||
{ _id: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
const crewMemberSchema = new Schema<ICrewMemberDatabase>(
|
|
||||||
{
|
|
||||||
ItemType: { type: String, required: true },
|
|
||||||
NemesisFingerprint: { type: BigInt, default: 0n },
|
|
||||||
Seed: { type: BigInt, default: 0n },
|
|
||||||
AssignedRole: Number,
|
|
||||||
SkillEfficiency: crewMemberSkillEfficiencySchema,
|
|
||||||
WeaponConfigIdx: Number,
|
|
||||||
WeaponId: { type: Schema.Types.ObjectId, default: "000000000000000000000000" },
|
|
||||||
XP: { type: Number, default: 0 },
|
|
||||||
PowersuitType: { type: String, required: true },
|
|
||||||
Configs: [ItemConfigSchema],
|
|
||||||
SecondInCommand: { type: Boolean, default: false }
|
|
||||||
},
|
|
||||||
{ id: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
crewMemberSchema.set("toJSON", {
|
|
||||||
virtuals: true,
|
|
||||||
transform(_doc, obj) {
|
|
||||||
const db = obj as ICrewMemberDatabase;
|
|
||||||
const client = obj as ICrewMemberClient;
|
|
||||||
|
|
||||||
client.WeaponId = toOid(db.WeaponId);
|
|
||||||
client.ItemId = toOid(db._id);
|
|
||||||
|
|
||||||
delete obj._id;
|
|
||||||
delete obj.__v;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const slotsBinSchema = new Schema<ISlots>(
|
const slotsBinSchema = new Schema<ISlots>(
|
||||||
{
|
{
|
||||||
Slots: Number,
|
Slots: Number,
|
||||||
@ -391,8 +329,8 @@ MailboxSchema.set("toJSON", {
|
|||||||
|
|
||||||
const DuviriInfoSchema = new Schema<IDuviriInfo>(
|
const DuviriInfoSchema = new Schema<IDuviriInfo>(
|
||||||
{
|
{
|
||||||
Seed: { type: BigInt, required: true },
|
Seed: Number,
|
||||||
NumCompletions: { type: Number, required: true }
|
NumCompletions: { type: Number, default: 0 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_id: false,
|
_id: false,
|
||||||
@ -560,39 +498,7 @@ const seasonChallengeHistorySchema = new Schema<ISeasonChallenge>(
|
|||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
const personalTechProjectSchema = new Schema<IPersonalTechProjectDatabase>({
|
//TODO: check whether this is complete
|
||||||
State: Number,
|
|
||||||
ReqCredits: Number,
|
|
||||||
ItemType: String,
|
|
||||||
ProductCategory: String,
|
|
||||||
CategoryItemId: Schema.Types.ObjectId,
|
|
||||||
ReqItems: { type: [typeCountSchema], default: undefined },
|
|
||||||
HasContributions: Boolean,
|
|
||||||
CompletionDate: Date
|
|
||||||
});
|
|
||||||
|
|
||||||
personalTechProjectSchema.virtual("ItemId").get(function () {
|
|
||||||
return { $oid: this._id.toString() };
|
|
||||||
});
|
|
||||||
|
|
||||||
personalTechProjectSchema.set("toJSON", {
|
|
||||||
virtuals: true,
|
|
||||||
transform(_doc, ret, _options) {
|
|
||||||
delete ret._id;
|
|
||||||
delete ret.__v;
|
|
||||||
|
|
||||||
const db = ret as IPersonalTechProjectDatabase;
|
|
||||||
const client = ret as IPersonalTechProjectClient;
|
|
||||||
|
|
||||||
if (db.CategoryItemId) {
|
|
||||||
client.CategoryItemId = toOid(db.CategoryItemId);
|
|
||||||
}
|
|
||||||
if (db.CompletionDate) {
|
|
||||||
client.CompletionDate = toMongoDate(db.CompletionDate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const playerSkillsSchema = new Schema<IPlayerSkills>(
|
const playerSkillsSchema = new Schema<IPlayerSkills>(
|
||||||
{
|
{
|
||||||
LPP_SPACE: { type: Number, default: 0 },
|
LPP_SPACE: { type: Number, default: 0 },
|
||||||
@ -689,27 +595,6 @@ questKeysSchema.set("toJSON", {
|
|||||||
|
|
||||||
export const fusionTreasuresSchema = new Schema<IFusionTreasure>().add(typeCountSchema).add({ Sockets: Number });
|
export const fusionTreasuresSchema = new Schema<IFusionTreasure>().add(typeCountSchema).add({ Sockets: Number });
|
||||||
|
|
||||||
const invasionProgressSchema = new Schema<IInvasionProgressDatabase>(
|
|
||||||
{
|
|
||||||
invasionId: Schema.Types.ObjectId,
|
|
||||||
Delta: Number,
|
|
||||||
AttackerScore: Number,
|
|
||||||
DefenderScore: Number
|
|
||||||
},
|
|
||||||
{ _id: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
invasionProgressSchema.set("toJSON", {
|
|
||||||
transform(_doc, obj) {
|
|
||||||
const db = obj as IInvasionProgressDatabase;
|
|
||||||
const client = obj as IInvasionProgressClient;
|
|
||||||
|
|
||||||
client._id = toOid(db.invasionId);
|
|
||||||
delete obj.invasionId;
|
|
||||||
delete obj.__v;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const spectreLoadoutsSchema = new Schema<ISpectreLoadout>(
|
const spectreLoadoutsSchema = new Schema<ISpectreLoadout>(
|
||||||
{
|
{
|
||||||
ItemType: String,
|
ItemType: String,
|
||||||
@ -727,7 +612,6 @@ const spectreLoadoutsSchema = new Schema<ISpectreLoadout>(
|
|||||||
const weaponSkinsSchema = new Schema<IWeaponSkinDatabase>(
|
const weaponSkinsSchema = new Schema<IWeaponSkinDatabase>(
|
||||||
{
|
{
|
||||||
ItemType: String,
|
ItemType: String,
|
||||||
Favorite: Boolean,
|
|
||||||
IsNew: Boolean
|
IsNew: Boolean
|
||||||
},
|
},
|
||||||
{ id: false }
|
{ id: false }
|
||||||
@ -781,26 +665,6 @@ const loreFragmentScansSchema = new Schema<ILoreFragmentScan>(
|
|||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
// const lotusCustomizationSchema = new Schema<ILotusCustomization>().add(ItemConfigSchema).add({
|
|
||||||
// Persona: String
|
|
||||||
// });
|
|
||||||
|
|
||||||
// Laxer schema for cleanupInventory
|
|
||||||
const lotusCustomizationSchema = new Schema<ILotusCustomization>(
|
|
||||||
{
|
|
||||||
Skins: [String],
|
|
||||||
pricol: colorSchema,
|
|
||||||
attcol: Schema.Types.Mixed,
|
|
||||||
sigcol: Schema.Types.Mixed,
|
|
||||||
eyecol: Schema.Types.Mixed,
|
|
||||||
facial: Schema.Types.Mixed,
|
|
||||||
cloth: Schema.Types.Mixed,
|
|
||||||
syancol: Schema.Types.Mixed,
|
|
||||||
Persona: String
|
|
||||||
},
|
|
||||||
{ _id: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
const evolutionProgressSchema = new Schema<IEvolutionProgress>(
|
const evolutionProgressSchema = new Schema<IEvolutionProgress>(
|
||||||
{
|
{
|
||||||
Progress: Number,
|
Progress: Number,
|
||||||
@ -818,23 +682,25 @@ const endlessXpProgressSchema = new Schema<IEndlessXpProgress>(
|
|||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
const crewShipWeaponEmplacementsSchema = new Schema<ICrewShipWeaponEmplacements>(
|
const crewShipPilotWeaponSchema = new Schema<ICrewShipPilotWeapon>(
|
||||||
{
|
{
|
||||||
PRIMARY_A: EquipmentSelectionSchema,
|
PRIMARY_A: EquipmentSelectionSchema,
|
||||||
PRIMARY_B: EquipmentSelectionSchema,
|
SECONDARY_A: EquipmentSelectionSchema
|
||||||
SECONDARY_A: EquipmentSelectionSchema,
|
},
|
||||||
SECONDARY_B: EquipmentSelectionSchema
|
{ _id: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
const crewShipPortGunsSchema = new Schema<ICrewShipPortGuns>(
|
||||||
|
{
|
||||||
|
PRIMARY_A: EquipmentSelectionSchema
|
||||||
},
|
},
|
||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
const crewShipWeaponSchema = new Schema<ICrewShipWeapon>(
|
const crewShipWeaponSchema = new Schema<ICrewShipWeapon>(
|
||||||
{
|
{
|
||||||
PILOT: crewShipWeaponEmplacementsSchema,
|
PILOT: crewShipPilotWeaponSchema,
|
||||||
PORT_GUNS: crewShipWeaponEmplacementsSchema,
|
PORT_GUNS: crewShipPortGunsSchema
|
||||||
STARBOARD_GUNS: crewShipWeaponEmplacementsSchema,
|
|
||||||
ARTILLERY: crewShipWeaponEmplacementsSchema,
|
|
||||||
SCANNER: crewShipWeaponEmplacementsSchema
|
|
||||||
},
|
},
|
||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
@ -858,7 +724,7 @@ const crewShipCustomizationSchema = new Schema<ICrewShipCustomization>(
|
|||||||
const crewShipMemberSchema = new Schema<ICrewShipMemberDatabase>(
|
const crewShipMemberSchema = new Schema<ICrewShipMemberDatabase>(
|
||||||
{
|
{
|
||||||
ItemId: { type: Schema.Types.ObjectId, required: false },
|
ItemId: { type: Schema.Types.ObjectId, required: false },
|
||||||
NemesisFingerprint: { type: BigInt, required: false }
|
NemesisFingerprint: { type: Number, required: false }
|
||||||
},
|
},
|
||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
@ -930,7 +796,7 @@ dialogueSchema.set("toJSON", {
|
|||||||
|
|
||||||
const dialogueHistorySchema = new Schema<IDialogueHistoryDatabase>(
|
const dialogueHistorySchema = new Schema<IDialogueHistoryDatabase>(
|
||||||
{
|
{
|
||||||
YearIteration: Number,
|
YearIteration: { type: Number, required: true },
|
||||||
Resets: Number,
|
Resets: Number,
|
||||||
Dialogues: { type: [dialogueSchema], required: false }
|
Dialogues: { type: [dialogueSchema], required: false }
|
||||||
},
|
},
|
||||||
@ -1014,7 +880,6 @@ const EquipmentSchema = new Schema<IEquipmentDatabase>(
|
|||||||
RailjackImage: FlavourItemSchema,
|
RailjackImage: FlavourItemSchema,
|
||||||
CrewMembers: crewShipMembersSchema,
|
CrewMembers: crewShipMembersSchema,
|
||||||
Details: detailsSchema,
|
Details: detailsSchema,
|
||||||
Favorite: Boolean,
|
|
||||||
IsNew: Boolean
|
IsNew: Boolean
|
||||||
},
|
},
|
||||||
{ id: false }
|
{ id: false }
|
||||||
@ -1055,8 +920,6 @@ const pendingRecipeSchema = new Schema<IPendingRecipeDatabase>(
|
|||||||
{
|
{
|
||||||
ItemType: String,
|
ItemType: String,
|
||||||
CompletionDate: Date,
|
CompletionDate: Date,
|
||||||
TargetItemId: String,
|
|
||||||
TargetFingerprint: String,
|
|
||||||
LongGuns: { type: [EquipmentSchema], default: undefined },
|
LongGuns: { type: [EquipmentSchema], default: undefined },
|
||||||
Pistols: { type: [EquipmentSchema], default: undefined },
|
Pistols: { type: [EquipmentSchema], default: undefined },
|
||||||
Melee: { type: [EquipmentSchema], default: undefined },
|
Melee: { type: [EquipmentSchema], default: undefined },
|
||||||
@ -1084,13 +947,6 @@ pendingRecipeSchema.set("toJSON", {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const accoladesSchema = new Schema<IAccolades>(
|
|
||||||
{
|
|
||||||
Heirloom: Boolean
|
|
||||||
},
|
|
||||||
{ _id: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
const infestedFoundrySchema = new Schema<IInfestedFoundryDatabase>(
|
const infestedFoundrySchema = new Schema<IInfestedFoundryDatabase>(
|
||||||
{
|
{
|
||||||
Name: String,
|
Name: String,
|
||||||
@ -1148,15 +1004,15 @@ const CustomMarkersSchema = new Schema<ICustomMarkers>(
|
|||||||
const calenderProgressSchema = new Schema<ICalendarProgress>(
|
const calenderProgressSchema = new Schema<ICalendarProgress>(
|
||||||
{
|
{
|
||||||
Version: { type: Number, default: 19 },
|
Version: { type: Number, default: 19 },
|
||||||
Iteration: { type: Number, required: true },
|
Iteration: { type: Number, default: 2 },
|
||||||
YearProgress: {
|
YearProgress: {
|
||||||
Upgrades: { type: [String], default: [] }
|
Upgrades: { type: [] }
|
||||||
},
|
},
|
||||||
SeasonProgress: {
|
SeasonProgress: {
|
||||||
SeasonType: { type: String, required: true },
|
SeasonType: String,
|
||||||
LastCompletedDayIdx: { type: Number, default: 0 },
|
LastCompletedDayIdx: { type: Number, default: -1 },
|
||||||
LastCompletedChallengeDayIdx: { type: Number, default: 0 },
|
LastCompletedChallengeDayIdx: { type: Number, default: -1 },
|
||||||
ActivatedChallenges: { type: [String], default: [] }
|
ActivatedChallenges: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ _id: false }
|
{ _id: false }
|
||||||
@ -1278,11 +1134,11 @@ const nemesisSchema = new Schema<INemesisDatabase>(
|
|||||||
PrevOwners: Number,
|
PrevOwners: Number,
|
||||||
SecondInCommand: Boolean,
|
SecondInCommand: Boolean,
|
||||||
Weakened: Boolean,
|
Weakened: Boolean,
|
||||||
InfNodes: { type: [infNodeSchema], default: undefined },
|
InfNodes: [infNodeSchema],
|
||||||
HenchmenKilled: Number,
|
HenchmenKilled: Number,
|
||||||
HintProgress: Number,
|
HintProgress: Number,
|
||||||
Hints: { type: [Number], default: undefined },
|
Hints: [Number],
|
||||||
GuessHistory: { type: [Number], default: undefined },
|
GuessHistory: [Number],
|
||||||
MissionCount: Number,
|
MissionCount: Number,
|
||||||
LastEnc: Number
|
LastEnc: Number
|
||||||
},
|
},
|
||||||
@ -1310,36 +1166,6 @@ const alignmentSchema = new Schema<IAlignment>(
|
|||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
const lastSortieRewardSchema = new Schema<ILastSortieRewardDatabase>(
|
|
||||||
{
|
|
||||||
SortieId: Schema.Types.ObjectId,
|
|
||||||
StoreItem: String,
|
|
||||||
Manifest: String
|
|
||||||
},
|
|
||||||
{ _id: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
lastSortieRewardSchema.set("toJSON", {
|
|
||||||
virtuals: true,
|
|
||||||
transform(_doc, obj) {
|
|
||||||
const db = obj as ILastSortieRewardDatabase;
|
|
||||||
const client = obj as ILastSortieRewardClient;
|
|
||||||
|
|
||||||
client.SortieId = toOid(db.SortieId);
|
|
||||||
|
|
||||||
delete obj._id;
|
|
||||||
delete obj.__v;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const sortieRewardAttenutationSchema = new Schema<ISortieRewardAttenuation>(
|
|
||||||
{
|
|
||||||
Tag: String,
|
|
||||||
Atten: Number
|
|
||||||
},
|
|
||||||
{ _id: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
const lockedWeaponGroupSchema = new Schema<ILockedWeaponGroupDatabase>(
|
const lockedWeaponGroupSchema = new Schema<ILockedWeaponGroupDatabase>(
|
||||||
{
|
{
|
||||||
s: Schema.Types.ObjectId,
|
s: Schema.Types.ObjectId,
|
||||||
@ -1351,21 +1177,12 @@ const lockedWeaponGroupSchema = new Schema<ILockedWeaponGroupDatabase>(
|
|||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
const hubNpcCustomizationSchema = new Schema<IHubNpcCustomization>(
|
|
||||||
{
|
|
||||||
Colors: colorSchema,
|
|
||||||
Pattern: String,
|
|
||||||
Tag: String
|
|
||||||
},
|
|
||||||
{ _id: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
||||||
{
|
{
|
||||||
accountOwnerId: Schema.Types.ObjectId,
|
accountOwnerId: Schema.Types.ObjectId,
|
||||||
SubscribedToEmails: { type: Number, default: 0 },
|
SubscribedToEmails: { type: Number, default: 0 },
|
||||||
SubscribedToEmailsPersonalized: { type: Number, default: 0 },
|
SubscribedToEmailsPersonalized: { type: Number, default: 0 },
|
||||||
RewardSeed: BigInt,
|
RewardSeed: Number,
|
||||||
|
|
||||||
//Credit
|
//Credit
|
||||||
RegularCredits: { type: Number, default: 0 },
|
RegularCredits: { type: Number, default: 0 },
|
||||||
@ -1399,7 +1216,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
//How many Gift do you have left*(gift spends the trade)
|
//How many Gift do you have left*(gift spends the trade)
|
||||||
GiftsRemaining: { type: Number, default: 8 },
|
GiftsRemaining: { type: Number, default: 8 },
|
||||||
//Curent trade info Giving or Getting items
|
//Curent trade info Giving or Getting items
|
||||||
//PendingTrades: [Schema.Types.Mixed],
|
PendingTrades: [Schema.Types.Mixed],
|
||||||
|
|
||||||
//Syndicate currently being pledged to.
|
//Syndicate currently being pledged to.
|
||||||
SupportedSyndicate: String,
|
SupportedSyndicate: String,
|
||||||
@ -1449,7 +1266,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
|
|
||||||
KubrowPetEggs: [kubrowPetEggSchema],
|
KubrowPetEggs: [kubrowPetEggSchema],
|
||||||
//Prints Cat(3 Prints)\Kubrow(2 Prints) Pets
|
//Prints Cat(3 Prints)\Kubrow(2 Prints) Pets
|
||||||
//KubrowPetPrints: [Schema.Types.Mixed],
|
KubrowPetPrints: [Schema.Types.Mixed],
|
||||||
|
|
||||||
//Item for EquippedGear example:Scaner,LoadoutTechSummon etc
|
//Item for EquippedGear example:Scaner,LoadoutTechSummon etc
|
||||||
Consumables: [typeCountSchema],
|
Consumables: [typeCountSchema],
|
||||||
@ -1486,7 +1303,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
CrewShipSalvagedWeaponSkins: [upgradeSchema],
|
CrewShipSalvagedWeaponSkins: [upgradeSchema],
|
||||||
|
|
||||||
//RailJack Crew
|
//RailJack Crew
|
||||||
CrewMembers: [crewMemberSchema],
|
CrewMembers: [Schema.Types.Mixed],
|
||||||
|
|
||||||
//Complete Mission\Quests
|
//Complete Mission\Quests
|
||||||
Missions: [missionSchema],
|
Missions: [missionSchema],
|
||||||
@ -1495,7 +1312,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
//item like DojoKey or Boss missions key
|
//item like DojoKey or Boss missions key
|
||||||
LevelKeys: [typeCountSchema],
|
LevelKeys: [typeCountSchema],
|
||||||
//Active quests
|
//Active quests
|
||||||
//Quests: [Schema.Types.Mixed],
|
Quests: [Schema.Types.Mixed],
|
||||||
|
|
||||||
//Cosmetics like profile glyphs\Kavasa Prime Kubrow Collar\Game Theme etc
|
//Cosmetics like profile glyphs\Kavasa Prime Kubrow Collar\Game Theme etc
|
||||||
FlavourItems: [FlavourItemSchema],
|
FlavourItems: [FlavourItemSchema],
|
||||||
@ -1507,16 +1324,6 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
//Mastery Rank next availability
|
//Mastery Rank next availability
|
||||||
TrainingDate: { type: Date, default: new Date(0) },
|
TrainingDate: { type: Date, default: new Date(0) },
|
||||||
|
|
||||||
//Accolades
|
|
||||||
Staff: Boolean,
|
|
||||||
Founder: Number,
|
|
||||||
Guide: Number,
|
|
||||||
Moderator: Boolean,
|
|
||||||
Partner: Boolean,
|
|
||||||
Accolades: accoladesSchema,
|
|
||||||
//Not an accolade but unlocks an extra chat
|
|
||||||
Counselor: Boolean,
|
|
||||||
|
|
||||||
//you saw last played Region when you opened the star map
|
//you saw last played Region when you opened the star map
|
||||||
LastRegionPlayed: String,
|
LastRegionPlayed: String,
|
||||||
|
|
||||||
@ -1534,7 +1341,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
TauntHistory: { type: [tauntSchema], default: undefined },
|
TauntHistory: { type: [tauntSchema], default: undefined },
|
||||||
|
|
||||||
//noShow2FA,VisitPrimeVault etc
|
//noShow2FA,VisitPrimeVault etc
|
||||||
//WebFlags: Schema.Types.Mixed,
|
WebFlags: Schema.Types.Mixed,
|
||||||
//Id CompletedAlerts
|
//Id CompletedAlerts
|
||||||
CompletedAlerts: [String],
|
CompletedAlerts: [String],
|
||||||
|
|
||||||
@ -1554,9 +1361,9 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
//the color your clan requests like Items/Research/DojoColors/DojoColorPlainsB
|
//the color your clan requests like Items/Research/DojoColors/DojoColorPlainsB
|
||||||
ActiveDojoColorResearch: String,
|
ActiveDojoColorResearch: String,
|
||||||
|
|
||||||
//SentientSpawnChanceBoosters: Schema.Types.Mixed,
|
SentientSpawnChanceBoosters: Schema.Types.Mixed,
|
||||||
|
|
||||||
QualifyingInvasions: [invasionProgressSchema],
|
QualifyingInvasions: [Schema.Types.Mixed],
|
||||||
FactionScores: [Number],
|
FactionScores: [Number],
|
||||||
|
|
||||||
// https://warframe.fandom.com/wiki/Specter_(Tenno)
|
// https://warframe.fandom.com/wiki/Specter_(Tenno)
|
||||||
@ -1576,9 +1383,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
|
|
||||||
//https://warframe.fandom.com/wiki/Sortie
|
//https://warframe.fandom.com/wiki/Sortie
|
||||||
CompletedSorties: [String],
|
CompletedSorties: [String],
|
||||||
LastSortieReward: { type: [lastSortieRewardSchema], default: undefined },
|
LastSortieReward: [Schema.Types.Mixed],
|
||||||
LastLiteSortieReward: { type: [lastSortieRewardSchema], default: undefined },
|
|
||||||
SortieRewardAttenuation: { type: [sortieRewardAttenutationSchema], default: undefined },
|
|
||||||
|
|
||||||
// Resource Extractor Drones
|
// Resource Extractor Drones
|
||||||
Drones: [droneSchema],
|
Drones: [droneSchema],
|
||||||
@ -1589,10 +1394,10 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
// open location store like EidolonPlainsDiscoverable or OrbVallisCaveDiscoverable
|
// open location store like EidolonPlainsDiscoverable or OrbVallisCaveDiscoverable
|
||||||
DiscoveredMarkers: [discoveredMarkerSchema],
|
DiscoveredMarkers: [discoveredMarkerSchema],
|
||||||
//Open location mission like "JobId" + "StageCompletions"
|
//Open location mission like "JobId" + "StageCompletions"
|
||||||
//CompletedJobs: [Schema.Types.Mixed],
|
CompletedJobs: [Schema.Types.Mixed],
|
||||||
|
|
||||||
//Game mission\ivent score example "Tag": "WaterFight", "Best": 170, "Count": 1258,
|
//Game mission\ivent score example "Tag": "WaterFight", "Best": 170, "Count": 1258,
|
||||||
//PersonalGoalProgress: [Schema.Types.Mixed],
|
PersonalGoalProgress: [Schema.Types.Mixed],
|
||||||
|
|
||||||
//Setting interface Style
|
//Setting interface Style
|
||||||
ThemeStyle: String,
|
ThemeStyle: String,
|
||||||
@ -1610,7 +1415,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
|
|
||||||
//https://warframe.fandom.com/wiki/Heist
|
//https://warframe.fandom.com/wiki/Heist
|
||||||
//ProfitTaker(1-4) Example:"LocationTag": "EudicoHeists", "Jobs":Mission name
|
//ProfitTaker(1-4) Example:"LocationTag": "EudicoHeists", "Jobs":Mission name
|
||||||
CompletedJobChains: { type: [completedJobChainsSchema], default: undefined },
|
CompletedJobChains: [completedJobChainsSchema],
|
||||||
//Night Wave Challenge
|
//Night Wave Challenge
|
||||||
SeasonChallengeHistory: [seasonChallengeHistorySchema],
|
SeasonChallengeHistory: [seasonChallengeHistorySchema],
|
||||||
|
|
||||||
@ -1622,27 +1427,27 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
LibraryActiveDailyTaskInfo: libraryDailyTaskInfoSchema,
|
LibraryActiveDailyTaskInfo: libraryDailyTaskInfoSchema,
|
||||||
|
|
||||||
//https://warframe.fandom.com/wiki/Invasion
|
//https://warframe.fandom.com/wiki/Invasion
|
||||||
//InvasionChainProgress: [Schema.Types.Mixed],
|
InvasionChainProgress: [Schema.Types.Mixed],
|
||||||
|
|
||||||
//CorpusLich or GrineerLich
|
//CorpusLich or GrineerLich
|
||||||
NemesisAbandonedRewards: { type: [String], default: [] },
|
NemesisAbandonedRewards: { type: [String], default: [] },
|
||||||
Nemesis: nemesisSchema,
|
Nemesis: nemesisSchema,
|
||||||
NemesisHistory: { type: [nemesisSchema], default: undefined },
|
NemesisHistory: [Schema.Types.Mixed],
|
||||||
//LastNemesisAllySpawnTime: Schema.Types.Mixed,
|
LastNemesisAllySpawnTime: Schema.Types.Mixed,
|
||||||
|
|
||||||
//TradingRulesConfirmed,ShowFriendInvNotifications(Option->Social)
|
//TradingRulesConfirmed,ShowFriendInvNotifications(Option->Social)
|
||||||
Settings: settingsSchema,
|
Settings: settingsSchema,
|
||||||
|
|
||||||
//Railjack craft
|
//Railjack craft
|
||||||
//https://warframe.fandom.com/wiki/Rising_Tide
|
//https://warframe.fandom.com/wiki/Rising_Tide
|
||||||
PersonalTechProjects: { type: [personalTechProjectSchema], default: [] },
|
PersonalTechProjects: [Schema.Types.Mixed],
|
||||||
|
|
||||||
//Modulars lvl and exp(Railjack|Duviri)
|
//Modulars lvl and exp(Railjack|Duviri)
|
||||||
//https://warframe.fandom.com/wiki/Intrinsics
|
//https://warframe.fandom.com/wiki/Intrinsics
|
||||||
PlayerSkills: { type: playerSkillsSchema, default: {} },
|
PlayerSkills: { type: playerSkillsSchema, default: {} },
|
||||||
|
|
||||||
//TradeBannedUntil data
|
//TradeBannedUntil data
|
||||||
//TradeBannedUntil: Schema.Types.Mixed,
|
TradeBannedUntil: Schema.Types.Mixed,
|
||||||
|
|
||||||
//https://warframe.fandom.com/wiki/Helminth
|
//https://warframe.fandom.com/wiki/Helminth
|
||||||
InfestedFoundry: infestedFoundrySchema,
|
InfestedFoundry: infestedFoundrySchema,
|
||||||
@ -1651,7 +1456,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
|
|
||||||
//Purchase this new permanent skin from the Lotus customization options in Personal Quarters located in your Orbiter.
|
//Purchase this new permanent skin from the Lotus customization options in Personal Quarters located in your Orbiter.
|
||||||
//https://warframe.fandom.com/wiki/Lotus#The_New_War
|
//https://warframe.fandom.com/wiki/Lotus#The_New_War
|
||||||
LotusCustomization: { type: lotusCustomizationSchema, default: undefined },
|
LotusCustomization: Schema.Types.Mixed,
|
||||||
|
|
||||||
//Progress+Rank+ItemType(ZarimanPumpShotgun)
|
//Progress+Rank+ItemType(ZarimanPumpShotgun)
|
||||||
//https://warframe.fandom.com/wiki/Incarnon
|
//https://warframe.fandom.com/wiki/Incarnon
|
||||||
@ -1662,24 +1467,23 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
|
|
||||||
//Unknown and system
|
//Unknown and system
|
||||||
DuviriInfo: DuviriInfoSchema,
|
DuviriInfo: DuviriInfoSchema,
|
||||||
LastInventorySync: Schema.Types.ObjectId,
|
|
||||||
Mailbox: MailboxSchema,
|
Mailbox: MailboxSchema,
|
||||||
HandlerPoints: Number,
|
HandlerPoints: Number,
|
||||||
ChallengesFixVersion: { type: Number, default: 6 },
|
ChallengesFixVersion: Number,
|
||||||
PlayedParkourTutorial: Boolean,
|
PlayedParkourTutorial: Boolean,
|
||||||
//ActiveLandscapeTraps: [Schema.Types.Mixed],
|
ActiveLandscapeTraps: [Schema.Types.Mixed],
|
||||||
//RepVotes: [Schema.Types.Mixed],
|
RepVotes: [Schema.Types.Mixed],
|
||||||
//LeagueTickets: [Schema.Types.Mixed],
|
LeagueTickets: [Schema.Types.Mixed],
|
||||||
HasContributedToDojo: Boolean,
|
HasContributedToDojo: Boolean,
|
||||||
HWIDProtectEnabled: Boolean,
|
HWIDProtectEnabled: Boolean,
|
||||||
LoadOutPresets: { type: Schema.Types.ObjectId, ref: "Loadout" },
|
LoadOutPresets: { type: Schema.Types.ObjectId, ref: "Loadout" },
|
||||||
CurrentLoadOutIds: [oidSchema],
|
CurrentLoadOutIds: [Schema.Types.Mixed],
|
||||||
RandomUpgradesIdentified: Number,
|
RandomUpgradesIdentified: Number,
|
||||||
BountyScore: Number,
|
BountyScore: Number,
|
||||||
//ChallengeInstanceStates: [Schema.Types.Mixed],
|
ChallengeInstanceStates: [Schema.Types.Mixed],
|
||||||
RecentVendorPurchases: { type: [recentVendorPurchaseSchema], default: undefined },
|
RecentVendorPurchases: { type: [recentVendorPurchaseSchema], default: undefined },
|
||||||
//Robotics: [Schema.Types.Mixed],
|
Robotics: [Schema.Types.Mixed],
|
||||||
//UsedDailyDeals: [Schema.Types.Mixed],
|
UsedDailyDeals: [Schema.Types.Mixed],
|
||||||
CollectibleSeries: { type: [collectibleEntrySchema], default: undefined },
|
CollectibleSeries: { type: [collectibleEntrySchema], default: undefined },
|
||||||
HasResetAccount: { type: Boolean, default: false },
|
HasResetAccount: { type: Boolean, default: false },
|
||||||
|
|
||||||
@ -1688,9 +1492,9 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
//Like BossAladV,BossCaptainVor come for you on missions % chance
|
//Like BossAladV,BossCaptainVor come for you on missions % chance
|
||||||
DeathMarks: { type: [String], default: [] },
|
DeathMarks: { type: [String], default: [] },
|
||||||
//Zanuka
|
//Zanuka
|
||||||
Harvestable: { type: Boolean, default: true },
|
Harvestable: Boolean,
|
||||||
//Grustag three
|
//Grustag three
|
||||||
DeathSquadable: { type: Boolean, default: true },
|
DeathSquadable: Boolean,
|
||||||
|
|
||||||
EndlessXP: { type: [endlessXpProgressSchema], default: undefined },
|
EndlessXP: { type: [endlessXpProgressSchema], default: undefined },
|
||||||
|
|
||||||
@ -1714,9 +1518,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
|
|
||||||
// G3 + Zanuka
|
// G3 + Zanuka
|
||||||
BrandedSuits: { type: [Schema.Types.ObjectId], default: undefined },
|
BrandedSuits: { type: [Schema.Types.ObjectId], default: undefined },
|
||||||
LockedWeaponGroup: { type: lockedWeaponGroupSchema, default: undefined },
|
LockedWeaponGroup: { type: lockedWeaponGroupSchema, default: undefined }
|
||||||
|
|
||||||
HubNpcCustomizations: { type: [hubNpcCustomizationSchema], default: undefined }
|
|
||||||
},
|
},
|
||||||
{ timestamps: { createdAt: "Created", updatedAt: false } }
|
{ timestamps: { createdAt: "Created", updatedAt: false } }
|
||||||
);
|
);
|
||||||
@ -1760,9 +1562,6 @@ inventorySchema.set("toJSON", {
|
|||||||
sn: inventoryDatabase.LockedWeaponGroup.sn ? toOid(inventoryDatabase.LockedWeaponGroup.sn) : undefined
|
sn: inventoryDatabase.LockedWeaponGroup.sn ? toOid(inventoryDatabase.LockedWeaponGroup.sn) : undefined
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (inventoryDatabase.LastInventorySync) {
|
|
||||||
inventoryResponse.LastInventorySync = toOid(inventoryDatabase.LastInventorySync);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1783,9 +1582,7 @@ export type InventoryDocumentProps = {
|
|||||||
QuestKeys: Types.DocumentArray<IQuestKeyDatabase>;
|
QuestKeys: Types.DocumentArray<IQuestKeyDatabase>;
|
||||||
Drones: Types.DocumentArray<IDroneDatabase>;
|
Drones: Types.DocumentArray<IDroneDatabase>;
|
||||||
CrewShipWeaponSkins: Types.DocumentArray<IUpgradeDatabase>;
|
CrewShipWeaponSkins: Types.DocumentArray<IUpgradeDatabase>;
|
||||||
CrewShipSalvagedWeaponSkins: Types.DocumentArray<IUpgradeDatabase>;
|
CrewShipSalvagedWeaponsSkins: Types.DocumentArray<IUpgradeDatabase>;
|
||||||
PersonalTechProjects: Types.DocumentArray<IPersonalTechProjectDatabase>;
|
|
||||||
CrewMembers: Types.DocumentArray<ICrewMemberDatabase>;
|
|
||||||
} & { [K in TEquipmentKey]: Types.DocumentArray<IEquipmentDatabase> };
|
} & { [K in TEquipmentKey]: Types.DocumentArray<IEquipmentDatabase> };
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||||
|
@ -3,7 +3,7 @@ import { IEquipmentSelection } from "@/src/types/inventoryTypes/commonInventoryT
|
|||||||
import { ILoadoutConfigDatabase, ILoadoutDatabase } from "@/src/types/saveLoadoutTypes";
|
import { ILoadoutConfigDatabase, ILoadoutDatabase } from "@/src/types/saveLoadoutTypes";
|
||||||
import { Document, Model, Schema, Types, model } from "mongoose";
|
import { Document, Model, Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
export const oidSchema = new Schema<IOid>(
|
const oidSchema = new Schema<IOid>(
|
||||||
{
|
{
|
||||||
$oid: String
|
$oid: String
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { IDatabaseAccountJson, IIgnore } from "@/src/types/loginTypes";
|
import { IDatabaseAccountJson } from "@/src/types/loginTypes";
|
||||||
import { model, Schema, SchemaOptions } from "mongoose";
|
import { model, Schema, SchemaOptions } from "mongoose";
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
@ -37,13 +37,3 @@ databaseAccountSchema.set("toJSON", {
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const Account = model<IDatabaseAccountJson>("Account", databaseAccountSchema);
|
export const Account = model<IDatabaseAccountJson>("Account", databaseAccountSchema);
|
||||||
|
|
||||||
const ignoreSchema = new Schema<IIgnore>({
|
|
||||||
ignorer: Schema.Types.ObjectId,
|
|
||||||
ignoree: Schema.Types.ObjectId
|
|
||||||
});
|
|
||||||
|
|
||||||
ignoreSchema.index({ ignorer: 1 });
|
|
||||||
ignoreSchema.index({ ignorer: 1, ignoree: 1 }, { unique: true });
|
|
||||||
|
|
||||||
export const Ignore = model<IIgnore>("Ignore", ignoreSchema);
|
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
|
import { toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
import { colorSchema } from "@/src/models/inventoryModels/inventoryModel";
|
import { colorSchema } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { IOrbiter, IPersonalRoomsDatabase, PersonalRoomsModelType } from "@/src/types/personalRoomsTypes";
|
import { IOrbiter, IPersonalRoomsDatabase, PersonalRoomsModelType } from "@/src/types/personalRoomsTypes";
|
||||||
import {
|
import {
|
||||||
|
IApartment,
|
||||||
IFavouriteLoadoutDatabase,
|
IFavouriteLoadoutDatabase,
|
||||||
IGardeningDatabase,
|
IGardening,
|
||||||
IPlacedDecosDatabase,
|
IPlacedDecosDatabase,
|
||||||
IPictureFrameInfo,
|
IPictureFrameInfo,
|
||||||
IRoom,
|
IRoom,
|
||||||
ITailorShopDatabase,
|
ITailorShopDatabase
|
||||||
IApartmentDatabase,
|
|
||||||
IPlanterDatabase,
|
|
||||||
IPlantDatabase,
|
|
||||||
IPlantClient
|
|
||||||
} from "@/src/types/shipTypes";
|
} from "@/src/types/shipTypes";
|
||||||
import { Schema, model } from "mongoose";
|
import { Schema, model } from "mongoose";
|
||||||
|
|
||||||
@ -65,64 +62,19 @@ const roomSchema = new Schema<IRoom>(
|
|||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
const favouriteLoadoutSchema = new Schema<IFavouriteLoadoutDatabase>(
|
const gardeningSchema = new Schema<IGardening>({
|
||||||
{
|
Planters: [Schema.Types.Mixed] //TODO: add when implementing gardening
|
||||||
Tag: String,
|
|
||||||
LoadoutId: Schema.Types.ObjectId
|
|
||||||
},
|
|
||||||
{ _id: false }
|
|
||||||
);
|
|
||||||
favouriteLoadoutSchema.set("toJSON", {
|
|
||||||
virtuals: true,
|
|
||||||
transform(_document, returnedObject) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
||||||
returnedObject.LoadoutId = toOid(returnedObject.LoadoutId);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const plantSchema = new Schema<IPlantDatabase>(
|
const apartmentSchema = new Schema<IApartment>(
|
||||||
{
|
|
||||||
PlantType: String,
|
|
||||||
EndTime: Date,
|
|
||||||
PlotIndex: Number
|
|
||||||
},
|
|
||||||
{ _id: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
plantSchema.set("toJSON", {
|
|
||||||
virtuals: true,
|
|
||||||
transform(_doc, obj) {
|
|
||||||
const client = obj as IPlantClient;
|
|
||||||
const db = obj as IPlantDatabase;
|
|
||||||
|
|
||||||
client.EndTime = toMongoDate(db.EndTime);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const planterSchema = new Schema<IPlanterDatabase>(
|
|
||||||
{
|
|
||||||
Name: { type: String, required: true },
|
|
||||||
Plants: { type: [plantSchema], default: [] }
|
|
||||||
},
|
|
||||||
{ _id: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
const gardeningSchema = new Schema<IGardeningDatabase>(
|
|
||||||
{
|
|
||||||
Planters: { type: [planterSchema], default: [] }
|
|
||||||
},
|
|
||||||
{ _id: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
const apartmentSchema = new Schema<IApartmentDatabase>(
|
|
||||||
{
|
{
|
||||||
Rooms: [roomSchema],
|
Rooms: [roomSchema],
|
||||||
FavouriteLoadouts: [favouriteLoadoutSchema],
|
FavouriteLoadouts: [Schema.Types.Mixed],
|
||||||
Gardening: gardeningSchema
|
Gardening: gardeningSchema // TODO: ensure this is correct
|
||||||
},
|
},
|
||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
const apartmentDefault: IApartmentDatabase = {
|
const apartmentDefault: IApartment = {
|
||||||
Rooms: [
|
Rooms: [
|
||||||
{ Name: "ElevatorLanding", MaxCapacity: 1600 },
|
{ Name: "ElevatorLanding", MaxCapacity: 1600 },
|
||||||
{ Name: "ApartmentRoomA", MaxCapacity: 1000 },
|
{ Name: "ApartmentRoomA", MaxCapacity: 1000 },
|
||||||
@ -131,19 +83,13 @@ const apartmentDefault: IApartmentDatabase = {
|
|||||||
{ Name: "DuviriHallway", MaxCapacity: 1600 }
|
{ Name: "DuviriHallway", MaxCapacity: 1600 }
|
||||||
],
|
],
|
||||||
FavouriteLoadouts: [],
|
FavouriteLoadouts: [],
|
||||||
Gardening: {
|
Gardening: {}
|
||||||
Planters: []
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const orbiterSchema = new Schema<IOrbiter>(
|
const orbiterSchema = new Schema<IOrbiter>(
|
||||||
{
|
{
|
||||||
Features: [String],
|
Features: [String],
|
||||||
Rooms: [roomSchema],
|
Rooms: [roomSchema],
|
||||||
VignetteFish: { type: [String], default: undefined },
|
|
||||||
FavouriteLoadoutId: Schema.Types.ObjectId,
|
|
||||||
Wallpaper: String,
|
|
||||||
Vignette: String,
|
|
||||||
ContentUrlSignature: { type: String, required: false },
|
ContentUrlSignature: { type: String, required: false },
|
||||||
BootLocation: String
|
BootLocation: String
|
||||||
},
|
},
|
||||||
@ -161,6 +107,21 @@ const orbiterDefault: IOrbiter = {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const favouriteLoadoutSchema = new Schema<IFavouriteLoadoutDatabase>(
|
||||||
|
{
|
||||||
|
Tag: String,
|
||||||
|
LoadoutId: Schema.Types.ObjectId
|
||||||
|
},
|
||||||
|
{ _id: false }
|
||||||
|
);
|
||||||
|
favouriteLoadoutSchema.set("toJSON", {
|
||||||
|
virtuals: true,
|
||||||
|
transform(_document, returnedObject) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||||
|
returnedObject.LoadoutId = toOid(returnedObject.LoadoutId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const tailorShopSchema = new Schema<ITailorShopDatabase>(
|
const tailorShopSchema = new Schema<ITailorShopDatabase>(
|
||||||
{
|
{
|
||||||
FavouriteLoadouts: [favouriteLoadoutSchema],
|
FavouriteLoadouts: [favouriteLoadoutSchema],
|
||||||
|
@ -4,7 +4,6 @@ import { abortDojoComponentController } from "@/src/controllers/api/abortDojoCom
|
|||||||
import { abortDojoComponentDestructionController } from "@/src/controllers/api/abortDojoComponentDestructionController";
|
import { abortDojoComponentDestructionController } from "@/src/controllers/api/abortDojoComponentDestructionController";
|
||||||
import { activateRandomModController } from "@/src/controllers/api/activateRandomModController";
|
import { activateRandomModController } from "@/src/controllers/api/activateRandomModController";
|
||||||
import { addFriendImageController } from "@/src/controllers/api/addFriendImageController";
|
import { addFriendImageController } from "@/src/controllers/api/addFriendImageController";
|
||||||
import { addIgnoredUserController } from "@/src/controllers/api/addIgnoredUserController";
|
|
||||||
import { addToAllianceController } from "@/src/controllers/api/addToAllianceController";
|
import { addToAllianceController } from "@/src/controllers/api/addToAllianceController";
|
||||||
import { addToGuildController } from "@/src/controllers/api/addToGuildController";
|
import { addToGuildController } from "@/src/controllers/api/addToGuildController";
|
||||||
import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController";
|
import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController";
|
||||||
@ -19,7 +18,6 @@ import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompl
|
|||||||
import { claimLibraryDailyTaskRewardController } from "@/src/controllers/api/claimLibraryDailyTaskRewardController";
|
import { claimLibraryDailyTaskRewardController } from "@/src/controllers/api/claimLibraryDailyTaskRewardController";
|
||||||
import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController";
|
import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController";
|
||||||
import { clearNewEpisodeRewardController } from "@/src/controllers/api/clearNewEpisodeRewardController";
|
import { clearNewEpisodeRewardController } from "@/src/controllers/api/clearNewEpisodeRewardController";
|
||||||
import { completeCalendarEventController } from "@/src/controllers/api/completeCalendarEventController";
|
|
||||||
import { completeRandomModChallengeController } from "@/src/controllers/api/completeRandomModChallengeController";
|
import { completeRandomModChallengeController } from "@/src/controllers/api/completeRandomModChallengeController";
|
||||||
import { confirmAllianceInvitationController } from "@/src/controllers/api/confirmAllianceInvitationController";
|
import { confirmAllianceInvitationController } from "@/src/controllers/api/confirmAllianceInvitationController";
|
||||||
import { confirmGuildInvitationGetController, confirmGuildInvitationPostController } from "@/src/controllers/api/confirmGuildInvitationController";
|
import { confirmGuildInvitationGetController, confirmGuildInvitationPostController } from "@/src/controllers/api/confirmGuildInvitationController";
|
||||||
@ -29,8 +27,6 @@ import { contributeToVaultController } from "@/src/controllers/api/contributeToV
|
|||||||
import { createAllianceController } from "@/src/controllers/api/createAllianceController";
|
import { createAllianceController } from "@/src/controllers/api/createAllianceController";
|
||||||
import { createGuildController } from "@/src/controllers/api/createGuildController";
|
import { createGuildController } from "@/src/controllers/api/createGuildController";
|
||||||
import { creditsController } from "@/src/controllers/api/creditsController";
|
import { creditsController } from "@/src/controllers/api/creditsController";
|
||||||
import { crewMembersController } from "@/src/controllers/api/crewMembersController";
|
|
||||||
import { crewShipIdentifySalvageController } from "@/src/controllers/api/crewShipIdentifySalvageController";
|
|
||||||
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
|
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
|
||||||
import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController";
|
import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController";
|
||||||
import { declineAllianceInviteController } from "@/src/controllers/api/declineAllianceInviteController";
|
import { declineAllianceInviteController } from "@/src/controllers/api/declineAllianceInviteController";
|
||||||
@ -39,7 +35,7 @@ import { deleteSessionController } from "@/src/controllers/api/deleteSessionCont
|
|||||||
import { destroyDojoDecoController } from "@/src/controllers/api/destroyDojoDecoController";
|
import { destroyDojoDecoController } from "@/src/controllers/api/destroyDojoDecoController";
|
||||||
import { divvyAllianceVaultController } from "@/src/controllers/api/divvyAllianceVaultController";
|
import { divvyAllianceVaultController } from "@/src/controllers/api/divvyAllianceVaultController";
|
||||||
import { dojoComponentRushController } from "@/src/controllers/api/dojoComponentRushController";
|
import { dojoComponentRushController } from "@/src/controllers/api/dojoComponentRushController";
|
||||||
import { dojoController, setDojoURLController } from "@/src/controllers/api/dojoController";
|
import { dojoController } from "@/src/controllers/api/dojoController";
|
||||||
import { dronesController } from "@/src/controllers/api/dronesController";
|
import { dronesController } from "@/src/controllers/api/dronesController";
|
||||||
import { endlessXpController } from "@/src/controllers/api/endlessXpController";
|
import { endlessXpController } from "@/src/controllers/api/endlessXpController";
|
||||||
import { entratiLabConquestModeController } from "@/src/controllers/api/entratiLabConquestModeController";
|
import { entratiLabConquestModeController } from "@/src/controllers/api/entratiLabConquestModeController";
|
||||||
@ -48,7 +44,6 @@ import { findSessionsController } from "@/src/controllers/api/findSessionsContro
|
|||||||
import { fishmongerController } from "@/src/controllers/api/fishmongerController";
|
import { fishmongerController } from "@/src/controllers/api/fishmongerController";
|
||||||
import { focusController } from "@/src/controllers/api/focusController";
|
import { focusController } from "@/src/controllers/api/focusController";
|
||||||
import { fusionTreasuresController } from "@/src/controllers/api/fusionTreasuresController";
|
import { fusionTreasuresController } from "@/src/controllers/api/fusionTreasuresController";
|
||||||
import { gardeningController } from "@/src/controllers/api/gardeningController";
|
|
||||||
import { genericUpdateController } from "@/src/controllers/api/genericUpdateController";
|
import { genericUpdateController } from "@/src/controllers/api/genericUpdateController";
|
||||||
import { getAllianceController } from "@/src/controllers/api/getAllianceController";
|
import { getAllianceController } from "@/src/controllers/api/getAllianceController";
|
||||||
import { getDailyDealStockLevelsController } from "@/src/controllers/api/getDailyDealStockLevelsController";
|
import { getDailyDealStockLevelsController } from "@/src/controllers/api/getDailyDealStockLevelsController";
|
||||||
@ -66,8 +61,7 @@ import { giftingController } from "@/src/controllers/api/giftingController";
|
|||||||
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 { giveKeyChainTriggeredMessageController } from "@/src/controllers/api/giveKeyChainTriggeredMessageController";
|
||||||
import { giveQuestKeyRewardController } from "@/src/controllers/api/giveQuestKeyRewardController";
|
import { giveQuestKeyRewardController } from "@/src/controllers/api/giveQuestKey";
|
||||||
import { giveShipDecoAndLoreFragmentController } from "@/src/controllers/api/giveShipDecoAndLoreFragmentController";
|
|
||||||
import { giveStartingGearController } from "@/src/controllers/api/giveStartingGearController";
|
import { giveStartingGearController } from "@/src/controllers/api/giveStartingGearController";
|
||||||
import { guildTechController } from "@/src/controllers/api/guildTechController";
|
import { guildTechController } from "@/src/controllers/api/guildTechController";
|
||||||
import { hostSessionController } from "@/src/controllers/api/hostSessionController";
|
import { hostSessionController } from "@/src/controllers/api/hostSessionController";
|
||||||
@ -91,7 +85,6 @@ import { modularWeaponSaleController } from "@/src/controllers/api/modularWeapon
|
|||||||
import { nameWeaponController } from "@/src/controllers/api/nameWeaponController";
|
import { nameWeaponController } from "@/src/controllers/api/nameWeaponController";
|
||||||
import { nemesisController } from "@/src/controllers/api/nemesisController";
|
import { nemesisController } from "@/src/controllers/api/nemesisController";
|
||||||
import { placeDecoInComponentController } from "@/src/controllers/api/placeDecoInComponentController";
|
import { placeDecoInComponentController } from "@/src/controllers/api/placeDecoInComponentController";
|
||||||
import { playedParkourTutorialController } from "@/src/controllers/api/playedParkourTutorialController";
|
|
||||||
import { playerSkillsController } from "@/src/controllers/api/playerSkillsController";
|
import { playerSkillsController } from "@/src/controllers/api/playerSkillsController";
|
||||||
import { postGuildAdvertisementController } from "@/src/controllers/api/postGuildAdvertisementController";
|
import { postGuildAdvertisementController } from "@/src/controllers/api/postGuildAdvertisementController";
|
||||||
import { projectionManagerController } from "@/src/controllers/api/projectionManagerController";
|
import { projectionManagerController } from "@/src/controllers/api/projectionManagerController";
|
||||||
@ -101,15 +94,13 @@ import { redeemPromoCodeController } from "@/src/controllers/api/redeemPromoCode
|
|||||||
import { releasePetController } from "@/src/controllers/api/releasePetController";
|
import { releasePetController } from "@/src/controllers/api/releasePetController";
|
||||||
import { removeFromAllianceController } from "@/src/controllers/api/removeFromAllianceController";
|
import { removeFromAllianceController } from "@/src/controllers/api/removeFromAllianceController";
|
||||||
import { removeFromGuildController } from "@/src/controllers/api/removeFromGuildController";
|
import { removeFromGuildController } from "@/src/controllers/api/removeFromGuildController";
|
||||||
import { removeIgnoredUserController } from "@/src/controllers/api/removeIgnoredUserController";
|
|
||||||
import { rerollRandomModController } from "@/src/controllers/api/rerollRandomModController";
|
import { rerollRandomModController } from "@/src/controllers/api/rerollRandomModController";
|
||||||
import { retrievePetFromStasisController } from "@/src/controllers/api/retrievePetFromStasisController";
|
import { retrievePetFromStasisController } from "@/src/controllers/api/retrievePetFromStasisController";
|
||||||
import { saveDialogueController } from "@/src/controllers/api/saveDialogueController";
|
import { saveDialogueController } from "@/src/controllers/api/saveDialogueController";
|
||||||
import { saveLoadoutController } from "@/src/controllers/api/saveLoadoutController";
|
import { saveLoadoutController } from "@/src/controllers/api/saveLoadout";
|
||||||
import { saveSettingsController } from "@/src/controllers/api/saveSettingsController";
|
import { saveSettingsController } from "@/src/controllers/api/saveSettingsController";
|
||||||
import { saveVaultAutoContributeController } from "@/src/controllers/api/saveVaultAutoContributeController";
|
import { saveVaultAutoContributeController } from "@/src/controllers/api/saveVaultAutoContributeController";
|
||||||
import { sellController } from "@/src/controllers/api/sellController";
|
import { sellController } from "@/src/controllers/api/sellController";
|
||||||
import { sendMsgToInBoxController } from "@/src/controllers/api/sendMsgToInBoxController";
|
|
||||||
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 { setAllianceGuildPermissionsController } from "@/src/controllers/api/setAllianceGuildPermissionsController";
|
import { setAllianceGuildPermissionsController } from "@/src/controllers/api/setAllianceGuildPermissionsController";
|
||||||
@ -119,11 +110,9 @@ import { setDojoComponentMessageController } from "@/src/controllers/api/setDojo
|
|||||||
import { setDojoComponentSettingsController } from "@/src/controllers/api/setDojoComponentSettingsController";
|
import { setDojoComponentSettingsController } from "@/src/controllers/api/setDojoComponentSettingsController";
|
||||||
import { setEquippedInstrumentController } from "@/src/controllers/api/setEquippedInstrumentController";
|
import { setEquippedInstrumentController } from "@/src/controllers/api/setEquippedInstrumentController";
|
||||||
import { setGuildMotdController } from "@/src/controllers/api/setGuildMotdController";
|
import { setGuildMotdController } from "@/src/controllers/api/setGuildMotdController";
|
||||||
import { setHubNpcCustomizationsController } from "@/src/controllers/api/setHubNpcCustomizationsController";
|
|
||||||
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";
|
||||||
import { setShipFavouriteLoadoutController } from "@/src/controllers/api/setShipFavouriteLoadoutController";
|
import { setShipFavouriteLoadoutController } from "@/src/controllers/api/setShipFavouriteLoadoutController";
|
||||||
import { setShipVignetteController } from "@/src/controllers/api/setShipVignetteController";
|
|
||||||
import { setSupportedSyndicateController } from "@/src/controllers/api/setSupportedSyndicateController";
|
import { setSupportedSyndicateController } from "@/src/controllers/api/setSupportedSyndicateController";
|
||||||
import { setWeaponSkillTreeController } from "@/src/controllers/api/setWeaponSkillTreeController";
|
import { setWeaponSkillTreeController } from "@/src/controllers/api/setWeaponSkillTreeController";
|
||||||
import { shipDecorationsController } from "@/src/controllers/api/shipDecorationsController";
|
import { shipDecorationsController } from "@/src/controllers/api/shipDecorationsController";
|
||||||
@ -156,11 +145,9 @@ const apiRouter = express.Router();
|
|||||||
apiRouter.get("/abandonLibraryDailyTask.php", abandonLibraryDailyTaskController);
|
apiRouter.get("/abandonLibraryDailyTask.php", abandonLibraryDailyTaskController);
|
||||||
apiRouter.get("/abortDojoComponentDestruction.php", abortDojoComponentDestructionController);
|
apiRouter.get("/abortDojoComponentDestruction.php", abortDojoComponentDestructionController);
|
||||||
apiRouter.get("/cancelGuildAdvertisement.php", cancelGuildAdvertisementController);
|
apiRouter.get("/cancelGuildAdvertisement.php", cancelGuildAdvertisementController);
|
||||||
apiRouter.get("/changeDojoRoot.php", changeDojoRootController);
|
|
||||||
apiRouter.get("/changeGuildRank.php", changeGuildRankController);
|
apiRouter.get("/changeGuildRank.php", changeGuildRankController);
|
||||||
apiRouter.get("/checkDailyMissionBonus.php", checkDailyMissionBonusController);
|
apiRouter.get("/checkDailyMissionBonus.php", checkDailyMissionBonusController);
|
||||||
apiRouter.get("/claimLibraryDailyTaskReward.php", claimLibraryDailyTaskRewardController);
|
apiRouter.get("/claimLibraryDailyTaskReward.php", claimLibraryDailyTaskRewardController);
|
||||||
apiRouter.get("/completeCalendarEvent.php", completeCalendarEventController);
|
|
||||||
apiRouter.get("/confirmAllianceInvitation.php", confirmAllianceInvitationController);
|
apiRouter.get("/confirmAllianceInvitation.php", confirmAllianceInvitationController);
|
||||||
apiRouter.get("/confirmGuildInvitation.php", confirmGuildInvitationGetController);
|
apiRouter.get("/confirmGuildInvitation.php", confirmGuildInvitationGetController);
|
||||||
apiRouter.get("/credits.php", creditsController);
|
apiRouter.get("/credits.php", creditsController);
|
||||||
@ -189,14 +176,12 @@ apiRouter.get("/logout.php", logoutController);
|
|||||||
apiRouter.get("/marketRecommendations.php", marketRecommendationsController);
|
apiRouter.get("/marketRecommendations.php", marketRecommendationsController);
|
||||||
apiRouter.get("/marketSearchRecommendations.php", marketRecommendationsController);
|
apiRouter.get("/marketSearchRecommendations.php", marketRecommendationsController);
|
||||||
apiRouter.get("/modularWeaponSale.php", modularWeaponSaleController);
|
apiRouter.get("/modularWeaponSale.php", modularWeaponSaleController);
|
||||||
apiRouter.get("/playedParkourTutorial.php", playedParkourTutorialController);
|
|
||||||
apiRouter.get("/queueDojoComponentDestruction.php", queueDojoComponentDestructionController);
|
apiRouter.get("/queueDojoComponentDestruction.php", queueDojoComponentDestructionController);
|
||||||
apiRouter.get("/removeFromAlliance.php", removeFromAllianceController);
|
apiRouter.get("/removeFromAlliance.php", removeFromAllianceController);
|
||||||
apiRouter.get("/setActiveQuest.php", setActiveQuestController);
|
apiRouter.get("/setActiveQuest.php", setActiveQuestController);
|
||||||
apiRouter.get("/setActiveShip.php", setActiveShipController);
|
apiRouter.get("/setActiveShip.php", setActiveShipController);
|
||||||
apiRouter.get("/setAllianceGuildPermissions.php", setAllianceGuildPermissionsController);
|
apiRouter.get("/setAllianceGuildPermissions.php", setAllianceGuildPermissionsController);
|
||||||
apiRouter.get("/setBootLocation.php", setBootLocationController);
|
apiRouter.get("/setBootLocation.php", setBootLocationController);
|
||||||
apiRouter.get("/setDojoURL", setDojoURLController);
|
|
||||||
apiRouter.get("/setGuildMotd.php", setGuildMotdController);
|
apiRouter.get("/setGuildMotd.php", setGuildMotdController);
|
||||||
apiRouter.get("/setSupportedSyndicate.php", setSupportedSyndicateController);
|
apiRouter.get("/setSupportedSyndicate.php", setSupportedSyndicateController);
|
||||||
apiRouter.get("/startLibraryDailyTask.php", startLibraryDailyTaskController);
|
apiRouter.get("/startLibraryDailyTask.php", startLibraryDailyTaskController);
|
||||||
@ -209,7 +194,6 @@ apiRouter.get("/updateSession.php", updateSessionGetController);
|
|||||||
apiRouter.post("/abortDojoComponent.php", abortDojoComponentController);
|
apiRouter.post("/abortDojoComponent.php", abortDojoComponentController);
|
||||||
apiRouter.post("/activateRandomMod.php", activateRandomModController);
|
apiRouter.post("/activateRandomMod.php", activateRandomModController);
|
||||||
apiRouter.post("/addFriendImage.php", addFriendImageController);
|
apiRouter.post("/addFriendImage.php", addFriendImageController);
|
||||||
apiRouter.post("/addIgnoredUser.php", addIgnoredUserController);
|
|
||||||
apiRouter.post("/addToAlliance.php", addToAllianceController);
|
apiRouter.post("/addToAlliance.php", addToAllianceController);
|
||||||
apiRouter.post("/addToGuild.php", addToGuildController);
|
apiRouter.post("/addToGuild.php", addToGuildController);
|
||||||
apiRouter.post("/arcaneCommon.php", arcaneCommonController);
|
apiRouter.post("/arcaneCommon.php", arcaneCommonController);
|
||||||
@ -227,8 +211,6 @@ apiRouter.post("/contributeToDojoComponent.php", contributeToDojoComponentContro
|
|||||||
apiRouter.post("/contributeToVault.php", contributeToVaultController);
|
apiRouter.post("/contributeToVault.php", contributeToVaultController);
|
||||||
apiRouter.post("/createAlliance.php", createAllianceController);
|
apiRouter.post("/createAlliance.php", createAllianceController);
|
||||||
apiRouter.post("/createGuild.php", createGuildController);
|
apiRouter.post("/createGuild.php", createGuildController);
|
||||||
apiRouter.post("/crewMembers.php", crewMembersController);
|
|
||||||
apiRouter.post("/crewShipIdentifySalvage.php", crewShipIdentifySalvageController);
|
|
||||||
apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
|
apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
|
||||||
apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
|
apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
|
||||||
apiRouter.post("/destroyDojoDeco.php", destroyDojoDecoController);
|
apiRouter.post("/destroyDojoDeco.php", destroyDojoDecoController);
|
||||||
@ -241,7 +223,6 @@ apiRouter.post("/findSessions.php", findSessionsController);
|
|||||||
apiRouter.post("/fishmonger.php", fishmongerController);
|
apiRouter.post("/fishmonger.php", fishmongerController);
|
||||||
apiRouter.post("/focus.php", focusController);
|
apiRouter.post("/focus.php", focusController);
|
||||||
apiRouter.post("/fusionTreasures.php", fusionTreasuresController);
|
apiRouter.post("/fusionTreasures.php", fusionTreasuresController);
|
||||||
apiRouter.post("/gardening.php", gardeningController);
|
|
||||||
apiRouter.post("/genericUpdate.php", genericUpdateController);
|
apiRouter.post("/genericUpdate.php", genericUpdateController);
|
||||||
apiRouter.post("/getAlliance.php", getAllianceController);
|
apiRouter.post("/getAlliance.php", getAllianceController);
|
||||||
apiRouter.post("/getFriends.php", getFriendsController);
|
apiRouter.post("/getFriends.php", getFriendsController);
|
||||||
@ -252,7 +233,6 @@ apiRouter.post("/gildWeapon.php", gildWeaponController);
|
|||||||
apiRouter.post("/giveKeyChainTriggeredItems.php", giveKeyChainTriggeredItemsController);
|
apiRouter.post("/giveKeyChainTriggeredItems.php", giveKeyChainTriggeredItemsController);
|
||||||
apiRouter.post("/giveKeyChainTriggeredMessage.php", giveKeyChainTriggeredMessageController);
|
apiRouter.post("/giveKeyChainTriggeredMessage.php", giveKeyChainTriggeredMessageController);
|
||||||
apiRouter.post("/giveQuestKeyReward.php", giveQuestKeyRewardController);
|
apiRouter.post("/giveQuestKeyReward.php", giveQuestKeyRewardController);
|
||||||
apiRouter.post("/giveShipDecoAndLoreFragment.php", giveShipDecoAndLoreFragmentController);
|
|
||||||
apiRouter.post("/giveStartingGear.php", giveStartingGearController);
|
apiRouter.post("/giveStartingGear.php", giveStartingGearController);
|
||||||
apiRouter.post("/guildTech.php", guildTechController);
|
apiRouter.post("/guildTech.php", guildTechController);
|
||||||
apiRouter.post("/hostSession.php", hostSessionController);
|
apiRouter.post("/hostSession.php", hostSessionController);
|
||||||
@ -276,7 +256,6 @@ apiRouter.post("/purchase.php", purchaseController);
|
|||||||
apiRouter.post("/redeemPromoCode.php", redeemPromoCodeController);
|
apiRouter.post("/redeemPromoCode.php", redeemPromoCodeController);
|
||||||
apiRouter.post("/releasePet.php", releasePetController);
|
apiRouter.post("/releasePet.php", releasePetController);
|
||||||
apiRouter.post("/removeFromGuild.php", removeFromGuildController);
|
apiRouter.post("/removeFromGuild.php", removeFromGuildController);
|
||||||
apiRouter.post("/removeIgnoredUser.php", removeIgnoredUserController);
|
|
||||||
apiRouter.post("/rerollRandomMod.php", rerollRandomModController);
|
apiRouter.post("/rerollRandomMod.php", rerollRandomModController);
|
||||||
apiRouter.post("/retrievePetFromStasis.php", retrievePetFromStasisController);
|
apiRouter.post("/retrievePetFromStasis.php", retrievePetFromStasisController);
|
||||||
apiRouter.post("/saveDialogue.php", saveDialogueController);
|
apiRouter.post("/saveDialogue.php", saveDialogueController);
|
||||||
@ -284,17 +263,14 @@ apiRouter.post("/saveLoadout.php", saveLoadoutController);
|
|||||||
apiRouter.post("/saveSettings.php", saveSettingsController);
|
apiRouter.post("/saveSettings.php", saveSettingsController);
|
||||||
apiRouter.post("/saveVaultAutoContribute.php", saveVaultAutoContributeController);
|
apiRouter.post("/saveVaultAutoContribute.php", saveVaultAutoContributeController);
|
||||||
apiRouter.post("/sell.php", sellController);
|
apiRouter.post("/sell.php", sellController);
|
||||||
apiRouter.post("/sendMsgToInBox.php", sendMsgToInBoxController);
|
|
||||||
apiRouter.post("/setDojoComponentColors.php", setDojoComponentColorsController);
|
apiRouter.post("/setDojoComponentColors.php", setDojoComponentColorsController);
|
||||||
apiRouter.post("/setDojoComponentMessage.php", setDojoComponentMessageController);
|
apiRouter.post("/setDojoComponentMessage.php", setDojoComponentMessageController);
|
||||||
apiRouter.post("/setDojoComponentSettings.php", setDojoComponentSettingsController);
|
apiRouter.post("/setDojoComponentSettings.php", setDojoComponentSettingsController);
|
||||||
apiRouter.post("/setEquippedInstrument.php", setEquippedInstrumentController);
|
apiRouter.post("/setEquippedInstrument.php", setEquippedInstrumentController);
|
||||||
apiRouter.post("/setGuildMotd.php", setGuildMotdController);
|
apiRouter.post("/setGuildMotd.php", setGuildMotdController);
|
||||||
apiRouter.post("/setHubNpcCustomizations.php", setHubNpcCustomizationsController);
|
|
||||||
apiRouter.post("/setPlacedDecoInfo.php", setPlacedDecoInfoController);
|
apiRouter.post("/setPlacedDecoInfo.php", setPlacedDecoInfoController);
|
||||||
apiRouter.post("/setShipCustomizations.php", setShipCustomizationsController);
|
apiRouter.post("/setShipCustomizations.php", setShipCustomizationsController);
|
||||||
apiRouter.post("/setShipFavouriteLoadout.php", setShipFavouriteLoadoutController);
|
apiRouter.post("/setShipFavouriteLoadout.php", setShipFavouriteLoadoutController);
|
||||||
apiRouter.post("/setShipVignette.php", setShipVignetteController);
|
|
||||||
apiRouter.post("/setWeaponSkillTree.php", setWeaponSkillTreeController);
|
apiRouter.post("/setWeaponSkillTree.php", setWeaponSkillTreeController);
|
||||||
apiRouter.post("/shipDecorations.php", shipDecorationsController);
|
apiRouter.post("/shipDecorations.php", shipDecorationsController);
|
||||||
apiRouter.post("/startCollectibleEntry.php", startCollectibleEntryController);
|
apiRouter.post("/startCollectibleEntry.php", startCollectibleEntryController);
|
||||||
|
@ -10,19 +10,19 @@ import { getAccountInfoController } from "@/src/controllers/custom/getAccountInf
|
|||||||
import { renameAccountController } from "@/src/controllers/custom/renameAccountController";
|
import { renameAccountController } from "@/src/controllers/custom/renameAccountController";
|
||||||
import { ircDroppedController } from "@/src/controllers/custom/ircDroppedController";
|
import { ircDroppedController } from "@/src/controllers/custom/ircDroppedController";
|
||||||
import { unlockAllIntrinsicsController } from "@/src/controllers/custom/unlockAllIntrinsicsController";
|
import { unlockAllIntrinsicsController } from "@/src/controllers/custom/unlockAllIntrinsicsController";
|
||||||
import { addMissingMaxRankModsController } from "@/src/controllers/custom/addMissingMaxRankModsController";
|
|
||||||
|
|
||||||
import { createAccountController } from "@/src/controllers/custom/createAccountController";
|
import { createAccountController } from "@/src/controllers/custom/createAccountController";
|
||||||
import { createMessageController } from "@/src/controllers/custom/createMessageController";
|
import { createMessageController } from "@/src/controllers/custom/createMessageController";
|
||||||
import { addCurrencyController } from "@/src/controllers/custom/addCurrencyController";
|
import { addCurrencyController } from "@/src/controllers/custom/addCurrencyController";
|
||||||
import { addItemsController } from "@/src/controllers/custom/addItemsController";
|
import { addItemsController } from "@/src/controllers/custom/addItemsController";
|
||||||
|
import { addModularEquipmentController } from "@/src/controllers/custom/addModularEquipmentController";
|
||||||
import { addXpController } from "@/src/controllers/custom/addXpController";
|
import { addXpController } from "@/src/controllers/custom/addXpController";
|
||||||
|
import { gildEquipmentController } from "@/src/controllers/custom/gildEquipmentController";
|
||||||
import { importController } from "@/src/controllers/custom/importController";
|
import { importController } from "@/src/controllers/custom/importController";
|
||||||
import { manageQuestsController } from "@/src/controllers/custom/manageQuestsController";
|
|
||||||
import { setEvolutionProgressController } from "@/src/controllers/custom/setEvolutionProgressController";
|
|
||||||
|
|
||||||
import { getConfigDataController } from "@/src/controllers/custom/getConfigDataController";
|
import { getConfigDataController } from "@/src/controllers/custom/getConfigDataController";
|
||||||
import { updateConfigDataController } from "@/src/controllers/custom/updateConfigDataController";
|
import { updateConfigDataController } from "@/src/controllers/custom/updateConfigDataController";
|
||||||
|
import { manageQuestsController } from "@/src/controllers/custom/manageQuestsController";
|
||||||
|
|
||||||
const customRouter = express.Router();
|
const customRouter = express.Router();
|
||||||
|
|
||||||
@ -36,16 +36,16 @@ customRouter.get("/getAccountInfo", getAccountInfoController);
|
|||||||
customRouter.get("/renameAccount", renameAccountController);
|
customRouter.get("/renameAccount", renameAccountController);
|
||||||
customRouter.get("/ircDropped", ircDroppedController);
|
customRouter.get("/ircDropped", ircDroppedController);
|
||||||
customRouter.get("/unlockAllIntrinsics", unlockAllIntrinsicsController);
|
customRouter.get("/unlockAllIntrinsics", unlockAllIntrinsicsController);
|
||||||
customRouter.get("/addMissingMaxRankMods", addMissingMaxRankModsController);
|
|
||||||
|
|
||||||
customRouter.post("/createAccount", createAccountController);
|
customRouter.post("/createAccount", createAccountController);
|
||||||
customRouter.post("/createMessage", createMessageController);
|
customRouter.post("/createMessage", createMessageController);
|
||||||
customRouter.post("/addCurrency", addCurrencyController);
|
customRouter.post("/addCurrency", addCurrencyController);
|
||||||
customRouter.post("/addItems", addItemsController);
|
customRouter.post("/addItems", addItemsController);
|
||||||
|
customRouter.post("/addModularEquipment", addModularEquipmentController);
|
||||||
customRouter.post("/addXp", addXpController);
|
customRouter.post("/addXp", addXpController);
|
||||||
|
customRouter.post("/gildEquipment", gildEquipmentController);
|
||||||
customRouter.post("/import", importController);
|
customRouter.post("/import", importController);
|
||||||
customRouter.post("/manageQuests", manageQuestsController);
|
customRouter.post("/manageQuests", manageQuestsController);
|
||||||
customRouter.post("/setEvolutionProgress", setEvolutionProgressController);
|
|
||||||
|
|
||||||
customRouter.get("/config", getConfigDataController);
|
customRouter.get("/config", getConfigDataController);
|
||||||
customRouter.post("/config", updateConfigDataController);
|
customRouter.post("/config", updateConfigDataController);
|
||||||
|
@ -24,29 +24,21 @@ interface IConfig {
|
|||||||
infiniteEndo?: boolean;
|
infiniteEndo?: boolean;
|
||||||
infiniteRegalAya?: boolean;
|
infiniteRegalAya?: boolean;
|
||||||
infiniteHelminthMaterials?: boolean;
|
infiniteHelminthMaterials?: boolean;
|
||||||
dontSubtractConsumables?: boolean;
|
|
||||||
unlockAllShipFeatures?: boolean;
|
unlockAllShipFeatures?: boolean;
|
||||||
unlockAllShipDecorations?: boolean;
|
unlockAllShipDecorations?: boolean;
|
||||||
unlockAllFlavourItems?: boolean;
|
unlockAllFlavourItems?: boolean;
|
||||||
unlockAllSkins?: boolean;
|
unlockAllSkins?: boolean;
|
||||||
unlockAllCapturaScenes?: boolean;
|
unlockAllCapturaScenes?: boolean;
|
||||||
unlockAllDecoRecipes?: boolean;
|
|
||||||
universalPolarityEverywhere?: boolean;
|
universalPolarityEverywhere?: boolean;
|
||||||
unlockDoubleCapacityPotatoesEverywhere?: boolean;
|
unlockDoubleCapacityPotatoesEverywhere?: boolean;
|
||||||
unlockExilusEverywhere?: boolean;
|
unlockExilusEverywhere?: boolean;
|
||||||
unlockArcanesEverywhere?: boolean;
|
unlockArcanesEverywhere?: boolean;
|
||||||
noDailyStandingLimits?: boolean;
|
noDailyStandingLimits?: boolean;
|
||||||
noDailyFocusLimit?: boolean;
|
|
||||||
noArgonCrystalDecay?: boolean;
|
noArgonCrystalDecay?: boolean;
|
||||||
noMasteryRankUpCooldown?: boolean;
|
noMasteryRankUpCooldown?: boolean;
|
||||||
noVendorPurchaseLimits?: boolean;
|
noVendorPurchaseLimits?: boolean;
|
||||||
noDeathMarks?: boolean;
|
|
||||||
noKimCooldowns?: boolean;
|
|
||||||
instantResourceExtractorDrones?: boolean;
|
instantResourceExtractorDrones?: boolean;
|
||||||
noResourceExtractorDronesDamage?: boolean;
|
|
||||||
skipClanKeyCrafting?: boolean;
|
|
||||||
noDojoRoomBuildStage?: boolean;
|
noDojoRoomBuildStage?: boolean;
|
||||||
noDojoDecoBuildStage?: boolean;
|
|
||||||
fastDojoRoomDestruction?: boolean;
|
fastDojoRoomDestruction?: boolean;
|
||||||
noDojoResearchCosts?: boolean;
|
noDojoResearchCosts?: boolean;
|
||||||
noDojoResearchTime?: boolean;
|
noDojoResearchTime?: boolean;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Request } from "express";
|
import { Request } from "express";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { addLevelKeys, addRecipes, combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { Alliance, AllianceMember, Guild, GuildAd, GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
|
import { Alliance, AllianceMember, Guild, GuildAd, GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
|
||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import {
|
import {
|
||||||
@ -30,8 +30,6 @@ import { Inbox } from "../models/inboxModel";
|
|||||||
import { IFusionTreasure, ITypeCount } from "../types/inventoryTypes/inventoryTypes";
|
import { IFusionTreasure, ITypeCount } from "../types/inventoryTypes/inventoryTypes";
|
||||||
import { IInventoryChanges } from "../types/purchaseTypes";
|
import { IInventoryChanges } from "../types/purchaseTypes";
|
||||||
import { parallelForeach } from "../utils/async-utils";
|
import { parallelForeach } from "../utils/async-utils";
|
||||||
import allDecoRecipes from "@/static/fixed_responses/allDecoRecipes.json";
|
|
||||||
import { createMessage } from "./inboxService";
|
|
||||||
|
|
||||||
export const getGuildForRequest = async (req: Request): Promise<TGuildDatabaseDocument> => {
|
export const getGuildForRequest = async (req: Request): Promise<TGuildDatabaseDocument> => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -59,7 +57,6 @@ export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: s
|
|||||||
|
|
||||||
const members: IGuildMemberClient[] = [];
|
const members: IGuildMemberClient[] = [];
|
||||||
let missingEntry = true;
|
let missingEntry = true;
|
||||||
const dataFillInPromises: Promise<void>[] = [];
|
|
||||||
for (const guildMember of guildMembers) {
|
for (const guildMember of guildMembers) {
|
||||||
const member: IGuildMemberClient = {
|
const member: IGuildMemberClient = {
|
||||||
_id: toOid(guildMember.accountId),
|
_id: toOid(guildMember.accountId),
|
||||||
@ -71,12 +68,8 @@ export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: s
|
|||||||
if (guildMember.accountId.equals(accountId)) {
|
if (guildMember.accountId.equals(accountId)) {
|
||||||
missingEntry = false;
|
missingEntry = false;
|
||||||
} else {
|
} else {
|
||||||
dataFillInPromises.push(
|
|
||||||
(async (): Promise<void> => {
|
|
||||||
member.DisplayName = (await Account.findById(guildMember.accountId, "DisplayName"))!.DisplayName;
|
member.DisplayName = (await Account.findById(guildMember.accountId, "DisplayName"))!.DisplayName;
|
||||||
})()
|
await fillInInventoryDataForGuildMember(member);
|
||||||
);
|
|
||||||
dataFillInPromises.push(fillInInventoryDataForGuildMember(member));
|
|
||||||
}
|
}
|
||||||
members.push(member);
|
members.push(member);
|
||||||
}
|
}
|
||||||
@ -95,8 +88,6 @@ export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: s
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(dataFillInPromises);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_id: toOid(guild._id),
|
_id: toOid(guild._id),
|
||||||
Name: guild.Name,
|
Name: guild.Name,
|
||||||
@ -105,7 +96,6 @@ export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: s
|
|||||||
Members: members,
|
Members: members,
|
||||||
Ranks: guild.Ranks,
|
Ranks: guild.Ranks,
|
||||||
Tier: guild.Tier,
|
Tier: guild.Tier,
|
||||||
Emblem: guild.Emblem,
|
|
||||||
Vault: getGuildVault(guild),
|
Vault: getGuildVault(guild),
|
||||||
ActiveDojoColorResearch: guild.ActiveDojoColorResearch,
|
ActiveDojoColorResearch: guild.ActiveDojoColorResearch,
|
||||||
Class: guild.Class,
|
Class: guild.Class,
|
||||||
@ -124,17 +114,14 @@ export const getGuildVault = (guild: TGuildDatabaseDocument): IGuildVault => {
|
|||||||
DojoRefundMiscItems: guild.VaultMiscItems,
|
DojoRefundMiscItems: guild.VaultMiscItems,
|
||||||
DojoRefundPremiumCredits: guild.VaultPremiumCredits,
|
DojoRefundPremiumCredits: guild.VaultPremiumCredits,
|
||||||
ShipDecorations: guild.VaultShipDecorations,
|
ShipDecorations: guild.VaultShipDecorations,
|
||||||
FusionTreasures: guild.VaultFusionTreasures,
|
FusionTreasures: guild.VaultFusionTreasures
|
||||||
DecoRecipes: config.unlockAllDecoRecipes
|
|
||||||
? allDecoRecipes.map(recipe => ({ ItemType: recipe, ItemCount: 1 }))
|
|
||||||
: guild.VaultDecoRecipes
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDojoClient = async (
|
export const getDojoClient = async (
|
||||||
guild: TGuildDatabaseDocument,
|
guild: TGuildDatabaseDocument,
|
||||||
status: number,
|
status: number,
|
||||||
componentId?: Types.ObjectId | string
|
componentId: Types.ObjectId | string | undefined = undefined
|
||||||
): Promise<IDojoClient> => {
|
): Promise<IDojoClient> => {
|
||||||
const dojo: IDojoClient = {
|
const dojo: IDojoClient = {
|
||||||
_id: { $oid: guild._id.toString() },
|
_id: { $oid: guild._id.toString() },
|
||||||
@ -160,7 +147,6 @@ export const getDojoClient = async (
|
|||||||
if (!componentId || dojoComponent._id.equals(componentId)) {
|
if (!componentId || dojoComponent._id.equals(componentId)) {
|
||||||
const clientComponent: IDojoComponentClient = {
|
const clientComponent: IDojoComponentClient = {
|
||||||
id: toOid(dojoComponent._id),
|
id: toOid(dojoComponent._id),
|
||||||
SortId: toOid(dojoComponent.SortId ?? dojoComponent._id), // always providing a SortId so decos don't need repositioning to reparent
|
|
||||||
pf: dojoComponent.pf,
|
pf: dojoComponent.pf,
|
||||||
ppf: dojoComponent.ppf,
|
ppf: dojoComponent.ppf,
|
||||||
Name: dojoComponent.Name,
|
Name: dojoComponent.Name,
|
||||||
@ -223,7 +209,6 @@ export const getDojoClient = async (
|
|||||||
Type: deco.Type,
|
Type: deco.Type,
|
||||||
Pos: deco.Pos,
|
Pos: deco.Pos,
|
||||||
Rot: deco.Rot,
|
Rot: deco.Rot,
|
||||||
Scale: deco.Scale,
|
|
||||||
Name: deco.Name,
|
Name: deco.Name,
|
||||||
Sockets: deco.Sockets,
|
Sockets: deco.Sockets,
|
||||||
PictureFrameInfo: deco.PictureFrameInfo
|
PictureFrameInfo: deco.PictureFrameInfo
|
||||||
@ -505,7 +490,7 @@ export const hasGuildPermissionEx = (
|
|||||||
|
|
||||||
export const removePigmentsFromGuildMembers = async (guildId: string | Types.ObjectId): Promise<void> => {
|
export const removePigmentsFromGuildMembers = async (guildId: string | Types.ObjectId): Promise<void> => {
|
||||||
const members = await GuildMember.find({ guildId, status: 0 }, "accountId");
|
const members = await GuildMember.find({ guildId, status: 0 }, "accountId");
|
||||||
await parallelForeach(members, async member => {
|
for (const member of members) {
|
||||||
const inventory = await getInventory(member.accountId.toString(), "MiscItems");
|
const inventory = await getInventory(member.accountId.toString(), "MiscItems");
|
||||||
const index = inventory.MiscItems.findIndex(
|
const index = inventory.MiscItems.findIndex(
|
||||||
x => x.ItemType == "/Lotus/Types/Items/Research/DojoColors/GenericDojoColorPigment"
|
x => x.ItemType == "/Lotus/Types/Items/Research/DojoColors/GenericDojoColorPigment"
|
||||||
@ -514,7 +499,7 @@ export const removePigmentsFromGuildMembers = async (guildId: string | Types.Obj
|
|||||||
inventory.MiscItems.splice(index, 1);
|
inventory.MiscItems.splice(index, 1);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const processGuildTechProjectContributionsUpdate = async (
|
export const processGuildTechProjectContributionsUpdate = async (
|
||||||
@ -554,7 +539,7 @@ export const setGuildTechLogState = (
|
|||||||
guild: TGuildDatabaseDocument,
|
guild: TGuildDatabaseDocument,
|
||||||
type: string,
|
type: string,
|
||||||
state: number,
|
state: number,
|
||||||
dateTime?: Date
|
dateTime: Date | undefined = undefined
|
||||||
): boolean => {
|
): boolean => {
|
||||||
guild.TechChanges ??= [];
|
guild.TechChanges ??= [];
|
||||||
const entry = guild.TechChanges.find(x => x.details == type);
|
const entry = guild.TechChanges.find(x => x.details == type);
|
||||||
@ -611,76 +596,6 @@ const setGuildTier = async (guild: TGuildDatabaseDocument, newTier: number): Pro
|
|||||||
await processGuildTechProjectContributionsUpdate(guild, project);
|
await processGuildTechProjectContributionsUpdate(guild, project);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (guild.CeremonyContributors) {
|
|
||||||
await checkClanAscensionHasRequiredContributors(guild);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const checkClanAscensionHasRequiredContributors = async (guild: TGuildDatabaseDocument): Promise<void> => {
|
|
||||||
const requiredContributors = [1, 5, 15, 30, 50][guild.Tier - 1];
|
|
||||||
// Once required contributor count is hit, the class is committed and there's 72 hours to claim endo.
|
|
||||||
if (guild.CeremonyContributors!.length >= requiredContributors) {
|
|
||||||
guild.Class = guild.CeremonyClass!;
|
|
||||||
guild.CeremonyClass = undefined;
|
|
||||||
guild.CeremonyResetDate = new Date(Date.now() + (config.fastClanAscension ? 5_000 : 72 * 3600_000));
|
|
||||||
if (!config.fastClanAscension) {
|
|
||||||
// Send message to all active guild members
|
|
||||||
const members = await GuildMember.find({ guildId: guild._id, status: 0 }, "accountId");
|
|
||||||
await parallelForeach(members, async member => {
|
|
||||||
// somewhat unfaithful as on live the "msg" is not a loctag, but since we don't have the string, we'll let the client fill it in with "arg".
|
|
||||||
await createMessage(member.accountId, [
|
|
||||||
{
|
|
||||||
sndr: guild.Name,
|
|
||||||
msg: "/Lotus/Language/Clan/Clan_AscensionCeremonyInProgressDetails",
|
|
||||||
arg: [
|
|
||||||
{
|
|
||||||
Key: "RESETDATE",
|
|
||||||
Tag:
|
|
||||||
guild.CeremonyResetDate!.getUTCMonth() +
|
|
||||||
"/" +
|
|
||||||
guild.CeremonyResetDate!.getUTCDate() +
|
|
||||||
"/" +
|
|
||||||
(guild.CeremonyResetDate!.getUTCFullYear() % 100) +
|
|
||||||
" " +
|
|
||||||
guild.CeremonyResetDate!.getUTCHours().toString().padStart(2, "0") +
|
|
||||||
":" +
|
|
||||||
guild.CeremonyResetDate!.getUTCMinutes().toString().padStart(2, "0")
|
|
||||||
}
|
|
||||||
],
|
|
||||||
sub: "/Lotus/Language/Clan/Clan_AscensionCeremonyInProgress",
|
|
||||||
icon: "/Lotus/Interface/Graphics/ClanTileImages/ClanEnterDojo.png",
|
|
||||||
highPriority: true
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const giveClanKey = (inventory: TInventoryDatabaseDocument, inventoryChanges?: IInventoryChanges): void => {
|
|
||||||
if (config.skipClanKeyCrafting) {
|
|
||||||
const levelKeyChanges = [
|
|
||||||
{
|
|
||||||
ItemType: "/Lotus/Types/Keys/DojoKey",
|
|
||||||
ItemCount: 1
|
|
||||||
}
|
|
||||||
];
|
|
||||||
addLevelKeys(inventory, levelKeyChanges);
|
|
||||||
if (inventoryChanges) {
|
|
||||||
combineInventoryChanges(inventoryChanges, { LevelKeys: levelKeyChanges });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const recipeChanges = [
|
|
||||||
{
|
|
||||||
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
|
|
||||||
ItemCount: 1
|
|
||||||
}
|
|
||||||
];
|
|
||||||
addRecipes(inventory, recipeChanges);
|
|
||||||
if (inventoryChanges) {
|
|
||||||
combineInventoryChanges(inventoryChanges, { Recipes: recipeChanges });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const removeDojoKeyItems = (inventory: TInventoryDatabaseDocument): IInventoryChanges => {
|
export const removeDojoKeyItems = (inventory: TInventoryDatabaseDocument): IInventoryChanges => {
|
||||||
|
@ -2,7 +2,6 @@ import { Types } from "mongoose";
|
|||||||
import {
|
import {
|
||||||
IEquipmentClient,
|
IEquipmentClient,
|
||||||
IEquipmentDatabase,
|
IEquipmentDatabase,
|
||||||
IItemConfig,
|
|
||||||
IOperatorConfigClient,
|
IOperatorConfigClient,
|
||||||
IOperatorConfigDatabase
|
IOperatorConfigDatabase
|
||||||
} from "../types/inventoryTypes/commonInventoryTypes";
|
} from "../types/inventoryTypes/commonInventoryTypes";
|
||||||
@ -38,7 +37,6 @@ import {
|
|||||||
} from "../types/inventoryTypes/inventoryTypes";
|
} from "../types/inventoryTypes/inventoryTypes";
|
||||||
import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel";
|
import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel";
|
||||||
import { ILoadoutConfigDatabase, ILoadoutDatabase } from "../types/saveLoadoutTypes";
|
import { ILoadoutConfigDatabase, ILoadoutDatabase } from "../types/saveLoadoutTypes";
|
||||||
import { slotNames } from "../types/purchaseTypes";
|
|
||||||
|
|
||||||
const convertDate = (value: IMongoDate): Date => {
|
const convertDate = (value: IMongoDate): Date => {
|
||||||
return new Date(parseInt(value.$date.$numberLong));
|
return new Date(parseInt(value.$date.$numberLong));
|
||||||
@ -106,18 +104,18 @@ const replaceSlots = (db: ISlots, client: ISlots): void => {
|
|||||||
db.Slots = client.Slots;
|
db.Slots = client.Slots;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const importCrewMemberId = (crewMemberId: ICrewShipMemberClient): ICrewShipMemberDatabase => {
|
const convertCrewShipMember = (client: ICrewShipMemberClient): ICrewShipMemberDatabase => {
|
||||||
if (crewMemberId.ItemId) {
|
return {
|
||||||
return { ItemId: new Types.ObjectId(crewMemberId.ItemId.$oid) };
|
...client,
|
||||||
}
|
ItemId: client.ItemId ? new Types.ObjectId(client.ItemId.$oid) : undefined
|
||||||
return { NemesisFingerprint: BigInt(crewMemberId.NemesisFingerprint ?? 0) };
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const convertCrewShipMembers = (client: ICrewShipMembersClient): ICrewShipMembersDatabase => {
|
const convertCrewShipMembers = (client: ICrewShipMembersClient): ICrewShipMembersDatabase => {
|
||||||
return {
|
return {
|
||||||
SLOT_A: client.SLOT_A ? importCrewMemberId(client.SLOT_A) : undefined,
|
SLOT_A: client.SLOT_A ? convertCrewShipMember(client.SLOT_A) : undefined,
|
||||||
SLOT_B: client.SLOT_B ? importCrewMemberId(client.SLOT_B) : undefined,
|
SLOT_B: client.SLOT_B ? convertCrewShipMember(client.SLOT_B) : undefined,
|
||||||
SLOT_C: client.SLOT_C ? importCrewMemberId(client.SLOT_C) : undefined
|
SLOT_C: client.SLOT_C ? convertCrewShipMember(client.SLOT_C) : undefined
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -170,25 +168,10 @@ const convertPendingRecipe = (client: IPendingRecipeClient): IPendingRecipeDatab
|
|||||||
const convertNemesis = (client: INemesisClient): INemesisDatabase => {
|
const convertNemesis = (client: INemesisClient): INemesisDatabase => {
|
||||||
return {
|
return {
|
||||||
...client,
|
...client,
|
||||||
fp: BigInt(client.fp),
|
|
||||||
d: convertDate(client.d)
|
d: convertDate(client.d)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Empty objects from live may have been encoded as empty arrays because of PHP.
|
|
||||||
const convertItemConfig = <T extends IItemConfig>(client: T): T => {
|
|
||||||
return {
|
|
||||||
...client,
|
|
||||||
pricol: Array.isArray(client.pricol) ? {} : client.pricol,
|
|
||||||
attcol: Array.isArray(client.attcol) ? {} : client.attcol,
|
|
||||||
sigcol: Array.isArray(client.sigcol) ? {} : client.sigcol,
|
|
||||||
eyecol: Array.isArray(client.eyecol) ? {} : client.eyecol,
|
|
||||||
facial: Array.isArray(client.facial) ? {} : client.facial,
|
|
||||||
cloth: Array.isArray(client.cloth) ? {} : client.cloth,
|
|
||||||
syancol: Array.isArray(client.syancol) ? {} : client.syancol
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<IInventoryClient>): void => {
|
export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<IInventoryClient>): void => {
|
||||||
for (const key of equipmentKeys) {
|
for (const key of equipmentKeys) {
|
||||||
if (client[key] !== undefined) {
|
if (client[key] !== undefined) {
|
||||||
@ -229,28 +212,35 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
|
|||||||
replaceArray<IOperatorConfigDatabase>(db[key], client[key].map(convertOperatorConfig));
|
replaceArray<IOperatorConfigDatabase>(db[key], client[key].map(convertOperatorConfig));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const key of slotNames) {
|
for (const key of [
|
||||||
|
"SuitBin",
|
||||||
|
"WeaponBin",
|
||||||
|
"SentinelBin",
|
||||||
|
"SpaceSuitBin",
|
||||||
|
"SpaceWeaponBin",
|
||||||
|
"PvpBonusLoadoutBin",
|
||||||
|
"PveBonusLoadoutBin",
|
||||||
|
"RandomModBin",
|
||||||
|
"MechBin",
|
||||||
|
"CrewMemberBin",
|
||||||
|
"OperatorAmpBin",
|
||||||
|
"CrewShipSalvageBin"
|
||||||
|
] as const) {
|
||||||
if (client[key] !== undefined) {
|
if (client[key] !== undefined) {
|
||||||
replaceSlots(db[key], client[key]);
|
replaceSlots(db[key], client[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// boolean
|
|
||||||
for (const key of [
|
for (const key of [
|
||||||
"UseAdultOperatorLoadout",
|
"UseAdultOperatorLoadout",
|
||||||
"HasOwnedVoidProjectionsPreviously",
|
"HasOwnedVoidProjectionsPreviously",
|
||||||
"ReceivedStartingGear",
|
"ReceivedStartingGear",
|
||||||
"ArchwingEnabled",
|
"ArchwingEnabled",
|
||||||
"PlayedParkourTutorial",
|
"PlayedParkourTutorial"
|
||||||
"Staff",
|
|
||||||
"Moderator",
|
|
||||||
"Partner",
|
|
||||||
"Counselor"
|
|
||||||
] as const) {
|
] as const) {
|
||||||
if (client[key] !== undefined) {
|
if (client[key] !== undefined) {
|
||||||
db[key] = client[key];
|
db[key] = client[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// number
|
|
||||||
for (const key of [
|
for (const key of [
|
||||||
"PlayerLevel",
|
"PlayerLevel",
|
||||||
"RegularCredits",
|
"RegularCredits",
|
||||||
@ -260,15 +250,12 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
|
|||||||
"PrimeTokens",
|
"PrimeTokens",
|
||||||
"TradesRemaining",
|
"TradesRemaining",
|
||||||
"GiftsRemaining",
|
"GiftsRemaining",
|
||||||
"ChallengesFixVersion",
|
"ChallengesFixVersion"
|
||||||
"Founder",
|
|
||||||
"Guide"
|
|
||||||
] as const) {
|
] as const) {
|
||||||
if (client[key] !== undefined) {
|
if (client[key] !== undefined) {
|
||||||
db[key] = client[key];
|
db[key] = client[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// string
|
|
||||||
for (const key of [
|
for (const key of [
|
||||||
"ThemeStyle",
|
"ThemeStyle",
|
||||||
"ThemeBackground",
|
"ThemeBackground",
|
||||||
@ -283,7 +270,6 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
|
|||||||
db[key] = client[key];
|
db[key] = client[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// string[]
|
|
||||||
for (const key of [
|
for (const key of [
|
||||||
"EquippedGear",
|
"EquippedGear",
|
||||||
"EquippedEmotes",
|
"EquippedEmotes",
|
||||||
@ -367,7 +353,7 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
|
|||||||
db.PlayerSkills = client.PlayerSkills;
|
db.PlayerSkills = client.PlayerSkills;
|
||||||
}
|
}
|
||||||
if (client.LotusCustomization !== undefined) {
|
if (client.LotusCustomization !== undefined) {
|
||||||
db.LotusCustomization = convertItemConfig(client.LotusCustomization);
|
db.LotusCustomization = client.LotusCustomization;
|
||||||
}
|
}
|
||||||
if (client.CollectibleSeries !== undefined) {
|
if (client.CollectibleSeries !== undefined) {
|
||||||
db.CollectibleSeries = client.CollectibleSeries;
|
db.CollectibleSeries = client.CollectibleSeries;
|
||||||
@ -394,9 +380,6 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (client.Accolades !== undefined) {
|
|
||||||
db.Accolades = client.Accolades;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const convertLoadOutConfig = (client: ILoadoutConfigClient): ILoadoutConfigDatabase => {
|
const convertLoadOutConfig = (client: ILoadoutConfigClient): ILoadoutConfigDatabase => {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -17,7 +17,6 @@ import {
|
|||||||
dict_uk,
|
dict_uk,
|
||||||
dict_zh,
|
dict_zh,
|
||||||
ExportArcanes,
|
ExportArcanes,
|
||||||
ExportBoosters,
|
|
||||||
ExportCustoms,
|
ExportCustoms,
|
||||||
ExportDrones,
|
ExportDrones,
|
||||||
ExportGear,
|
ExportGear,
|
||||||
@ -186,15 +185,14 @@ export const getKeyChainMessage = ({ KeyChain, ChainStage }: IKeyChainRequest):
|
|||||||
throw new Error(`KeyChain ${KeyChain} does not contain chain stages`);
|
throw new Error(`KeyChain ${KeyChain} does not contain chain stages`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let i = ChainStage;
|
const keyChainStage = chainStages[ChainStage];
|
||||||
let chainStageMessage = chainStages[i].messageToSendWhenTriggered;
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
while (!chainStageMessage) {
|
if (!keyChainStage) {
|
||||||
if (++i >= chainStages.length) {
|
throw new Error(`KeyChainStage ${ChainStage} not found`);
|
||||||
break;
|
|
||||||
}
|
|
||||||
chainStageMessage = chainStages[i].messageToSendWhenTriggered;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const chainStageMessage = keyChainStage.messageToSendWhenTriggered;
|
||||||
|
|
||||||
if (!chainStageMessage) {
|
if (!chainStageMessage) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`client requested key chain message in keychain ${KeyChain} at stage ${ChainStage} but they did not exist`
|
`client requested key chain message in keychain ${KeyChain} at stage ${ChainStage} but they did not exist`
|
||||||
@ -218,30 +216,15 @@ export const convertInboxMessage = (message: IInboxMessage): IMessage => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const isStoreItem = (type: string): boolean => {
|
export const isStoreItem = (type: string): boolean => {
|
||||||
return type.startsWith("/Lotus/StoreItems/") || type in ExportBoosters;
|
return type.startsWith("/Lotus/StoreItems/");
|
||||||
};
|
};
|
||||||
|
|
||||||
export const toStoreItem = (type: string): string => {
|
export const toStoreItem = (type: string): string => {
|
||||||
if (type.startsWith("/Lotus/Types/StoreItems/Boosters/")) {
|
|
||||||
const boosterEntry = Object.entries(ExportBoosters).find(arr => arr[1].typeName == type);
|
|
||||||
if (boosterEntry) {
|
|
||||||
return boosterEntry[0];
|
|
||||||
}
|
|
||||||
throw new Error(`could not convert ${type} to a store item`);
|
|
||||||
}
|
|
||||||
return "/Lotus/StoreItems/" + type.substring("/Lotus/".length);
|
return "/Lotus/StoreItems/" + type.substring("/Lotus/".length);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fromStoreItem = (type: string): string => {
|
export const fromStoreItem = (type: string): string => {
|
||||||
if (type.startsWith("/Lotus/StoreItems/")) {
|
|
||||||
return "/Lotus/" + type.substring("/Lotus/StoreItems/".length);
|
return "/Lotus/" + type.substring("/Lotus/StoreItems/".length);
|
||||||
}
|
|
||||||
|
|
||||||
if (type in ExportBoosters) {
|
|
||||||
return ExportBoosters[type].typeName;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(`${type} is not a store item`);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDefaultUpgrades = (parts: string[]): IDefaultUpgrade[] | undefined => {
|
export const getDefaultUpgrades = (parts: string[]): IDefaultUpgrade[] | undefined => {
|
||||||
|
@ -8,7 +8,7 @@ export const submitLeaderboardScore = async (
|
|||||||
ownerId: string,
|
ownerId: string,
|
||||||
displayName: string,
|
displayName: string,
|
||||||
score: number,
|
score: number,
|
||||||
guildId: string | undefined
|
guildId?: string
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
let expiry: Date;
|
let expiry: Date;
|
||||||
if (schedule == "daily") {
|
if (schedule == "daily") {
|
||||||
@ -39,9 +39,9 @@ export const getLeaderboard = async (
|
|||||||
leaderboard: string,
|
leaderboard: string,
|
||||||
before: number,
|
before: number,
|
||||||
after: number,
|
after: number,
|
||||||
pivotId: string | undefined,
|
pivotId?: string,
|
||||||
guildId: string | undefined,
|
guildId?: string,
|
||||||
guildTier: number | undefined
|
guildTier?: number
|
||||||
): Promise<ILeaderboardEntryClient[]> => {
|
): Promise<ILeaderboardEntryClient[]> => {
|
||||||
const filter: { leaderboard: string; guildId?: string; guildTier?: number } = { leaderboard };
|
const filter: { leaderboard: string; guildId?: string; guildTier?: number } = { leaderboard };
|
||||||
if (guildId) {
|
if (guildId) {
|
||||||
|
@ -77,6 +77,7 @@ const getRandomLoginReward = (rng: CRng, day: number, inventory: TInventoryDatab
|
|||||||
const reward = rng.randomReward(randomRewards)!;
|
const reward = rng.randomReward(randomRewards)!;
|
||||||
//const reward = randomRewards.find(x => x.RewardType == "RT_BOOSTER")!;
|
//const reward = randomRewards.find(x => x.RewardType == "RT_BOOSTER")!;
|
||||||
if (reward.RewardType == "RT_RANDOM_RECIPE") {
|
if (reward.RewardType == "RT_RANDOM_RECIPE") {
|
||||||
|
// Not very faithful implementation but roughly the same idea
|
||||||
const masteredItems = new Set();
|
const masteredItems = new Set();
|
||||||
for (const entry of inventory.XPInfo) {
|
for (const entry of inventory.XPInfo) {
|
||||||
masteredItems.add(entry.ItemType);
|
masteredItems.add(entry.ItemType);
|
||||||
@ -94,15 +95,15 @@ const getRandomLoginReward = (rng: CRng, day: number, inventory: TInventoryDatab
|
|||||||
}
|
}
|
||||||
const eligibleRecipes: string[] = [];
|
const eligibleRecipes: string[] = [];
|
||||||
for (const [uniqueName, recipe] of Object.entries(ExportRecipes)) {
|
for (const [uniqueName, recipe] of Object.entries(ExportRecipes)) {
|
||||||
if (!recipe.excludeFromMarket && unmasteredItems.has(recipe.resultType)) {
|
if (unmasteredItems.has(recipe.resultType)) {
|
||||||
eligibleRecipes.push(uniqueName);
|
eligibleRecipes.push(uniqueName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (eligibleRecipes.length == 0) {
|
if (eligibleRecipes.length == 0) {
|
||||||
// This account has all applicable warframes and weapons already mastered (filthy cheater), need a different reward.
|
// This account has all warframes and weapons already mastered (filthy cheater), need a different reward.
|
||||||
return getRandomLoginReward(rng, day, inventory);
|
return getRandomLoginReward(rng, day, inventory);
|
||||||
}
|
}
|
||||||
reward.StoreItemType = toStoreItem(rng.randomElement(eligibleRecipes)!);
|
reward.StoreItemType = toStoreItem(rng.randomElement(eligibleRecipes));
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
//_id: toOid(new Types.ObjectId()),
|
//_id: toOid(new Types.ObjectId()),
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,9 @@
|
|||||||
import { PersonalRooms } from "@/src/models/personalRoomsModel";
|
import { PersonalRooms } from "@/src/models/personalRoomsModel";
|
||||||
import { addItem, getInventory } from "@/src/services/inventoryService";
|
import { addItem, getInventory } from "@/src/services/inventoryService";
|
||||||
import { TPersonalRoomsDatabaseDocument } from "../types/personalRoomsTypes";
|
import { TPersonalRoomsDatabaseDocument } from "../types/personalRoomsTypes";
|
||||||
import { IGardeningDatabase } from "../types/shipTypes";
|
|
||||||
import { getRandomElement } from "./rngService";
|
|
||||||
|
|
||||||
export const getPersonalRooms = async (
|
export const getPersonalRooms = async (accountId: string): Promise<TPersonalRoomsDatabaseDocument> => {
|
||||||
accountId: string,
|
const personalRooms = await PersonalRooms.findOne({ personalRoomsOwnerId: accountId });
|
||||||
projection?: string
|
|
||||||
): Promise<TPersonalRoomsDatabaseDocument> => {
|
|
||||||
const personalRooms = await PersonalRooms.findOne({ personalRoomsOwnerId: accountId }, projection);
|
|
||||||
|
|
||||||
if (!personalRooms) {
|
if (!personalRooms) {
|
||||||
throw new Error(`personal rooms not found for account ${accountId}`);
|
throw new Error(`personal rooms not found for account ${accountId}`);
|
||||||
@ -30,64 +25,3 @@ export const updateShipFeature = async (accountId: string, shipFeature: string):
|
|||||||
await addItem(inventory, shipFeature, -1);
|
await addItem(inventory, shipFeature, -1);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createGarden = (): IGardeningDatabase => {
|
|
||||||
const plantTypes = [
|
|
||||||
"/Lotus/Types/Items/Plants/MiscItems/DuvxDuviriGrowingPlantA",
|
|
||||||
"/Lotus/Types/Items/Plants/MiscItems/DuvxDuviriGrowingPlantB",
|
|
||||||
"/Lotus/Types/Items/Plants/MiscItems/DuvxDuviriGrowingPlantC",
|
|
||||||
"/Lotus/Types/Items/Plants/MiscItems/DuvxDuviriGrowingPlantD",
|
|
||||||
"/Lotus/Types/Items/Plants/MiscItems/DuvxDuviriGrowingPlantE",
|
|
||||||
"/Lotus/Types/Items/Plants/MiscItems/DuvxDuviriGrowingPlantF"
|
|
||||||
];
|
|
||||||
const endTime = new Date((Math.trunc(Date.now() / 1000) + 79200) * 1000); // Plants will take 22 hours to grow
|
|
||||||
return {
|
|
||||||
Planters: [
|
|
||||||
{
|
|
||||||
Name: "Garden0",
|
|
||||||
Plants: [
|
|
||||||
{
|
|
||||||
PlantType: getRandomElement(plantTypes)!,
|
|
||||||
EndTime: endTime,
|
|
||||||
PlotIndex: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
PlantType: getRandomElement(plantTypes)!,
|
|
||||||
EndTime: endTime,
|
|
||||||
PlotIndex: 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Garden1",
|
|
||||||
Plants: [
|
|
||||||
{
|
|
||||||
PlantType: getRandomElement(plantTypes)!,
|
|
||||||
EndTime: endTime,
|
|
||||||
PlotIndex: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
PlantType: getRandomElement(plantTypes)!,
|
|
||||||
EndTime: endTime,
|
|
||||||
PlotIndex: 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Garden2",
|
|
||||||
Plants: [
|
|
||||||
{
|
|
||||||
PlantType: getRandomElement(plantTypes)!,
|
|
||||||
EndTime: endTime,
|
|
||||||
PlotIndex: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
PlantType: getRandomElement(plantTypes)!,
|
|
||||||
EndTime: endTime,
|
|
||||||
PlotIndex: 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
@ -66,18 +66,6 @@ export const handlePurchase = async (
|
|||||||
if (!offer) {
|
if (!offer) {
|
||||||
throw new Error(`unknown vendor offer: ${ItemId ? ItemId : purchaseRequest.PurchaseParams.StoreItem}`);
|
throw new Error(`unknown vendor offer: ${ItemId ? ItemId : purchaseRequest.PurchaseParams.StoreItem}`);
|
||||||
}
|
}
|
||||||
if (offer.RegularPrice) {
|
|
||||||
combineInventoryChanges(
|
|
||||||
prePurchaseInventoryChanges,
|
|
||||||
updateCurrency(inventory, offer.RegularPrice[0], false)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (offer.PremiumPrice) {
|
|
||||||
combineInventoryChanges(
|
|
||||||
prePurchaseInventoryChanges,
|
|
||||||
updateCurrency(inventory, offer.PremiumPrice[0], true)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (offer.ItemPrices) {
|
if (offer.ItemPrices) {
|
||||||
handleItemPrices(
|
handleItemPrices(
|
||||||
inventory,
|
inventory,
|
||||||
@ -153,8 +141,7 @@ export const handlePurchase = async (
|
|||||||
inventory,
|
inventory,
|
||||||
purchaseRequest.PurchaseParams.Quantity,
|
purchaseRequest.PurchaseParams.Quantity,
|
||||||
undefined,
|
undefined,
|
||||||
false,
|
undefined,
|
||||||
purchaseRequest.PurchaseParams.UsePremium,
|
|
||||||
seed
|
seed
|
||||||
);
|
);
|
||||||
combineInventoryChanges(purchaseResponse.InventoryChanges, prePurchaseInventoryChanges);
|
combineInventoryChanges(purchaseResponse.InventoryChanges, prePurchaseInventoryChanges);
|
||||||
@ -182,9 +169,6 @@ export const handlePurchase = async (
|
|||||||
purchaseResponse.InventoryChanges,
|
purchaseResponse.InventoryChanges,
|
||||||
updateCurrency(inventory, offer.RegularPrice, false)
|
updateCurrency(inventory, offer.RegularPrice, false)
|
||||||
);
|
);
|
||||||
if (purchaseRequest.PurchaseParams.ExpectedPrice) {
|
|
||||||
throw new Error(`vendor purchase should not have an expected price`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const invItem: IMiscItem = {
|
const invItem: IMiscItem = {
|
||||||
ItemType: "/Lotus/Types/Items/MiscItems/PrimeBucks",
|
ItemType: "/Lotus/Types/Items/MiscItems/PrimeBucks",
|
||||||
@ -238,18 +222,12 @@ export const handlePurchase = async (
|
|||||||
const vendor = ExportVendors[purchaseRequest.PurchaseParams.SourceId!];
|
const vendor = ExportVendors[purchaseRequest.PurchaseParams.SourceId!];
|
||||||
const offer = vendor.items.find(x => x.storeItem == purchaseRequest.PurchaseParams.StoreItem);
|
const offer = vendor.items.find(x => x.storeItem == purchaseRequest.PurchaseParams.StoreItem);
|
||||||
if (offer) {
|
if (offer) {
|
||||||
if (typeof offer.credits == "number") {
|
if (offer.credits) {
|
||||||
combineInventoryChanges(
|
combineInventoryChanges(
|
||||||
purchaseResponse.InventoryChanges,
|
purchaseResponse.InventoryChanges,
|
||||||
updateCurrency(inventory, offer.credits, false)
|
updateCurrency(inventory, offer.credits, false)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (typeof offer.platinum == "number") {
|
|
||||||
combineInventoryChanges(
|
|
||||||
purchaseResponse.InventoryChanges,
|
|
||||||
updateCurrency(inventory, offer.platinum, true)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (offer.itemPrices) {
|
if (offer.itemPrices) {
|
||||||
handleItemPrices(
|
handleItemPrices(
|
||||||
inventory,
|
inventory,
|
||||||
@ -260,9 +238,6 @@ export const handlePurchase = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (purchaseRequest.PurchaseParams.ExpectedPrice) {
|
|
||||||
throw new Error(`vendor purchase should not have an expected price`);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 18: {
|
case 18: {
|
||||||
if (purchaseRequest.PurchaseParams.SourceId! != worldState.PrimeVaultTraders[0]._id.$oid) {
|
if (purchaseRequest.PurchaseParams.SourceId! != worldState.PrimeVaultTraders[0]._id.$oid) {
|
||||||
@ -356,7 +331,6 @@ export const handleStoreItemAcquisition = async (
|
|||||||
quantity: number = 1,
|
quantity: number = 1,
|
||||||
durability: TRarity = "COMMON",
|
durability: TRarity = "COMMON",
|
||||||
ignorePurchaseQuantity: boolean = false,
|
ignorePurchaseQuantity: boolean = false,
|
||||||
premiumPurchase: boolean = true,
|
|
||||||
seed?: bigint
|
seed?: bigint
|
||||||
): Promise<IPurchaseResponse> => {
|
): Promise<IPurchaseResponse> => {
|
||||||
let purchaseResponse = {
|
let purchaseResponse = {
|
||||||
@ -378,20 +352,11 @@ export const handleStoreItemAcquisition = async (
|
|||||||
}
|
}
|
||||||
switch (storeCategory) {
|
switch (storeCategory) {
|
||||||
default: {
|
default: {
|
||||||
purchaseResponse = {
|
purchaseResponse = { InventoryChanges: await addItem(inventory, internalName, quantity, true, seed) };
|
||||||
InventoryChanges: await addItem(inventory, internalName, quantity, premiumPurchase, seed)
|
|
||||||
};
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "Types":
|
case "Types":
|
||||||
purchaseResponse = await handleTypesPurchase(
|
purchaseResponse = await handleTypesPurchase(internalName, inventory, quantity, ignorePurchaseQuantity);
|
||||||
internalName,
|
|
||||||
inventory,
|
|
||||||
quantity,
|
|
||||||
ignorePurchaseQuantity,
|
|
||||||
premiumPurchase,
|
|
||||||
seed
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case "Boosters":
|
case "Boosters":
|
||||||
purchaseResponse = handleBoostersPurchase(storeItemName, inventory, durability);
|
purchaseResponse = handleBoostersPurchase(storeItemName, inventory, durability);
|
||||||
@ -513,15 +478,13 @@ const handleTypesPurchase = async (
|
|||||||
typesName: string,
|
typesName: string,
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
quantity: number,
|
quantity: number,
|
||||||
ignorePurchaseQuantity: boolean,
|
ignorePurchaseQuantity: boolean
|
||||||
premiumPurchase: boolean = true,
|
|
||||||
seed?: bigint
|
|
||||||
): Promise<IPurchaseResponse> => {
|
): Promise<IPurchaseResponse> => {
|
||||||
const typeCategory = getStoreItemTypesCategory(typesName);
|
const typeCategory = getStoreItemTypesCategory(typesName);
|
||||||
logger.debug(`type category ${typeCategory}`);
|
logger.debug(`type category ${typeCategory}`);
|
||||||
switch (typeCategory) {
|
switch (typeCategory) {
|
||||||
default:
|
default:
|
||||||
return { InventoryChanges: await addItem(inventory, typesName, quantity, premiumPurchase, seed) };
|
return { InventoryChanges: await addItem(inventory, typesName, quantity) };
|
||||||
case "BoosterPacks":
|
case "BoosterPacks":
|
||||||
return handleBoosterPackPurchase(typesName, inventory, quantity);
|
return handleBoosterPackPurchase(typesName, inventory, quantity);
|
||||||
case "SlotItems":
|
case "SlotItems":
|
||||||
|
@ -191,25 +191,6 @@ const getQuestCompletionItems = (questKey: string): ITypeCount[] | undefined =>
|
|||||||
return items;
|
return items;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Checks that `questKey` is in `requirements`, and if so, that all other quests in `requirements` are also already completed.
|
|
||||||
const doesQuestCompletionFinishSet = (
|
|
||||||
inventory: TInventoryDatabaseDocument,
|
|
||||||
questKey: string,
|
|
||||||
requirements: string[]
|
|
||||||
): boolean => {
|
|
||||||
let holds = false;
|
|
||||||
for (const requirement of requirements) {
|
|
||||||
if (questKey == requirement) {
|
|
||||||
holds = true;
|
|
||||||
} else {
|
|
||||||
if (!inventory.QuestKeys.find(x => x.ItemType == requirement)?.Completed) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return holds;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleQuestCompletion = async (
|
const handleQuestCompletion = async (
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
questKey: string,
|
questKey: string,
|
||||||
@ -235,44 +216,6 @@ const handleQuestCompletion = async (
|
|||||||
setupKahlSyndicate(inventory);
|
setupKahlSyndicate(inventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whispers in the Walls is unlocked once The New + Heart of Deimos are completed.
|
|
||||||
if (
|
|
||||||
doesQuestCompletionFinishSet(inventory, questKey, [
|
|
||||||
"/Lotus/Types/Keys/NewWarQuest/NewWarQuestKeyChain",
|
|
||||||
"/Lotus/Types/Keys/InfestedMicroplanetQuest/InfestedMicroplanetQuestKeyChain"
|
|
||||||
])
|
|
||||||
) {
|
|
||||||
await createMessage(inventory.accountOwnerId, [
|
|
||||||
{
|
|
||||||
sndr: "/Lotus/Language/Bosses/Loid",
|
|
||||||
msg: "/Lotus/Language/EntratiLab/EntratiQuest/WiTWQuestRecievedInboxBody",
|
|
||||||
att: ["/Lotus/Types/Keys/EntratiLab/EntratiQuestKeyChain"],
|
|
||||||
sub: "/Lotus/Language/EntratiLab/EntratiQuest/WiTWQuestRecievedInboxTitle",
|
|
||||||
icon: "/Lotus/Interface/Icons/Npcs/Entrati/Loid.png",
|
|
||||||
highPriority: true
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Hex (Quest) is unlocked once The Lotus Eaters + The Duviri Paradox are completed.
|
|
||||||
if (
|
|
||||||
doesQuestCompletionFinishSet(inventory, questKey, [
|
|
||||||
"/Lotus/Types/Keys/1999PrologueQuest/1999PrologueQuestKeyChain",
|
|
||||||
"/Lotus/Types/Keys/DuviriQuest/DuviriQuestKeyChain"
|
|
||||||
])
|
|
||||||
) {
|
|
||||||
await createMessage(inventory.accountOwnerId, [
|
|
||||||
{
|
|
||||||
sndr: "/Lotus/Language/NewWar/P3M1ChooseMara",
|
|
||||||
msg: "/Lotus/Language/1999Quest/1999QuestInboxBody",
|
|
||||||
att: ["/Lotus/Types/Keys/1999Quest/1999QuestKeyChain"],
|
|
||||||
sub: "/Lotus/Language/1999Quest/1999QuestInboxSubject",
|
|
||||||
icon: "/Lotus/Interface/Icons/Npcs/Operator.png",
|
|
||||||
highPriority: true
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const questCompletionItems = getQuestCompletionItems(questKey);
|
const questCompletionItems = getQuestCompletionItems(questKey);
|
||||||
logger.debug(`quest completion items`, questCompletionItems);
|
logger.debug(`quest completion items`, questCompletionItems);
|
||||||
if (questCompletionItems) {
|
if (questCompletionItems) {
|
||||||
@ -289,7 +232,7 @@ export const giveKeyChainItem = async (
|
|||||||
const inventoryChanges = await addKeyChainItems(inventory, keyChainInfo);
|
const inventoryChanges = await addKeyChainItems(inventory, keyChainInfo);
|
||||||
|
|
||||||
if (isEmptyObject(inventoryChanges)) {
|
if (isEmptyObject(inventoryChanges)) {
|
||||||
logger.warn("inventory changes was empty after getting keychain items: should not happen");
|
throw new Error("inventory changes was empty after getting keychain items: should not happen");
|
||||||
}
|
}
|
||||||
// items were added: update quest stage's i (item was given)
|
// items were added: update quest stage's i (item was given)
|
||||||
updateQuestStage(inventory, keyChainInfo, { i: true });
|
updateQuestStage(inventory, keyChainInfo, { i: true });
|
||||||
|
@ -6,7 +6,7 @@ export interface IRngResult {
|
|||||||
probability: number;
|
probability: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getRandomElement = <T>(arr: readonly T[]): T | undefined => {
|
export const getRandomElement = <T>(arr: T[]): T => {
|
||||||
return arr[Math.floor(Math.random() * arr.length)];
|
return arr[Math.floor(Math.random() * arr.length)];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -18,10 +18,7 @@ export const getRandomInt = (min: number, max: number): number => {
|
|||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getRewardAtPercentage = <T extends { probability: number }>(
|
const getRewardAtPercentage = <T extends { probability: number }>(pool: T[], percentage: number): T | undefined => {
|
||||||
pool: T[],
|
|
||||||
percentage: number
|
|
||||||
): T | undefined => {
|
|
||||||
if (pool.length == 0) return;
|
if (pool.length == 0) return;
|
||||||
|
|
||||||
const totalChance = pool.reduce((accum, item) => accum + item.probability, 0);
|
const totalChance = pool.reduce((accum, item) => accum + item.probability, 0);
|
||||||
@ -34,7 +31,7 @@ export const getRewardAtPercentage = <T extends { probability: number }>(
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pool[pool.length - 1];
|
throw new Error("What the fuck?");
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getRandomReward = <T extends { probability: number }>(pool: T[]): T | undefined => {
|
export const getRandomReward = <T extends { probability: number }>(pool: T[]): T | undefined => {
|
||||||
@ -100,32 +97,18 @@ export class CRng {
|
|||||||
}
|
}
|
||||||
|
|
||||||
randomInt(min: number, max: number): number {
|
randomInt(min: number, max: number): number {
|
||||||
const diff = max - min;
|
min = Math.ceil(min);
|
||||||
if (diff != 0) {
|
max = Math.floor(max);
|
||||||
if (diff < 0) {
|
return Math.floor(this.random() * (max - min + 1)) + min;
|
||||||
throw new Error(`max must be greater than min`);
|
|
||||||
}
|
|
||||||
if (diff > 0x3fffffff) {
|
|
||||||
throw new Error(`insufficient entropy`);
|
|
||||||
}
|
|
||||||
min += Math.floor(this.random() * (diff + 1));
|
|
||||||
}
|
|
||||||
return min;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
randomElement<T>(arr: readonly T[]): T | undefined {
|
randomElement<T>(arr: T[]): T {
|
||||||
return arr[Math.floor(this.random() * arr.length)];
|
return arr[Math.floor(this.random() * arr.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
randomReward<T extends { probability: number }>(pool: T[]): T | undefined {
|
randomReward<T extends { probability: number }>(pool: T[]): T | undefined {
|
||||||
return getRewardAtPercentage(pool, this.random());
|
return getRewardAtPercentage(pool, this.random());
|
||||||
}
|
}
|
||||||
|
|
||||||
churnSeed(its: number): void {
|
|
||||||
while (its--) {
|
|
||||||
this.state = (this.state * 1103515245 + 12345) & 0x7fffffff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seeded RNG for cases where we need identical results to the game client. Based on work by Donald Knuth.
|
// Seeded RNG for cases where we need identical results to the game client. Based on work by Donald Knuth.
|
||||||
@ -145,7 +128,7 @@ export class SRng {
|
|||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
|
|
||||||
randomElement<T>(arr: readonly T[]): T | undefined {
|
randomElement<T>(arr: T[]): T {
|
||||||
return arr[this.randomInt(0, arr.length - 1)];
|
return arr[this.randomInt(0, arr.length - 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,8 +136,4 @@ export class SRng {
|
|||||||
this.state = (0x5851f42d4c957f2dn * this.state + 0x14057b7ef767814fn) & 0xffffffffffffffffn;
|
this.state = (0x5851f42d4c957f2dn * this.state + 0x14057b7ef767814fn) & 0xffffffffffffffffn;
|
||||||
return (Number(this.state >> 38n) & 0xffffff) * 0.000000059604645;
|
return (Number(this.state >> 38n) & 0xffffff) * 0.000000059604645;
|
||||||
}
|
}
|
||||||
|
|
||||||
randomReward<T extends { probability: number }>(pool: T[]): T | undefined {
|
|
||||||
return getRewardAtPercentage(pool, this.randomFloat());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,6 @@ import { Types } from "mongoose";
|
|||||||
import { isEmptyObject } from "@/src/helpers/general";
|
import { isEmptyObject } from "@/src/helpers/general";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { equipmentKeys, TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { equipmentKeys, TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { IItemConfig } from "../types/inventoryTypes/commonInventoryTypes";
|
|
||||||
import { importCrewMemberId } from "./importService";
|
|
||||||
|
|
||||||
//TODO: setup default items on account creation or like originally in giveStartingItems.php
|
//TODO: setup default items on account creation or like originally in giveStartingItems.php
|
||||||
|
|
||||||
@ -142,28 +140,8 @@ export const handleInventoryItemConfigChange = async (
|
|||||||
case "WeaponSkins": {
|
case "WeaponSkins": {
|
||||||
const itemEntries = equipment as IItemEntry;
|
const itemEntries = equipment as IItemEntry;
|
||||||
for (const [itemId, itemConfigEntries] of Object.entries(itemEntries)) {
|
for (const [itemId, itemConfigEntries] of Object.entries(itemEntries)) {
|
||||||
if (itemId.startsWith("ca70ca70ca70ca70")) {
|
inventory.WeaponSkins.id(itemId)!.IsNew = itemConfigEntries.IsNew;
|
||||||
logger.warn(
|
|
||||||
`unlockAllSkins does not work with favoriting items because you don't actually own it`
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const inventoryItem = inventory.WeaponSkins.id(itemId);
|
|
||||||
if (!inventoryItem) {
|
|
||||||
throw new Error(`inventory item WeaponSkins not found with id ${itemId}`);
|
|
||||||
}
|
}
|
||||||
if ("Favorite" in itemConfigEntries) {
|
|
||||||
inventoryItem.Favorite = itemConfigEntries.Favorite;
|
|
||||||
}
|
|
||||||
if ("IsNew" in itemConfigEntries) {
|
|
||||||
inventoryItem.IsNew = itemConfigEntries.IsNew;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "LotusCustomization": {
|
|
||||||
logger.debug(`saved LotusCustomization`, equipmentChanges.LotusCustomization);
|
|
||||||
inventory.LotusCustomization = equipmentChanges.LotusCustomization;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@ -181,36 +159,13 @@ export const handleInventoryItemConfigChange = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const [configId, config] of Object.entries(itemConfigEntries)) {
|
for (const [configId, config] of Object.entries(itemConfigEntries)) {
|
||||||
if (/^[0-9]+$/.test(configId)) {
|
if (typeof config !== "boolean") {
|
||||||
inventoryItem.Configs[parseInt(configId)] = config as IItemConfig;
|
inventoryItem.Configs[parseInt(configId)] = config;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ("Favorite" in itemConfigEntries) {
|
|
||||||
inventoryItem.Favorite = itemConfigEntries.Favorite;
|
|
||||||
}
|
|
||||||
if ("IsNew" in itemConfigEntries) {
|
if ("IsNew" in itemConfigEntries) {
|
||||||
inventoryItem.IsNew = itemConfigEntries.IsNew;
|
inventoryItem.IsNew = itemConfigEntries.IsNew;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("ItemName" in itemConfigEntries) {
|
|
||||||
inventoryItem.ItemName = itemConfigEntries.ItemName;
|
|
||||||
}
|
|
||||||
if ("RailjackImage" in itemConfigEntries) {
|
|
||||||
inventoryItem.RailjackImage = itemConfigEntries.RailjackImage;
|
|
||||||
}
|
|
||||||
if ("Customization" in itemConfigEntries) {
|
|
||||||
inventoryItem.Customization = itemConfigEntries.Customization;
|
|
||||||
}
|
|
||||||
if ("Weapon" in itemConfigEntries) {
|
|
||||||
inventoryItem.Weapon = itemConfigEntries.Weapon;
|
|
||||||
}
|
|
||||||
if (itemConfigEntries.CrewMembers) {
|
|
||||||
inventoryItem.CrewMembers = {
|
|
||||||
SLOT_A: importCrewMemberId(itemConfigEntries.CrewMembers.SLOT_A ?? {}),
|
|
||||||
SLOT_B: importCrewMemberId(itemConfigEntries.CrewMembers.SLOT_B ?? {}),
|
|
||||||
SLOT_C: importCrewMemberId(itemConfigEntries.CrewMembers.SLOT_C ?? {})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,308 +1,143 @@
|
|||||||
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
import fs from "fs";
|
||||||
import { catBreadHash } from "@/src/helpers/stringHelpers";
|
import path from "path";
|
||||||
|
import { repoDir } from "@/src/helpers/pathHelper";
|
||||||
import { CRng, mixSeeds } from "@/src/services/rngService";
|
import { CRng, mixSeeds } from "@/src/services/rngService";
|
||||||
import { IMongoDate } from "@/src/types/commonTypes";
|
import { IMongoDate } from "@/src/types/commonTypes";
|
||||||
import { IItemManifest, IVendorInfo, IVendorManifest } from "@/src/types/vendorTypes";
|
import { IItemManifestPreprocessed, IRawVendorManifest, IVendorManifestPreprocessed } from "@/src/types/vendorTypes";
|
||||||
import { ExportVendors, IRange } from "warframe-public-export-plus";
|
import { JSONParse } from "json-with-bigint";
|
||||||
|
import { ExportVendors } from "warframe-public-export-plus";
|
||||||
|
|
||||||
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
|
const getVendorManifestJson = (name: string): IRawVendorManifest => {
|
||||||
import DeimosEntratiFragmentVendorProductsManifest from "@/static/fixed_responses/getVendorInfo/DeimosEntratiFragmentVendorProductsManifest.json";
|
return JSONParse(fs.readFileSync(path.join(repoDir, `static/fixed_responses/getVendorInfo/${name}.json`), "utf-8"));
|
||||||
import DeimosHivemindCommisionsManifestFishmonger from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestFishmonger.json";
|
|
||||||
import DeimosHivemindCommisionsManifestPetVendor from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestPetVendor.json";
|
|
||||||
import DeimosHivemindCommisionsManifestProspector from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestProspector.json";
|
|
||||||
import DeimosHivemindCommisionsManifestTokenVendor from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestTokenVendor.json";
|
|
||||||
import DeimosHivemindCommisionsManifestWeaponsmith from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestWeaponsmith.json";
|
|
||||||
import DeimosHivemindTokenVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosHivemindTokenVendorManifest.json";
|
|
||||||
import DeimosPetVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosPetVendorManifest.json";
|
|
||||||
import DeimosProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosProspectorVendorManifest.json";
|
|
||||||
import DuviriAcrithisVendorManifest from "@/static/fixed_responses/getVendorInfo/DuviriAcrithisVendorManifest.json";
|
|
||||||
import EntratiLabsEntratiLabsCommisionsManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabsCommisionsManifest.json";
|
|
||||||
import EntratiLabsEntratiLabVendorManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabVendorManifest.json";
|
|
||||||
import HubsIronwakeDondaVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsIronwakeDondaVendorManifest.json";
|
|
||||||
import HubsRailjackCrewMemberVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json";
|
|
||||||
import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSalesmanManifest.json";
|
|
||||||
import Nova1999ConquestShopManifest from "@/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json";
|
|
||||||
import OstronPetVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronPetVendorManifest.json";
|
|
||||||
import OstronProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronProspectorVendorManifest.json";
|
|
||||||
import RadioLegionIntermission12VendorManifest from "@/static/fixed_responses/getVendorInfo/RadioLegionIntermission12VendorManifest.json";
|
|
||||||
import SolarisDebtTokenVendorRepossessionsManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorRepossessionsManifest.json";
|
|
||||||
import SolarisProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisProspectorVendorManifest.json";
|
|
||||||
import Temple1999VendorManifest from "@/static/fixed_responses/getVendorInfo/Temple1999VendorManifest.json";
|
|
||||||
import TeshinHardModeVendorManifest from "@/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json";
|
|
||||||
import ZarimanCommisionsManifestArchimedean from "@/static/fixed_responses/getVendorInfo/ZarimanCommisionsManifestArchimedean.json";
|
|
||||||
|
|
||||||
const rawVendorManifests: IVendorManifest[] = [
|
|
||||||
ArchimedeanVendorManifest,
|
|
||||||
DeimosEntratiFragmentVendorProductsManifest,
|
|
||||||
DeimosHivemindCommisionsManifestFishmonger,
|
|
||||||
DeimosHivemindCommisionsManifestPetVendor,
|
|
||||||
DeimosHivemindCommisionsManifestProspector,
|
|
||||||
DeimosHivemindCommisionsManifestTokenVendor,
|
|
||||||
DeimosHivemindCommisionsManifestWeaponsmith,
|
|
||||||
DeimosHivemindTokenVendorManifest,
|
|
||||||
DeimosPetVendorManifest,
|
|
||||||
DeimosProspectorVendorManifest,
|
|
||||||
DuviriAcrithisVendorManifest,
|
|
||||||
EntratiLabsEntratiLabsCommisionsManifest,
|
|
||||||
EntratiLabsEntratiLabVendorManifest,
|
|
||||||
HubsIronwakeDondaVendorManifest, // uses preprocessing
|
|
||||||
HubsRailjackCrewMemberVendorManifest,
|
|
||||||
MaskSalesmanManifest,
|
|
||||||
Nova1999ConquestShopManifest,
|
|
||||||
OstronPetVendorManifest,
|
|
||||||
OstronProspectorVendorManifest,
|
|
||||||
RadioLegionIntermission12VendorManifest,
|
|
||||||
SolarisDebtTokenVendorRepossessionsManifest,
|
|
||||||
SolarisProspectorVendorManifest,
|
|
||||||
Temple1999VendorManifest,
|
|
||||||
TeshinHardModeVendorManifest, // uses preprocessing
|
|
||||||
ZarimanCommisionsManifestArchimedean
|
|
||||||
];
|
|
||||||
|
|
||||||
interface IGeneratableVendorInfo extends Omit<IVendorInfo, "ItemManifest" | "Expiry"> {
|
|
||||||
cycleOffset?: number;
|
|
||||||
cycleDuration: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const generatableVendors: IGeneratableVendorInfo[] = [
|
|
||||||
{
|
|
||||||
_id: { $oid: "67dadc30e4b6e0e5979c8d84" },
|
|
||||||
TypeName: "/Lotus/Types/Game/VendorManifests/TheHex/InfestedLichWeaponVendorManifest",
|
|
||||||
RandomSeedType: "VRST_WEAPON",
|
|
||||||
RequiredGoalTag: "",
|
|
||||||
WeaponUpgradeValueAttenuationExponent: 2.25,
|
|
||||||
cycleOffset: 1740960000_000,
|
|
||||||
cycleDuration: 4 * unixTimesInMs.day
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_id: { $oid: "60ad3b6ec96976e97d227e19" },
|
|
||||||
TypeName: "/Lotus/Types/Game/VendorManifests/Hubs/PerrinSequenceWeaponVendorManifest",
|
|
||||||
RandomSeedType: "VRST_WEAPON",
|
|
||||||
WeaponUpgradeValueAttenuationExponent: 2.25,
|
|
||||||
cycleOffset: 1744934400_000,
|
|
||||||
cycleDuration: 4 * unixTimesInMs.day
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_id: { $oid: "61ba123467e5d37975aeeb03" },
|
|
||||||
TypeName: "/Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest",
|
|
||||||
RandomSeedType: "VRST_FLAVOUR_TEXT",
|
|
||||||
cycleDuration: unixTimesInMs.week // TODO: Auto-detect this based on the items, so we don't need to specify it explicitly.
|
|
||||||
}
|
|
||||||
// {
|
|
||||||
// _id: { $oid: "5dbb4c41e966f7886c3ce939" },
|
|
||||||
// TypeName: "/Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest"
|
|
||||||
// }
|
|
||||||
];
|
|
||||||
|
|
||||||
const getVendorOid = (typeName: string): string => {
|
|
||||||
return "5be4a159b144f3cd" + catBreadHash(typeName).toString(16).padStart(8, "0");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getVendorManifestByTypeName = (typeName: string): IVendorManifest | undefined => {
|
const rawVendorManifests: IRawVendorManifest[] = [
|
||||||
|
getVendorManifestJson("ArchimedeanVendorManifest"),
|
||||||
|
getVendorManifestJson("DeimosEntratiFragmentVendorProductsManifest"),
|
||||||
|
getVendorManifestJson("DeimosFishmongerVendorManifest"),
|
||||||
|
getVendorManifestJson("DeimosHivemindCommisionsManifestFishmonger"),
|
||||||
|
getVendorManifestJson("DeimosHivemindCommisionsManifestPetVendor"),
|
||||||
|
getVendorManifestJson("DeimosHivemindCommisionsManifestProspector"),
|
||||||
|
getVendorManifestJson("DeimosHivemindCommisionsManifestTokenVendor"),
|
||||||
|
getVendorManifestJson("DeimosHivemindCommisionsManifestWeaponsmith"),
|
||||||
|
getVendorManifestJson("DeimosHivemindTokenVendorManifest"),
|
||||||
|
getVendorManifestJson("DeimosPetVendorManifest"),
|
||||||
|
getVendorManifestJson("DeimosProspectorVendorManifest"),
|
||||||
|
getVendorManifestJson("DuviriAcrithisVendorManifest"),
|
||||||
|
getVendorManifestJson("EntratiLabsEntratiLabsCommisionsManifest"),
|
||||||
|
getVendorManifestJson("EntratiLabsEntratiLabVendorManifest"),
|
||||||
|
getVendorManifestJson("GuildAdvertisementVendorManifest"), // uses preprocessing
|
||||||
|
getVendorManifestJson("HubsIronwakeDondaVendorManifest"), // uses preprocessing
|
||||||
|
getVendorManifestJson("HubsPerrinSequenceWeaponVendorManifest"),
|
||||||
|
getVendorManifestJson("HubsRailjackCrewMemberVendorManifest"),
|
||||||
|
getVendorManifestJson("MaskSalesmanManifest"),
|
||||||
|
getVendorManifestJson("Nova1999ConquestShopManifest"),
|
||||||
|
getVendorManifestJson("OstronFishmongerVendorManifest"),
|
||||||
|
getVendorManifestJson("OstronPetVendorManifest"),
|
||||||
|
getVendorManifestJson("OstronProspectorVendorManifest"),
|
||||||
|
getVendorManifestJson("RadioLegionIntermission12VendorManifest"),
|
||||||
|
getVendorManifestJson("SolarisDebtTokenVendorManifest"),
|
||||||
|
getVendorManifestJson("SolarisDebtTokenVendorRepossessionsManifest"),
|
||||||
|
getVendorManifestJson("SolarisFishmongerVendorManifest"),
|
||||||
|
getVendorManifestJson("SolarisProspectorVendorManifest"),
|
||||||
|
getVendorManifestJson("TeshinHardModeVendorManifest"), // uses preprocessing
|
||||||
|
getVendorManifestJson("ZarimanCommisionsManifestArchimedean")
|
||||||
|
];
|
||||||
|
|
||||||
|
export const getVendorManifestByTypeName = (typeName: string): IVendorManifestPreprocessed | undefined => {
|
||||||
for (const vendorManifest of rawVendorManifests) {
|
for (const vendorManifest of rawVendorManifests) {
|
||||||
if (vendorManifest.VendorInfo.TypeName == typeName) {
|
if (vendorManifest.VendorInfo.TypeName == typeName) {
|
||||||
return preprocessVendorManifest(vendorManifest);
|
return preprocessVendorManifest(vendorManifest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const vendorInfo of generatableVendors) {
|
if (typeName == "/Lotus/Types/Game/VendorManifests/TheHex/InfestedLichWeaponVendorManifest") {
|
||||||
if (vendorInfo.TypeName == typeName) {
|
return generateCodaWeaponVendorManifest();
|
||||||
return generateVendorManifest(vendorInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (typeName in ExportVendors) {
|
|
||||||
return generateVendorManifest({
|
|
||||||
_id: { $oid: getVendorOid(typeName) },
|
|
||||||
TypeName: typeName,
|
|
||||||
RandomSeedType: ExportVendors[typeName].randomSeedType,
|
|
||||||
cycleDuration: unixTimesInMs.hour
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getVendorManifestByOid = (oid: string): IVendorManifest | undefined => {
|
export const getVendorManifestByOid = (oid: string): IVendorManifestPreprocessed | undefined => {
|
||||||
for (const vendorManifest of rawVendorManifests) {
|
for (const vendorManifest of rawVendorManifests) {
|
||||||
if (vendorManifest.VendorInfo._id.$oid == oid) {
|
if (vendorManifest.VendorInfo._id.$oid == oid) {
|
||||||
return preprocessVendorManifest(vendorManifest);
|
return preprocessVendorManifest(vendorManifest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const vendorInfo of generatableVendors) {
|
if (oid == "67dadc30e4b6e0e5979c8d84") {
|
||||||
if (vendorInfo._id.$oid == oid) {
|
return generateCodaWeaponVendorManifest();
|
||||||
return generateVendorManifest(vendorInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const [typeName, manifest] of Object.entries(ExportVendors)) {
|
|
||||||
const typeNameOid = getVendorOid(typeName);
|
|
||||||
if (typeNameOid == oid) {
|
|
||||||
return generateVendorManifest({
|
|
||||||
_id: { $oid: typeNameOid },
|
|
||||||
TypeName: typeName,
|
|
||||||
RandomSeedType: manifest.randomSeedType,
|
|
||||||
cycleDuration: unixTimesInMs.hour
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const preprocessVendorManifest = (originalManifest: IVendorManifest): IVendorManifest => {
|
const preprocessVendorManifest = (originalManifest: IRawVendorManifest): IVendorManifestPreprocessed => {
|
||||||
if (Date.now() >= parseInt(originalManifest.VendorInfo.Expiry.$date.$numberLong)) {
|
if (Date.now() >= parseInt(originalManifest.VendorInfo.Expiry.$date.$numberLong)) {
|
||||||
const manifest = structuredClone(originalManifest);
|
const manifest = structuredClone(originalManifest);
|
||||||
const info = manifest.VendorInfo;
|
const info = manifest.VendorInfo;
|
||||||
refreshExpiry(info.Expiry);
|
refreshExpiry(info.Expiry);
|
||||||
for (const offer of info.ItemManifest) {
|
for (const offer of info.ItemManifest) {
|
||||||
refreshExpiry(offer.Expiry);
|
const iteration = refreshExpiry(offer.Expiry);
|
||||||
|
if (offer.ItemPrices) {
|
||||||
|
for (const price of offer.ItemPrices) {
|
||||||
|
if (typeof price.ItemType != "string") {
|
||||||
|
const itemSeed = parseInt(offer.Id.$oid.substring(16), 16);
|
||||||
|
const rng = new CRng(mixSeeds(itemSeed, iteration));
|
||||||
|
price.ItemType = rng.randomElement(price.ItemType);
|
||||||
}
|
}
|
||||||
return manifest;
|
|
||||||
}
|
}
|
||||||
return originalManifest;
|
}
|
||||||
|
}
|
||||||
|
return manifest as IVendorManifestPreprocessed;
|
||||||
|
}
|
||||||
|
return originalManifest as IVendorManifestPreprocessed;
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshExpiry = (expiry: IMongoDate): void => {
|
const refreshExpiry = (expiry: IMongoDate): number => {
|
||||||
const period = parseInt(expiry.$date.$numberLong);
|
const period = parseInt(expiry.$date.$numberLong);
|
||||||
if (Date.now() >= period) {
|
if (Date.now() >= period) {
|
||||||
const epoch = 1734307200_000; // Monday (for weekly schedules)
|
const epoch = 1734307200 * 1000; // Monday (for weekly schedules)
|
||||||
const iteration = Math.trunc((Date.now() - epoch) / period);
|
const iteration = Math.trunc((Date.now() - epoch) / period);
|
||||||
const start = epoch + iteration * period;
|
const start = epoch + iteration * period;
|
||||||
const end = start + period;
|
const end = start + period;
|
||||||
expiry.$date.$numberLong = end.toString();
|
expiry.$date.$numberLong = end.toString();
|
||||||
|
return iteration;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const toRange = (value: IRange | number): IRange => {
|
const generateCodaWeaponVendorManifest = (): IVendorManifestPreprocessed => {
|
||||||
if (typeof value == "number") {
|
const EPOCH = 1740960000 * 1000;
|
||||||
return { minValue: value, maxValue: value };
|
const DUR = 4 * 86400 * 1000;
|
||||||
}
|
const cycle = Math.trunc((Date.now() - EPOCH) / DUR);
|
||||||
return value;
|
const cycleStart = EPOCH + cycle * DUR;
|
||||||
};
|
const cycleEnd = cycleStart + DUR;
|
||||||
|
const binThisCycle = cycle % 2; // isOneBinPerCycle
|
||||||
const vendorInfoCache: Record<string, IVendorInfo> = {};
|
const items: IItemManifestPreprocessed[] = [];
|
||||||
|
const manifest = ExportVendors["/Lotus/Types/Game/VendorManifests/TheHex/InfestedLichWeaponVendorManifest"];
|
||||||
const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorManifest => {
|
const rng = new CRng(cycle);
|
||||||
if (!(vendorInfo.TypeName in vendorInfoCache)) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
const { cycleOffset, cycleDuration, ...clientVendorInfo } = vendorInfo;
|
|
||||||
vendorInfoCache[vendorInfo.TypeName] = {
|
|
||||||
...clientVendorInfo,
|
|
||||||
ItemManifest: [],
|
|
||||||
Expiry: { $date: { $numberLong: "0" } }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const processed = vendorInfoCache[vendorInfo.TypeName];
|
|
||||||
if (Date.now() >= parseInt(processed.Expiry.$date.$numberLong)) {
|
|
||||||
// Remove expired offers
|
|
||||||
for (let i = 0; i != processed.ItemManifest.length; ) {
|
|
||||||
if (Date.now() >= parseInt(processed.ItemManifest[i].Expiry.$date.$numberLong)) {
|
|
||||||
processed.ItemManifest.splice(i, 1);
|
|
||||||
} else {
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add new offers
|
|
||||||
const vendorSeed = parseInt(vendorInfo._id.$oid.substring(16), 16);
|
|
||||||
const cycleOffset = vendorInfo.cycleOffset ?? 1734307200_000;
|
|
||||||
const cycleDuration = vendorInfo.cycleDuration;
|
|
||||||
const cycleIndex = Math.trunc((Date.now() - cycleOffset) / cycleDuration);
|
|
||||||
const rng = new CRng(mixSeeds(vendorSeed, cycleIndex));
|
|
||||||
const manifest = ExportVendors[vendorInfo.TypeName];
|
|
||||||
const offersToAdd = [];
|
|
||||||
if (manifest.numItems && !manifest.isOneBinPerCycle) {
|
|
||||||
const numItemsTarget = rng.randomInt(manifest.numItems.minValue, manifest.numItems.maxValue);
|
|
||||||
while (processed.ItemManifest.length + offersToAdd.length < numItemsTarget) {
|
|
||||||
// TODO: Consider per-bin item limits
|
|
||||||
// TODO: Consider item probability weightings
|
|
||||||
offersToAdd.push(rng.randomElement(manifest.items)!);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let binThisCycle;
|
|
||||||
if (manifest.isOneBinPerCycle) {
|
|
||||||
binThisCycle = cycleIndex % 2; // Note: May want to auto-compute the bin size, but this is only used for coda weapons right now.
|
|
||||||
}
|
|
||||||
for (const rawItem of manifest.items) {
|
for (const rawItem of manifest.items) {
|
||||||
if (!manifest.isOneBinPerCycle || rawItem.bin == binThisCycle) {
|
if (rawItem.bin != binThisCycle) {
|
||||||
offersToAdd.push(rawItem);
|
continue;
|
||||||
}
|
}
|
||||||
}
|
items.push({
|
||||||
|
|
||||||
// For most vendors, the offers seem to roughly be in reverse order from the manifest. Coda weapons are an odd exception.
|
|
||||||
if (!manifest.isOneBinPerCycle) {
|
|
||||||
offersToAdd.reverse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const cycleStart = cycleOffset + cycleIndex * cycleDuration;
|
|
||||||
for (const rawItem of offersToAdd) {
|
|
||||||
const durationHoursRange = toRange(rawItem.durationHours);
|
|
||||||
const expiry =
|
|
||||||
cycleStart +
|
|
||||||
rng.randomInt(durationHoursRange.minValue, durationHoursRange.maxValue) * unixTimesInMs.hour;
|
|
||||||
const item: IItemManifest = {
|
|
||||||
StoreItem: rawItem.storeItem,
|
StoreItem: rawItem.storeItem,
|
||||||
ItemPrices: rawItem.itemPrices?.map(itemPrice => ({ ...itemPrice, ProductCategory: "MiscItems" })),
|
ItemPrices: rawItem.itemPrices!.map(item => ({ ...item, ProductCategory: "MiscItems" })),
|
||||||
Bin: "BIN_" + rawItem.bin,
|
Bin: "BIN_" + rawItem.bin,
|
||||||
QuantityMultiplier: 1,
|
QuantityMultiplier: 1,
|
||||||
Expiry: { $date: { $numberLong: expiry.toString() } },
|
Expiry: { $date: { $numberLong: cycleEnd.toString() } },
|
||||||
AllowMultipurchase: false,
|
AllowMultipurchase: false,
|
||||||
Id: {
|
LocTagRandSeed: (BigInt(rng.randomInt(0, 0xffffffff)) << 32n) | BigInt(rng.randomInt(0, 0xffffffff)),
|
||||||
$oid:
|
Id: { $oid: "67e9da12793a120d" + rng.randomInt(0, 0xffffffff).toString(16).padStart(8, "0") }
|
||||||
((cycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") +
|
|
||||||
vendorInfo._id.$oid.substring(8, 16) +
|
|
||||||
rng.randomInt(0, 0xffff).toString(16).padStart(4, "0") +
|
|
||||||
rng.randomInt(0, 0xffff).toString(16).padStart(4, "0")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (rawItem.numRandomItemPrices) {
|
|
||||||
item.ItemPrices = [];
|
|
||||||
for (let i = 0; i != rawItem.numRandomItemPrices; ++i) {
|
|
||||||
let itemPrice: { type: string; count: IRange };
|
|
||||||
do {
|
|
||||||
itemPrice = rng.randomElement(manifest.randomItemPricesPerBin![rawItem.bin])!;
|
|
||||||
} while (item.ItemPrices.find(x => x.ItemType == itemPrice.type));
|
|
||||||
item.ItemPrices.push({
|
|
||||||
ItemType: itemPrice.type,
|
|
||||||
ItemCount: rng.randomInt(itemPrice.count.minValue, itemPrice.count.maxValue),
|
|
||||||
ProductCategory: "MiscItems"
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (rawItem.credits) {
|
|
||||||
const value =
|
|
||||||
typeof rawItem.credits == "number"
|
|
||||||
? rawItem.credits
|
|
||||||
: rng.randomInt(
|
|
||||||
rawItem.credits.minValue / rawItem.credits.step,
|
|
||||||
rawItem.credits.maxValue / rawItem.credits.step
|
|
||||||
) * rawItem.credits.step;
|
|
||||||
item.RegularPrice = [value, value];
|
|
||||||
}
|
|
||||||
if (rawItem.platinum) {
|
|
||||||
const value =
|
|
||||||
typeof rawItem.platinum == "number"
|
|
||||||
? rawItem.platinum
|
|
||||||
: rng.randomInt(rawItem.platinum.minValue, rawItem.platinum.maxValue);
|
|
||||||
item.PremiumPrice = [value, value];
|
|
||||||
}
|
|
||||||
if (vendorInfo.RandomSeedType) {
|
|
||||||
item.LocTagRandSeed = (rng.randomInt(0, 0xffff) << 16) | rng.randomInt(0, 0xffff);
|
|
||||||
if (vendorInfo.RandomSeedType == "VRST_WEAPON") {
|
|
||||||
const highDword = (rng.randomInt(0, 0xffff) << 16) | rng.randomInt(0, 0xffff);
|
|
||||||
item.LocTagRandSeed = (BigInt(highDword) << 32n) | (BigInt(item.LocTagRandSeed) & 0xffffffffn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
processed.ItemManifest.push(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update vendor expiry
|
|
||||||
let soonestOfferExpiry: number = Number.MAX_SAFE_INTEGER;
|
|
||||||
for (const offer of processed.ItemManifest) {
|
|
||||||
const offerExpiry = parseInt(offer.Expiry.$date.$numberLong);
|
|
||||||
if (soonestOfferExpiry > offerExpiry) {
|
|
||||||
soonestOfferExpiry = offerExpiry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
processed.Expiry.$date.$numberLong = soonestOfferExpiry.toString();
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
VendorInfo: processed
|
VendorInfo: {
|
||||||
|
_id: { $oid: "67dadc30e4b6e0e5979c8d84" },
|
||||||
|
TypeName: "/Lotus/Types/Game/VendorManifests/TheHex/InfestedLichWeaponVendorManifest",
|
||||||
|
ItemManifest: items,
|
||||||
|
PropertyTextHash: "77093DD05A8561A022DEC9A4B9BB4A56",
|
||||||
|
RandomSeedType: "VRST_WEAPON",
|
||||||
|
RequiredGoalTag: "",
|
||||||
|
WeaponUpgradeValueAttenuationExponent: 2.25,
|
||||||
|
Expiry: { $date: { $numberLong: cycleEnd.toString() } }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Stats, TStatsDatabaseDocument } from "@/src/models/statsModel";
|
import { Stats, TStatsDatabaseDocument } from "@/src/models/statsModel";
|
||||||
import {
|
import {
|
||||||
|
IEnemy,
|
||||||
IStatsAdd,
|
IStatsAdd,
|
||||||
IStatsMax,
|
IStatsMax,
|
||||||
IStatsSet,
|
IStatsSet,
|
||||||
@ -136,21 +137,16 @@ export const updateStats = async (accountOwnerId: string, payload: IStatsUpdate)
|
|||||||
case "HEADSHOT":
|
case "HEADSHOT":
|
||||||
case "KILL_ASSIST": {
|
case "KILL_ASSIST": {
|
||||||
playerStats.Enemies ??= [];
|
playerStats.Enemies ??= [];
|
||||||
const enemyStatKey = (
|
const enemyStatKey = {
|
||||||
{
|
|
||||||
KILL_ENEMY: "kills",
|
KILL_ENEMY: "kills",
|
||||||
EXECUTE_ENEMY: "executions",
|
EXECUTE_ENEMY: "executions",
|
||||||
HEADSHOT: "headshots",
|
HEADSHOT: "headshots",
|
||||||
KILL_ASSIST: "assists"
|
KILL_ASSIST: "assists"
|
||||||
} as const
|
}[category] as "kills" | "executions" | "headshots" | "assists";
|
||||||
)[category];
|
|
||||||
|
|
||||||
for (const [type, count] of Object.entries(data as IUploadEntry)) {
|
for (const [type, count] of Object.entries(data as IUploadEntry)) {
|
||||||
let enemy = playerStats.Enemies.find(element => element.type === type);
|
const enemy = playerStats.Enemies.find(element => element.type === type);
|
||||||
if (!enemy) {
|
if (enemy) {
|
||||||
enemy = { type: type };
|
|
||||||
playerStats.Enemies.push(enemy);
|
|
||||||
}
|
|
||||||
if (category === "KILL_ENEMY") {
|
if (category === "KILL_ENEMY") {
|
||||||
enemy.kills ??= 0;
|
enemy.kills ??= 0;
|
||||||
const captureCount = (actionData as IStatsAdd)["CAPTURE_ENEMY"]?.[type];
|
const captureCount = (actionData as IStatsAdd)["CAPTURE_ENEMY"]?.[type];
|
||||||
@ -165,6 +161,11 @@ export const updateStats = async (accountOwnerId: string, payload: IStatsUpdate)
|
|||||||
enemy[enemyStatKey] ??= 0;
|
enemy[enemyStatKey] ??= 0;
|
||||||
enemy[enemyStatKey] += count;
|
enemy[enemyStatKey] += count;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
const newEnemy: IEnemy = { type: type };
|
||||||
|
newEnemy[enemyStatKey] = count;
|
||||||
|
playerStats.Enemies.push(newEnemy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -377,8 +378,7 @@ export const updateStats = async (accountOwnerId: string, payload: IStatsUpdate)
|
|||||||
category,
|
category,
|
||||||
accountOwnerId,
|
accountOwnerId,
|
||||||
payload.displayName,
|
payload.displayName,
|
||||||
data as number,
|
data as number
|
||||||
payload.guildId
|
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,6 @@ export interface IGuildClient {
|
|||||||
Members: IGuildMemberClient[];
|
Members: IGuildMemberClient[];
|
||||||
Ranks: IGuildRank[];
|
Ranks: IGuildRank[];
|
||||||
Tier: number;
|
Tier: number;
|
||||||
Emblem?: boolean;
|
|
||||||
Vault: IGuildVault;
|
Vault: IGuildVault;
|
||||||
ActiveDojoColorResearch: string;
|
ActiveDojoColorResearch: string;
|
||||||
Class: number;
|
Class: number;
|
||||||
@ -45,7 +44,6 @@ export interface IGuildDatabase {
|
|||||||
VaultMiscItems?: IMiscItem[];
|
VaultMiscItems?: IMiscItem[];
|
||||||
VaultShipDecorations?: ITypeCount[];
|
VaultShipDecorations?: ITypeCount[];
|
||||||
VaultFusionTreasures?: IFusionTreasure[];
|
VaultFusionTreasures?: IFusionTreasure[];
|
||||||
VaultDecoRecipes?: ITypeCount[];
|
|
||||||
|
|
||||||
TechProjects?: ITechProjectDatabase[];
|
TechProjects?: ITechProjectDatabase[];
|
||||||
ActiveDojoColorResearch: string;
|
ActiveDojoColorResearch: string;
|
||||||
@ -104,12 +102,12 @@ export interface IGuildMemberDatabase {
|
|||||||
ShipDecorationsContributed?: ITypeCount[];
|
ShipDecorationsContributed?: ITypeCount[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IFriendInfo {
|
interface IFriendInfo {
|
||||||
_id: IOid;
|
_id: IOid;
|
||||||
DisplayName?: string;
|
DisplayName?: string;
|
||||||
PlatformNames?: string[];
|
PlatformNames?: string[];
|
||||||
PlatformAccountId?: string;
|
PlatformAccountId?: string;
|
||||||
Status?: number;
|
Status: number;
|
||||||
ActiveAvatarImageType?: string;
|
ActiveAvatarImageType?: string;
|
||||||
LastLogin?: IMongoDate;
|
LastLogin?: IMongoDate;
|
||||||
PlayerLevel?: number;
|
PlayerLevel?: number;
|
||||||
@ -192,7 +190,6 @@ export interface IDojoComponentDatabase
|
|||||||
"id" | "SortId" | "pi" | "CompletionTime" | "DestructionTime" | "Decos" | "PaintBot"
|
"id" | "SortId" | "pi" | "CompletionTime" | "DestructionTime" | "Decos" | "PaintBot"
|
||||||
> {
|
> {
|
||||||
_id: Types.ObjectId;
|
_id: Types.ObjectId;
|
||||||
SortId?: Types.ObjectId;
|
|
||||||
pi?: Types.ObjectId;
|
pi?: Types.ObjectId;
|
||||||
CompletionTime?: Date;
|
CompletionTime?: Date;
|
||||||
CompletionLogPending?: boolean;
|
CompletionLogPending?: boolean;
|
||||||
@ -207,7 +204,6 @@ export interface IDojoDecoClient {
|
|||||||
Type: string;
|
Type: string;
|
||||||
Pos: number[];
|
Pos: number[];
|
||||||
Rot: number[];
|
Rot: number[];
|
||||||
Scale?: number;
|
|
||||||
Name?: string; // for teleporters
|
Name?: string; // for teleporters
|
||||||
Sockets?: number;
|
Sockets?: number;
|
||||||
RegularCredits?: number;
|
RegularCredits?: number;
|
||||||
|
@ -142,7 +142,6 @@ export interface IEquipmentDatabase {
|
|||||||
RailjackImage?: IFlavourItem;
|
RailjackImage?: IFlavourItem;
|
||||||
CrewMembers?: ICrewShipMembersDatabase;
|
CrewMembers?: ICrewShipMembersDatabase;
|
||||||
Details?: IKubrowPetDetailsDatabase;
|
Details?: IKubrowPetDetailsDatabase;
|
||||||
Favorite?: boolean;
|
|
||||||
IsNew?: boolean;
|
IsNew?: boolean;
|
||||||
_id: Types.ObjectId;
|
_id: Types.ObjectId;
|
||||||
}
|
}
|
||||||
|
@ -43,16 +43,9 @@ export interface IInventoryDatabase
|
|||||||
| "RecentVendorPurchases"
|
| "RecentVendorPurchases"
|
||||||
| "NextRefill"
|
| "NextRefill"
|
||||||
| "Nemesis"
|
| "Nemesis"
|
||||||
| "NemesisHistory"
|
|
||||||
| "EntratiVaultCountResetDate"
|
| "EntratiVaultCountResetDate"
|
||||||
| "BrandedSuits"
|
| "BrandedSuits"
|
||||||
| "LockedWeaponGroup"
|
| "LockedWeaponGroup"
|
||||||
| "PersonalTechProjects"
|
|
||||||
| "LastSortieReward"
|
|
||||||
| "LastLiteSortieReward"
|
|
||||||
| "CrewMembers"
|
|
||||||
| "QualifyingInvasions"
|
|
||||||
| "LastInventorySync"
|
|
||||||
| TEquipmentKey
|
| TEquipmentKey
|
||||||
>,
|
>,
|
||||||
InventoryDatabaseEquipment {
|
InventoryDatabaseEquipment {
|
||||||
@ -81,16 +74,9 @@ export interface IInventoryDatabase
|
|||||||
RecentVendorPurchases?: IRecentVendorPurchaseDatabase[];
|
RecentVendorPurchases?: IRecentVendorPurchaseDatabase[];
|
||||||
NextRefill?: Date;
|
NextRefill?: Date;
|
||||||
Nemesis?: INemesisDatabase;
|
Nemesis?: INemesisDatabase;
|
||||||
NemesisHistory?: INemesisBaseDatabase[];
|
|
||||||
EntratiVaultCountResetDate?: Date;
|
EntratiVaultCountResetDate?: Date;
|
||||||
BrandedSuits?: Types.ObjectId[];
|
BrandedSuits?: Types.ObjectId[];
|
||||||
LockedWeaponGroup?: ILockedWeaponGroupDatabase;
|
LockedWeaponGroup?: ILockedWeaponGroupDatabase;
|
||||||
PersonalTechProjects: IPersonalTechProjectDatabase[];
|
|
||||||
LastSortieReward?: ILastSortieRewardDatabase[];
|
|
||||||
LastLiteSortieReward?: ILastSortieRewardDatabase[];
|
|
||||||
CrewMembers: ICrewMemberDatabase[];
|
|
||||||
QualifyingInvasions: IInvasionProgressDatabase[];
|
|
||||||
LastInventorySync?: Types.ObjectId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IQuestKeyDatabase {
|
export interface IQuestKeyDatabase {
|
||||||
@ -138,7 +124,7 @@ export const equipmentKeys = [
|
|||||||
export type TEquipmentKey = (typeof equipmentKeys)[number];
|
export type TEquipmentKey = (typeof equipmentKeys)[number];
|
||||||
|
|
||||||
export interface IDuviriInfo {
|
export interface IDuviriInfo {
|
||||||
Seed: bigint;
|
Seed: number;
|
||||||
NumCompletions: number;
|
NumCompletions: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,11 +157,6 @@ export type TSolarMapRegion =
|
|||||||
|
|
||||||
//TODO: perhaps split response and database into their own files
|
//TODO: perhaps split response and database into their own files
|
||||||
|
|
||||||
export enum LoadoutIndex {
|
|
||||||
NORMAL = 0,
|
|
||||||
DATAKNIFE = 7
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IDailyAffiliations {
|
export interface IDailyAffiliations {
|
||||||
DailyAffiliation: number;
|
DailyAffiliation: number;
|
||||||
DailyAffiliationPvp: number;
|
DailyAffiliationPvp: number;
|
||||||
@ -202,11 +183,11 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
OperatorLoadOuts: IOperatorConfigClient[];
|
OperatorLoadOuts: IOperatorConfigClient[];
|
||||||
KahlLoadOuts: IOperatorConfigClient[];
|
KahlLoadOuts: IOperatorConfigClient[];
|
||||||
|
|
||||||
DuviriInfo?: IDuviriInfo;
|
DuviriInfo: IDuviriInfo;
|
||||||
Mailbox?: IMailboxClient;
|
Mailbox?: IMailboxClient;
|
||||||
SubscribedToEmails: number;
|
SubscribedToEmails: number;
|
||||||
Created: IMongoDate;
|
Created: IMongoDate;
|
||||||
RewardSeed: bigint;
|
RewardSeed: number;
|
||||||
RegularCredits: number;
|
RegularCredits: number;
|
||||||
PremiumCredits: number;
|
PremiumCredits: number;
|
||||||
PremiumCreditsFree: number;
|
PremiumCreditsFree: number;
|
||||||
@ -239,7 +220,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
ActiveQuest: string;
|
ActiveQuest: string;
|
||||||
FlavourItems: IFlavourItem[];
|
FlavourItems: IFlavourItem[];
|
||||||
LoadOutPresets: ILoadOutPresets;
|
LoadOutPresets: ILoadOutPresets;
|
||||||
CurrentLoadOutIds: IOid[]; // we store it in the database using this representation as well :/
|
CurrentLoadOutIds: IOid[]; //TODO: we store it in the database using this representation as well :/
|
||||||
Missions: IMission[];
|
Missions: IMission[];
|
||||||
RandomUpgradesIdentified?: number;
|
RandomUpgradesIdentified?: number;
|
||||||
LastRegionPlayed: TSolarMapRegion;
|
LastRegionPlayed: TSolarMapRegion;
|
||||||
@ -254,13 +235,14 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
Guide?: number;
|
Guide?: number;
|
||||||
Moderator?: boolean;
|
Moderator?: boolean;
|
||||||
Partner?: boolean;
|
Partner?: boolean;
|
||||||
Accolades?: IAccolades;
|
Accolades?: {
|
||||||
Counselor?: boolean;
|
Heirloom?: boolean;
|
||||||
|
};
|
||||||
Upgrades: IUpgradeClient[];
|
Upgrades: IUpgradeClient[];
|
||||||
EquippedGear: string[];
|
EquippedGear: string[];
|
||||||
DeathMarks: string[];
|
DeathMarks: string[];
|
||||||
FusionTreasures: IFusionTreasure[];
|
FusionTreasures: IFusionTreasure[];
|
||||||
//WebFlags: IWebFlags;
|
WebFlags: IWebFlags;
|
||||||
CompletedAlerts: string[];
|
CompletedAlerts: string[];
|
||||||
Consumables: ITypeCount[];
|
Consumables: ITypeCount[];
|
||||||
LevelKeys: ITypeCount[];
|
LevelKeys: ITypeCount[];
|
||||||
@ -270,13 +252,13 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
KubrowPetEggs?: IKubrowPetEggClient[];
|
KubrowPetEggs?: IKubrowPetEggClient[];
|
||||||
LoreFragmentScans: ILoreFragmentScan[];
|
LoreFragmentScans: ILoreFragmentScan[];
|
||||||
EquippedEmotes: string[];
|
EquippedEmotes: string[];
|
||||||
//PendingTrades: IPendingTrade[];
|
PendingTrades: IPendingTrade[];
|
||||||
Boosters: IBooster[];
|
Boosters: IBooster[];
|
||||||
ActiveDojoColorResearch: string;
|
ActiveDojoColorResearch: string;
|
||||||
//SentientSpawnChanceBoosters: ISentientSpawnChanceBoosters;
|
SentientSpawnChanceBoosters: ISentientSpawnChanceBoosters;
|
||||||
SupportedSyndicate?: string;
|
SupportedSyndicate?: string;
|
||||||
Affiliations: IAffiliation[];
|
Affiliations: IAffiliation[];
|
||||||
QualifyingInvasions: IInvasionProgressClient[];
|
QualifyingInvasions: any[];
|
||||||
FactionScores: number[];
|
FactionScores: number[];
|
||||||
ArchwingEnabled?: boolean;
|
ArchwingEnabled?: boolean;
|
||||||
PendingSpectreLoadouts?: ISpectreLoadout[];
|
PendingSpectreLoadouts?: ISpectreLoadout[];
|
||||||
@ -287,65 +269,63 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
Wishlist: string[];
|
Wishlist: string[];
|
||||||
Alignment?: IAlignment;
|
Alignment?: IAlignment;
|
||||||
CompletedSorties: string[];
|
CompletedSorties: string[];
|
||||||
LastSortieReward?: ILastSortieRewardClient[];
|
LastSortieReward: ILastSortieReward[];
|
||||||
LastLiteSortieReward?: ILastSortieRewardClient[];
|
|
||||||
SortieRewardAttenuation?: ISortieRewardAttenuation[];
|
|
||||||
Drones: IDroneClient[];
|
Drones: IDroneClient[];
|
||||||
StepSequencers: IStepSequencer[];
|
StepSequencers: IStepSequencer[];
|
||||||
ActiveAvatarImageType: string;
|
ActiveAvatarImageType: string;
|
||||||
ShipDecorations: ITypeCount[];
|
ShipDecorations: ITypeCount[];
|
||||||
DiscoveredMarkers: IDiscoveredMarker[];
|
DiscoveredMarkers: IDiscoveredMarker[];
|
||||||
//CompletedJobs: ICompletedJob[];
|
CompletedJobs: ICompletedJob[];
|
||||||
FocusAbility?: string;
|
FocusAbility?: string;
|
||||||
FocusUpgrades: IFocusUpgrade[];
|
FocusUpgrades: IFocusUpgrade[];
|
||||||
HasContributedToDojo?: boolean;
|
HasContributedToDojo?: boolean;
|
||||||
HWIDProtectEnabled?: boolean;
|
HWIDProtectEnabled?: boolean;
|
||||||
//KubrowPetPrints: IKubrowPetPrint[];
|
KubrowPetPrints: IKubrowPetPrint[];
|
||||||
AlignmentReplay?: IAlignment;
|
AlignmentReplay?: IAlignment;
|
||||||
//PersonalGoalProgress: IPersonalGoalProgress[];
|
PersonalGoalProgress: IPersonalGoalProgress[];
|
||||||
ThemeStyle: string;
|
ThemeStyle: string;
|
||||||
ThemeBackground: string;
|
ThemeBackground: string;
|
||||||
ThemeSounds: string;
|
ThemeSounds: string;
|
||||||
BountyScore: number;
|
BountyScore: number;
|
||||||
//ChallengeInstanceStates: IChallengeInstanceState[];
|
ChallengeInstanceStates: IChallengeInstanceState[];
|
||||||
LoginMilestoneRewards: string[];
|
LoginMilestoneRewards: string[];
|
||||||
RecentVendorPurchases?: IRecentVendorPurchaseClient[];
|
RecentVendorPurchases?: IRecentVendorPurchaseClient[];
|
||||||
NodeIntrosCompleted: string[];
|
NodeIntrosCompleted: string[];
|
||||||
GuildId?: IOid;
|
GuildId?: IOid;
|
||||||
CompletedJobChains?: ICompletedJobChain[];
|
CompletedJobChains: ICompletedJobChain[];
|
||||||
SeasonChallengeHistory: ISeasonChallenge[];
|
SeasonChallengeHistory: ISeasonChallenge[];
|
||||||
EquippedInstrument?: string;
|
EquippedInstrument?: string;
|
||||||
//InvasionChainProgress: IInvasionChainProgress[];
|
InvasionChainProgress: IInvasionChainProgress[];
|
||||||
Nemesis?: INemesisClient;
|
Nemesis?: INemesisClient;
|
||||||
NemesisHistory?: INemesisBaseClient[];
|
NemesisHistory: INemesisBaseClient[];
|
||||||
//LastNemesisAllySpawnTime?: IMongoDate;
|
LastNemesisAllySpawnTime?: IMongoDate;
|
||||||
Settings?: ISettings;
|
Settings?: ISettings;
|
||||||
PersonalTechProjects: IPersonalTechProjectClient[];
|
PersonalTechProjects: IPersonalTechProject[];
|
||||||
PlayerSkills: IPlayerSkills;
|
PlayerSkills: IPlayerSkills;
|
||||||
CrewShipAmmo: ITypeCount[];
|
CrewShipAmmo: ITypeCount[];
|
||||||
CrewShipWeaponSkins: IUpgradeClient[];
|
CrewShipWeaponSkins: IUpgradeClient[];
|
||||||
CrewShipSalvagedWeaponSkins: IUpgradeClient[];
|
CrewShipSalvagedWeaponSkins: IUpgradeClient[];
|
||||||
//TradeBannedUntil?: IMongoDate;
|
TradeBannedUntil?: IMongoDate;
|
||||||
PlayedParkourTutorial: boolean;
|
PlayedParkourTutorial: boolean;
|
||||||
SubscribedToEmailsPersonalized: number;
|
SubscribedToEmailsPersonalized: number;
|
||||||
InfestedFoundry?: IInfestedFoundryClient;
|
InfestedFoundry?: IInfestedFoundryClient;
|
||||||
BlessingCooldown?: IMongoDate;
|
BlessingCooldown?: IMongoDate;
|
||||||
CrewShipRawSalvage: ITypeCount[];
|
CrewShipRawSalvage: ITypeCount[];
|
||||||
CrewMembers: ICrewMemberClient[];
|
CrewMembers: ICrewMember[];
|
||||||
LotusCustomization?: ILotusCustomization;
|
LotusCustomization: ILotusCustomization;
|
||||||
UseAdultOperatorLoadout?: boolean;
|
UseAdultOperatorLoadout?: boolean;
|
||||||
NemesisAbandonedRewards: string[];
|
NemesisAbandonedRewards: string[];
|
||||||
LastInventorySync?: IOid;
|
LastInventorySync: IOid;
|
||||||
NextRefill?: IMongoDate;
|
NextRefill?: IMongoDate;
|
||||||
FoundToday?: IMiscItem[]; // for Argon Crystals
|
FoundToday?: IMiscItem[]; // for Argon Crystals
|
||||||
CustomMarkers?: ICustomMarkers[];
|
CustomMarkers?: ICustomMarkers[];
|
||||||
//ActiveLandscapeTraps: any[];
|
ActiveLandscapeTraps: any[];
|
||||||
EvolutionProgress?: IEvolutionProgress[];
|
EvolutionProgress?: IEvolutionProgress[];
|
||||||
//RepVotes: any[];
|
RepVotes: any[];
|
||||||
//LeagueTickets: any[];
|
LeagueTickets: any[];
|
||||||
//Quests: any[];
|
Quests: any[];
|
||||||
//Robotics: any[];
|
Robotics: any[];
|
||||||
//UsedDailyDeals: any[];
|
UsedDailyDeals: any[];
|
||||||
LibraryPersonalTarget?: string;
|
LibraryPersonalTarget?: string;
|
||||||
LibraryPersonalProgress: ILibraryPersonalProgress[];
|
LibraryPersonalProgress: ILibraryPersonalProgress[];
|
||||||
CollectibleSeries?: ICollectibleEntry[];
|
CollectibleSeries?: ICollectibleEntry[];
|
||||||
@ -357,7 +337,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
DeathSquadable: boolean;
|
DeathSquadable: boolean;
|
||||||
EndlessXP?: IEndlessXpProgress[];
|
EndlessXP?: IEndlessXpProgress[];
|
||||||
DialogueHistory?: IDialogueHistoryClient;
|
DialogueHistory?: IDialogueHistoryClient;
|
||||||
CalendarProgress?: ICalendarProgress;
|
CalendarProgress: ICalendarProgress;
|
||||||
SongChallenges?: ISongChallenge[];
|
SongChallenges?: ISongChallenge[];
|
||||||
EntratiVaultCountLastPeriod?: number;
|
EntratiVaultCountLastPeriod?: number;
|
||||||
EntratiVaultCountResetDate?: IMongoDate;
|
EntratiVaultCountResetDate?: IMongoDate;
|
||||||
@ -372,7 +352,6 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
EchoesHexConquestActiveStickers?: string[];
|
EchoesHexConquestActiveStickers?: string[];
|
||||||
BrandedSuits?: IOid[];
|
BrandedSuits?: IOid[];
|
||||||
LockedWeaponGroup?: ILockedWeaponGroupClient;
|
LockedWeaponGroup?: ILockedWeaponGroupClient;
|
||||||
HubNpcCustomizations?: IHubNpcCustomization[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAffiliation {
|
export interface IAffiliation {
|
||||||
@ -469,36 +448,32 @@ export interface ICompletedJob {
|
|||||||
StageCompletions: number[];
|
StageCompletions: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICrewMemberSkill {
|
export interface ICrewMember {
|
||||||
Assigned: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ICrewMemberSkillEfficiency {
|
|
||||||
PILOTING: ICrewMemberSkill;
|
|
||||||
GUNNERY: ICrewMemberSkill;
|
|
||||||
ENGINEERING: ICrewMemberSkill;
|
|
||||||
COMBAT: ICrewMemberSkill;
|
|
||||||
SURVIVABILITY: ICrewMemberSkill;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ICrewMemberClient {
|
|
||||||
ItemType: string;
|
ItemType: string;
|
||||||
NemesisFingerprint: bigint;
|
NemesisFingerprint: number;
|
||||||
Seed: bigint;
|
Seed: number;
|
||||||
AssignedRole?: number;
|
HireDate: IMongoDate;
|
||||||
SkillEfficiency: ICrewMemberSkillEfficiency;
|
AssignedRole: number;
|
||||||
|
SkillEfficiency: ISkillEfficiency;
|
||||||
WeaponConfigIdx: number;
|
WeaponConfigIdx: number;
|
||||||
WeaponId: IOid;
|
WeaponId: IOid;
|
||||||
XP: number;
|
XP: number;
|
||||||
PowersuitType: string;
|
PowersuitType: string;
|
||||||
Configs: IItemConfig[];
|
Configs: IItemConfig[];
|
||||||
SecondInCommand: boolean; // on call
|
SecondInCommand: boolean;
|
||||||
ItemId: IOid;
|
ItemId: IOid;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICrewMemberDatabase extends Omit<ICrewMemberClient, "WeaponId" | "ItemId"> {
|
export interface ISkillEfficiency {
|
||||||
WeaponId: Types.ObjectId;
|
PILOTING: ICombat;
|
||||||
_id: Types.ObjectId;
|
GUNNERY: ICombat;
|
||||||
|
ENGINEERING: ICombat;
|
||||||
|
COMBAT: ICombat;
|
||||||
|
SURVIVABILITY: ICombat;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICombat {
|
||||||
|
Assigned: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum InventorySlot {
|
export enum InventorySlot {
|
||||||
@ -544,12 +519,12 @@ export interface ICrewShipMembersDatabase {
|
|||||||
|
|
||||||
export interface ICrewShipMemberClient {
|
export interface ICrewShipMemberClient {
|
||||||
ItemId?: IOid;
|
ItemId?: IOid;
|
||||||
NemesisFingerprint?: number | bigint;
|
NemesisFingerprint?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICrewShipMemberDatabase {
|
export interface ICrewShipMemberDatabase {
|
||||||
ItemId?: Types.ObjectId;
|
ItemId?: Types.ObjectId;
|
||||||
NemesisFingerprint?: bigint;
|
NemesisFingerprint?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICrewShipCustomization {
|
export interface ICrewShipCustomization {
|
||||||
@ -574,18 +549,17 @@ export type IMiscItem = ITypeCount;
|
|||||||
|
|
||||||
// inventory.CrewShips[0].Weapon
|
// inventory.CrewShips[0].Weapon
|
||||||
export interface ICrewShipWeapon {
|
export interface ICrewShipWeapon {
|
||||||
PILOT?: ICrewShipWeaponEmplacements;
|
PILOT: ICrewShipPilotWeapon;
|
||||||
PORT_GUNS?: ICrewShipWeaponEmplacements;
|
PORT_GUNS: ICrewShipPortGuns;
|
||||||
STARBOARD_GUNS?: ICrewShipWeaponEmplacements;
|
|
||||||
ARTILLERY?: ICrewShipWeaponEmplacements;
|
|
||||||
SCANNER?: ICrewShipWeaponEmplacements;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICrewShipWeaponEmplacements {
|
export interface ICrewShipPilotWeapon {
|
||||||
PRIMARY_A?: IEquipmentSelection;
|
PRIMARY_A: IEquipmentSelection;
|
||||||
PRIMARY_B?: IEquipmentSelection;
|
SECONDARY_A: IEquipmentSelection;
|
||||||
SECONDARY_A?: IEquipmentSelection;
|
}
|
||||||
SECONDARY_B?: IEquipmentSelection;
|
|
||||||
|
export interface ICrewShipPortGuns {
|
||||||
|
PRIMARY_A: IEquipmentSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IDiscoveredMarker {
|
export interface IDiscoveredMarker {
|
||||||
@ -681,17 +655,6 @@ export interface IInvasionChainProgress {
|
|||||||
count: number;
|
count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IInvasionProgressClient {
|
|
||||||
_id: IOid;
|
|
||||||
Delta: number;
|
|
||||||
AttackerScore: number;
|
|
||||||
DefenderScore: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IInvasionProgressDatabase extends Omit<IInvasionProgressClient, "_id"> {
|
|
||||||
invasionId: Types.ObjectId;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IKubrowPetEggClient {
|
export interface IKubrowPetEggClient {
|
||||||
ItemType: string;
|
ItemType: string;
|
||||||
ExpirationDate: IMongoDate; // seems to be set to 7 days ahead @ 0 UTC
|
ExpirationDate: IMongoDate; // seems to be set to 7 days ahead @ 0 UTC
|
||||||
@ -753,21 +716,12 @@ export enum Status {
|
|||||||
StatusStasis = "STATUS_STASIS"
|
StatusStasis = "STATUS_STASIS"
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ILastSortieRewardClient {
|
export interface ILastSortieReward {
|
||||||
SortieId: IOid;
|
SortieId: IOid;
|
||||||
StoreItem: string;
|
StoreItem: string;
|
||||||
Manifest: string;
|
Manifest: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ILastSortieRewardDatabase extends Omit<ILastSortieRewardClient, "SortieId"> {
|
|
||||||
SortieId: Types.ObjectId;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ISortieRewardAttenuation {
|
|
||||||
Tag: string;
|
|
||||||
Atten: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ILibraryDailyTaskInfo {
|
export interface ILibraryDailyTaskInfo {
|
||||||
EnemyTypes: string[];
|
EnemyTypes: string[];
|
||||||
EnemyLocTag: string;
|
EnemyLocTag: string;
|
||||||
@ -849,7 +803,7 @@ export interface IMission extends IMissionDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface INemesisBaseClient {
|
export interface INemesisBaseClient {
|
||||||
fp: bigint | number;
|
fp: bigint;
|
||||||
manifest: string;
|
manifest: string;
|
||||||
KillingSuit: string;
|
KillingSuit: string;
|
||||||
killingDamageType: number;
|
killingDamageType: number;
|
||||||
@ -867,8 +821,7 @@ export interface INemesisBaseClient {
|
|||||||
Weakened: boolean;
|
Weakened: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface INemesisBaseDatabase extends Omit<INemesisBaseClient, "fp" | "d"> {
|
export interface INemesisBaseDatabase extends Omit<INemesisBaseClient, "d"> {
|
||||||
fp: bigint;
|
|
||||||
d: Date;
|
d: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -882,8 +835,7 @@ export interface INemesisClient extends INemesisBaseClient {
|
|||||||
LastEnc: number;
|
LastEnc: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface INemesisDatabase extends Omit<INemesisClient, "fp" | "d"> {
|
export interface INemesisDatabase extends Omit<INemesisClient, "d"> {
|
||||||
fp: bigint;
|
|
||||||
d: Date;
|
d: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -906,8 +858,8 @@ export interface IPendingRecipeDatabase {
|
|||||||
ItemType: string;
|
ItemType: string;
|
||||||
CompletionDate: Date;
|
CompletionDate: Date;
|
||||||
ItemId: IOid;
|
ItemId: IOid;
|
||||||
TargetItemId?: string; // unsure what this is for
|
TargetItemId?: string; // likely related to liches
|
||||||
TargetFingerprint?: string;
|
TargetFingerprint?: string; // likely related to liches
|
||||||
LongGuns?: IEquipmentDatabase[];
|
LongGuns?: IEquipmentDatabase[];
|
||||||
Pistols?: IEquipmentDatabase[];
|
Pistols?: IEquipmentDatabase[];
|
||||||
Melee?: IEquipmentDatabase[];
|
Melee?: IEquipmentDatabase[];
|
||||||
@ -919,10 +871,6 @@ export interface IPendingRecipeClient
|
|||||||
CompletionDate: IMongoDate;
|
CompletionDate: IMongoDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAccolades {
|
|
||||||
Heirloom?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPendingTrade {
|
export interface IPendingTrade {
|
||||||
State: number;
|
State: number;
|
||||||
SelfReady: boolean;
|
SelfReady: boolean;
|
||||||
@ -951,21 +899,6 @@ export interface IInnateDamageFingerprint {
|
|||||||
buffs: IFingerprintStat[];
|
buffs: IFingerprintStat[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICrewShipComponentFingerprint extends IInnateDamageFingerprint {
|
|
||||||
SubroutineIndex?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface INemesisWeaponTargetFingerprint {
|
|
||||||
ItemType: string;
|
|
||||||
UpgradeFingerprint: IInnateDamageFingerprint;
|
|
||||||
Name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface INemesisPetTargetFingerprint {
|
|
||||||
Parts: string[];
|
|
||||||
Name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum GettingSlotOrderInfo {
|
export enum GettingSlotOrderInfo {
|
||||||
Empty = "",
|
Empty = "",
|
||||||
LotusUpgradesModsRandomizedPlayerMeleeWeaponRandomModRare0 = "/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare:0",
|
LotusUpgradesModsRandomizedPlayerMeleeWeaponRandomModRare0 = "/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare:0",
|
||||||
@ -1002,22 +935,16 @@ export interface IPersonalGoalProgress {
|
|||||||
ReceivedClanReward1?: boolean;
|
ReceivedClanReward1?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPersonalTechProjectDatabase {
|
export interface IPersonalTechProject {
|
||||||
State: number;
|
State: number;
|
||||||
ReqCredits: number;
|
ReqCredits: number;
|
||||||
ItemType: string;
|
ItemType: string;
|
||||||
ProductCategory?: string;
|
|
||||||
CategoryItemId?: Types.ObjectId;
|
|
||||||
ReqItems: ITypeCount[];
|
ReqItems: ITypeCount[];
|
||||||
HasContributions?: boolean;
|
|
||||||
CompletionDate?: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPersonalTechProjectClient
|
|
||||||
extends Omit<IPersonalTechProjectDatabase, "CategoryItemId" | "CompletionDate"> {
|
|
||||||
CategoryItemId?: IOid;
|
|
||||||
CompletionDate?: IMongoDate;
|
CompletionDate?: IMongoDate;
|
||||||
ItemId: IOid;
|
ItemId: IOid;
|
||||||
|
ProductCategory?: string;
|
||||||
|
CategoryItemId?: IOid;
|
||||||
|
HasContributions?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPlayerSkills {
|
export interface IPlayerSkills {
|
||||||
@ -1107,7 +1034,6 @@ export interface ITaunt {
|
|||||||
|
|
||||||
export interface IWeaponSkinDatabase {
|
export interface IWeaponSkinDatabase {
|
||||||
ItemType: string;
|
ItemType: string;
|
||||||
Favorite?: boolean;
|
|
||||||
IsNew?: boolean;
|
IsNew?: boolean;
|
||||||
_id: Types.ObjectId;
|
_id: Types.ObjectId;
|
||||||
}
|
}
|
||||||
@ -1147,13 +1073,13 @@ export interface IEndlessXpProgress {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IDialogueHistoryClient {
|
export interface IDialogueHistoryClient {
|
||||||
YearIteration?: number;
|
YearIteration: number;
|
||||||
Resets?: number; // added in 38.5.0
|
Resets?: number; // added in 38.5.0
|
||||||
Dialogues?: IDialogueClient[];
|
Dialogues?: IDialogueClient[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IDialogueHistoryDatabase {
|
export interface IDialogueHistoryDatabase {
|
||||||
YearIteration?: number;
|
YearIteration: number;
|
||||||
Resets?: number;
|
Resets?: number;
|
||||||
Dialogues?: IDialogueDatabase[];
|
Dialogues?: IDialogueDatabase[];
|
||||||
}
|
}
|
||||||
@ -1210,18 +1136,17 @@ export interface IMarker {
|
|||||||
z: number;
|
z: number;
|
||||||
showInHud: boolean;
|
showInHud: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISeasonProgress {
|
export interface ISeasonProgress {
|
||||||
SeasonType: "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL";
|
SeasonType: "CST_UNDEFINED" | "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL";
|
||||||
LastCompletedDayIdx: number;
|
LastCompletedDayIdx: number;
|
||||||
LastCompletedChallengeDayIdx: number;
|
LastCompletedChallengeDayIdx: number;
|
||||||
ActivatedChallenges: string[];
|
ActivatedChallenges: unknown[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICalendarProgress {
|
export interface ICalendarProgress {
|
||||||
Version: number;
|
Version: number;
|
||||||
Iteration: number;
|
Iteration: number;
|
||||||
YearProgress: { Upgrades: string[] };
|
YearProgress: { Upgrades: unknown[] };
|
||||||
SeasonProgress: ISeasonProgress;
|
SeasonProgress: ISeasonProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1247,9 +1172,3 @@ export interface ILockedWeaponGroupDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type TPartialStartingGear = Pick<IInventoryClient, "LongGuns" | "Suits" | "Pistols" | "Melee">;
|
export type TPartialStartingGear = Pick<IInventoryClient, "LongGuns" | "Suits" | "Pistols" | "Melee">;
|
||||||
|
|
||||||
export interface IHubNpcCustomization {
|
|
||||||
Colors?: IColor;
|
|
||||||
Pattern: string;
|
|
||||||
Tag: string;
|
|
||||||
}
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user