Merge remote-tracking branch 'upstream/main'

This commit is contained in:
Master 2024-07-04 08:43:25 +08:00
commit 37078f3107
32 changed files with 719 additions and 264 deletions

View File

@ -4,14 +4,13 @@
"plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking" "plugin:@typescript-eslint/recommended-requiring-type-checking"
], ],
"plugins": ["@typescript-eslint"], "plugins": ["@typescript-eslint", "prettier"],
"env": { "env": {
"browser": true, "browser": true,
"es6": true, "es6": true,
"node": true "node": true
}, },
"rules": { "rules": {
"@typescript-eslint/semi": "warn",
"@typescript-eslint/explicit-function-return-type": "warn", "@typescript-eslint/explicit-function-return-type": "warn",
"@typescript-eslint/explicit-module-boundary-types": "warn", "@typescript-eslint/explicit-module-boundary-types": "warn",
"@typescript-eslint/restrict-template-expressions": "warn", "@typescript-eslint/restrict-template-expressions": "warn",
@ -25,7 +24,9 @@
"@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",
"no-case-declarations": "warn", "no-case-declarations": "warn",
"no-mixed-spaces-and-tabs": "warn" "prettier/prettier": "error",
"@typescript-eslint/semi": "error",
"no-mixed-spaces-and-tabs": "error"
}, },
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"parserOptions": { "parserOptions": {

View File

@ -5,15 +5,16 @@ on:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: strategy:
contents: write matrix:
version: [18, 20, 22]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4.1.2 uses: actions/checkout@v4.1.2
- name: Setup Node.js environment - name: Setup Node.js environment
uses: actions/setup-node@v4.0.2 uses: actions/setup-node@v4.0.2
with: with:
node-version: "20.x" 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: echo '{"version":"","buildLabel":"","matchmakingBuildId":""}' > static/data/buildConfig.json

View File

@ -1,23 +0,0 @@
name: Prettier
on: [push]
jobs:
format:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4.1.2
with:
ref: ${{ github.head_ref }}
- name: Setup Node.js environment
uses: actions/setup-node@v4.0.2
with:
node-version: "20.x"
- run: npm ci
- run: npm run prettier
- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v5.0.0
with:
commit_message: Apply prettier changes
branch: ${{ github.head_ref }}

View File

@ -11,6 +11,7 @@
"autoCreateAccount": true, "autoCreateAccount": true,
"skipStoryModeChoice": true, "skipStoryModeChoice": true,
"skipTutorial": true, "skipTutorial": true,
"skipAllDialogue": true,
"unlockAllScans": true, "unlockAllScans": true,
"unlockAllMissions": true, "unlockAllMissions": true,
"unlockAllQuests": true, "unlockAllQuests": true,

215
package-lock.json generated
View File

@ -11,25 +11,24 @@
"dependencies": { "dependencies": {
"copyfiles": "^2.4.1", "copyfiles": "^2.4.1",
"express": "^5.0.0-beta.3", "express": "^5.0.0-beta.3",
"mongoose": "^8.1.1", "mongoose": "^8.4.4",
"warframe-public-export-plus": "^0.4.0", "warframe-public-export-plus": "^0.4.1",
"warframe-riven-info": "^0.1.0", "warframe-riven-info": "^0.1.0",
"winston": "^3.11.0", "winston": "^3.13.0",
"winston-daily-rotate-file": "^4.7.1" "winston-daily-rotate-file": "^5.0.0"
}, },
"devDependencies": { "devDependencies": {
"@tsconfig/node20": "^1.0.0",
"@types/express": "^4.17.20", "@types/express": "^4.17.20",
"@types/morgan": "^1.9.7", "@types/morgan": "^1.9.7",
"@typescript-eslint/eslint-plugin": "^7.13.1", "@typescript-eslint/eslint-plugin": "^7.14",
"@typescript-eslint/parser": "^7.13.1", "@typescript-eslint/parser": "^7.14",
"eslint": "^8.56.0", "eslint": "^8.56.0",
"eslint-plugin-prettier": "^5.1.3", "eslint-plugin-prettier": "^5.1.3",
"morgan": "^1.10.0", "morgan": "^1.10.0",
"prettier": "^3.2.4", "prettier": "^3.2.4",
"ts-node-dev": "^2.0.0", "ts-node-dev": "^2.0.0",
"tsconfig-paths": "^4.2.0", "tsconfig-paths": "^4.2.0",
"typescript": "^5.2.2" "typescript": "^5.5"
}, },
"engines": { "engines": {
"node": ">=18.15.0", "node": ">=18.15.0",
@ -236,9 +235,9 @@
} }
}, },
"node_modules/@mongodb-js/saslprep": { "node_modules/@mongodb-js/saslprep": {
"version": "1.1.4", "version": "1.1.7",
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.4.tgz", "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.7.tgz",
"integrity": "sha512-8zJ8N1x51xo9hwPh6AWnKdLGEC5N3lDa6kms1YHmFBoRhTpJR6HG8wWk0td1MVCu9cD4YBrvjZEtd5Obw0Fbnw==", "integrity": "sha512-dCHW/oEX0KJ4NjDULBo3JiOaK5+6axtpBbS+ao2ZInoAL9/YRQLhXzSNAFz7hP4nzLkIqsfYAK/PDE3+XHny0Q==",
"dependencies": { "dependencies": {
"sparse-bitfield": "^3.0.3" "sparse-bitfield": "^3.0.3"
} }
@ -314,12 +313,6 @@
"integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
"dev": true "dev": true
}, },
"node_modules/@tsconfig/node20": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@tsconfig/node20/-/node20-1.0.0.tgz",
"integrity": "sha512-AwbXtpWEaRUjbGVwdlusNqwet+jeSk3Nnqf/8+77WJ1/9d6xnqs2QpE9Pdwv8RCoXxtMedWEtlmWY+/irBPcUw==",
"dev": true
},
"node_modules/@types/body-parser": { "node_modules/@types/body-parser": {
"version": "1.19.2", "version": "1.19.2",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
@ -439,24 +432,24 @@
"integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA=="
}, },
"node_modules/@types/whatwg-url": { "node_modules/@types/whatwg-url": {
"version": "11.0.4", "version": "11.0.5",
"resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.4.tgz", "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz",
"integrity": "sha512-lXCmTWSHJvf0TRSO58nm978b8HJ/EdsSsEKLd3ODHFjo+3VGAyyTp4v50nWvwtzBxSMQrVOK7tcuN0zGPLICMw==", "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==",
"dependencies": { "dependencies": {
"@types/webidl-conversions": "*" "@types/webidl-conversions": "*"
} }
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "7.13.1", "version": "7.15.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.15.0.tgz",
"integrity": "sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==", "integrity": "sha512-uiNHpyjZtFrLwLDpHnzaDlP3Tt6sGMqTCiqmxaN4n4RP0EfYZDODJyddiFDF44Hjwxr5xAcaYxVKm9QKQFJFLA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.10.0", "@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "7.13.1", "@typescript-eslint/scope-manager": "7.15.0",
"@typescript-eslint/type-utils": "7.13.1", "@typescript-eslint/type-utils": "7.15.0",
"@typescript-eslint/utils": "7.13.1", "@typescript-eslint/utils": "7.15.0",
"@typescript-eslint/visitor-keys": "7.13.1", "@typescript-eslint/visitor-keys": "7.15.0",
"graphemer": "^1.4.0", "graphemer": "^1.4.0",
"ignore": "^5.3.1", "ignore": "^5.3.1",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
@ -480,15 +473,15 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "7.13.1", "version": "7.15.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.15.0.tgz",
"integrity": "sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==", "integrity": "sha512-k9fYuQNnypLFcqORNClRykkGOMOj+pV6V91R4GO/l1FDGwpqmSwoOQrOHo3cGaH63e+D3ZiCAOsuS/D2c99j/A==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "7.13.1", "@typescript-eslint/scope-manager": "7.15.0",
"@typescript-eslint/types": "7.13.1", "@typescript-eslint/types": "7.15.0",
"@typescript-eslint/typescript-estree": "7.13.1", "@typescript-eslint/typescript-estree": "7.15.0",
"@typescript-eslint/visitor-keys": "7.13.1", "@typescript-eslint/visitor-keys": "7.15.0",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@ -531,13 +524,13 @@
"dev": true "dev": true
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "7.13.1", "version": "7.15.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.15.0.tgz",
"integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", "integrity": "sha512-Q/1yrF/XbxOTvttNVPihxh1b9fxamjEoz2Os/Pe38OHwxC24CyCqXxGTOdpb4lt6HYtqw9HetA/Rf6gDGaMPlw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/types": "7.13.1", "@typescript-eslint/types": "7.15.0",
"@typescript-eslint/visitor-keys": "7.13.1" "@typescript-eslint/visitor-keys": "7.15.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || >=20.0.0" "node": "^18.18.0 || >=20.0.0"
@ -548,13 +541,13 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "7.13.1", "version": "7.15.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.15.0.tgz",
"integrity": "sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==", "integrity": "sha512-SkgriaeV6PDvpA6253PDVep0qCqgbO1IOBiycjnXsszNTVQe5flN5wR5jiczoEoDEnAqYFSFFc9al9BSGVltkg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/typescript-estree": "7.13.1", "@typescript-eslint/typescript-estree": "7.15.0",
"@typescript-eslint/utils": "7.13.1", "@typescript-eslint/utils": "7.15.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"ts-api-utils": "^1.3.0" "ts-api-utils": "^1.3.0"
}, },
@ -598,9 +591,9 @@
"dev": true "dev": true
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "7.13.1", "version": "7.15.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.15.0.tgz",
"integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", "integrity": "sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": "^18.18.0 || >=20.0.0" "node": "^18.18.0 || >=20.0.0"
@ -611,13 +604,13 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "7.13.1", "version": "7.15.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.15.0.tgz",
"integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", "integrity": "sha512-gjyB/rHAopL/XxfmYThQbXbzRMGhZzGw6KpcMbfe8Q3nNQKStpxnUKeXb0KiN/fFDR42Z43szs6rY7eHk0zdGQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/types": "7.13.1", "@typescript-eslint/types": "7.15.0",
"@typescript-eslint/visitor-keys": "7.13.1", "@typescript-eslint/visitor-keys": "7.15.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"globby": "^11.1.0", "globby": "^11.1.0",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
@ -665,9 +658,9 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
"version": "9.0.4", "version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"brace-expansion": "^2.0.1" "brace-expansion": "^2.0.1"
@ -686,15 +679,15 @@
"dev": true "dev": true
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "7.13.1", "version": "7.15.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.15.0.tgz",
"integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", "integrity": "sha512-hfDMDqaqOqsUVGiEPSMLR/AjTSCsmJwjpKkYQRo1FNbmW4tBwBspYDwO9eh7sKSTwMQgBw9/T4DHudPaqshRWA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.4.0", "@eslint-community/eslint-utils": "^4.4.0",
"@typescript-eslint/scope-manager": "7.13.1", "@typescript-eslint/scope-manager": "7.15.0",
"@typescript-eslint/types": "7.13.1", "@typescript-eslint/types": "7.15.0",
"@typescript-eslint/typescript-estree": "7.13.1" "@typescript-eslint/typescript-estree": "7.15.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || >=20.0.0" "node": "^18.18.0 || >=20.0.0"
@ -708,12 +701,12 @@
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "7.13.1", "version": "7.15.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.15.0.tgz",
"integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", "integrity": "sha512-Hqgy/ETgpt2L5xueA/zHHIl4fJI2O4XUE9l4+OIfbJIRSnTJb/QscncdqqZzofQegIJugRIF57OJea1khw2SDw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/types": "7.13.1", "@typescript-eslint/types": "7.15.0",
"eslint-visitor-keys": "^3.4.3" "eslint-visitor-keys": "^3.4.3"
}, },
"engines": { "engines": {
@ -948,9 +941,9 @@
} }
}, },
"node_modules/bson": { "node_modules/bson": {
"version": "6.3.0", "version": "6.8.0",
"resolved": "https://registry.npmjs.org/bson/-/bson-6.3.0.tgz", "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz",
"integrity": "sha512-balJfqwwTBddxfnidJZagCBPP/f48zj9Sdp3OJswREOgsJzHiQSaOIAtApSgDQFYgHqAvFkp53AFSqjMDZoTFw==", "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==",
"engines": { "engines": {
"node": ">=16.20.1" "node": ">=16.20.1"
} }
@ -2212,9 +2205,9 @@
} }
}, },
"node_modules/kareem": { "node_modules/kareem": {
"version": "2.5.1", "version": "2.6.3",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
"integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==", "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==",
"engines": { "engines": {
"node": ">=12.0.0" "node": ">=12.0.0"
} }
@ -2392,12 +2385,12 @@
} }
}, },
"node_modules/mongodb": { "node_modules/mongodb": {
"version": "6.3.0", "version": "6.6.2",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.3.0.tgz", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.6.2.tgz",
"integrity": "sha512-tt0KuGjGtLUhLoU263+xvQmPHEGTw5LbcNC73EoFRYgSHwZt5tsoJC110hDyO1kjQzpgNrpdcSza9PknWN4LrA==", "integrity": "sha512-ZF9Ugo2JCG/GfR7DEb4ypfyJJyiKbg5qBYKRintebj8+DNS33CyGMkWbrS9lara+u+h+yEOGSRiLhFO/g1s1aw==",
"dependencies": { "dependencies": {
"@mongodb-js/saslprep": "^1.1.0", "@mongodb-js/saslprep": "^1.1.5",
"bson": "^6.2.0", "bson": "^6.7.0",
"mongodb-connection-string-url": "^3.0.0" "mongodb-connection-string-url": "^3.0.0"
}, },
"engines": { "engines": {
@ -2437,26 +2430,26 @@
} }
}, },
"node_modules/mongodb-connection-string-url": { "node_modules/mongodb-connection-string-url": {
"version": "3.0.0", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.0.tgz", "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz",
"integrity": "sha512-t1Vf+m1I5hC2M5RJx/7AtxgABy1cZmIPQRMXw+gEIPn/cZNF3Oiy+l0UIypUwVB5trcWHq3crg2g3uAR9aAwsQ==", "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==",
"dependencies": { "dependencies": {
"@types/whatwg-url": "^11.0.2", "@types/whatwg-url": "^11.0.2",
"whatwg-url": "^13.0.0" "whatwg-url": "^13.0.0"
} }
}, },
"node_modules/mongoose": { "node_modules/mongoose": {
"version": "8.1.1", "version": "8.4.4",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.1.1.tgz", "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.4.4.tgz",
"integrity": "sha512-DbLb0NsiEXmaqLOpEz+AtAsgwhRw6f25gwa1dF5R7jj6lS1D8X6uTdhBSC8GDVtOwe5Tfw2EL7nTn6hiJT3Bgg==", "integrity": "sha512-Nya808odIJoHP4JuJKbWA2eIaerXieu59kE8pQlvJpUBoSKWUyhLji0g1WMVaYXWmzPYXP2Jd6XdR4KJE8RELw==",
"dependencies": { "dependencies": {
"bson": "^6.2.0", "bson": "^6.7.0",
"kareem": "2.5.1", "kareem": "2.6.3",
"mongodb": "6.3.0", "mongodb": "6.6.2",
"mpath": "0.9.0", "mpath": "0.9.0",
"mquery": "5.0.0", "mquery": "5.0.0",
"ms": "2.1.3", "ms": "2.1.3",
"sift": "16.0.1" "sift": "17.1.3"
}, },
"engines": { "engines": {
"node": ">=16.20.1" "node": ">=16.20.1"
@ -2581,9 +2574,9 @@
} }
}, },
"node_modules/object-hash": { "node_modules/object-hash": {
"version": "2.2.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
"integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
"engines": { "engines": {
"node": ">= 6" "node": ">= 6"
} }
@ -3168,9 +3161,9 @@
} }
}, },
"node_modules/sift": { "node_modules/sift": {
"version": "16.0.1", "version": "17.1.3",
"resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz",
"integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ=="
}, },
"node_modules/simple-swizzle": { "node_modules/simple-swizzle": {
"version": "0.2.2", "version": "0.2.2",
@ -3604,9 +3597,9 @@
} }
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.2.2", "version": "5.5.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz",
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==",
"dev": true, "dev": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
@ -3669,9 +3662,9 @@
} }
}, },
"node_modules/warframe-public-export-plus": { "node_modules/warframe-public-export-plus": {
"version": "0.4.0", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.4.0.tgz", "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.4.1.tgz",
"integrity": "sha512-8wOkh9dET4IHmHDSZ8g8RW0GlfEevHnBwEETAqy3jRhwssyF0TgQsOOpJVuhcPKedCYeudR92HJ3JoXoiTCr6A==" "integrity": "sha512-5SwnT/K/rMI0zJpdodzeEPlO/UnMlHiKv8NZGH647/5u52LZf8xfOpJHP4/yr/anjVVzDQJwY5K3CmbX0uMQdw=="
}, },
"node_modules/warframe-riven-info": { "node_modules/warframe-riven-info": {
"version": "0.1.0", "version": "0.1.0",
@ -3714,9 +3707,9 @@
} }
}, },
"node_modules/winston": { "node_modules/winston": {
"version": "3.11.0", "version": "3.13.0",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz",
"integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==",
"dependencies": { "dependencies": {
"@colors/colors": "^1.6.0", "@colors/colors": "^1.6.0",
"@dabh/diagnostics": "^2.0.2", "@dabh/diagnostics": "^2.0.2",
@ -3728,21 +3721,21 @@
"safe-stable-stringify": "^2.3.1", "safe-stable-stringify": "^2.3.1",
"stack-trace": "0.0.x", "stack-trace": "0.0.x",
"triple-beam": "^1.3.0", "triple-beam": "^1.3.0",
"winston-transport": "^4.5.0" "winston-transport": "^4.7.0"
}, },
"engines": { "engines": {
"node": ">= 12.0.0" "node": ">= 12.0.0"
} }
}, },
"node_modules/winston-daily-rotate-file": { "node_modules/winston-daily-rotate-file": {
"version": "4.7.1", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-4.7.1.tgz", "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-5.0.0.tgz",
"integrity": "sha512-7LGPiYGBPNyGHLn9z33i96zx/bd71pjBn9tqQzO3I4Tayv94WPmBNwKC7CO1wPHdP9uvu+Md/1nr6VSH9h0iaA==", "integrity": "sha512-JDjiXXkM5qvwY06733vf09I2wnMXpZEhxEVOSPenZMii+g7pcDcTBt2MRugnoi8BwVSuCT2jfRXBUy+n1Zz/Yw==",
"dependencies": { "dependencies": {
"file-stream-rotator": "^0.6.1", "file-stream-rotator": "^0.6.1",
"object-hash": "^2.0.1", "object-hash": "^3.0.0",
"triple-beam": "^1.3.0", "triple-beam": "^1.4.1",
"winston-transport": "^4.4.0" "winston-transport": "^4.7.0"
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
@ -3752,9 +3745,9 @@
} }
}, },
"node_modules/winston-transport": { "node_modules/winston-transport": {
"version": "4.6.0", "version": "4.7.0",
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz", "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz",
"integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==", "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==",
"dependencies": { "dependencies": {
"logform": "^2.3.2", "logform": "^2.3.2",
"readable-stream": "^3.6.0", "readable-stream": "^3.6.0",

View File

@ -15,25 +15,24 @@
"dependencies": { "dependencies": {
"copyfiles": "^2.4.1", "copyfiles": "^2.4.1",
"express": "^5.0.0-beta.3", "express": "^5.0.0-beta.3",
"mongoose": "^8.1.1", "mongoose": "^8.4.4",
"warframe-public-export-plus": "^0.4.0", "warframe-public-export-plus": "^0.4.1",
"warframe-riven-info": "^0.1.0", "warframe-riven-info": "^0.1.0",
"winston": "^3.11.0", "winston": "^3.13.0",
"winston-daily-rotate-file": "^4.7.1" "winston-daily-rotate-file": "^5.0.0"
}, },
"devDependencies": { "devDependencies": {
"@tsconfig/node20": "^1.0.0",
"@types/express": "^4.17.20", "@types/express": "^4.17.20",
"@types/morgan": "^1.9.7", "@types/morgan": "^1.9.7",
"@typescript-eslint/eslint-plugin": "^7.13.1", "@typescript-eslint/eslint-plugin": "^7.14",
"@typescript-eslint/parser": "^7.13.1", "@typescript-eslint/parser": "^7.14",
"eslint": "^8.56.0", "eslint": "^8.56.0",
"eslint-plugin-prettier": "^5.1.3", "eslint-plugin-prettier": "^5.1.3",
"morgan": "^1.10.0", "morgan": "^1.10.0",
"prettier": "^3.2.4", "prettier": "^3.2.4",
"ts-node-dev": "^2.0.0", "ts-node-dev": "^2.0.0",
"tsconfig-paths": "^4.2.0", "tsconfig-paths": "^4.2.0",
"typescript": "^5.2.2" "typescript": "^5.5"
}, },
"engines": { "engines": {
"node": ">=18.15.0", "node": ">=18.15.0",

View File

@ -1,7 +1,23 @@
import { RequestHandler } from "express"; import { RequestHandler } from "express";
import getVendorInfoResponse from "@/static/fixed_responses/getVendorInfo.json"; 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) => {
console.assert(req.query.vendor == "/Lotus/Types/Game/VendorManifests/Ostron/MaskSalesmanManifest"); switch (req.query.vendor as string) {
res.json(getVendorInfoResponse); case "/Lotus/Types/Game/VendorManifests/Zariman/ArchimedeanVendorManifest":
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}`);
}
}; };

View File

@ -3,9 +3,10 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
import { toInventoryResponse } from "@/src/helpers/inventoryHelpers"; import { toInventoryResponse } from "@/src/helpers/inventoryHelpers";
import { Inventory } from "@/src/models/inventoryModels/inventoryModel"; 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 allMissions from "@/static/fixed_responses/allMissions.json"; import allMissions from "@/static/fixed_responses/allMissions.json";
import { ILoadoutDatabase } from "@/src/types/saveLoadoutTypes"; import { ILoadoutDatabase } from "@/src/types/saveLoadoutTypes";
import { IShipInventory, equipmentKeys } from "@/src/types/inventoryTypes/inventoryTypes"; import { IInventoryDatabase, IShipInventory, equipmentKeys } from "@/src/types/inventoryTypes/inventoryTypes";
import { IPolarity, ArtifactPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes"; import { IPolarity, ArtifactPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { ExportCustoms, ExportFlavour, ExportKeys, ExportResources } from "warframe-public-export-plus"; import { ExportCustoms, ExportFlavour, ExportKeys, ExportResources } from "warframe-public-export-plus";
@ -20,9 +21,7 @@ const inventoryController: RequestHandler = async (request, response) => {
} }
const inventory = await Inventory.findOne({ accountOwnerId: accountId }) const inventory = await Inventory.findOne({ accountOwnerId: accountId })
.populate<{ .populate<{ LoadOutPresets: ILoadoutDatabase }>("LoadOutPresets")
LoadOutPresets: ILoadoutDatabase;
}>("LoadOutPresets")
.populate<{ Ships: IShipInventory }>("Ships", "-ShipInteriorColors"); .populate<{ Ships: IShipInventory }>("Ships", "-ShipInteriorColors");
if (!inventory) { if (!inventory) {
@ -31,7 +30,7 @@ const inventoryController: RequestHandler = async (request, response) => {
} }
//TODO: make a function that converts from database representation to client //TODO: make a function that converts from database representation to client
const inventoryJSON = inventory.toJSON(); const inventoryJSON: IInventoryDatabase = inventory.toJSON();
console.log(inventoryJSON.Ships); console.log(inventoryJSON.Ships);
const inventoryResponse = toInventoryResponse(inventoryJSON); const inventoryResponse = toInventoryResponse(inventoryJSON);
@ -43,9 +42,21 @@ const inventoryController: RequestHandler = async (request, response) => {
inventoryResponse.PremiumCredits = 999999999; inventoryResponse.PremiumCredits = 999999999;
} }
if (config.skipAllDialogue) {
inventoryResponse.TauntHistory = [
{
node: "TreasureTutorial",
state: "TS_COMPLETED"
}
];
for (const str of allDialogue) {
addString(inventoryResponse.NodeIntrosCompleted, str);
}
}
if (config.unlockAllMissions) { if (config.unlockAllMissions) {
inventoryResponse.Missions = allMissions; inventoryResponse.Missions = allMissions;
inventoryResponse.NodeIntrosCompleted.push("TeshinHardModeUnlocked"); addString(inventoryResponse.NodeIntrosCompleted, "TeshinHardModeUnlocked");
} }
if (config.unlockAllQuests) { if (config.unlockAllQuests) {
@ -73,7 +84,7 @@ const inventoryController: RequestHandler = async (request, response) => {
inventoryResponse.ArchwingEnabled = true; inventoryResponse.ArchwingEnabled = true;
// Skip "Watch The Maker" // Skip "Watch The Maker"
inventoryResponse.NodeIntrosCompleted.push("/Lotus/Levels/Cinematics/NewWarIntro/NewWarStageTwo.level"); addString(inventoryResponse.NodeIntrosCompleted, "/Lotus/Levels/Cinematics/NewWarIntro/NewWarStageTwo.level");
} }
if (config.unlockAllShipDecorations) { if (config.unlockAllShipDecorations) {
@ -142,6 +153,12 @@ const inventoryController: RequestHandler = async (request, response) => {
response.json(inventoryResponse); response.json(inventoryResponse);
}; };
const addString = (arr: string[], str: string): void => {
if (!arr.find(x => x == str)) {
arr.push(str);
}
};
const getExpRequiredForMr = (rank: number): number => { const getExpRequiredForMr = (rank: number): number => {
if (rank <= 30) { if (rank <= 30) {
return 2500 * rank * rank; return 2500 * rank * rank;

View File

@ -0,0 +1,64 @@
import { RequestHandler } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
import { ExportRelics, IRelic } from "warframe-public-export-plus";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const projectionManagerController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId);
const request = JSON.parse(String(req.body)) as IProjectionUpgradeRequest;
const [era, category, currentQuality] = parseProjection(request.projectionType);
const upgradeCost = (request.qualityTag - qualityKeywordToNumber[currentQuality]) * 25;
const newProjectionType = findProjection(era, category, qualityNumberToKeyword[request.qualityTag]);
addMiscItems(inventory, [
{
ItemType: request.projectionType,
ItemCount: -1
},
{
ItemType: newProjectionType,
ItemCount: 1
},
{
ItemType: "/Lotus/Types/Items/MiscItems/VoidTearDrop",
ItemCount: -upgradeCost
}
]);
await inventory.save();
res.json({
prevProjection: request.projectionType,
upgradedProjection: newProjectionType,
upgradeCost: upgradeCost
});
};
interface IProjectionUpgradeRequest {
projectionType: string;
qualityTag: number;
}
type VoidProjectionQuality = "VPQ_BRONZE" | "VPQ_SILVER" | "VPQ_GOLD" | "VPQ_PLATINUM";
const qualityNumberToKeyword: VoidProjectionQuality[] = ["VPQ_BRONZE", "VPQ_SILVER", "VPQ_GOLD", "VPQ_PLATINUM"];
const qualityKeywordToNumber: Record<VoidProjectionQuality, number> = {
VPQ_BRONZE: 0,
VPQ_SILVER: 1,
VPQ_GOLD: 2,
VPQ_PLATINUM: 3
};
// e.g. "/Lotus/Types/Game/Projections/T2VoidProjectionProteaPrimeDBronze" -> ["Lith", "W5", "VPQ_BRONZE"]
const parseProjection = (typeName: string): [string, string, VoidProjectionQuality] => {
const relic: IRelic | undefined = ExportRelics[typeName];
if (!relic) {
throw new Error(`Unknown projection ${typeName}`);
}
return [relic.era, relic.category, relic.quality];
};
const findProjection = (era: string, category: string, quality: VoidProjectionQuality): string => {
return Object.entries(ExportRelics).find(
([_, relic]) => relic.era == era && relic.category == category && relic.quality == quality
)![0];
};

View File

@ -0,0 +1,22 @@
import { RequestHandler } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getInventory } from "@/src/services/inventoryService";
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) => {
const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId);
const clientTaunt = JSON.parse(String(req.body)) as ITaunt;
logger.debug(`updating taunt ${clientTaunt.node} to state ${clientTaunt.state}`);
inventory.TauntHistory ??= [];
const taunt = inventory.TauntHistory.find(x => x.node == clientTaunt.node);
if (taunt) {
taunt.state = clientTaunt.state;
} else {
inventory.TauntHistory.push(clientTaunt);
}
await inventory.save();
res.end();
};

View File

@ -64,6 +64,7 @@ export const upgradesController: RequestHandler = async (req, res) => {
case "/Lotus/Types/Items/MiscItems/WeaponPrimaryArcaneUnlocker": case "/Lotus/Types/Items/MiscItems/WeaponPrimaryArcaneUnlocker":
case "/Lotus/Types/Items/MiscItems/WeaponSecondaryArcaneUnlocker": case "/Lotus/Types/Items/MiscItems/WeaponSecondaryArcaneUnlocker":
case "/Lotus/Types/Items/MiscItems/WeaponMeleeArcaneUnlocker": case "/Lotus/Types/Items/MiscItems/WeaponMeleeArcaneUnlocker":
case "/Lotus/Types/Items/MiscItems/WeaponAmpArcaneUnlocker":
for (const item of inventory[payload.ItemCategory]) { for (const item of inventory[payload.ItemCategory]) {
if (item._id.toString() == payload.ItemId.$oid) { if (item._id.toString() == payload.ItemId.$oid) {
item.Features ??= 0; item.Features ??= 0;

View File

@ -10,11 +10,13 @@ export const pushArchonCrystalUpgradeController: RequestHandler = async (req, re
if (suit) { if (suit) {
suit.ArchonCrystalUpgrades ??= []; suit.ArchonCrystalUpgrades ??= [];
const count = (req.query.count as number | undefined) ?? 1; const count = (req.query.count as number | undefined) ?? 1;
for (let i = 0; i != count; ++i) { if (count >= 1 && count <= 10000) {
suit.ArchonCrystalUpgrades.push({ UpgradeType: req.query.type as string }); for (let i = 0; i != count; ++i) {
suit.ArchonCrystalUpgrades.push({ UpgradeType: req.query.type as string });
}
await inventory.save();
res.end();
} }
await inventory.save();
res.end();
} }
res.status(400).end(); res.status(400).end();
}; };

View File

@ -3,6 +3,9 @@ import { /*NextFunction,*/ Request, Response } from "express";
const unknownEndpointHandler = (request: Request, response: Response) => { const unknownEndpointHandler = (request: Request, response: Response) => {
logger.error(`unknown endpoint ${request.method} ${request.path}`); logger.error(`unknown endpoint ${request.method} ${request.path}`);
if (request.body) {
logger.debug(`data provided to ${request.path}: ${String(request.body)}`);
}
response.status(404).json({ error: "endpoint was not found" }); response.status(404).json({ error: "endpoint was not found" });
}; };

View File

@ -31,7 +31,7 @@ import {
IFusionTreasure, IFusionTreasure,
ISpectreLoadout, ISpectreLoadout,
IWeaponSkinDatabase, IWeaponSkinDatabase,
ITauntHistory, ITaunt,
IPeriodicMissionCompletionDatabase, IPeriodicMissionCompletionDatabase,
IPeriodicMissionCompletionResponse, IPeriodicMissionCompletionResponse,
ILoreFragmentScan, ILoreFragmentScan,
@ -533,7 +533,7 @@ weaponSkinsSchema.set("toJSON", {
} }
}); });
const tauntHistorySchema = new Schema<ITauntHistory>( const tauntSchema = new Schema<ITaunt>(
{ {
node: String, node: String,
state: String state: String
@ -772,8 +772,8 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
//Ayatan Item //Ayatan Item
FusionTreasures: [fusionTreasuresSchema], FusionTreasures: [fusionTreasuresSchema],
//"node": "TreasureTutorial", "state": "TS_COMPLETED" //only used for Maroo apparently - { "node": "TreasureTutorial", "state": "TS_COMPLETED" }
TauntHistory: [tauntHistorySchema], TauntHistory: { type: [tauntSchema], default: undefined },
//noShow2FA,VisitPrimeVault etc //noShow2FA,VisitPrimeVault etc
WebFlags: Schema.Types.Mixed, WebFlags: Schema.Types.Mixed,

View File

@ -24,6 +24,7 @@ import { getShipController } from "@/src/controllers/api/getShipController";
import { getVendorInfoController } from "@/src/controllers/api/getVendorInfoController"; import { getVendorInfoController } from "@/src/controllers/api/getVendorInfoController";
import { giveKeyChainTriggeredItemsController } from "@/src/controllers/api/giveKeyChainTriggeredItemsController"; import { giveKeyChainTriggeredItemsController } from "@/src/controllers/api/giveKeyChainTriggeredItemsController";
import { giveKeyChainTriggeredMessageController } from "@/src/controllers/api/giveKeyChainTriggeredMessageController"; import { giveKeyChainTriggeredMessageController } from "@/src/controllers/api/giveKeyChainTriggeredMessageController";
import { gildWeaponController } from "@/src/controllers/api/gildWeaponController";
import { guildTechController } from "@/src/controllers/api/guildTechController"; import { guildTechController } from "@/src/controllers/api/guildTechController";
import { hostSessionController } from "@/src/controllers/api/hostSessionController"; import { hostSessionController } from "@/src/controllers/api/hostSessionController";
import { hubController } from "@/src/controllers/api/hubController"; import { hubController } from "@/src/controllers/api/hubController";
@ -41,6 +42,7 @@ import { missionInventoryUpdateController } from "@/src/controllers/api/missionI
import { modularWeaponCraftingController } from "@/src/controllers/api/modularWeaponCraftingController"; import { modularWeaponCraftingController } from "@/src/controllers/api/modularWeaponCraftingController";
import { modularWeaponSaleController } from "@/src/controllers/api/modularWeaponSaleController"; import { modularWeaponSaleController } from "@/src/controllers/api/modularWeaponSaleController";
import { nameWeaponController } from "@/src/controllers/api/nameWeaponController"; import { nameWeaponController } from "@/src/controllers/api/nameWeaponController";
import { projectionManagerController } from "../controllers/api/projectionManagerController";
import { purchaseController } from "@/src/controllers/api/purchaseController"; import { purchaseController } from "@/src/controllers/api/purchaseController";
import { queueDojoComponentDestructionController } from "@/src/controllers/api/queueDojoComponentDestructionController"; import { queueDojoComponentDestructionController } from "@/src/controllers/api/queueDojoComponentDestructionController";
import { rerollRandomModController } from "@/src/controllers/api/rerollRandomModController"; import { rerollRandomModController } from "@/src/controllers/api/rerollRandomModController";
@ -57,7 +59,8 @@ import { startDojoRecipeController } from "@/src/controllers/api/startDojoRecipe
import { startRecipeController } from "@/src/controllers/api/startRecipeController"; import { startRecipeController } from "@/src/controllers/api/startRecipeController";
import { stepSequencersController } from "@/src/controllers/api/stepSequencersController"; import { stepSequencersController } from "@/src/controllers/api/stepSequencersController";
import { surveysController } from "@/src/controllers/api/surveysController"; import { surveysController } from "@/src/controllers/api/surveysController";
import { syndicateSacrificeController } from "@/src/controllers/api/syndicateSacrificeController"; import { syndicateSacrificeController } from "../controllers/api/syndicateSacrificeController";
import { tauntHistoryController } from "@/src/controllers/api/tauntHistoryController";
import { trainingResultController } from "@/src/controllers/api/trainingResultController"; import { trainingResultController } from "@/src/controllers/api/trainingResultController";
import { unlockShipFeatureController } from "@/src/controllers/api/unlockShipFeatureController"; import { unlockShipFeatureController } from "@/src/controllers/api/unlockShipFeatureController";
import { updateChallengeProgressController } from "@/src/controllers/api/updateChallengeProgressController"; import { updateChallengeProgressController } from "@/src/controllers/api/updateChallengeProgressController";
@ -65,7 +68,6 @@ import { updateQuestController } from "@/src/controllers/api/updateQuestControll
import { updateSessionGetController, updateSessionPostController } from "@/src/controllers/api/updateSessionController"; import { updateSessionGetController, updateSessionPostController } from "@/src/controllers/api/updateSessionController";
import { updateThemeController } from "@/src/controllers/api/updateThemeController"; import { updateThemeController } from "@/src/controllers/api/updateThemeController";
import { upgradesController } from "@/src/controllers/api/upgradesController"; import { upgradesController } from "@/src/controllers/api/upgradesController";
import { gildWeaponController } from "@/src/controllers/api/gildWeaponController";
const apiRouter = express.Router(); const apiRouter = express.Router();
@ -123,6 +125,7 @@ apiRouter.post("/login.php", loginController);
apiRouter.post("/missionInventoryUpdate.php", missionInventoryUpdateController); apiRouter.post("/missionInventoryUpdate.php", missionInventoryUpdateController);
apiRouter.post("/modularWeaponCrafting.php", modularWeaponCraftingController); apiRouter.post("/modularWeaponCrafting.php", modularWeaponCraftingController);
apiRouter.post("/nameWeapon.php", nameWeaponController); apiRouter.post("/nameWeapon.php", nameWeaponController);
apiRouter.post("/projectionManager.php", projectionManagerController);
apiRouter.post("/purchase.php", purchaseController); apiRouter.post("/purchase.php", purchaseController);
apiRouter.post("/rerollRandomMod.php", rerollRandomModController); apiRouter.post("/rerollRandomMod.php", rerollRandomModController);
apiRouter.post("/saveLoadout.php", saveLoadoutController); apiRouter.post("/saveLoadout.php", saveLoadoutController);
@ -134,6 +137,7 @@ apiRouter.post("/startDojoRecipe.php", startDojoRecipeController);
apiRouter.post("/startRecipe.php", startRecipeController); apiRouter.post("/startRecipe.php", startRecipeController);
apiRouter.post("/stepSequencers.php", stepSequencersController); apiRouter.post("/stepSequencers.php", stepSequencersController);
apiRouter.post("/syndicateSacrifice.php", syndicateSacrificeController); apiRouter.post("/syndicateSacrifice.php", syndicateSacrificeController);
apiRouter.post("/tauntHistory.php", tauntHistoryController);
apiRouter.post("/trainingResult.php", trainingResultController); apiRouter.post("/trainingResult.php", trainingResultController);
apiRouter.post("/unlockShipFeature.php", unlockShipFeatureController); apiRouter.post("/unlockShipFeature.php", unlockShipFeatureController);
apiRouter.post("/updateChallengeProgress.php", updateChallengeProgressController); apiRouter.post("/updateChallengeProgress.php", updateChallengeProgressController);

View File

@ -28,6 +28,7 @@ interface IConfig {
autoCreateAccount?: boolean; autoCreateAccount?: boolean;
skipStoryModeChoice?: boolean; skipStoryModeChoice?: boolean;
skipTutorial?: boolean; skipTutorial?: boolean;
skipAllDialogue?: boolean;
unlockAllScans?: boolean; unlockAllScans?: boolean;
unlockAllMissions?: boolean; unlockAllMissions?: boolean;
unlockAllQuests?: boolean; unlockAllQuests?: boolean;

View File

@ -2,7 +2,7 @@ import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
import new_inventory from "@/static/fixed_responses/postTutorialInventory.json"; import new_inventory from "@/static/fixed_responses/postTutorialInventory.json";
import { config } from "@/src/services/configService"; import { config } from "@/src/services/configService";
import { Types } from "mongoose"; import { Types } from "mongoose";
import { SlotNames, IInventoryChanges } from "@/src/types/purchaseTypes"; import { SlotNames, IInventoryChanges, IBinChanges } from "@/src/types/purchaseTypes";
import { import {
IChallengeProgress, IChallengeProgress,
IConsumable, IConsumable,
@ -19,7 +19,8 @@ import {
KubrowPetEggItemType, KubrowPetEggItemType,
IKubrowPetEgg, IKubrowPetEgg,
TEquipmentKey, TEquipmentKey,
equipmentKeys equipmentKeys,
IFusionTreasure
} from "@/src/types/inventoryTypes/inventoryTypes"; } from "@/src/types/inventoryTypes/inventoryTypes";
import { IGenericUpdate } from "../types/genericUpdate"; import { IGenericUpdate } from "../types/genericUpdate";
import { import {
@ -34,6 +35,7 @@ import { ISyndicateSacrifice, ISyndicateSacrificeResponse } from "../types/syndi
import { IEquipmentClient, IEquipmentDatabase } from "../types/inventoryTypes/commonInventoryTypes"; import { IEquipmentClient, IEquipmentDatabase } from "../types/inventoryTypes/commonInventoryTypes";
import { import {
ExportArcanes, ExportArcanes,
ExportBoosterPacks,
ExportCustoms, ExportCustoms,
ExportFlavour, ExportFlavour,
ExportFusionBundles, ExportFusionBundles,
@ -44,6 +46,7 @@ import {
} from "warframe-public-export-plus"; } from "warframe-public-export-plus";
import { updateQuestKeys } from "./questService"; import { updateQuestKeys } from "./questService";
import { toOid } from "../helpers/inventoryHelpers"; import { toOid } from "../helpers/inventoryHelpers";
import { getRandomWeightedReward } from "./rngService";
export const createInventory = async ( export const createInventory = async (
accountOwnerId: Types.ObjectId, accountOwnerId: Types.ObjectId,
@ -73,6 +76,31 @@ export const createInventory = async (
} }
}; };
export const combineInventoryChanges = (InventoryChanges: IInventoryChanges, delta: IInventoryChanges): void => {
for (const key in delta) {
if (!(key in InventoryChanges)) {
InventoryChanges[key] = delta[key];
} else if (Array.isArray(delta[key])) {
const left = InventoryChanges[key] as object[];
const right: object[] = delta[key] as object[];
for (const item of right) {
left.push(item);
}
} else {
console.assert(key.substring(-3) == "Bin");
const left = InventoryChanges[key] as IBinChanges;
const right: IBinChanges = delta[key] as IBinChanges;
left.count += right.count;
left.platinum += right.platinum;
left.Slots += right.Slots;
if (right.Extra) {
left.Extra ??= 0;
left.Extra += right.Extra;
}
}
}
};
export const getInventory = async (accountOwnerId: string) => { export const getInventory = async (accountOwnerId: string) => {
const inventory = await Inventory.findOne({ accountOwnerId: accountOwnerId }); const inventory = await Inventory.findOne({ accountOwnerId: accountOwnerId });
@ -228,7 +256,38 @@ export const addItem = async (
} }
}; };
} }
if (typeName in ExportBoosterPacks) {
const pack = ExportBoosterPacks[typeName];
const InventoryChanges = {};
for (const weights of pack.rarityWeightsPerRoll) {
const result = getRandomWeightedReward(pack.components, weights);
if (result) {
logger.debug(`booster pack rolled`, result);
combineInventoryChanges(
InventoryChanges,
(await addItem(accountId, result.type, result.itemCount)).InventoryChanges
);
}
}
return { InventoryChanges };
}
if (miscItems.includes(typeName)) {
const miscItemChanges = [
{
ItemType: typeName,
ItemCount: quantity
} satisfies IMiscItem
];
const inventory = await getInventory(accountId);
addMiscItems(inventory, miscItemChanges);
await inventory.save();
return {
InventoryChanges: {
MiscItems: miscItemChanges
}
};
}
// Path-based duck typing // Path-based duck typing
switch (typeName.substring(1).split("/")[1]) { switch (typeName.substring(1).split("/")[1]) {
case "Powersuits": case "Powersuits":
@ -368,8 +427,26 @@ export const addItem = async (
} }
} }
} }
case "Restoratives": { case "Game":
// Codex Scanner, Remote Observer, Starburst if (typeName.substring(1).split("/")[3] == "Projections") {
// Void Relics, e.g. /Lotus/Types/Game/Projections/T2VoidProjectionGaussPrimeDBronze
const inventory = await getInventory(accountId);
const miscItemChanges = [
{
ItemType: typeName,
ItemCount: quantity
} satisfies IMiscItem
];
addMiscItems(inventory, miscItemChanges);
await inventory.save();
return {
InventoryChanges: {
MiscItems: miscItemChanges
}
};
}
break;
case "Restoratives": // Codex Scanner, Remote Observer, Starburst
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
const consumablesChanges = [ const consumablesChanges = [
{ {
@ -384,26 +461,9 @@ export const addItem = async (
Consumables: consumablesChanges Consumables: consumablesChanges
} }
}; };
}
} }
break; break;
} }
if (miscItems.includes(typeName)) {
const miscItemChanges = [
{
ItemType: typeName,
ItemCount: quantity
} satisfies IMiscItem
];
const inventory = await getInventory(accountId);
addMiscItems(inventory, miscItemChanges);
await inventory.save();
return {
InventoryChanges: {
MiscItems: miscItemChanges
}
};
}
const errorMessage = `unable to add item: ${typeName}`; const errorMessage = `unable to add item: ${typeName}`;
logger.error(errorMessage); logger.error(errorMessage);
throw new Error(errorMessage); throw new Error(errorMessage);
@ -716,6 +776,26 @@ export const addMods = (inventory: IInventoryDatabaseDocument, itemsArray: IRawU
}); });
}; };
export const addFusionTreasures = (
inventory: IInventoryDatabaseDocument,
itemsArray: IFusionTreasure[] | undefined
) => {
const { FusionTreasures } = inventory;
itemsArray?.forEach(({ ItemType, ItemCount, Sockets }) => {
const itemIndex = FusionTreasures.findIndex(i => {
i.ItemType === ItemType;
i.Sockets === Sockets;
});
if (itemIndex !== -1) {
FusionTreasures[itemIndex].ItemCount += ItemCount;
inventory.markModified(`FusionTreasures.${itemIndex}.ItemCount`);
} else {
FusionTreasures.push({ ItemCount, ItemType, Sockets });
}
});
};
export const updateChallengeProgress = async (challenges: IUpdateChallengeProgressRequest, accountId: string) => { export const updateChallengeProgress = async (challenges: IUpdateChallengeProgressRequest, accountId: string) => {
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
@ -779,7 +859,8 @@ export const missionInventoryUpdate = async (data: IMissionInventoryUpdateReques
Consumables, Consumables,
Recipes, Recipes,
Missions, Missions,
QuestKeys QuestKeys,
FusionTreasures
} = data; } = data;
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
@ -837,6 +918,7 @@ export const missionInventoryUpdate = async (data: IMissionInventoryUpdateReques
addConsumables(inventory, Consumables); addConsumables(inventory, Consumables);
addRecipes(inventory, Recipes); addRecipes(inventory, Recipes);
addChallenges(inventory, ChallengeProgress); addChallenges(inventory, ChallengeProgress);
addFusionTreasures(inventory, FusionTreasures);
if (Missions) { if (Missions) {
addMissionComplete(inventory, Missions); addMissionComplete(inventory, Missions);
} }

View File

@ -13,6 +13,7 @@ import {
} from "warframe-public-export-plus"; } from "warframe-public-export-plus";
import { IMissionInventoryUpdateRequest } from "../types/requestTypes"; import { IMissionInventoryUpdateRequest } from "../types/requestTypes";
import { logger } from "@/src/utils/logger"; import { logger } from "@/src/utils/logger";
import { IRngResult, getRandomReward } from "@/src/services/rngService";
// need reverse engineer rewardSeed, otherwise ingame displayed rotation reward will be different than added to db or displayed on mission end // need reverse engineer rewardSeed, otherwise ingame displayed rotation reward will be different than added to db or displayed on mission end
const getRewards = ({ const getRewards = ({
@ -25,7 +26,7 @@ const getRewards = ({
return { InventoryChanges: {}, MissionRewards: [] }; return { InventoryChanges: {}, MissionRewards: [] };
} }
const drops: IReward[] = []; const drops: IRngResult[] = [];
if (RewardInfo.node in ExportRegions) { if (RewardInfo.node in ExportRegions) {
const region = ExportRegions[RewardInfo.node]; const region = ExportRegions[RewardInfo.node];
const rewardManifests = region.rewardManifests ?? []; const rewardManifests = region.rewardManifests ?? [];
@ -127,21 +128,8 @@ const getRotations = (rotationCount: number): number[] => {
return rotatedValues; return rotatedValues;
}; };
const getRandomRewardByChance = (data: IReward[]): IReward | undefined => { const getRandomRewardByChance = (pool: IReward[]): IRngResult | undefined => {
if (data.length == 0) return; return getRandomReward(pool as IRngResult[]);
const totalChance = data.reduce((sum, item) => sum + item.probability!, 0);
const randomValue = Math.random() * totalChance;
let cumulativeChance = 0;
for (const item of data) {
cumulativeChance += item.probability!;
if (randomValue <= cumulativeChance) {
return item;
}
}
return;
}; };
const creditBundles: Record<string, number> = { const creditBundles: Record<string, number> = {
@ -157,7 +145,7 @@ const creditBundles: Record<string, number> = {
"/Lotus/StoreItems/Types/StoreItems/CreditBundles/Zariman/TableACreditsUncommon": 30000, "/Lotus/StoreItems/Types/StoreItems/CreditBundles/Zariman/TableACreditsUncommon": 30000,
"/Lotus/StoreItems/Types/PickUps/Credits/CorpusArenaCreditRewards/CorpusArenaRewardOneHard": 105000, "/Lotus/StoreItems/Types/PickUps/Credits/CorpusArenaCreditRewards/CorpusArenaRewardOneHard": 105000,
"/Lotus/StoreItems/Types/PickUps/Credits/CorpusArenaCreditRewards/CorpusArenaRewardTwoHard": 175000, "/Lotus/StoreItems/Types/PickUps/Credits/CorpusArenaCreditRewards/CorpusArenaRewardTwoHard": 175000,
"/Lotus/StoreItems/Types/PickUps/Credits/CorpusArenaCreditRewards/CorpusArenaRewardThreeHard": 25000 "/Lotus/StoreItems/Types/PickUps/Credits/CorpusArenaCreditRewards/CorpusArenaRewardThreeHard": 250000
}; };
const fusionBundles: Record<string, number> = { const fusionBundles: Record<string, number> = {
@ -167,7 +155,7 @@ const fusionBundles: Record<string, number> = {
}; };
const formatRewardsToInventoryType = ( const formatRewardsToInventoryType = (
rewards: IReward[] rewards: IRngResult[]
): { InventoryChanges: IMissionInventoryUpdateRequest; MissionRewards: IMissionRewardResponse[] } => { ): { InventoryChanges: IMissionInventoryUpdateRequest; MissionRewards: IMissionRewardResponse[] } => {
const InventoryChanges: IMissionInventoryUpdateRequest = {}; const InventoryChanges: IMissionInventoryUpdateRequest = {};
const MissionRewards: IMissionRewardResponse[] = []; const MissionRewards: IMissionRewardResponse[] = [];
@ -211,7 +199,7 @@ const addRewardResponse = (
InventoryChanges[InventoryCategory] = []; InventoryChanges[InventoryCategory] = [];
} }
const existReward = InventoryChanges[InventoryCategory]!.find(item => item.ItemType === ItemType); const existReward = InventoryChanges[InventoryCategory].find(item => item.ItemType === ItemType);
if (existReward) { if (existReward) {
existReward.ItemCount += ItemCount; existReward.ItemCount += ItemCount;
const missionReward = MissionRewards.find(missionReward => missionReward.TypeName === ItemType); const missionReward = MissionRewards.find(missionReward => missionReward.TypeName === ItemType);
@ -219,7 +207,7 @@ const addRewardResponse = (
missionReward.ItemCount += ItemCount; missionReward.ItemCount += ItemCount;
} }
} else { } else {
InventoryChanges[InventoryCategory]!.push({ ItemType, ItemCount }); InventoryChanges[InventoryCategory].push({ ItemType, ItemCount });
MissionRewards.push({ MissionRewards.push({
ItemCount, ItemCount,
TweetText: ItemType, // ensure if/how this even still used, or if it's needed at all TweetText: ItemType, // ensure if/how this even still used, or if it's needed at all

View File

@ -1,7 +1,13 @@
import { parseSlotPurchaseName } from "@/src/helpers/purchaseHelpers"; import { parseSlotPurchaseName } from "@/src/helpers/purchaseHelpers";
import { getSubstringFromKeyword } from "@/src/helpers/stringHelpers"; import { getSubstringFromKeyword } from "@/src/helpers/stringHelpers";
import { addItem, addBooster, updateCurrency, updateSlots } from "@/src/services/inventoryService"; import {
import { IPurchaseRequest, SlotPurchase, IInventoryChanges, IBinChanges } from "@/src/types/purchaseTypes"; addItem,
addBooster,
combineInventoryChanges,
updateCurrency,
updateSlots
} from "@/src/services/inventoryService";
import { IPurchaseRequest, SlotPurchase, IInventoryChanges } from "@/src/types/purchaseTypes";
import { logger } from "@/src/utils/logger"; import { logger } from "@/src/utils/logger";
import { ExportBundles, ExportGear, TRarity } from "warframe-public-export-plus"; import { ExportBundles, ExportGear, TRarity } from "warframe-public-export-plus";
@ -46,31 +52,6 @@ export const handlePurchase = async (purchaseRequest: IPurchaseRequest, accountI
return purchaseResponse; return purchaseResponse;
}; };
const addInventoryChanges = (InventoryChanges: IInventoryChanges, delta: IInventoryChanges): void => {
for (const key in delta) {
if (!(key in InventoryChanges)) {
InventoryChanges[key] = delta[key];
} else if (Array.isArray(delta[key])) {
const left = InventoryChanges[key] as object[];
const right = delta[key] as object[];
for (const item of right) {
left.push(item);
}
} else {
console.assert(key.substring(-3) == "Bin");
const left = InventoryChanges[key] as IBinChanges;
const right = delta[key] as IBinChanges;
left.count += right.count;
left.platinum += right.platinum;
left.Slots += right.Slots;
if (right.Extra) {
left.Extra ??= 0;
left.Extra += right.Extra;
}
}
}
};
const handleStoreItemAcquisition = async ( const handleStoreItemAcquisition = async (
storeItemName: string, storeItemName: string,
accountId: string, accountId: string,
@ -86,7 +67,7 @@ const handleStoreItemAcquisition = async (
const bundle = ExportBundles[storeItemName]; const bundle = ExportBundles[storeItemName];
logger.debug("acquiring bundle", bundle); logger.debug("acquiring bundle", bundle);
for (const component of bundle.components) { for (const component of bundle.components) {
addInventoryChanges( combineInventoryChanges(
purchaseResponse.InventoryChanges, purchaseResponse.InventoryChanges,
( (
await handleStoreItemAcquisition( await handleStoreItemAcquisition(

View File

@ -0,0 +1,42 @@
import { TRarity } from "warframe-public-export-plus";
export interface IRngResult {
type: string;
itemCount: number;
probability: number;
}
export const getRandomReward = (pool: IRngResult[]): IRngResult | undefined => {
if (pool.length == 0) return;
const totalChance = pool.reduce((accum, item) => accum + item.probability, 0);
const randomValue = Math.random() * totalChance;
let cumulativeChance = 0;
for (const item of pool) {
cumulativeChance += item.probability;
if (randomValue <= cumulativeChance) {
return item;
}
}
throw new Error("What the fuck?");
};
export const getRandomWeightedReward = (
pool: { Item: string; Rarity: TRarity }[],
weights: Record<TRarity, number>
): IRngResult | undefined => {
const resultPool: IRngResult[] = [];
const rarityCounts: Record<TRarity, number> = { COMMON: 0, UNCOMMON: 0, RARE: 0, LEGENDARY: 0 };
for (const entry of pool) {
++rarityCounts[entry.Rarity];
}
for (const entry of pool) {
resultPool.push({
type: entry.Item,
itemCount: 1,
probability: weights[entry.Rarity] / rarityCounts[entry.Rarity]
});
}
return getRandomReward(resultPool);
};

View File

@ -167,8 +167,9 @@ export const handleInventoryItemConfigChange = async (
inventory.CurrentLoadOutIds = loadoutIds; inventory.CurrentLoadOutIds = loadoutIds;
break; break;
} }
case "EquippedGear": { case "EquippedGear":
inventory.EquippedGear = equipment as string[]; case "EquippedEmotes": {
inventory[equipmentName] = equipment as string[];
break; break;
} }
case "UseAdultOperatorLoadout": { case "UseAdultOperatorLoadout": {

View File

@ -177,7 +177,7 @@ export interface IInventoryResponse {
CompletedAlerts: string[]; CompletedAlerts: string[];
Consumables: IConsumable[]; Consumables: IConsumable[];
LevelKeys: IConsumable[]; LevelKeys: IConsumable[];
TauntHistory: ITauntHistory[]; TauntHistory?: ITaunt[];
StoryModeChoice: string; StoryModeChoice: string;
PeriodicMissionCompletions: IPeriodicMissionCompletionDatabase[]; PeriodicMissionCompletions: IPeriodicMissionCompletionDatabase[];
KubrowPetEggs: IKubrowPetEgg[]; KubrowPetEggs: IKubrowPetEgg[];
@ -888,9 +888,9 @@ export interface INotePacks {
PERCUSSION: string; PERCUSSION: string;
} }
export interface ITauntHistory { export interface ITaunt {
node: string; node: string;
state: string; state: "TS_UNLOCKED" | "TS_COMPLETED";
} }
export interface IWeaponSkinDatabase { export interface IWeaponSkinDatabase {

View File

@ -11,9 +11,10 @@ import {
IMission, IMission,
IRawUpgrade, IRawUpgrade,
ISeasonChallenge, ISeasonChallenge,
TEquipmentKey, TSolarMapRegion,
IQuestKeyDatabase, IQuestKeyDatabase,
TSolarMapRegion TEquipmentKey,
IFusionTreasure
} from "./inventoryTypes/inventoryTypes"; } from "./inventoryTypes/inventoryTypes";
export interface IArtifactsRequest { export interface IArtifactsRequest {
@ -62,6 +63,7 @@ export interface IMissionInventoryUpdateRequest {
RawUpgrades?: IRawUpgrade[]; RawUpgrades?: IRawUpgrade[];
MiscItems?: IMiscItem[]; MiscItems?: IMiscItem[];
Consumables?: IConsumable[]; Consumables?: IConsumable[];
FusionTreasures?: IFusionTreasure[];
Recipes?: IConsumable[]; Recipes?: IConsumable[];
RegularCredits?: number; RegularCredits?: number;
ChallengeProgress?: IChallengeProgress[]; ChallengeProgress?: IChallengeProgress[];

View File

@ -33,6 +33,7 @@ export interface ISaveLoadoutRequest {
CurrentLoadOutIds: IOid[]; CurrentLoadOutIds: IOid[];
ValidNewLoadoutId: string; ValidNewLoadoutId: string;
EquippedGear: string[]; EquippedGear: string[];
EquippedEmotes: string[];
UseAdultOperatorLoadout: boolean; UseAdultOperatorLoadout: boolean;
} }

View File

@ -0,0 +1,139 @@
[
"SolarisUnitedHub1",
"/Lotus/Language/SolarisVenus/FishmongerName",
"/Lotus/Language/SolarisVenus/ProspectorName",
"/Lotus/Language/SolarisVenus/StockbrokerName",
"/Lotus/Language/SolarisVenus/WeaponsmithShopName",
"/Lotus/Language/SolarisVenus/LegsShopName",
"/Lotus/Language/Actions/KDriveVendor",
"/Lotus/Language/SolarisVenus/SolarisUnitedContactName",
"SaturnWolf1",
"SaturnWolf2",
"SaturnWolf3",
"SaturnWolf4",
"SaturnWolf5",
"ConclaveSyndicate",
"ArbitersSyndicate",
"LibrarySyndicate",
"RedVeilSyndicate",
"PerrinSyndicate",
"CephalonSudaSyndicate",
"NewLokaSyndicate",
"SteelMeridianSyndicate",
"CetusSyndicate",
"QuillsSyndicate",
"VentKidsSyndicate",
"SolarisSyndicate",
"VoxSyndicate",
"RadioLegionSyndicate",
"EventSyndicate",
"TheEmissary1",
"TheEmissary2",
"TheEmissary3",
"TheEmissary4",
"LeverianIntro",
"TheEmissary5",
"RailjackMultiToolIntro",
"EnterRailjackOnceOnly",
"ScenarioEventHub5",
"Glassmaker1",
"/Lotus/Types/Items/Glassmaker/CetusBurnedNoteCEvidence",
"/Lotus/Types/Items/Glassmaker/CetusWeaponBEvidence",
"/Lotus/Types/Items/Glassmaker/CetusDatapadOneBEvidence",
"/Lotus/Types/Items/Glassmaker/CetusEyeBEvidence",
"/Lotus/Types/Items/Glassmaker/CetusDatapadTwoAEvidence",
"/Lotus/Types/Items/Glassmaker/WeaveEvidencePartOne",
"Glassmaker2",
"/Lotus/Types/Items/Glassmaker/CorpusJournalBEvidence",
"/Lotus/Types/Items/Glassmaker/CorpusCatalogRobotsEvidence",
"/Lotus/Types/Items/Glassmaker/CorpusDatapadEvidenceC",
"/Lotus/Types/Items/Glassmaker/CorpusHelmetEngineerEvidence",
"/Lotus/Types/Items/Glassmaker/CorpusBadgeMarsHiddenEvidence",
"/Lotus/Types/Items/Glassmaker/WeaveEvidencePartTwo",
"Glassmaker3",
"/Lotus/Types/Items/Glassmaker/GrineerTechCEvidence",
"/Lotus/Types/Items/Glassmaker/GrineerWeaponBEvidence",
"/Lotus/Types/Items/Glassmaker/GrineerPlushAEvidence",
"/Lotus/Types/Items/Glassmaker/GrineerMessageBEvidence",
"/Lotus/Types/Items/Glassmaker/GrineerDatapadBEvidence",
"/Lotus/Types/Items/Glassmaker/WeaveEvidencePartThree",
"TL20Start",
"TL20End",
"EudicoHeists",
"Glassmaker4",
"/Lotus/Types/Items/Glassmaker/OrokinManifestoBEvidence",
"/Lotus/Types/Items/Glassmaker/OrokinDatapadBEvidence",
"/Lotus/Types/Items/Glassmaker/OrokinNihilPlanCEvidence",
"/Lotus/Types/Items/Glassmaker/OrokinAppraisalBEvidence",
"/Lotus/Types/Items/Glassmaker/OrokinDossierAEvidence",
"/Lotus/Types/Items/Glassmaker/WeaveEvidencePartFour",
"/Lotus/Language/SolarisVenus/LegsShopNameLoved",
"/Lotus/Language/SolarisVenus/EudicoLoved",
"/Lotus/Language/SolarisVenus/ProspectorNameLoved",
"/Lotus/Language/SolarisVenus/StockbrokerNameLoved",
"/Lotus/Language/SolarisVenus/WeaponsmithShopNameLoved",
"/Lotus/Language/SolarisVenus/FishmongerNameLoved",
"DeimosHub",
"EntratiSyndicate",
"/Lotus/Language/InfestedMicroplanet/HivemindTokenVendorName",
"/Lotus/Language/InfestedMicroplanet/HivemindProspector",
"/Lotus/Language/InfestedMicroplanet/HivemindGunsmithName",
"/Lotus/Language/InfestedMicroplanet/HivemindPetVendor",
"ModularCrafting45",
"ModularCrafting55",
"NecraloidSyndicate",
"/Lotus/Language/InfestedMicroplanet/HivemindMechsName",
"/Lotus/Language/Npcs/EntratiMother",
"/Lotus/Language/InfestedMicroplanet/HivemindFishmonger",
"/Lotus/Language/SolarisVenus/SolarisUnitedAgentLoved",
"Glassmaker5",
"/Lotus/Types/Items/Glassmaker/InfestedOroShardsAEvidence",
"/Lotus/Types/Items/Glassmaker/InfestedOroWeaponCEvidence",
"/Lotus/Types/Items/Glassmaker/InfestedOroProbeBEvidence",
"/Lotus/Types/Items/Glassmaker/InfestedOroShackleBEvidence",
"/Lotus/Types/Items/Glassmaker/InfestedOroTabletBEvidence",
"/Lotus/Types/Items/Glassmaker/WeaveEvidencePartFive",
"GlassmakerBossFight",
"/Lotus/Language/InfestedMicroplanet/HivemindGunsmithNameLoved",
"/Lotus/Language/InfestedMicroplanet/HivemindTokenVendorNameLoved",
"/Lotus/Language/Npcs/EntratiMotherLoved",
"/Lotus/Language/InfestedMicroplanet/HivemindPetVendorLoved",
"/Lotus/Language/InfestedMicroplanet/HivemindFishmongerLoved",
"/Lotus/Language/InfestedMicroplanet/HivemindProspectorLoved",
"/Lotus/Language/InfestedMicroplanet/HivemindMechsNameLoved",
"/Lotus/Language/InfestedMicroplanet/HivemindPetVendorName",
"/Lotus/Language/InfestedMicroplanet/HivemindPetVendorNameLoved",
"/Lotus/Language/InfestedMicroplanet/HivemindFishmongerName",
"/Lotus/Language/InfestedMicroplanet/HivemindFishmongerNameLoved",
"/Lotus/Language/InfestedMicroplanet/HivemindProspectorName",
"/Lotus/Language/InfestedMicroplanet/HivemindProspectorNameLoved",
"DebtTokenVendorCrewMembers_FirstVisit",
"ZarimanSyndicate",
"/Lotus/Language/Npcs/Kahl",
"RankZeroConversationOne",
"RankZeroConversationTwo",
"EntratiLabSyndicate",
"/Lotus/Language/EntratiLab/EntratiGeneral/HumanLoid",
"/Lotus/Language/EntratiLab/EntratiGeneral/Fibonacci",
"/Lotus/Language/EntratiLab/EntratiGeneral/BirdThree",
"/Lotus/Language/Zariman/Quinn",
"/Lotus/Language/EntratiLab/EntratiGeneral/TagferFirstRank1",
"VoidVaultIntro",
"PurchasePlatformLockedNotificationSeen",
"/Lotus/Language/Zariman/Yonta",
"ZarimanSyndicateFirstOpen",
"HivemindTokenVendorBarter_FirstVisit",
"OtakLastWishManifest_FirstVisit",
"/Lotus/Language/Zariman/Cavalero",
"/Lotus/Language/Duviri/Acrithis",
"/Lotus/Language/Npcs/PrimeVaultTrader",
"/Lotus/Language/Zariman/Hombask",
"EntratiLabDisruptionManifest_FirstVisit",
"/Lotus/Language/EntratiLab/EntratiGeneral/BirdThreeLoved",
"/Lotus/Language/EntratiLab/EntratiGeneral/TagferFirstRank5",
"DanteLeverian",
"/Lotus/Language/EntratiLab/EntratiGeneral/HumanLoidLoved",
"ConquestSetupIntro",
"EntratiLabConquestHardModeUnlocked",
"/Lotus/Language/Npcs/KonzuPostNewWar"
]

View File

@ -0,0 +1,38 @@
{
"VendorInfo": {
"_id": { "$oid": "62695b0467e5d379750f9f75" },
"TypeName": "/Lotus/Types/Game/VendorManifests/Zariman/ArchimedeanVendorManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/VoidPlumeAOrnament",
"ItemPrices": [{ "ItemCount": 1, "ItemType": "/Lotus/Types/Gameplay/Zariman/Resources/VoidAngelItem", "ProductCategory": "MiscItems" }],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
"AllowMultipurchase": true,
"Id": { "$oid": "63ed01ef4c37f93d0b797826" }
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/VoidPlumeBOrnament",
"ItemPrices": [{ "ItemCount": 1, "ItemType": "/Lotus/Types/Gameplay/Zariman/Resources/VoidAngelItem", "ProductCategory": "MiscItems" }],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
"AllowMultipurchase": true,
"Id": { "$oid": "63ed01ef4c37f93d0b797827" }
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/Kuva",
"ItemPrices": [{ "ItemCount": 5, "ItemType": "/Lotus/Types/Gameplay/Zariman/Resources/VoidAngelItem", "ProductCategory": "MiscItems" }],
"Bin": "BIN_0",
"QuantityMultiplier": 35000,
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": { "$oid": "66664112af1177b5070ab882" }
}
],
"PropertyTextHash": "DB7BF03C3FE6D0036A4DC30066A9A17E",
"Expiry": { "$date": { "$numberLong": "9999999000000" } }
}
}

View File

@ -0,0 +1,75 @@
{
"VendorInfo": {
"_id": { "$oid": "62a20ba667e5d3797540d831" },
"TypeName": "/Lotus/Types/Game/VendorManifests/Zariman/ZarimanCommisionsManifestArchimedean",
"ItemManifest": [
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Zariman/AchimedeanTaskE",
"ItemPrices": [
{ "ItemType": "/Lotus/Types/Gameplay/Zariman/Resources/ZarimanMiscItemB", "ItemCount": 4, "ProductCategory": "MiscItems" },
{ "ItemType": "/Lotus/Types/Gameplay/Zariman/Resources/ZarimanMiscItemA", "ItemCount": 6, "ProductCategory": "MiscItems" }
],
"Bin": "BIN_4",
"QuantityMultiplier": 1,
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": { "$oid": "6678b612aa3d8ee5c2597299" }
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Zariman/AchimedeanTaskD",
"ItemPrices": [
{ "ItemType": "/Lotus/Types/Gameplay/Zariman/Resources/ZarimanMiscItemA", "ItemCount": 5, "ProductCategory": "MiscItems" },
{ "ItemType": "/Lotus/Types/Gameplay/Zariman/Resources/ZarimanMiscItemB", "ItemCount": 3, "ProductCategory": "MiscItems" }
],
"Bin": "BIN_3",
"QuantityMultiplier": 1,
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": { "$oid": "6678b612aa3d8ee5c259729a" }
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Zariman/AchimedeanTaskC",
"ItemPrices": [
{ "ItemType": "/Lotus/Types/Gameplay/Zariman/Resources/VoidWraithItem", "ItemCount": 15, "ProductCategory": "MiscItems" },
{ "ItemType": "/Lotus/Types/Gameplay/Zariman/Resources/ZarimanDogTagUncommon", "ItemCount": 1, "ProductCategory": "MiscItems" }
],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": { "$oid": "6678b612aa3d8ee5c259729b" }
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Zariman/AchimedeanTaskB",
"ItemPrices": [
{ "ItemType": "/Lotus/Types/Gameplay/Zariman/Resources/VoidWraithItem", "ItemCount": 4, "ProductCategory": "MiscItems" },
{ "ItemType": "/Lotus/Types/Gameplay/Zariman/Resources/ZarimanMiscItemB", "ItemCount": 1, "ProductCategory": "MiscItems" }
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": { "$oid": "6678b612aa3d8ee5c259729c" }
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Zariman/AchimedeanTaskA",
"ItemPrices": [
{ "ItemType": "/Lotus/Types/Gameplay/Zariman/Resources/ZarimanMiscItemB", "ItemCount": 1, "ProductCategory": "MiscItems" },
{ "ItemType": "/Lotus/Types/Gameplay/Zariman/Resources/ZarimanMiscItemA", "ItemCount": 2, "ProductCategory": "MiscItems" }
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": { "$oid": "6678b612aa3d8ee5c259729d" }
}
],
"PropertyTextHash": "F43F0ED811985EEF856970A8342EF322",
"Expiry": { "$date": { "$numberLong": "9999999000000" } }
}
}

View File

@ -1,21 +1,21 @@
{ {
"Events": [ "Events": [
{ {
"Msg": "Join the OpenWF Discord!",
"Messages": [ "Messages": [
{ "LanguageCode": "en", "Message": "Join the OpenWF Discord!" }, { "LanguageCode": "fr", "Message": "Rejoignez le Discord OpenWF!" },
{ "LanguageCode": "fr", "Message": "Join the OpenWF Discord!" }, { "LanguageCode": "it", "Message": "Unisciti al Discord di OpenWF!" },
{ "LanguageCode": "it", "Message": "Join the OpenWF Discord!" }, { "LanguageCode": "de", "Message": "Tritt dem OpenWF Discord bei!" },
{ "LanguageCode": "de", "Message": "Join the OpenWF Discord!" }, { "LanguageCode": "es", "Message": "Únete al Discord de OpenWF!" },
{ "LanguageCode": "es", "Message": "Join the OpenWF Discord!" }, { "LanguageCode": "pt", "Message": "Junte-se ao Discord do OpenWF!" },
{ "LanguageCode": "pt", "Message": "Join the OpenWF Discord!" }, { "LanguageCode": "ru", "Message": "Присоединяйтесь к OpenWF Discord!" },
{ "LanguageCode": "ru", "Message": "Join the OpenWF Discord!" }, { "LanguageCode": "pl", "Message": "Dołącz do Discord OpenWF!" },
{ "LanguageCode": "pl", "Message": "Join the OpenWF Discord!" }, { "LanguageCode": "uk", "Message": "Приєднуйтесь до OpenWF Discord!" },
{ "LanguageCode": "uk", "Message": "Join the OpenWF Discord!" }, { "LanguageCode": "tr", "Message": "OpenWF Discord'a katıl!" },
{ "LanguageCode": "tr", "Message": "Join the OpenWF Discord!" }, { "LanguageCode": "ja", "Message": "OpenWFのDiscordに参加しよう" },
{ "LanguageCode": "ja", "Message": "Join the OpenWF Discord!" }, { "LanguageCode": "zh", "Message": "加入OpenWF Discord!" },
{ "LanguageCode": "zh", "Message": "Join the OpenWF Discord!" }, { "LanguageCode": "ko", "Message": "OpenWF Discord에 가입하세요!" },
{ "LanguageCode": "ko", "Message": "Join the OpenWF Discord!" }, { "LanguageCode": "tc", "Message": "加入OpenWF Discord!" }
{ "LanguageCode": "tc", "Message": "Join the OpenWF Discord!" }
], ],
"Prop": "https://discord.gg/PNNZ3asUuY", "Prop": "https://discord.gg/PNNZ3asUuY",
"Icon": "/Lotus/Interface/Icons/DiscordIconNoBacker.png" "Icon": "/Lotus/Interface/Icons/DiscordIconNoBacker.png"

View File

@ -114,7 +114,7 @@
<div class="card-body"> <div class="card-body">
<p>You can use these unlimited slots to apply a wide range of upgrades.</p> <p>You can use these unlimited slots to apply a wide range of upgrades.</p>
<form class="input-group mb-3" onsubmit="doPushArchonCrystalUpgrade();return false;"> <form class="input-group mb-3" onsubmit="doPushArchonCrystalUpgrade();return false;">
<input type="number" id="archon-crystal-add-count" min="1" value="1" class="form-control" style="max-width:100px" /> <input type="number" id="archon-crystal-add-count" min="1" max="10000" value="1" class="form-control" style="max-width:100px" />
<span class="input-group-text">x</span> <span class="input-group-text">x</span>
<input class="form-control" list="datalist-archonCrystalUpgrades" /> <input class="form-control" list="datalist-archonCrystalUpgrades" />
<button class="btn btn-primary" type="submit">Add</button> <button class="btn btn-primary" type="submit">Add</button>
@ -188,6 +188,10 @@
<input class="form-check-input" type="checkbox" id="skipTutorial" /> <input class="form-check-input" type="checkbox" id="skipTutorial" />
<label class="form-check-label" for="skipTutorial">Skip Tutorial</label> <label class="form-check-label" for="skipTutorial">Skip Tutorial</label>
</div> </div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="skipAllDialogue" />
<label class="form-check-label" for="skipAllDialogue">Skip All Dialogue</label>
</div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllScans" /> <input class="form-check-input" type="checkbox" id="unlockAllScans" />
<label class="form-check-label" for="unlockAllScans">Unlock All Scans</label> <label class="form-check-label" for="unlockAllScans">Unlock All Scans</label>

View File

@ -731,6 +731,7 @@ const uiConfigs = [
"autoCreateAccount", "autoCreateAccount",
"skipStoryModeChoice", "skipStoryModeChoice",
"skipTutorial", "skipTutorial",
"skipAllDialogue",
"unlockAllScans", "unlockAllScans",
"unlockAllMissions", "unlockAllMissions",
"unlockAllQuests", "unlockAllQuests",

View File

@ -1,5 +1,4 @@
{ {
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": { "compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */ /* Visit https://aka.ms/tsconfig to read more about this file */
@ -12,8 +11,8 @@
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */ /* Language and Environment */
//"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, "target": "es2022" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
// "lib": ["es2023"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ "lib": ["es2023"] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
// "jsx": "preserve", /* Specify what JSX code is generated. */ // "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
@ -26,7 +25,7 @@
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */ /* Modules */
//"module": "commonjs" /* Specify what module code is generated. */, "module": "node16" /* Specify what module code is generated. */,
// "rootDir": "./", /* Specify the root folder within your source files. */ // "rootDir": "./", /* Specify the root folder within your source files. */
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */