forked from OpenWF/SpaceNinjaServer
Compare commits
6 Commits
main
...
janisslsm/
Author | SHA1 | Date | |
---|---|---|---|
![]() |
225cd83cea | ||
![]() |
e824087034 | ||
![]() |
fd2027b071 | ||
![]() |
0af98bc6c2 | ||
![]() |
3403d496b4 | ||
![]() |
58b1cfc30f |
@ -1,5 +0,0 @@
|
|||||||
**/.dockerignore
|
|
||||||
**/.git
|
|
||||||
Dockerfile*
|
|
||||||
.*
|
|
||||||
docker-data/
|
|
4
.env.example
Normal file
4
.env.example
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Docker may need a .env file for the following settings:
|
||||||
|
DATABASE_PORT=27017
|
||||||
|
DATABASE_USERNAME=root
|
||||||
|
DATABASE_PASSWORD=database
|
@ -12,6 +12,7 @@
|
|||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"@typescript-eslint/explicit-function-return-type": "warn",
|
"@typescript-eslint/explicit-function-return-type": "warn",
|
||||||
|
"@typescript-eslint/explicit-module-boundary-types": "warn",
|
||||||
"@typescript-eslint/restrict-template-expressions": "warn",
|
"@typescript-eslint/restrict-template-expressions": "warn",
|
||||||
"@typescript-eslint/restrict-plus-operands": "warn",
|
"@typescript-eslint/restrict-plus-operands": "warn",
|
||||||
"@typescript-eslint/no-unsafe-member-access": "warn",
|
"@typescript-eslint/no-unsafe-member-access": "warn",
|
||||||
@ -22,13 +23,10 @@
|
|||||||
"@typescript-eslint/no-unsafe-assignment": "warn",
|
"@typescript-eslint/no-unsafe-assignment": "warn",
|
||||||
"@typescript-eslint/no-explicit-any": "warn",
|
"@typescript-eslint/no-explicit-any": "warn",
|
||||||
"@typescript-eslint/no-loss-of-precision": "warn",
|
"@typescript-eslint/no-loss-of-precision": "warn",
|
||||||
"@typescript-eslint/no-unnecessary-condition": "warn",
|
"no-case-declarations": "warn",
|
||||||
"no-case-declarations": "error",
|
|
||||||
"prettier/prettier": "error",
|
"prettier/prettier": "error",
|
||||||
"@typescript-eslint/semi": "error",
|
"@typescript-eslint/semi": "error",
|
||||||
"no-mixed-spaces-and-tabs": "error",
|
"no-mixed-spaces-and-tabs": "error"
|
||||||
"require-await": "off",
|
|
||||||
"@typescript-eslint/require-await": "error"
|
|
||||||
},
|
},
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
|
1
.github/workflows/build.yml
vendored
1
.github/workflows/build.yml
vendored
@ -17,5 +17,6 @@ jobs:
|
|||||||
node-version: ${{ matrix.version }}
|
node-version: ${{ matrix.version }}
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: cp config.json.example config.json
|
- run: cp config.json.example config.json
|
||||||
|
- run: echo '{"version":"","buildLabel":"","matchmakingBuildId":""}' > static/data/buildConfig.json
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
- run: npm run lint
|
- run: npm run lint
|
||||||
|
24
.github/workflows/docker.yml
vendored
24
.github/workflows/docker.yml
vendored
@ -1,24 +0,0 @@
|
|||||||
name: Build Docker image
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
jobs:
|
|
||||||
docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Set up Docker buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Log in to container registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: openwf
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
tags: |
|
|
||||||
openwf/spaceninjaserver:latest
|
|
||||||
openwf/spaceninjaserver:${{ github.sha }}
|
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -16,6 +16,3 @@ yarn.lock
|
|||||||
|
|
||||||
# MongoDB VSCode extension playground scripts
|
# MongoDB VSCode extension playground scripts
|
||||||
/database_scripts
|
/database_scripts
|
||||||
|
|
||||||
# Default Docker directory
|
|
||||||
/docker-data
|
|
||||||
|
19
.vscode/launch.json
vendored
19
.vscode/launch.json
vendored
@ -1,19 +0,0 @@
|
|||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
{
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"type": "node",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Debug and Watch",
|
|
||||||
"runtimeArgs": ["-r", "tsconfig-paths/register", "-r", "ts-node/register", "--watch-path", "src"],
|
|
||||||
"args": ["${workspaceFolder}/src/index.ts"],
|
|
||||||
"console": "integratedTerminal"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
//can use "console": "internalConsole" for VS Code's Debug Console. For that, forceConsole in logger.ts is needed to be true
|
|
||||||
//"internalConsoleOptions": "openOnSessionStart" can be useful then
|
|
29
Dockerfile
29
Dockerfile
@ -1,28 +1,5 @@
|
|||||||
FROM node:18-alpine3.19
|
FROM mongo as base
|
||||||
|
|
||||||
ENV APP_MONGODB_URL=mongodb://mongodb:27017/openWF
|
EXPOSE 27017
|
||||||
ENV APP_MY_ADDRESS=localhost
|
|
||||||
ENV APP_HTTP_PORT=80
|
|
||||||
ENV APP_HTTPS_PORT=443
|
|
||||||
ENV APP_AUTO_CREATE_ACCOUNT=true
|
|
||||||
ENV APP_SKIP_STORY_MODE_CHOICE=true
|
|
||||||
ENV APP_SKIP_TUTORIAL=true
|
|
||||||
ENV APP_SKIP_ALL_DIALOGUE=true
|
|
||||||
ENV APP_UNLOCK_ALL_SCANS=true
|
|
||||||
ENV APP_UNLOCK_ALL_MISSIONS=true
|
|
||||||
ENV APP_UNLOCK_ALL_QUESTS=true
|
|
||||||
ENV APP_COMPLETE_ALL_QUESTS=true
|
|
||||||
ENV APP_INFINITE_RESOURCES=true
|
|
||||||
ENV APP_UNLOCK_ALL_SHIP_FEATURES=true
|
|
||||||
ENV APP_UNLOCK_ALL_SHIP_DECORATIONS=true
|
|
||||||
ENV APP_UNLOCK_ALL_FLAVOUR_ITEMS=true
|
|
||||||
ENV APP_UNLOCK_ALL_SKINS=true
|
|
||||||
ENV APP_UNIVERSAL_POLARITY_EVERYWHERE=true
|
|
||||||
ENV APP_SPOOF_MASTERY_RANK=-1
|
|
||||||
|
|
||||||
RUN apk add --no-cache bash sed wget jq
|
CMD ["mongod"]
|
||||||
|
|
||||||
COPY . /app
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
|
@ -1,8 +1,3 @@
|
|||||||
# Space Ninja Server
|
# Space Ninja Server
|
||||||
|
|
||||||
More information for the moment here: [https://discord.gg/PNNZ3asUuY](https://discord.gg/PNNZ3asUuY)
|
More information for the moment here: [https://discord.gg/PNNZ3asUuY](https://discord.gg/PNNZ3asUuY)
|
||||||
|
|
||||||
## config.json
|
|
||||||
|
|
||||||
- `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 ]`.
|
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
@echo off
|
|
||||||
|
|
||||||
echo Updating SpaceNinjaServer...
|
|
||||||
git config remote.origin.url https://openwf.io/SpaceNinjaServer.git
|
|
||||||
git fetch --prune
|
|
||||||
git reset --hard origin/main
|
|
||||||
|
|
||||||
if exist static\data\0\ (
|
|
||||||
echo Updating stripped assets...
|
|
||||||
cd static\data\0\
|
|
||||||
git pull
|
|
||||||
cd ..\..\..\
|
|
||||||
)
|
|
||||||
|
|
||||||
echo Updating dependencies...
|
|
||||||
call npm i
|
|
||||||
|
|
||||||
call npm run build
|
|
||||||
call npm run start
|
|
||||||
|
|
||||||
echo SpaceNinjaServer seems to have crashed.
|
|
||||||
:a
|
|
||||||
pause > nul
|
|
||||||
goto a
|
|
@ -1,35 +1,26 @@
|
|||||||
{
|
{
|
||||||
"mongodbUrl": "mongodb://127.0.0.1:27017/openWF",
|
"mongodbUrl": "mongodb://127.0.0.1:27017/openWF_2013",
|
||||||
"logger": {
|
"logger": {
|
||||||
"files": true,
|
"files": true,
|
||||||
"level": "trace"
|
"level": "trace",
|
||||||
|
"__valid_levels": "fatal, error, warn, info, http, debug, trace"
|
||||||
},
|
},
|
||||||
"myAddress": "localhost",
|
"myAddress": "localhost",
|
||||||
"hubAddress": "https://localhost/api/",
|
|
||||||
"platformCDNs": ["https://localhost/"],
|
|
||||||
"NRS": ["localhost"],
|
|
||||||
"httpPort": 80,
|
"httpPort": 80,
|
||||||
"httpsPort": 443,
|
"httpsPort": 443,
|
||||||
"administratorNames": [],
|
|
||||||
"autoCreateAccount": true,
|
"autoCreateAccount": true,
|
||||||
|
"skipStoryModeChoice": true,
|
||||||
"skipTutorial": true,
|
"skipTutorial": true,
|
||||||
"skipAllDialogue": true,
|
"skipAllDialogue": true,
|
||||||
"unlockAllScans": true,
|
"unlockAllScans": true,
|
||||||
"unlockAllMissions": true,
|
"unlockAllMissions": true,
|
||||||
"infiniteCredits": true,
|
"unlockAllQuests": true,
|
||||||
"infinitePlatinum": true,
|
"completeAllQuests": false,
|
||||||
"infiniteEndo": true,
|
"infiniteResources": true,
|
||||||
"infiniteRegalAya": true,
|
|
||||||
"infiniteHelminthMaterials": false,
|
|
||||||
"unlockAllShipFeatures": true,
|
"unlockAllShipFeatures": true,
|
||||||
"unlockAllShipDecorations": true,
|
"unlockAllShipDecorations": true,
|
||||||
"unlockAllFlavourItems": true,
|
"unlockAllFlavourItems": true,
|
||||||
"unlockAllSkins": true,
|
"unlockAllSkins": true,
|
||||||
"unlockAllCapturaScenes": true,
|
|
||||||
"universalPolarityEverywhere": true,
|
"universalPolarityEverywhere": true,
|
||||||
"unlockDoubleCapacityPotatoesEverywhere": true,
|
|
||||||
"unlockExilusEverywhere": true,
|
|
||||||
"unlockArcanesEverywhere": true,
|
|
||||||
"noDailyStandingLimits": true,
|
|
||||||
"spoofMasteryRank": -1
|
"spoofMasteryRank": -1
|
||||||
}
|
}
|
||||||
|
@ -1,43 +1,24 @@
|
|||||||
|
version: "3.9"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
spaceninjaserver:
|
|
||||||
# build: .
|
|
||||||
image: openwf/spaceninjaserver:latest
|
|
||||||
environment:
|
|
||||||
APP_MONGODB_URL: mongodb://openwfagent:spaceninjaserver@mongodb:27017/
|
|
||||||
|
|
||||||
# Following environment variables are set to default image values.
|
|
||||||
# Uncomment to edit.
|
|
||||||
|
|
||||||
# APP_MY_ADDRESS: localhost
|
|
||||||
# APP_HTTP_PORT: 80
|
|
||||||
# APP_HTTPS_PORT: 443
|
|
||||||
# APP_AUTO_CREATE_ACCOUNT: true
|
|
||||||
# APP_SKIP_STORY_MODE_CHOICE: true
|
|
||||||
# APP_SKIP_TUTORIAL: true
|
|
||||||
# APP_SKIP_ALL_DIALOGUE: true
|
|
||||||
# APP_UNLOCK_ALL_SCANS: true
|
|
||||||
# APP_UNLOCK_ALL_MISSIONS: true
|
|
||||||
# APP_UNLOCK_ALL_QUESTS: true
|
|
||||||
# APP_COMPLETE_ALL_QUESTS: true
|
|
||||||
# APP_INFINITE_RESOURCES: true
|
|
||||||
# APP_UNLOCK_ALL_SHIP_FEATURES: true
|
|
||||||
# APP_UNLOCK_ALL_SHIP_DECORATIONS: true
|
|
||||||
# APP_UNLOCK_ALL_FLAVOUR_ITEMS: true
|
|
||||||
# APP_UNLOCK_ALL_SKINS: true
|
|
||||||
# APP_UNIVERSAL_POLARITY_EVERYWHERE: true
|
|
||||||
# APP_SPOOF_MASTERY_RANK: -1
|
|
||||||
volumes:
|
|
||||||
- ./docker-data/static:/app/static/data
|
|
||||||
- ./docker-data/logs:/app/logs
|
|
||||||
ports:
|
|
||||||
- 80:80
|
|
||||||
- 443:443
|
|
||||||
depends_on:
|
|
||||||
- mongodb
|
|
||||||
mongodb:
|
mongodb:
|
||||||
image: docker.io/library/mongo:8.0.0-noble
|
container_name: mongodb
|
||||||
|
image: mongodb
|
||||||
|
restart: always
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
target: base
|
||||||
environment:
|
environment:
|
||||||
MONGO_INITDB_ROOT_USERNAME: openwfagent
|
MONGO_INITDB_ROOT_USERNAME: ${DATABASE_USERNAME}
|
||||||
MONGO_INITDB_ROOT_PASSWORD: spaceninjaserver
|
MONGO_INITDB_ROOT_PASSWORD: ${DATABASE_PASSWORD}
|
||||||
volumes:
|
ports:
|
||||||
- ./docker-data/database:/data/db
|
- ${DATABASE_PORT}:${DATABASE_PORT}
|
||||||
|
expose:
|
||||||
|
- "${DATABASE_PORT}"
|
||||||
|
networks:
|
||||||
|
- docker
|
||||||
|
|
||||||
|
networks:
|
||||||
|
docker:
|
||||||
|
external: true
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Set up the configuration file using environment variables.
|
|
||||||
echo '{
|
|
||||||
"logger": {
|
|
||||||
"files": true,
|
|
||||||
"level": "trace",
|
|
||||||
"__valid_levels": "fatal, error, warn, info, http, debug, trace"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
' > config.json
|
|
||||||
|
|
||||||
for config in $(env | grep "APP_")
|
|
||||||
do
|
|
||||||
var=$(echo "${config}" | tr '[:upper:]' '[:lower:]' | sed 's/app_//g' | sed -E 's/_([a-z])/\U\1/g' | sed 's/=.*//g')
|
|
||||||
val=$(echo "${config}" | sed 's/.*=//g')
|
|
||||||
jq --arg variable "$var" --arg value "$val" '.[$variable] += try [$value|fromjson][] catch $value' config.json > config.tmp
|
|
||||||
mv config.tmp config.json
|
|
||||||
done
|
|
||||||
|
|
||||||
npm install
|
|
||||||
exec npm run dev
|
|
2178
package-lock.json
generated
2178
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
26
package.json
26
package.json
@ -9,32 +9,30 @@
|
|||||||
"build": "tsc && copyfiles static/webui/** build",
|
"build": "tsc && copyfiles static/webui/** build",
|
||||||
"lint": "eslint --ext .ts .",
|
"lint": "eslint --ext .ts .",
|
||||||
"lint:fix": "eslint --fix --ext .ts .",
|
"lint:fix": "eslint --fix --ext .ts .",
|
||||||
"prettier": "prettier --write .",
|
"prettier": "prettier --write ."
|
||||||
"update-translations": "cd scripts && node update-translations.js"
|
|
||||||
},
|
},
|
||||||
"license": "GNU",
|
"license": "GNU",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
"express": "^5",
|
"express": "^5.0.0-beta.3",
|
||||||
"mongoose": "^8.9.4",
|
"mongoose": "^8.4.5",
|
||||||
"warframe-public-export-plus": "^0.5.36",
|
"warframe-public-export-plus": "^0.4.4",
|
||||||
"warframe-riven-info": "^0.1.2",
|
"warframe-riven-info": "^0.1.1",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.13.0",
|
||||||
"winston-daily-rotate-file": "^5.0.0"
|
"winston-daily-rotate-file": "^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^5",
|
"@types/express": "^4.17.20",
|
||||||
"@types/morgan": "^1.9.9",
|
"@types/morgan": "^1.9.9",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.18",
|
"@typescript-eslint/eslint-plugin": "^7.14",
|
||||||
"@typescript-eslint/parser": "^7.18",
|
"@typescript-eslint/parser": "^7.14",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-plugin-prettier": "^5.2.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.3.2",
|
||||||
"ts-node": "^10.9.2",
|
|
||||||
"ts-node-dev": "^2.0.0",
|
"ts-node-dev": "^2.0.0",
|
||||||
"tsconfig-paths": "^4.2.0",
|
"tsconfig-paths": "^4.2.0",
|
||||||
"typescript": ">=4.7.4 <5.6.0"
|
"typescript": "^5.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.15.0",
|
"node": ">=18.15.0",
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
// Based on http://209.141.38.3/OpenWF/Translations/src/branch/main/update.php
|
|
||||||
// Converted via ChatGPT-4o
|
|
||||||
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
function extractStrings(content) {
|
|
||||||
const regex = /([a-zA-Z_]+): `([^`]*)`,/g;
|
|
||||||
let matches;
|
|
||||||
const strings = {};
|
|
||||||
while ((matches = regex.exec(content)) !== null) {
|
|
||||||
strings[matches[1]] = matches[2];
|
|
||||||
}
|
|
||||||
return strings;
|
|
||||||
}
|
|
||||||
|
|
||||||
const source = fs.readFileSync("../static/webui/translations/en.js", "utf8");
|
|
||||||
const sourceStrings = extractStrings(source);
|
|
||||||
const sourceLines = source.split("\n");
|
|
||||||
|
|
||||||
fs.readdirSync("../static/webui/translations").forEach(file => {
|
|
||||||
if (fs.lstatSync(`../static/webui/translations/${file}`).isFile() && file !== "en.js") {
|
|
||||||
const content = fs.readFileSync(`../static/webui/translations/${file}`, "utf8");
|
|
||||||
const targetStrings = extractStrings(content);
|
|
||||||
const contentLines = content.split("\n");
|
|
||||||
|
|
||||||
const fileHandle = fs.openSync(`../static/webui/translations/${file}`, "w");
|
|
||||||
fs.writeSync(fileHandle, contentLines[0] + "\n");
|
|
||||||
|
|
||||||
sourceLines.forEach(line => {
|
|
||||||
const strings = extractStrings(line);
|
|
||||||
if (Object.keys(strings).length > 0) {
|
|
||||||
Object.entries(strings).forEach(([key, value]) => {
|
|
||||||
if (targetStrings.hasOwnProperty(key)) {
|
|
||||||
fs.writeSync(fileHandle, ` ${key}: \`${targetStrings[key]}\`,\n`);
|
|
||||||
} else {
|
|
||||||
fs.writeSync(fileHandle, ` ${key}: \`[UNTRANSLATED] ${value}\`,\n`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (line.length) {
|
|
||||||
fs.writeSync(fileHandle, line + "\n");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
fs.closeSync(fileHandle);
|
|
||||||
}
|
|
||||||
});
|
|
43
src/app.ts
43
src/app.ts
@ -1,34 +1,65 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
|
|
||||||
import bodyParser from "body-parser";
|
|
||||||
import { unknownEndpointHandler } from "@/src/middleware/middleware";
|
import { unknownEndpointHandler } from "@/src/middleware/middleware";
|
||||||
import { requestLogger } from "@/src/middleware/morgenMiddleware";
|
import { requestLogger } from "@/src/middleware/morgenMiddleware";
|
||||||
import { errorHandler } from "@/src/middleware/errorHandler";
|
|
||||||
|
|
||||||
import { apiRouter } from "@/src/routes/api";
|
import { apiRouter } from "@/src/routes/api";
|
||||||
|
//import { testRouter } from "@/src/routes/test";
|
||||||
import { cacheRouter } from "@/src/routes/cache";
|
import { cacheRouter } from "@/src/routes/cache";
|
||||||
|
import bodyParser from "body-parser";
|
||||||
|
|
||||||
|
import { steamPacksController } from "@/src/controllers/misc/steamPacksController";
|
||||||
import { customRouter } from "@/src/routes/custom";
|
import { customRouter } from "@/src/routes/custom";
|
||||||
import { dynamicController } from "@/src/routes/dynamic";
|
import { dynamicController } from "@/src/routes/dynamic";
|
||||||
import { payRouter } from "@/src/routes/pay";
|
|
||||||
import { statsRouter } from "@/src/routes/stats";
|
import { statsRouter } from "@/src/routes/stats";
|
||||||
import { webuiRouter } from "@/src/routes/webui";
|
import { webuiRouter } from "@/src/routes/webui";
|
||||||
|
import { connectDatabase } from "@/src/services/mongoService";
|
||||||
|
import { registerLogFileCreationListener } from "@/src/utils/logger";
|
||||||
|
import * as zlib from "zlib";
|
||||||
|
|
||||||
|
void registerLogFileCreationListener();
|
||||||
|
void connectDatabase();
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
|
app.use(function (req, _res, next) {
|
||||||
|
const buffer: Buffer[] = [];
|
||||||
|
req.on("data", function (chunk: Buffer) {
|
||||||
|
if (chunk !== undefined && chunk.length > 2 && chunk[0] == 0x1f && chunk[1] == 0x8b) {
|
||||||
|
buffer.push(Buffer.from(chunk));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on("end", function () {
|
||||||
|
zlib.gunzip(Buffer.concat(buffer), function (_err, dezipped) {
|
||||||
|
if (typeof dezipped != "undefined") {
|
||||||
|
req.body = dezipped.toString("utf-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
app.use(bodyParser.raw());
|
app.use(bodyParser.raw());
|
||||||
app.use(express.json({ limit: "4mb" }));
|
app.use(express.json());
|
||||||
app.use(bodyParser.text());
|
app.use(bodyParser.text());
|
||||||
app.use(requestLogger);
|
app.use(requestLogger);
|
||||||
|
//app.use(requestLogger);
|
||||||
|
|
||||||
app.use("/api", apiRouter);
|
app.use("/api", apiRouter);
|
||||||
|
//app.use("/test", testRouter);
|
||||||
app.use("/", cacheRouter);
|
app.use("/", cacheRouter);
|
||||||
app.use("/custom", customRouter);
|
app.use("/custom", customRouter);
|
||||||
app.use("/:id/dynamic", dynamicController);
|
app.use("/:id/dynamic", dynamicController);
|
||||||
app.use("/pay", payRouter);
|
|
||||||
|
app.post("/pay/steamPacks.php", steamPacksController);
|
||||||
app.use("/stats", statsRouter);
|
app.use("/stats", statsRouter);
|
||||||
|
|
||||||
app.use("/", webuiRouter);
|
app.use("/", webuiRouter);
|
||||||
|
|
||||||
app.use(unknownEndpointHandler);
|
app.use(unknownEndpointHandler);
|
||||||
app.use(errorHandler);
|
|
||||||
|
//app.use(errorHandler)
|
||||||
|
|
||||||
export { app };
|
export { app };
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { addMods, getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { getRandomElement, getRandomInt, getRandomReward, IRngResult } from "@/src/services/rngService";
|
|
||||||
import { logger } from "@/src/utils/logger";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
import { ExportUpgrades } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
export const activateRandomModController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const request = getJSONfromString<IActiveRandomModRequest>(String(req.body));
|
|
||||||
addMods(inventory, [
|
|
||||||
{
|
|
||||||
ItemType: request.ItemType,
|
|
||||||
ItemCount: -1
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType]);
|
|
||||||
const challenge = getRandomElement(ExportUpgrades[rivenType].availableChallenges!);
|
|
||||||
const fingerprintChallenge: IRandomModChallenge = {
|
|
||||||
Type: challenge.fullName,
|
|
||||||
Progress: 0,
|
|
||||||
Required: getRandomInt(challenge.countRange[0], challenge.countRange[1])
|
|
||||||
};
|
|
||||||
if (Math.random() < challenge.complicationChance) {
|
|
||||||
const complicationsAsRngResults: IRngResult[] = [];
|
|
||||||
for (const complication of challenge.complications) {
|
|
||||||
complicationsAsRngResults.push({
|
|
||||||
type: complication.fullName,
|
|
||||||
itemCount: 1,
|
|
||||||
probability: complication.weight
|
|
||||||
});
|
|
||||||
}
|
|
||||||
fingerprintChallenge.Complication = getRandomReward(complicationsAsRngResults)!.type;
|
|
||||||
logger.debug(
|
|
||||||
`riven rolled challenge ${fingerprintChallenge.Type} with complication ${fingerprintChallenge.Complication}`
|
|
||||||
);
|
|
||||||
const complication = challenge.complications.find(x => x.fullName == fingerprintChallenge.Complication)!;
|
|
||||||
fingerprintChallenge.Required *= complication.countMultiplier;
|
|
||||||
} else {
|
|
||||||
logger.debug(`riven rolled challenge ${fingerprintChallenge.Type}`);
|
|
||||||
}
|
|
||||||
const upgradeIndex =
|
|
||||||
inventory.Upgrades.push({
|
|
||||||
ItemType: rivenType,
|
|
||||||
UpgradeFingerprint: JSON.stringify({ challenge: fingerprintChallenge })
|
|
||||||
}) - 1;
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
NewMod: inventory.Upgrades[upgradeIndex].toJSON()
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IActiveRandomModRequest {
|
|
||||||
ItemType: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IRandomModChallenge {
|
|
||||||
Type: string;
|
|
||||||
Progress: number;
|
|
||||||
Required: number;
|
|
||||||
Complication?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rivenRawToRealWeighted: Record<string, string[]> = {
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/RawArchgunRandomMod": [
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/LotusArchgunRandomModRare"
|
|
||||||
],
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/RawMeleeRandomMod": [
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare"
|
|
||||||
],
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/RawModularMeleeRandomMod": [
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/LotusModularMeleeRandomModRare"
|
|
||||||
],
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/RawModularPistolRandomMod": [
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/LotusModularPistolRandomModRare"
|
|
||||||
],
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/RawPistolRandomMod": ["/Lotus/Upgrades/Mods/Randomized/LotusPistolRandomModRare"],
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/RawRifleRandomMod": ["/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare"],
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/RawShotgunRandomMod": [
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/LotusShotgunRandomModRare"
|
|
||||||
],
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/RawSentinelWeaponRandomMod": [
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/LotusShotgunRandomModRare",
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/LotusPistolRandomModRare",
|
|
||||||
"/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare"
|
|
||||||
]
|
|
||||||
};
|
|
@ -4,9 +4,10 @@ import { IUpdateGlyphRequest } from "@/src/types/requestTypes";
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
const addFriendImageController: RequestHandler = async (req, res) => {
|
const addFriendImageController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const json = getJSONfromString<IUpdateGlyphRequest>(String(req.body));
|
const json = getJSONfromString(String(req.body)) as IUpdateGlyphRequest;
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
inventory.ActiveAvatarImageType = json.AvatarImageType;
|
inventory.ActiveAvatarImageType = json.AvatarImageType;
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
@ -1,76 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { getInventory, addMods } from "@/src/services/inventoryService";
|
|
||||||
import { IOid } from "@/src/types/commonTypes";
|
|
||||||
|
|
||||||
export const arcaneCommonController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const json = getJSONfromString<IArcaneCommonRequest>(String(req.body));
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const upgrade = inventory.Upgrades.id(json.arcane.ItemId.$oid);
|
|
||||||
if (json.newRank == -1) {
|
|
||||||
// Break down request?
|
|
||||||
if (!upgrade || !upgrade.UpgradeFingerprint) {
|
|
||||||
throw new Error(`Failed to find upgrade with OID ${json.arcane.ItemId.$oid}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove Upgrade
|
|
||||||
inventory.Upgrades.pull({ _id: json.arcane.ItemId.$oid });
|
|
||||||
|
|
||||||
// Add RawUpgrades
|
|
||||||
const numRawUpgradesToGive = arcaneLevelCounts[(JSON.parse(upgrade.UpgradeFingerprint) as { lvl: number }).lvl];
|
|
||||||
addMods(inventory, [
|
|
||||||
{
|
|
||||||
ItemType: json.arcane.ItemType,
|
|
||||||
ItemCount: numRawUpgradesToGive
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
res.json({ upgradeId: json.arcane.ItemId.$oid, numConsumed: numRawUpgradesToGive });
|
|
||||||
} else {
|
|
||||||
// Upgrade request?
|
|
||||||
let numConsumed = arcaneLevelCounts[json.newRank];
|
|
||||||
let upgradeId = json.arcane.ItemId.$oid;
|
|
||||||
if (upgrade) {
|
|
||||||
// Have an existing Upgrade item?
|
|
||||||
if (upgrade.UpgradeFingerprint) {
|
|
||||||
const existingLevel = (JSON.parse(upgrade.UpgradeFingerprint) as { lvl: number }).lvl;
|
|
||||||
numConsumed -= arcaneLevelCounts[existingLevel];
|
|
||||||
}
|
|
||||||
upgrade.UpgradeFingerprint = JSON.stringify({ lvl: json.newRank });
|
|
||||||
} else {
|
|
||||||
const newLength = inventory.Upgrades.push({
|
|
||||||
ItemType: json.arcane.ItemType,
|
|
||||||
UpgradeFingerprint: JSON.stringify({ lvl: json.newRank })
|
|
||||||
});
|
|
||||||
upgradeId = inventory.Upgrades[newLength - 1]._id.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove RawUpgrades
|
|
||||||
addMods(inventory, [
|
|
||||||
{
|
|
||||||
ItemType: json.arcane.ItemType,
|
|
||||||
ItemCount: numConsumed * -1
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
res.json({ newLevel: json.newRank, numConsumed, upgradeId });
|
|
||||||
}
|
|
||||||
await inventory.save();
|
|
||||||
};
|
|
||||||
|
|
||||||
const arcaneLevelCounts = [0, 3, 6, 10, 15, 21];
|
|
||||||
|
|
||||||
interface IArcaneCommonRequest {
|
|
||||||
arcane: {
|
|
||||||
ItemType: string;
|
|
||||||
ItemId: IOid;
|
|
||||||
FromSKU: boolean;
|
|
||||||
UpgradeFingerprint: string;
|
|
||||||
PendingRerollFingerprint: string;
|
|
||||||
ItemCount: number;
|
|
||||||
LastAdded: IOid;
|
|
||||||
};
|
|
||||||
newRank: number;
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { colorToShard, combineColors, shardToColor } from "@/src/helpers/shardHelper";
|
|
||||||
|
|
||||||
export const archonFusionController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const request = JSON.parse(String(req.body)) as IArchonFusionRequest;
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
request.Consumed.forEach(x => {
|
|
||||||
x.ItemCount *= -1;
|
|
||||||
});
|
|
||||||
addMiscItems(inventory, request.Consumed);
|
|
||||||
const newArchons: IMiscItem[] = [];
|
|
||||||
switch (request.FusionType) {
|
|
||||||
case "AFT_ASCENT":
|
|
||||||
newArchons.push({
|
|
||||||
ItemType: request.Consumed[0].ItemType + "Mythic",
|
|
||||||
ItemCount: 1
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "AFT_COALESCENT":
|
|
||||||
newArchons.push({
|
|
||||||
ItemType:
|
|
||||||
colorToShard[
|
|
||||||
combineColors(
|
|
||||||
shardToColor[request.Consumed[0].ItemType],
|
|
||||||
shardToColor[request.Consumed[1].ItemType]
|
|
||||||
)
|
|
||||||
],
|
|
||||||
ItemCount: 1
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Error(`unknown archon fusion type: ${request.FusionType}`);
|
|
||||||
}
|
|
||||||
addMiscItems(inventory, newArchons);
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
NewArchons: newArchons
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IArchonFusionRequest {
|
|
||||||
Consumed: IMiscItem[];
|
|
||||||
FusionType: string;
|
|
||||||
StatResultType: "SRT_NEW_STAT"; // ???
|
|
||||||
}
|
|
@ -1,70 +1,22 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { upgradeMod } from "@/src/services/inventoryService";
|
||||||
|
import { IArtifactsRequest } from "@/src/types/requestTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { IInventoryClient, IUpgradeClient } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { addMods, getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { config } from "@/src/services/configService";
|
|
||||||
|
|
||||||
export const artifactsController: RequestHandler = async (req, res) => {
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
|
const artifactsController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const artifactsData = getJSONfromString<IArtifactsRequest>(String(req.body));
|
|
||||||
|
|
||||||
const { Upgrade, LevelDiff, Cost, FusionPointCost } = artifactsData;
|
try {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call
|
||||||
const inventory = await getInventory(accountId);
|
const artifactsData = getJSONfromString(req.body.toString()) as IArtifactsRequest;
|
||||||
const { Upgrades } = inventory;
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||||
const { ItemType, UpgradeFingerprint, ItemId } = Upgrade;
|
const upgradeModId = await upgradeMod(artifactsData, accountId);
|
||||||
|
res.send(upgradeModId);
|
||||||
const safeUpgradeFingerprint = UpgradeFingerprint || '{"lvl":0}';
|
} catch (err) {
|
||||||
const parsedUpgradeFingerprint = JSON.parse(safeUpgradeFingerprint) as { lvl: number };
|
console.error("Error parsing JSON data:", err);
|
||||||
parsedUpgradeFingerprint.lvl += LevelDiff;
|
|
||||||
const stringifiedUpgradeFingerprint = JSON.stringify(parsedUpgradeFingerprint);
|
|
||||||
|
|
||||||
let itemIndex = Upgrades.findIndex(upgrade => upgrade._id.equals(ItemId.$oid));
|
|
||||||
|
|
||||||
if (itemIndex !== -1) {
|
|
||||||
Upgrades[itemIndex].UpgradeFingerprint = stringifiedUpgradeFingerprint;
|
|
||||||
inventory.markModified(`Upgrades.${itemIndex}.UpgradeFingerprint`);
|
|
||||||
} else {
|
|
||||||
itemIndex =
|
|
||||||
Upgrades.push({
|
|
||||||
UpgradeFingerprint: stringifiedUpgradeFingerprint,
|
|
||||||
ItemType
|
|
||||||
}) - 1;
|
|
||||||
|
|
||||||
addMods(inventory, [{ ItemType, ItemCount: -1 }]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.infiniteCredits) {
|
|
||||||
inventory.RegularCredits -= Cost;
|
|
||||||
}
|
|
||||||
if (!config.infiniteEndo) {
|
|
||||||
inventory.FusionPoints -= FusionPointCost;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (artifactsData.LegendaryFusion) {
|
|
||||||
addMods(inventory, [
|
|
||||||
{
|
|
||||||
ItemType: "/Lotus/Upgrades/Mods/Fusers/LegendaryModFuser",
|
|
||||||
ItemCount: -1
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const changedInventory = await inventory.save();
|
|
||||||
const itemId = changedInventory.toJSON<IInventoryClient>().Upgrades[itemIndex].ItemId.$oid;
|
|
||||||
|
|
||||||
if (!itemId) {
|
|
||||||
throw new Error("Item Id not found in upgradeMod");
|
|
||||||
}
|
|
||||||
|
|
||||||
res.send(itemId);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IArtifactsRequest {
|
export { artifactsController };
|
||||||
Upgrade: IUpgradeClient;
|
|
||||||
LevelDiff: number;
|
|
||||||
Cost: number;
|
|
||||||
FusionPointCost: number;
|
|
||||||
LegendaryFusion?: boolean;
|
|
||||||
}
|
|
||||||
|
@ -1,90 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { getDojoClient, getGuildForRequest } from "@/src/services/guildService";
|
|
||||||
import { logger } from "@/src/utils/logger";
|
|
||||||
import { IDojoComponentDatabase } from "@/src/types/guildTypes";
|
|
||||||
import { Types } from "mongoose";
|
|
||||||
|
|
||||||
export const changeDojoRootController: RequestHandler = async (req, res) => {
|
|
||||||
const guild = await getGuildForRequest(req);
|
|
||||||
// At this point, we know that a member of the guild is making this request. Assuming they are allowed to change the root.
|
|
||||||
|
|
||||||
const idToNode: Record<string, INode> = {};
|
|
||||||
guild.DojoComponents!.forEach(x => {
|
|
||||||
idToNode[x._id.toString()] = {
|
|
||||||
component: x,
|
|
||||||
parent: undefined,
|
|
||||||
children: []
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
let oldRoot: INode | undefined;
|
|
||||||
guild.DojoComponents!.forEach(x => {
|
|
||||||
const node = idToNode[x._id.toString()];
|
|
||||||
if (x.pi) {
|
|
||||||
idToNode[x.pi.toString()].children.push(node);
|
|
||||||
node.parent = idToNode[x.pi.toString()];
|
|
||||||
} else {
|
|
||||||
oldRoot = node;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
logger.debug("Old tree:\n" + treeToString(oldRoot!));
|
|
||||||
|
|
||||||
const newRoot = idToNode[req.query.newRoot as string];
|
|
||||||
recursivelyTurnParentsIntoChildren(newRoot);
|
|
||||||
newRoot.component.pi = undefined;
|
|
||||||
newRoot.component.op = undefined;
|
|
||||||
newRoot.component.pp = undefined;
|
|
||||||
newRoot.parent = undefined;
|
|
||||||
|
|
||||||
// Don't even ask me why this is needed because I don't know either
|
|
||||||
const stack: INode[] = [newRoot];
|
|
||||||
let i = 0;
|
|
||||||
const idMap: Record<string, Types.ObjectId> = {};
|
|
||||||
while (stack.length != 0) {
|
|
||||||
const top = stack.shift()!;
|
|
||||||
idMap[top.component._id.toString()] = new Types.ObjectId(
|
|
||||||
(++i).toString(16).padStart(8, "0") + top.component._id.toString().substr(8)
|
|
||||||
);
|
|
||||||
top.children.forEach(x => stack.push(x));
|
|
||||||
}
|
|
||||||
guild.DojoComponents!.forEach(x => {
|
|
||||||
x._id = idMap[x._id.toString()];
|
|
||||||
if (x.pi) {
|
|
||||||
x.pi = idMap[x.pi.toString()];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
logger.debug("New tree:\n" + treeToString(newRoot));
|
|
||||||
|
|
||||||
await guild.save();
|
|
||||||
|
|
||||||
res.json(getDojoClient(guild, 0));
|
|
||||||
};
|
|
||||||
|
|
||||||
interface INode {
|
|
||||||
component: IDojoComponentDatabase;
|
|
||||||
parent: INode | undefined;
|
|
||||||
children: INode[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const treeToString = (root: INode, depth: number = 0): string => {
|
|
||||||
let str = " ".repeat(depth * 4) + root.component.pf + " (" + root.component._id.toString() + ")\n";
|
|
||||||
root.children.forEach(x => {
|
|
||||||
str += treeToString(x, depth + 1);
|
|
||||||
});
|
|
||||||
return str;
|
|
||||||
};
|
|
||||||
|
|
||||||
const recursivelyTurnParentsIntoChildren = (node: INode): void => {
|
|
||||||
if (node.parent!.parent) {
|
|
||||||
recursivelyTurnParentsIntoChildren(node.parent!);
|
|
||||||
}
|
|
||||||
|
|
||||||
node.parent!.component.pi = node.component._id;
|
|
||||||
node.parent!.component.op = node.component.pp;
|
|
||||||
node.parent!.component.pp = node.component.op;
|
|
||||||
|
|
||||||
node.parent!.parent = node;
|
|
||||||
node.parent!.children.splice(node.parent!.children.indexOf(node), 1);
|
|
||||||
node.children.push(node.parent!);
|
|
||||||
};
|
|
@ -13,34 +13,43 @@ export interface IClaimCompletedRecipeRequest {
|
|||||||
RecipeIds: IOid[];
|
RecipeIds: IOid[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const claimCompletedRecipeController: RequestHandler = async (req, res) => {
|
export const claimCompletedRecipeController: RequestHandler = async (req, res) => {
|
||||||
const claimCompletedRecipeRequest = getJSONfromString<IClaimCompletedRecipeRequest>(String(req.body));
|
const claimCompletedRecipeRequest = getJSONfromString(String(req.body)) as IClaimCompletedRecipeRequest;
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
if (!accountId) throw new Error("no account id");
|
if (!accountId) throw new Error("no account id");
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
const pendingRecipe = inventory.PendingRecipes.id(claimCompletedRecipeRequest.RecipeIds[0].$oid);
|
const pendingRecipe = inventory.PendingRecipes.find(
|
||||||
|
recipe => recipe._id?.toString() === claimCompletedRecipeRequest.RecipeIds[0].$id
|
||||||
|
);
|
||||||
if (!pendingRecipe) {
|
if (!pendingRecipe) {
|
||||||
throw new Error(`no pending recipe found with id ${claimCompletedRecipeRequest.RecipeIds[0].$oid}`);
|
logger.error(`no pending recipe found with id ${claimCompletedRecipeRequest.RecipeIds[0].$id}`);
|
||||||
|
throw new Error(`no pending recipe found with id ${claimCompletedRecipeRequest.RecipeIds[0].$id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
//check recipe is indeed ready to be completed
|
//check recipe is indeed ready to be completed
|
||||||
// if (pendingRecipe.CompletionDate > new Date()) {
|
// if (pendingRecipe.CompletionDate > new Date()) {
|
||||||
|
// logger.error(`recipe ${pendingRecipe._id} is not ready to be completed`);
|
||||||
// throw new Error(`recipe ${pendingRecipe._id} is not ready to be completed`);
|
// throw new Error(`recipe ${pendingRecipe._id} is not ready to be completed`);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
inventory.PendingRecipes.pull(pendingRecipe._id);
|
inventory.PendingRecipes.pull(pendingRecipe._id);
|
||||||
|
await inventory.save();
|
||||||
|
|
||||||
const recipe = getRecipe(pendingRecipe.ItemType);
|
const recipe = getRecipe(pendingRecipe.ItemType);
|
||||||
if (!recipe) {
|
if (!recipe) {
|
||||||
throw new Error(`no completed item found for recipe ${pendingRecipe._id.toString()}`);
|
logger.error(`no completed item found for recipe ${pendingRecipe._id}`);
|
||||||
|
throw new Error(`no completed item found for recipe ${pendingRecipe._id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.query.cancel) {
|
if (req.query.cancel) {
|
||||||
const currencyChanges = updateCurrency(inventory, recipe.buildPrice * -1, false);
|
const currencyChanges = await updateCurrency(recipe.buildPrice * -1, false, accountId);
|
||||||
addMiscItems(inventory, recipe.ingredients);
|
|
||||||
|
|
||||||
|
const inventory = await getInventory(accountId);
|
||||||
|
addMiscItems(inventory, recipe.ingredients);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
// Not a bug: In the specific case of cancelling a recipe, InventoryChanges are expected to be the root.
|
// Not a bug: In the specific case of cancelling a recipe, InventoryChanges are expected to be the root.
|
||||||
res.json({
|
res.json({
|
||||||
...currencyChanges,
|
...currencyChanges,
|
||||||
@ -48,28 +57,6 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
logger.debug("Claiming Recipe", { recipe, pendingRecipe });
|
logger.debug("Claiming Recipe", { recipe, pendingRecipe });
|
||||||
|
|
||||||
if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") {
|
|
||||||
inventory.PendingSpectreLoadouts ??= [];
|
|
||||||
inventory.SpectreLoadouts ??= [];
|
|
||||||
|
|
||||||
const pendingLoadoutIndex = inventory.PendingSpectreLoadouts.findIndex(
|
|
||||||
x => x.ItemType == recipe.resultType
|
|
||||||
);
|
|
||||||
if (pendingLoadoutIndex != -1) {
|
|
||||||
const loadoutIndex = inventory.SpectreLoadouts.findIndex(x => x.ItemType == recipe.resultType);
|
|
||||||
if (loadoutIndex != -1) {
|
|
||||||
inventory.SpectreLoadouts.splice(loadoutIndex, 1);
|
|
||||||
}
|
|
||||||
logger.debug(
|
|
||||||
"moving spectre loadout from pending to active",
|
|
||||||
inventory.toJSON().PendingSpectreLoadouts![pendingLoadoutIndex]
|
|
||||||
);
|
|
||||||
inventory.SpectreLoadouts.push(inventory.PendingSpectreLoadouts[pendingLoadoutIndex]);
|
|
||||||
inventory.PendingSpectreLoadouts.splice(pendingLoadoutIndex, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let InventoryChanges = {};
|
let InventoryChanges = {};
|
||||||
if (recipe.consumeOnUse) {
|
if (recipe.consumeOnUse) {
|
||||||
const recipeChanges = [
|
const recipeChanges = [
|
||||||
@ -81,19 +68,21 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
|
|||||||
|
|
||||||
InventoryChanges = { ...InventoryChanges, Recipes: recipeChanges };
|
InventoryChanges = { ...InventoryChanges, Recipes: recipeChanges };
|
||||||
|
|
||||||
|
const inventory = await getInventory(accountId);
|
||||||
addRecipes(inventory, recipeChanges);
|
addRecipes(inventory, recipeChanges);
|
||||||
|
await inventory.save();
|
||||||
}
|
}
|
||||||
if (req.query.rush) {
|
if (req.query.rush) {
|
||||||
InventoryChanges = {
|
InventoryChanges = {
|
||||||
...InventoryChanges,
|
...InventoryChanges,
|
||||||
...updateCurrency(inventory, recipe.skipBuildTimePrice, true)
|
...(await updateCurrency(recipe.skipBuildTimePrice, true, accountId))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
InventoryChanges = {
|
res.json({
|
||||||
|
InventoryChanges: {
|
||||||
...InventoryChanges,
|
...InventoryChanges,
|
||||||
...(await addItem(inventory, recipe.resultType, recipe.num)).InventoryChanges
|
...(await addItem(accountId, recipe.resultType, recipe.num)).InventoryChanges
|
||||||
};
|
}
|
||||||
await inventory.save();
|
});
|
||||||
res.json({ InventoryChanges });
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const clearDialogueHistoryController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const request = JSON.parse(String(req.body)) as IClearDialogueRequest;
|
|
||||||
if (inventory.DialogueHistory && inventory.DialogueHistory.Dialogues) {
|
|
||||||
for (const dialogueName of request.Dialogues) {
|
|
||||||
const index = inventory.DialogueHistory.Dialogues.findIndex(x => x.DialogueName == dialogueName);
|
|
||||||
if (index != -1) {
|
|
||||||
inventory.DialogueHistory.Dialogues.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await inventory.save();
|
|
||||||
res.end();
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IClearDialogueRequest {
|
|
||||||
Dialogues: string[];
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
|
||||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { IUnveiledRivenFingerprint, randomiseRivenStats } from "@/src/helpers/rivenFingerprintHelper";
|
|
||||||
import { getRandomElement, getRandomInt } from "@/src/services/rngService";
|
|
||||||
import { ExportUpgrades } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
export const completeRandomModChallengeController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const request = getJSONfromString<ICompleteRandomModChallengeRequest>(String(req.body));
|
|
||||||
let inventoryChanges: IInventoryChanges = {};
|
|
||||||
|
|
||||||
// Remove 20 plat or riven cipher
|
|
||||||
if ((req.query.p as string) == "1") {
|
|
||||||
inventoryChanges = { ...updateCurrency(inventory, 20, true) };
|
|
||||||
} else {
|
|
||||||
const miscItemChanges: IMiscItem[] = [
|
|
||||||
{
|
|
||||||
ItemType: "/Lotus/Types/Items/MiscItems/RivenIdentifier",
|
|
||||||
ItemCount: -1
|
|
||||||
}
|
|
||||||
];
|
|
||||||
addMiscItems(inventory, miscItemChanges);
|
|
||||||
inventoryChanges.MiscItems = miscItemChanges;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update riven fingerprint to a randomised unveiled state
|
|
||||||
const upgrade = inventory.Upgrades.id(request.ItemId)!;
|
|
||||||
const meta = ExportUpgrades[upgrade.ItemType];
|
|
||||||
const fingerprint: IUnveiledRivenFingerprint = {
|
|
||||||
compat: getRandomElement(meta.compatibleItems!),
|
|
||||||
lim: 0,
|
|
||||||
lvl: 0,
|
|
||||||
lvlReq: getRandomInt(8, 16),
|
|
||||||
pol: getRandomElement(["AP_ATTACK", "AP_DEFENSE", "AP_TACTIC"]),
|
|
||||||
buffs: [],
|
|
||||||
curses: []
|
|
||||||
};
|
|
||||||
randomiseRivenStats(meta, fingerprint);
|
|
||||||
upgrade.UpgradeFingerprint = JSON.stringify(fingerprint);
|
|
||||||
|
|
||||||
await inventory.save();
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: inventoryChanges,
|
|
||||||
Fingerprint: upgrade.UpgradeFingerprint
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ICompleteRandomModChallengeRequest {
|
|
||||||
ItemId: string;
|
|
||||||
}
|
|
@ -3,10 +3,12 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { Guild } from "@/src/models/guildModel";
|
import { Guild } from "@/src/models/guildModel";
|
||||||
|
import { ICreateGuildRequest } from "@/src/types/guildTypes";
|
||||||
|
|
||||||
export const createGuildController: RequestHandler = async (req, res) => {
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
|
const createGuildController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const payload = getJSONfromString<ICreateGuildRequest>(String(req.body));
|
const payload = getJSONfromString(String(req.body)) as ICreateGuildRequest;
|
||||||
|
|
||||||
// Create guild on database
|
// Create guild on database
|
||||||
const guild = new Guild({
|
const guild = new Guild({
|
||||||
@ -21,6 +23,7 @@ export const createGuildController: RequestHandler = async (req, res) => {
|
|||||||
inventory.GuildId = guild._id;
|
inventory.GuildId = guild._id;
|
||||||
|
|
||||||
// Give clan key (TODO: This should only be a blueprint)
|
// Give clan key (TODO: This should only be a blueprint)
|
||||||
|
inventory.LevelKeys ??= [];
|
||||||
inventory.LevelKeys.push({
|
inventory.LevelKeys.push({
|
||||||
ItemType: "/Lotus/Types/Keys/DojoKey",
|
ItemType: "/Lotus/Types/Keys/DojoKey",
|
||||||
ItemCount: 1
|
ItemCount: 1
|
||||||
@ -32,6 +35,4 @@ export const createGuildController: RequestHandler = async (req, res) => {
|
|||||||
res.json(guild);
|
res.json(guild);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ICreateGuildRequest {
|
export { createGuildController };
|
||||||
guildName: string;
|
|
||||||
}
|
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { config } from "@/src/services/configService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
|
|
||||||
export const creditsController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
|
|
||||||
const inventory = await getInventory(accountId, "RegularCredits TradesRemaining PremiumCreditsFree PremiumCredits");
|
|
||||||
|
|
||||||
const response = {
|
|
||||||
RegularCredits: inventory.RegularCredits,
|
|
||||||
TradesRemaining: inventory.TradesRemaining,
|
|
||||||
PremiumCreditsFree: inventory.PremiumCreditsFree,
|
|
||||||
PremiumCredits: inventory.PremiumCredits
|
|
||||||
};
|
|
||||||
|
|
||||||
if (config.infiniteCredits) {
|
|
||||||
response.RegularCredits = 999999999;
|
|
||||||
}
|
|
||||||
if (config.infinitePlatinum) {
|
|
||||||
response.PremiumCreditsFree = 999999999;
|
|
||||||
response.PremiumCredits = 999999999;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json(response);
|
|
||||||
};
|
|
@ -1,60 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { TEndlessXpCategory } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
|
|
||||||
export const endlessXpController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const payload = getJSONfromString<IEndlessXpRequest>(String(req.body));
|
|
||||||
|
|
||||||
inventory.EndlessXP ??= [];
|
|
||||||
const entry = inventory.EndlessXP.find(x => x.Category == payload.Category);
|
|
||||||
if (entry) {
|
|
||||||
entry.Choices = payload.Choices;
|
|
||||||
} else {
|
|
||||||
inventory.EndlessXP.push({
|
|
||||||
Category: payload.Category,
|
|
||||||
Choices: payload.Choices
|
|
||||||
});
|
|
||||||
}
|
|
||||||
await inventory.save();
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
NewProgress: {
|
|
||||||
Category: payload.Category,
|
|
||||||
Earn: 0,
|
|
||||||
Claim: 0,
|
|
||||||
BonusAvailable: {
|
|
||||||
$date: {
|
|
||||||
$numberLong: "9999999999999"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Expiry: {
|
|
||||||
$date: {
|
|
||||||
$numberLong: "9999999999999"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Choices: payload.Choices,
|
|
||||||
PendingRewards: [
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 190,
|
|
||||||
Rewards: [
|
|
||||||
{
|
|
||||||
StoreItem: "/Lotus/StoreItems/Upgrades/Mods/Aura/PlayerHealthAuraMod",
|
|
||||||
ItemCount: 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
// ...
|
|
||||||
]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IEndlessXpRequest {
|
|
||||||
Mode: string; // "r"
|
|
||||||
Category: TEndlessXpCategory;
|
|
||||||
Choices: string[];
|
|
||||||
}
|
|
@ -1,21 +1,18 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getRecipe, WeaponTypeInternal } from "@/src/services/itemDataService";
|
import { WeaponTypeInternal } from "@/src/services/itemDataService";
|
||||||
import { EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const evolveWeaponController: RequestHandler = async (req, res) => {
|
export const evolveWeaponController: 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 payload = getJSONfromString<IEvolveWeaponRequest>(String(req.body));
|
const payload = getJSONfromString(String(req.body)) as IEvolveWeaponRequest;
|
||||||
|
console.assert(payload.Action == "EWA_INSTALL");
|
||||||
|
|
||||||
const recipe = getRecipe(payload.Recipe)!;
|
// TODO: We should remove the Genesis item & its resources, but currently we don't know these "recipes".
|
||||||
if (payload.Action == "EWA_INSTALL") {
|
|
||||||
addMiscItems(
|
|
||||||
inventory,
|
|
||||||
recipe.ingredients.map(x => ({ ItemType: x.ItemType, ItemCount: x.ItemCount * -1 }))
|
|
||||||
);
|
|
||||||
|
|
||||||
const item = inventory[payload.Category].find(item => item._id.toString() == (req.query.ItemId as string))!;
|
const item = inventory[payload.Category].find(item => item._id.toString() == (req.query.ItemId as string))!;
|
||||||
item.Features ??= 0;
|
item.Features ??= 0;
|
||||||
@ -31,26 +28,13 @@ export const evolveWeaponController: RequestHandler = async (req, res) => {
|
|||||||
ItemType: payload.EvoType
|
ItemType: payload.EvoType
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (payload.Action == "EWA_UNINSTALL") {
|
|
||||||
addMiscItems(inventory, [
|
|
||||||
{
|
|
||||||
ItemType: recipe.resultType,
|
|
||||||
ItemCount: 1
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
const item = inventory[payload.Category].find(item => item._id.toString() == (req.query.ItemId as string))!;
|
|
||||||
item.Features! &= ~EquipmentFeatures.INCARNON_GENESIS;
|
|
||||||
} else {
|
|
||||||
throw new Error(`unexpected evolve weapon action: ${payload.Action}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.end();
|
res.end();
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IEvolveWeaponRequest {
|
interface IEvolveWeaponRequest {
|
||||||
Action: string;
|
Action: "EWA_INSTALL";
|
||||||
Category: WeaponTypeInternal;
|
Category: WeaponTypeInternal;
|
||||||
Recipe: string; // e.g. "/Lotus/Types/Items/MiscItems/IncarnonAdapters/UnlockerBlueprints/DespairIncarnonBlueprint"
|
Recipe: string; // e.g. "/Lotus/Types/Items/MiscItems/IncarnonAdapters/UnlockerBlueprints/DespairIncarnonBlueprint"
|
||||||
UninstallRecipe: "";
|
UninstallRecipe: "";
|
||||||
|
@ -1,28 +1,31 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getSession } from "@/src/managers/sessionManager";
|
import { getSession } from "@/src/managers/sessionManager";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { IFindSessionRequest } from "@/src/types/session";
|
|
||||||
|
|
||||||
export const findSessionsController: RequestHandler = (_req, res) => {
|
//TODO: cleanup
|
||||||
const req = JSON.parse(String(_req.body)) as IFindSessionRequest;
|
const findSessionsController: RequestHandler = (_req, res) => {
|
||||||
logger.debug("FindSession Request ", req);
|
const reqBody = JSON.parse(String(_req.body));
|
||||||
|
logger.debug("FindSession Request ", { reqBody });
|
||||||
|
const req = JSON.parse(String(_req.body));
|
||||||
if (req.id != undefined) {
|
if (req.id != undefined) {
|
||||||
logger.debug("Found ID");
|
logger.debug("Found ID");
|
||||||
const session = getSession(req.id);
|
const session = getSession(req.id as string);
|
||||||
|
|
||||||
if (session.length) res.json({ queryId: req.queryId, Sessions: session });
|
if (session) res.json({ queryId: req.queryId, Sessions: session });
|
||||||
else res.json({});
|
else res.json({});
|
||||||
} else if (req.originalSessionId != undefined) {
|
} else if (req.originalSessionId != undefined) {
|
||||||
logger.debug("Found OriginalSessionID");
|
logger.debug("Found OriginalSessionID");
|
||||||
|
|
||||||
const session = getSession(req.originalSessionId);
|
const session = getSession(req.originalSessionId as string);
|
||||||
if (session.length) res.json({ queryId: req.queryId, Sessions: session });
|
if (session) res.json({ queryId: req.queryId, Sessions: session });
|
||||||
else res.json({});
|
else res.json({});
|
||||||
} else {
|
} else {
|
||||||
logger.debug("Found SessionRequest");
|
logger.debug("Found SessionRequest");
|
||||||
|
|
||||||
const session = getSession(req);
|
const session = getSession(String(_req.body));
|
||||||
if (session.length) res.json({ queryId: req.queryId, Sessions: session });
|
if (session) res.json({ queryId: req.queryId, Sessions: session });
|
||||||
else res.json({});
|
else res.json({});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { findSessionsController };
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper";
|
|
||||||
import { addMiscItems, getInventory, getStandingLimit, updateStandingLimit } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
import { ExportResources, ExportSyndicates } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
export const fishmongerController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const body = getJSONfromString<IFishmongerRequest>(String(req.body));
|
|
||||||
const miscItemChanges: IMiscItem[] = [];
|
|
||||||
let syndicateTag: string | undefined;
|
|
||||||
let gainedStanding = 0;
|
|
||||||
for (const fish of body.Fish) {
|
|
||||||
const fishData = ExportResources[fish.ItemType];
|
|
||||||
if (req.query.dissect == "1") {
|
|
||||||
for (const part of fishData.dissectionParts!) {
|
|
||||||
const partItem = miscItemChanges.find(x => x.ItemType == part.ItemType);
|
|
||||||
if (partItem) {
|
|
||||||
partItem.ItemCount += part.ItemCount * fish.ItemCount;
|
|
||||||
} else {
|
|
||||||
miscItemChanges.push({ ItemType: part.ItemType, ItemCount: part.ItemCount * fish.ItemCount });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
syndicateTag = fishData.syndicateTag!;
|
|
||||||
gainedStanding += fishData.standingBonus! * fish.ItemCount;
|
|
||||||
}
|
|
||||||
miscItemChanges.push({ ItemType: fish.ItemType, ItemCount: fish.ItemCount * -1 });
|
|
||||||
}
|
|
||||||
addMiscItems(inventory, miscItemChanges);
|
|
||||||
if (gainedStanding && syndicateTag) {
|
|
||||||
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();
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: {
|
|
||||||
MiscItems: miscItemChanges
|
|
||||||
},
|
|
||||||
SyndicateTag: syndicateTag,
|
|
||||||
StandingChange: gainedStanding
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IFishmongerRequest {
|
|
||||||
Fish: IMiscItem[];
|
|
||||||
}
|
|
@ -1,41 +1,19 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getInventory, addMiscItems, addEquipment } from "@/src/services/inventoryService";
|
import { getInventory, addMiscItems, addEquipment } from "@/src/services/inventoryService";
|
||||||
import { IMiscItem, TFocusPolarity, TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IMiscItem, TFocusPolarity } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { ExportFocusUpgrades } from "warframe-public-export-plus";
|
import { ExportFocusUpgrades } from "warframe-public-export-plus";
|
||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const focusController: RequestHandler = async (req, res) => {
|
export const focusController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
switch (req.query.op) {
|
switch (req.query.op) {
|
||||||
default:
|
default:
|
||||||
logger.error("Unhandled focus op type: " + String(req.query.op));
|
logger.error("Unhandled focus op type: " + req.query.op);
|
||||||
logger.debug(String(req.body));
|
logger.debug(req.body.toString());
|
||||||
res.end();
|
res.end();
|
||||||
break;
|
break;
|
||||||
case FocusOperation.InstallLens: {
|
|
||||||
const request = JSON.parse(String(req.body)) as ILensInstallRequest;
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
for (const item of inventory[request.Category]) {
|
|
||||||
if (item._id.toString() == request.WeaponId) {
|
|
||||||
item.FocusLens = request.LensType;
|
|
||||||
addMiscItems(inventory, [
|
|
||||||
{
|
|
||||||
ItemType: request.LensType,
|
|
||||||
ItemCount: -1
|
|
||||||
} satisfies IMiscItem
|
|
||||||
]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
weaponId: request.WeaponId,
|
|
||||||
lensType: request.LensType
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FocusOperation.UnlockWay: {
|
case FocusOperation.UnlockWay: {
|
||||||
const focusType = (JSON.parse(String(req.body)) as IWayRequest).FocusType;
|
const focusType = (JSON.parse(String(req.body)) as IWayRequest).FocusType;
|
||||||
const focusPolarity = focusTypeToPolarity(focusType);
|
const focusPolarity = focusTypeToPolarity(focusType);
|
||||||
@ -70,7 +48,7 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
cost += ExportFocusUpgrades[focusType].baseFocusPointCost;
|
cost += ExportFocusUpgrades[focusType].baseFocusPointCost;
|
||||||
inventory.FocusUpgrades.push({ ItemType: focusType, Level: 0 });
|
inventory.FocusUpgrades.push({ ItemType: focusType, Level: 0 });
|
||||||
}
|
}
|
||||||
inventory.FocusXP![focusPolarity] -= cost;
|
inventory.FocusXP[focusPolarity] -= cost;
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
FocusTypes: request.FocusTypes,
|
FocusTypes: request.FocusTypes,
|
||||||
@ -88,7 +66,7 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
const focusUpgradeDb = inventory.FocusUpgrades.find(entry => entry.ItemType == focusUpgrade.ItemType)!;
|
const focusUpgradeDb = inventory.FocusUpgrades.find(entry => entry.ItemType == focusUpgrade.ItemType)!;
|
||||||
focusUpgradeDb.Level = focusUpgrade.Level;
|
focusUpgradeDb.Level = focusUpgrade.Level;
|
||||||
}
|
}
|
||||||
inventory.FocusXP![focusPolarity] -= cost;
|
inventory.FocusXP[focusPolarity] -= cost;
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
FocusInfos: request.FocusInfos,
|
FocusInfos: request.FocusInfos,
|
||||||
@ -103,17 +81,15 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
"/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 result = await addEquipment("OperatorAmps", request.StartingWeaponType, accountId, parts);
|
||||||
const inventoryChanges = addEquipment(inventory, "OperatorAmps", request.StartingWeaponType, parts);
|
res.json(result);
|
||||||
await inventory.save();
|
|
||||||
res.json((inventoryChanges.OperatorAmps as IEquipmentClient[])[0]);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FocusOperation.UnbindUpgrade: {
|
case FocusOperation.UnbindUpgrade: {
|
||||||
const request = JSON.parse(String(req.body)) as IUnbindUpgradeRequest;
|
const request = JSON.parse(String(req.body)) as IUnbindUpgradeRequest;
|
||||||
const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
|
const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
inventory.FocusXP![focusPolarity] -= 750_000 * request.FocusTypes.length;
|
inventory.FocusXP[focusPolarity] -= 750_000 * request.FocusTypes.length;
|
||||||
addMiscItems(inventory, [
|
addMiscItems(inventory, [
|
||||||
{
|
{
|
||||||
ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantItem",
|
ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantItem",
|
||||||
@ -168,7 +144,6 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum FocusOperation {
|
enum FocusOperation {
|
||||||
InstallLens = "1",
|
|
||||||
UnlockWay = "2",
|
UnlockWay = "2",
|
||||||
UnlockUpgrade = "3",
|
UnlockUpgrade = "3",
|
||||||
LevelUpUpgrade = "4",
|
LevelUpUpgrade = "4",
|
||||||
@ -211,12 +186,6 @@ interface ISentTrainingAmplifierRequest {
|
|||||||
StartingWeaponType: string;
|
StartingWeaponType: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ILensInstallRequest {
|
|
||||||
LensType: string;
|
|
||||||
Category: TEquipmentKey;
|
|
||||||
WeaponId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Works for ways & upgrades
|
// Works for ways & upgrades
|
||||||
const focusTypeToPolarity = (type: string): TFocusPolarity => {
|
const focusTypeToPolarity = (type: string): TFocusPolarity => {
|
||||||
return ("AP_" + type.substr(1).split("/")[3].toUpperCase()) as TFocusPolarity;
|
return ("AP_" + type.substr(1).split("/")[3].toUpperCase()) as TFocusPolarity;
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { ExportResources } from "warframe-public-export-plus";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { addFusionTreasures, addMiscItems, getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { IFusionTreasure, IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
|
|
||||||
interface IFusionTreasureRequest {
|
|
||||||
oldTreasureName: string;
|
|
||||||
newTreasureName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const parseFusionTreasure = (name: string, count: number): IFusionTreasure => {
|
|
||||||
const arr = name.split("_");
|
|
||||||
return {
|
|
||||||
ItemType: arr[0],
|
|
||||||
Sockets: parseInt(arr[1], 16),
|
|
||||||
ItemCount: count
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fusionTreasuresController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const request = JSON.parse(String(req.body)) as IFusionTreasureRequest;
|
|
||||||
|
|
||||||
const oldTreasure = parseFusionTreasure(request.oldTreasureName, -1);
|
|
||||||
const newTreasure = parseFusionTreasure(request.newTreasureName, 1);
|
|
||||||
|
|
||||||
// Swap treasures
|
|
||||||
addFusionTreasures(inventory, [oldTreasure]);
|
|
||||||
addFusionTreasures(inventory, [newTreasure]);
|
|
||||||
|
|
||||||
// Remove consumed stars
|
|
||||||
const miscItemChanges: IMiscItem[] = [];
|
|
||||||
const filledSockets = newTreasure.Sockets & ~oldTreasure.Sockets;
|
|
||||||
for (let i = 0; filledSockets >> i; ++i) {
|
|
||||||
if ((filledSockets >> i) & 1) {
|
|
||||||
//console.log("Socket", i, "has been filled with", ExportResources[oldTreasure.ItemType].sockets![i]);
|
|
||||||
miscItemChanges.push({
|
|
||||||
ItemType: ExportResources[oldTreasure.ItemType].sockets![i],
|
|
||||||
ItemCount: -1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addMiscItems(inventory, miscItemChanges);
|
|
||||||
|
|
||||||
await inventory.save();
|
|
||||||
res.end();
|
|
||||||
};
|
|
@ -7,11 +7,11 @@ import { IGenericUpdate } from "@/src/types/genericUpdate";
|
|||||||
// This endpoint used to be /api/genericUpdate.php, but sometime around the Jade Shadows update, it was changed to /api/updateNodeIntros.php.
|
// This endpoint used to be /api/genericUpdate.php, but sometime around the Jade Shadows update, it was changed to /api/updateNodeIntros.php.
|
||||||
// SpaceNinjaServer supports both endpoints right now.
|
// SpaceNinjaServer supports both endpoints right now.
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
const genericUpdateController: RequestHandler = async (request, response) => {
|
const genericUpdateController: RequestHandler = async (request, response) => {
|
||||||
const accountId = await getAccountIdForRequest(request);
|
const accountId = await getAccountIdForRequest(request);
|
||||||
const update = getJSONfromString<IGenericUpdate>(String(request.body));
|
const update = getJSONfromString(String(request.body)) as IGenericUpdate;
|
||||||
await updateGeneric(update, accountId);
|
response.json(await updateGeneric(update, accountId));
|
||||||
response.json(update);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export { genericUpdateController };
|
export { genericUpdateController };
|
||||||
|
29
src/controllers/api/getCreditsController.ts
Normal file
29
src/controllers/api/getCreditsController.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { config } from "@/src/services/configService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
|
export const getCreditsController: RequestHandler = async (req, res) => {
|
||||||
|
let accountId;
|
||||||
|
try {
|
||||||
|
accountId = await getAccountIdForRequest(req);
|
||||||
|
} catch (e) {
|
||||||
|
res.status(400).send("Log-in expired");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.infiniteResources) {
|
||||||
|
res.json({
|
||||||
|
RegularCredits: 999999999,
|
||||||
|
PremiumCredits: 999999999
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inventory = await getInventory(accountId);
|
||||||
|
res.json({
|
||||||
|
RegularCredits: inventory.RegularCredits,
|
||||||
|
PremiumCredits: inventory.PremiumCredits
|
||||||
|
});
|
||||||
|
};
|
@ -1,6 +1,6 @@
|
|||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
|
|
||||||
const getFriendsController = (_request: Request, response: Response): void => {
|
const getFriendsController = (_request: Request, response: Response) => {
|
||||||
response.writeHead(200, {
|
response.writeHead(200, {
|
||||||
//Connection: "keep-alive",
|
//Connection: "keep-alive",
|
||||||
//"Content-Encoding": "gzip",
|
//"Content-Encoding": "gzip",
|
||||||
|
@ -1,72 +1,6 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
|
||||||
import { Guild } from "@/src/models/guildModel";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { toOid } from "@/src/helpers/inventoryHelpers";
|
|
||||||
|
|
||||||
const getGuildController: RequestHandler = async (req, res) => {
|
const getGuildController: RequestHandler = (_, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await Inventory.findOne({ accountOwnerId: accountId });
|
|
||||||
if (!inventory) {
|
|
||||||
res.status(400).json({ error: "inventory was undefined" });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (inventory.GuildId) {
|
|
||||||
const guild = await Guild.findOne({ _id: inventory.GuildId });
|
|
||||||
if (guild) {
|
|
||||||
res.json({
|
|
||||||
_id: toOid(guild._id),
|
|
||||||
Name: guild.Name,
|
|
||||||
Members: [
|
|
||||||
{
|
|
||||||
_id: { $oid: req.query.accountId },
|
|
||||||
Rank: 0,
|
|
||||||
Status: 0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
Ranks: [
|
|
||||||
{
|
|
||||||
Name: "/Lotus/Language/Game/Rank_Creator",
|
|
||||||
Permissions: 16351
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "/Lotus/Language/Game/Rank_Warlord",
|
|
||||||
Permissions: 14303
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "/Lotus/Language/Game/Rank_General",
|
|
||||||
Permissions: 4318
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "/Lotus/Language/Game/Rank_Officer",
|
|
||||||
Permissions: 4314
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "/Lotus/Language/Game/Rank_Leader",
|
|
||||||
Permissions: 4106
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "/Lotus/Language/Game/Rank_Sage",
|
|
||||||
Permissions: 4304
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "/Lotus/Language/Game/Rank_Soldier",
|
|
||||||
Permissions: 4098
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "/Lotus/Language/Game/Rank_Initiate",
|
|
||||||
Permissions: 4096
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "/Lotus/Language/Game/Rank_Utility",
|
|
||||||
Permissions: 4096
|
|
||||||
}
|
|
||||||
],
|
|
||||||
Tier: 1
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.json({});
|
res.json({});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { Guild } from "@/src/models/guildModel";
|
import { Guild } from "@/src/models/guildModel";
|
||||||
import { getDojoClient } from "@/src/services/guildService";
|
import { IDojoClient, IDojoComponentClient } from "@/src/types/guildTypes";
|
||||||
|
import { toOid, toMongoDate } from "@/src/helpers/inventoryHelpers";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const getGuildDojoController: RequestHandler = async (req, res) => {
|
export const getGuildDojoController: RequestHandler = async (req, res) => {
|
||||||
const guildId = req.query.guildId as string;
|
const guildId = req.query.guildId as string;
|
||||||
|
|
||||||
@ -25,5 +27,34 @@ export const getGuildDojoController: RequestHandler = async (req, res) => {
|
|||||||
await guild.save();
|
await guild.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json(getDojoClient(guild, 0));
|
const dojo: IDojoClient = {
|
||||||
|
_id: { $id: guildId },
|
||||||
|
Name: guild.Name,
|
||||||
|
Tier: 1,
|
||||||
|
FixedContributions: true,
|
||||||
|
DojoRevision: 1,
|
||||||
|
RevisionTime: Math.round(Date.now() / 1000),
|
||||||
|
Energy: 5,
|
||||||
|
Capacity: 100,
|
||||||
|
DojoRequestStatus: 0,
|
||||||
|
DojoComponents: []
|
||||||
|
};
|
||||||
|
guild.DojoComponents.forEach(dojoComponent => {
|
||||||
|
const clientComponent: IDojoComponentClient = {
|
||||||
|
id: toOid(dojoComponent._id),
|
||||||
|
pf: dojoComponent.pf,
|
||||||
|
ppf: dojoComponent.ppf,
|
||||||
|
DecoCapacity: 600
|
||||||
|
};
|
||||||
|
if (dojoComponent.pi) {
|
||||||
|
clientComponent.pi = toOid(dojoComponent.pi);
|
||||||
|
clientComponent.op = dojoComponent.op!;
|
||||||
|
clientComponent.pp = dojoComponent.pp!;
|
||||||
|
}
|
||||||
|
if (dojoComponent.CompletionTime) {
|
||||||
|
clientComponent.CompletionTime = toMongoDate(dojoComponent.CompletionTime);
|
||||||
|
}
|
||||||
|
dojo.DojoComponents.push(clientComponent);
|
||||||
|
});
|
||||||
|
res.json(dojo);
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const getNewRewardSeedController: RequestHandler = (_req, res) => {
|
const getNewRewardSeedController: RequestHandler = (_req, res) => {
|
||||||
res.json({ rewardSeed: generateRewardSeed() });
|
res.json({ rewardSeed: generateRewardSeed() });
|
||||||
};
|
};
|
||||||
|
|
||||||
export function generateRewardSeed(): number {
|
function generateRewardSeed(): number {
|
||||||
const min = -Number.MAX_SAFE_INTEGER;
|
const min = -Number.MAX_SAFE_INTEGER;
|
||||||
const max = Number.MAX_SAFE_INTEGER;
|
const max = Number.MAX_SAFE_INTEGER;
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export { getNewRewardSeedController };
|
||||||
|
@ -4,32 +4,31 @@ import allShipFeatures from "@/static/fixed_responses/allShipFeatures.json";
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
||||||
import { getShip } from "@/src/services/shipService";
|
import { getShip } from "@/src/services/shipService";
|
||||||
|
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
||||||
|
import { logger } from "@/src/utils/logger";
|
||||||
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 { IPersonalRooms } from "@/src/types/personalRoomsTypes";
|
|
||||||
import { getLoadout } from "@/src/services/loadoutService";
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
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 personalRooms = await getPersonalRooms(accountId);
|
||||||
const personalRooms = personalRoomsDb.toJSON<IPersonalRooms>();
|
|
||||||
const loadout = await getLoadout(accountId);
|
const loadout = await getLoadout(accountId);
|
||||||
const ship = await getShip(personalRoomsDb.activeShipId, "ShipAttachments SkinFlavourItem");
|
const ship = await getShip(personalRooms.activeShipId, "ShipInteriorColors ShipAttachments SkinFlavourItem");
|
||||||
|
|
||||||
const getShipResponse: IGetShipResponse = {
|
const getShipResponse: IGetShipResponse = {
|
||||||
ShipOwnerId: accountId,
|
ShipOwnerId: accountId,
|
||||||
LoadOutInventory: { LoadOutPresets: loadout.toJSON() },
|
LoadOutInventory: { LoadOutPresets: loadout.toJSON() },
|
||||||
Ship: {
|
Ship: {
|
||||||
...personalRooms.Ship,
|
...personalRooms.toJSON().Ship,
|
||||||
ShipId: toOid(personalRoomsDb.activeShipId),
|
ShipId: toOid(personalRooms.activeShipId),
|
||||||
ShipInterior: {
|
ShipInterior: {
|
||||||
Colors: personalRooms.ShipInteriorColors,
|
Colors: ship.ShipInteriorColors,
|
||||||
ShipAttachments: ship.ShipAttachments,
|
ShipAttachments: ship.ShipAttachments,
|
||||||
SkinFlavourItem: ship.SkinFlavourItem
|
SkinFlavourItem: ship.SkinFlavourItem
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Apartment: personalRooms.Apartment,
|
Apartment: personalRooms.Apartment
|
||||||
TailorShop: personalRooms.TailorShop
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (config.unlockAllShipFeatures) {
|
if (config.unlockAllShipFeatures) {
|
||||||
@ -38,3 +37,14 @@ export const getShipController: RequestHandler = async (req, res) => {
|
|||||||
|
|
||||||
res.json(getShipResponse);
|
res.json(getShipResponse);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getLoadout = async (accountId: string) => {
|
||||||
|
const loadout = await Loadout.findOne({ loadoutOwnerId: accountId });
|
||||||
|
|
||||||
|
if (!loadout) {
|
||||||
|
logger.error(`loadout not found for account ${accountId}`);
|
||||||
|
throw new Error("loadout not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadout;
|
||||||
|
};
|
||||||
|
@ -1,14 +1,23 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getVendorManifestByTypeName } from "@/src/services/serversideVendorsService";
|
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
|
||||||
|
import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSalesmanManifest.json";
|
||||||
|
import ZarimanCommisionsManifestArchimedean from "@/static/fixed_responses/getVendorInfo/ZarimanCommisionsManifestArchimedean.json";
|
||||||
|
|
||||||
export const getVendorInfoController: RequestHandler = (req, res) => {
|
export const getVendorInfoController: RequestHandler = (req, res) => {
|
||||||
if (typeof req.query.vendor == "string") {
|
switch (req.query.vendor as string) {
|
||||||
const manifest = getVendorManifestByTypeName(req.query.vendor);
|
case "/Lotus/Types/Game/VendorManifests/Zariman/ArchimedeanVendorManifest":
|
||||||
if (!manifest) {
|
res.json(ArchimedeanVendorManifest);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "/Lotus/Types/Game/VendorManifests/Ostron/MaskSalesmanManifest":
|
||||||
|
res.json(MaskSalesmanManifest);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "/Lotus/Types/Game/VendorManifests/Zariman/ZarimanCommisionsManifestArchimedean":
|
||||||
|
res.json(ZarimanCommisionsManifestArchimedean);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
throw new Error(`Unknown vendor: ${req.query.vendor}`);
|
throw new Error(`Unknown vendor: ${req.query.vendor}`);
|
||||||
}
|
}
|
||||||
res.json(manifest);
|
|
||||||
} else {
|
|
||||||
res.status(400).end();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { crackRelic } from "@/src/helpers/relicHelper";
|
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { IVoidTearParticipantInfo } from "@/src/types/requestTypes";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const getVoidProjectionRewardsController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const data = getJSONfromString<IVoidProjectionRewardRequest>(String(req.body));
|
|
||||||
|
|
||||||
if (data.ParticipantInfo.QualifiesForReward && !data.ParticipantInfo.HaveRewardResponse) {
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
await crackRelic(inventory, data.ParticipantInfo);
|
|
||||||
await inventory.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
const response: IVoidProjectionRewardResponse = {
|
|
||||||
CurrentWave: data.CurrentWave,
|
|
||||||
ParticipantInfo: data.ParticipantInfo,
|
|
||||||
DifficultyTier: data.DifficultyTier
|
|
||||||
};
|
|
||||||
res.json(response);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IVoidProjectionRewardRequest {
|
|
||||||
CurrentWave: number;
|
|
||||||
ParticipantInfo: IVoidTearParticipantInfo;
|
|
||||||
VoidTier: string;
|
|
||||||
DifficultyTier: number;
|
|
||||||
VoidProjectionRemovalHash: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IVoidProjectionRewardResponse {
|
|
||||||
CurrentWave: number;
|
|
||||||
ParticipantInfo: IVoidTearParticipantInfo;
|
|
||||||
DifficultyTier: number;
|
|
||||||
}
|
|
@ -24,19 +24,23 @@ interface IGildWeaponRequest {
|
|||||||
|
|
||||||
// In export there no recipes for gild action, so reputation and ressources only consumed visually
|
// In export there no recipes for gild action, so reputation and ressources only consumed visually
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
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: IGildWeaponRequest = getJSONfromString(String(req.body));
|
||||||
data.ItemId = String(req.query.ItemId);
|
data.ItemId = String(req.query.ItemId);
|
||||||
if (!modularWeaponCategory.includes(req.query.Category as WeaponTypeInternal | "Hoverboards")) {
|
if (!modularWeaponCategory.includes(req.query.Category as WeaponTypeInternal | "Hoverboards")) {
|
||||||
throw new Error(`Unknown modular weapon Category: ${String(req.query.Category)}`);
|
throw new Error(`Unknown modular weapon Category: ${req.query.Category}`);
|
||||||
}
|
}
|
||||||
data.Category = req.query.Category as WeaponTypeInternal | "Hoverboards";
|
data.Category = req.query.Category as WeaponTypeInternal | "Hoverboards";
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
|
if (!inventory[data.Category]) {
|
||||||
|
throw new Error(`Category ${req.query.Category} not found in inventory`);
|
||||||
|
}
|
||||||
const weaponIndex = inventory[data.Category].findIndex(x => String(x._id) === data.ItemId);
|
const weaponIndex = inventory[data.Category].findIndex(x => String(x._id) === data.ItemId);
|
||||||
if (weaponIndex === -1) {
|
if (weaponIndex === -1) {
|
||||||
throw new Error(`Weapon with ${data.ItemId} not found in category ${String(req.query.Category)}`);
|
throw new Error(`Weapon with ${data.ItemId} not found in category ${req.query.Category}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const weapon = inventory[data.Category][weaponIndex];
|
const weapon = inventory[data.Category][weaponIndex];
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { parseString } from "@/src/helpers/general";
|
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { IGroup } from "@/src/types/loginTypes";
|
|
||||||
import { giveKeyChainItem } from "@/src/services/questService";
|
|
||||||
|
|
||||||
export const giveKeyChainTriggeredItemsController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = parseString(req.query.accountId);
|
|
||||||
const keyChainInfo = getJSONfromString<IKeyChainRequest>((req.body as string).toString());
|
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const inventoryChanges = await giveKeyChainItem(inventory, keyChainInfo);
|
|
||||||
await inventory.save();
|
|
||||||
|
|
||||||
res.send(inventoryChanges);
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface IKeyChainRequest {
|
|
||||||
KeyChain: string;
|
|
||||||
ChainStage: number;
|
|
||||||
Groups?: IGroup[];
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
import { IKeyChainRequest } from "@/src/controllers/api/giveKeyChainTriggeredItemsController";
|
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { giveKeyChainMessage } from "@/src/services/questService";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const giveKeyChainTriggeredMessageController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const keyChainInfo = JSON.parse((req.body as Buffer).toString()) as IKeyChainRequest;
|
|
||||||
|
|
||||||
const inventory = await getInventory(accountId, "QuestKeys");
|
|
||||||
await giveKeyChainMessage(inventory, accountId, keyChainInfo);
|
|
||||||
await inventory.save();
|
|
||||||
|
|
||||||
res.send(1);
|
|
||||||
};
|
|
@ -1,45 +0,0 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { addItem, getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { IOid } from "@/src/types/commonTypes";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const giveQuestKeyRewardController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const rewardRequest = getJSONfromString<IQuestKeyRewardRequest>((req.body as Buffer).toString());
|
|
||||||
|
|
||||||
if (Array.isArray(rewardRequest.reward)) {
|
|
||||||
throw new Error("Multiple rewards not expected");
|
|
||||||
}
|
|
||||||
|
|
||||||
const reward = rewardRequest.reward;
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const inventoryChanges = await addItem(inventory, reward.ItemType, reward.Amount);
|
|
||||||
await inventory.save();
|
|
||||||
res.json(inventoryChanges.InventoryChanges);
|
|
||||||
//TODO: consider whishlist changes
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface IQuestKeyRewardRequest {
|
|
||||||
reward: IQuestKeyReward;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IQuestKeyReward {
|
|
||||||
RewardType: string;
|
|
||||||
CouponType: string;
|
|
||||||
Icon: string;
|
|
||||||
ItemType: string;
|
|
||||||
StoreItemType: string;
|
|
||||||
ProductCategory: string;
|
|
||||||
Amount: number;
|
|
||||||
ScalingMultiplier: number;
|
|
||||||
Durability: string;
|
|
||||||
DisplayName: string;
|
|
||||||
Duration: number;
|
|
||||||
CouponSku: number;
|
|
||||||
Syndicate: string;
|
|
||||||
Milestones: any[];
|
|
||||||
ChooseSetIndex: number;
|
|
||||||
NewSystemReward: boolean;
|
|
||||||
_id: IOid;
|
|
||||||
}
|
|
@ -1,96 +1,14 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { InventoryDocumentProps } from "@/src/models/inventoryModels/inventoryModel";
|
|
||||||
import {
|
|
||||||
addEquipment,
|
|
||||||
addItem,
|
|
||||||
combineInventoryChanges,
|
|
||||||
getInventory,
|
|
||||||
updateSlots
|
|
||||||
} from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IInventoryClient, IInventoryDatabase, InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { HydratedDocument } from "mongoose";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
|
||||||
type TPartialStartingGear = Pick<IInventoryClient, "LongGuns" | "Suits" | "Pistols" | "Melee">;
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const giveStartingGearController: RequestHandler = async (req, res) => {
|
export const giveStartingGearController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const startingGear = getJSONfromString<TPartialStartingGear>(String(req.body));
|
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
|
|
||||||
const inventoryChanges = await addStartingGear(inventory, startingGear);
|
|
||||||
await inventory.save();
|
|
||||||
|
|
||||||
res.send(inventoryChanges);
|
|
||||||
};
|
|
||||||
|
|
||||||
//TODO: RawUpgrades might need to return a LastAdded
|
|
||||||
const awakeningRewards = [
|
|
||||||
"/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem1",
|
|
||||||
"/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem2",
|
|
||||||
"/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem3",
|
|
||||||
"/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem4",
|
|
||||||
"/Lotus/Types/Restoratives/LisetAutoHack",
|
|
||||||
"/Lotus/Upgrades/Mods/Warframe/AvatarShieldMaxMod"
|
|
||||||
];
|
|
||||||
|
|
||||||
export const addStartingGear = async (
|
|
||||||
inventory: HydratedDocument<IInventoryDatabase, InventoryDocumentProps>,
|
|
||||||
startingGear: TPartialStartingGear | undefined = undefined
|
|
||||||
): Promise<IInventoryChanges> => {
|
|
||||||
const { LongGuns, Pistols, Suits, Melee } = startingGear || {
|
|
||||||
LongGuns: [{ ItemType: "/Lotus/Weapons/Tenno/Rifle/Rifle" }],
|
|
||||||
Pistols: [{ ItemType: "/Lotus/Weapons/Tenno/Pistol/Pistol" }],
|
|
||||||
Suits: [{ ItemType: "/Lotus/Powersuits/Excalibur/Excalibur" }],
|
|
||||||
Melee: [{ ItemType: "/Lotus/Weapons/Tenno/Melee/LongSword/LongSword" }]
|
|
||||||
};
|
|
||||||
|
|
||||||
//TODO: properly merge weapon bin changes it is currently static here
|
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
|
||||||
addEquipment(inventory, "LongGuns", LongGuns[0].ItemType, undefined, inventoryChanges);
|
|
||||||
addEquipment(inventory, "Pistols", Pistols[0].ItemType, undefined, inventoryChanges);
|
|
||||||
addEquipment(inventory, "Melee", Melee[0].ItemType, undefined, inventoryChanges);
|
|
||||||
addEquipment(inventory, "Suits", Suits[0].ItemType, undefined, inventoryChanges, { Configs: Suits[0].Configs });
|
|
||||||
addEquipment(
|
|
||||||
inventory,
|
|
||||||
"DataKnives",
|
|
||||||
"/Lotus/Weapons/Tenno/HackingDevices/TnHackingDevice/TnHackingDeviceWeapon",
|
|
||||||
undefined,
|
|
||||||
inventoryChanges,
|
|
||||||
{ XP: 450_000 }
|
|
||||||
);
|
|
||||||
addEquipment(
|
|
||||||
inventory,
|
|
||||||
"Scoops",
|
|
||||||
"/Lotus/Weapons/Tenno/Speedball/SpeedballWeaponTest",
|
|
||||||
undefined,
|
|
||||||
inventoryChanges
|
|
||||||
);
|
|
||||||
|
|
||||||
updateSlots(inventory, InventorySlot.SUITS, 0, 1);
|
|
||||||
updateSlots(inventory, InventorySlot.WEAPONS, 0, 3);
|
|
||||||
inventoryChanges.SuitBin = { count: 1, platinum: 0, Slots: -1 };
|
|
||||||
inventoryChanges.WeaponBin = { count: 3, platinum: 0, Slots: -3 };
|
|
||||||
|
|
||||||
await addItem(inventory, "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain");
|
|
||||||
inventory.ActiveQuest = "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain";
|
|
||||||
|
|
||||||
inventory.PremiumCredits = 50;
|
|
||||||
inventory.PremiumCreditsFree = 50;
|
|
||||||
inventoryChanges.PremiumCredits = 50;
|
|
||||||
inventoryChanges.PremiumCreditsFree = 50;
|
|
||||||
inventory.RegularCredits = 3000;
|
|
||||||
inventoryChanges.RegularCredits = 3000;
|
|
||||||
|
|
||||||
for (const item of awakeningRewards) {
|
|
||||||
const inventoryDelta = await addItem(inventory, item);
|
|
||||||
combineInventoryChanges(inventoryChanges, inventoryDelta.InventoryChanges);
|
|
||||||
}
|
|
||||||
|
|
||||||
inventory.PlayedParkourTutorial = true;
|
|
||||||
inventory.ReceivedStartingGear = true;
|
inventory.ReceivedStartingGear = true;
|
||||||
|
console.log(req.query);
|
||||||
return inventoryChanges;
|
await inventory.save();
|
||||||
|
res.status(200);
|
||||||
};
|
};
|
||||||
|
@ -1,127 +1,5 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getGuildForRequestEx } from "@/src/services/guildService";
|
|
||||||
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { addMiscItems, addRecipes, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
|
||||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
|
||||||
|
|
||||||
export const guildTechController: RequestHandler = async (req, res) => {
|
export const guildTechController: RequestHandler = (_req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
res.status(500).end(); // This is what I got for a fresh clan.
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const guild = await getGuildForRequestEx(req, inventory);
|
|
||||||
const data = JSON.parse(String(req.body)) as TGuildTechRequest;
|
|
||||||
const action = data.Action.split(",")[0];
|
|
||||||
if (action == "Sync") {
|
|
||||||
res.json({
|
|
||||||
TechProjects: guild.toJSON().TechProjects
|
|
||||||
});
|
|
||||||
} else if (action == "Start") {
|
|
||||||
const recipe = ExportDojoRecipes.research[data.RecipeType!];
|
|
||||||
guild.TechProjects ??= [];
|
|
||||||
if (!guild.TechProjects.find(x => x.ItemType == data.RecipeType)) {
|
|
||||||
guild.TechProjects.push({
|
|
||||||
ItemType: data.RecipeType!,
|
|
||||||
ReqCredits: scaleRequiredCount(recipe.price),
|
|
||||||
ReqItems: recipe.ingredients.map(x => ({
|
|
||||||
ItemType: x.ItemType,
|
|
||||||
ItemCount: scaleRequiredCount(x.ItemCount)
|
|
||||||
})),
|
|
||||||
State: 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
await guild.save();
|
|
||||||
res.end();
|
|
||||||
} else if (action == "Contribute") {
|
|
||||||
const contributions = data as IGuildTechContributeFields;
|
|
||||||
const techProject = guild.TechProjects!.find(x => x.ItemType == contributions.RecipeType)!;
|
|
||||||
if (contributions.RegularCredits > techProject.ReqCredits) {
|
|
||||||
contributions.RegularCredits = techProject.ReqCredits;
|
|
||||||
}
|
|
||||||
techProject.ReqCredits -= contributions.RegularCredits;
|
|
||||||
const miscItemChanges = [];
|
|
||||||
for (const miscItem of contributions.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);
|
|
||||||
const inventoryChanges: IInventoryChanges = {
|
|
||||||
...updateCurrency(inventory, contributions.RegularCredits, false),
|
|
||||||
MiscItems: miscItemChanges
|
|
||||||
};
|
|
||||||
|
|
||||||
if (techProject.ReqCredits == 0 && !techProject.ReqItems.find(x => x.ItemCount > 0)) {
|
|
||||||
// This research is now fully funded.
|
|
||||||
techProject.State = 1;
|
|
||||||
const recipe = ExportDojoRecipes.research[data.RecipeType!];
|
|
||||||
techProject.CompletionDate = new Date(new Date().getTime() + recipe.time * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
await guild.save();
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: inventoryChanges
|
|
||||||
});
|
|
||||||
} else if (action == "Buy") {
|
|
||||||
const purchase = data as IGuildTechBuyFields;
|
|
||||||
const quantity = parseInt(data.Action.split(",")[1]);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const recipeChanges = [
|
|
||||||
{
|
|
||||||
ItemType: purchase.RecipeType,
|
|
||||||
ItemCount: quantity
|
|
||||||
}
|
|
||||||
];
|
|
||||||
addRecipes(inventory, recipeChanges);
|
|
||||||
const currencyChanges = updateCurrency(
|
|
||||||
inventory,
|
|
||||||
ExportDojoRecipes.research[purchase.RecipeType].replicatePrice,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
await inventory.save();
|
|
||||||
// Not a mistake: This response uses `inventoryChanges` instead of `InventoryChanges`.
|
|
||||||
res.json({
|
|
||||||
inventoryChanges: {
|
|
||||||
...currencyChanges,
|
|
||||||
Recipes: recipeChanges
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
throw new Error(`unknown guildTech action: ${data.Action}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
type TGuildTechRequest = {
|
|
||||||
Action: string;
|
|
||||||
} & Partial<IGuildTechStartFields> &
|
|
||||||
Partial<IGuildTechContributeFields>;
|
|
||||||
|
|
||||||
interface IGuildTechStartFields {
|
|
||||||
Mode: "Guild";
|
|
||||||
RecipeType: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
type IGuildTechBuyFields = IGuildTechStartFields;
|
|
||||||
|
|
||||||
interface IGuildTechContributeFields {
|
|
||||||
ResearchId: "";
|
|
||||||
RecipeType: string;
|
|
||||||
RegularCredits: number;
|
|
||||||
MiscItems: IMiscItem[];
|
|
||||||
VaultCredits: number;
|
|
||||||
VaultMiscItems: IMiscItem[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const scaleRequiredCount = (count: number): number => {
|
|
||||||
// The recipes in the export are for Moon clans. For now we'll just assume we only have Ghost clans.
|
|
||||||
return Math.max(1, Math.trunc(count / 100));
|
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@ import { createNewSession } from "@/src/managers/sessionManager";
|
|||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { ISession } from "@/src/types/session";
|
import { ISession } from "@/src/types/session";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
const hostSessionController: RequestHandler = async (req, res) => {
|
const hostSessionController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const hostSessionRequest = JSON.parse(req.body as string) as ISession;
|
const hostSessionRequest = JSON.parse(req.body as string) as ISession;
|
||||||
@ -11,7 +12,7 @@ const hostSessionController: RequestHandler = async (req, res) => {
|
|||||||
const session = createNewSession(hostSessionRequest, accountId);
|
const session = createNewSession(hostSessionRequest, accountId);
|
||||||
logger.debug(`New Session Created`, { session });
|
logger.debug(`New Session Created`, { session });
|
||||||
|
|
||||||
res.json({ sessionId: { $oid: session.sessionId }, rewardSeed: 99999999 });
|
res.json({ sessionId: { $id: session.sessionId }, rewardSeed: 99999999 });
|
||||||
};
|
};
|
||||||
|
|
||||||
export { hostSessionController };
|
export { hostSessionController };
|
||||||
|
@ -1,87 +1,8 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { Inbox } from "@/src/models/inboxModel";
|
import inbox from "@/static/fixed_responses/inbox.json";
|
||||||
import {
|
|
||||||
createNewEventMessages,
|
|
||||||
deleteAllMessagesRead,
|
|
||||||
deleteMessageRead,
|
|
||||||
getAllMessagesSorted,
|
|
||||||
getMessage
|
|
||||||
} from "@/src/services/inboxService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { addItems, getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { logger } from "@/src/utils/logger";
|
|
||||||
import { ExportGear } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
export const inboxController: RequestHandler = async (req, res) => {
|
const inboxController: RequestHandler = (_req, res) => {
|
||||||
const { deleteId, lastMessage: latestClientMessageId, messageId } = req.query;
|
res.json(inbox);
|
||||||
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
|
|
||||||
if (deleteId) {
|
|
||||||
if (deleteId === "DeleteAllRead") {
|
|
||||||
await deleteAllMessagesRead(accountId);
|
|
||||||
res.status(200).end();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await deleteMessageRead(deleteId as string);
|
|
||||||
res.status(200).end();
|
|
||||||
} else if (messageId) {
|
|
||||||
const message = await getMessage(messageId as string);
|
|
||||||
message.r = true;
|
|
||||||
const attachmentItems = message.att;
|
|
||||||
const attachmentCountedItems = message.countedAtt;
|
|
||||||
|
|
||||||
if (!attachmentItems && !attachmentCountedItems) {
|
|
||||||
await message.save();
|
|
||||||
|
|
||||||
res.status(200).end();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const inventoryChanges = {};
|
|
||||||
if (attachmentItems) {
|
|
||||||
await addItems(
|
|
||||||
inventory,
|
|
||||||
attachmentItems.map(attItem => ({
|
|
||||||
ItemType: attItem,
|
|
||||||
ItemCount: attItem in ExportGear ? (ExportGear[attItem].purchaseQuantity ?? 1) : 1
|
|
||||||
})),
|
|
||||||
inventoryChanges
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (attachmentCountedItems) {
|
|
||||||
await addItems(inventory, attachmentCountedItems, inventoryChanges);
|
|
||||||
}
|
|
||||||
await inventory.save();
|
|
||||||
await message.save();
|
|
||||||
|
|
||||||
res.json({ InventoryChanges: inventoryChanges });
|
|
||||||
} else if (latestClientMessageId) {
|
|
||||||
await createNewEventMessages(req);
|
|
||||||
const messages = await Inbox.find({ ownerId: accountId }).sort({ date: 1 });
|
|
||||||
|
|
||||||
const latestClientMessage = messages.find(m => m._id.toString() === latestClientMessageId);
|
|
||||||
|
|
||||||
if (!latestClientMessage) {
|
|
||||||
logger.debug(`this should only happen after DeleteAllRead `);
|
|
||||||
res.json({ Inbox: messages });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const newMessages = messages.filter(m => m.date > latestClientMessage.date);
|
|
||||||
|
|
||||||
if (newMessages.length === 0) {
|
|
||||||
res.send("no-new");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json({ Inbox: newMessages });
|
|
||||||
} else {
|
|
||||||
//newly created event messages must be newer than account.LatestEventMessageDate
|
|
||||||
await createNewEventMessages(req);
|
|
||||||
const messages = await getAllMessagesSorted(accountId);
|
|
||||||
const inbox = messages.map(m => m.toJSON());
|
|
||||||
res.json({ Inbox: inbox });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { inboxController };
|
||||||
|
@ -1,33 +1,18 @@
|
|||||||
import { RequestHandler } from "express";
|
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 { getInventory, addMiscItems, updateCurrency, addRecipes } from "@/src/services/inventoryService";
|
import { getInventory, addMiscItems } from "@/src/services/inventoryService";
|
||||||
import { IOid } from "@/src/types/commonTypes";
|
import { IOid } from "@/src/types/commonTypes";
|
||||||
import {
|
|
||||||
IConsumedSuit,
|
|
||||||
IHelminthFoodRecord,
|
|
||||||
IInfestedFoundryClient,
|
|
||||||
IInfestedFoundryDatabase,
|
|
||||||
IInventoryClient,
|
|
||||||
IMiscItem,
|
|
||||||
ITypeCount
|
|
||||||
} from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { ExportMisc, ExportRecipes } from "warframe-public-export-plus";
|
|
||||||
import { getRecipe } from "@/src/services/itemDataService";
|
|
||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
|
||||||
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
|
|
||||||
import { logger } from "@/src/utils/logger";
|
|
||||||
import { colorToShard } from "@/src/helpers/shardHelper";
|
|
||||||
import { config } from "@/src/services/configService";
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const infestedFoundryController: RequestHandler = async (req, res) => {
|
export const infestedFoundryController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
switch (req.query.mode) {
|
switch (req.query.mode) {
|
||||||
case "s": {
|
case "s": {
|
||||||
// shard installation
|
// shard installation
|
||||||
const request = getJSONfromString<IShardInstallRequest>(String(req.body));
|
const request = getJSONfromString(String(req.body)) as IShardInstallRequest;
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
const suit = inventory.Suits.find(suit => suit._id.toString() == request.SuitId.$oid)!;
|
const suit = inventory.Suits.find(suit => suit._id.toString() == request.SuitId.$id)!;
|
||||||
if (!suit.ArchonCrystalUpgrades || suit.ArchonCrystalUpgrades.length != 5) {
|
if (!suit.ArchonCrystalUpgrades || suit.ArchonCrystalUpgrades.length != 5) {
|
||||||
suit.ArchonCrystalUpgrades = [{}, {}, {}, {}, {}];
|
suit.ArchonCrystalUpgrades = [{}, {}, {}, {}, {}];
|
||||||
}
|
}
|
||||||
@ -51,51 +36,9 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "x": {
|
|
||||||
// shard removal
|
|
||||||
const request = getJSONfromString<IShardUninstallRequest>(String(req.body));
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const suit = inventory.Suits.find(suit => suit._id.toString() == request.SuitId.$oid)!;
|
|
||||||
|
|
||||||
// refund shard
|
|
||||||
const shard = Object.entries(colorToShard).find(
|
|
||||||
([color]) => color == suit.ArchonCrystalUpgrades![request.Slot].Color
|
|
||||||
)![1];
|
|
||||||
const miscItemChanges = [
|
|
||||||
{
|
|
||||||
ItemType: shard,
|
|
||||||
ItemCount: 1
|
|
||||||
}
|
|
||||||
];
|
|
||||||
addMiscItems(inventory, miscItemChanges);
|
|
||||||
|
|
||||||
// remove from suit
|
|
||||||
suit.ArchonCrystalUpgrades![request.Slot] = {};
|
|
||||||
|
|
||||||
if (!config.infiniteHelminthMaterials) {
|
|
||||||
// remove bile
|
|
||||||
const bile = inventory.InfestedFoundry!.Resources!.find(
|
|
||||||
x => x.ItemType == "/Lotus/Types/Items/InfestedFoundry/HelminthBile"
|
|
||||||
)!;
|
|
||||||
bile.Count -= 300;
|
|
||||||
}
|
|
||||||
|
|
||||||
await inventory.save();
|
|
||||||
|
|
||||||
const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
|
|
||||||
applyCheatsToInfestedFoundry(infestedFoundry);
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: {
|
|
||||||
MiscItems: miscItemChanges,
|
|
||||||
InfestedFoundry: infestedFoundry
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case "n": {
|
case "n": {
|
||||||
// name the beast
|
// name the beast
|
||||||
const request = getJSONfromString<IHelminthNameRequest>(String(req.body));
|
const request = getJSONfromString(String(req.body)) as IHelminthNameRequest;
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
inventory.InfestedFoundry ??= {};
|
inventory.InfestedFoundry ??= {};
|
||||||
inventory.InfestedFoundry.Name = request.newName;
|
inventory.InfestedFoundry.Name = request.newName;
|
||||||
@ -110,251 +53,13 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "c": {
|
case "o": // offerings update
|
||||||
// consume items
|
// {"OfferingsIndex":540,"SuitTypes":["/Lotus/Powersuits/PaxDuviricus/PaxDuviricusBaseSuit","/Lotus/Powersuits/Nezha/NezhaBaseSuit","/Lotus/Powersuits/Devourer/DevourerBaseSuit"],"Extra":false}
|
||||||
|
res.status(404).end();
|
||||||
if (config.infiniteHelminthMaterials) {
|
|
||||||
res.status(400).end();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const request = getJSONfromString<IHelminthFeedRequest>(String(req.body));
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
inventory.InfestedFoundry ??= {};
|
|
||||||
inventory.InfestedFoundry.Resources ??= [];
|
|
||||||
|
|
||||||
const miscItemChanges: IMiscItem[] = [];
|
|
||||||
let totalPercentagePointsGained = 0;
|
|
||||||
|
|
||||||
const currentUnixSeconds = Math.trunc(new Date().getTime() / 1000);
|
|
||||||
|
|
||||||
for (const contribution of request.ResourceContributions) {
|
|
||||||
const snack = ExportMisc.helminthSnacks[contribution.ItemType];
|
|
||||||
|
|
||||||
// tally items for removal
|
|
||||||
const change = miscItemChanges.find(x => x.ItemType == contribution.ItemType);
|
|
||||||
if (change) {
|
|
||||||
change.ItemCount -= snack.count;
|
|
||||||
} else {
|
|
||||||
miscItemChanges.push({ ItemType: contribution.ItemType, ItemCount: snack.count * -1 });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snack.type == "/Lotus/Types/Items/InfestedFoundry/HelminthAppetiteCooldownReducer") {
|
|
||||||
// sentinent apetite
|
|
||||||
let mostDislikedSnackRecord: IHelminthFoodRecord = { ItemType: "", Date: 0 };
|
|
||||||
for (const resource of inventory.InfestedFoundry.Resources) {
|
|
||||||
if (resource.RecentlyConvertedResources) {
|
|
||||||
for (const record of resource.RecentlyConvertedResources) {
|
|
||||||
if (record.Date > mostDislikedSnackRecord.Date) {
|
|
||||||
mostDislikedSnackRecord = record;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.debug("helminth eats sentient resource; most disliked snack:", {
|
|
||||||
type: mostDislikedSnackRecord.ItemType,
|
|
||||||
date: mostDislikedSnackRecord.Date
|
|
||||||
});
|
|
||||||
mostDislikedSnackRecord.Date = currentUnixSeconds + 24 * 60 * 60; // Possibly unfaithful
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let resource = inventory.InfestedFoundry.Resources.find(x => x.ItemType == snack.type);
|
|
||||||
if (!resource) {
|
|
||||||
resource =
|
|
||||||
inventory.InfestedFoundry.Resources[
|
|
||||||
inventory.InfestedFoundry.Resources.push({ ItemType: snack.type, Count: 0 }) - 1
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
resource.RecentlyConvertedResources ??= [];
|
|
||||||
let record = resource.RecentlyConvertedResources.find(x => x.ItemType == contribution.ItemType);
|
|
||||||
if (!record) {
|
|
||||||
record =
|
|
||||||
resource.RecentlyConvertedResources[
|
|
||||||
resource.RecentlyConvertedResources.push({ ItemType: contribution.ItemType, Date: 0 }) - 1
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
const hoursRemaining = (record.Date - currentUnixSeconds) / 3600;
|
|
||||||
const apetiteFactor = apetiteModel(hoursRemaining) / 30;
|
|
||||||
logger.debug(`helminth eating ${contribution.ItemType} (+${(snack.gain * 100).toFixed(0)}%)`, {
|
|
||||||
hoursRemaining,
|
|
||||||
apetiteFactor
|
|
||||||
});
|
|
||||||
if (hoursRemaining >= 18) {
|
|
||||||
record.Date = currentUnixSeconds + 72 * 60 * 60; // Possibly unfaithful
|
|
||||||
} else {
|
|
||||||
record.Date = currentUnixSeconds + 24 * 60 * 60;
|
|
||||||
}
|
|
||||||
|
|
||||||
totalPercentagePointsGained += snack.gain * 100 * apetiteFactor; // 30% would be gain=0.3, so percentage points is equal to gain * 100.
|
|
||||||
resource.Count += Math.trunc(snack.gain * 1000 * apetiteFactor); // 30% would be gain=0.3 or Count=300, so Count=gain*1000.
|
|
||||||
if (resource.Count > 1000) resource.Count = 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry, 666 * totalPercentagePointsGained);
|
|
||||||
addRecipes(inventory, recipeChanges);
|
|
||||||
addMiscItems(inventory, miscItemChanges);
|
|
||||||
await inventory.save();
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: {
|
|
||||||
Recipes: recipeChanges,
|
|
||||||
InfestedFoundry: {
|
|
||||||
XP: inventory.InfestedFoundry.XP,
|
|
||||||
Resources: inventory.InfestedFoundry.Resources,
|
|
||||||
Slots: inventory.InfestedFoundry.Slots
|
|
||||||
},
|
|
||||||
MiscItems: miscItemChanges
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case "o": {
|
|
||||||
// offerings update
|
|
||||||
const request = getJSONfromString<IHelminthOfferingsUpdate>(String(req.body));
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
inventory.InfestedFoundry ??= {};
|
|
||||||
inventory.InfestedFoundry.InvigorationIndex = request.OfferingsIndex;
|
|
||||||
inventory.InfestedFoundry.InvigorationSuitOfferings = request.SuitTypes;
|
|
||||||
if (request.Extra) {
|
|
||||||
inventory.InfestedFoundry.InvigorationsApplied = 0;
|
|
||||||
}
|
|
||||||
await inventory.save();
|
|
||||||
const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
|
|
||||||
applyCheatsToInfestedFoundry(infestedFoundry);
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: {
|
|
||||||
InfestedFoundry: infestedFoundry
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case "a": {
|
|
||||||
// subsume warframe
|
|
||||||
const request = getJSONfromString<IHelminthSubsumeRequest>(String(req.body));
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const recipe = getRecipe(request.Recipe)!;
|
|
||||||
if (!config.infiniteHelminthMaterials) {
|
|
||||||
for (const ingredient of recipe.secretIngredients!) {
|
|
||||||
const resource = inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType);
|
|
||||||
if (resource) {
|
|
||||||
resource.Count -= ingredient.ItemCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const suit = inventory.Suits.id(request.SuitId.$oid)!;
|
|
||||||
inventory.Suits.pull(suit);
|
|
||||||
const consumedSuit: IConsumedSuit = { s: suit.ItemType };
|
|
||||||
if (suit.Configs[0] && suit.Configs[0].pricol) {
|
|
||||||
consumedSuit.c = suit.Configs[0].pricol;
|
|
||||||
}
|
|
||||||
if ((inventory.InfestedFoundry!.XP ?? 0) < 73125_00) {
|
|
||||||
inventory.InfestedFoundry!.Slots!--;
|
|
||||||
}
|
|
||||||
inventory.InfestedFoundry!.ConsumedSuits ??= [];
|
|
||||||
inventory.InfestedFoundry!.ConsumedSuits.push(consumedSuit);
|
|
||||||
inventory.InfestedFoundry!.LastConsumedSuit = suit;
|
|
||||||
inventory.InfestedFoundry!.AbilityOverrideUnlockCooldown = new Date(
|
|
||||||
new Date().getTime() + 24 * 60 * 60 * 1000
|
|
||||||
);
|
|
||||||
const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, 1600_00);
|
|
||||||
addRecipes(inventory, recipeChanges);
|
|
||||||
await inventory.save();
|
|
||||||
const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
|
|
||||||
applyCheatsToInfestedFoundry(infestedFoundry);
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: {
|
|
||||||
Recipes: recipeChanges,
|
|
||||||
RemovedIdItems: [
|
|
||||||
{
|
|
||||||
ItemId: request.SuitId
|
|
||||||
}
|
|
||||||
],
|
|
||||||
SuitBin: {
|
|
||||||
count: -1,
|
|
||||||
platinum: 0,
|
|
||||||
Slots: 1
|
|
||||||
},
|
|
||||||
InfestedFoundry: infestedFoundry
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case "r": {
|
|
||||||
// rush subsume
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const currencyChanges = updateCurrency(inventory, 50, true);
|
|
||||||
const recipeChanges = handleSubsumeCompletion(inventory);
|
|
||||||
await inventory.save();
|
|
||||||
const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
|
|
||||||
applyCheatsToInfestedFoundry(infestedFoundry);
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: {
|
|
||||||
...currencyChanges,
|
|
||||||
Recipes: recipeChanges,
|
|
||||||
InfestedFoundry: infestedFoundry
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case "u": {
|
|
||||||
const request = getJSONfromString<IHelminthInvigorationRequest>(String(req.body));
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const suit = inventory.Suits.id(request.SuitId.$oid)!;
|
|
||||||
const upgradesExpiry = new Date(new Date().getTime() + 7 * 24 * 60 * 60 * 1000);
|
|
||||||
suit.OffensiveUpgrade = request.OffensiveUpgradeType;
|
|
||||||
suit.DefensiveUpgrade = request.DefensiveUpgradeType;
|
|
||||||
suit.UpgradesExpiry = upgradesExpiry;
|
|
||||||
const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, 4800_00);
|
|
||||||
addRecipes(inventory, recipeChanges);
|
|
||||||
if (!config.infiniteHelminthMaterials) {
|
|
||||||
for (let i = 0; i != request.ResourceTypes.length; ++i) {
|
|
||||||
inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == request.ResourceTypes[i])!.Count -=
|
|
||||||
request.ResourceCosts[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inventory.InfestedFoundry!.InvigorationsApplied ??= 0;
|
|
||||||
inventory.InfestedFoundry!.InvigorationsApplied += 1;
|
|
||||||
await inventory.save();
|
|
||||||
const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
|
|
||||||
applyCheatsToInfestedFoundry(infestedFoundry);
|
|
||||||
res.json({
|
|
||||||
SuitId: request.SuitId,
|
|
||||||
OffensiveUpgrade: request.OffensiveUpgradeType,
|
|
||||||
DefensiveUpgrade: request.DefensiveUpgradeType,
|
|
||||||
UpgradesExpiry: toMongoDate(upgradesExpiry),
|
|
||||||
InventoryChanges: {
|
|
||||||
Recipes: recipeChanges,
|
|
||||||
InfestedFoundry: infestedFoundry
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case "custom_unlockall": {
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
inventory.InfestedFoundry ??= {};
|
|
||||||
inventory.InfestedFoundry.XP ??= 0;
|
|
||||||
if (151875_00 > inventory.InfestedFoundry.XP) {
|
|
||||||
const recipeChanges = addInfestedFoundryXP(
|
|
||||||
inventory.InfestedFoundry,
|
|
||||||
151875_00 - inventory.InfestedFoundry.XP
|
|
||||||
);
|
|
||||||
addRecipes(inventory, recipeChanges);
|
|
||||||
await inventory.save();
|
|
||||||
}
|
|
||||||
res.end();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`unhandled infestedFoundry mode: ${String(req.query.mode)}`);
|
throw new Error(`unhandled infestedFoundry mode: ${req.query.mode}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -365,179 +70,21 @@ interface IShardInstallRequest {
|
|||||||
Color: string;
|
Color: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IShardUninstallRequest {
|
|
||||||
SuitId: IOid;
|
|
||||||
Slot: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IHelminthNameRequest {
|
interface IHelminthNameRequest {
|
||||||
newName: string;
|
newName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IHelminthFeedRequest {
|
const colorToShard: Record<string, string> = {
|
||||||
ResourceContributions: {
|
ACC_RED: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalAmar",
|
||||||
ItemType: string;
|
ACC_RED_MYTHIC: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalAmarMythic",
|
||||||
Date: number; // unix timestamp
|
ACC_YELLOW: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalNira",
|
||||||
}[];
|
ACC_YELLOW_MYTHIC: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalNiraMythic",
|
||||||
}
|
ACC_BLUE: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalBoreal",
|
||||||
|
ACC_BLUE_MYTHIC: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalBorealMythic",
|
||||||
export const addInfestedFoundryXP = (infestedFoundry: IInfestedFoundryDatabase, delta: number): ITypeCount[] => {
|
ACC_GREEN: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalGreen",
|
||||||
const recipeChanges: ITypeCount[] = [];
|
ACC_GREEN_MYTHIC: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalGreenMythic",
|
||||||
infestedFoundry.XP ??= 0;
|
ACC_ORANGE: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalOrange",
|
||||||
const prevXP = infestedFoundry.XP;
|
ACC_ORANGE_MYTHIC: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalOrangeMythic",
|
||||||
infestedFoundry.XP += delta;
|
ACC_PURPLE: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalViolet",
|
||||||
if (prevXP < 2250_00 && infestedFoundry.XP >= 2250_00) {
|
ACC_PURPLE_MYTHIC: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalVioletMythic"
|
||||||
infestedFoundry.Slots ??= 0;
|
|
||||||
infestedFoundry.Slots += 3;
|
|
||||||
}
|
|
||||||
if (prevXP < 5625_00 && infestedFoundry.XP >= 5625_00) {
|
|
||||||
recipeChanges.push({
|
|
||||||
ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthShieldsBlueprint",
|
|
||||||
ItemCount: 1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (prevXP < 10125_00 && infestedFoundry.XP >= 10125_00) {
|
|
||||||
recipeChanges.push({ ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthHackBlueprint", ItemCount: 1 });
|
|
||||||
}
|
|
||||||
if (prevXP < 15750_00 && infestedFoundry.XP >= 15750_00) {
|
|
||||||
infestedFoundry.Slots ??= 0;
|
|
||||||
infestedFoundry.Slots += 10;
|
|
||||||
}
|
|
||||||
if (prevXP < 22500_00 && infestedFoundry.XP >= 22500_00) {
|
|
||||||
recipeChanges.push({
|
|
||||||
ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthAmmoEfficiencyBlueprint",
|
|
||||||
ItemCount: 1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (prevXP < 30375_00 && infestedFoundry.XP >= 30375_00) {
|
|
||||||
recipeChanges.push({ ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthStunBlueprint", ItemCount: 1 });
|
|
||||||
}
|
|
||||||
if (prevXP < 39375_00 && infestedFoundry.XP >= 39375_00) {
|
|
||||||
infestedFoundry.Slots ??= 0;
|
|
||||||
infestedFoundry.Slots += 20;
|
|
||||||
}
|
|
||||||
if (prevXP < 60750_00 && infestedFoundry.XP >= 60750_00) {
|
|
||||||
recipeChanges.push({ ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthStatusBlueprint", ItemCount: 1 });
|
|
||||||
}
|
|
||||||
if (prevXP < 73125_00 && infestedFoundry.XP >= 73125_00) {
|
|
||||||
infestedFoundry.Slots = 1;
|
|
||||||
}
|
|
||||||
if (prevXP < 86625_00 && infestedFoundry.XP >= 86625_00) {
|
|
||||||
recipeChanges.push({
|
|
||||||
ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthShieldArmorBlueprint",
|
|
||||||
ItemCount: 1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (prevXP < 101250_00 && infestedFoundry.XP >= 101250_00) {
|
|
||||||
recipeChanges.push({
|
|
||||||
ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthProcBlockBlueprint",
|
|
||||||
ItemCount: 1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (prevXP < 117000_00 && infestedFoundry.XP >= 117000_00) {
|
|
||||||
recipeChanges.push({
|
|
||||||
ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthEnergyShareBlueprint",
|
|
||||||
ItemCount: 1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (prevXP < 133875_00 && infestedFoundry.XP >= 133875_00) {
|
|
||||||
recipeChanges.push({
|
|
||||||
ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthMaxStatusBlueprint",
|
|
||||||
ItemCount: 1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (prevXP < 151875_00 && infestedFoundry.XP >= 151875_00) {
|
|
||||||
recipeChanges.push({
|
|
||||||
ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthTreasureBlueprint",
|
|
||||||
ItemCount: 1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return recipeChanges;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IHelminthSubsumeRequest {
|
|
||||||
SuitId: IOid;
|
|
||||||
Recipe: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const handleSubsumeCompletion = (inventory: TInventoryDatabaseDocument): ITypeCount[] => {
|
|
||||||
const [recipeType] = Object.entries(ExportRecipes).find(
|
|
||||||
([_recipeType, recipe]) =>
|
|
||||||
recipe.secretIngredientAction == "SIA_WARFRAME_ABILITY" &&
|
|
||||||
recipe.secretIngredients![0].ItemType == inventory.InfestedFoundry!.LastConsumedSuit!.ItemType
|
|
||||||
)!;
|
|
||||||
inventory.InfestedFoundry!.LastConsumedSuit = undefined;
|
|
||||||
inventory.InfestedFoundry!.AbilityOverrideUnlockCooldown = undefined;
|
|
||||||
const recipeChanges: ITypeCount[] = [
|
|
||||||
{
|
|
||||||
ItemType: recipeType,
|
|
||||||
ItemCount: 1
|
|
||||||
}
|
|
||||||
];
|
|
||||||
addRecipes(inventory, recipeChanges);
|
|
||||||
return recipeChanges;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const applyCheatsToInfestedFoundry = (infestedFoundry: IInfestedFoundryClient): void => {
|
|
||||||
if (config.infiniteHelminthMaterials) {
|
|
||||||
infestedFoundry.Resources = [
|
|
||||||
{ ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthCalx", Count: 1000 },
|
|
||||||
{ ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthBiotics", Count: 1000 },
|
|
||||||
{ ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthSynthetics", Count: 1000 },
|
|
||||||
{ ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthPheromones", Count: 1000 },
|
|
||||||
{ ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthBile", Count: 1000 },
|
|
||||||
{ ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthOxides", Count: 1000 }
|
|
||||||
];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IHelminthOfferingsUpdate {
|
|
||||||
OfferingsIndex: number;
|
|
||||||
SuitTypes: string[];
|
|
||||||
Extra: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IHelminthInvigorationRequest {
|
|
||||||
SuitId: IOid;
|
|
||||||
OffensiveUpgradeType: string;
|
|
||||||
DefensiveUpgradeType: string;
|
|
||||||
ResourceTypes: string[];
|
|
||||||
ResourceCosts: number[];
|
|
||||||
}
|
|
||||||
|
|
||||||
// A fitted model for observed apetite values. Likely slightly inaccurate.
|
|
||||||
//
|
|
||||||
// Hours remaining, percentage points gained (out of 30 total)
|
|
||||||
// 0, 30
|
|
||||||
// 5, 25.8
|
|
||||||
// 10, 21.6
|
|
||||||
// 12, 20
|
|
||||||
// 16, 16.6
|
|
||||||
// 17, 15.8
|
|
||||||
// 18, 15
|
|
||||||
// 20, 15
|
|
||||||
// 24, 15
|
|
||||||
// 36, 15
|
|
||||||
// 40, 13.6
|
|
||||||
// 47, 11.3
|
|
||||||
// 48, 11
|
|
||||||
// 50, 10.3
|
|
||||||
// 60, 7
|
|
||||||
// 70, 3.6
|
|
||||||
// 71, 3.3
|
|
||||||
// 72, 3
|
|
||||||
const apetiteModel = (x: number): number => {
|
|
||||||
if (x <= 0) {
|
|
||||||
return 30;
|
|
||||||
}
|
|
||||||
if (x < 18) {
|
|
||||||
return -0.84 * x + 30;
|
|
||||||
}
|
|
||||||
if (x <= 36) {
|
|
||||||
return 15;
|
|
||||||
}
|
|
||||||
if (x < 71.9) {
|
|
||||||
return -0.3327892 * x + 26.94135;
|
|
||||||
}
|
|
||||||
return 3;
|
|
||||||
};
|
};
|
||||||
|
@ -1,149 +1,71 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { Inventory, TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
import { toInventoryResponse } from "@/src/helpers/inventoryHelpers";
|
||||||
|
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { config } from "@/src/services/configService";
|
import { config } from "@/src/services/configService";
|
||||||
import allDialogue from "@/static/fixed_responses/allDialogue.json";
|
import { IInventoryDatabase } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { ILoadoutDatabase } from "@/src/types/saveLoadoutTypes";
|
//import new_inventory from "@/static/fixed_responses/postTutorialInventory.json";
|
||||||
import { IInventoryClient, IShipInventory, equipmentKeys } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { IPolarity, ArtifactPolarity, EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
|
||||||
import {
|
|
||||||
ExportCustoms,
|
|
||||||
ExportFlavour,
|
|
||||||
ExportRegions,
|
|
||||||
ExportResources,
|
|
||||||
ExportVirtuals
|
|
||||||
} from "warframe-public-export-plus";
|
|
||||||
import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "./infestedFoundryController";
|
|
||||||
import { allDailyAffiliationKeys } from "@/src/services/inventoryService";
|
|
||||||
|
|
||||||
export const inventoryController: RequestHandler = async (request, response) => {
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
const account = await getAccountForRequest(request);
|
const inventoryController: RequestHandler = async (request, response) => {
|
||||||
|
let accountId;
|
||||||
|
try {
|
||||||
|
accountId = await getAccountIdForRequest(request);
|
||||||
|
} catch (e) {
|
||||||
|
response.status(400).send("Log-in expired");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const inventory = await Inventory.findOne({ accountOwnerId: account._id.toString() });
|
const inventory = await Inventory.findOne({ accountOwnerId: accountId });
|
||||||
|
|
||||||
if (!inventory) {
|
if (!inventory) {
|
||||||
response.status(400).json({ error: "inventory was undefined" });
|
response.status(400).json({ error: "inventory was undefined" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle daily reset
|
//TODO: make a function that converts from database representation to client
|
||||||
const today: number = Math.trunc(new Date().getTime() / 86400000);
|
const inventoryJSON: IInventoryDatabase = inventory.toJSON();
|
||||||
if (account.LastLoginDay != today) {
|
console.log(inventoryJSON.Ships);
|
||||||
account.LastLoginDay = today;
|
|
||||||
await account.save();
|
|
||||||
|
|
||||||
for (const key of allDailyAffiliationKeys) {
|
const inventoryResponse = toInventoryResponse(inventoryJSON);
|
||||||
inventory[key] = 16000 + inventory.PlayerLevel * 500;
|
|
||||||
}
|
|
||||||
inventory.DailyFocus = 250000 + inventory.PlayerLevel * 5000;
|
|
||||||
await inventory.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (config.infiniteResources) {
|
||||||
inventory.InfestedFoundry &&
|
|
||||||
inventory.InfestedFoundry.AbilityOverrideUnlockCooldown &&
|
|
||||||
new Date() >= inventory.InfestedFoundry.AbilityOverrideUnlockCooldown
|
|
||||||
) {
|
|
||||||
handleSubsumeCompletion(inventory);
|
|
||||||
await inventory.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
response.json(await getInventoryResponse(inventory, "xpBasedLevelCapDisabled" in request.query));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getInventoryResponse = async (
|
|
||||||
inventory: TInventoryDatabaseDocument,
|
|
||||||
xpBasedLevelCapDisabled: boolean
|
|
||||||
): Promise<IInventoryClient> => {
|
|
||||||
const inventoryWithLoadOutPresets = await inventory.populate<{ LoadOutPresets: ILoadoutDatabase }>(
|
|
||||||
"LoadOutPresets"
|
|
||||||
);
|
|
||||||
const inventoryWithLoadOutPresetsAndShips = await inventoryWithLoadOutPresets.populate<{ Ships: IShipInventory }>(
|
|
||||||
"Ships"
|
|
||||||
);
|
|
||||||
const inventoryResponse = inventoryWithLoadOutPresetsAndShips.toJSON<IInventoryClient>();
|
|
||||||
|
|
||||||
if (config.infiniteCredits) {
|
|
||||||
inventoryResponse.RegularCredits = 999999999;
|
inventoryResponse.RegularCredits = 999999999;
|
||||||
}
|
|
||||||
if (config.infinitePlatinum) {
|
|
||||||
inventoryResponse.PremiumCreditsFree = 999999999;
|
|
||||||
inventoryResponse.PremiumCredits = 999999999;
|
inventoryResponse.PremiumCredits = 999999999;
|
||||||
}
|
}
|
||||||
if (config.infiniteEndo) {
|
|
||||||
inventoryResponse.FusionPoints = 999999999;
|
|
||||||
}
|
|
||||||
if (config.infiniteRegalAya) {
|
|
||||||
inventoryResponse.PrimeTokens = 999999999;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.skipAllDialogue) {
|
// if (config.unlockAllMissions) {
|
||||||
inventoryResponse.TauntHistory = [
|
// //inventoryResponse.Missions = allMissions;
|
||||||
{
|
// //inventoryResponse.NodeIntrosCompleted.push("TeshinHardModeUnlocked");
|
||||||
node: "TreasureTutorial",
|
// }
|
||||||
state: "TS_COMPLETED"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
for (const str of allDialogue) {
|
|
||||||
addString(inventoryResponse.NodeIntrosCompleted, str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.unlockAllMissions) {
|
// if (config.unlockAllMissions) {
|
||||||
inventoryResponse.Missions = [];
|
// //inventoryResponse.Missions = allMissions;
|
||||||
for (const tag of Object.keys(ExportRegions)) {
|
// //addString(inventoryResponse.NodeIntrosCompleted, "TeshinHardModeUnlocked");
|
||||||
inventoryResponse.Missions.push({
|
// }
|
||||||
Completes: 1,
|
|
||||||
Tier: 1,
|
|
||||||
Tag: tag
|
|
||||||
});
|
|
||||||
}
|
|
||||||
addString(inventoryResponse.NodeIntrosCompleted, "TeshinHardModeUnlocked");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.unlockAllShipDecorations) {
|
// if (config.unlockAllFlavourItems) {
|
||||||
inventoryResponse.ShipDecorations = [];
|
// inventoryResponse.FlavourItems = [];
|
||||||
for (const [uniqueName, item] of Object.entries(ExportResources)) {
|
// for (const uniqueName in ExportFlavour) {
|
||||||
if (item.productCategory == "ShipDecorations") {
|
// inventoryResponse.FlavourItems.push({ ItemType: uniqueName });
|
||||||
inventoryResponse.ShipDecorations.push({ ItemType: uniqueName, ItemCount: 1 });
|
// }
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.unlockAllFlavourItems) {
|
// if (config.unlockAllSkins) {
|
||||||
inventoryResponse.FlavourItems = [];
|
// inventoryResponse.WeaponSkins = [];
|
||||||
for (const uniqueName in ExportFlavour) {
|
// for (const uniqueName in ExportCustoms) {
|
||||||
inventoryResponse.FlavourItems.push({ ItemType: uniqueName });
|
// inventoryResponse.WeaponSkins.push({
|
||||||
}
|
// ItemId: {
|
||||||
}
|
// $id: "000000000000000000000000"
|
||||||
|
// },
|
||||||
if (config.unlockAllSkins) {
|
// ItemType: uniqueName
|
||||||
const missingWeaponSkins = new Set(Object.keys(ExportCustoms));
|
// });
|
||||||
inventoryResponse.WeaponSkins.forEach(x => missingWeaponSkins.delete(x.ItemType));
|
// }
|
||||||
for (const uniqueName of missingWeaponSkins) {
|
// }
|
||||||
inventoryResponse.WeaponSkins.push({
|
|
||||||
ItemId: {
|
|
||||||
$oid: "ca70ca70ca70ca70" + catBreadHash(uniqueName).toString(16).padStart(8, "0")
|
|
||||||
},
|
|
||||||
ItemType: uniqueName
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.unlockAllCapturaScenes) {
|
|
||||||
for (const uniqueName of Object.keys(ExportResources)) {
|
|
||||||
if (resourceInheritsFrom(uniqueName, "/Lotus/Types/Items/MiscItems/PhotoboothTile")) {
|
|
||||||
inventoryResponse.MiscItems.push({
|
|
||||||
ItemType: uniqueName,
|
|
||||||
ItemCount: 1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof config.spoofMasteryRank === "number" && config.spoofMasteryRank >= 0) {
|
if (typeof config.spoofMasteryRank === "number" && config.spoofMasteryRank >= 0) {
|
||||||
inventoryResponse.PlayerLevel = config.spoofMasteryRank;
|
inventoryResponse.PlayerLevel = config.spoofMasteryRank;
|
||||||
if (!xpBasedLevelCapDisabled) {
|
if (!("xpBasedLevelCapDisabled" in request.query)) {
|
||||||
// This client has not been patched to accept any mastery rank, need to fake the XP.
|
// This client has not been patched to accept any mastery rank, need to fake the XP.
|
||||||
inventoryResponse.XPInfo = [];
|
inventoryResponse.XPInfo = [];
|
||||||
let numFrames = getExpRequiredForMr(Math.min(config.spoofMasteryRank, 5030)) / 6000;
|
let numFrames = getExpRequiredForMr(Math.min(config.spoofMasteryRank, 5030)) / 6000;
|
||||||
@ -156,83 +78,18 @@ export const getInventoryResponse = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.universalPolarityEverywhere) {
|
|
||||||
const Polarity: IPolarity[] = [];
|
|
||||||
for (let i = 0; i != 12; ++i) {
|
|
||||||
Polarity.push({
|
|
||||||
Slot: i,
|
|
||||||
Value: ArtifactPolarity.Any
|
|
||||||
});
|
|
||||||
}
|
|
||||||
for (const key of equipmentKeys) {
|
|
||||||
if (key in inventoryResponse) {
|
|
||||||
for (const equipment of inventoryResponse[key]) {
|
|
||||||
equipment.Polarity = Polarity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.unlockDoubleCapacityPotatoesEverywhere) {
|
|
||||||
for (const key of equipmentKeys) {
|
|
||||||
if (key in inventoryResponse) {
|
|
||||||
for (const equipment of inventoryResponse[key]) {
|
|
||||||
equipment.Features ??= 0;
|
|
||||||
equipment.Features |= EquipmentFeatures.DOUBLE_CAPACITY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.unlockExilusEverywhere) {
|
|
||||||
for (const key of equipmentKeys) {
|
|
||||||
if (key in inventoryResponse) {
|
|
||||||
for (const equipment of inventoryResponse[key]) {
|
|
||||||
equipment.Features ??= 0;
|
|
||||||
equipment.Features |= EquipmentFeatures.UTILITY_SLOT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.unlockArcanesEverywhere) {
|
|
||||||
for (const key of equipmentKeys) {
|
|
||||||
if (key in inventoryResponse) {
|
|
||||||
for (const equipment of inventoryResponse[key]) {
|
|
||||||
equipment.Features ??= 0;
|
|
||||||
equipment.Features |= EquipmentFeatures.ARCANE_SLOT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.noDailyStandingLimits) {
|
|
||||||
for (const key of allDailyAffiliationKeys) {
|
|
||||||
inventoryResponse[key] = 999_999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inventoryResponse.InfestedFoundry) {
|
|
||||||
applyCheatsToInfestedFoundry(inventoryResponse.InfestedFoundry);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix for #380
|
// Fix for #380
|
||||||
inventoryResponse.NextRefill = { $date: { $numberLong: "9999999999999" } };
|
inventoryResponse.NextRefill = { $date: { $numberLong: "9999999999999" } };
|
||||||
|
|
||||||
// This determines if the "void fissures" tab is shown in navigation.
|
response.json(inventoryResponse);
|
||||||
inventoryResponse.HasOwnedVoidProjectionsPreviously = true;
|
|
||||||
|
|
||||||
// Omitting this field so opening the navigation resyncs the inventory which is more desirable for typical usage.
|
|
||||||
//inventoryResponse.LastInventorySync = toOid(new Types.ObjectId());
|
|
||||||
|
|
||||||
return inventoryResponse;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addString = (arr: string[], str: string): void => {
|
/*
|
||||||
|
const addString = (arr: string[], str: string): void => {
|
||||||
if (!arr.find(x => x == str)) {
|
if (!arr.find(x => x == str)) {
|
||||||
arr.push(str);
|
arr.push(str);
|
||||||
}
|
}
|
||||||
};
|
};*/
|
||||||
|
|
||||||
const getExpRequiredForMr = (rank: number): number => {
|
const getExpRequiredForMr = (rank: number): number => {
|
||||||
if (rank <= 30) {
|
if (rank <= 30) {
|
||||||
@ -241,29 +98,4 @@ const getExpRequiredForMr = (rank: number): number => {
|
|||||||
return 2_250_000 + 147_500 * (rank - 30);
|
return 2_250_000 + 147_500 * (rank - 30);
|
||||||
};
|
};
|
||||||
|
|
||||||
const resourceInheritsFrom = (resourceName: string, targetName: string): boolean => {
|
export { inventoryController };
|
||||||
let parentName = resourceGetParent(resourceName);
|
|
||||||
for (; parentName != undefined; parentName = resourceGetParent(parentName)) {
|
|
||||||
if (parentName == targetName) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const resourceGetParent = (resourceName: string): string | undefined => {
|
|
||||||
if (resourceName in ExportResources) {
|
|
||||||
return ExportResources[resourceName].parentName;
|
|
||||||
}
|
|
||||||
return ExportVirtuals[resourceName]?.parentName;
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is FNV1a-32 except operating under modulus 2^31 because JavaScript is stinky and likes producing negative integers out of nowhere.
|
|
||||||
const catBreadHash = (name: string): number => {
|
|
||||||
let hash = 2166136261;
|
|
||||||
for (let i = 0; i != name.length; ++i) {
|
|
||||||
hash = (hash ^ name.charCodeAt(i)) & 0x7fffffff;
|
|
||||||
hash = (hash * 16777619) & 0x7fffffff;
|
|
||||||
}
|
|
||||||
return hash;
|
|
||||||
};
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getInventory, updateCurrency } from "@/src/services/inventoryService";
|
import { updateCurrency } from "@/src/services/inventoryService";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { updateSlots } from "@/src/services/inventoryService";
|
import { updateSlots } from "@/src/services/inventoryService";
|
||||||
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
@ -18,16 +18,19 @@ import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
|||||||
number of frames = extra - slots + 2
|
number of frames = extra - slots + 2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const inventorySlotsController: RequestHandler = async (req, res) => {
|
export const inventorySlotsController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
//const body = JSON.parse(req.body as string) as IInventorySlotsRequest;
|
//const body = JSON.parse(req.body as string) as IInventorySlotsRequest;
|
||||||
|
|
||||||
|
//console.log(body);
|
||||||
|
|
||||||
//TODO: check which slot was purchased because pvpBonus is also possible
|
//TODO: check which slot was purchased because pvpBonus is also possible
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
const currencyChanges = await updateCurrency(20, true, accountId);
|
||||||
const currencyChanges = updateCurrency(inventory, 20, true);
|
await updateSlots(accountId, InventorySlot.PVE_LOADOUTS, 1, 1);
|
||||||
updateSlots(inventory, InventorySlot.PVE_LOADOUTS, 1, 1);
|
|
||||||
await inventory.save();
|
//console.log({ InventoryChanges: currencyChanges }, " added loadout changes:");
|
||||||
|
|
||||||
res.json({ InventoryChanges: currencyChanges });
|
res.json({ InventoryChanges: currencyChanges });
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,7 @@ const joinSessionController: RequestHandler = (_req, res) => {
|
|||||||
logger.debug(`JoinSession Request`, { reqBody });
|
logger.debug(`JoinSession Request`, { reqBody });
|
||||||
const req = JSON.parse(String(_req.body));
|
const req = JSON.parse(String(_req.body));
|
||||||
const session = getSessionByID(req.sessionIds[0] as string);
|
const session = getSessionByID(req.sessionIds[0] as string);
|
||||||
res.json({ rewardSeed: session?.rewardSeed, sessionId: { $oid: session?.sessionId } });
|
res.json({ rewardSeed: session?.rewardSeed, sessionId: { $id: session?.sessionId } });
|
||||||
};
|
};
|
||||||
|
|
||||||
export { joinSessionController };
|
export { joinSessionController };
|
||||||
|
@ -1,50 +1,43 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
import { config } from "@/src/services/configService";
|
import { config } from "@/src/services/configService";
|
||||||
import { buildConfig } from "@/src/services/buildConfigService";
|
import buildConfig from "@/static/data/buildConfig.json";
|
||||||
|
|
||||||
|
import { toLoginRequest } from "@/src/helpers/loginHelpers";
|
||||||
import { Account } from "@/src/models/loginModel";
|
import { Account } from "@/src/models/loginModel";
|
||||||
import { createAccount, isCorrectPassword, isNameTaken } from "@/src/services/loginService";
|
import { createAccount, isCorrectPassword } from "@/src/services/loginService";
|
||||||
import { IDatabaseAccountJson, ILoginRequest, ILoginResponse } from "@/src/types/loginTypes";
|
import { ILoginResponse } from "@/src/types/loginTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
|
|
||||||
export const loginController: RequestHandler = async (request, response) => {
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
const loginRequest = JSON.parse(String(request.body)) as ILoginRequest; // parse octet stream of json data to json object
|
const loginController: RequestHandler = async (request, response) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-argument
|
||||||
|
const body = JSON.parse(request.body); // parse octet stream of json data to json object
|
||||||
|
const loginRequest = toLoginRequest(body);
|
||||||
|
|
||||||
const account = await Account.findOne({ email: loginRequest.email });
|
const account = await Account.findOne({ email: loginRequest.email });
|
||||||
const nonce = Math.round(Math.random() * Number.MAX_SAFE_INTEGER);
|
const nonce = Math.round(Math.random() * Number.MAX_SAFE_INTEGER);
|
||||||
|
|
||||||
const buildLabel: string =
|
|
||||||
typeof request.query.buildLabel == "string"
|
|
||||||
? request.query.buildLabel.split(" ").join("+")
|
|
||||||
: buildConfig.buildLabel;
|
|
||||||
|
|
||||||
if (!account && config.autoCreateAccount && loginRequest.ClientType != "webui") {
|
if (!account && config.autoCreateAccount && loginRequest.ClientType != "webui") {
|
||||||
try {
|
try {
|
||||||
const nameFromEmail = loginRequest.email.substring(0, loginRequest.email.indexOf("@"));
|
|
||||||
let name = nameFromEmail;
|
|
||||||
if (await isNameTaken(name)) {
|
|
||||||
let suffix = 0;
|
|
||||||
do {
|
|
||||||
++suffix;
|
|
||||||
name = nameFromEmail + suffix;
|
|
||||||
} while (await isNameTaken(name));
|
|
||||||
}
|
|
||||||
const newAccount = await createAccount({
|
const newAccount = await createAccount({
|
||||||
email: loginRequest.email,
|
email: loginRequest.email,
|
||||||
password: loginRequest.password,
|
password: loginRequest.password,
|
||||||
DisplayName: name,
|
DisplayName: loginRequest.email.substring(0, loginRequest.email.indexOf("@")),
|
||||||
CountryCode: loginRequest.lang.toUpperCase(),
|
Nonce: nonce
|
||||||
ClientType: loginRequest.ClientType,
|
|
||||||
CrossPlatformAllowed: true,
|
|
||||||
ForceLogoutVersion: 0,
|
|
||||||
ConsentNeeded: false,
|
|
||||||
TrackedSettings: [],
|
|
||||||
Nonce: nonce,
|
|
||||||
LatestEventMessageDate: new Date(0)
|
|
||||||
});
|
});
|
||||||
logger.debug("created new account");
|
logger.debug("created new account");
|
||||||
response.json(createLoginResponse(newAccount, buildLabel));
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const { email, password, ...databaseAccount } = newAccount;
|
||||||
|
const newLoginResponse: ILoginResponse = {
|
||||||
|
...databaseAccount,
|
||||||
|
BuildLabel: buildConfig.buildLabel,
|
||||||
|
NatHash: "0",
|
||||||
|
SteamId: "0"
|
||||||
|
};
|
||||||
|
|
||||||
|
response.json(newLoginResponse);
|
||||||
return;
|
return;
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
@ -62,34 +55,18 @@ export const loginController: RequestHandler = async (request, response) => {
|
|||||||
if (account.Nonce == 0 || loginRequest.ClientType != "webui") {
|
if (account.Nonce == 0 || loginRequest.ClientType != "webui") {
|
||||||
account.Nonce = nonce;
|
account.Nonce = nonce;
|
||||||
}
|
}
|
||||||
if (loginRequest.ClientType != "webui") {
|
|
||||||
account.CountryCode = loginRequest.lang.toUpperCase();
|
|
||||||
}
|
|
||||||
await account.save();
|
await account.save();
|
||||||
|
|
||||||
response.json(createLoginResponse(account.toJSON(), buildLabel));
|
const { email, password, ...databaseAccount } = account.toJSON();
|
||||||
|
const newLoginResponse: ILoginResponse = {
|
||||||
|
...databaseAccount,
|
||||||
|
BuildLabel: buildConfig.buildLabel,
|
||||||
|
NatHash: "0",
|
||||||
|
SteamId: "0"
|
||||||
};
|
};
|
||||||
|
|
||||||
const createLoginResponse = (account: IDatabaseAccountJson, buildLabel: string): ILoginResponse => {
|
response.json(newLoginResponse);
|
||||||
return {
|
|
||||||
id: account.id,
|
|
||||||
DisplayName: account.DisplayName,
|
|
||||||
CountryCode: account.CountryCode,
|
|
||||||
ClientType: account.ClientType,
|
|
||||||
CrossPlatformAllowed: account.CrossPlatformAllowed,
|
|
||||||
ForceLogoutVersion: account.ForceLogoutVersion,
|
|
||||||
AmazonAuthToken: account.AmazonAuthToken,
|
|
||||||
AmazonRefreshToken: account.AmazonRefreshToken,
|
|
||||||
ConsentNeeded: account.ConsentNeeded,
|
|
||||||
TrackedSettings: account.TrackedSettings,
|
|
||||||
Nonce: account.Nonce,
|
|
||||||
Groups: [],
|
|
||||||
IRC: config.myIrcAddresses ?? [config.myAddress],
|
|
||||||
platformCDNs: config.platformCDNs,
|
|
||||||
HUB: config.hubAddress,
|
|
||||||
NRS: config.NRS,
|
|
||||||
DTLS: 99,
|
|
||||||
BuildLabel: buildLabel,
|
|
||||||
MatchmakingBuildId: buildConfig.matchmakingBuildId
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { loginController };
|
||||||
|
@ -2,6 +2,7 @@ import { RequestHandler } from "express";
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { Account } from "@/src/models/loginModel";
|
import { Account } from "@/src/models/loginModel";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
const logoutController: RequestHandler = async (req, res) => {
|
const logoutController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const account = await Account.findOne({ _id: accountId });
|
const account = await Account.findOne({ _id: accountId });
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
import { missionInventoryUpdate } from "@/src/services/inventoryService";
|
||||||
|
import { combineRewardAndLootInventory, getRewards } from "@/src/services/missionInventoryUpdateService";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IMissionInventoryUpdateRequest } from "@/src/types/requestTypes";
|
import { IMissionInventoryUpdateRequest } from "@/src/types/requestTypes";
|
||||||
import { addMissionInventoryUpdates, addMissionRewards } from "@/src/services/missionInventoryUpdateService";
|
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getInventoryResponse } from "./inventoryController";
|
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
**** INPUT ****
|
**** INPUT ****
|
||||||
- [ ] crossPlaySetting
|
- [ ] crossPlaySetting
|
||||||
@ -32,13 +30,13 @@ import { logger } from "@/src/utils/logger";
|
|||||||
- [ ] hosts
|
- [ ] hosts
|
||||||
- [x] ChallengeProgress
|
- [x] ChallengeProgress
|
||||||
- [ ] SeasonChallengeHistory
|
- [ ] SeasonChallengeHistory
|
||||||
- [ ] PS (anticheat data)
|
- [ ] PS (Passive anti-cheat data which includes your username, module list, process list, and system name.)
|
||||||
- [ ] ActiveDojoColorResearch
|
- [ ] ActiveDojoColorResearch
|
||||||
- [x] RewardInfo
|
- [x] RewardInfo
|
||||||
- [ ] ReceivedCeremonyMsg
|
- [ ] ReceivedCeremonyMsg
|
||||||
- [ ] LastCeremonyResetDate
|
- [ ] LastCeremonyResetDate
|
||||||
- [ ] MissionPTS (Used to validate the mission/alive time above.)
|
- [ ] MissionPTS (Used to validate the mission/alive time above.)
|
||||||
- [ ] RepHash
|
- [ ] RepHash (A hash from the replication manager/RepMgr Unknown what it does.)
|
||||||
- [ ] EndOfMatchUpload
|
- [ ] EndOfMatchUpload
|
||||||
- [ ] ObjectiveReached
|
- [ ] ObjectiveReached
|
||||||
- [ ] FpsAvg
|
- [ ] FpsAvg
|
||||||
@ -46,40 +44,37 @@ import { logger } from "@/src/utils/logger";
|
|||||||
- [ ] FpsMax
|
- [ ] FpsMax
|
||||||
- [ ] FpsSamples
|
- [ ] FpsSamples
|
||||||
*/
|
*/
|
||||||
//move credit calc in here, return MissionRewards: [] if no reward info
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const missionInventoryUpdateController: RequestHandler = async (req, res): Promise<void> => {
|
const missionInventoryUpdateController: RequestHandler = async (req, res): Promise<void> => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const missionReport = getJSONfromString<IMissionInventoryUpdateRequest>((req.body as string).toString());
|
|
||||||
logger.debug("mission report:", missionReport);
|
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
try {
|
||||||
const inventoryUpdates = addMissionInventoryUpdates(inventory, missionReport);
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call
|
||||||
|
const lootInventory = getJSONfromString(req.body.toString()) as IMissionInventoryUpdateRequest;
|
||||||
|
|
||||||
if (missionReport.MissionStatus !== "GS_SUCCESS") {
|
logger.debug("missionInventoryUpdate with lootInventory =", lootInventory);
|
||||||
await inventory.save();
|
|
||||||
const inventoryResponse = await getInventoryResponse(inventory, true);
|
const { InventoryChanges, MissionRewards } = getRewards(lootInventory);
|
||||||
|
|
||||||
|
const { combinedInventoryChanges, TotalCredits, CreditsBonus, MissionCredits } = combineRewardAndLootInventory(
|
||||||
|
InventoryChanges,
|
||||||
|
lootInventory
|
||||||
|
);
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const InventoryJson = JSON.stringify(await missionInventoryUpdate(combinedInventoryChanges, accountId));
|
||||||
res.json({
|
res.json({
|
||||||
InventoryJson: JSON.stringify(inventoryResponse),
|
// InventoryJson, // this part will reset game data and missions will be locked
|
||||||
MissionRewards: []
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { MissionRewards, inventoryChanges, credits } = await addMissionRewards(inventory, missionReport);
|
|
||||||
|
|
||||||
await inventory.save();
|
|
||||||
const inventoryResponse = await getInventoryResponse(inventory, true);
|
|
||||||
|
|
||||||
//TODO: figure out when to send inventory. it is needed for many cases.
|
|
||||||
res.json({
|
|
||||||
InventoryJson: JSON.stringify(inventoryResponse),
|
|
||||||
InventoryChanges: inventoryChanges,
|
|
||||||
MissionRewards,
|
MissionRewards,
|
||||||
...credits,
|
InventoryChanges,
|
||||||
...inventoryUpdates,
|
TotalCredits,
|
||||||
FusionPoints: inventoryChanges?.FusionPoints
|
CreditsBonus,
|
||||||
|
MissionCredits
|
||||||
});
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error parsing JSON data:", err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -92,3 +87,5 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
|
|||||||
- [x] InventoryChanges
|
- [x] InventoryChanges
|
||||||
- [x] FusionPoints
|
- [x] FusionPoints
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export { missionInventoryUpdateController };
|
||||||
|
@ -2,21 +2,10 @@ 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 { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import {
|
import { getInventory, updateCurrency, addEquipment, addMiscItems } from "@/src/services/inventoryService";
|
||||||
getInventory,
|
|
||||||
updateCurrency,
|
|
||||||
addEquipment,
|
|
||||||
addMiscItems,
|
|
||||||
applyDefaultUpgrades
|
|
||||||
} from "@/src/services/inventoryService";
|
|
||||||
import { ExportWeapons } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
const modularWeaponTypes: Record<string, TEquipmentKey> = {
|
const modularWeaponTypes: Record<string, TEquipmentKey> = {
|
||||||
"/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimary": "LongGuns",
|
|
||||||
"/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryBeam": "LongGuns",
|
"/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryBeam": "LongGuns",
|
||||||
"/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryLauncher": "LongGuns",
|
|
||||||
"/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryShotgun": "LongGuns",
|
|
||||||
"/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimarySniper": "LongGuns",
|
|
||||||
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary": "Pistols",
|
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary": "Pistols",
|
||||||
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryBeam": "Pistols",
|
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryBeam": "Pistols",
|
||||||
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryShotgun": "Pistols",
|
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryShotgun": "Pistols",
|
||||||
@ -34,22 +23,26 @@ interface IModularCraftRequest {
|
|||||||
Parts: string[];
|
Parts: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const modularWeaponCraftingController: RequestHandler = async (req, res) => {
|
export const modularWeaponCraftingController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const data = getJSONfromString<IModularCraftRequest>(String(req.body));
|
const data = getJSONfromString(String(req.body)) as IModularCraftRequest;
|
||||||
if (!(data.WeaponType in modularWeaponTypes)) {
|
if (!(data.WeaponType in modularWeaponTypes)) {
|
||||||
throw new Error(`unknown modular weapon type: ${data.WeaponType}`);
|
throw new Error(`unknown modular weapon type: ${data.WeaponType}`);
|
||||||
}
|
}
|
||||||
const category = modularWeaponTypes[data.WeaponType];
|
const category = modularWeaponTypes[data.WeaponType];
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
||||||
const configs = applyDefaultUpgrades(inventory, ExportWeapons[data.Parts[0]]?.defaultUpgrades);
|
|
||||||
|
|
||||||
// Give weapon
|
// Give weapon
|
||||||
const inventoryChanges = addEquipment(inventory, category, data.WeaponType, data.Parts, {}, { Configs: configs });
|
const weapon = await addEquipment(category, data.WeaponType, accountId, data.Parts);
|
||||||
|
|
||||||
// Remove credits & parts
|
// Remove credits
|
||||||
|
const currencyChanges = await updateCurrency(
|
||||||
|
category == "Hoverboards" || category == "MoaPets" ? 5000 : 4000,
|
||||||
|
false,
|
||||||
|
accountId
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remove parts
|
||||||
const miscItemChanges = [];
|
const miscItemChanges = [];
|
||||||
for (const part of data.Parts) {
|
for (const part of data.Parts) {
|
||||||
miscItemChanges.push({
|
miscItemChanges.push({
|
||||||
@ -57,19 +50,15 @@ export const modularWeaponCraftingController: RequestHandler = async (req, res)
|
|||||||
ItemCount: -1
|
ItemCount: -1
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const currencyChanges = updateCurrency(
|
const inventory = await getInventory(accountId);
|
||||||
inventory,
|
|
||||||
category == "Hoverboards" || category == "MoaPets" ? 5000 : 4000,
|
|
||||||
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: {
|
||||||
...inventoryChanges,
|
|
||||||
...currencyChanges,
|
...currencyChanges,
|
||||||
|
[category]: [weapon],
|
||||||
MiscItems: miscItemChanges
|
MiscItems: miscItemChanges
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -8,10 +8,11 @@ interface INameWeaponRequest {
|
|||||||
ItemName: string;
|
ItemName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const nameWeaponController: RequestHandler = async (req, res) => {
|
export const nameWeaponController: 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 body = getJSONfromString<INameWeaponRequest>(String(req.body));
|
const body = getJSONfromString(String(req.body)) as INameWeaponRequest;
|
||||||
const item = inventory[req.query.Category as string as TEquipmentKey].find(
|
const item = inventory[req.query.Category as string as TEquipmentKey].find(
|
||||||
item => item._id.toString() == (req.query.ItemId as string)
|
item => item._id.toString() == (req.query.ItemId as string)
|
||||||
)!;
|
)!;
|
||||||
@ -20,9 +21,8 @@ export const nameWeaponController: RequestHandler = async (req, res) => {
|
|||||||
} else {
|
} else {
|
||||||
item.ItemName = undefined;
|
item.ItemName = undefined;
|
||||||
}
|
}
|
||||||
const currencyChanges = updateCurrency(inventory, "webui" in req.query ? 0 : 15, true);
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
InventoryChanges: currencyChanges
|
InventoryChanges: await updateCurrency("webui" in req.query ? 0 : 15, true, accountId)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { IPlayerSkills } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const playerSkillsController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const request = getJSONfromString<IPlayerSkillsRequest>(String(req.body));
|
|
||||||
|
|
||||||
const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills];
|
|
||||||
const cost = (request.Pool == "LPP_DRIFTER" ? drifterCosts[oldRank] : 1 << oldRank) * 1000;
|
|
||||||
inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost;
|
|
||||||
inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++;
|
|
||||||
await inventory.save();
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
Pool: request.Pool,
|
|
||||||
PoolInc: -cost,
|
|
||||||
Skill: request.Skill,
|
|
||||||
Rank: oldRank + 1
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IPlayerSkillsRequest {
|
|
||||||
Pool: string;
|
|
||||||
Skill: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const drifterCosts = [20, 25, 30, 45, 65, 90, 125, 160, 205, 255];
|
|
@ -3,6 +3,7 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
|
|||||||
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
|
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
|
||||||
import { ExportRelics, IRelic } from "warframe-public-export-plus";
|
import { ExportRelics, IRelic } from "warframe-public-export-plus";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const projectionManagerController: RequestHandler = async (req, res) => {
|
export const projectionManagerController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
@ -50,7 +51,6 @@ const qualityKeywordToNumber: Record<VoidProjectionQuality, number> = {
|
|||||||
// e.g. "/Lotus/Types/Game/Projections/T2VoidProjectionProteaPrimeDBronze" -> ["Lith", "W5", "VPQ_BRONZE"]
|
// e.g. "/Lotus/Types/Game/Projections/T2VoidProjectionProteaPrimeDBronze" -> ["Lith", "W5", "VPQ_BRONZE"]
|
||||||
const parseProjection = (typeName: string): [string, string, VoidProjectionQuality] => {
|
const parseProjection = (typeName: string): [string, string, VoidProjectionQuality] => {
|
||||||
const relic: IRelic | undefined = ExportRelics[typeName];
|
const relic: IRelic | undefined = ExportRelics[typeName];
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
||||||
if (!relic) {
|
if (!relic) {
|
||||||
throw new Error(`Unknown projection ${typeName}`);
|
throw new Error(`Unknown projection ${typeName}`);
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IPurchaseRequest } from "@/src/types/purchaseTypes";
|
import { toPurchaseRequest } from "@/src/helpers/purchaseHelpers";
|
||||||
import { handlePurchase } from "@/src/services/purchaseService";
|
import { handlePurchase } from "@/src/services/purchaseService";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const purchaseController: RequestHandler = async (req, res) => {
|
export const purchaseController: RequestHandler = async (req, res) => {
|
||||||
const purchaseRequest = JSON.parse(String(req.body)) as IPurchaseRequest;
|
const purchaseRequest = toPurchaseRequest(JSON.parse(String(req.body)));
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(accountId);
|
const response = await handlePurchase(purchaseRequest, accountId);
|
||||||
const response = await handlePurchase(purchaseRequest, inventory);
|
|
||||||
await inventory.save();
|
|
||||||
res.json(response);
|
res.json(response);
|
||||||
};
|
};
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
import { getDojoClient, getGuildForRequest } from "@/src/services/guildService";
|
import { getGuildForRequest } from "@/src/services/guildService";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const queueDojoComponentDestructionController: RequestHandler = async (req, res) => {
|
export const queueDojoComponentDestructionController: RequestHandler = async (req, res) => {
|
||||||
const guild = await getGuildForRequest(req);
|
const guild = await getGuildForRequest(req);
|
||||||
const componentId = req.query.componentId as string;
|
const componentId = req.query.componentId as string;
|
||||||
const component = guild.DojoComponents!.splice(
|
guild.DojoComponents!.splice(
|
||||||
guild.DojoComponents!.findIndex(x => x._id.toString() === componentId),
|
guild.DojoComponents!.findIndex(x => x._id.toString() === componentId),
|
||||||
1
|
1
|
||||||
)[0];
|
);
|
||||||
const room = Object.values(ExportDojoRecipes.rooms).find(x => x.resultType == component.pf);
|
|
||||||
if (room) {
|
|
||||||
guild.DojoCapacity -= room.capacity;
|
|
||||||
guild.DojoEnergy -= room.energy;
|
|
||||||
}
|
|
||||||
await guild.save();
|
await guild.save();
|
||||||
res.json(getDojoClient(guild, 1));
|
res.json({
|
||||||
|
DojoRequestStatus: 1
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,66 +1,9 @@
|
|||||||
|
import { logger } from "@/src/utils/logger";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { IUnveiledRivenFingerprint, randomiseRivenStats } from "@/src/helpers/rivenFingerprintHelper";
|
|
||||||
import { ExportUpgrades } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
export const rerollRandomModController: RequestHandler = async (req, res) => {
|
const rerollRandomModController: RequestHandler = (_req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
logger.debug("RerollRandomMod Request", { info: _req.body.toString("hex").replace(/(.)(.)/g, "$1$2 ") });
|
||||||
const request = getJSONfromString<RerollRandomModRequest>(String(req.body));
|
res.json({});
|
||||||
if ("ItemIds" in request) {
|
|
||||||
const inventory = await getInventory(accountId, "Upgrades MiscItems");
|
|
||||||
const upgrade = inventory.Upgrades.id(request.ItemIds[0])!;
|
|
||||||
const fingerprint = JSON.parse(upgrade.UpgradeFingerprint!) as IUnveiledRivenFingerprint;
|
|
||||||
|
|
||||||
fingerprint.rerolls ??= 0;
|
|
||||||
const kuvaCost = fingerprint.rerolls < rerollCosts.length ? rerollCosts[fingerprint.rerolls] : 3500;
|
|
||||||
addMiscItems(inventory, [
|
|
||||||
{
|
|
||||||
ItemType: "/Lotus/Types/Items/MiscItems/Kuva",
|
|
||||||
ItemCount: kuvaCost * -1
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
fingerprint.rerolls++;
|
|
||||||
upgrade.UpgradeFingerprint = JSON.stringify(fingerprint);
|
|
||||||
|
|
||||||
randomiseRivenStats(ExportUpgrades[upgrade.ItemType], fingerprint);
|
|
||||||
upgrade.PendingRerollFingerprint = JSON.stringify(fingerprint);
|
|
||||||
|
|
||||||
await inventory.save();
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
changes: [
|
|
||||||
{
|
|
||||||
ItemId: { $oid: request.ItemIds[0] },
|
|
||||||
UpgradeFingerprint: upgrade.UpgradeFingerprint,
|
|
||||||
PendingRerollFingerprint: upgrade.PendingRerollFingerprint
|
|
||||||
}
|
|
||||||
],
|
|
||||||
cost: kuvaCost
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const inventory = await getInventory(accountId, "Upgrades");
|
|
||||||
const upgrade = inventory.Upgrades.id(request.ItemId)!;
|
|
||||||
if (request.CommitReroll && upgrade.PendingRerollFingerprint) {
|
|
||||||
upgrade.UpgradeFingerprint = upgrade.PendingRerollFingerprint;
|
|
||||||
}
|
|
||||||
upgrade.PendingRerollFingerprint = undefined;
|
|
||||||
await inventory.save();
|
|
||||||
res.send(upgrade.UpgradeFingerprint);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type RerollRandomModRequest = LetsGoGamblingRequest | AwDangitRequest;
|
export { rerollRandomModController };
|
||||||
|
|
||||||
interface LetsGoGamblingRequest {
|
|
||||||
ItemIds: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AwDangitRequest {
|
|
||||||
ItemId: string;
|
|
||||||
CommitReroll: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rerollCosts = [900, 1000, 1200, 1400, 1700, 2000, 2350, 2750, 3150];
|
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { ICompletedDialogue } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { logger } from "@/src/utils/logger";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const saveDialogueController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const request = JSON.parse(String(req.body)) as SaveDialogueRequest;
|
|
||||||
if ("YearIteration" in request) {
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
if (inventory.DialogueHistory) {
|
|
||||||
inventory.DialogueHistory.YearIteration = request.YearIteration;
|
|
||||||
} else {
|
|
||||||
inventory.DialogueHistory = { YearIteration: request.YearIteration };
|
|
||||||
}
|
|
||||||
await inventory.save();
|
|
||||||
res.end();
|
|
||||||
} else {
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
if (!inventory.DialogueHistory) {
|
|
||||||
throw new Error("bad inventory state");
|
|
||||||
}
|
|
||||||
if (request.QueuedDialogues.length != 0 || request.OtherDialogueInfos.length != 0) {
|
|
||||||
logger.error(`saveDialogue request not fully handled: ${String(req.body)}`);
|
|
||||||
}
|
|
||||||
inventory.DialogueHistory.Dialogues ??= [];
|
|
||||||
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),
|
|
||||||
Gifts: [],
|
|
||||||
Booleans: [],
|
|
||||||
Completed: [],
|
|
||||||
DialogueName: request.DialogueName
|
|
||||||
}) - 1
|
|
||||||
];
|
|
||||||
}
|
|
||||||
dialogue.Rank = request.Rank;
|
|
||||||
dialogue.Chemistry = request.Chemistry;
|
|
||||||
//dialogue.QueuedDialogues = request.QueuedDialogues;
|
|
||||||
for (const bool of request.Booleans) {
|
|
||||||
dialogue.Booleans.push(bool);
|
|
||||||
}
|
|
||||||
for (const bool of request.ResetBooleans) {
|
|
||||||
const index = dialogue.Booleans.findIndex(x => x == bool);
|
|
||||||
if (index != -1) {
|
|
||||||
dialogue.Booleans.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dialogue.Completed.push(request.Data);
|
|
||||||
const tomorrowAt0Utc = (Math.trunc(Date.now() / (86400 * 1000)) + 1) * 86400 * 1000;
|
|
||||||
dialogue.AvailableDate = new Date(tomorrowAt0Utc);
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: [],
|
|
||||||
AvailableDate: { $date: { $numberLong: tomorrowAt0Utc.toString() } }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
type SaveDialogueRequest = SaveYearIterationRequest | SaveCompletedDialogueRequest;
|
|
||||||
|
|
||||||
interface SaveYearIterationRequest {
|
|
||||||
YearIteration: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SaveCompletedDialogueRequest {
|
|
||||||
DialogueName: string;
|
|
||||||
Rank: number;
|
|
||||||
Chemistry: number;
|
|
||||||
CompletionType: number;
|
|
||||||
QueuedDialogues: string[]; // unsure
|
|
||||||
Booleans: string[];
|
|
||||||
ResetBooleans: string[];
|
|
||||||
Data: ICompletedDialogue;
|
|
||||||
OtherDialogueInfos: string[]; // unsure
|
|
||||||
}
|
|
@ -4,6 +4,7 @@ import { handleInventoryItemConfigChange } from "@/src/services/saveLoadoutServi
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const saveLoadoutController: RequestHandler = async (req, res) => {
|
export const saveLoadoutController: RequestHandler = async (req, res) => {
|
||||||
//validate here
|
//validate here
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
import { ISettings } from "../../types/inventoryTypes/inventoryTypes";
|
|
||||||
|
|
||||||
interface ISaveSettingsRequest {
|
|
||||||
Settings: ISettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
const saveSettingsController: RequestHandler = async (req, res): Promise<void> => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
|
|
||||||
const settingResults = getJSONfromString<ISaveSettingsRequest>(String(req.body));
|
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
inventory.Settings = Object.assign(inventory.Settings, settingResults.Settings);
|
|
||||||
await inventory.save();
|
|
||||||
res.json(inventory.Settings);
|
|
||||||
};
|
|
||||||
|
|
||||||
export { saveSettingsController };
|
|
@ -1,7 +1,9 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
import { ISellRequest } from "@/src/types/sellTypes";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getInventory, addMods, addRecipes, addMiscItems, addConsumables } from "@/src/services/inventoryService";
|
import { getInventory, addMods, addRecipes } from "@/src/services/inventoryService";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
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);
|
||||||
@ -12,20 +14,6 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
inventory.RegularCredits += payload.SellPrice;
|
inventory.RegularCredits += payload.SellPrice;
|
||||||
} else if (payload.SellCurrency == "SC_FusionPoints") {
|
} else if (payload.SellCurrency == "SC_FusionPoints") {
|
||||||
inventory.FusionPoints += payload.SellPrice;
|
inventory.FusionPoints += payload.SellPrice;
|
||||||
} else if (payload.SellCurrency == "SC_PrimeBucks") {
|
|
||||||
addMiscItems(inventory, [
|
|
||||||
{
|
|
||||||
ItemType: "/Lotus/Types/Items/MiscItems/PrimeBucks",
|
|
||||||
ItemCount: payload.SellPrice
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
} else if (payload.SellCurrency == "SC_DistillPoints") {
|
|
||||||
addMiscItems(inventory, [
|
|
||||||
{
|
|
||||||
ItemType: "/Lotus/Types/Items/MiscItems/DistillPoints",
|
|
||||||
ItemCount: payload.SellPrice
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Unknown SellCurrency: " + payload.SellCurrency);
|
throw new Error("Unknown SellCurrency: " + payload.SellCurrency);
|
||||||
}
|
}
|
||||||
@ -51,51 +39,6 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
inventory.Melee.pull({ _id: sellItem.String });
|
inventory.Melee.pull({ _id: sellItem.String });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (payload.Items.SpaceSuits) {
|
|
||||||
payload.Items.SpaceSuits.forEach(sellItem => {
|
|
||||||
inventory.SpaceSuits.pull({ _id: sellItem.String });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (payload.Items.SpaceGuns) {
|
|
||||||
payload.Items.SpaceGuns.forEach(sellItem => {
|
|
||||||
inventory.SpaceGuns.pull({ _id: sellItem.String });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (payload.Items.SpaceMelee) {
|
|
||||||
payload.Items.SpaceMelee.forEach(sellItem => {
|
|
||||||
inventory.SpaceMelee.pull({ _id: sellItem.String });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (payload.Items.Sentinels) {
|
|
||||||
payload.Items.Sentinels.forEach(sellItem => {
|
|
||||||
inventory.Sentinels.pull({ _id: sellItem.String });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (payload.Items.SentinelWeapons) {
|
|
||||||
payload.Items.SentinelWeapons.forEach(sellItem => {
|
|
||||||
inventory.SentinelWeapons.pull({ _id: sellItem.String });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (payload.Items.OperatorAmps) {
|
|
||||||
payload.Items.OperatorAmps.forEach(sellItem => {
|
|
||||||
inventory.OperatorAmps.pull({ _id: sellItem.String });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (payload.Items.Hoverboards) {
|
|
||||||
payload.Items.Hoverboards.forEach(sellItem => {
|
|
||||||
inventory.Hoverboards.pull({ _id: sellItem.String });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (payload.Items.Consumables) {
|
|
||||||
const consumablesChanges = [];
|
|
||||||
for (const sellItem of payload.Items.Consumables) {
|
|
||||||
consumablesChanges.push({
|
|
||||||
ItemType: sellItem.String,
|
|
||||||
ItemCount: sellItem.Count * -1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
addConsumables(inventory, consumablesChanges);
|
|
||||||
}
|
|
||||||
if (payload.Items.Recipes) {
|
if (payload.Items.Recipes) {
|
||||||
const recipeChanges = [];
|
const recipeChanges = [];
|
||||||
for (const sellItem of payload.Items.Recipes) {
|
for (const sellItem of payload.Items.Recipes) {
|
||||||
@ -120,51 +63,7 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (payload.Items.MiscItems) {
|
|
||||||
payload.Items.MiscItems.forEach(sellItem => {
|
|
||||||
addMiscItems(inventory, [
|
|
||||||
{
|
|
||||||
ItemType: sellItem.String,
|
|
||||||
ItemCount: sellItem.Count * -1
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({});
|
res.json({});
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ISellRequest {
|
|
||||||
Items: {
|
|
||||||
Suits?: ISellItem[];
|
|
||||||
LongGuns?: ISellItem[];
|
|
||||||
Pistols?: ISellItem[];
|
|
||||||
Melee?: ISellItem[];
|
|
||||||
Consumables?: ISellItem[];
|
|
||||||
Recipes?: ISellItem[];
|
|
||||||
Upgrades?: ISellItem[];
|
|
||||||
MiscItems?: ISellItem[];
|
|
||||||
SpaceSuits?: ISellItem[];
|
|
||||||
SpaceGuns?: ISellItem[];
|
|
||||||
SpaceMelee?: ISellItem[];
|
|
||||||
Sentinels?: ISellItem[];
|
|
||||||
SentinelWeapons?: ISellItem[];
|
|
||||||
OperatorAmps?: ISellItem[];
|
|
||||||
Hoverboards?: ISellItem[];
|
|
||||||
};
|
|
||||||
SellPrice: number;
|
|
||||||
SellCurrency:
|
|
||||||
| "SC_RegularCredits"
|
|
||||||
| "SC_PrimeBucks"
|
|
||||||
| "SC_FusionPoints"
|
|
||||||
| "SC_DistillPoints"
|
|
||||||
| "SC_CrewShipFusionPoints"
|
|
||||||
| "SC_Resources";
|
|
||||||
buildLabel: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ISellItem {
|
|
||||||
String: string; // oid or uniqueName
|
|
||||||
Count: number;
|
|
||||||
}
|
|
||||||
|
@ -1,18 +1,7 @@
|
|||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const setActiveQuestController: RequestHandler<
|
const setActiveQuestController: RequestHandler = (_req, res) => {
|
||||||
Record<string, never>,
|
res.sendStatus(200);
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
{ quest: string | undefined }
|
|
||||||
> = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const quest = req.query.quest;
|
|
||||||
|
|
||||||
const inventory = await getInventory(accountId, "ActiveQuest");
|
|
||||||
inventory.ActiveQuest = quest ?? "";
|
|
||||||
await inventory.save();
|
|
||||||
res.status(200).end();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { setActiveQuestController };
|
||||||
|
@ -4,6 +4,7 @@ import { parseString } from "@/src/helpers/general";
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const setActiveShipController: RequestHandler = async (req, res) => {
|
export const setActiveShipController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const shipId = parseString(req.query.shipId);
|
const shipId = parseString(req.query.shipId);
|
||||||
|
@ -2,23 +2,12 @@ import { RequestHandler } from "express";
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
||||||
import { TBootLocation } from "@/src/types/shipTypes";
|
import { TBootLocation } from "@/src/types/shipTypes";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const setBootLocationController: RequestHandler = async (req, res) => {
|
export const setBootLocationController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const personalRooms = await getPersonalRooms(accountId);
|
const personalRooms = await getPersonalRooms(accountId);
|
||||||
personalRooms.Ship.BootLocation = req.query.bootLocation as string as TBootLocation;
|
personalRooms.Ship.BootLocation = req.query.bootLocation as string as TBootLocation;
|
||||||
await personalRooms.save();
|
await personalRooms.save();
|
||||||
|
|
||||||
if (personalRooms.Ship.BootLocation == "SHOP") {
|
|
||||||
// Temp fix so the motorcycle in the backroom doesn't appear broken.
|
|
||||||
// This code may be removed when quests are fully implemented.
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
if (inventory.Motorcycles.length == 0) {
|
|
||||||
inventory.Motorcycles.push({ ItemType: "/Lotus/Types/Vehicles/Motorcycle/MotorcyclePowerSuit" });
|
|
||||||
await inventory.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res.end();
|
res.end();
|
||||||
};
|
};
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { getDojoClient, getGuildForRequest } from "@/src/services/guildService";
|
|
||||||
|
|
||||||
export const setDojoComponentMessageController: RequestHandler = async (req, res) => {
|
|
||||||
const guild = await getGuildForRequest(req);
|
|
||||||
// At this point, we know that a member of the guild is making this request. Assuming they are allowed to change the message.
|
|
||||||
const component = guild.DojoComponents!.find(x => x._id.equals(req.query.componentId as string))!;
|
|
||||||
const payload = JSON.parse(String(req.body)) as SetDojoComponentMessageRequest;
|
|
||||||
if ("Name" in payload) {
|
|
||||||
component.Name = payload.Name;
|
|
||||||
} else {
|
|
||||||
component.Message = payload.Message;
|
|
||||||
}
|
|
||||||
await guild.save();
|
|
||||||
res.json(getDojoClient(guild, 1));
|
|
||||||
};
|
|
||||||
|
|
||||||
type SetDojoComponentMessageRequest = { Name: string } | { Message: string };
|
|
@ -1,17 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
|
|
||||||
export const setEquippedInstrumentController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const body = getJSONfromString<ISetEquippedInstrumentRequest>(String(req.body));
|
|
||||||
inventory.EquippedInstrument = body.Instrument;
|
|
||||||
await inventory.save();
|
|
||||||
res.end();
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ISetEquippedInstrumentRequest {
|
|
||||||
Instrument: string;
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { ISetPlacedDecoInfoRequest } from "@/src/types/shipTypes";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
import { handleSetPlacedDecoInfo } from "@/src/services/shipCustomizationsService";
|
|
||||||
|
|
||||||
export const setPlacedDecoInfoController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const payload = JSON.parse(req.body as string) as ISetPlacedDecoInfoRequest;
|
|
||||||
await handleSetPlacedDecoInfo(accountId, payload);
|
|
||||||
res.end();
|
|
||||||
};
|
|
@ -1,15 +1,14 @@
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { setShipCustomizations } from "@/src/services/shipCustomizationsService";
|
import { setShipCustomizations } from "@/src/services/shipCustomizationsService";
|
||||||
import { ISetShipCustomizationsRequest } from "@/src/types/shipTypes";
|
import { ISetShipCustomizationsRequest } from "@/src/types/shipTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const setShipCustomizationsController: RequestHandler = async (req, res) => {
|
export const setShipCustomizationsController: RequestHandler = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const setShipCustomizationsRequest = JSON.parse(req.body as string) as ISetShipCustomizationsRequest;
|
const setShipCustomizationsRequest = JSON.parse(req.body as string) as ISetShipCustomizationsRequest;
|
||||||
|
|
||||||
const setShipCustomizationsResponse = await setShipCustomizations(accountId, setShipCustomizationsRequest);
|
const setShipCustomizationsResponse = await setShipCustomizations(setShipCustomizationsRequest);
|
||||||
res.json(setShipCustomizationsResponse);
|
res.json(setShipCustomizationsResponse);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
|
||||||
import { IOid } from "@/src/types/commonTypes";
|
|
||||||
import { Types } from "mongoose";
|
|
||||||
|
|
||||||
export const setShipFavouriteLoadoutController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const personalRooms = await getPersonalRooms(accountId);
|
|
||||||
const body = JSON.parse(String(req.body)) as ISetShipFavouriteLoadoutRequest;
|
|
||||||
if (body.BootLocation != "SHOP") {
|
|
||||||
throw new Error(`unexpected BootLocation: ${body.BootLocation}`);
|
|
||||||
}
|
|
||||||
const display = personalRooms.TailorShop.FavouriteLoadouts.find(x => x.Tag == body.TagName);
|
|
||||||
if (display) {
|
|
||||||
display.LoadoutId = new Types.ObjectId(body.FavouriteLoadoutId.$oid);
|
|
||||||
} else {
|
|
||||||
personalRooms.TailorShop.FavouriteLoadouts.push({
|
|
||||||
Tag: body.TagName,
|
|
||||||
LoadoutId: new Types.ObjectId(body.FavouriteLoadoutId.$oid)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
await personalRooms.save();
|
|
||||||
res.json({});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ISetShipFavouriteLoadoutRequest {
|
|
||||||
BootLocation: string;
|
|
||||||
FavouriteLoadoutId: IOid;
|
|
||||||
TagName: string;
|
|
||||||
}
|
|
@ -2,6 +2,7 @@ import { RequestHandler } from "express";
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const setSupportedSyndicateController: RequestHandler = async (req, res) => {
|
export const setSupportedSyndicateController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
|
@ -4,10 +4,11 @@ import { getInventory } from "@/src/services/inventoryService";
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { WeaponTypeInternal } from "@/src/services/itemDataService";
|
import { WeaponTypeInternal } from "@/src/services/itemDataService";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const setWeaponSkillTreeController: RequestHandler = async (req, res) => {
|
export const setWeaponSkillTreeController: 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 payload = getJSONfromString<ISetWeaponSkillTreeRequest>(String(req.body));
|
const payload = getJSONfromString(String(req.body)) as ISetWeaponSkillTreeRequest;
|
||||||
|
|
||||||
const item = inventory[req.query.Category as WeaponTypeInternal].find(
|
const item = inventory[req.query.Category as WeaponTypeInternal].find(
|
||||||
item => item._id.toString() == (req.query.ItemId as string)
|
item => item._id.toString() == (req.query.ItemId as string)
|
||||||
|
@ -4,6 +4,7 @@ import { logger } from "@/src/utils/logger";
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { handleSetShipDecorations } from "@/src/services/shipCustomizationsService";
|
import { handleSetShipDecorations } from "@/src/services/shipCustomizationsService";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const shipDecorationsController: RequestHandler = async (req, res) => {
|
export const shipDecorationsController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const shipDecorationsRequest = JSON.parse(req.body as string) as IShipDecorationsRequest;
|
const shipDecorationsRequest = JSON.parse(req.body as string) as IShipDecorationsRequest;
|
||||||
@ -13,7 +14,7 @@ export const shipDecorationsController: RequestHandler = async (req, res) => {
|
|||||||
res.send(placedDecoration);
|
res.send(placedDecoration);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
logger.error(`error in shipDecorationsController: ${error.message}`);
|
logger.error(`error in saveLoadoutController: ${error.message}`);
|
||||||
res.status(400).json({ error: error.message });
|
res.status(400).json({ error: error.message });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,29 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { IDojoComponentClient } from "@/src/types/guildTypes";
|
import { IDojoComponentClient } from "@/src/types/guildTypes";
|
||||||
import { getDojoClient, getGuildForRequest } from "@/src/services/guildService";
|
import { getGuildForRequest } from "@/src/services/guildService";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
interface IStartDojoRecipeRequest {
|
interface IStartDojoRecipeRequest {
|
||||||
PlacedComponent: IDojoComponentClient;
|
PlacedComponent: IDojoComponentClient;
|
||||||
Revision: number;
|
Revision: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const startDojoRecipeController: RequestHandler = async (req, res) => {
|
export const startDojoRecipeController: RequestHandler = async (req, res) => {
|
||||||
const guild = await getGuildForRequest(req);
|
const guild = await getGuildForRequest(req);
|
||||||
// At this point, we know that a member of the guild is making this request. Assuming they are allowed to start a build.
|
// At this point, we know that a member of the guild is making this request. Assuming they are allowed to start a build.
|
||||||
const request = JSON.parse(String(req.body)) as IStartDojoRecipeRequest;
|
const request = JSON.parse(String(req.body)) as IStartDojoRecipeRequest;
|
||||||
|
|
||||||
const room = Object.values(ExportDojoRecipes.rooms).find(x => x.resultType == request.PlacedComponent.pf);
|
|
||||||
if (room) {
|
|
||||||
guild.DojoCapacity += room.capacity;
|
|
||||||
guild.DojoEnergy += room.energy;
|
|
||||||
}
|
|
||||||
|
|
||||||
guild.DojoComponents!.push({
|
guild.DojoComponents!.push({
|
||||||
_id: new Types.ObjectId(),
|
_id: new Types.ObjectId(),
|
||||||
pf: request.PlacedComponent.pf,
|
pf: request.PlacedComponent.pf,
|
||||||
ppf: request.PlacedComponent.ppf,
|
ppf: request.PlacedComponent.ppf,
|
||||||
pi: new Types.ObjectId(request.PlacedComponent.pi!.$oid),
|
pi: new Types.ObjectId(request.PlacedComponent.pi!.$id),
|
||||||
op: request.PlacedComponent.op,
|
op: request.PlacedComponent.op,
|
||||||
pp: request.PlacedComponent.pp,
|
pp: request.PlacedComponent.pp,
|
||||||
CompletionTime: new Date(Date.now()) // TOOD: Omit this field & handle the "Collecting Materials" state.
|
CompletionTime: new Date(Date.now()) // TOOD: Omit this field & handle the "Collecting Materials" state.
|
||||||
});
|
});
|
||||||
await guild.save();
|
await guild.save();
|
||||||
res.json(getDojoClient(guild, 0));
|
res.json({
|
||||||
|
DojoRequestStatus: 0
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const startLibraryPersonalTargetController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
inventory.LibraryPersonalTarget = req.query.target as string;
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
IsQuest: false,
|
|
||||||
Target: req.query.target
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,106 +1,21 @@
|
|||||||
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 { startRecipe } from "@/src/services/recipeService";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getRecipe } from "@/src/services/itemDataService";
|
|
||||||
import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
|
||||||
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
|
||||||
import { Types } from "mongoose";
|
|
||||||
import { ISpectreLoadout } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
|
|
||||||
interface IStartRecipeRequest {
|
interface IStartRecipeRequest {
|
||||||
RecipeName: string;
|
RecipeName: string;
|
||||||
Ids: string[];
|
Ids: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const startRecipeController: RequestHandler = async (req, res) => {
|
export const startRecipeController: RequestHandler = async (req, res) => {
|
||||||
const startRecipeRequest = getJSONfromString<IStartRecipeRequest>(String(req.body));
|
const startRecipeRequest = getJSONfromString(String(req.body)) as IStartRecipeRequest;
|
||||||
logger.debug("StartRecipe Request", { startRecipeRequest });
|
logger.debug("StartRecipe Request", { startRecipeRequest });
|
||||||
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|
||||||
const recipeName = startRecipeRequest.RecipeName;
|
const newRecipeId = await startRecipe(startRecipeRequest.RecipeName, accountId);
|
||||||
const recipe = getRecipe(recipeName);
|
res.json(newRecipeId);
|
||||||
|
|
||||||
if (!recipe) {
|
|
||||||
throw new Error(`unknown recipe ${recipeName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ingredientsInverse = recipe.ingredients.map(component => ({
|
|
||||||
ItemType: component.ItemType,
|
|
||||||
ItemCount: component.ItemCount * -1
|
|
||||||
}));
|
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
updateCurrency(inventory, recipe.buildPrice, false);
|
|
||||||
addMiscItems(inventory, ingredientsInverse);
|
|
||||||
|
|
||||||
//buildtime is in seconds
|
|
||||||
const completionDate = new Date(Date.now() + recipe.buildTime * unixTimesInMs.second);
|
|
||||||
|
|
||||||
inventory.PendingRecipes.push({
|
|
||||||
ItemType: recipeName,
|
|
||||||
CompletionDate: completionDate,
|
|
||||||
_id: new Types.ObjectId()
|
|
||||||
});
|
|
||||||
|
|
||||||
if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") {
|
|
||||||
const spectreLoadout: ISpectreLoadout = {
|
|
||||||
ItemType: recipe.resultType,
|
|
||||||
Suits: "",
|
|
||||||
LongGuns: "",
|
|
||||||
Pistols: "",
|
|
||||||
Melee: ""
|
|
||||||
};
|
|
||||||
for (
|
|
||||||
let secretIngredientsIndex = 0;
|
|
||||||
secretIngredientsIndex != recipe.secretIngredients!.length;
|
|
||||||
++secretIngredientsIndex
|
|
||||||
) {
|
|
||||||
const type = recipe.secretIngredients![secretIngredientsIndex].ItemType;
|
|
||||||
const oid = startRecipeRequest.Ids[recipe.ingredients.length + secretIngredientsIndex];
|
|
||||||
if (oid == "ffffffffffffffffffffffff") {
|
|
||||||
// user chose to preserve the active loadout
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (type == "/Lotus/Types/Game/PowerSuits/PlayerPowerSuit") {
|
|
||||||
const item = inventory.Suits.id(oid)!;
|
|
||||||
spectreLoadout.Suits = item.ItemType;
|
|
||||||
} else if (type == "/Lotus/Weapons/Tenno/Pistol/LotusPistol") {
|
|
||||||
const item = inventory.Pistols.id(oid)!;
|
|
||||||
spectreLoadout.Pistols = item.ItemType;
|
|
||||||
spectreLoadout.PistolsModularParts = item.ModularParts;
|
|
||||||
} else if (type == "/Lotus/Weapons/Tenno/LotusLongGun") {
|
|
||||||
const item = inventory.LongGuns.id(oid)!;
|
|
||||||
spectreLoadout.LongGuns = item.ItemType;
|
|
||||||
spectreLoadout.LongGunsModularParts = item.ModularParts;
|
|
||||||
} else {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
||||||
console.assert(type == "/Lotus/Types/Game/LotusMeleeWeapon");
|
|
||||||
const item = inventory.Melee.id(oid)!;
|
|
||||||
spectreLoadout.Melee = item.ItemType;
|
|
||||||
spectreLoadout.MeleeModularParts = item.ModularParts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
spectreLoadout.Suits != "" &&
|
|
||||||
spectreLoadout.LongGuns != "" &&
|
|
||||||
spectreLoadout.Pistols != "" &&
|
|
||||||
spectreLoadout.Melee != ""
|
|
||||||
) {
|
|
||||||
inventory.PendingSpectreLoadouts ??= [];
|
|
||||||
const existingIndex = inventory.PendingSpectreLoadouts.findIndex(x => x.ItemType == recipe.resultType);
|
|
||||||
if (existingIndex != -1) {
|
|
||||||
inventory.PendingSpectreLoadouts.splice(existingIndex, 1);
|
|
||||||
}
|
|
||||||
inventory.PendingSpectreLoadouts.push(spectreLoadout);
|
|
||||||
logger.debug("pending spectre loadout", spectreLoadout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const newInventory = await inventory.save();
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
RecipeId: { $oid: newInventory.PendingRecipes[newInventory.PendingRecipes.length - 1]._id.toString() }
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
@ -3,6 +3,7 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
|
|||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { IStepSequencer } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IStepSequencer } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const stepSequencersController: RequestHandler = async (req, res) => {
|
export const stepSequencersController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
|
@ -1,84 +1,25 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
|
import { syndicateSacrifice } from "@/src/services/inventoryService";
|
||||||
|
import { ISyndicateSacrifice } from "@/src/types/syndicateTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { ExportSyndicates, ISyndicateSacrifice } from "warframe-public-export-plus";
|
|
||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
|
||||||
import { addMiscItems, combineInventoryChanges, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
|
||||||
|
|
||||||
export const syndicateSacrificeController: RequestHandler = async (request, response) => {
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
|
const syndicateSacrificeController: RequestHandler = async (request, response) => {
|
||||||
const accountId = await getAccountIdForRequest(request);
|
const accountId = await getAccountIdForRequest(request);
|
||||||
const inventory = await getInventory(accountId);
|
const update = getJSONfromString(String(request.body)) as ISyndicateSacrifice;
|
||||||
const data = getJSONfromString<ISyndicateSacrificeRequest>(String(request.body));
|
let reply = {};
|
||||||
|
try {
|
||||||
let syndicate = inventory.Affiliations.find(x => x.Tag == data.AffiliationTag);
|
if (typeof update !== "object") {
|
||||||
if (!syndicate) {
|
throw new Error("Invalid data format");
|
||||||
syndicate = inventory.Affiliations[inventory.Affiliations.push({ Tag: data.AffiliationTag, Standing: 0 }) - 1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const level = data.SacrificeLevel - (syndicate.Title ?? 0);
|
reply = await syndicateSacrifice(update, accountId);
|
||||||
const res: ISyndicateSacrificeResponse = {
|
} catch (err) {
|
||||||
AffiliationTag: data.AffiliationTag,
|
console.error("Error parsing JSON data:", err);
|
||||||
InventoryChanges: {},
|
}
|
||||||
Level: data.SacrificeLevel,
|
|
||||||
LevelIncrease: level <= 0 ? 1 : level,
|
response.json(reply);
|
||||||
NewEpisodeReward: syndicate.Tag == "RadioLegionIntermission9Syndicate"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const manifest = ExportSyndicates[data.AffiliationTag];
|
export { syndicateSacrificeController };
|
||||||
let sacrifice: ISyndicateSacrifice | undefined;
|
|
||||||
let reward: string | undefined;
|
|
||||||
if (data.SacrificeLevel == 0) {
|
|
||||||
sacrifice = manifest.initiationSacrifice;
|
|
||||||
reward = manifest.initiationReward;
|
|
||||||
syndicate.Initiated = true;
|
|
||||||
} else {
|
|
||||||
sacrifice = manifest.titles?.find(x => x.level == data.SacrificeLevel)?.sacrifice;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sacrifice) {
|
|
||||||
res.InventoryChanges = { ...updateCurrency(inventory, sacrifice.credits, false) };
|
|
||||||
|
|
||||||
const miscItemChanges = sacrifice.items.map(x => ({
|
|
||||||
ItemType: x.ItemType,
|
|
||||||
ItemCount: x.ItemCount * -1
|
|
||||||
}));
|
|
||||||
addMiscItems(inventory, miscItemChanges);
|
|
||||||
res.InventoryChanges.MiscItems = miscItemChanges;
|
|
||||||
}
|
|
||||||
|
|
||||||
syndicate.Title ??= 0;
|
|
||||||
syndicate.Title += 1;
|
|
||||||
|
|
||||||
if (syndicate.Title > 0 && manifest.favours.length != 0) {
|
|
||||||
syndicate.FreeFavorsEarned ??= [];
|
|
||||||
if (!syndicate.FreeFavorsEarned.includes(syndicate.Title)) {
|
|
||||||
syndicate.FreeFavorsEarned.push(syndicate.Title);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reward) {
|
|
||||||
combineInventoryChanges(
|
|
||||||
res.InventoryChanges,
|
|
||||||
(await handleStoreItemAcquisition(reward, inventory)).InventoryChanges
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
await inventory.save();
|
|
||||||
|
|
||||||
response.json(res);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ISyndicateSacrificeRequest {
|
|
||||||
AffiliationTag: string;
|
|
||||||
SacrificeLevel: number;
|
|
||||||
AllowMultiple: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ISyndicateSacrificeResponse {
|
|
||||||
AffiliationTag: string;
|
|
||||||
Level: number;
|
|
||||||
LevelIncrease: number;
|
|
||||||
InventoryChanges: IInventoryChanges;
|
|
||||||
NewEpisodeReward: boolean;
|
|
||||||
}
|
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { addMiscItems, getInventory, getStandingLimit, updateStandingLimit } from "@/src/services/inventoryService";
|
|
||||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { IOid } from "@/src/types/commonTypes";
|
|
||||||
import { ExportSyndicates } from "warframe-public-export-plus";
|
|
||||||
import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper";
|
|
||||||
|
|
||||||
export const syndicateStandingBonusController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const request = JSON.parse(String(req.body)) as ISyndicateStandingBonusRequest;
|
|
||||||
|
|
||||||
const syndicateMeta = ExportSyndicates[request.Operation.AffiliationTag];
|
|
||||||
|
|
||||||
let gainedStanding = 0;
|
|
||||||
request.Operation.Items.forEach(item => {
|
|
||||||
const medallion = (syndicateMeta.medallions ?? []).find(medallion => medallion.itemType == item.ItemType);
|
|
||||||
if (medallion) {
|
|
||||||
gainedStanding += medallion.standing * item.ItemCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
item.ItemCount *= -1;
|
|
||||||
});
|
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
addMiscItems(inventory, request.Operation.Items);
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: {
|
|
||||||
MiscItems: request.Operation.Items
|
|
||||||
},
|
|
||||||
AffiliationMods: [
|
|
||||||
{
|
|
||||||
Tag: request.Operation.AffiliationTag,
|
|
||||||
Standing: gainedStanding
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ISyndicateStandingBonusRequest {
|
|
||||||
Operation: {
|
|
||||||
AffiliationTag: string;
|
|
||||||
AlternateBonusReward: ""; // ???
|
|
||||||
Items: IMiscItem[];
|
|
||||||
};
|
|
||||||
ModularWeaponId: IOid; // Seems to just be "000000000000000000000000", also note there's a "Category" query field
|
|
||||||
}
|
|
@ -2,20 +2,18 @@ import { RequestHandler } from "express";
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { ITaunt } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { ITaunt } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const tauntHistoryController: RequestHandler = async (req, res) => {
|
export const tauntHistoryController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
|
if (req.body !== undefined) {
|
||||||
const clientTaunt = JSON.parse(String(req.body)) as ITaunt;
|
const clientTaunt = JSON.parse(String(req.body)) as ITaunt;
|
||||||
logger.debug(`updating taunt ${clientTaunt.node} to state ${clientTaunt.state}`);
|
|
||||||
inventory.TauntHistory ??= [];
|
inventory.TauntHistory ??= [];
|
||||||
const taunt = inventory.TauntHistory.find(x => x.node == clientTaunt.node);
|
|
||||||
if (taunt) {
|
|
||||||
taunt.state = clientTaunt.state;
|
|
||||||
} else {
|
|
||||||
inventory.TauntHistory.push(clientTaunt);
|
inventory.TauntHistory.push(clientTaunt);
|
||||||
}
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.end();
|
res.end();
|
||||||
|
} else {
|
||||||
|
res.json({});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,30 +1,24 @@
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { IMongoDate } from "@/src/types/commonTypes";
|
import { IMongoDate } from "@/src/types/commonTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
|
||||||
|
|
||||||
interface ITrainingResultsRequest {
|
|
||||||
numLevelsGained: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ITrainingResultsResponse {
|
interface ITrainingResultsResponse {
|
||||||
NewTrainingDate: IMongoDate;
|
NewTrainingDate: IMongoDate;
|
||||||
NewLevel: number;
|
NewLevel: number;
|
||||||
InventoryChanges: IInventoryChanges;
|
InventoryChanges: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
const trainingResultController: RequestHandler = async (req, res): Promise<void> => {
|
const trainingResultController: RequestHandler = async (req, res): Promise<void> => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const numLevelsGained = parseInt(req.query.numLevelsGained as string);
|
||||||
const trainingResults = getJSONfromString<ITrainingResultsRequest>(String(req.body));
|
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
|
console.log(req.query);
|
||||||
|
inventory.TrainingDate = new Date(Date.now() + unixTimesInMs.day);
|
||||||
|
|
||||||
if (trainingResults.numLevelsGained == 1) {
|
if (numLevelsGained == 1) {
|
||||||
inventory.TrainingDate = new Date(Date.now() + unixTimesInMs.hour * 23);
|
|
||||||
inventory.PlayerLevel += 1;
|
inventory.PlayerLevel += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,8 +28,8 @@ const trainingResultController: RequestHandler = async (req, res): Promise<void>
|
|||||||
NewTrainingDate: {
|
NewTrainingDate: {
|
||||||
$date: { $numberLong: changedinventory.TrainingDate.getTime().toString() }
|
$date: { $numberLong: changedinventory.TrainingDate.getTime().toString() }
|
||||||
},
|
},
|
||||||
NewLevel: trainingResults.numLevelsGained == 1 ? changedinventory.PlayerLevel : inventory.PlayerLevel,
|
NewLevel: numLevelsGained == 1 ? changedinventory.PlayerLevel : inventory.PlayerLevel,
|
||||||
InventoryChanges: {}
|
InventoryChanges: []
|
||||||
} satisfies ITrainingResultsResponse);
|
} satisfies ITrainingResultsResponse);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { updateShipFeature } from "@/src/services/personalRoomsService";
|
|
||||||
import { IUnlockShipFeatureRequest } from "@/src/types/requestTypes";
|
|
||||||
import { parseString } from "@/src/helpers/general";
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
||||||
export const unlockShipFeatureController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = parseString(req.query.accountId);
|
|
||||||
const shipFeatureRequest = JSON.parse((req.body as string).toString()) as IUnlockShipFeatureRequest;
|
|
||||||
await updateShipFeature(accountId, shipFeatureRequest.Feature);
|
|
||||||
res.send([]);
|
|
||||||
};
|
|
@ -4,8 +4,9 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
|
|||||||
import { updateChallengeProgress } from "@/src/services/inventoryService";
|
import { updateChallengeProgress } from "@/src/services/inventoryService";
|
||||||
import { IUpdateChallengeProgressRequest } from "@/src/types/requestTypes";
|
import { IUpdateChallengeProgressRequest } from "@/src/types/requestTypes";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
const updateChallengeProgressController: RequestHandler = async (req, res) => {
|
const updateChallengeProgressController: RequestHandler = async (req, res) => {
|
||||||
const payload = getJSONfromString<IUpdateChallengeProgressRequest>(String(req.body));
|
const payload = getJSONfromString(String(req.body)) as IUpdateChallengeProgressRequest;
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|
||||||
await updateChallengeProgress(payload, accountId);
|
await updateChallengeProgress(payload, accountId);
|
||||||
|
156
src/controllers/api/updateInventoryController.ts
Normal file
156
src/controllers/api/updateInventoryController.ts
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { missionInventoryUpdate } from "@/src/services/inventoryService";
|
||||||
|
import { combineRewardAndLootInventory } from "@/src/services/missionInventoryUpdateService";
|
||||||
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
|
import { IMissionInventoryUpdateRequest } from "@/src/types/requestTypes";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
|
export const updateInventoryController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const lootInventory = getJSONfromString(req.body as string) as IMissionInventoryUpdateRequest;
|
||||||
|
const { combinedInventoryChanges, TotalCredits, CreditsBonus, MissionCredits } = combineRewardAndLootInventory(
|
||||||
|
lootInventory,
|
||||||
|
lootInventory
|
||||||
|
);
|
||||||
|
|
||||||
|
await missionInventoryUpdate(combinedInventoryChanges, accountId);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
// InventoryJson, // this part will reset game data and missions will be locked
|
||||||
|
combinedInventoryChanges,
|
||||||
|
TotalCredits,
|
||||||
|
CreditsBonus,
|
||||||
|
MissionCredits
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
"LongGuns" : [
|
||||||
|
{
|
||||||
|
"ItemType" : "",
|
||||||
|
"ItemId" : {
|
||||||
|
"$id" : ""
|
||||||
|
},
|
||||||
|
"XP" : 882,
|
||||||
|
"UpgradeVer" : 0,
|
||||||
|
"UnlockLevel" : 0,
|
||||||
|
"ExtraCapacity" : 4,
|
||||||
|
"ExtraRemaining" : 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Pistols" : [
|
||||||
|
{
|
||||||
|
"ItemType" : "",
|
||||||
|
"ItemId" : {
|
||||||
|
"$id" : ""
|
||||||
|
},
|
||||||
|
"XP" : 0,
|
||||||
|
"UpgradeVer" : 0,
|
||||||
|
"UnlockLevel" : 0,
|
||||||
|
"ExtraCapacity" : 4,
|
||||||
|
"ExtraRemaining" : 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Suits" : [
|
||||||
|
{
|
||||||
|
"ItemType" : "",
|
||||||
|
"ItemId" : {
|
||||||
|
"$id" : ""
|
||||||
|
},
|
||||||
|
"XP" : 982,
|
||||||
|
"UpgradeVer" : 101,
|
||||||
|
"UnlockLevel" : 0,
|
||||||
|
"ExtraCapacity" : 4,
|
||||||
|
"ExtraRemaining" : 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Melee" : [
|
||||||
|
{
|
||||||
|
"ItemType" : "",
|
||||||
|
"ItemId" : {
|
||||||
|
"$id" : ""
|
||||||
|
},
|
||||||
|
"XP" : 0,
|
||||||
|
"UpgradeVer" : 0,
|
||||||
|
"UnlockLevel" : 0,
|
||||||
|
"ExtraCapacity" : 4,
|
||||||
|
"ExtraRemaining" : 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"WeaponSkins" : [],
|
||||||
|
"Upgrades" : [],
|
||||||
|
"Boosters" : [],
|
||||||
|
"Robotics" : [],
|
||||||
|
"Consumables" : [],
|
||||||
|
"FlavourItems" : [],
|
||||||
|
"MiscItems" : [],
|
||||||
|
"Cards" : [],
|
||||||
|
"Recipes" : [],
|
||||||
|
"XPInfo" : [],
|
||||||
|
"Sentinels" : [],
|
||||||
|
"SentinelWeapons" : [],
|
||||||
|
"SuitBin" : {
|
||||||
|
"Slots" : 0,
|
||||||
|
"Extra" : 0
|
||||||
|
},
|
||||||
|
"WeaponBin" : {
|
||||||
|
"Slots" : 0,
|
||||||
|
"Extra" : 0
|
||||||
|
},
|
||||||
|
"MiscBin" : {
|
||||||
|
"Slots" : 0,
|
||||||
|
"Extra" : 0
|
||||||
|
},
|
||||||
|
"SentinelBin" : {
|
||||||
|
"Slots" : 0,
|
||||||
|
"Extra" : 0
|
||||||
|
},
|
||||||
|
"RegularCredits" : 1304,
|
||||||
|
"PremiumCredits" : 0,
|
||||||
|
"PlayerXP" : 784,
|
||||||
|
"AdditionalPlayerXP" : 0,
|
||||||
|
"Rating" : 15,
|
||||||
|
"PlayerLevel" : 0,
|
||||||
|
"TrainingDate" : {
|
||||||
|
"sec" : "",
|
||||||
|
"usec" : ""
|
||||||
|
},
|
||||||
|
"AliveTime" : 193.78572,
|
||||||
|
"Missions" : {
|
||||||
|
"Tag" : "SolNode103",
|
||||||
|
"Completes" : 1,
|
||||||
|
"BestRating" : 0.2
|
||||||
|
},
|
||||||
|
"AssignedMissions" : [],
|
||||||
|
"CompletedAlerts" : [],
|
||||||
|
"DeathMarks" : [],
|
||||||
|
"MissionReport" : {
|
||||||
|
"HostId" : "",
|
||||||
|
"MishStartTime" : "1725359860",
|
||||||
|
"MishName" : "SolNode103",
|
||||||
|
"PlayerReport" : {
|
||||||
|
"ReporterId" : "",
|
||||||
|
"FullReport" : true,
|
||||||
|
"PlayerMishInfos" : [
|
||||||
|
{
|
||||||
|
"Pid" : "",
|
||||||
|
"Creds" : 304,
|
||||||
|
"CredBonus" : 1000,
|
||||||
|
"Xp" : 784,
|
||||||
|
"XpBonus" : 0,
|
||||||
|
"SuitXpBonus" : 590,
|
||||||
|
"PistolXpBonus" : 0,
|
||||||
|
"RfileXpBonus" : 490,
|
||||||
|
"MeleeXpBonus" : 0,
|
||||||
|
"SentnlXPBonus" : 0,
|
||||||
|
"SentnlWepXpBonus" : 0,
|
||||||
|
"Rating" : 0.2,
|
||||||
|
"Upgrades" : []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
@ -1,47 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { parseString } from "@/src/helpers/general";
|
|
||||||
import { logger } from "@/src/utils/logger";
|
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|
||||||
import { updateQuestKey, IUpdateQuestRequest } from "@/src/services/questService";
|
|
||||||
import { getQuestCompletionItems } from "@/src/services/itemDataService";
|
|
||||||
import { addItems, getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
||||||
export const updateQuestController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = parseString(req.query.accountId);
|
|
||||||
const updateQuestRequest = getJSONfromString<IUpdateQuestRequest>((req.body as string).toString());
|
|
||||||
|
|
||||||
// updates should be made only to one quest key per request
|
|
||||||
if (updateQuestRequest.QuestKeys.length > 1) {
|
|
||||||
throw new Error(`quest keys array should only have 1 item, but has ${updateQuestRequest.QuestKeys.length}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
|
|
||||||
const updateQuestResponse: { CustomData?: string; InventoryChanges?: IInventoryChanges; MissionRewards: [] } = {
|
|
||||||
MissionRewards: []
|
|
||||||
};
|
|
||||||
updateQuestKey(inventory, updateQuestRequest.QuestKeys);
|
|
||||||
|
|
||||||
if (updateQuestRequest.QuestKeys[0].Completed) {
|
|
||||||
logger.debug(`completed quest ${updateQuestRequest.QuestKeys[0].ItemType} `);
|
|
||||||
const questKeyName = updateQuestRequest.QuestKeys[0].ItemType;
|
|
||||||
const questCompletionItems = getQuestCompletionItems(questKeyName);
|
|
||||||
logger.debug(`quest completion items`, questCompletionItems);
|
|
||||||
|
|
||||||
if (questCompletionItems) {
|
|
||||||
const inventoryChanges = await addItems(inventory, questCompletionItems);
|
|
||||||
updateQuestResponse.InventoryChanges = inventoryChanges;
|
|
||||||
}
|
|
||||||
inventory.ActiveQuest = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: might need to parse the custom data and add the associated items to inventory
|
|
||||||
if (updateQuestRequest.QuestKeys[0].CustomData) {
|
|
||||||
updateQuestResponse.CustomData = updateQuestRequest.QuestKeys[0].CustomData;
|
|
||||||
}
|
|
||||||
|
|
||||||
await inventory.save();
|
|
||||||
res.send(updateQuestResponse);
|
|
||||||
};
|
|
@ -5,8 +5,8 @@ const updateSessionGetController: RequestHandler = (_req, res) => {
|
|||||||
res.json({});
|
res.json({});
|
||||||
};
|
};
|
||||||
const updateSessionPostController: RequestHandler = (_req, res) => {
|
const updateSessionPostController: RequestHandler = (_req, res) => {
|
||||||
//console.log("UpdateSessions POST Request:", JSON.parse(String(_req.body)));
|
console.log("UpdateSessions POST Request:", JSON.parse(String(_req.body)));
|
||||||
//console.log("ReqID:", _req.query.sessionId as string);
|
console.log("ReqID:", _req.query.sessionId as string);
|
||||||
updateSession(_req.query.sessionId as string, String(_req.body));
|
updateSession(_req.query.sessionId as string, String(_req.body));
|
||||||
res.json({});
|
res.json({});
|
||||||
};
|
};
|
||||||
|
@ -4,12 +4,13 @@ import { updateTheme } from "@/src/services/inventoryService";
|
|||||||
import { IThemeUpdateRequest } from "@/src/types/requestTypes";
|
import { IThemeUpdateRequest } from "@/src/types/requestTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
const updateThemeController: RequestHandler = async (request, response) => {
|
const updateThemeController: RequestHandler = async (request, response) => {
|
||||||
const accountId = await getAccountIdForRequest(request);
|
const accountId = await getAccountIdForRequest(request);
|
||||||
const body = String(request.body);
|
const body = String(request.body);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const json = getJSONfromString<IThemeUpdateRequest>(body);
|
const json = getJSONfromString(body) as IThemeUpdateRequest;
|
||||||
if (typeof json !== "object") {
|
if (typeof json !== "object") {
|
||||||
throw new Error("Invalid data format");
|
throw new Error("Invalid data format");
|
||||||
}
|
}
|
||||||
|
@ -1,174 +1,34 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { IUpgradesRequest } from "@/src/types/requestTypes";
|
import { IUpgradesRequest } from "@/src/types/requestTypes";
|
||||||
import {
|
|
||||||
ArtifactPolarity,
|
|
||||||
IEquipmentDatabase,
|
|
||||||
EquipmentFeatures,
|
|
||||||
IAbilityOverride
|
|
||||||
} from "@/src/types/inventoryTypes/commonInventoryTypes";
|
|
||||||
import { IInventoryClient, IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { addMiscItems, addRecipes, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getRecipeByResult } from "@/src/services/itemDataService";
|
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
|
||||||
import { addInfestedFoundryXP } from "./infestedFoundryController";
|
|
||||||
import { config } from "@/src/services/configService";
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
export const upgradesController: RequestHandler = async (req, res) => {
|
export const upgradesController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const payload = JSON.parse(String(req.body)) as IUpgradesRequest;
|
const payload = JSON.parse(String(req.body)) as IUpgradesRequest;
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
console.log(req.body);
|
||||||
for (const operation of payload.Operations) {
|
for (const item of payload.UpgradesToAttach) {
|
||||||
if (
|
for (const upgrade of inventory.Upgrades) {
|
||||||
operation.UpgradeRequirement == "/Lotus/Types/Items/MiscItems/ModSlotUnlocker" ||
|
if (upgrade._id?.toString() == item.ItemId.$id) {
|
||||||
operation.UpgradeRequirement == "/Lotus/Types/Items/MiscItems/CustomizationSlotUnlocker"
|
upgrade.UpgradeFingerprint = item.UpgradeFingerprint;
|
||||||
) {
|
upgrade.Slot = item.Slot;
|
||||||
updateCurrency(inventory, 10, true);
|
upgrade.ParentId = payload.Weapon.ItemId;
|
||||||
} else {
|
|
||||||
addMiscItems(inventory, [
|
|
||||||
{
|
|
||||||
ItemType: operation.UpgradeRequirement,
|
|
||||||
ItemCount: -1
|
|
||||||
} satisfies IMiscItem
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operation.OperationType == "UOT_ABILITY_OVERRIDE") {
|
|
||||||
console.assert(payload.ItemCategory == "Suits");
|
|
||||||
const suit = inventory.Suits.id(payload.ItemId.$oid)!;
|
|
||||||
|
|
||||||
let newAbilityOverride: IAbilityOverride | undefined;
|
|
||||||
let totalPercentagePointsConsumed = 0;
|
|
||||||
if (operation.UpgradeRequirement != "") {
|
|
||||||
newAbilityOverride = {
|
|
||||||
Ability: operation.UpgradeRequirement,
|
|
||||||
Index: operation.PolarizeSlot
|
|
||||||
};
|
|
||||||
|
|
||||||
const recipe = getRecipeByResult(operation.UpgradeRequirement)!;
|
|
||||||
for (const ingredient of recipe.ingredients) {
|
|
||||||
totalPercentagePointsConsumed += ingredient.ItemCount / 10;
|
|
||||||
if (!config.infiniteHelminthMaterials) {
|
|
||||||
inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType)!.Count -=
|
|
||||||
ingredient.ItemCount;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const entry of operation.PolarityRemap) {
|
for (const item of payload.UpgradesToDetach) {
|
||||||
suit.Configs[entry.Slot] ??= {};
|
for (const upgrade of inventory.Upgrades) {
|
||||||
suit.Configs[entry.Slot].AbilityOverride = newAbilityOverride;
|
if (upgrade._id?.toString() == item.ItemId.$id) {
|
||||||
|
upgrade.UpgradeFingerprint = undefined;
|
||||||
|
upgrade.Slot = undefined;
|
||||||
|
upgrade.ParentId = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, totalPercentagePointsConsumed * 8);
|
|
||||||
addRecipes(inventory, recipeChanges);
|
|
||||||
|
|
||||||
inventoryChanges.Recipes = recipeChanges;
|
|
||||||
inventoryChanges.InfestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry;
|
|
||||||
} else
|
|
||||||
switch (operation.UpgradeRequirement) {
|
|
||||||
case "/Lotus/Types/Items/MiscItems/OrokinReactor":
|
|
||||||
case "/Lotus/Types/Items/MiscItems/OrokinCatalyst":
|
|
||||||
for (const item of inventory[payload.ItemCategory]) {
|
|
||||||
if (item._id.toString() == payload.ItemId.$oid) {
|
|
||||||
item.Features ??= 0;
|
|
||||||
item.Features |= EquipmentFeatures.DOUBLE_CAPACITY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "/Lotus/Types/Items/MiscItems/UtilityUnlocker":
|
|
||||||
case "/Lotus/Types/Items/MiscItems/WeaponUtilityUnlocker":
|
|
||||||
for (const item of inventory[payload.ItemCategory]) {
|
|
||||||
if (item._id.toString() == payload.ItemId.$oid) {
|
|
||||||
item.Features ??= 0;
|
|
||||||
item.Features |= EquipmentFeatures.UTILITY_SLOT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "/Lotus/Types/Items/MiscItems/HeavyWeaponCatalyst":
|
|
||||||
console.assert(payload.ItemCategory == "SpaceGuns");
|
|
||||||
for (const item of inventory[payload.ItemCategory]) {
|
|
||||||
if (item._id.toString() == payload.ItemId.$oid) {
|
|
||||||
item.Features ??= 0;
|
|
||||||
item.Features |= EquipmentFeatures.GRAVIMAG_INSTALLED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "/Lotus/Types/Items/MiscItems/WeaponPrimaryArcaneUnlocker":
|
|
||||||
case "/Lotus/Types/Items/MiscItems/WeaponSecondaryArcaneUnlocker":
|
|
||||||
case "/Lotus/Types/Items/MiscItems/WeaponMeleeArcaneUnlocker":
|
|
||||||
case "/Lotus/Types/Items/MiscItems/WeaponAmpArcaneUnlocker":
|
|
||||||
for (const item of inventory[payload.ItemCategory]) {
|
|
||||||
if (item._id.toString() == payload.ItemId.$oid) {
|
|
||||||
item.Features ??= 0;
|
|
||||||
item.Features |= EquipmentFeatures.ARCANE_SLOT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "/Lotus/Types/Items/MiscItems/Forma":
|
|
||||||
case "/Lotus/Types/Items/MiscItems/FormaUmbra":
|
|
||||||
case "/Lotus/Types/Items/MiscItems/FormaAura":
|
|
||||||
case "/Lotus/Types/Items/MiscItems/FormaStance":
|
|
||||||
for (const item of inventory[payload.ItemCategory]) {
|
|
||||||
if (item._id.toString() == payload.ItemId.$oid) {
|
|
||||||
item.XP = 0;
|
|
||||||
setSlotPolarity(item, operation.PolarizeSlot, operation.PolarizeValue);
|
|
||||||
item.Polarized ??= 0;
|
|
||||||
item.Polarized += 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "/Lotus/Types/Items/MiscItems/ModSlotUnlocker":
|
|
||||||
for (const item of inventory[payload.ItemCategory]) {
|
|
||||||
if (item._id.toString() == payload.ItemId.$oid) {
|
|
||||||
item.ModSlotPurchases ??= 0;
|
|
||||||
item.ModSlotPurchases += 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "/Lotus/Types/Items/MiscItems/CustomizationSlotUnlocker":
|
|
||||||
for (const item of inventory[payload.ItemCategory]) {
|
|
||||||
if (item._id.toString() == payload.ItemId.$oid) {
|
|
||||||
item.CustomizationSlotPurchases ??= 0;
|
|
||||||
item.CustomizationSlotPurchases += 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "":
|
|
||||||
console.assert(operation.OperationType == "UOT_SWAP_POLARITY");
|
|
||||||
for (const item of inventory[payload.ItemCategory]) {
|
|
||||||
if (item._id.toString() == payload.ItemId.$oid) {
|
|
||||||
for (let i = 0; i != operation.PolarityRemap.length; ++i) {
|
|
||||||
if (operation.PolarityRemap[i].Slot != i) {
|
|
||||||
setSlotPolarity(item, i, operation.PolarityRemap[i].Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error("Unsupported upgrade: " + operation.UpgradeRequirement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({ InventoryChanges: inventoryChanges });
|
res.json({});
|
||||||
};
|
|
||||||
|
|
||||||
const setSlotPolarity = (item: IEquipmentDatabase, slot: number, polarity: ArtifactPolarity): void => {
|
|
||||||
item.Polarity ??= [];
|
|
||||||
const entry = item.Polarity.find(entry => entry.Slot == slot);
|
|
||||||
if (entry) {
|
|
||||||
entry.Value = polarity;
|
|
||||||
} else {
|
|
||||||
item.Polarity.push({ Slot: slot, Value: polarity });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
|
||||||
|
|
||||||
export const addCurrencyController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const request = req.body as IAddCurrencyRequest;
|
|
||||||
inventory[request.currency] += request.delta;
|
|
||||||
await inventory.save();
|
|
||||||
res.end();
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IAddCurrencyRequest {
|
|
||||||
currency: "RegularCredits" | "PremiumCredits" | "FusionPoints" | "PrimeTokens";
|
|
||||||
delta: number;
|
|
||||||
}
|
|
28
src/controllers/custom/addItemController.ts
Normal file
28
src/controllers/custom/addItemController.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { ItemType, toAddItemRequest } from "@/src/helpers/customHelpers/addItemHelpers";
|
||||||
|
import { getWeaponType } from "@/src/services/itemDataService";
|
||||||
|
import { addPowerSuit, addEquipment } from "@/src/services/inventoryService";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
|
const addItemController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const request = toAddItemRequest(req.body);
|
||||||
|
|
||||||
|
switch (request.type) {
|
||||||
|
case ItemType.Powersuit:
|
||||||
|
const powersuit = await addPowerSuit(request.InternalName, accountId);
|
||||||
|
res.json(powersuit);
|
||||||
|
return;
|
||||||
|
case ItemType.Weapon:
|
||||||
|
const weaponType = getWeaponType(request.InternalName);
|
||||||
|
const weapon = await addEquipment(weaponType, request.InternalName, accountId);
|
||||||
|
res.json(weapon);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res.status(400).json({ error: "something went wrong" });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export { addItemController };
|
@ -1,19 +0,0 @@
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { getInventory, addItem } from "@/src/services/inventoryService";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const addItemsController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const requests = req.body as IAddItemRequest[];
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
for (const request of requests) {
|
|
||||||
await addItem(inventory, request.ItemType, request.ItemCount);
|
|
||||||
}
|
|
||||||
await inventory.save();
|
|
||||||
res.end();
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IAddItemRequest {
|
|
||||||
ItemType: string;
|
|
||||||
ItemCount: number;
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
import { addGearExpByCategory, getInventory } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
|
||||||
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { RequestHandler } from "express";
|
|
||||||
import { ExportMisc } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
export const addXpController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const request = req.body as IAddXpRequest;
|
|
||||||
for (const [category, gear] of Object.entries(request)) {
|
|
||||||
for (const clientItem of gear) {
|
|
||||||
const dbItem = inventory[category as TEquipmentKey].id(clientItem.ItemId.$oid);
|
|
||||||
if (dbItem) {
|
|
||||||
if (dbItem.ItemType in ExportMisc.uniqueLevelCaps) {
|
|
||||||
if ((dbItem.Polarized ?? 0) < 5) {
|
|
||||||
dbItem.Polarized = 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addGearExpByCategory(inventory, gear, category as TEquipmentKey);
|
|
||||||
}
|
|
||||||
await inventory.save();
|
|
||||||
res.end();
|
|
||||||
};
|
|
||||||
|
|
||||||
type IAddXpRequest = {
|
|
||||||
[_ in TEquipmentKey]: IEquipmentClient[];
|
|
||||||
};
|
|
@ -1,16 +1,15 @@
|
|||||||
import { toCreateAccount, toDatabaseAccount } from "@/src/helpers/customHelpers/customHelpers";
|
import { toCreateAccount, toDatabaseAccount } from "@/src/helpers/customHelpers/customHelpers";
|
||||||
import { createAccount, isNameTaken } from "@/src/services/loginService";
|
import { createAccount } from "@/src/services/loginService";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
const createAccountController: RequestHandler = async (req, res) => {
|
const createAccountController: RequestHandler = async (req, res) => {
|
||||||
const createAccountData = toCreateAccount(req.body);
|
const createAccountData = toCreateAccount(req.body);
|
||||||
if (await isNameTaken(createAccountData.DisplayName)) {
|
|
||||||
res.status(409).json("Name already in use");
|
|
||||||
} else {
|
|
||||||
const databaseAccount = toDatabaseAccount(createAccountData);
|
const databaseAccount = toDatabaseAccount(createAccountData);
|
||||||
|
|
||||||
const account = await createAccount(databaseAccount);
|
const account = await createAccount(databaseAccount);
|
||||||
|
|
||||||
res.json(account);
|
res.json(account);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export { createAccountController };
|
export { createAccountController };
|
||||||
|
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