forked from OpenWF/SpaceNinjaServer
Compare commits
211 Commits
Author | SHA1 | Date | |
---|---|---|---|
7bc5065251 | |||
3194a693b3 | |||
261dbd5fdf | |||
fd2ec696a0 | |||
9cc0c76ef5 | |||
2a4488d1dd | |||
2e1326cde8 | |||
70be467cbf | |||
fac3ec01c6 | |||
ebdca760e6 | |||
51c0ddda38 | |||
9129bdb5fc | |||
a4922d4c35 | |||
679752633a | |||
67b5890f39 | |||
5d54e79e5d | |||
4606f28a58 | |||
a2d383ee3c | |||
834b7a8196 | |||
4a2d863c9c | |||
9f0cd91105 | |||
ebfef52fb1 | |||
dd7bacd22e | |||
c00967931e | |||
b15a635e11 | |||
7e618539fa | |||
a29398fae6 | |||
601091f1c0 | |||
f561884f2c | |||
6e1cb0c9f9 | |||
9286627668 | |||
f94f2005d3 | |||
9901b7af54 | |||
2fa846f465 | |||
541ec3d702 | |||
0a28eab65d | |||
8e639a16bd | |||
522924a823 | |||
48e3f324e2 | |||
8f77c722cb | |||
e7287933b5 | |||
b21bca7a6d | |||
d30d450311 | |||
b62e326920 | |||
8b4bc114f6 | |||
564aa06762 | |||
2e84f71af8 | |||
ddfa98e0b2 | |||
bb3c3e01b0 | |||
695dcf98e0 | |||
509f7f0d9b | |||
aada031a80 | |||
a2a441ecb0 | |||
c0a0463a68 | |||
2307a40833 | |||
304af514e2 | |||
ddf3cd49b5 | |||
41e3f0136f | |||
c0ca9d9398 | |||
0f6b55beed | |||
f8550e9afe | |||
b53c4d9125 | |||
922b65cfab | |||
2f642df20a | |||
62314e89c7 | |||
56aa3e3331 | |||
c3f486488f | |||
49c353d895 | |||
90ab560620 | |||
b0e80fcfa8 | |||
2c62fb3c3c | |||
5b215733aa | |||
39866b9a2b | |||
fad1ee9314 | |||
64b43fcccf | |||
e407262cf8 | |||
00e57c43df | |||
2ab9f39507 | |||
b60723ef54 | |||
b3bf291d10 | |||
db86e2d265 | |||
f6cb8414c1 | |||
ba3df4bdbc | |||
8feb3a5b3c | |||
66f3d65d77 | |||
b18f06087b | |||
987b5b98ff | |||
fbbd9076cf | |||
838818543c | |||
a16e2716f1 | |||
f4c7ce582b | |||
c0187f9446 | |||
f796f9a851 | |||
e18b8e09ea | |||
0d8044b87c | |||
a109ea6c5d | |||
7eb95c995c | |||
dc8f32d4d8 | |||
ba70ba88dd | |||
08d4a03c50 | |||
45feff682b | |||
65be1083ce | |||
07e7c9e897 | |||
dcb26471c9 | |||
5a75d88385 | |||
a35572e306 | |||
c46c43f143 | |||
98ed2b5ee4 | |||
7aa1b12306 | |||
b410f6b554 | |||
1dffcf979f | |||
c86bba017b | |||
2c499cec3d | |||
d6145561fd | |||
1545cdb8ce | |||
80b5e2df7f | |||
76e61129bf | |||
ea3e299861 | |||
3d8c1d036a | |||
773f96ebbc | |||
2a80307c26 | |||
a40ff27fea | |||
c9a4359714 | |||
280ed8bef1 | |||
9c89e907b1 | |||
b54fd96098 | |||
c7c7fd4ea0 | |||
a75e6d6b95 | |||
5089f67146 | |||
0416221d15 | |||
26729ce21a | |||
ee4adc7d55 | |||
29aadf4e78 | |||
0b32bc21be | |||
e09e5ebec2 | |||
b2de8608c6 | |||
2b23db1433 | |||
a45bacc388 | |||
46d37d3688 | |||
41686aea88 | |||
61ac2f8b72 | |||
d2ab894c01 | |||
8c85cdcd1d | |||
aa6191f033 | |||
e26d2635fb | |||
dd6ae8898f | |||
499ca23ffb | |||
d3102acb7c | |||
363028c9ce | |||
1d60745f18 | |||
a9b3b16d31 | |||
fd1d72a1cf | |||
75832afdbe | |||
aa916d2820 | |||
5a5f6106a3 | |||
24d9dc27e2 | |||
5e05a15743 | |||
545b949202 | |||
0c9b27a29b | |||
cfa750b6f7 | |||
049baa4313 | |||
e267ca8f55 | |||
1a2d8ab19a | |||
8c19aec340 | |||
d1c860c693 | |||
69f9d5ebc5 | |||
d66f1c58d8 | |||
5234cf213e | |||
7c7d2b9061 | |||
3d46d05a6c | |||
00cea6788e | |||
58bdb2d2ec | |||
c4c622d82b | |||
44a129ab0b | |||
5a7caa5ba9 | |||
a9c5e30994 | |||
f0547cb9e6 | |||
ef3d3b92c7 | |||
a9359bd989 | |||
3d21813a79 | |||
7cad831702 | |||
0f2b6c68cd | |||
4fcac6dc37 | |||
d2cae012a7 | |||
b36d524953 | |||
abb5b8880f | |||
4895b4630b | |||
690b872b5e | |||
d77fe60cd8 | |||
3cae42c7d6 | |||
bbccee0637 | |||
31e24c27ad | |||
4acd87aae6 | |||
d8ff601be7 | |||
d79e7c0274 | |||
4f1f9592b0 | |||
764cdd1ab8 | |||
0ba641a2ac | |||
eb7b51852b | |||
a3be376489 | |||
d94cd38120 | |||
8c22555904 | |||
c9edef39f8 | |||
b42182c85f | |||
86f86d0476 | |||
0fdf8b2c75 | |||
285b1bbf60 | |||
731ce6c215 | |||
39630c5af7 | |||
d5be202835 | |||
3a6e4ac2e1 |
36
.eslintrc
36
.eslintrc
@ -1,36 +1,46 @@
|
|||||||
{
|
{
|
||||||
|
"plugins": ["@typescript-eslint", "prettier", "import"],
|
||||||
"extends": [
|
"extends": [
|
||||||
"eslint:recommended",
|
"eslint:recommended",
|
||||||
"plugin:@typescript-eslint/recommended",
|
"plugin:@typescript-eslint/recommended",
|
||||||
"plugin:@typescript-eslint/recommended-requiring-type-checking"
|
"plugin:@typescript-eslint/recommended-requiring-type-checking",
|
||||||
|
"plugin:import/recommended",
|
||||||
|
"plugin:import/typescript"
|
||||||
],
|
],
|
||||||
"plugins": ["@typescript-eslint", "prettier"],
|
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"es6": true,
|
"es6": true,
|
||||||
"node": true
|
"node": true
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"@typescript-eslint/explicit-function-return-type": "warn",
|
"@typescript-eslint/explicit-function-return-type": "error",
|
||||||
"@typescript-eslint/restrict-template-expressions": "warn",
|
"@typescript-eslint/restrict-template-expressions": "error",
|
||||||
"@typescript-eslint/restrict-plus-operands": "warn",
|
"@typescript-eslint/restrict-plus-operands": "error",
|
||||||
"@typescript-eslint/no-unsafe-member-access": "warn",
|
"@typescript-eslint/no-unsafe-member-access": "error",
|
||||||
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_", "caughtErrors": "none" }],
|
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_", "caughtErrors": "none" }],
|
||||||
"@typescript-eslint/no-unsafe-argument": "error",
|
"@typescript-eslint/no-unsafe-argument": "error",
|
||||||
"@typescript-eslint/no-unsafe-call": "warn",
|
"@typescript-eslint/no-unsafe-call": "error",
|
||||||
"@typescript-eslint/no-unsafe-assignment": "warn",
|
"@typescript-eslint/no-unsafe-assignment": "error",
|
||||||
"@typescript-eslint/no-explicit-any": "warn",
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
"no-loss-of-precision": "warn",
|
"no-loss-of-precision": "error",
|
||||||
"@typescript-eslint/no-unnecessary-condition": "warn",
|
"@typescript-eslint/no-unnecessary-condition": "error",
|
||||||
"@typescript-eslint/no-base-to-string": "off",
|
"@typescript-eslint/no-base-to-string": "off",
|
||||||
"no-case-declarations": "error",
|
"no-case-declarations": "error",
|
||||||
"prettier/prettier": "error",
|
"prettier/prettier": "error",
|
||||||
"no-mixed-spaces-and-tabs": "error",
|
"no-mixed-spaces-and-tabs": "error",
|
||||||
"require-await": "off",
|
"@typescript-eslint/require-await": "error",
|
||||||
"@typescript-eslint/require-await": "error"
|
"import/no-named-as-default-member": "off",
|
||||||
|
"import/no-cycle": "warn"
|
||||||
},
|
},
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"project": "./tsconfig.json"
|
"project": "./tsconfig.json"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"import/extensions": [ ".ts" ],
|
||||||
|
"import/resolver": {
|
||||||
|
"typescript": true,
|
||||||
|
"node": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@ -14,11 +14,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: ">=20.6.0"
|
node-version: ">=20.6.0"
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: cp config.json.example config.json
|
- run: cp config-vanilla.json config.json
|
||||||
- run: npm run verify
|
- run: npm run verify
|
||||||
- run: npm run lint:ci
|
- run: npm run lint:ci
|
||||||
- run: npm run prettier
|
- run: npm run prettier
|
||||||
- run: npm run update-translations
|
- run: npm run update-translations
|
||||||
|
- run: npm run fix-imports
|
||||||
- name: Fail if there are uncommitted changes
|
- name: Fail if there are uncommitted changes
|
||||||
run: |
|
run: |
|
||||||
if [[ -n "$(git status --porcelain)" ]]; then
|
if [[ -n "$(git status --porcelain)" ]]; then
|
||||||
|
@ -2,3 +2,4 @@ src/routes/api.ts
|
|||||||
static/webui/libs/
|
static/webui/libs/
|
||||||
*.html
|
*.html
|
||||||
*.md
|
*.md
|
||||||
|
config-vanilla.json
|
||||||
|
3
.vscode/launch.json
vendored
3
.vscode/launch.json
vendored
@ -8,8 +8,7 @@
|
|||||||
"type": "node",
|
"type": "node",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Debug and Watch",
|
"name": "Debug and Watch",
|
||||||
"runtimeArgs": ["-r", "tsconfig-paths/register", "-r", "ts-node/register", "--watch-path", "src"],
|
"args": ["${workspaceFolder}/scripts/dev.js"],
|
||||||
"args": ["${workspaceFolder}/src/index.ts"],
|
|
||||||
"console": "integratedTerminal"
|
"console": "integratedTerminal"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -7,5 +7,6 @@ WORKDIR /app
|
|||||||
|
|
||||||
RUN npm i --omit=dev
|
RUN npm i --omit=dev
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
RUN date '+%d %B %Y' > BUILD_DATE
|
||||||
|
|
||||||
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
||||||
|
@ -10,7 +10,7 @@ To get an idea of what functionality you can expect to be missing [have a look t
|
|||||||
|
|
||||||
## config.json
|
## config.json
|
||||||
|
|
||||||
SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [config.json.example](config.json.example), which has most cheats disabled.
|
SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [config-vanilla.json](config-vanilla.json), which has most cheats disabled.
|
||||||
|
|
||||||
- `logger.level` can be `fatal`, `error`, `warn`, `info`, `http`, `debug`, or `trace`.
|
- `logger.level` can be `fatal`, `error`, `warn`, `info`, `http`, `debug`, or `trace`.
|
||||||
- `myIrcAddresses` can be used to point to an IRC server. If not provided, defaults to `[ myAddress ]`.
|
- `myIrcAddresses` can be used to point to an IRC server. If not provided, defaults to `[ myAddress ]`.
|
||||||
@ -34,4 +34,5 @@ SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [confi
|
|||||||
- `RadioLegion2Syndicate` for The Emissary
|
- `RadioLegion2Syndicate` for The Emissary
|
||||||
- `RadioLegionIntermissionSyndicate` for Intermission I
|
- `RadioLegionIntermissionSyndicate` for Intermission I
|
||||||
- `RadioLegionSyndicate` for The Wolf of Saturn Six
|
- `RadioLegionSyndicate` for The Wolf of Saturn Six
|
||||||
- `worldState.circuitGameModes` can be provided with an array of valid game modes (`Survival`, `VoidFlood`, `Excavation`, `Defense`, `Exterminate`, `Assassination`, `Alchemy`)
|
- `allTheFissures` can be set to `normal` or `hard` to enable all fissures either in normal or steel path, respectively.
|
||||||
|
- `worldState.circuitGameModes` can be set to an array of game modes which will override the otherwise-random pattern in The Circuit. Valid element values are `Survival`, `VoidFlood`, `Excavation`, `Defense`, `Exterminate`, `Assassination`, and `Alchemy`.
|
||||||
|
@ -58,7 +58,9 @@
|
|||||||
"fastClanAscension": false,
|
"fastClanAscension": false,
|
||||||
"missionsCanGiveAllRelics": false,
|
"missionsCanGiveAllRelics": false,
|
||||||
"unlockAllSimarisResearchEntries": false,
|
"unlockAllSimarisResearchEntries": false,
|
||||||
|
"disableDailyTribute": false,
|
||||||
"spoofMasteryRank": -1,
|
"spoofMasteryRank": -1,
|
||||||
|
"relicRewardItemCountMultiplier": 1,
|
||||||
"nightwaveStandingMultiplier": 1,
|
"nightwaveStandingMultiplier": 1,
|
||||||
"unfaithfulBugFixes": {
|
"unfaithfulBugFixes": {
|
||||||
"ignore1999LastRegionPlayed": false,
|
"ignore1999LastRegionPlayed": false,
|
||||||
@ -68,12 +70,29 @@
|
|||||||
"creditBoost": false,
|
"creditBoost": false,
|
||||||
"affinityBoost": false,
|
"affinityBoost": false,
|
||||||
"resourceBoost": false,
|
"resourceBoost": false,
|
||||||
"starDays": true,
|
"tennoLiveRelay": false,
|
||||||
|
"wolfHunt": false,
|
||||||
|
"longShadow": false,
|
||||||
|
"hallowedFlame": false,
|
||||||
|
"hallowedNightmares": false,
|
||||||
|
"hallowedNightmaresRewardsOverride": 0,
|
||||||
|
"proxyRebellion": false,
|
||||||
|
"proxyRebellionRewardsOverride": 0,
|
||||||
|
"galleonOfGhouls": 0,
|
||||||
|
"ghoulEmergenceOverride": null,
|
||||||
|
"plagueStarOverride": null,
|
||||||
|
"starDaysOverride": null,
|
||||||
|
"dogDaysOverride": null,
|
||||||
|
"dogDaysRewardsOverride": null,
|
||||||
"eidolonOverride": "",
|
"eidolonOverride": "",
|
||||||
"vallisOverride": "",
|
"vallisOverride": "",
|
||||||
"duviriOverride": "",
|
"duviriOverride": "",
|
||||||
"nightwaveOverride": "",
|
"nightwaveOverride": "",
|
||||||
"circuitGameModes": null
|
"allTheFissures": "",
|
||||||
|
"circuitGameModes": null,
|
||||||
|
"darvoStockMultiplier": 1,
|
||||||
|
"varziaOverride": "",
|
||||||
|
"varziaFullyStocked": false
|
||||||
},
|
},
|
||||||
"dev": {
|
"dev": {
|
||||||
"keepVendorsExpired": false
|
"keepVendorsExpired": false
|
@ -2,7 +2,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
if [ ! -f conf/config.json ]; then
|
if [ ! -f conf/config.json ]; then
|
||||||
jq --arg value "mongodb://openwfagent:spaceninjaserver@mongodb:27017/" '.mongodbUrl = $value' /app/config.json.example > /app/conf/config.json
|
jq --arg value "mongodb://openwfagent:spaceninjaserver@mongodb:27017/" '.mongodbUrl = $value' /app/config-vanilla.json > /app/conf/config.json
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exec npm run start -- --configPath conf/config.json
|
exec npm run start -- --configPath conf/config.json
|
||||||
|
2658
package-lock.json
generated
2658
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
19
package.json
19
package.json
@ -5,19 +5,24 @@
|
|||||||
"main": "index.ts",
|
"main": "index.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node --enable-source-maps --import ./build/src/pathman.js build/src/index.js",
|
"start": "node --enable-source-maps --import ./build/src/pathman.js build/src/index.js",
|
||||||
"build": "tsc --incremental --sourceMap && ncp static/webui build/static/webui",
|
"build": "tsgo --sourceMap && ncp static/webui build/static/webui",
|
||||||
"build:dev": "tsc --incremental --sourceMap",
|
"build:tsc": "tsc --incremental --sourceMap && ncp static/webui build/static/webui",
|
||||||
|
"build:dev": "tsgo --sourceMap",
|
||||||
|
"build:dev:tsc": "tsc --incremental --sourceMap",
|
||||||
"build-and-start": "npm run build && npm run start",
|
"build-and-start": "npm run build && npm run start",
|
||||||
"build-and-start:bun": "npm run verify && npm run bun-run",
|
"build-and-start:bun": "npm run verify && npm run bun-run",
|
||||||
"dev": "node scripts/dev.js",
|
"dev": "node scripts/dev.js",
|
||||||
"dev:bun": "bun scripts/dev.js",
|
"dev:bun": "bun scripts/dev.js",
|
||||||
"verify": "tsgo --noEmit",
|
"verify": "tsgo --noEmit",
|
||||||
|
"verify:tsc": "tsc --noEmit",
|
||||||
"bun-run": "bun src/index.ts",
|
"bun-run": "bun src/index.ts",
|
||||||
"lint": "eslint --ext .ts .",
|
"lint": "eslint --ext .ts .",
|
||||||
"lint:ci": "eslint --ext .ts --rule \"prettier/prettier: off\" .",
|
"lint:ci": "eslint --ext .ts --rule \"prettier/prettier: off\" .",
|
||||||
"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"
|
"update-translations": "cd scripts && node update-translations.js",
|
||||||
|
"fix-imports": "cd scripts && node fix-imports.js",
|
||||||
|
"fix": "npm run update-translations && npm run fix-imports && npm run prettier"
|
||||||
},
|
},
|
||||||
"license": "GNU",
|
"license": "GNU",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -25,6 +30,8 @@
|
|||||||
"@types/morgan": "^1.9.9",
|
"@types/morgan": "^1.9.9",
|
||||||
"@types/websocket": "^1.0.10",
|
"@types/websocket": "^1.0.10",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
|
"@typescript/native-preview": "^7.0.0-dev.20250625.1",
|
||||||
|
"chokidar": "^4.0.3",
|
||||||
"crc-32": "^1.2.2",
|
"crc-32": "^1.2.2",
|
||||||
"express": "^5",
|
"express": "^5",
|
||||||
"json-with-bigint": "^3.4.4",
|
"json-with-bigint": "^3.4.4",
|
||||||
@ -33,7 +40,7 @@
|
|||||||
"ncp": "^2.0.0",
|
"ncp": "^2.0.0",
|
||||||
"typescript": "^5.5",
|
"typescript": "^5.5",
|
||||||
"undici": "^7.10.0",
|
"undici": "^7.10.0",
|
||||||
"warframe-public-export-plus": "^0.5.68",
|
"warframe-public-export-plus": "^0.5.80",
|
||||||
"warframe-riven-info": "^0.1.2",
|
"warframe-riven-info": "^0.1.2",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.17.0",
|
||||||
"winston-daily-rotate-file": "^5.0.0",
|
"winston-daily-rotate-file": "^5.0.0",
|
||||||
@ -42,9 +49,9 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^8.28.0",
|
"@typescript-eslint/eslint-plugin": "^8.28.0",
|
||||||
"@typescript-eslint/parser": "^8.28.0",
|
"@typescript-eslint/parser": "^8.28.0",
|
||||||
"@typescript/native-preview": "^7.0.0-dev.20250523.1",
|
|
||||||
"chokidar": "^4.0.3",
|
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
|
"eslint-import-resolver-typescript": "^4.4.4",
|
||||||
|
"eslint-plugin-import": "^2.32.0",
|
||||||
"eslint-plugin-prettier": "^5.2.5",
|
"eslint-plugin-prettier": "^5.2.5",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"tree-kill": "^1.2.2"
|
"tree-kill": "^1.2.2"
|
||||||
|
46
scripts/fix-imports.js
Normal file
46
scripts/fix-imports.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const root = path.join(process.cwd(), "..");
|
||||||
|
|
||||||
|
function listFiles(dir) {
|
||||||
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||||||
|
let results = [];
|
||||||
|
for (const entry of entries) {
|
||||||
|
const fullPath = path.join(dir, entry.name);
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
results = results.concat(listFiles(fullPath));
|
||||||
|
} else {
|
||||||
|
results.push(fullPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
const files = listFiles(path.join(root, "src"));
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
let content;
|
||||||
|
try {
|
||||||
|
content = fs.readFileSync(file, "utf8");
|
||||||
|
} catch (e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const dir = path.dirname(file);
|
||||||
|
const fixedContent = content.replaceAll(/} from "([^"]+)";/g, (sub, importPath) => {
|
||||||
|
if (!importPath.startsWith("@/")) {
|
||||||
|
const fullImportPath = path.resolve(dir, importPath);
|
||||||
|
if (fs.existsSync(fullImportPath + ".ts")) {
|
||||||
|
const relative = path.relative(root, fullImportPath).replace(/\\/g, "/");
|
||||||
|
const fixedPath = "@/" + relative;
|
||||||
|
console.log(`${importPath} -> ${fixedPath}`);
|
||||||
|
return sub.split(importPath).join(fixedPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sub;
|
||||||
|
});
|
||||||
|
if (content != fixedContent) {
|
||||||
|
fs.writeFileSync(file, fixedContent, "utf8");
|
||||||
|
}
|
||||||
|
}
|
@ -31,7 +31,7 @@ fs.readdirSync("../static/webui/translations").forEach(file => {
|
|||||||
const strings = extractStrings(line);
|
const strings = extractStrings(line);
|
||||||
if (Object.keys(strings).length > 0) {
|
if (Object.keys(strings).length > 0) {
|
||||||
Object.entries(strings).forEach(([key, value]) => {
|
Object.entries(strings).forEach(([key, value]) => {
|
||||||
if (targetStrings.hasOwnProperty(key)) {
|
if (targetStrings.hasOwnProperty(key) && !targetStrings[key].startsWith("[UNTRANSLATED] ")) {
|
||||||
fs.writeSync(fileHandle, ` ${key}: \`${targetStrings[key]}\`,\n`);
|
fs.writeSync(fileHandle, ` ${key}: \`${targetStrings[key]}\`,\n`);
|
||||||
} else {
|
} else {
|
||||||
fs.writeSync(fileHandle, ` ${key}: \`[UNTRANSLATED] ${value}\`,\n`);
|
fs.writeSync(fileHandle, ` ${key}: \`[UNTRANSLATED] ${value}\`,\n`);
|
||||||
|
22
src/controllers/api/apartmentController.ts
Normal file
22
src/controllers/api/apartmentController.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
export const apartmentController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const personalRooms = await getPersonalRooms(accountId, "Apartment");
|
||||||
|
const response: IApartmentResponse = {};
|
||||||
|
if (req.query.backdrop !== undefined) {
|
||||||
|
response.NewBackdropItem = personalRooms.Apartment.VideoWallBackdrop = req.query.backdrop as string;
|
||||||
|
}
|
||||||
|
if (req.query.soundscape !== undefined) {
|
||||||
|
response.NewSoundscapeItem = personalRooms.Apartment.Soundscape = req.query.soundscape as string;
|
||||||
|
}
|
||||||
|
await personalRooms.save();
|
||||||
|
res.json(response);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IApartmentResponse {
|
||||||
|
NewBackdropItem?: string;
|
||||||
|
NewSoundscapeItem?: string;
|
||||||
|
}
|
@ -24,7 +24,6 @@ export const artifactsController: RequestHandler = async (req, res) => {
|
|||||||
|
|
||||||
if (itemIndex !== -1) {
|
if (itemIndex !== -1) {
|
||||||
Upgrades[itemIndex].UpgradeFingerprint = stringifiedUpgradeFingerprint;
|
Upgrades[itemIndex].UpgradeFingerprint = stringifiedUpgradeFingerprint;
|
||||||
inventory.markModified(`Upgrades.${itemIndex}.UpgradeFingerprint`);
|
|
||||||
} else {
|
} else {
|
||||||
itemIndex =
|
itemIndex =
|
||||||
Upgrades.push({
|
Upgrades.push({
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
|
import { getAccountForRequest } from "@/src/services/loginService";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
const checkDailyMissionBonusController: RequestHandler = (_req, res) => {
|
export const checkDailyMissionBonusController: RequestHandler = async (req, res) => {
|
||||||
const data = Buffer.from([
|
const account = await getAccountForRequest(req);
|
||||||
0x44, 0x61, 0x69, 0x6c, 0x79, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x6f, 0x6e, 0x75, 0x73, 0x3a,
|
const today = Math.trunc(Date.now() / 86400000) * 86400;
|
||||||
0x31, 0x2d, 0x44, 0x61, 0x69, 0x6c, 0x79, 0x50, 0x56, 0x50, 0x57, 0x69, 0x6e, 0x42, 0x6f, 0x6e, 0x75, 0x73,
|
if (account.DailyFirstWinDate != today) {
|
||||||
0x3a, 0x31, 0x0a
|
res.send("DailyMissionBonus:1-DailyPVPWinBonus:1\n");
|
||||||
]);
|
} else {
|
||||||
res.writeHead(200, {
|
res.send("DailyMissionBonus:0-DailyPVPWinBonus:1\n");
|
||||||
"Content-Type": "text/html",
|
}
|
||||||
"Content-Length": data.length
|
|
||||||
});
|
|
||||||
res.end(data);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export { checkDailyMissionBonusController };
|
|
||||||
|
@ -13,15 +13,18 @@ import {
|
|||||||
addItem,
|
addItem,
|
||||||
addRecipes,
|
addRecipes,
|
||||||
occupySlot,
|
occupySlot,
|
||||||
combineInventoryChanges
|
combineInventoryChanges,
|
||||||
|
addKubrowPetPrint,
|
||||||
|
addPowerSuit,
|
||||||
|
addEquipment
|
||||||
} from "@/src/services/inventoryService";
|
} from "@/src/services/inventoryService";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { InventorySlot, IPendingRecipeDatabase } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { InventorySlot, IPendingRecipeDatabase, Status } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { toOid2 } from "@/src/helpers/inventoryHelpers";
|
import { toOid2 } from "@/src/helpers/inventoryHelpers";
|
||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { IRecipe } from "warframe-public-export-plus";
|
import { IRecipe } from "warframe-public-export-plus";
|
||||||
import { config } from "@/src/services/configService";
|
import { config } from "@/src/services/configService";
|
||||||
|
import { EquipmentFeatures, IEquipmentClient, Status } from "@/src/types/equipmentTypes";
|
||||||
|
|
||||||
interface IClaimCompletedRecipeRequest {
|
interface IClaimCompletedRecipeRequest {
|
||||||
RecipeIds: IOid[];
|
RecipeIds: IOid[];
|
||||||
@ -119,18 +122,126 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pet.Details!.Status = canSetActive ? Status.StatusAvailable : Status.StatusStasis;
|
pet.Details!.Status = canSetActive ? Status.StatusAvailable : Status.StatusStasis;
|
||||||
|
} else if (recipe.secretIngredientAction == "SIA_DISTILL_PRINT") {
|
||||||
|
const pet = inventory.KubrowPets.id(pendingRecipe.KubrowPet!)!;
|
||||||
|
addKubrowPetPrint(inventory, pet, InventoryChanges);
|
||||||
} else if (recipe.secretIngredientAction != "SIA_UNBRAND") {
|
} else if (recipe.secretIngredientAction != "SIA_UNBRAND") {
|
||||||
InventoryChanges = {
|
if (recipe.resultType == "/Lotus/Powersuits/Excalibur/ExcaliburUmbra") {
|
||||||
...InventoryChanges,
|
// Quite the special case here...
|
||||||
...(await addItem(
|
// We don't just get Umbra, but also Skiajati and Umbra Mods. Both items are max rank, potatoed, and with the mods are pre-installed.
|
||||||
|
// Source: https://wiki.warframe.com/w/The_Sacrifice, https://wiki.warframe.com/w/Excalibur/Umbra, https://wiki.warframe.com/w/Skiajati
|
||||||
|
|
||||||
|
const umbraModA = (
|
||||||
|
await addItem(
|
||||||
|
inventory,
|
||||||
|
"/Lotus/Upgrades/Mods/Sets/Umbra/WarframeUmbraModA",
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
undefined,
|
||||||
|
`{"lvl":5}`
|
||||||
|
)
|
||||||
|
).Upgrades![0];
|
||||||
|
const umbraModB = (
|
||||||
|
await addItem(
|
||||||
|
inventory,
|
||||||
|
"/Lotus/Upgrades/Mods/Sets/Umbra/WarframeUmbraModB",
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
undefined,
|
||||||
|
`{"lvl":5}`
|
||||||
|
)
|
||||||
|
).Upgrades![0];
|
||||||
|
const umbraModC = (
|
||||||
|
await addItem(
|
||||||
|
inventory,
|
||||||
|
"/Lotus/Upgrades/Mods/Sets/Umbra/WarframeUmbraModC",
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
undefined,
|
||||||
|
`{"lvl":5}`
|
||||||
|
)
|
||||||
|
).Upgrades![0];
|
||||||
|
const sacrificeModA = (
|
||||||
|
await addItem(
|
||||||
|
inventory,
|
||||||
|
"/Lotus/Upgrades/Mods/Sets/Sacrifice/MeleeSacrificeModA",
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
undefined,
|
||||||
|
`{"lvl":5}`
|
||||||
|
)
|
||||||
|
).Upgrades![0];
|
||||||
|
const sacrificeModB = (
|
||||||
|
await addItem(
|
||||||
|
inventory,
|
||||||
|
"/Lotus/Upgrades/Mods/Sets/Sacrifice/MeleeSacrificeModB",
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
undefined,
|
||||||
|
`{"lvl":5}`
|
||||||
|
)
|
||||||
|
).Upgrades![0];
|
||||||
|
InventoryChanges.Upgrades ??= [];
|
||||||
|
InventoryChanges.Upgrades.push(umbraModA, umbraModB, umbraModC, sacrificeModA, sacrificeModB);
|
||||||
|
|
||||||
|
await addPowerSuit(
|
||||||
inventory,
|
inventory,
|
||||||
recipe.resultType,
|
"/Lotus/Powersuits/Excalibur/ExcaliburUmbra",
|
||||||
recipe.num,
|
{
|
||||||
false,
|
Configs: [
|
||||||
undefined,
|
{
|
||||||
pendingRecipe.TargetFingerprint
|
Upgrades: [
|
||||||
))
|
"",
|
||||||
};
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
umbraModA.ItemId.$oid,
|
||||||
|
umbraModB.ItemId.$oid,
|
||||||
|
umbraModC.ItemId.$oid
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
XP: 900_000,
|
||||||
|
Features: EquipmentFeatures.DOUBLE_CAPACITY
|
||||||
|
},
|
||||||
|
InventoryChanges
|
||||||
|
);
|
||||||
|
inventory.XPInfo.push({
|
||||||
|
ItemType: "/Lotus/Powersuits/Excalibur/ExcaliburUmbra",
|
||||||
|
XP: 900_000
|
||||||
|
});
|
||||||
|
|
||||||
|
addEquipment(
|
||||||
|
inventory,
|
||||||
|
"Melee",
|
||||||
|
"/Lotus/Weapons/Tenno/Melee/Swords/UmbraKatana/UmbraKatana",
|
||||||
|
{
|
||||||
|
Configs: [
|
||||||
|
{ Upgrades: ["", "", "", "", "", "", sacrificeModA.ItemId.$oid, sacrificeModB.ItemId.$oid] }
|
||||||
|
],
|
||||||
|
XP: 450_000,
|
||||||
|
Features: EquipmentFeatures.DOUBLE_CAPACITY
|
||||||
|
},
|
||||||
|
InventoryChanges
|
||||||
|
);
|
||||||
|
inventory.XPInfo.push({
|
||||||
|
ItemType: "/Lotus/Weapons/Tenno/Melee/Swords/UmbraKatana/UmbraKatana",
|
||||||
|
XP: 450_000
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
InventoryChanges = {
|
||||||
|
...InventoryChanges,
|
||||||
|
...(await addItem(
|
||||||
|
inventory,
|
||||||
|
recipe.resultType,
|
||||||
|
recipe.num,
|
||||||
|
false,
|
||||||
|
undefined,
|
||||||
|
pendingRecipe.TargetFingerprint
|
||||||
|
))
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
config.claimingBlueprintRefundsIngredients &&
|
config.claimingBlueprintRefundsIngredients &&
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
|
import { combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { ExportChallenges } from "warframe-public-export-plus";
|
||||||
|
|
||||||
|
export const claimJunctionChallengeRewardController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId);
|
||||||
|
const data = getJSONfromString<IClaimJunctionChallengeRewardRequest>(String(req.body));
|
||||||
|
const challengeProgress = inventory.ChallengeProgress.find(x => x.Name == data.Challenge)!;
|
||||||
|
if (challengeProgress.ReceivedJunctionReward) {
|
||||||
|
throw new Error(`attempt to double-claim junction reward`);
|
||||||
|
}
|
||||||
|
challengeProgress.ReceivedJunctionReward = true;
|
||||||
|
inventory.ClaimedJunctionChallengeRewards ??= [];
|
||||||
|
inventory.ClaimedJunctionChallengeRewards.push(data.Challenge);
|
||||||
|
const challengeMeta = Object.entries(ExportChallenges).find(arr => arr[0].endsWith("/" + data.Challenge))![1];
|
||||||
|
const inventoryChanges = {};
|
||||||
|
for (const reward of challengeMeta.countedRewards!) {
|
||||||
|
combineInventoryChanges(
|
||||||
|
inventoryChanges,
|
||||||
|
(await handleStoreItemAcquisition(reward.StoreItem, inventory, reward.ItemCount)).InventoryChanges
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await inventory.save();
|
||||||
|
res.json({
|
||||||
|
inventoryChanges: inventoryChanges // Yeah, it's "inventoryChanges" in the response here.
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IClaimJunctionChallengeRewardRequest {
|
||||||
|
Challenge: string;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { checkCalendarChallengeCompletion, getCalendarProgress, getInventory } from "@/src/services/inventoryService";
|
import { checkCalendarAutoAdvance, getCalendarProgress, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
||||||
import { getWorldState } from "@/src/services/worldStateService";
|
import { getWorldState } from "@/src/services/worldStateService";
|
||||||
@ -28,7 +28,7 @@ export const completeCalendarEventController: RequestHandler = async (req, res)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
calendarProgress.SeasonProgress.LastCompletedDayIdx = dayIndex;
|
calendarProgress.SeasonProgress.LastCompletedDayIdx = dayIndex;
|
||||||
checkCalendarChallengeCompletion(calendarProgress, currentSeason);
|
checkCalendarAutoAdvance(inventory, currentSeason);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
InventoryChanges: inventoryChanges,
|
InventoryChanges: inventoryChanges,
|
||||||
|
@ -4,8 +4,7 @@ import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inven
|
|||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { createUnveiledRivenFingerprint } from "@/src/helpers/rivenHelper";
|
import { IVeiledRivenFingerprint } from "@/src/helpers/rivenHelper";
|
||||||
import { ExportUpgrades } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
export const completeRandomModChallengeController: RequestHandler = async (req, res) => {
|
export const completeRandomModChallengeController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -27,10 +26,11 @@ export const completeRandomModChallengeController: RequestHandler = async (req,
|
|||||||
inventoryChanges.MiscItems = miscItemChanges;
|
inventoryChanges.MiscItems = miscItemChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update riven fingerprint to a randomised unveiled state
|
// Complete the riven challenge
|
||||||
const upgrade = inventory.Upgrades.id(request.ItemId)!;
|
const upgrade = inventory.Upgrades.id(request.ItemId)!;
|
||||||
const meta = ExportUpgrades[upgrade.ItemType];
|
const fp = JSON.parse(upgrade.UpgradeFingerprint!) as IVeiledRivenFingerprint;
|
||||||
upgrade.UpgradeFingerprint = JSON.stringify(createUnveiledRivenFingerprint(meta));
|
fp.challenge.Progress = fp.challenge.Required;
|
||||||
|
upgrade.UpgradeFingerprint = JSON.stringify(fp);
|
||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
|
@ -21,7 +21,8 @@ import {
|
|||||||
updateCurrency
|
updateCurrency
|
||||||
} from "@/src/services/inventoryService";
|
} from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IFusionTreasure, IMiscItem, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { ITypeCount } from "@/src/types/commonTypes";
|
||||||
|
import { IFusionTreasure, IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const contributeToVaultController: RequestHandler = async (req, res) => {
|
export const contributeToVaultController: RequestHandler = async (req, res) => {
|
||||||
|
@ -4,9 +4,15 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
|
|||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
|
||||||
export const creditsController: RequestHandler = async (req, res) => {
|
export const creditsController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const inventory = (
|
||||||
|
await Promise.all([
|
||||||
const inventory = await getInventory(accountId, "RegularCredits TradesRemaining PremiumCreditsFree PremiumCredits");
|
getAccountIdForRequest(req),
|
||||||
|
getInventory(
|
||||||
|
req.query.accountId as string,
|
||||||
|
"RegularCredits TradesRemaining PremiumCreditsFree PremiumCredits"
|
||||||
|
)
|
||||||
|
])
|
||||||
|
)[1];
|
||||||
|
|
||||||
const response = {
|
const response = {
|
||||||
RegularCredits: inventory.RegularCredits,
|
RegularCredits: inventory.RegularCredits,
|
||||||
|
@ -88,7 +88,6 @@ export const crewShipFusionController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
superiorItem.UpgradeFingerprint = JSON.stringify(fingerprint);
|
superiorItem.UpgradeFingerprint = JSON.stringify(fingerprint);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
inventoryChanges[category] = [superiorItem.toJSON() as any];
|
inventoryChanges[category] = [superiorItem.toJSON() as any];
|
||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
@ -12,7 +12,7 @@ import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { getRandomInt } from "@/src/services/rngService";
|
import { getRandomInt } from "@/src/services/rngService";
|
||||||
import { IFingerprintStat } from "@/src/helpers/rivenHelper";
|
import { IFingerprintStat } from "@/src/helpers/rivenHelper";
|
||||||
import { IEquipmentDatabase } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IEquipmentDatabase } from "@/src/types/equipmentTypes";
|
||||||
|
|
||||||
export const crewShipIdentifySalvageController: RequestHandler = async (req, res) => {
|
export const crewShipIdentifySalvageController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Guild } from "@/src/models/guildModel";
|
import { Guild } from "@/src/models/guildModel";
|
||||||
import { getAccountForRequest } from "@/src/services/loginService";
|
import { hasAccessToDojo, hasGuildPermission } from "@/src/services/guildService";
|
||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountForRequest, getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { GuildPermission } from "@/src/types/guildTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const customObstacleCourseLeaderboardController: RequestHandler = async (req, res) => {
|
export const customObstacleCourseLeaderboardController: RequestHandler = async (req, res) => {
|
||||||
const data = getJSONfromString<ICustomObstacleCourseLeaderboardRequest>(String(req.body));
|
const data = getJSONfromString<ICustomObstacleCourseLeaderboardRequest>(String(req.body));
|
||||||
const guild = (await Guild.findById(data.g, "DojoComponents"))!;
|
const guild = (await Guild.findById(data.g, "DojoComponents Ranks"))!;
|
||||||
const component = guild.DojoComponents.id(data.c)!;
|
const component = guild.DojoComponents.id(data.c)!;
|
||||||
if (req.query.act == "f") {
|
if (req.query.act == "f") {
|
||||||
res.json({
|
res.json({
|
||||||
@ -34,6 +37,19 @@ export const customObstacleCourseLeaderboardController: RequestHandler = async (
|
|||||||
entry.r = ++r;
|
entry.r = ++r;
|
||||||
}
|
}
|
||||||
await guild.save();
|
await guild.save();
|
||||||
|
res.status(200).end();
|
||||||
|
} else if (req.query.act == "c") {
|
||||||
|
// TOVERIFY: What clan permission is actually needed for this?
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId, "GuildId LevelKeys");
|
||||||
|
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Decorator))) {
|
||||||
|
res.status(400).end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
component.Leaderboard = undefined;
|
||||||
|
await guild.save();
|
||||||
|
|
||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
} else {
|
} else {
|
||||||
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
||||||
|
@ -3,11 +3,13 @@ import {
|
|||||||
getGuildForRequestEx,
|
getGuildForRequestEx,
|
||||||
hasAccessToDojo,
|
hasAccessToDojo,
|
||||||
hasGuildPermission,
|
hasGuildPermission,
|
||||||
|
refundDojoDeco,
|
||||||
removeDojoDeco
|
removeDojoDeco
|
||||||
} from "@/src/services/guildService";
|
} from "@/src/services/guildService";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { GuildPermission } from "@/src/types/guildTypes";
|
import { GuildPermission } from "@/src/types/guildTypes";
|
||||||
|
import { logger } from "@/src/utils/logger";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const destroyDojoDecoController: RequestHandler = async (req, res) => {
|
export const destroyDojoDecoController: RequestHandler = async (req, res) => {
|
||||||
@ -18,9 +20,20 @@ export const destroyDojoDecoController: RequestHandler = async (req, res) => {
|
|||||||
res.json({ DojoRequestStatus: -1 });
|
res.json({ DojoRequestStatus: -1 });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const request = JSON.parse(String(req.body)) as IDestroyDojoDecoRequest;
|
const request = JSON.parse(String(req.body)) as IDestroyDojoDecoRequest | IClearObstacleCourseRequest;
|
||||||
|
if ("DecoType" in request) {
|
||||||
removeDojoDeco(guild, request.ComponentId, request.DecoId);
|
removeDojoDeco(guild, request.ComponentId, request.DecoId);
|
||||||
|
} else if (request.Act == "cObst") {
|
||||||
|
const component = guild.DojoComponents.id(request.ComponentId)!;
|
||||||
|
if (component.Decos) {
|
||||||
|
for (const deco of component.Decos) {
|
||||||
|
refundDojoDeco(guild, component, deco);
|
||||||
|
}
|
||||||
|
component.Decos.splice(0, component.Decos.length);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.error(`unhandled destroyDojoDeco request`, request);
|
||||||
|
}
|
||||||
|
|
||||||
await guild.save();
|
await guild.save();
|
||||||
res.json(await getDojoClient(guild, 0, request.ComponentId));
|
res.json(await getDojoClient(guild, 0, request.ComponentId));
|
||||||
@ -31,3 +44,8 @@ interface IDestroyDojoDecoRequest {
|
|||||||
ComponentId: string;
|
ComponentId: string;
|
||||||
DecoId: string;
|
DecoId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IClearObstacleCourseRequest {
|
||||||
|
ComponentId: string;
|
||||||
|
Act: "cObst" | "maybesomethingelsewedontknowabout";
|
||||||
|
}
|
||||||
|
@ -3,7 +3,7 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
|
|||||||
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
|
import { addMiscItems, 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 { getRecipe, WeaponTypeInternal } from "@/src/services/itemDataService";
|
||||||
import { EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { EquipmentFeatures } from "@/src/types/equipmentTypes";
|
||||||
|
|
||||||
export const evolveWeaponController: RequestHandler = async (req, res) => {
|
export const evolveWeaponController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
@ -4,7 +4,6 @@ import { getInventory, addMiscItems, addEquipment, occupySlot } from "@/src/serv
|
|||||||
import { IMiscItem, TFocusPolarity, TEquipmentKey, InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IMiscItem, TFocusPolarity, TEquipmentKey, InventorySlot } 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";
|
|
||||||
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
|
|
||||||
export const focusController: RequestHandler = async (req, res) => {
|
export const focusController: RequestHandler = async (req, res) => {
|
||||||
@ -116,7 +115,7 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
});
|
});
|
||||||
occupySlot(inventory, InventorySlot.AMPS, false);
|
occupySlot(inventory, InventorySlot.AMPS, false);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json((inventoryChanges.OperatorAmps as IEquipmentClient[])[0]);
|
res.json(inventoryChanges.OperatorAmps![0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FocusOperation.UnbindUpgrade: {
|
case FocusOperation.UnbindUpgrade: {
|
||||||
|
@ -2,22 +2,14 @@ import { RequestHandler } from "express";
|
|||||||
import { ExportResources } from "warframe-public-export-plus";
|
import { ExportResources } from "warframe-public-export-plus";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { addFusionTreasures, addMiscItems, getInventory } from "@/src/services/inventoryService";
|
import { addFusionTreasures, addMiscItems, getInventory } from "@/src/services/inventoryService";
|
||||||
import { IFusionTreasure, IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
import { parseFusionTreasure } from "@/src/helpers/inventoryHelpers";
|
||||||
|
|
||||||
interface IFusionTreasureRequest {
|
interface IFusionTreasureRequest {
|
||||||
oldTreasureName: string;
|
oldTreasureName: string;
|
||||||
newTreasureName: 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) => {
|
export const fusionTreasuresController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
|
@ -6,9 +6,8 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
|
|||||||
import { createGarden, getPersonalRooms } from "@/src/services/personalRoomsService";
|
import { createGarden, getPersonalRooms } from "@/src/services/personalRoomsService";
|
||||||
import { IMongoDate } from "@/src/types/commonTypes";
|
import { IMongoDate } from "@/src/types/commonTypes";
|
||||||
import { IMissionReward } from "@/src/types/missionTypes";
|
import { IMissionReward } from "@/src/types/missionTypes";
|
||||||
import { IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
|
import { IGardeningClient, IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { IGardeningClient } from "@/src/types/shipTypes";
|
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { dict_en, ExportResources } from "warframe-public-export-plus";
|
import { dict_en, ExportResources } from "warframe-public-export-plus";
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
import { DailyDeal } from "@/src/models/worldStateModel";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const getDailyDealStockLevelsController: RequestHandler = (req, res) => {
|
export const getDailyDealStockLevelsController: RequestHandler = async (req, res) => {
|
||||||
|
const dailyDeal = (await DailyDeal.findOne({ StoreItem: req.query.productName }, "AmountSold"))!;
|
||||||
res.json({
|
res.json({
|
||||||
StoreItem: req.query.productName,
|
StoreItem: req.query.productName,
|
||||||
AmountSold: 0
|
AmountSold: dailyDeal.AmountSold
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { generateRewardSeed } from "@/src/services/inventoryService";
|
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { generateRewardSeed } from "@/src/services/rngService";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const getNewRewardSeedController: RequestHandler = async (req, res) => {
|
export const getNewRewardSeedController: RequestHandler = async (req, res) => {
|
||||||
|
62
src/controllers/api/getPastWeeklyChallengesController.ts
Normal file
62
src/controllers/api/getPastWeeklyChallengesController.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { EPOCH, getSeasonChallengePools, getWorldState, pushWeeklyActs } from "@/src/services/worldStateService";
|
||||||
|
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
||||||
|
import { ISeasonChallenge } from "@/src/types/worldStateTypes";
|
||||||
|
import { ExportChallenges } from "warframe-public-export-plus";
|
||||||
|
|
||||||
|
export const getPastWeeklyChallengesController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId, "SeasonChallengeHistory ChallengeProgress");
|
||||||
|
const worldState = getWorldState(undefined);
|
||||||
|
|
||||||
|
if (worldState.SeasonInfo) {
|
||||||
|
const pools = getSeasonChallengePools(worldState.SeasonInfo.AffiliationTag);
|
||||||
|
const nightwaveStartTimestamp = Number(worldState.SeasonInfo.Activation.$date.$numberLong);
|
||||||
|
const nightwaveSeason = worldState.SeasonInfo.Season;
|
||||||
|
const timeMs = worldState.Time * 1000;
|
||||||
|
const completedChallengesIds = new Set<string>();
|
||||||
|
|
||||||
|
inventory.SeasonChallengeHistory.forEach(challengeHistory => {
|
||||||
|
const entryNightwaveSeason = parseInt(challengeHistory.id.slice(0, 4), 10) - 1;
|
||||||
|
if (nightwaveSeason == entryNightwaveSeason) {
|
||||||
|
const meta = Object.entries(ExportChallenges).find(
|
||||||
|
([key]) => key.split("/").pop() === challengeHistory.challenge
|
||||||
|
);
|
||||||
|
if (meta) {
|
||||||
|
const [, challengeMeta] = meta;
|
||||||
|
const challengeProgress = inventory.ChallengeProgress.find(
|
||||||
|
c => c.Name === challengeHistory.challenge
|
||||||
|
);
|
||||||
|
|
||||||
|
if (challengeProgress && challengeProgress.Progress >= (challengeMeta.requiredCount ?? 1)) {
|
||||||
|
completedChallengesIds.add(challengeHistory.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const PastWeeklyChallenges: ISeasonChallenge[] = [];
|
||||||
|
|
||||||
|
let week = Math.trunc((timeMs - EPOCH) / unixTimesInMs.week) - 1;
|
||||||
|
|
||||||
|
while (EPOCH + week * unixTimesInMs.week >= nightwaveStartTimestamp && PastWeeklyChallenges.length < 3) {
|
||||||
|
const tempActs: ISeasonChallenge[] = [];
|
||||||
|
pushWeeklyActs(tempActs, pools, week, nightwaveStartTimestamp, nightwaveSeason);
|
||||||
|
|
||||||
|
for (const act of tempActs) {
|
||||||
|
if (!completedChallengesIds.has(act._id.$oid) && PastWeeklyChallenges.length < 3) {
|
||||||
|
if (act.Challenge.startsWith("/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanent")) {
|
||||||
|
act.Permanent = true;
|
||||||
|
}
|
||||||
|
PastWeeklyChallenges.push(act);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
week--;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({ PastWeeklyChallenges: PastWeeklyChallenges });
|
||||||
|
}
|
||||||
|
};
|
@ -3,10 +3,9 @@ import { config } from "@/src/services/configService";
|
|||||||
import allShipFeatures from "@/static/fixed_responses/allShipFeatures.json";
|
import allShipFeatures from "@/static/fixed_responses/allShipFeatures.json";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { createGarden, getPersonalRooms } from "@/src/services/personalRoomsService";
|
import { createGarden, getPersonalRooms } from "@/src/services/personalRoomsService";
|
||||||
import { toOid } from "@/src/helpers/inventoryHelpers";
|
import { IGetShipResponse, IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
|
||||||
import { IGetShipResponse } from "@/src/types/shipTypes";
|
|
||||||
import { IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
|
|
||||||
import { getLoadout } from "@/src/services/loadoutService";
|
import { getLoadout } from "@/src/services/loadoutService";
|
||||||
|
import { toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
|
|
||||||
export const getShipController: RequestHandler = async (req, res) => {
|
export const getShipController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -26,15 +25,7 @@ export const getShipController: RequestHandler = async (req, res) => {
|
|||||||
LoadOutInventory: { LoadOutPresets: loadout.toJSON() },
|
LoadOutInventory: { LoadOutPresets: loadout.toJSON() },
|
||||||
Ship: {
|
Ship: {
|
||||||
...personalRooms.Ship,
|
...personalRooms.Ship,
|
||||||
ShipId: toOid(personalRoomsDb.activeShipId),
|
ShipId: toOid(personalRoomsDb.activeShipId)
|
||||||
ShipInterior: {
|
|
||||||
Colors: personalRooms.ShipInteriorColors,
|
|
||||||
ShipAttachments: { HOOD_ORNAMENT: "" },
|
|
||||||
SkinFlavourItem: ""
|
|
||||||
},
|
|
||||||
FavouriteLoadoutId: personalRooms.Ship.FavouriteLoadoutId
|
|
||||||
? toOid(personalRooms.Ship.FavouriteLoadoutId)
|
|
||||||
: undefined
|
|
||||||
},
|
},
|
||||||
Apartment: personalRooms.Apartment,
|
Apartment: personalRooms.Apartment,
|
||||||
TailorShop: personalRooms.TailorShop
|
TailorShop: personalRooms.TailorShop
|
||||||
|
@ -9,15 +9,26 @@ import {
|
|||||||
updateCurrency
|
updateCurrency
|
||||||
} from "@/src/services/inventoryService";
|
} from "@/src/services/inventoryService";
|
||||||
import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
|
import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
|
||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
import { handleDailyDealPurchase, handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
||||||
import { IOid } from "@/src/types/commonTypes";
|
import { IOid } from "@/src/types/commonTypes";
|
||||||
import { IInventoryChanges, IPurchaseParams, PurchaseSource } from "@/src/types/purchaseTypes";
|
import { IPurchaseParams, IPurchaseResponse, PurchaseSource } from "@/src/types/purchaseTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { ExportBundles, ExportFlavour } from "warframe-public-export-plus";
|
import { ExportBundles, ExportFlavour } from "warframe-public-export-plus";
|
||||||
|
|
||||||
|
const checkPurchaseParams = (params: IPurchaseParams): boolean => {
|
||||||
|
switch (params.Source) {
|
||||||
|
case PurchaseSource.Market:
|
||||||
|
return params.UsePremium;
|
||||||
|
|
||||||
|
case PurchaseSource.DailyDeal:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
export const giftingController: RequestHandler = async (req, res) => {
|
export const giftingController: RequestHandler = async (req, res) => {
|
||||||
const data = getJSONfromString<IGiftingRequest>(String(req.body));
|
const data = getJSONfromString<IGiftingRequest>(String(req.body));
|
||||||
if (data.PurchaseParams.Source != PurchaseSource.Market || !data.PurchaseParams.UsePremium) {
|
if (!checkPurchaseParams(data.PurchaseParams)) {
|
||||||
throw new Error(`unexpected purchase params in gifting request: ${String(req.body)}`);
|
throw new Error(`unexpected purchase params in gifting request: ${String(req.body)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,16 +69,19 @@ export const giftingController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
senderInventory.GiftsRemaining -= 1;
|
senderInventory.GiftsRemaining -= 1;
|
||||||
|
|
||||||
const inventoryChanges: IInventoryChanges = updateCurrency(
|
const response: IPurchaseResponse = {
|
||||||
senderInventory,
|
InventoryChanges: {}
|
||||||
data.PurchaseParams.ExpectedPrice,
|
};
|
||||||
true
|
if (data.PurchaseParams.Source == PurchaseSource.DailyDeal) {
|
||||||
);
|
await handleDailyDealPurchase(senderInventory, data.PurchaseParams, response);
|
||||||
|
} else {
|
||||||
|
updateCurrency(senderInventory, data.PurchaseParams.ExpectedPrice, true, response.InventoryChanges);
|
||||||
|
}
|
||||||
if (data.PurchaseParams.StoreItem in ExportBundles) {
|
if (data.PurchaseParams.StoreItem in ExportBundles) {
|
||||||
const bundle = ExportBundles[data.PurchaseParams.StoreItem];
|
const bundle = ExportBundles[data.PurchaseParams.StoreItem];
|
||||||
if (bundle.giftingBonus) {
|
if (bundle.giftingBonus) {
|
||||||
combineInventoryChanges(
|
combineInventoryChanges(
|
||||||
inventoryChanges,
|
response.InventoryChanges,
|
||||||
(await handleStoreItemAcquisition(bundle.giftingBonus, senderInventory)).InventoryChanges
|
(await handleStoreItemAcquisition(bundle.giftingBonus, senderInventory)).InventoryChanges
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -99,9 +113,7 @@ export const giftingController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
res.json({
|
res.json(response);
|
||||||
InventoryChanges: inventoryChanges
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IGiftingRequest {
|
interface IGiftingRequest {
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { sendWsBroadcastTo } from "@/src/services/wsService";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
|
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
|
||||||
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { ArtifactPolarity, EquipmentFeatures, IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { ArtifactPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { ExportRecipes } from "warframe-public-export-plus";
|
import { ExportRecipes } from "warframe-public-export-plus";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
|
import { EquipmentFeatures, IEquipmentClient } from "@/src/types/equipmentTypes";
|
||||||
|
|
||||||
interface IGildWeaponRequest {
|
interface IGildWeaponRequest {
|
||||||
ItemName: string;
|
ItemName: string;
|
||||||
@ -72,4 +74,5 @@ export const gildWeaponController: RequestHandler = async (req, res) => {
|
|||||||
InventoryChanges: inventoryChanges,
|
InventoryChanges: inventoryChanges,
|
||||||
AffiliationMods: affiliationMods
|
AffiliationMods: affiliationMods
|
||||||
});
|
});
|
||||||
|
sendWsBroadcastTo(accountId, { update_inventory: true });
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { addLoreFragmentScans, addShipDecorations, getInventory } from "@/src/services/inventoryService";
|
import { addLoreFragmentScans, addShipDecorations, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { ILoreFragmentScan, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { ITypeCount } from "@/src/types/commonTypes";
|
||||||
|
import { ILoreFragmentScan } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const giveShipDecoAndLoreFragmentController: RequestHandler = async (req, res) => {
|
export const giveShipDecoAndLoreFragmentController: RequestHandler = async (req, res) => {
|
||||||
|
@ -5,6 +5,7 @@ import {
|
|||||||
getGuildVault,
|
getGuildVault,
|
||||||
hasAccessToDojo,
|
hasAccessToDojo,
|
||||||
hasGuildPermission,
|
hasGuildPermission,
|
||||||
|
processCompletedGuildTechProject,
|
||||||
processFundedGuildTechProject,
|
processFundedGuildTechProject,
|
||||||
processGuildTechProjectContributionsUpdate,
|
processGuildTechProjectContributionsUpdate,
|
||||||
removePigmentsFromGuildMembers,
|
removePigmentsFromGuildMembers,
|
||||||
@ -51,8 +52,12 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
|||||||
};
|
};
|
||||||
if (project.CompletionDate) {
|
if (project.CompletionDate) {
|
||||||
techProject.CompletionDate = toMongoDate(project.CompletionDate);
|
techProject.CompletionDate = toMongoDate(project.CompletionDate);
|
||||||
if (Date.now() >= project.CompletionDate.getTime()) {
|
if (
|
||||||
needSave ||= setGuildTechLogState(guild, project.ItemType, 4, project.CompletionDate);
|
Date.now() >= project.CompletionDate.getTime() &&
|
||||||
|
setGuildTechLogState(guild, project.ItemType, 4, project.CompletionDate)
|
||||||
|
) {
|
||||||
|
processCompletedGuildTechProject(guild, project.ItemType);
|
||||||
|
needSave = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
techProjects.push(techProject);
|
techProjects.push(techProject);
|
||||||
|
@ -13,7 +13,8 @@ import {
|
|||||||
addItems,
|
addItems,
|
||||||
combineInventoryChanges,
|
combineInventoryChanges,
|
||||||
getEffectiveAvatarImageType,
|
getEffectiveAvatarImageType,
|
||||||
getInventory
|
getInventory,
|
||||||
|
updateCurrency
|
||||||
} from "@/src/services/inventoryService";
|
} from "@/src/services/inventoryService";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { ExportFlavour } from "warframe-public-export-plus";
|
import { ExportFlavour } from "warframe-public-export-plus";
|
||||||
@ -100,6 +101,9 @@ export const inboxController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (message.RegularCredits) {
|
||||||
|
updateCurrency(inventory, -message.RegularCredits, false, inventoryChanges);
|
||||||
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({ InventoryChanges: inventoryChanges });
|
res.json({ InventoryChanges: inventoryChanges });
|
||||||
} else if (latestClientMessageId) {
|
} else if (latestClientMessageId) {
|
||||||
|
@ -5,15 +5,25 @@ import { config } from "@/src/services/configService";
|
|||||||
import allDialogue from "@/static/fixed_responses/allDialogue.json";
|
import allDialogue from "@/static/fixed_responses/allDialogue.json";
|
||||||
import { ILoadoutDatabase } from "@/src/types/saveLoadoutTypes";
|
import { ILoadoutDatabase } from "@/src/types/saveLoadoutTypes";
|
||||||
import { IInventoryClient, IShipInventory, equipmentKeys } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IInventoryClient, IShipInventory, equipmentKeys } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { IPolarity, ArtifactPolarity, EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IPolarity, ArtifactPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { ExportCustoms, ExportFlavour, ExportResources, ExportVirtuals } from "warframe-public-export-plus";
|
import {
|
||||||
|
eFaction,
|
||||||
|
ExportCustoms,
|
||||||
|
ExportFlavour,
|
||||||
|
ExportResources,
|
||||||
|
ExportVirtuals,
|
||||||
|
ICountedItem
|
||||||
|
} from "warframe-public-export-plus";
|
||||||
import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "@/src/services/infestedFoundryService";
|
import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "@/src/services/infestedFoundryService";
|
||||||
import {
|
import {
|
||||||
|
addEmailItem,
|
||||||
|
addItem,
|
||||||
addMiscItems,
|
addMiscItems,
|
||||||
allDailyAffiliationKeys,
|
allDailyAffiliationKeys,
|
||||||
|
checkCalendarAutoAdvance,
|
||||||
cleanupInventory,
|
cleanupInventory,
|
||||||
createLibraryDailyTask,
|
createLibraryDailyTask,
|
||||||
generateRewardSeed
|
getCalendarProgress
|
||||||
} from "@/src/services/inventoryService";
|
} from "@/src/services/inventoryService";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { addString, catBreadHash } from "@/src/helpers/stringHelpers";
|
import { addString, catBreadHash } from "@/src/helpers/stringHelpers";
|
||||||
@ -22,7 +32,14 @@ import { getNemesisManifest } from "@/src/helpers/nemesisHelpers";
|
|||||||
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
||||||
import { IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
|
import { IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
|
||||||
import { Ship } from "@/src/models/shipModel";
|
import { Ship } from "@/src/models/shipModel";
|
||||||
import { toLegacyOid, version_compare } from "@/src/helpers/inventoryHelpers";
|
import { toLegacyOid, toOid, version_compare } from "@/src/helpers/inventoryHelpers";
|
||||||
|
import { Inbox } from "@/src/models/inboxModel";
|
||||||
|
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
||||||
|
import { DailyDeal } from "@/src/models/worldStateModel";
|
||||||
|
import { EquipmentFeatures } from "@/src/types/equipmentTypes";
|
||||||
|
import { generateRewardSeed } from "@/src/services/rngService";
|
||||||
|
import { getInvasionByOid, getWorldState } from "@/src/services/worldStateService";
|
||||||
|
import { createMessage } from "@/src/services/inboxService";
|
||||||
|
|
||||||
export const inventoryController: RequestHandler = async (request, response) => {
|
export const inventoryController: RequestHandler = async (request, response) => {
|
||||||
const account = await getAccountForRequest(request);
|
const account = await getAccountForRequest(request);
|
||||||
@ -36,6 +53,8 @@ export const inventoryController: RequestHandler = async (request, response) =>
|
|||||||
|
|
||||||
// Handle daily reset
|
// Handle daily reset
|
||||||
if (!inventory.NextRefill || Date.now() >= inventory.NextRefill.getTime()) {
|
if (!inventory.NextRefill || Date.now() >= inventory.NextRefill.getTime()) {
|
||||||
|
const today = Math.trunc(Date.now() / 86400000);
|
||||||
|
|
||||||
for (const key of allDailyAffiliationKeys) {
|
for (const key of allDailyAffiliationKeys) {
|
||||||
inventory[key] = 16000 + inventory.PlayerLevel * 500;
|
inventory[key] = 16000 + inventory.PlayerLevel * 500;
|
||||||
}
|
}
|
||||||
@ -46,12 +65,12 @@ export const inventoryController: RequestHandler = async (request, response) =>
|
|||||||
inventory.LibraryAvailableDailyTaskInfo = createLibraryDailyTask();
|
inventory.LibraryAvailableDailyTaskInfo = createLibraryDailyTask();
|
||||||
|
|
||||||
if (inventory.NextRefill) {
|
if (inventory.NextRefill) {
|
||||||
|
const lastLoginDay = Math.trunc(inventory.NextRefill.getTime() / 86400000) - 1;
|
||||||
|
const daysPassed = today - lastLoginDay;
|
||||||
|
|
||||||
if (config.noArgonCrystalDecay) {
|
if (config.noArgonCrystalDecay) {
|
||||||
inventory.FoundToday = undefined;
|
inventory.FoundToday = undefined;
|
||||||
} else {
|
} else {
|
||||||
const lastLoginDay = Math.trunc(inventory.NextRefill.getTime() / 86400000) - 1;
|
|
||||||
const today = Math.trunc(Date.now() / 86400000);
|
|
||||||
const daysPassed = today - lastLoginDay;
|
|
||||||
for (let i = 0; i != daysPassed; ++i) {
|
for (let i = 0; i != daysPassed; ++i) {
|
||||||
const numArgonCrystals =
|
const numArgonCrystals =
|
||||||
inventory.MiscItems.find(x => x.ItemType == "/Lotus/Types/Items/MiscItems/ArgonCrystal")
|
inventory.MiscItems.find(x => x.ItemType == "/Lotus/Types/Items/MiscItems/ArgonCrystal")
|
||||||
@ -83,11 +102,87 @@ export const inventoryController: RequestHandler = async (request, response) =>
|
|||||||
inventory.FoundToday = undefined;
|
inventory.FoundToday = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inventory.UsedDailyDeals.length != 0) {
|
||||||
|
if (daysPassed == 1) {
|
||||||
|
const todayAt0Utc = today * 86400000;
|
||||||
|
const darvoIndex = Math.trunc((todayAt0Utc - 25200000) / (26 * unixTimesInMs.hour));
|
||||||
|
const darvoStart = darvoIndex * (26 * unixTimesInMs.hour) + 25200000;
|
||||||
|
const darvoOid =
|
||||||
|
((darvoStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "adc51a72f7324d95";
|
||||||
|
const deal = await DailyDeal.findById(darvoOid);
|
||||||
|
if (deal) {
|
||||||
|
inventory.UsedDailyDeals = inventory.UsedDailyDeals.filter(x => x == deal.StoreItem); // keep only the deal that came into this new day with us
|
||||||
|
} else {
|
||||||
|
inventory.UsedDailyDeals = [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inventory.UsedDailyDeals = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Setup CalendarProgress as part of 1999 mission completion?
|
||||||
|
|
||||||
|
const previousYearIteration = inventory.CalendarProgress?.Iteration;
|
||||||
|
|
||||||
|
// We need to do the following to ensure the in-game calendar does not break:
|
||||||
|
getCalendarProgress(inventory); // Keep the CalendarProgress up-to-date (at least for the current year iteration) (https://onlyg.it/OpenWF/SpaceNinjaServer/issues/2364)
|
||||||
|
checkCalendarAutoAdvance(inventory, getWorldState().KnownCalendarSeasons[0]); // Skip birthday events for characters if we do not have them unlocked yet (https://onlyg.it/OpenWF/SpaceNinjaServer/issues/2424)
|
||||||
|
|
||||||
|
// also handle sending of kiss cinematic at year rollover
|
||||||
|
if (
|
||||||
|
inventory.CalendarProgress!.Iteration != previousYearIteration &&
|
||||||
|
inventory.DialogueHistory &&
|
||||||
|
inventory.DialogueHistory.Dialogues
|
||||||
|
) {
|
||||||
|
let kalymos = false;
|
||||||
|
for (const { dialogueName, kissEmail } of [
|
||||||
|
{
|
||||||
|
dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/ArthurDialogue_rom.dialogue",
|
||||||
|
kissEmail: "/Lotus/Types/Items/EmailItems/ArthurKissEmailItem"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/EleanorDialogue_rom.dialogue",
|
||||||
|
kissEmail: "/Lotus/Types/Items/EmailItems/EleanorKissEmailItem"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/LettieDialogue_rom.dialogue",
|
||||||
|
kissEmail: "/Lotus/Types/Items/EmailItems/LettieKissEmailItem"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/JabirDialogue_rom.dialogue",
|
||||||
|
kissEmail: "/Lotus/Types/Items/EmailItems/AmirKissEmailItem"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/AoiDialogue_rom.dialogue",
|
||||||
|
kissEmail: "/Lotus/Types/Items/EmailItems/AoiKissEmailItem"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/QuincyDialogue_rom.dialogue",
|
||||||
|
kissEmail: "/Lotus/Types/Items/EmailItems/QuincyKissEmailItem"
|
||||||
|
}
|
||||||
|
]) {
|
||||||
|
const dialogue = inventory.DialogueHistory.Dialogues.find(x => x.DialogueName == dialogueName);
|
||||||
|
if (dialogue) {
|
||||||
|
if (dialogue.Rank == 7) {
|
||||||
|
await addEmailItem(inventory, kissEmail);
|
||||||
|
kalymos = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (dialogue.Rank == 6) {
|
||||||
|
kalymos = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (kalymos) {
|
||||||
|
await addEmailItem(inventory, "/Lotus/Types/Items/EmailItems/KalymosKissEmailItem");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanupInventory(inventory);
|
cleanupInventory(inventory);
|
||||||
|
|
||||||
inventory.NextRefill = new Date((Math.trunc(Date.now() / 86400000) + 1) * 86400000);
|
inventory.NextRefill = new Date((today + 1) * 86400000); // tomorrow at 0 UTC
|
||||||
//await inventory.save();
|
//await inventory.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,6 +195,63 @@ export const inventoryController: RequestHandler = async (request, response) =>
|
|||||||
//await inventory.save();
|
//await inventory.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i != inventory.QualifyingInvasions.length; ) {
|
||||||
|
const qi = inventory.QualifyingInvasions[i];
|
||||||
|
const invasion = getInvasionByOid(qi.invasionId.toString());
|
||||||
|
if (!invasion) {
|
||||||
|
logger.debug(`removing QualifyingInvasions entry for unknown invasion: ${qi.invasionId.toString()}`);
|
||||||
|
inventory.QualifyingInvasions.splice(i, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (invasion.Completed) {
|
||||||
|
let factionSidedWith: string | undefined;
|
||||||
|
let battlePay: ICountedItem[] | undefined;
|
||||||
|
if (qi.AttackerScore >= 3) {
|
||||||
|
factionSidedWith = invasion.Faction;
|
||||||
|
battlePay = invasion.AttackerReward.countedItems;
|
||||||
|
logger.debug(`invasion pay from ${factionSidedWith}`, { battlePay });
|
||||||
|
} else if (qi.DefenderScore >= 3) {
|
||||||
|
factionSidedWith = invasion.DefenderFaction;
|
||||||
|
battlePay = invasion.DefenderReward.countedItems;
|
||||||
|
logger.debug(`invasion pay from ${factionSidedWith}`, { battlePay });
|
||||||
|
}
|
||||||
|
if (factionSidedWith) {
|
||||||
|
if (battlePay) {
|
||||||
|
// Decoupling rewards from the inbox message because it may delete itself without being read
|
||||||
|
for (const item of battlePay) {
|
||||||
|
await addItem(inventory, item.ItemType, item.ItemCount);
|
||||||
|
}
|
||||||
|
await createMessage(account._id, [
|
||||||
|
{
|
||||||
|
sndr: eFaction.find(x => x.tag == factionSidedWith)?.name ?? factionSidedWith, // TOVERIFY
|
||||||
|
msg: `/Lotus/Language/G1Quests/${factionSidedWith}_InvasionThankyouMessageBody`,
|
||||||
|
sub: `/Lotus/Language/G1Quests/${factionSidedWith}_InvasionThankyouMessageSubject`,
|
||||||
|
countedAtt: battlePay,
|
||||||
|
attVisualOnly: true,
|
||||||
|
icon:
|
||||||
|
factionSidedWith == "FC_GRINEER"
|
||||||
|
? "/Lotus/Interface/Icons/Npcs/EliteRifleLancerAvatar.png" // Source: https://www.reddit.com/r/Warframe/comments/1aj4usx/battle_pay_worth_10_plat/, https://www.youtube.com/watch?v=XhNZ6ai6BOY
|
||||||
|
: "/Lotus/Interface/Icons/Npcs/CrewmanNormal.png", // My best source for this is https://www.youtube.com/watch?v=rxrCCFm73XE around 1:37
|
||||||
|
// TOVERIFY: highPriority?
|
||||||
|
endDate: new Date(Date.now() + 86400_000) // TOVERIFY: This type of inbox message seems to automatically delete itself. We'll just delete it after 24 hours, but it's not clear if this is correct.
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if (invasion.Faction != "FC_INFESTATION") {
|
||||||
|
// Sided with grineer -> opposed corpus -> send zanuka (harvester)
|
||||||
|
// Sided with corpus -> opposed grineer -> send g3 (death squad)
|
||||||
|
inventory[factionSidedWith != "FC_GRINEER" ? "DeathSquadable" : "Harvestable"] = true;
|
||||||
|
// TOVERIFY: Should this happen earlier?
|
||||||
|
// TOVERIFY: Should this send an (ephemeral) email?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.debug(`removing QualifyingInvasions entry for completed invasion: ${qi.invasionId.toString()}`);
|
||||||
|
inventory.QualifyingInvasions.splice(i, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
if (inventory.LastInventorySync) {
|
if (inventory.LastInventorySync) {
|
||||||
const lastSyncDuviriMood = Math.trunc(inventory.LastInventorySync.getTimestamp().getTime() / 7200000);
|
const lastSyncDuviriMood = Math.trunc(inventory.LastInventorySync.getTimestamp().getTime() / 7200000);
|
||||||
const currentDuviriMood = Math.trunc(Date.now() / 7200000);
|
const currentDuviriMood = Math.trunc(Date.now() / 7200000);
|
||||||
@ -128,13 +280,21 @@ export const getInventoryResponse = async (
|
|||||||
xpBasedLevelCapDisabled: boolean,
|
xpBasedLevelCapDisabled: boolean,
|
||||||
buildLabel: string | undefined
|
buildLabel: string | undefined
|
||||||
): Promise<IInventoryClient> => {
|
): Promise<IInventoryClient> => {
|
||||||
const [inventoryWithLoadOutPresets, ships] = await Promise.all([
|
const [inventoryWithLoadOutPresets, ships, latestMessage] = await Promise.all([
|
||||||
inventory.populate<{ LoadOutPresets: ILoadoutDatabase }>("LoadOutPresets"),
|
inventory.populate<{ LoadOutPresets: ILoadoutDatabase }>("LoadOutPresets"),
|
||||||
Ship.find({ ShipOwnerId: inventory.accountOwnerId })
|
Ship.find({ ShipOwnerId: inventory.accountOwnerId }),
|
||||||
|
Inbox.findOne({ ownerId: inventory.accountOwnerId }, "_id").sort({ date: -1 })
|
||||||
]);
|
]);
|
||||||
const inventoryResponse = inventoryWithLoadOutPresets.toJSON<IInventoryClient>();
|
const inventoryResponse = inventoryWithLoadOutPresets.toJSON<IInventoryClient>();
|
||||||
inventoryResponse.Ships = ships.map(x => x.toJSON<IShipInventory>());
|
inventoryResponse.Ships = ships.map(x => x.toJSON<IShipInventory>());
|
||||||
|
|
||||||
|
// In case mission inventory update added an inbox message, we need to send the Mailbox part so the client knows to refresh it.
|
||||||
|
if (latestMessage) {
|
||||||
|
inventoryResponse.Mailbox = {
|
||||||
|
LastInboxId: toOid(latestMessage._id)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (config.infiniteCredits) {
|
if (config.infiniteCredits) {
|
||||||
inventoryResponse.RegularCredits = 999999999;
|
inventoryResponse.RegularCredits = 999999999;
|
||||||
}
|
}
|
||||||
@ -175,6 +335,17 @@ export const getInventoryResponse = async (
|
|||||||
for (const uniqueName in ExportFlavour) {
|
for (const uniqueName in ExportFlavour) {
|
||||||
inventoryResponse.FlavourItems.push({ ItemType: uniqueName });
|
inventoryResponse.FlavourItems.push({ ItemType: uniqueName });
|
||||||
}
|
}
|
||||||
|
} else if (config.worldState?.baroTennoConRelay) {
|
||||||
|
[
|
||||||
|
"/Lotus/Types/Items/Events/TennoConRelay2022EarlyAccess",
|
||||||
|
"/Lotus/Types/Items/Events/TennoConRelay2023EarlyAccess",
|
||||||
|
"/Lotus/Types/Items/Events/TennoConRelay2024EarlyAccess",
|
||||||
|
"/Lotus/Types/Items/Events/TennoConRelay2025EarlyAccess"
|
||||||
|
].forEach(uniqueName => {
|
||||||
|
if (!inventoryResponse.FlavourItems.some(x => x.ItemType == uniqueName)) {
|
||||||
|
inventoryResponse.FlavourItems.push({ ItemType: uniqueName });
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.unlockAllSkins) {
|
if (config.unlockAllSkins) {
|
||||||
@ -282,9 +453,6 @@ export const getInventoryResponse = async (
|
|||||||
applyCheatsToInfestedFoundry(inventoryResponse.InfestedFoundry);
|
applyCheatsToInfestedFoundry(inventoryResponse.InfestedFoundry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Omitting this field so opening the navigation resyncs the inventory which is more desirable for typical usage.
|
|
||||||
inventoryResponse.LastInventorySync = undefined;
|
|
||||||
|
|
||||||
// Set 2FA enabled so trading post can be used
|
// Set 2FA enabled so trading post can be used
|
||||||
inventoryResponse.HWIDProtectEnabled = true;
|
inventoryResponse.HWIDProtectEnabled = true;
|
||||||
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getInventory, updateCurrency } from "@/src/services/inventoryService";
|
import { getInventory, updateCurrency, updateSlots } from "@/src/services/inventoryService";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { updateSlots } from "@/src/services/inventoryService";
|
|
||||||
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { exhaustive } from "@/src/utils/ts-utils";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
loadout slots are additionally purchased slots only
|
loadout slots are additionally purchased slots only
|
||||||
@ -23,13 +22,44 @@ 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;
|
||||||
|
|
||||||
if (body.Bin != InventorySlot.SUITS && body.Bin != InventorySlot.PVE_LOADOUTS) {
|
let price;
|
||||||
logger.warn(`unexpected slot purchase of type ${body.Bin}, account may be overcharged`);
|
let amount;
|
||||||
|
switch (body.Bin) {
|
||||||
|
case InventorySlot.SUITS:
|
||||||
|
case InventorySlot.MECHSUITS:
|
||||||
|
case InventorySlot.PVE_LOADOUTS:
|
||||||
|
case InventorySlot.CREWMEMBERS:
|
||||||
|
price = 20;
|
||||||
|
amount = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InventorySlot.SPACESUITS:
|
||||||
|
price = 12;
|
||||||
|
amount = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InventorySlot.WEAPONS:
|
||||||
|
case InventorySlot.SPACEWEAPONS:
|
||||||
|
case InventorySlot.SENTINELS:
|
||||||
|
case InventorySlot.RJ_COMPONENT_AND_ARMAMENTS:
|
||||||
|
case InventorySlot.AMPS:
|
||||||
|
price = 12;
|
||||||
|
amount = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InventorySlot.RIVENS:
|
||||||
|
price = 60;
|
||||||
|
amount = 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
exhaustive(body.Bin);
|
||||||
|
throw new Error(`unexpected slot purchase of type ${body.Bin as string}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
const currencyChanges = updateCurrency(inventory, 20, true);
|
const currencyChanges = updateCurrency(inventory, price, true);
|
||||||
updateSlots(inventory, body.Bin, 1, 1);
|
updateSlots(inventory, body.Bin, amount, amount);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
res.json({ InventoryChanges: currencyChanges });
|
res.json({ InventoryChanges: currencyChanges });
|
||||||
|
@ -8,7 +8,7 @@ import { createAccount, createNonce, getUsernameFromEmail, isCorrectPassword } f
|
|||||||
import { IDatabaseAccountJson, ILoginRequest, ILoginResponse } from "@/src/types/loginTypes";
|
import { IDatabaseAccountJson, ILoginRequest, ILoginResponse } from "@/src/types/loginTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { version_compare } from "@/src/helpers/inventoryHelpers";
|
import { version_compare } from "@/src/helpers/inventoryHelpers";
|
||||||
import { sendWsBroadcastTo } from "@/src/services/webService";
|
import { sendWsBroadcastTo } from "@/src/services/wsService";
|
||||||
|
|
||||||
export const loginController: RequestHandler = async (request, response) => {
|
export const loginController: RequestHandler = async (request, response) => {
|
||||||
const loginRequest = JSON.parse(String(request.body)) as ILoginRequest; // parse octet stream of json data to json object
|
const loginRequest = JSON.parse(String(request.body)) as ILoginRequest; // parse octet stream of json data to json object
|
||||||
@ -130,7 +130,7 @@ const createLoginResponse = (
|
|||||||
resp.Groups = [];
|
resp.Groups = [];
|
||||||
}
|
}
|
||||||
if (version_compare(buildLabel, "2021.04.13.19.58") >= 0) {
|
if (version_compare(buildLabel, "2021.04.13.19.58") >= 0) {
|
||||||
resp.DTLS = 99;
|
resp.DTLS = 0; // bit 0 enables DTLS. if enabled, additional bits can be set, e.g. bit 2 to enable logging. on live, the value is 99.
|
||||||
}
|
}
|
||||||
if (version_compare(buildLabel, "2022.04.29.12.53") >= 0) {
|
if (version_compare(buildLabel, "2022.04.29.12.53") >= 0) {
|
||||||
resp.ClientType = account.ClientType;
|
resp.ClientType = account.ClientType;
|
||||||
|
@ -8,6 +8,8 @@ import {
|
|||||||
setAccountGotLoginRewardToday
|
setAccountGotLoginRewardToday
|
||||||
} from "@/src/services/loginRewardService";
|
} from "@/src/services/loginRewardService";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { config } from "@/src/services/configService";
|
||||||
|
import { sendWsBroadcastTo } from "@/src/services/wsService";
|
||||||
|
|
||||||
export const loginRewardsController: RequestHandler = async (req, res) => {
|
export const loginRewardsController: RequestHandler = async (req, res) => {
|
||||||
const account = await getAccountForRequest(req);
|
const account = await getAccountForRequest(req);
|
||||||
@ -15,7 +17,7 @@ export const loginRewardsController: RequestHandler = async (req, res) => {
|
|||||||
const isMilestoneDay = account.LoginDays == 5 || account.LoginDays % 50 == 0;
|
const isMilestoneDay = account.LoginDays == 5 || account.LoginDays % 50 == 0;
|
||||||
const nextMilestoneDay = account.LoginDays < 5 ? 5 : (Math.trunc(account.LoginDays / 50) + 1) * 50;
|
const nextMilestoneDay = account.LoginDays < 5 ? 5 : (Math.trunc(account.LoginDays / 50) + 1) * 50;
|
||||||
|
|
||||||
if (today == account.LastLoginRewardDate) {
|
if (today == account.LastLoginRewardDate || config.disableDailyTribute) {
|
||||||
res.json({
|
res.json({
|
||||||
DailyTributeInfo: {
|
DailyTributeInfo: {
|
||||||
IsMilestoneDay: isMilestoneDay,
|
IsMilestoneDay: isMilestoneDay,
|
||||||
@ -46,10 +48,10 @@ export const loginRewardsController: RequestHandler = async (req, res) => {
|
|||||||
response.DailyTributeInfo.HasChosenReward = true;
|
response.DailyTributeInfo.HasChosenReward = true;
|
||||||
response.DailyTributeInfo.ChosenReward = randomRewards[0];
|
response.DailyTributeInfo.ChosenReward = randomRewards[0];
|
||||||
response.DailyTributeInfo.NewInventory = await claimLoginReward(inventory, randomRewards[0]);
|
response.DailyTributeInfo.NewInventory = await claimLoginReward(inventory, randomRewards[0]);
|
||||||
await inventory.save();
|
|
||||||
|
|
||||||
setAccountGotLoginRewardToday(account);
|
setAccountGotLoginRewardToday(account);
|
||||||
await account.save();
|
await Promise.all([inventory.save(), account.save()]);
|
||||||
|
|
||||||
|
sendWsBroadcastTo(account._id.toString(), { update_inventory: true });
|
||||||
}
|
}
|
||||||
res.json(response);
|
res.json(response);
|
||||||
};
|
};
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
} from "@/src/services/loginRewardService";
|
} from "@/src/services/loginRewardService";
|
||||||
import { getAccountForRequest } from "@/src/services/loginService";
|
import { getAccountForRequest } from "@/src/services/loginService";
|
||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
||||||
|
import { sendWsBroadcastTo } from "@/src/services/wsService";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
@ -34,11 +35,10 @@ export const loginRewardsSelectionController: RequestHandler = async (req, res)
|
|||||||
chosenReward = randomRewards.find(x => x.StoreItemType == body.ChosenReward)!;
|
chosenReward = randomRewards.find(x => x.StoreItemType == body.ChosenReward)!;
|
||||||
inventoryChanges = await claimLoginReward(inventory, chosenReward);
|
inventoryChanges = await claimLoginReward(inventory, chosenReward);
|
||||||
}
|
}
|
||||||
await inventory.save();
|
|
||||||
|
|
||||||
setAccountGotLoginRewardToday(account);
|
setAccountGotLoginRewardToday(account);
|
||||||
await account.save();
|
await Promise.all([inventory.save(), account.save()]);
|
||||||
|
|
||||||
|
sendWsBroadcastTo(account._id.toString(), { update_inventory: true });
|
||||||
res.json({
|
res.json({
|
||||||
DailyTributeInfo: {
|
DailyTributeInfo: {
|
||||||
NewInventory: inventoryChanges,
|
NewInventory: inventoryChanges,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { Account } from "@/src/models/loginModel";
|
import { Account } from "@/src/models/loginModel";
|
||||||
import { sendWsBroadcastTo } from "@/src/services/webService";
|
import { sendWsBroadcastTo } from "@/src/services/wsService";
|
||||||
|
|
||||||
export const logoutController: RequestHandler = async (req, res) => {
|
export const logoutController: RequestHandler = async (req, res) => {
|
||||||
if (!req.query.accountId) {
|
if (!req.query.accountId) {
|
||||||
|
@ -3,11 +3,16 @@ import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|||||||
import { getAccountForRequest } from "@/src/services/loginService";
|
import { getAccountForRequest } from "@/src/services/loginService";
|
||||||
import { IMissionInventoryUpdateRequest } from "@/src/types/requestTypes";
|
import { IMissionInventoryUpdateRequest } from "@/src/types/requestTypes";
|
||||||
import { addMissionInventoryUpdates, addMissionRewards } from "@/src/services/missionInventoryUpdateService";
|
import { addMissionInventoryUpdates, addMissionRewards } from "@/src/services/missionInventoryUpdateService";
|
||||||
import { generateRewardSeed, getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getInventoryResponse } from "./inventoryController";
|
import { getInventoryResponse } from "@/src/controllers/api/inventoryController";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { IMissionInventoryUpdateResponse } from "@/src/types/missionTypes";
|
import {
|
||||||
import { sendWsBroadcastTo } from "@/src/services/webService";
|
IMissionInventoryUpdateResponse,
|
||||||
|
IMissionInventoryUpdateResponseBackToDryDock,
|
||||||
|
IMissionInventoryUpdateResponseRailjackInterstitial
|
||||||
|
} from "@/src/types/missionTypes";
|
||||||
|
import { sendWsBroadcastTo } from "@/src/services/wsService";
|
||||||
|
import { generateRewardSeed } from "@/src/services/rngService";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
**** INPUT ****
|
**** INPUT ****
|
||||||
@ -88,17 +93,15 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
|
|||||||
AffiliationMods,
|
AffiliationMods,
|
||||||
SyndicateXPItemReward,
|
SyndicateXPItemReward,
|
||||||
ConquestCompletedMissionsCount
|
ConquestCompletedMissionsCount
|
||||||
} = await addMissionRewards(inventory, missionReport, firstCompletion);
|
} = await addMissionRewards(account, inventory, missionReport, firstCompletion);
|
||||||
|
|
||||||
if (missionReport.EndOfMatchUpload) {
|
if (missionReport.EndOfMatchUpload) {
|
||||||
inventory.RewardSeed = generateRewardSeed();
|
inventory.RewardSeed = generateRewardSeed();
|
||||||
}
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
const inventoryResponse = await getInventoryResponse(inventory, true, account.BuildLabel);
|
|
||||||
|
|
||||||
//TODO: figure out when to send inventory. it is needed for many cases.
|
//TODO: figure out when to send inventory. it is needed for many cases.
|
||||||
res.json({
|
const deltas: IMissionInventoryUpdateResponseRailjackInterstitial = {
|
||||||
InventoryJson: JSON.stringify(inventoryResponse),
|
|
||||||
InventoryChanges: inventoryChanges,
|
InventoryChanges: inventoryChanges,
|
||||||
MissionRewards,
|
MissionRewards,
|
||||||
...credits,
|
...credits,
|
||||||
@ -107,7 +110,25 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
|
|||||||
SyndicateXPItemReward,
|
SyndicateXPItemReward,
|
||||||
AffiliationMods,
|
AffiliationMods,
|
||||||
ConquestCompletedMissionsCount
|
ConquestCompletedMissionsCount
|
||||||
} satisfies IMissionInventoryUpdateResponse);
|
};
|
||||||
|
if (missionReport.RJ) {
|
||||||
|
logger.debug(`railjack interstitial request, sending only deltas`, deltas);
|
||||||
|
res.json(deltas);
|
||||||
|
} else if (missionReport.RewardInfo) {
|
||||||
|
logger.debug(`classic mission completion, sending everything`);
|
||||||
|
const inventoryResponse = await getInventoryResponse(inventory, true, account.BuildLabel);
|
||||||
|
res.json({
|
||||||
|
InventoryJson: JSON.stringify(inventoryResponse),
|
||||||
|
...deltas
|
||||||
|
} satisfies IMissionInventoryUpdateResponse);
|
||||||
|
} else {
|
||||||
|
logger.debug(`no reward info, assuming this wasn't a mission completion and we should just sync inventory`);
|
||||||
|
const inventoryResponse = await getInventoryResponse(inventory, true, account.BuildLabel);
|
||||||
|
res.json({
|
||||||
|
InventoryJson: JSON.stringify(inventoryResponse)
|
||||||
|
} satisfies IMissionInventoryUpdateResponseBackToDryDock);
|
||||||
|
}
|
||||||
|
|
||||||
sendWsBroadcastTo(account._id.toString(), { update_inventory: true });
|
sendWsBroadcastTo(account._id.toString(), { update_inventory: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { sendWsBroadcastTo } from "@/src/services/wsService";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import {
|
import {
|
||||||
getInventory,
|
getInventory,
|
||||||
@ -15,10 +16,9 @@ import {
|
|||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { getDefaultUpgrades } from "@/src/services/itemDataService";
|
import { getDefaultUpgrades } from "@/src/services/itemDataService";
|
||||||
import { modularWeaponTypes } from "@/src/helpers/modularWeaponHelper";
|
import { modularWeaponTypes } from "@/src/helpers/modularWeaponHelper";
|
||||||
import { IEquipmentDatabase } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
|
||||||
import { getRandomInt } from "@/src/services/rngService";
|
import { getRandomInt } from "@/src/services/rngService";
|
||||||
import { ExportSentinels, ExportWeapons, IDefaultUpgrade } from "warframe-public-export-plus";
|
import { ExportSentinels, ExportWeapons, IDefaultUpgrade } from "warframe-public-export-plus";
|
||||||
import { Status } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IEquipmentDatabase, Status } from "@/src/types/equipmentTypes";
|
||||||
|
|
||||||
interface IModularCraftRequest {
|
interface IModularCraftRequest {
|
||||||
WeaponType: string;
|
WeaponType: string;
|
||||||
@ -195,4 +195,5 @@ export const modularWeaponCraftingController: RequestHandler = async (req, res)
|
|||||||
MiscItems: miscItemChanges
|
MiscItems: miscItemChanges
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
sendWsBroadcastTo(accountId, { update_inventory: true });
|
||||||
};
|
};
|
||||||
|
@ -3,7 +3,7 @@ import { ExportWeapons } from "warframe-public-export-plus";
|
|||||||
import { IMongoDate } from "@/src/types/commonTypes";
|
import { IMongoDate } from "@/src/types/commonTypes";
|
||||||
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
|
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
|
||||||
import { SRng } from "@/src/services/rngService";
|
import { SRng } from "@/src/services/rngService";
|
||||||
import { ArtifactPolarity, EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { ArtifactPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import {
|
import {
|
||||||
addEquipment,
|
addEquipment,
|
||||||
@ -15,8 +15,10 @@ import {
|
|||||||
} from "@/src/services/inventoryService";
|
} from "@/src/services/inventoryService";
|
||||||
import { getDefaultUpgrades } from "@/src/services/itemDataService";
|
import { getDefaultUpgrades } from "@/src/services/itemDataService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { sendWsBroadcastTo } from "@/src/services/wsService";
|
||||||
import { modularWeaponTypes } from "@/src/helpers/modularWeaponHelper";
|
import { modularWeaponTypes } from "@/src/helpers/modularWeaponHelper";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
|
import { EquipmentFeatures } from "@/src/types/equipmentTypes";
|
||||||
|
|
||||||
export const modularWeaponSaleController: RequestHandler = async (req, res) => {
|
export const modularWeaponSaleController: RequestHandler = async (req, res) => {
|
||||||
const partTypeToParts: Record<string, string[]> = {};
|
const partTypeToParts: Record<string, string[]> = {};
|
||||||
@ -67,6 +69,7 @@ export const modularWeaponSaleController: RequestHandler = async (req, res) => {
|
|||||||
res.json({
|
res.json({
|
||||||
InventoryChanges: inventoryChanges
|
InventoryChanges: inventoryChanges
|
||||||
});
|
});
|
||||||
|
sendWsBroadcastTo(accountId, { update_inventory: true });
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`unknown modularWeaponSale op: ${String(req.query.op)}`);
|
throw new Error(`unknown modularWeaponSale op: ${String(req.query.op)}`);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
|
|||||||
import { getInventory, updateCurrency } from "@/src/services/inventoryService";
|
import { getInventory, updateCurrency } from "@/src/services/inventoryService";
|
||||||
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 { sendWsBroadcastTo } from "@/src/services/webService";
|
import { sendWsBroadcastTo } from "@/src/services/wsService";
|
||||||
|
|
||||||
interface INameWeaponRequest {
|
interface INameWeaponRequest {
|
||||||
ItemName: string;
|
ItemName: string;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { version_compare } from "@/src/helpers/inventoryHelpers";
|
import { version_compare } from "@/src/helpers/inventoryHelpers";
|
||||||
import {
|
import {
|
||||||
antivirusMods,
|
antivirusMods,
|
||||||
consumeModCharge,
|
|
||||||
decodeNemesisGuess,
|
decodeNemesisGuess,
|
||||||
encodeNemesisGuess,
|
encodeNemesisGuess,
|
||||||
getInfNodes,
|
getInfNodes,
|
||||||
@ -17,12 +16,13 @@ import {
|
|||||||
parseUpgrade
|
parseUpgrade
|
||||||
} from "@/src/helpers/nemesisHelpers";
|
} from "@/src/helpers/nemesisHelpers";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
|
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
||||||
import { freeUpSlot, getInventory } from "@/src/services/inventoryService";
|
import { addMods, freeUpSlot, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountForRequest } from "@/src/services/loginService";
|
import { getAccountForRequest } from "@/src/services/loginService";
|
||||||
import { SRng } from "@/src/services/rngService";
|
import { SRng } from "@/src/services/rngService";
|
||||||
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IEquipmentClient } from "@/src/types/equipmentTypes";
|
||||||
import {
|
import {
|
||||||
IInnateDamageFingerprint,
|
IInnateDamageFingerprint,
|
||||||
IInventoryClient,
|
IInventoryClient,
|
||||||
@ -36,6 +36,7 @@ import {
|
|||||||
} from "@/src/types/inventoryTypes/inventoryTypes";
|
} from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
export const nemesisController: RequestHandler = async (req, res) => {
|
export const nemesisController: RequestHandler = async (req, res) => {
|
||||||
const account = await getAccountForRequest(req);
|
const account = await getAccountForRequest(req);
|
||||||
@ -391,3 +392,54 @@ interface IKnife {
|
|||||||
AttachedUpgrades: IUpgradeClient[];
|
AttachedUpgrades: IUpgradeClient[];
|
||||||
HiddenWhenHolstered: boolean;
|
HiddenWhenHolstered: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const consumeModCharge = (
|
||||||
|
response: IKnifeResponse,
|
||||||
|
inventory: TInventoryDatabaseDocument,
|
||||||
|
upgrade: { ItemId: IOid; ItemType: string },
|
||||||
|
dataknifeUpgrades: string[]
|
||||||
|
): void => {
|
||||||
|
response.UpgradeIds ??= [];
|
||||||
|
response.UpgradeTypes ??= [];
|
||||||
|
response.UpgradeFingerprints ??= [];
|
||||||
|
response.UpgradeNew ??= [];
|
||||||
|
response.HasKnife = true;
|
||||||
|
|
||||||
|
if (upgrade.ItemId.$oid != "000000000000000000000000") {
|
||||||
|
const dbUpgrade = inventory.Upgrades.id(upgrade.ItemId.$oid)!;
|
||||||
|
const fingerprint = JSON.parse(dbUpgrade.UpgradeFingerprint!) as { lvl: number };
|
||||||
|
fingerprint.lvl += 1;
|
||||||
|
dbUpgrade.UpgradeFingerprint = JSON.stringify(fingerprint);
|
||||||
|
|
||||||
|
response.UpgradeIds.push(upgrade.ItemId.$oid);
|
||||||
|
response.UpgradeTypes.push(upgrade.ItemType);
|
||||||
|
response.UpgradeFingerprints.push(fingerprint);
|
||||||
|
response.UpgradeNew.push(false);
|
||||||
|
} else {
|
||||||
|
const id = new Types.ObjectId();
|
||||||
|
inventory.Upgrades.push({
|
||||||
|
_id: id,
|
||||||
|
ItemType: upgrade.ItemType,
|
||||||
|
UpgradeFingerprint: `{"lvl":1}`
|
||||||
|
});
|
||||||
|
|
||||||
|
addMods(inventory, [
|
||||||
|
{
|
||||||
|
ItemType: upgrade.ItemType,
|
||||||
|
ItemCount: -1
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
const dataknifeRawUpgradeIndex = dataknifeUpgrades.indexOf(upgrade.ItemType);
|
||||||
|
if (dataknifeRawUpgradeIndex != -1) {
|
||||||
|
dataknifeUpgrades[dataknifeRawUpgradeIndex] = id.toString();
|
||||||
|
} else {
|
||||||
|
logger.warn(`${upgrade.ItemType} not found in dataknife config`);
|
||||||
|
}
|
||||||
|
|
||||||
|
response.UpgradeIds.push(id.toString());
|
||||||
|
response.UpgradeTypes.push(upgrade.ItemType);
|
||||||
|
response.UpgradeFingerprints.push({ lvl: 1 });
|
||||||
|
response.UpgradeNew.push(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -57,7 +57,15 @@ export const placeDecoInComponentController: RequestHandler = async (req, res) =
|
|||||||
component.DecoCapacity -= meta.capacityCost;
|
component.DecoCapacity -= meta.capacityCost;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const itemType = Object.entries(ExportResources).find(arr => arr[1].deco == deco.Type)![0];
|
const entry = Object.entries(ExportResources).find(arr => arr[1].deco == deco.Type);
|
||||||
|
if (!entry) {
|
||||||
|
throw new Error(`unknown deco type: ${deco.Type}`);
|
||||||
|
}
|
||||||
|
const [itemType, meta] = entry;
|
||||||
|
if (meta.dojoCapacityCost === undefined) {
|
||||||
|
throw new Error(`unknown deco type: ${deco.Type}`);
|
||||||
|
}
|
||||||
|
component.DecoCapacity -= meta.dojoCapacityCost;
|
||||||
if (deco.Sockets !== undefined) {
|
if (deco.Sockets !== undefined) {
|
||||||
guild.VaultFusionTreasures!.find(x => x.ItemType == itemType && x.Sockets == deco.Sockets)!.ItemCount -=
|
guild.VaultFusionTreasures!.find(x => x.ItemType == itemType && x.Sockets == deco.Sockets)!.ItemCount -=
|
||||||
1;
|
1;
|
||||||
@ -71,7 +79,13 @@ export const placeDecoInComponentController: RequestHandler = async (req, res) =
|
|||||||
if (meta) {
|
if (meta) {
|
||||||
processDojoBuildMaterialsGathered(guild, meta);
|
processDojoBuildMaterialsGathered(guild, meta);
|
||||||
}
|
}
|
||||||
} else if (guild.AutoContributeFromVault && guild.VaultRegularCredits && guild.VaultMiscItems) {
|
} else if (
|
||||||
|
deco.Type.startsWith("/Lotus/Objects/Tenno/Dojo/NpcPlaceables/") ||
|
||||||
|
(guild.AutoContributeFromVault && guild.VaultRegularCredits && guild.VaultMiscItems)
|
||||||
|
) {
|
||||||
|
if (!guild.VaultRegularCredits || !guild.VaultMiscItems) {
|
||||||
|
throw new Error(`dojo visitor placed without anything in vault?!`);
|
||||||
|
}
|
||||||
if (guild.VaultRegularCredits >= scaleRequiredCount(guild.Tier, meta.price)) {
|
if (guild.VaultRegularCredits >= scaleRequiredCount(guild.Tier, meta.price)) {
|
||||||
let enoughMiscItems = true;
|
let enoughMiscItems = true;
|
||||||
for (const ingredient of meta.ingredients) {
|
for (const ingredient of meta.ingredients) {
|
||||||
|
@ -1,25 +1,52 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { addConsumables, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IPlayerSkills } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IPlayerSkills } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const playerSkillsController: RequestHandler = async (req, res) => {
|
export const playerSkillsController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(accountId, "PlayerSkills");
|
const inventory = await getInventory(accountId, "PlayerSkills Consumables");
|
||||||
const request = getJSONfromString<IPlayerSkillsRequest>(String(req.body));
|
const request = getJSONfromString<IPlayerSkillsRequest>(String(req.body));
|
||||||
|
|
||||||
const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills];
|
const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills];
|
||||||
const cost = (request.Pool == "LPP_DRIFTER" ? drifterCosts[oldRank] : 1 << oldRank) * 1000;
|
const cost = (request.Pool == "LPP_DRIFTER" ? drifterCosts[oldRank] : 1 << oldRank) * 1000;
|
||||||
inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost;
|
inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost;
|
||||||
inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++;
|
inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++;
|
||||||
await inventory.save();
|
|
||||||
|
|
||||||
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
|
if (request.Skill == "LPS_COMMAND") {
|
||||||
|
if (inventory.PlayerSkills.LPS_COMMAND == 9) {
|
||||||
|
const consumablesChanges = [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Restoratives/Consumable/CrewmateBall",
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
addConsumables(inventory, consumablesChanges);
|
||||||
|
inventoryChanges.Consumables = consumablesChanges;
|
||||||
|
}
|
||||||
|
} else if (request.Skill == "LPS_DRIFT_RIDING") {
|
||||||
|
if (inventory.PlayerSkills.LPS_DRIFT_RIDING == 9) {
|
||||||
|
const consumablesChanges = [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Restoratives/ErsatzSummon",
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
addConsumables(inventory, consumablesChanges);
|
||||||
|
inventoryChanges.Consumables = consumablesChanges;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
Pool: request.Pool,
|
Pool: request.Pool,
|
||||||
PoolInc: -cost,
|
PoolInc: -cost,
|
||||||
Skill: request.Skill,
|
Skill: request.Skill,
|
||||||
Rank: oldRank + 1
|
Rank: oldRank + 1,
|
||||||
|
InventoryChanges: inventoryChanges
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ export const projectionManagerController: RequestHandler = async (req, res) => {
|
|||||||
const [era, category, currentQuality] = parseProjection(request.projectionType);
|
const [era, category, currentQuality] = parseProjection(request.projectionType);
|
||||||
const upgradeCost = config.dontSubtractVoidTraces
|
const upgradeCost = config.dontSubtractVoidTraces
|
||||||
? 0
|
? 0
|
||||||
: (request.qualityTag - qualityKeywordToNumber[currentQuality]) * 25;
|
: qualityNumberToCost[request.qualityTag] - qualityNumberToCost[qualityKeywordToNumber[currentQuality]];
|
||||||
const newProjectionType = findProjection(era, category, qualityNumberToKeyword[request.qualityTag]);
|
const newProjectionType = findProjection(era, category, qualityNumberToKeyword[request.qualityTag]);
|
||||||
addMiscItems(inventory, [
|
addMiscItems(inventory, [
|
||||||
{
|
{
|
||||||
@ -49,6 +49,7 @@ const qualityKeywordToNumber: Record<VoidProjectionQuality, number> = {
|
|||||||
VPQ_GOLD: 2,
|
VPQ_GOLD: 2,
|
||||||
VPQ_PLATINUM: 3
|
VPQ_PLATINUM: 3
|
||||||
};
|
};
|
||||||
|
const qualityNumberToCost = [0, 25, 50, 100];
|
||||||
|
|
||||||
// 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] => {
|
||||||
|
@ -3,7 +3,7 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
|
|||||||
import { IPurchaseRequest } from "@/src/types/purchaseTypes";
|
import { IPurchaseRequest } from "@/src/types/purchaseTypes";
|
||||||
import { handlePurchase } from "@/src/services/purchaseService";
|
import { handlePurchase } from "@/src/services/purchaseService";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { sendWsBroadcastTo } from "@/src/services/webService";
|
import { sendWsBroadcastTo } from "@/src/services/wsService";
|
||||||
|
|
||||||
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 = JSON.parse(String(req.body)) as IPurchaseRequest;
|
||||||
@ -11,6 +11,7 @@ export const purchaseController: RequestHandler = async (req, res) => {
|
|||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
const response = await handlePurchase(purchaseRequest, inventory);
|
const response = await handlePurchase(purchaseRequest, inventory);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
//console.log(JSON.stringify(response, null, 2));
|
||||||
res.json(response);
|
res.json(response);
|
||||||
sendWsBroadcastTo(accountId, { update_inventory: true });
|
sendWsBroadcastTo(accountId, { update_inventory: true });
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getInventory, updateCurrency } from "@/src/services/inventoryService";
|
import { getInventory, updateCurrency } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { sendWsBroadcastTo } from "@/src/services/wsService";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const releasePetController: RequestHandler = async (req, res) => {
|
export const releasePetController: RequestHandler = async (req, res) => {
|
||||||
@ -19,6 +20,7 @@ export const releasePetController: RequestHandler = async (req, res) => {
|
|||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({ inventoryChanges }); // Not a mistake; it's "inventoryChanges" here.
|
res.json({ inventoryChanges }); // Not a mistake; it's "inventoryChanges" here.
|
||||||
|
sendWsBroadcastTo(accountId, { update_inventory: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IReleasePetRequest {
|
interface IReleasePetRequest {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getInventory, updateCurrency } from "@/src/services/inventoryService";
|
import { getInventory, updateCurrency } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { sendWsBroadcastTo } from "@/src/services/webService";
|
import { sendWsBroadcastTo } from "@/src/services/wsService";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
5
src/controllers/api/resetQuestProgressController.ts
Normal file
5
src/controllers/api/resetQuestProgressController.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
export const resetQuestProgressController: RequestHandler = (_req, res) => {
|
||||||
|
res.send("1").end();
|
||||||
|
};
|
@ -1,7 +1,7 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { Status } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { Status } from "@/src/types/equipmentTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const retrievePetFromStasisController: RequestHandler = async (req, res) => {
|
export const retrievePetFromStasisController: RequestHandler = async (req, res) => {
|
||||||
|
@ -2,7 +2,7 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { ISettings } from "../../types/inventoryTypes/inventoryTypes";
|
import { ISettings } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
|
||||||
interface ISaveSettingsRequest {
|
interface ISaveSettingsRequest {
|
||||||
Settings: ISettings;
|
Settings: ISettings;
|
||||||
|
@ -9,22 +9,28 @@ import {
|
|||||||
freeUpSlot,
|
freeUpSlot,
|
||||||
combineInventoryChanges,
|
combineInventoryChanges,
|
||||||
addCrewShipRawSalvage,
|
addCrewShipRawSalvage,
|
||||||
addFusionPoints
|
addFusionPoints,
|
||||||
|
addCrewShipFusionPoints,
|
||||||
|
addFusionTreasures
|
||||||
} from "@/src/services/inventoryService";
|
} from "@/src/services/inventoryService";
|
||||||
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { sendWsBroadcastTo } from "@/src/services/webService";
|
import { sendWsBroadcastEx } from "@/src/services/wsService";
|
||||||
|
import { parseFusionTreasure } from "@/src/helpers/inventoryHelpers";
|
||||||
|
|
||||||
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;
|
||||||
|
//console.log(JSON.stringify(payload, null, 2));
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const requiredFields = new Set<keyof TInventoryDatabaseDocument>();
|
const requiredFields = new Set<keyof TInventoryDatabaseDocument>();
|
||||||
if (payload.SellCurrency == "SC_RegularCredits") {
|
if (payload.SellCurrency == "SC_RegularCredits") {
|
||||||
requiredFields.add("RegularCredits");
|
requiredFields.add("RegularCredits");
|
||||||
} else if (payload.SellCurrency == "SC_FusionPoints") {
|
} else if (payload.SellCurrency == "SC_FusionPoints") {
|
||||||
requiredFields.add("FusionPoints");
|
requiredFields.add("FusionPoints");
|
||||||
|
} else if (payload.SellCurrency == "SC_CrewShipFusionPoints") {
|
||||||
|
requiredFields.add("CrewShipFusionPoints");
|
||||||
} else {
|
} else {
|
||||||
requiredFields.add("MiscItems");
|
requiredFields.add("MiscItems");
|
||||||
}
|
}
|
||||||
@ -58,6 +64,9 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
if (payload.Items.Hoverboards) {
|
if (payload.Items.Hoverboards) {
|
||||||
requiredFields.add(InventorySlot.SPACESUITS);
|
requiredFields.add(InventorySlot.SPACESUITS);
|
||||||
}
|
}
|
||||||
|
if (payload.Items.CrewMembers) {
|
||||||
|
requiredFields.add(InventorySlot.CREWMEMBERS);
|
||||||
|
}
|
||||||
if (payload.Items.CrewShipWeapons || payload.Items.CrewShipWeaponSkins) {
|
if (payload.Items.CrewShipWeapons || payload.Items.CrewShipWeaponSkins) {
|
||||||
requiredFields.add(InventorySlot.RJ_COMPONENT_AND_ARMAMENTS);
|
requiredFields.add(InventorySlot.RJ_COMPONENT_AND_ARMAMENTS);
|
||||||
requiredFields.add("CrewShipRawSalvage");
|
requiredFields.add("CrewShipRawSalvage");
|
||||||
@ -75,6 +84,8 @@ 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") {
|
||||||
addFusionPoints(inventory, payload.SellPrice);
|
addFusionPoints(inventory, payload.SellPrice);
|
||||||
|
} else if (payload.SellCurrency == "SC_CrewShipFusionPoints") {
|
||||||
|
addCrewShipFusionPoints(inventory, payload.SellPrice);
|
||||||
} else if (payload.SellCurrency == "SC_PrimeBucks") {
|
} else if (payload.SellCurrency == "SC_PrimeBucks") {
|
||||||
addMiscItems(inventory, [
|
addMiscItems(inventory, [
|
||||||
{
|
{
|
||||||
@ -181,6 +192,17 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
inventory.Drones.pull({ _id: sellItem.String });
|
inventory.Drones.pull({ _id: sellItem.String });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (payload.Items.KubrowPetPrints) {
|
||||||
|
payload.Items.KubrowPetPrints.forEach(sellItem => {
|
||||||
|
inventory.KubrowPetPrints.pull({ _id: sellItem.String });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (payload.Items.CrewMembers) {
|
||||||
|
payload.Items.CrewMembers.forEach(sellItem => {
|
||||||
|
inventory.CrewMembers.pull({ _id: sellItem.String });
|
||||||
|
freeUpSlot(inventory, InventorySlot.CREWMEMBERS);
|
||||||
|
});
|
||||||
|
}
|
||||||
if (payload.Items.CrewShipWeapons) {
|
if (payload.Items.CrewShipWeapons) {
|
||||||
payload.Items.CrewShipWeapons.forEach(sellItem => {
|
payload.Items.CrewShipWeapons.forEach(sellItem => {
|
||||||
if (sellItem.String[0] == "/") {
|
if (sellItem.String[0] == "/") {
|
||||||
@ -275,12 +297,17 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (payload.Items.FusionTreasures) {
|
||||||
|
payload.Items.FusionTreasures.forEach(sellItem => {
|
||||||
|
addFusionTreasures(inventory, [parseFusionTreasure(sellItem.String, sellItem.Count * -1)]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
inventoryChanges: inventoryChanges // "inventoryChanges" for this response instead of the usual "InventoryChanges"
|
inventoryChanges: inventoryChanges // "inventoryChanges" for this response instead of the usual "InventoryChanges"
|
||||||
});
|
});
|
||||||
sendWsBroadcastTo(accountId, { update_inventory: true });
|
sendWsBroadcastEx({ update_inventory: true }, accountId, parseInt(String(req.query.wsid)));
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ISellRequest {
|
interface ISellRequest {
|
||||||
@ -303,8 +330,11 @@ interface ISellRequest {
|
|||||||
OperatorAmps?: ISellItem[];
|
OperatorAmps?: ISellItem[];
|
||||||
Hoverboards?: ISellItem[];
|
Hoverboards?: ISellItem[];
|
||||||
Drones?: ISellItem[];
|
Drones?: ISellItem[];
|
||||||
|
KubrowPetPrints?: ISellItem[];
|
||||||
|
CrewMembers?: ISellItem[];
|
||||||
CrewShipWeapons?: ISellItem[];
|
CrewShipWeapons?: ISellItem[];
|
||||||
CrewShipWeaponSkins?: ISellItem[];
|
CrewShipWeaponSkins?: ISellItem[];
|
||||||
|
FusionTreasures?: ISellItem[];
|
||||||
};
|
};
|
||||||
SellPrice: number;
|
SellPrice: number;
|
||||||
SellCurrency:
|
SellCurrency:
|
||||||
@ -313,7 +343,8 @@ interface ISellRequest {
|
|||||||
| "SC_FusionPoints"
|
| "SC_FusionPoints"
|
||||||
| "SC_DistillPoints"
|
| "SC_DistillPoints"
|
||||||
| "SC_CrewShipFusionPoints"
|
| "SC_CrewShipFusionPoints"
|
||||||
| "SC_Resources";
|
| "SC_Resources"
|
||||||
|
| "somethingelsewemightnotknowabout";
|
||||||
buildLabel: string;
|
buildLabel: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { RequestHandler } from "express";
|
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/personalRoomsTypes";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
|
||||||
export const setBootLocationController: RequestHandler = async (req, res) => {
|
export const setBootLocationController: RequestHandler = async (req, res) => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IPictureFrameInfo, ISetPlacedDecoInfoRequest } from "@/src/types/shipTypes";
|
import { IPictureFrameInfo, ISetPlacedDecoInfoRequest } from "@/src/types/personalRoomsTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { handleSetPlacedDecoInfo } from "@/src/services/shipCustomizationsService";
|
import { handleSetPlacedDecoInfo } from "@/src/services/shipCustomizationsService";
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
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/personalRoomsTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { RequestHandler } from "express";
|
|||||||
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
||||||
import { IOid } from "@/src/types/commonTypes";
|
import { IOid } from "@/src/types/commonTypes";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { IFavouriteLoadoutDatabase, TBootLocation } from "@/src/types/shipTypes";
|
import { IFavouriteLoadoutDatabase, TBootLocation } from "@/src/types/personalRoomsTypes";
|
||||||
|
|
||||||
export const setShipFavouriteLoadoutController: RequestHandler = async (req, res) => {
|
export const setShipFavouriteLoadoutController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
@ -2,7 +2,7 @@ import { fromMongoDate, fromOid } from "@/src/helpers/inventoryHelpers";
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IEquipmentClient } from "@/src/types/equipmentTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const setSuitInfectionController: RequestHandler = async (req, res) => {
|
export const setSuitInfectionController: RequestHandler = async (req, res) => {
|
||||||
|
@ -1,20 +1,17 @@
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IShipDecorationsRequest } from "@/src/types/shipTypes";
|
import { IShipDecorationsRequest, IResetShipDecorationsRequest } from "@/src/types/personalRoomsTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { handleSetShipDecorations } from "@/src/services/shipCustomizationsService";
|
import { handleResetShipDecorations, handleSetShipDecorations } from "@/src/services/shipCustomizationsService";
|
||||||
|
|
||||||
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;
|
if (req.query.reset == "1") {
|
||||||
|
const request = JSON.parse(req.body as string) as IResetShipDecorationsRequest;
|
||||||
try {
|
const response = await handleResetShipDecorations(accountId, request);
|
||||||
|
res.send(response);
|
||||||
|
} else {
|
||||||
|
const shipDecorationsRequest = JSON.parse(req.body as string) as IShipDecorationsRequest;
|
||||||
const placedDecoration = await handleSetShipDecorations(accountId, shipDecorationsRequest);
|
const placedDecoration = await handleSetShipDecorations(accountId, shipDecorationsRequest);
|
||||||
res.send(placedDecoration);
|
res.send(placedDecoration);
|
||||||
} catch (error: unknown) {
|
|
||||||
if (error instanceof Error) {
|
|
||||||
logger.error(`error in shipDecorationsController: ${error.message}`);
|
|
||||||
res.status(400).json({ error: error.message });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -45,9 +45,9 @@ export const startRecipeController: RequestHandler = async (req, res) => {
|
|||||||
for (let i = 0; i != recipe.ingredients.length; ++i) {
|
for (let i = 0; i != recipe.ingredients.length; ++i) {
|
||||||
if (startRecipeRequest.Ids[i] && startRecipeRequest.Ids[i][0] != "/") {
|
if (startRecipeRequest.Ids[i] && startRecipeRequest.Ids[i][0] != "/") {
|
||||||
if (recipe.ingredients[i].ItemType == "/Lotus/Types/Game/KubrowPet/Eggs/KubrowPetEggItem") {
|
if (recipe.ingredients[i].ItemType == "/Lotus/Types/Game/KubrowPet/Eggs/KubrowPetEggItem") {
|
||||||
const index = inventory.KubrowPetEggs!.findIndex(x => x._id.equals(startRecipeRequest.Ids[i]));
|
const index = inventory.KubrowPetEggs.findIndex(x => x._id.equals(startRecipeRequest.Ids[i]));
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
inventory.KubrowPetEggs!.splice(index, 1);
|
inventory.KubrowPetEggs.splice(index, 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const category = ExportWeapons[recipe.ingredients[i].ItemType].productCategory;
|
const category = ExportWeapons[recipe.ingredients[i].ItemType].productCategory;
|
||||||
@ -72,6 +72,10 @@ export const startRecipeController: RequestHandler = async (req, res) => {
|
|||||||
if (recipe.secretIngredientAction == "SIA_CREATE_KUBROW") {
|
if (recipe.secretIngredientAction == "SIA_CREATE_KUBROW") {
|
||||||
inventoryChanges = addKubrowPet(inventory, getRandomElement(recipe.secretIngredients!)!.ItemType);
|
inventoryChanges = addKubrowPet(inventory, getRandomElement(recipe.secretIngredients!)!.ItemType);
|
||||||
pr.KubrowPet = new Types.ObjectId(fromOid(inventoryChanges.KubrowPets![0].ItemId));
|
pr.KubrowPet = new Types.ObjectId(fromOid(inventoryChanges.KubrowPets![0].ItemId));
|
||||||
|
} else if (recipe.secretIngredientAction == "SIA_DISTILL_PRINT") {
|
||||||
|
pr.KubrowPet = new Types.ObjectId(startRecipeRequest.Ids[recipe.ingredients.length]);
|
||||||
|
const pet = inventory.KubrowPets.id(pr.KubrowPet)!;
|
||||||
|
pet.Details!.PrintsRemaining -= 1;
|
||||||
} else if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") {
|
} else if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") {
|
||||||
const spectreLoadout: ISpectreLoadout = {
|
const spectreLoadout: ISpectreLoadout = {
|
||||||
ItemType: recipe.resultType,
|
ItemType: recipe.resultType,
|
||||||
|
@ -6,7 +6,7 @@ import { IOid } from "@/src/types/commonTypes";
|
|||||||
import { ExportSyndicates, ExportWeapons } from "warframe-public-export-plus";
|
import { ExportSyndicates, ExportWeapons } from "warframe-public-export-plus";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { IAffiliationMods, IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IAffiliationMods, IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { EquipmentFeatures } from "@/src/types/equipmentTypes";
|
||||||
|
|
||||||
export const syndicateStandingBonusController: RequestHandler = async (req, res) => {
|
export const syndicateStandingBonusController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
@ -2,7 +2,7 @@ import { fromMongoDate, fromOid } from "@/src/helpers/inventoryHelpers";
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { addMiscItem, getInventory } from "@/src/services/inventoryService";
|
import { addMiscItem, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IEquipmentClient } from "@/src/types/equipmentTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const umbraController: RequestHandler = async (req, res) => {
|
export const umbraController: RequestHandler = async (req, res) => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getAccountForRequest } from "@/src/services/loginService";
|
import { getAccountForRequest } from "@/src/services/loginService";
|
||||||
import { addChallenges, getInventory } from "@/src/services/inventoryService";
|
import { addCalendarProgress, addChallenges, getInventory } from "@/src/services/inventoryService";
|
||||||
import { IChallengeProgress, ISeasonChallenge } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IChallengeProgress, ISeasonChallenge } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { IAffiliationMods } from "@/src/types/purchaseTypes";
|
import { IAffiliationMods } from "@/src/types/purchaseTypes";
|
||||||
import { getEntriesUnsafe } from "@/src/utils/ts-utils";
|
import { getEntriesUnsafe } from "@/src/utils/ts-utils";
|
||||||
@ -10,6 +10,7 @@ import { logger } from "@/src/utils/logger";
|
|||||||
export const updateChallengeProgressController: RequestHandler = async (req, res) => {
|
export const updateChallengeProgressController: RequestHandler = async (req, res) => {
|
||||||
const challenges = getJSONfromString<IUpdateChallengeProgressRequest>(String(req.body));
|
const challenges = getJSONfromString<IUpdateChallengeProgressRequest>(String(req.body));
|
||||||
const account = await getAccountForRequest(req);
|
const account = await getAccountForRequest(req);
|
||||||
|
logger.debug(`challenge report:`, challenges);
|
||||||
|
|
||||||
const inventory = await getInventory(
|
const inventory = await getInventory(
|
||||||
account._id.toString(),
|
account._id.toString(),
|
||||||
@ -17,7 +18,7 @@ export const updateChallengeProgressController: RequestHandler = async (req, res
|
|||||||
);
|
);
|
||||||
let affiliationMods: IAffiliationMods[] = [];
|
let affiliationMods: IAffiliationMods[] = [];
|
||||||
if (challenges.ChallengeProgress) {
|
if (challenges.ChallengeProgress) {
|
||||||
affiliationMods = addChallenges(
|
affiliationMods = await addChallenges(
|
||||||
account,
|
account,
|
||||||
inventory,
|
inventory,
|
||||||
challenges.ChallengeProgress,
|
challenges.ChallengeProgress,
|
||||||
@ -25,13 +26,17 @@ export const updateChallengeProgressController: RequestHandler = async (req, res
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
for (const [key, value] of getEntriesUnsafe(challenges)) {
|
for (const [key, value] of getEntriesUnsafe(challenges)) {
|
||||||
|
if (value === undefined) {
|
||||||
|
logger.error(`Challenge progress update key ${key} has no value`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "ChallengesFixVersion":
|
case "ChallengesFixVersion":
|
||||||
inventory.ChallengesFixVersion = value;
|
inventory.ChallengesFixVersion = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "SeasonChallengeHistory":
|
case "SeasonChallengeHistory":
|
||||||
value!.forEach(({ challenge, id }) => {
|
value.forEach(({ challenge, id }) => {
|
||||||
const itemIndex = inventory.SeasonChallengeHistory.findIndex(i => i.challenge === challenge);
|
const itemIndex = inventory.SeasonChallengeHistory.findIndex(i => i.challenge === challenge);
|
||||||
if (itemIndex !== -1) {
|
if (itemIndex !== -1) {
|
||||||
inventory.SeasonChallengeHistory[itemIndex].id = id;
|
inventory.SeasonChallengeHistory[itemIndex].id = id;
|
||||||
@ -41,6 +46,10 @@ export const updateChallengeProgressController: RequestHandler = async (req, res
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "CalendarProgress":
|
||||||
|
addCalendarProgress(inventory, value);
|
||||||
|
break;
|
||||||
|
|
||||||
case "ChallengeProgress":
|
case "ChallengeProgress":
|
||||||
case "SeasonChallengeCompletions":
|
case "SeasonChallengeCompletions":
|
||||||
case "ChallengePTS":
|
case "ChallengePTS":
|
||||||
@ -63,5 +72,6 @@ interface IUpdateChallengeProgressRequest {
|
|||||||
ChallengeProgress?: IChallengeProgress[];
|
ChallengeProgress?: IChallengeProgress[];
|
||||||
SeasonChallengeHistory?: ISeasonChallenge[];
|
SeasonChallengeHistory?: ISeasonChallenge[];
|
||||||
SeasonChallengeCompletions?: ISeasonChallenge[];
|
SeasonChallengeCompletions?: ISeasonChallenge[];
|
||||||
|
CalendarProgress?: { challenge: string }[];
|
||||||
crossPlaySetting?: string;
|
crossPlaySetting?: string;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { IUpgradesRequest } from "@/src/types/requestTypes";
|
import { IUpgradesRequest } from "@/src/types/requestTypes";
|
||||||
import {
|
import { ArtifactPolarity, IAbilityOverride } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
ArtifactPolarity,
|
|
||||||
IEquipmentDatabase,
|
|
||||||
EquipmentFeatures,
|
|
||||||
IAbilityOverride
|
|
||||||
} from "@/src/types/inventoryTypes/commonInventoryTypes";
|
|
||||||
import { IInventoryClient, IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
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 { addMiscItems, addRecipes, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
||||||
@ -13,6 +8,8 @@ import { getRecipeByResult } from "@/src/services/itemDataService";
|
|||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { addInfestedFoundryXP, applyCheatsToInfestedFoundry } from "@/src/services/infestedFoundryService";
|
import { addInfestedFoundryXP, applyCheatsToInfestedFoundry } from "@/src/services/infestedFoundryService";
|
||||||
import { config } from "@/src/services/configService";
|
import { config } from "@/src/services/configService";
|
||||||
|
import { sendWsBroadcastTo } from "@/src/services/wsService";
|
||||||
|
import { EquipmentFeatures, IEquipmentDatabase } from "@/src/types/equipmentTypes";
|
||||||
|
|
||||||
export const upgradesController: RequestHandler = async (req, res) => {
|
export const upgradesController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -120,6 +117,7 @@ export const upgradesController: RequestHandler = async (req, res) => {
|
|||||||
setSlotPolarity(item, operation.PolarizeSlot, operation.PolarizeValue);
|
setSlotPolarity(item, operation.PolarizeSlot, operation.PolarizeValue);
|
||||||
item.Polarized ??= 0;
|
item.Polarized ??= 0;
|
||||||
item.Polarized += 1;
|
item.Polarized += 1;
|
||||||
|
sendWsBroadcastTo(accountId, { update_inventory: true }); // webui may need to to re-add "max rank" button
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "/Lotus/Types/Items/MiscItems/ModSlotUnlocker": {
|
case "/Lotus/Types/Items/MiscItems/ModSlotUnlocker": {
|
||||||
|
33
src/controllers/custom/abilityOverrideController.ts
Normal file
33
src/controllers/custom/abilityOverrideController.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
export const abilityOverrideController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const request = req.body as IAbilityOverrideRequest;
|
||||||
|
if (request.category === "Suits") {
|
||||||
|
const inventory = await getInventory(accountId, request.category);
|
||||||
|
const item = inventory[request.category].id(request.oid);
|
||||||
|
if (item) {
|
||||||
|
if (request.action == "set") {
|
||||||
|
item.Configs[request.configIndex].AbilityOverride = request.AbilityOverride;
|
||||||
|
} else {
|
||||||
|
item.Configs[request.configIndex].AbilityOverride = undefined;
|
||||||
|
}
|
||||||
|
await inventory.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IAbilityOverrideRequest {
|
||||||
|
category: TEquipmentKey;
|
||||||
|
oid: string;
|
||||||
|
action: "set" | "remove";
|
||||||
|
configIndex: number;
|
||||||
|
AbilityOverride: {
|
||||||
|
Ability: string;
|
||||||
|
Index: number;
|
||||||
|
};
|
||||||
|
}
|
@ -7,7 +7,7 @@ export const addItemsController: RequestHandler = async (req, res) => {
|
|||||||
const requests = req.body as IAddItemRequest[];
|
const requests = req.body as IAddItemRequest[];
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
for (const request of requests) {
|
for (const request of requests) {
|
||||||
await addItem(inventory, request.ItemType, request.ItemCount, true, undefined, undefined, true);
|
await addItem(inventory, request.ItemType, request.ItemCount, true, undefined, request.Fingerprint, true);
|
||||||
}
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.end();
|
res.end();
|
||||||
@ -16,4 +16,5 @@ export const addItemsController: RequestHandler = async (req, res) => {
|
|||||||
interface IAddItemRequest {
|
interface IAddItemRequest {
|
||||||
ItemType: string;
|
ItemType: string;
|
||||||
ItemCount: number;
|
ItemCount: number;
|
||||||
|
Fingerprint?: string;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { getInventory, addRecipes } from "@/src/services/inventoryService";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { ExportRecipes } from "warframe-public-export-plus";
|
||||||
|
|
||||||
|
export const addMissingHelminthBlueprintsController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId, "Recipes");
|
||||||
|
const allHelminthRecipes = Object.keys(ExportRecipes).filter(
|
||||||
|
key => ExportRecipes[key].secretIngredientAction === "SIA_WARFRAME_ABILITY"
|
||||||
|
);
|
||||||
|
const inventoryHelminthRecipes = inventory.Recipes.filter(recipe =>
|
||||||
|
recipe.ItemType.startsWith("/Lotus/Types/Recipes/AbilityOverrides/")
|
||||||
|
).map(recipe => recipe.ItemType);
|
||||||
|
|
||||||
|
const missingHelminthRecipes = allHelminthRecipes
|
||||||
|
.filter(key => !inventoryHelminthRecipes.includes(key))
|
||||||
|
.map(ItemType => ({ ItemType, ItemCount: 1 }));
|
||||||
|
|
||||||
|
addRecipes(inventory, missingHelminthRecipes);
|
||||||
|
|
||||||
|
await inventory.save();
|
||||||
|
res.end();
|
||||||
|
};
|
@ -1,7 +1,7 @@
|
|||||||
import { applyClientEquipmentUpdates, getInventory } from "@/src/services/inventoryService";
|
import { applyClientEquipmentUpdates, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IOid } from "@/src/types/commonTypes";
|
import { IOid } from "@/src/types/commonTypes";
|
||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IEquipmentClient } from "@/src/types/equipmentTypes";
|
||||||
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { ExportMisc } from "warframe-public-export-plus";
|
import { ExportMisc } from "warframe-public-export-plus";
|
||||||
|
65
src/controllers/custom/changeModularPartsController.ts
Normal file
65
src/controllers/custom/changeModularPartsController.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
export const changeModularPartsController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const request = req.body as IUpdateFingerPrintRequest;
|
||||||
|
const inventory = await getInventory(accountId, request.category);
|
||||||
|
const item = inventory[request.category].id(request.oid);
|
||||||
|
if (item) {
|
||||||
|
item.ModularParts = request.modularParts;
|
||||||
|
|
||||||
|
request.modularParts.forEach(part => {
|
||||||
|
const categoryMap = mapping[part];
|
||||||
|
if (categoryMap && categoryMap[request.category]) {
|
||||||
|
item.ItemType = categoryMap[request.category]!;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await inventory.save();
|
||||||
|
}
|
||||||
|
res.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IUpdateFingerPrintRequest {
|
||||||
|
category: TEquipmentKey;
|
||||||
|
oid: string;
|
||||||
|
modularParts: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapping: Partial<Record<string, Partial<Record<TEquipmentKey, string>>>> = {
|
||||||
|
"/Lotus/Weapons/SolarisUnited/Secondary/SUModularSecondarySet1/Barrel/SUModularSecondaryBarrelAPart": {
|
||||||
|
LongGuns: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryShotgun",
|
||||||
|
Pistols: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryShotgun"
|
||||||
|
},
|
||||||
|
"/Lotus/Weapons/Infested/Pistols/InfKitGun/Barrels/InfBarrelEgg/InfModularBarrelEggPart": {
|
||||||
|
LongGuns: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryShotgun",
|
||||||
|
Pistols: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryShotgun"
|
||||||
|
},
|
||||||
|
"/Lotus/Weapons/SolarisUnited/Secondary/SUModularSecondarySet1/Barrel/SUModularSecondaryBarrelBPart": {
|
||||||
|
LongGuns: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimary",
|
||||||
|
Pistols: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary"
|
||||||
|
},
|
||||||
|
"/Lotus/Weapons/SolarisUnited/Secondary/SUModularSecondarySet1/Barrel/SUModularSecondaryBarrelCPart": {
|
||||||
|
LongGuns: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimary",
|
||||||
|
Pistols: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary"
|
||||||
|
},
|
||||||
|
"/Lotus/Weapons/SolarisUnited/Secondary/SUModularSecondarySet1/Barrel/SUModularSecondaryBarrelDPart": {
|
||||||
|
LongGuns: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryBeam",
|
||||||
|
Pistols: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryBeam"
|
||||||
|
},
|
||||||
|
"/Lotus/Weapons/Infested/Pistols/InfKitGun/Barrels/InfBarrelBeam/InfModularBarrelBeamPart": {
|
||||||
|
LongGuns: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryBeam",
|
||||||
|
Pistols: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryBeam"
|
||||||
|
},
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadA": {
|
||||||
|
MoaPets: "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetAPowerSuit"
|
||||||
|
},
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadB": {
|
||||||
|
MoaPets: "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetBPowerSuit"
|
||||||
|
},
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadC": {
|
||||||
|
MoaPets: "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetCPowerSuit"
|
||||||
|
}
|
||||||
|
};
|
@ -12,18 +12,24 @@ export const completeAllMissionsController: RequestHandler = async (req, res) =>
|
|||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
const MissionRewards: IMissionReward[] = [];
|
const MissionRewards: IMissionReward[] = [];
|
||||||
for (const [tag, node] of Object.entries(ExportRegions)) {
|
for (const [tag, node] of Object.entries(ExportRegions)) {
|
||||||
if (!inventory.Missions.find(x => x.Tag == tag)) {
|
let mission = inventory.Missions.find(x => x.Tag == tag);
|
||||||
inventory.Missions.push({
|
if (!mission) {
|
||||||
Completes: 1,
|
mission =
|
||||||
Tier: 1,
|
inventory.Missions[
|
||||||
Tag: tag
|
inventory.Missions.push({
|
||||||
});
|
Completes: 0,
|
||||||
|
Tier: 0,
|
||||||
|
Tag: tag
|
||||||
|
}) - 1
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (mission.Completes == 0) {
|
||||||
|
mission.Completes++;
|
||||||
if (node.missionReward) {
|
if (node.missionReward) {
|
||||||
console.log(node.missionReward);
|
addFixedLevelRewards(node.missionReward, MissionRewards);
|
||||||
addFixedLevelRewards(node.missionReward, inventory, MissionRewards);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mission.Tier = 1;
|
||||||
}
|
}
|
||||||
for (const reward of MissionRewards) {
|
for (const reward of MissionRewards) {
|
||||||
await handleStoreItemAcquisition(reward.StoreItem, inventory, reward.ItemCount, undefined, true);
|
await handleStoreItemAcquisition(reward.StoreItem, inventory, reward.ItemCount, undefined, true);
|
||||||
|
47
src/controllers/custom/configController.ts
Normal file
47
src/controllers/custom/configController.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { config, syncConfigWithDatabase } from "@/src/services/configService";
|
||||||
|
import { getAccountForRequest, isAdministrator } from "@/src/services/loginService";
|
||||||
|
import { saveConfig } from "@/src/services/configWriterService";
|
||||||
|
import { sendWsBroadcastEx } from "@/src/services/wsService";
|
||||||
|
|
||||||
|
export const getConfigController: RequestHandler = async (req, res) => {
|
||||||
|
const account = await getAccountForRequest(req);
|
||||||
|
if (isAdministrator(account)) {
|
||||||
|
const responseData: Record<string, boolean | string | number | null> = {};
|
||||||
|
for (const id of req.body as string[]) {
|
||||||
|
const [obj, idx] = configIdToIndexable(id);
|
||||||
|
responseData[id] = obj[idx] ?? null;
|
||||||
|
}
|
||||||
|
res.json(responseData);
|
||||||
|
} else {
|
||||||
|
res.status(401).end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setConfigController: RequestHandler = async (req, res) => {
|
||||||
|
const account = await getAccountForRequest(req);
|
||||||
|
if (isAdministrator(account)) {
|
||||||
|
for (const [id, value] of Object.entries(req.body as Record<string, boolean | string | number>)) {
|
||||||
|
const [obj, idx] = configIdToIndexable(id);
|
||||||
|
obj[idx] = value;
|
||||||
|
}
|
||||||
|
sendWsBroadcastEx({ config_reloaded: true }, undefined, parseInt(String(req.query.wsid)));
|
||||||
|
syncConfigWithDatabase();
|
||||||
|
await saveConfig();
|
||||||
|
res.end();
|
||||||
|
} else {
|
||||||
|
res.status(401).end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const configIdToIndexable = (id: string): [Record<string, boolean | string | number | undefined>, string] => {
|
||||||
|
let obj = config as unknown as Record<string, never>;
|
||||||
|
const arr = id.split(".");
|
||||||
|
while (arr.length > 1) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
|
obj[arr[0]] ??= {} as never;
|
||||||
|
obj = obj[arr[0]];
|
||||||
|
arr.splice(0, 1);
|
||||||
|
}
|
||||||
|
return [obj, arr[0]];
|
||||||
|
};
|
@ -11,6 +11,7 @@ import { GuildMember } from "@/src/models/guildModel";
|
|||||||
import { Leaderboard } from "@/src/models/leaderboardModel";
|
import { Leaderboard } from "@/src/models/leaderboardModel";
|
||||||
import { deleteGuild } from "@/src/services/guildService";
|
import { deleteGuild } from "@/src/services/guildService";
|
||||||
import { Friendship } from "@/src/models/friendModel";
|
import { Friendship } from "@/src/models/friendModel";
|
||||||
|
import { sendWsBroadcastTo } from "@/src/services/wsService";
|
||||||
|
|
||||||
export const deleteAccountController: RequestHandler = async (req, res) => {
|
export const deleteAccountController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -36,5 +37,8 @@ export const deleteAccountController: RequestHandler = async (req, res) => {
|
|||||||
Ship.deleteMany({ ShipOwnerId: accountId }),
|
Ship.deleteMany({ ShipOwnerId: accountId }),
|
||||||
Stats.deleteOne({ accountOwnerId: accountId })
|
Stats.deleteOne({ accountOwnerId: accountId })
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
sendWsBroadcastTo(accountId, { logged_out: true });
|
||||||
|
|
||||||
res.end();
|
res.end();
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
const DEFAULT_UPGRADE_EXPIRY_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
||||||
|
|
||||||
|
export const editSuitInvigorationUpgradeController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const { oid, data } = req.body as {
|
||||||
|
oid: string;
|
||||||
|
data?: {
|
||||||
|
DefensiveUpgrade: string;
|
||||||
|
OffensiveUpgrade: string;
|
||||||
|
UpgradesExpiry?: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
const inventory = await getInventory(accountId);
|
||||||
|
const suit = inventory.Suits.id(oid)!;
|
||||||
|
if (data) {
|
||||||
|
suit.DefensiveUpgrade = data.DefensiveUpgrade;
|
||||||
|
suit.OffensiveUpgrade = data.OffensiveUpgrade;
|
||||||
|
if (data.UpgradesExpiry) {
|
||||||
|
suit.UpgradesExpiry = new Date(data.UpgradesExpiry);
|
||||||
|
} else {
|
||||||
|
suit.UpgradesExpiry = new Date(Date.now() + DEFAULT_UPGRADE_EXPIRY_MS);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
suit.DefensiveUpgrade = undefined;
|
||||||
|
suit.OffensiveUpgrade = undefined;
|
||||||
|
suit.UpgradesExpiry = undefined;
|
||||||
|
}
|
||||||
|
await inventory.save();
|
||||||
|
res.end();
|
||||||
|
};
|
@ -1,14 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { config } from "@/src/services/configService";
|
|
||||||
import { getAccountForRequest, isAdministrator } from "@/src/services/loginService";
|
|
||||||
|
|
||||||
const getConfigDataController: RequestHandler = async (req, res) => {
|
|
||||||
const account = await getAccountForRequest(req);
|
|
||||||
if (isAdministrator(account)) {
|
|
||||||
res.json(config);
|
|
||||||
} else {
|
|
||||||
res.status(401).end();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export { getConfigDataController };
|
|
@ -1,6 +1,7 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getDict, getItemName, getString } from "@/src/services/itemDataService";
|
import { getDict, getItemName, getString } from "@/src/services/itemDataService";
|
||||||
import {
|
import {
|
||||||
|
ExportAbilities,
|
||||||
ExportArcanes,
|
ExportArcanes,
|
||||||
ExportAvionics,
|
ExportAvionics,
|
||||||
ExportBoosters,
|
ExportBoosters,
|
||||||
@ -21,6 +22,7 @@ import {
|
|||||||
TRelicQuality
|
TRelicQuality
|
||||||
} from "warframe-public-export-plus";
|
} from "warframe-public-export-plus";
|
||||||
import allIncarnons from "@/static/fixed_responses/allIncarnonList.json";
|
import allIncarnons from "@/static/fixed_responses/allIncarnonList.json";
|
||||||
|
import varzia from "@/static/fixed_responses/worldState/varzia.json";
|
||||||
|
|
||||||
interface ListedItem {
|
interface ListedItem {
|
||||||
uniqueName: string;
|
uniqueName: string;
|
||||||
@ -55,6 +57,9 @@ interface ItemLists {
|
|||||||
EvolutionProgress: ListedItem[];
|
EvolutionProgress: ListedItem[];
|
||||||
mods: ListedItem[];
|
mods: ListedItem[];
|
||||||
Boosters: ListedItem[];
|
Boosters: ListedItem[];
|
||||||
|
VarziaOffers: ListedItem[];
|
||||||
|
Abilities: ListedItem[];
|
||||||
|
//circuitGameModes: ListedItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const relicQualitySuffixes: Record<TRelicQuality, string> = {
|
const relicQualitySuffixes: Record<TRelicQuality, string> = {
|
||||||
@ -64,6 +69,10 @@ const relicQualitySuffixes: Record<TRelicQuality, string> = {
|
|||||||
VPQ_PLATINUM: " [Exceptional]"
|
VPQ_PLATINUM: " [Exceptional]"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*const toTitleCase = (str: string): string => {
|
||||||
|
return str.replace(/[^\s-]+/g, word => word.charAt(0).toUpperCase() + word.substr(1).toLowerCase());
|
||||||
|
};*/
|
||||||
|
|
||||||
const getItemListsController: RequestHandler = (req, response) => {
|
const getItemListsController: RequestHandler = (req, response) => {
|
||||||
const lang = getDict(typeof req.query.lang == "string" ? req.query.lang : "en");
|
const lang = getDict(typeof req.query.lang == "string" ? req.query.lang : "en");
|
||||||
const res: ItemLists = {
|
const res: ItemLists = {
|
||||||
@ -86,7 +95,39 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
KubrowPets: [],
|
KubrowPets: [],
|
||||||
EvolutionProgress: [],
|
EvolutionProgress: [],
|
||||||
mods: [],
|
mods: [],
|
||||||
Boosters: []
|
Boosters: [],
|
||||||
|
VarziaOffers: [],
|
||||||
|
Abilities: []
|
||||||
|
/*circuitGameModes: [
|
||||||
|
{
|
||||||
|
uniqueName: "Survival",
|
||||||
|
name: toTitleCase(getString("/Lotus/Language/Missions/MissionName_Survival", lang))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uniqueName: "VoidFlood",
|
||||||
|
name: toTitleCase(getString("/Lotus/Language/Missions/MissionName_Corruption", lang))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uniqueName: "Excavation",
|
||||||
|
name: toTitleCase(getString("/Lotus/Language/Missions/MissionName_Excavation", lang))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uniqueName: "Defense",
|
||||||
|
name: toTitleCase(getString("/Lotus/Language/Missions/MissionName_Defense", lang))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uniqueName: "Exterminate",
|
||||||
|
name: toTitleCase(getString("/Lotus/Language/Missions/MissionName_Exterminate", lang))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uniqueName: "Assassination",
|
||||||
|
name: toTitleCase(getString("/Lotus/Language/Missions/MissionName_Assassination", lang))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uniqueName: "Alchemy",
|
||||||
|
name: toTitleCase(getString("/Lotus/Language/Missions/MissionName_Alchemy", lang))
|
||||||
|
}
|
||||||
|
]*/
|
||||||
};
|
};
|
||||||
for (const [uniqueName, item] of Object.entries(ExportWarframes)) {
|
for (const [uniqueName, item] of Object.entries(ExportWarframes)) {
|
||||||
res[item.productCategory].push({
|
res[item.productCategory].push({
|
||||||
@ -94,6 +135,12 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
name: getString(item.name, lang),
|
name: getString(item.name, lang),
|
||||||
exalted: item.exalted
|
exalted: item.exalted
|
||||||
});
|
});
|
||||||
|
item.abilities.forEach(ability => {
|
||||||
|
res.Abilities.push({
|
||||||
|
uniqueName: ability.uniqueName,
|
||||||
|
name: getString(ability.name || uniqueName, lang)
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
for (const [uniqueName, item] of Object.entries(ExportSentinels)) {
|
for (const [uniqueName, item] of Object.entries(ExportSentinels)) {
|
||||||
if (item.productCategory == "Sentinels" || item.productCategory == "KubrowPets") {
|
if (item.productCategory == "Sentinels" || item.productCategory == "KubrowPets") {
|
||||||
@ -106,18 +153,21 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
}
|
}
|
||||||
for (const [uniqueName, item] of Object.entries(ExportWeapons)) {
|
for (const [uniqueName, item] of Object.entries(ExportWeapons)) {
|
||||||
if (item.partType) {
|
if (item.partType) {
|
||||||
if (!uniqueName.startsWith("/Lotus/Types/Items/Deimos/")) {
|
if (!uniqueName.split("/")[7]?.startsWith("PvPVariant")) {
|
||||||
res.ModularParts.push({
|
// not a pvp variant
|
||||||
uniqueName,
|
if (!uniqueName.startsWith("/Lotus/Types/Items/Deimos/")) {
|
||||||
name: getString(item.name, lang),
|
res.ModularParts.push({
|
||||||
partType: item.partType
|
uniqueName,
|
||||||
});
|
name: getString(item.name, lang),
|
||||||
}
|
partType: item.partType
|
||||||
if (uniqueName.split("/")[5] != "SentTrainingAmplifier") {
|
});
|
||||||
res.miscitems.push({
|
}
|
||||||
uniqueName: uniqueName,
|
if (uniqueName.split("/")[5] != "SentTrainingAmplifier") {
|
||||||
name: getString(item.name, lang)
|
res.miscitems.push({
|
||||||
});
|
uniqueName: uniqueName,
|
||||||
|
name: getString(item.name, lang)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (item.totalDamage !== 0) {
|
} else if (item.totalDamage !== 0) {
|
||||||
if (
|
if (
|
||||||
@ -303,6 +353,20 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const item of Object.values(varzia.primeDualPacks)) {
|
||||||
|
res.VarziaOffers.push({
|
||||||
|
uniqueName: item.ItemType,
|
||||||
|
name: getString(getItemName(item.ItemType) || "", lang)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [uniqueName, ability] of Object.entries(ExportAbilities)) {
|
||||||
|
res.Abilities.push({
|
||||||
|
uniqueName,
|
||||||
|
name: getString(ability.name || uniqueName, lang)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
response.json(res);
|
response.json(res);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountForRequest, isAdministrator, isNameTaken } from "@/src/services/loginService";
|
import { getAccountForRequest, isAdministrator, isNameTaken } from "@/src/services/loginService";
|
||||||
import { config } from "@/src/services/configService";
|
import { config } from "@/src/services/configService";
|
||||||
import { saveConfig } from "@/src/services/configWatcherService";
|
import { saveConfig } from "@/src/services/configWriterService";
|
||||||
|
|
||||||
export const renameAccountController: RequestHandler = async (req, res) => {
|
export const renameAccountController: RequestHandler = async (req, res) => {
|
||||||
const account = await getAccountForRequest(req);
|
const account = await getAccountForRequest(req);
|
||||||
|
@ -23,9 +23,9 @@ export const setBoosterController: RequestHandler = async (req, res) => {
|
|||||||
res.status(400).send("Invalid ItemType provided.");
|
res.status(400).send("Invalid ItemType provided.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const now = Math.floor(Date.now() / 1000);
|
const now = Math.trunc(Date.now() / 1000);
|
||||||
for (const { ItemType, ExpiryDate } of requests) {
|
for (const { ItemType, ExpiryDate } of requests) {
|
||||||
if (ExpiryDate < now) {
|
if (ExpiryDate <= now) {
|
||||||
// remove expired boosters
|
// remove expired boosters
|
||||||
const index = boosters.findIndex(item => item.ItemType === ItemType);
|
const index = boosters.findIndex(item => item.ItemType === ItemType);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
import { RequestHandler } from "express";
|
|
||||||
import { saveConfig } from "@/src/services/configWatcherService";
|
|
||||||
import { getAccountForRequest, isAdministrator } from "@/src/services/loginService";
|
|
||||||
import { config, IConfig } from "@/src/services/configService";
|
|
||||||
|
|
||||||
export const updateConfigDataController: RequestHandler = async (req, res) => {
|
|
||||||
const account = await getAccountForRequest(req);
|
|
||||||
if (isAdministrator(account)) {
|
|
||||||
const data = req.body as IUpdateConfigDataRequest;
|
|
||||||
config[data.key] = data.value;
|
|
||||||
await saveConfig();
|
|
||||||
res.end();
|
|
||||||
} else {
|
|
||||||
res.status(401).end();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IUpdateConfigDataRequest {
|
|
||||||
key: keyof IConfig;
|
|
||||||
value: never;
|
|
||||||
}
|
|
39
src/controllers/custom/updateFingerprintController.ts
Normal file
39
src/controllers/custom/updateFingerprintController.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { WeaponTypeInternal } from "@/src/services/itemDataService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
export const updateFingerprintController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const request = req.body as IUpdateFingerPrintRequest;
|
||||||
|
const inventory = await getInventory(accountId, request.category);
|
||||||
|
const item = inventory[request.category].id(request.oid);
|
||||||
|
if (item) {
|
||||||
|
if (request.action == "set" && request.upgradeFingerprint.buffs[0].Tag) {
|
||||||
|
const newUpgradeFingerprint = request.upgradeFingerprint;
|
||||||
|
if (!newUpgradeFingerprint.compact) newUpgradeFingerprint.compact = item.ItemType;
|
||||||
|
|
||||||
|
item.UpgradeType = request.upgradeType;
|
||||||
|
item.UpgradeFingerprint = JSON.stringify(newUpgradeFingerprint);
|
||||||
|
} else if (request.action == "remove") {
|
||||||
|
item.UpgradeFingerprint = undefined;
|
||||||
|
item.UpgradeType = undefined;
|
||||||
|
}
|
||||||
|
await inventory.save();
|
||||||
|
}
|
||||||
|
res.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IUpdateFingerPrintRequest {
|
||||||
|
category: WeaponTypeInternal;
|
||||||
|
oid: string;
|
||||||
|
action: "set" | "remove";
|
||||||
|
upgradeType: string;
|
||||||
|
upgradeFingerprint: {
|
||||||
|
compact?: string;
|
||||||
|
buffs: {
|
||||||
|
Tag: string;
|
||||||
|
Value: number;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import { args } from "@/src/helpers/commandLineArguments";
|
import { args } from "@/src/helpers/commandLineArguments";
|
||||||
import { sendWsBroadcast } from "@/src/services/webService";
|
import { sendWsBroadcast } from "@/src/services/wsService";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const webuiFileChangeDetectedController: RequestHandler = (req, res) => {
|
export const webuiFileChangeDetectedController: RequestHandler = (req, res) => {
|
||||||
|
@ -6,13 +6,11 @@ import { Account } from "@/src/models/loginModel";
|
|||||||
import { Stats, TStatsDatabaseDocument } from "@/src/models/statsModel";
|
import { Stats, TStatsDatabaseDocument } from "@/src/models/statsModel";
|
||||||
import { allDailyAffiliationKeys } from "@/src/services/inventoryService";
|
import { allDailyAffiliationKeys } from "@/src/services/inventoryService";
|
||||||
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
|
||||||
import {
|
import {
|
||||||
IAffiliation,
|
IAffiliation,
|
||||||
IAlignment,
|
IAlignment,
|
||||||
IChallengeProgress,
|
IChallengeProgress,
|
||||||
IDailyAffiliations,
|
IDailyAffiliations,
|
||||||
ILoadoutConfigClient,
|
|
||||||
IMission,
|
IMission,
|
||||||
IPlayerSkills,
|
IPlayerSkills,
|
||||||
ITypeXPItem
|
ITypeXPItem
|
||||||
@ -23,6 +21,8 @@ import { ExportCustoms, ExportDojoRecipes } from "warframe-public-export-plus";
|
|||||||
import { IStatsClient } from "@/src/types/statTypes";
|
import { IStatsClient } from "@/src/types/statTypes";
|
||||||
import { toStoreItem } from "@/src/services/itemDataService";
|
import { toStoreItem } from "@/src/services/itemDataService";
|
||||||
import { FlattenMaps } from "mongoose";
|
import { FlattenMaps } from "mongoose";
|
||||||
|
import { IEquipmentClient } from "@/src/types/equipmentTypes";
|
||||||
|
import { ILoadoutConfigClient } from "@/src/types/saveLoadoutTypes";
|
||||||
|
|
||||||
const getProfileViewingDataByPlayerIdImpl = async (playerId: string): Promise<IProfileViewingData | undefined> => {
|
const getProfileViewingDataByPlayerIdImpl = async (playerId: string): Promise<IProfileViewingData | undefined> => {
|
||||||
const account = await Account.findById(playerId, "DisplayName");
|
const account = await Account.findById(playerId, "DisplayName");
|
||||||
@ -141,7 +141,7 @@ export const getProfileViewingDataGetController: RequestHandler = async (req, re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||||
combinedStats[arrayName].push(entry as any);
|
combinedStats[arrayName].push(entry as any);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getWorldState, populateFissures } from "@/src/services/worldStateService";
|
import { getWorldState, populateDailyDeal, populateFissures } from "@/src/services/worldStateService";
|
||||||
import { version_compare } from "@/src/helpers/inventoryHelpers";
|
import { version_compare } from "@/src/helpers/inventoryHelpers";
|
||||||
|
|
||||||
export const worldStateController: RequestHandler = async (req, res) => {
|
export const worldStateController: RequestHandler = async (req, res) => {
|
||||||
const buildLabel = req.query.buildLabel as string | undefined;
|
const buildLabel = req.query.buildLabel as string | undefined;
|
||||||
const worldState = getWorldState(buildLabel);
|
const worldState = getWorldState(buildLabel);
|
||||||
|
|
||||||
|
const populatePromises = [populateDailyDeal(worldState)];
|
||||||
|
|
||||||
// Omitting void fissures for versions prior to Dante Unbound to avoid script errors.
|
// Omitting void fissures for versions prior to Dante Unbound to avoid script errors.
|
||||||
if (!buildLabel || version_compare(buildLabel, "2024.03.24.20.00") >= 0) {
|
if (!buildLabel || version_compare(buildLabel, "2024.03.24.20.00") >= 0) {
|
||||||
await populateFissures(worldState);
|
populatePromises.push(populateFissures(worldState));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await Promise.all(populatePromises);
|
||||||
|
|
||||||
res.json(worldState);
|
res.json(worldState);
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { IAccountCreation } from "@/src/types/customTypes";
|
import { IAccountCreation } from "@/src/types/customTypes";
|
||||||
import { IDatabaseAccountRequiredFields } from "@/src/types/loginTypes";
|
import { IDatabaseAccountRequiredFields } from "@/src/types/loginTypes";
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import { isString, parseEmail, parseString } from "../general";
|
import { isString, parseEmail, parseString } from "@/src/helpers/general";
|
||||||
|
|
||||||
const getWhirlpoolHash = (rawPassword: string): string => {
|
const getWhirlpoolHash = (rawPassword: string): string => {
|
||||||
const whirlpool = crypto.createHash("whirlpool");
|
const whirlpool = crypto.createHash("whirlpool");
|
||||||
|
@ -9,11 +9,11 @@ export const isEmptyObject = (obj: object): boolean => {
|
|||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const isString = (text: unknown): text is string => {
|
export const isString = (text: unknown): text is string => {
|
||||||
return typeof text === "string" || text instanceof String;
|
return typeof text === "string" || text instanceof String;
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseString = (data: unknown): string => {
|
export const parseString = (data: unknown): string => {
|
||||||
if (!isString(data)) {
|
if (!isString(data)) {
|
||||||
throw new Error("data is not a string");
|
throw new Error("data is not a string");
|
||||||
}
|
}
|
||||||
@ -21,11 +21,11 @@ const parseString = (data: unknown): string => {
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
const isNumber = (number: unknown): number is number => {
|
export const isNumber = (number: unknown): number is number => {
|
||||||
return typeof number === "number" && !isNaN(number);
|
return typeof number === "number" && !isNaN(number);
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseNumber = (data: unknown): number => {
|
export const parseNumber = (data: unknown): number => {
|
||||||
if (!isNumber(data)) {
|
if (!isNumber(data)) {
|
||||||
throw new Error("data is not a number");
|
throw new Error("data is not a number");
|
||||||
}
|
}
|
||||||
@ -33,11 +33,11 @@ const parseNumber = (data: unknown): number => {
|
|||||||
return Number(data);
|
return Number(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isDate = (date: string): boolean => {
|
export const isDate = (date: string): boolean => {
|
||||||
return Date.parse(date) != 0;
|
return Date.parse(date) != 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseDateNumber = (date: unknown): string => {
|
export const parseDateNumber = (date: unknown): string => {
|
||||||
if (!isString(date) || !isDate(date)) {
|
if (!isString(date) || !isDate(date)) {
|
||||||
throw new Error("date could not be parsed");
|
throw new Error("date could not be parsed");
|
||||||
}
|
}
|
||||||
@ -45,18 +45,18 @@ const parseDateNumber = (date: unknown): string => {
|
|||||||
return date;
|
return date;
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseEmail = (email: unknown): string => {
|
export const parseEmail = (email: unknown): string => {
|
||||||
if (!isString(email)) {
|
if (!isString(email)) {
|
||||||
throw new Error("incorrect email");
|
throw new Error("incorrect email");
|
||||||
}
|
}
|
||||||
return email;
|
return email;
|
||||||
};
|
};
|
||||||
|
|
||||||
const isBoolean = (booleanCandidate: unknown): booleanCandidate is boolean => {
|
export const isBoolean = (booleanCandidate: unknown): booleanCandidate is boolean => {
|
||||||
return typeof booleanCandidate === "boolean";
|
return typeof booleanCandidate === "boolean";
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseBoolean = (booleanCandidate: unknown): boolean => {
|
export const parseBoolean = (booleanCandidate: unknown): boolean => {
|
||||||
if (!isBoolean(booleanCandidate)) {
|
if (!isBoolean(booleanCandidate)) {
|
||||||
throw new Error("argument was not a boolean");
|
throw new Error("argument was not a boolean");
|
||||||
}
|
}
|
||||||
@ -70,5 +70,3 @@ export const isObject = (objectCandidate: unknown): objectCandidate is Record<st
|
|||||||
!Array.isArray(objectCandidate)
|
!Array.isArray(objectCandidate)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export { isString, isNumber, parseString, parseNumber, parseDateNumber, parseBoolean, parseEmail };
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { IMongoDate, IOid, IOidWithLegacySupport } from "@/src/types/commonTypes";
|
import { IMongoDate, IOid, IOidWithLegacySupport } from "@/src/types/commonTypes";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { TRarity } from "warframe-public-export-plus";
|
import { TRarity } from "warframe-public-export-plus";
|
||||||
|
import { IFusionTreasure } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
|
||||||
export const version_compare = (a: string, b: string): number => {
|
export const version_compare = (a: string, b: string): number => {
|
||||||
const a_digits = a
|
const a_digits = a
|
||||||
@ -51,6 +52,20 @@ export const fromMongoDate = (date: IMongoDate): Date => {
|
|||||||
return new Date(parseInt(date.$date.$numberLong));
|
return new Date(parseInt(date.$date.$numberLong));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const parseFusionTreasure = (name: string, count: number): IFusionTreasure => {
|
||||||
|
const arr = name.split("_");
|
||||||
|
return {
|
||||||
|
ItemType: arr[0],
|
||||||
|
Sockets: parseInt(arr[1], 16),
|
||||||
|
ItemCount: count
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TTraitsPool = Record<
|
||||||
|
"Colors" | "EyeColors" | "FurPatterns" | "BodyTypes" | "Heads" | "Tails",
|
||||||
|
{ type: string; rarity: TRarity }[]
|
||||||
|
>;
|
||||||
|
|
||||||
export const kubrowWeights: Record<TRarity, number> = {
|
export const kubrowWeights: Record<TRarity, number> = {
|
||||||
COMMON: 6,
|
COMMON: 6,
|
||||||
UNCOMMON: 4,
|
UNCOMMON: 4,
|
||||||
@ -65,126 +80,126 @@ export const kubrowFurPatternsWeights: Record<TRarity, number> = {
|
|||||||
LEGENDARY: 1
|
LEGENDARY: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
export const catbrowDetails = {
|
export const catbrowDetails: TTraitsPool = {
|
||||||
Colors: [
|
Colors: [
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseA", rarity: "COMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseA", rarity: "COMMON" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseB", rarity: "COMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseB", rarity: "COMMON" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseC", rarity: "COMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseC", rarity: "COMMON" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseD", rarity: "COMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseD", rarity: "COMMON" },
|
||||||
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryA", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryA", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryB", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryB", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryC", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryC", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryD", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryD", rarity: "UNCOMMON" },
|
||||||
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryA", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryA", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryB", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryB", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryC", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryC", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryD", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryD", rarity: "RARE" },
|
||||||
|
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsA", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsA", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsB", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsB", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsC", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsC", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsD", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsD", rarity: "LEGENDARY" }
|
||||||
],
|
],
|
||||||
|
|
||||||
EyeColors: [
|
EyeColors: [
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesA", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesA", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesB", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesB", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesC", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesC", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesD", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesD", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesE", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesE", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesF", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesF", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesG", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesG", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesH", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesH", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesI", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesI", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesJ", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesJ", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesK", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesK", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesL", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesL", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesM", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesM", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesN", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesN", rarity: "LEGENDARY" }
|
||||||
],
|
],
|
||||||
|
|
||||||
FurPatterns: [{ type: "/Lotus/Types/Game/CatbrowPet/Patterns/CatbrowPetPatternA", rarity: "COMMON" as TRarity }],
|
FurPatterns: [{ type: "/Lotus/Types/Game/CatbrowPet/Patterns/CatbrowPetPatternA", rarity: "COMMON" }],
|
||||||
|
|
||||||
BodyTypes: [
|
BodyTypes: [
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetRegularBodyType", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetRegularBodyType", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetRegularBodyType", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetRegularBodyType", rarity: "LEGENDARY" }
|
||||||
],
|
],
|
||||||
|
|
||||||
Heads: [
|
Heads: [
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadA", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadA", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadB", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadB", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadC", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadC", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadD", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadD", rarity: "LEGENDARY" }
|
||||||
],
|
],
|
||||||
|
|
||||||
Tails: [
|
Tails: [
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailA", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailA", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailB", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailB", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailC", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailC", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailD", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailD", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailE", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailE", rarity: "LEGENDARY" }
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
export const kubrowDetails = {
|
export const kubrowDetails: TTraitsPool = {
|
||||||
Colors: [
|
Colors: [
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneA", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneA", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneB", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneB", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneC", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneC", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneD", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneD", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneE", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneE", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneF", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneF", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneG", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneG", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneH", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneH", rarity: "UNCOMMON" },
|
||||||
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidA", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidA", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidB", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidB", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidC", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidC", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidD", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidD", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidE", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidE", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidF", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidF", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidG", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidG", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidH", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidH", rarity: "RARE" },
|
||||||
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantA", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantA", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantB", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantB", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantC", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantC", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantD", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantD", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantE", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantE", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantF", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantF", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantG", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantG", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantH", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantH", rarity: "LEGENDARY" }
|
||||||
],
|
],
|
||||||
|
|
||||||
EyeColors: [
|
EyeColors: [
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesA", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesA", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesB", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesB", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesC", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesC", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesD", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesD", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesE", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesE", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesF", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesF", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesG", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesG", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesH", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesH", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesI", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesI", rarity: "LEGENDARY" }
|
||||||
],
|
],
|
||||||
|
|
||||||
FurPatterns: [
|
FurPatterns: [
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternB", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternB", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternA", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternA", rarity: "UNCOMMON" },
|
||||||
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternC", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternC", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternD", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternD", rarity: "RARE" },
|
||||||
|
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternE", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternE", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternF", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternF", rarity: "LEGENDARY" }
|
||||||
],
|
],
|
||||||
|
|
||||||
BodyTypes: [
|
BodyTypes: [
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetRegularBodyType", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetRegularBodyType", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetHeavyBodyType", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetHeavyBodyType", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetThinBodyType", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetThinBodyType", rarity: "LEGENDARY" }
|
||||||
],
|
],
|
||||||
|
|
||||||
Heads: [],
|
Heads: [],
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { TEquipmentKey } from "../types/inventoryTypes/inventoryTypes";
|
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
|
||||||
export const modularWeaponTypes: Record<string, TEquipmentKey> = {
|
export const modularWeaponTypes: Record<string, TEquipmentKey> = {
|
||||||
"/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimary": "LongGuns",
|
"/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimary": "LongGuns",
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
import { ExportRegions, ExportWarframes } from "warframe-public-export-plus";
|
import { ExportRegions, ExportWarframes } from "warframe-public-export-plus";
|
||||||
import { IInfNode, TNemesisFaction } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IInfNode, TNemesisFaction } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { getRewardAtPercentage, SRng } from "@/src/services/rngService";
|
import { generateRewardSeed, getRewardAtPercentage, SRng } from "@/src/services/rngService";
|
||||||
import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel";
|
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { logger } from "../utils/logger";
|
import { IOid } from "@/src/types/commonTypes";
|
||||||
import { IOid } from "../types/commonTypes";
|
import { isArchwingMission } from "@/src/services/worldStateService";
|
||||||
import { Types } from "mongoose";
|
|
||||||
import { addMods, generateRewardSeed } from "../services/inventoryService";
|
|
||||||
import { isArchwingMission } from "../services/worldStateService";
|
|
||||||
|
|
||||||
type TInnateDamageTag =
|
type TInnateDamageTag =
|
||||||
| "InnateElectricityDamage"
|
| "InnateElectricityDamage"
|
||||||
@ -364,57 +361,6 @@ export const parseUpgrade = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const consumeModCharge = (
|
|
||||||
response: IKnifeResponse,
|
|
||||||
inventory: TInventoryDatabaseDocument,
|
|
||||||
upgrade: { ItemId: IOid; ItemType: string },
|
|
||||||
dataknifeUpgrades: string[]
|
|
||||||
): void => {
|
|
||||||
response.UpgradeIds ??= [];
|
|
||||||
response.UpgradeTypes ??= [];
|
|
||||||
response.UpgradeFingerprints ??= [];
|
|
||||||
response.UpgradeNew ??= [];
|
|
||||||
response.HasKnife = true;
|
|
||||||
|
|
||||||
if (upgrade.ItemId.$oid != "000000000000000000000000") {
|
|
||||||
const dbUpgrade = inventory.Upgrades.id(upgrade.ItemId.$oid)!;
|
|
||||||
const fingerprint = JSON.parse(dbUpgrade.UpgradeFingerprint!) as { lvl: number };
|
|
||||||
fingerprint.lvl += 1;
|
|
||||||
dbUpgrade.UpgradeFingerprint = JSON.stringify(fingerprint);
|
|
||||||
|
|
||||||
response.UpgradeIds.push(upgrade.ItemId.$oid);
|
|
||||||
response.UpgradeTypes.push(upgrade.ItemType);
|
|
||||||
response.UpgradeFingerprints.push(fingerprint);
|
|
||||||
response.UpgradeNew.push(false);
|
|
||||||
} else {
|
|
||||||
const id = new Types.ObjectId();
|
|
||||||
inventory.Upgrades.push({
|
|
||||||
_id: id,
|
|
||||||
ItemType: upgrade.ItemType,
|
|
||||||
UpgradeFingerprint: `{"lvl":1}`
|
|
||||||
});
|
|
||||||
|
|
||||||
addMods(inventory, [
|
|
||||||
{
|
|
||||||
ItemType: upgrade.ItemType,
|
|
||||||
ItemCount: -1
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
const dataknifeRawUpgradeIndex = dataknifeUpgrades.indexOf(upgrade.ItemType);
|
|
||||||
if (dataknifeRawUpgradeIndex != -1) {
|
|
||||||
dataknifeUpgrades[dataknifeRawUpgradeIndex] = id.toString();
|
|
||||||
} else {
|
|
||||||
logger.warn(`${upgrade.ItemType} not found in dataknife config`);
|
|
||||||
}
|
|
||||||
|
|
||||||
response.UpgradeIds.push(id.toString());
|
|
||||||
response.UpgradeTypes.push(upgrade.ItemType);
|
|
||||||
response.UpgradeFingerprints.push({ lvl: 1 });
|
|
||||||
response.UpgradeNew.push(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getInnateDamageTag = (KillingSuit: string): TInnateDamageTag => {
|
export const getInnateDamageTag = (KillingSuit: string): TInnateDamageTag => {
|
||||||
return ExportWarframes[KillingSuit].nemesisUpgradeTag!;
|
return ExportWarframes[KillingSuit].nemesisUpgradeTag!;
|
||||||
};
|
};
|
||||||
|
@ -5,7 +5,8 @@ import { getRandomWeightedReward, IRngResult } from "@/src/services/rngService";
|
|||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { addMiscItems, combineInventoryChanges } from "@/src/services/inventoryService";
|
import { addMiscItems, combineInventoryChanges } from "@/src/services/inventoryService";
|
||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
||||||
import { IInventoryChanges } from "../types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
|
import { config } from "@/src/services/configService";
|
||||||
|
|
||||||
export const crackRelic = async (
|
export const crackRelic = async (
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
@ -13,12 +14,25 @@ export const crackRelic = async (
|
|||||||
inventoryChanges: IInventoryChanges = {}
|
inventoryChanges: IInventoryChanges = {}
|
||||||
): Promise<IRngResult> => {
|
): Promise<IRngResult> => {
|
||||||
const relic = ExportRelics[participant.VoidProjection];
|
const relic = ExportRelics[participant.VoidProjection];
|
||||||
const weights = refinementToWeights[relic.quality];
|
let weights = refinementToWeights[relic.quality];
|
||||||
|
if (relic.quality == "VPQ_SILVER" && config.exceptionalRelicsAlwaysGiveBronzeReward) {
|
||||||
|
weights = { COMMON: 1, UNCOMMON: 0, RARE: 0, LEGENDARY: 0 };
|
||||||
|
} else if (relic.quality == "VPQ_GOLD" && config.flawlessRelicsAlwaysGiveSilverReward) {
|
||||||
|
weights = { COMMON: 0, UNCOMMON: 1, RARE: 0, LEGENDARY: 0 };
|
||||||
|
} else if (relic.quality == "VPQ_PLATINUM" && config.radiantRelicsAlwaysGiveGoldReward) {
|
||||||
|
weights = { COMMON: 0, UNCOMMON: 0, RARE: 1, LEGENDARY: 0 };
|
||||||
|
}
|
||||||
logger.debug(`opening a relic of quality ${relic.quality}; rarity weights are`, weights);
|
logger.debug(`opening a relic of quality ${relic.quality}; rarity weights are`, weights);
|
||||||
const reward = getRandomWeightedReward(
|
let reward = getRandomWeightedReward(
|
||||||
ExportRewards[relic.rewardManifest][0] as { type: string; itemCount: number; rarity: TRarity }[], // rarity is nullable in PE+ typings, but always present for relics
|
ExportRewards[relic.rewardManifest][0] as { type: string; itemCount: number; rarity: TRarity }[], // rarity is nullable in PE+ typings, but always present for relics
|
||||||
weights
|
weights
|
||||||
)!;
|
)!;
|
||||||
|
if (config.relicRewardItemCountMultiplier !== undefined && (config.relicRewardItemCountMultiplier ?? 1) != 1) {
|
||||||
|
reward = {
|
||||||
|
...reward,
|
||||||
|
itemCount: reward.itemCount * config.relicRewardItemCountMultiplier
|
||||||
|
};
|
||||||
|
}
|
||||||
logger.debug(`relic rolled`, reward);
|
logger.debug(`relic rolled`, reward);
|
||||||
participant.Reward = reward.type;
|
participant.Reward = reward.type;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { IUpgrade } from "warframe-public-export-plus";
|
import { IUpgrade } from "warframe-public-export-plus";
|
||||||
import { getRandomElement, getRandomInt, getRandomReward } from "../services/rngService";
|
import { getRandomElement, getRandomInt, getRandomReward } from "@/src/services/rngService";
|
||||||
|
|
||||||
export type RivenFingerprint = IVeiledRivenFingerprint | IUnveiledRivenFingerprint;
|
export type RivenFingerprint = IVeiledRivenFingerprint | IUnveiledRivenFingerprint;
|
||||||
|
|
||||||
|
22
src/index.ts
22
src/index.ts
@ -1,5 +1,5 @@
|
|||||||
// First, init config.
|
// First, init config.
|
||||||
import { config, configPath, loadConfig } from "@/src/services/configService";
|
import { config, configPath, loadConfig, syncConfigWithDatabase } from "@/src/services/configService";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
try {
|
try {
|
||||||
loadConfig();
|
loadConfig();
|
||||||
@ -7,7 +7,7 @@ try {
|
|||||||
if (fs.existsSync("config.json")) {
|
if (fs.existsSync("config.json")) {
|
||||||
console.log("Failed to load " + configPath + ": " + (e as Error).message);
|
console.log("Failed to load " + configPath + ": " + (e as Error).message);
|
||||||
} else {
|
} else {
|
||||||
console.log("Failed to load " + configPath + ". You can copy config.json.example to create your config file.");
|
console.log("Failed to load " + configPath + ". You can copy config-vanilla.json to create your config file.");
|
||||||
}
|
}
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
@ -18,21 +18,29 @@ logger.info("Starting up...");
|
|||||||
|
|
||||||
// Proceed with normal startup: bring up config watcher service, validate config, connect to MongoDB, and finally start listening for HTTP.
|
// Proceed with normal startup: bring up config watcher service, validate config, connect to MongoDB, and finally start listening for HTTP.
|
||||||
import mongoose from "mongoose";
|
import mongoose from "mongoose";
|
||||||
|
import path from "path";
|
||||||
import { JSONStringify } from "json-with-bigint";
|
import { JSONStringify } from "json-with-bigint";
|
||||||
import { startWebServer } from "./services/webService";
|
import { startWebServer } from "@/src/services/webService";
|
||||||
|
|
||||||
import { validateConfig } from "@/src/services/configWatcherService";
|
import { validateConfig } from "@/src/services/configWatcherService";
|
||||||
import { updateWorldStateCollections } from "./services/worldStateService";
|
import { updateWorldStateCollections } from "@/src/services/worldStateService";
|
||||||
|
import { repoDir } from "@/src/helpers/pathHelper";
|
||||||
|
|
||||||
// Patch JSON.stringify to work flawlessly with Bigints.
|
JSON.stringify = JSONStringify; // Patch JSON.stringify to work flawlessly with Bigints.
|
||||||
JSON.stringify = JSONStringify;
|
|
||||||
|
|
||||||
validateConfig();
|
validateConfig();
|
||||||
|
|
||||||
|
fs.readFile(path.join(repoDir, "BUILD_DATE"), "utf-8", (err, data) => {
|
||||||
|
if (!err) {
|
||||||
|
logger.info(`Docker image was built on ${data.trim()}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
mongoose
|
mongoose
|
||||||
.connect(config.mongodbUrl)
|
.connect(config.mongodbUrl)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.info("Connected to MongoDB");
|
logger.info("Connected to MongoDB");
|
||||||
|
syncConfigWithDatabase();
|
||||||
|
|
||||||
startWebServer();
|
startWebServer();
|
||||||
|
|
||||||
void updateWorldStateCollections();
|
void updateWorldStateCollections();
|
||||||
|
@ -1,16 +1,11 @@
|
|||||||
import { NextFunction, Request, Response } from "express";
|
import { NextFunction, Request, Response } from "express";
|
||||||
import { logger } from "../utils/logger";
|
import { logError } from "@/src/utils/logger";
|
||||||
|
|
||||||
export const errorHandler = (err: Error, req: Request, res: Response, _next: NextFunction): void => {
|
export const errorHandler = (err: Error, req: Request, res: Response, _next: NextFunction): void => {
|
||||||
if (err.message == "Invalid accountId-nonce pair") {
|
if (err.message == "Invalid accountId-nonce pair") {
|
||||||
res.status(400).send("Log-in expired");
|
res.status(400).send("Log-in expired");
|
||||||
} else if (err.stack) {
|
|
||||||
const stackArr = err.stack.split("\n");
|
|
||||||
stackArr[0] += ` while processing ${req.path} request`;
|
|
||||||
logger.error(stackArr.join("\n"));
|
|
||||||
res.status(500).end();
|
|
||||||
} else {
|
} else {
|
||||||
logger.error(`uncaught error while processing ${req.path} request: ${err.message}`);
|
logError(err, `processing ${req.path} request`);
|
||||||
res.status(500).end();
|
res.status(500).end();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
25
src/models/commonModel.ts
Normal file
25
src/models/commonModel.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { Schema } from "mongoose";
|
||||||
|
import { IColor, IShipCustomization } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
|
|
||||||
|
export const colorSchema = new Schema<IColor>(
|
||||||
|
{
|
||||||
|
t0: Number,
|
||||||
|
t1: Number,
|
||||||
|
t2: Number,
|
||||||
|
t3: Number,
|
||||||
|
en: Number,
|
||||||
|
e1: Number,
|
||||||
|
m0: Number,
|
||||||
|
m1: Number
|
||||||
|
},
|
||||||
|
{ _id: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
export const shipCustomizationSchema = new Schema<IShipCustomization>(
|
||||||
|
{
|
||||||
|
SkinFlavourItem: String,
|
||||||
|
Colors: colorSchema,
|
||||||
|
ShipAttachments: { HOOD_ORNAMENT: String }
|
||||||
|
},
|
||||||
|
{ _id: false }
|
||||||
|
);
|
@ -17,8 +17,8 @@ import {
|
|||||||
GuildPermission
|
GuildPermission
|
||||||
} from "@/src/types/guildTypes";
|
} from "@/src/types/guildTypes";
|
||||||
import { Document, Model, model, Schema, Types } from "mongoose";
|
import { Document, Model, model, Schema, Types } from "mongoose";
|
||||||
import { fusionTreasuresSchema, typeCountSchema } from "./inventoryModels/inventoryModel";
|
import { fusionTreasuresSchema, typeCountSchema } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { pictureFrameInfoSchema } from "./personalRoomsModel";
|
import { pictureFrameInfoSchema } from "@/src/models/personalRoomsModel";
|
||||||
|
|
||||||
const dojoDecoSchema = new Schema<IDojoDecoDatabase>({
|
const dojoDecoSchema = new Schema<IDojoDecoDatabase>({
|
||||||
Type: String,
|
Type: String,
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import { model, Schema, Types } from "mongoose";
|
import { model, Schema, Types } from "mongoose";
|
||||||
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
|
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
import { typeCountSchema } from "@/src/models/inventoryModels/inventoryModel";
|
import { typeCountSchema } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
import { IMongoDate, IOid, ITypeCount } from "@/src/types/commonTypes";
|
||||||
import { ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
|
|
||||||
export interface IMessageClient
|
export interface IMessageClient
|
||||||
extends Omit<IMessageDatabase, "_id" | "date" | "startDate" | "endDate" | "ownerId" | "attVisualOnly" | "expiry"> {
|
extends Omit<
|
||||||
|
IMessageDatabase,
|
||||||
|
"_id" | "globaUpgradeId" | "date" | "startDate" | "endDate" | "ownerId" | "attVisualOnly" | "expiry"
|
||||||
|
> {
|
||||||
_id?: IOid;
|
_id?: IOid;
|
||||||
|
globaUpgradeId?: IOid; // [sic]
|
||||||
date: IMongoDate;
|
date: IMongoDate;
|
||||||
startDate?: IMongoDate;
|
startDate?: IMongoDate;
|
||||||
endDate?: IMongoDate;
|
endDate?: IMongoDate;
|
||||||
@ -15,6 +18,7 @@ export interface IMessageClient
|
|||||||
|
|
||||||
export interface IMessageDatabase extends IMessage {
|
export interface IMessageDatabase extends IMessage {
|
||||||
ownerId: Types.ObjectId;
|
ownerId: Types.ObjectId;
|
||||||
|
globaUpgradeId?: Types.ObjectId; // [sic]
|
||||||
date: Date; //created at
|
date: Date; //created at
|
||||||
attVisualOnly?: boolean;
|
attVisualOnly?: boolean;
|
||||||
_id: Types.ObjectId;
|
_id: Types.ObjectId;
|
||||||
@ -23,15 +27,18 @@ export interface IMessageDatabase extends IMessage {
|
|||||||
export interface IMessage {
|
export interface IMessage {
|
||||||
sndr: string;
|
sndr: string;
|
||||||
msg: string;
|
msg: string;
|
||||||
|
cinematic?: string;
|
||||||
sub: string;
|
sub: string;
|
||||||
|
customData?: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
highPriority?: boolean;
|
highPriority?: boolean;
|
||||||
lowPrioNewPlayers?: boolean;
|
lowPrioNewPlayers?: boolean;
|
||||||
startDate?: Date;
|
transmission?: string;
|
||||||
endDate?: Date;
|
|
||||||
att?: string[];
|
att?: string[];
|
||||||
countedAtt?: ITypeCount[];
|
countedAtt?: ITypeCount[];
|
||||||
transmission?: string;
|
startDate?: Date;
|
||||||
|
endDate?: Date;
|
||||||
|
goalTag?: string;
|
||||||
CrossPlatform?: boolean;
|
CrossPlatform?: boolean;
|
||||||
arg?: Arg[];
|
arg?: Arg[];
|
||||||
gifts?: IGift[];
|
gifts?: IGift[];
|
||||||
@ -40,6 +47,7 @@ export interface IMessage {
|
|||||||
acceptAction?: string;
|
acceptAction?: string;
|
||||||
declineAction?: string;
|
declineAction?: string;
|
||||||
hasAccountAction?: boolean;
|
hasAccountAction?: boolean;
|
||||||
|
RegularCredits?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Arg {
|
export interface Arg {
|
||||||
@ -99,14 +107,18 @@ const giftSchema = new Schema<IGift>(
|
|||||||
const messageSchema = new Schema<IMessageDatabase>(
|
const messageSchema = new Schema<IMessageDatabase>(
|
||||||
{
|
{
|
||||||
ownerId: Schema.Types.ObjectId,
|
ownerId: Schema.Types.ObjectId,
|
||||||
|
globaUpgradeId: Schema.Types.ObjectId,
|
||||||
sndr: String,
|
sndr: String,
|
||||||
msg: String,
|
msg: String,
|
||||||
|
cinematic: String,
|
||||||
sub: String,
|
sub: String,
|
||||||
|
customData: String,
|
||||||
icon: String,
|
icon: String,
|
||||||
highPriority: Boolean,
|
highPriority: Boolean,
|
||||||
lowPrioNewPlayers: Boolean,
|
lowPrioNewPlayers: Boolean,
|
||||||
startDate: Date,
|
startDate: Date,
|
||||||
endDate: Date,
|
endDate: Date,
|
||||||
|
goalTag: String,
|
||||||
date: { type: Date, required: true },
|
date: { type: Date, required: true },
|
||||||
r: Boolean,
|
r: Boolean,
|
||||||
CrossPlatform: Boolean,
|
CrossPlatform: Boolean,
|
||||||
@ -128,7 +140,8 @@ const messageSchema = new Schema<IMessageDatabase>(
|
|||||||
contextInfo: String,
|
contextInfo: String,
|
||||||
acceptAction: String,
|
acceptAction: String,
|
||||||
declineAction: String,
|
declineAction: String,
|
||||||
hasAccountAction: Boolean
|
hasAccountAction: Boolean,
|
||||||
|
RegularCredits: Number
|
||||||
},
|
},
|
||||||
{ id: false }
|
{ id: false }
|
||||||
);
|
);
|
||||||
@ -139,7 +152,7 @@ messageSchema.virtual("messageId").get(function (this: IMessageDatabase) {
|
|||||||
|
|
||||||
messageSchema.set("toJSON", {
|
messageSchema.set("toJSON", {
|
||||||
virtuals: true,
|
virtuals: true,
|
||||||
transform(_document, returnedObject) {
|
transform(_document, returnedObject: Record<string, any>) {
|
||||||
const messageDatabase = returnedObject as IMessageDatabase;
|
const messageDatabase = returnedObject as IMessageDatabase;
|
||||||
const messageClient = returnedObject as IMessageClient;
|
const messageClient = returnedObject as IMessageClient;
|
||||||
|
|
||||||
@ -149,6 +162,10 @@ messageSchema.set("toJSON", {
|
|||||||
delete returnedObject.attVisualOnly;
|
delete returnedObject.attVisualOnly;
|
||||||
delete returnedObject.expiry;
|
delete returnedObject.expiry;
|
||||||
|
|
||||||
|
if (messageDatabase.globaUpgradeId) {
|
||||||
|
messageClient.globaUpgradeId = toOid(messageDatabase.globaUpgradeId);
|
||||||
|
}
|
||||||
|
|
||||||
messageClient.date = toMongoDate(messageDatabase.date);
|
messageClient.date = toMongoDate(messageDatabase.date);
|
||||||
|
|
||||||
if (messageDatabase.startDate && messageDatabase.endDate) {
|
if (messageDatabase.startDate && messageDatabase.endDate) {
|
||||||
|
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